Merge m-c to fx-team a=merge
authorWes Kocher <wkocher@mozilla.com>
Tue, 27 Jan 2015 16:20:59 -0800
changeset 239436 4e3fba743b3a848bed39a686582455782c50eb26
parent 239353 86cba9403d817682de61b4d3f9e56b318d80d4c6 (current diff)
parent 239435 b2b10231606bb89fb75d11596abc49a9b6eecbc2 (diff)
child 239437 a7736ab45ab468d4483f82b9e8215900cac444cb
push id497
push usermleibovic@mozilla.com
push dateWed, 28 Jan 2015 16:43:37 +0000
reviewersmerge
milestone38.0a1
Merge m-c to fx-team a=merge
--- a/b2g/app/b2g.js
+++ b/b2g/app/b2g.js
@@ -688,75 +688,60 @@ pref("dom.ipc.processPriorityManager.tem
 // Number of different background levels for background processes.  We use
 // these different levels to force the low-memory killer to kill processes in
 // a LRU order.
 pref("dom.ipc.processPriorityManager.backgroundLRUPoolLevels", 5);
 
 // Kernel parameters for process priorities.  These affect how processes are
 // killed on low-memory and their relative CPU priorities.
 //
+// Note: The maximum nice value on Linux is 19, but the max value you should
+// use here is 18.  NSPR adds 1 to some threads' nice values, to mark
+// low-priority threads.  If the process priority manager were to renice a
+// process (and all its threads) to 19, all threads would have the same
+// niceness.  Then when we reniced the process to (say) 10, all threads would
+// /still/ have the same niceness; we'd effectively have erased NSPR's thread
+// priorities.
+
 // The kernel can only accept 6 (OomScoreAdjust, KillUnderKB) pairs. But it is
 // okay, kernel will still kill processes with larger OomScoreAdjust first even
 // its OomScoreAdjust don't have a corresponding KillUnderKB.
 
 pref("hal.processPriorityManager.gonk.MASTER.OomScoreAdjust", 0);
 pref("hal.processPriorityManager.gonk.MASTER.KillUnderKB", 4096);
-pref("hal.processPriorityManager.gonk.MASTER.cgroup", "");
+pref("hal.processPriorityManager.gonk.MASTER.Nice", 0);
 
 pref("hal.processPriorityManager.gonk.PREALLOC.OomScoreAdjust", 67);
-pref("hal.processPriorityManager.gonk.PREALLOC.cgroup", "apps/bg_non_interactive");
+pref("hal.processPriorityManager.gonk.PREALLOC.Nice", 18);
 
 pref("hal.processPriorityManager.gonk.FOREGROUND_HIGH.OomScoreAdjust", 67);
 pref("hal.processPriorityManager.gonk.FOREGROUND_HIGH.KillUnderKB", 5120);
-pref("hal.processPriorityManager.gonk.FOREGROUND_HIGH.cgroup", "apps/critical");
+pref("hal.processPriorityManager.gonk.FOREGROUND_HIGH.Nice", 0);
 
 pref("hal.processPriorityManager.gonk.FOREGROUND.OomScoreAdjust", 134);
 pref("hal.processPriorityManager.gonk.FOREGROUND.KillUnderKB", 6144);
-pref("hal.processPriorityManager.gonk.FOREGROUND.cgroup", "apps");
+pref("hal.processPriorityManager.gonk.FOREGROUND.Nice", 1);
 
 pref("hal.processPriorityManager.gonk.FOREGROUND_KEYBOARD.OomScoreAdjust", 200);
-pref("hal.processPriorityManager.gonk.FOREGROUND_KEYBOARD.cgroup", "apps");
+pref("hal.processPriorityManager.gonk.FOREGROUND_KEYBOARD.Nice", 1);
 
 pref("hal.processPriorityManager.gonk.BACKGROUND_PERCEIVABLE.OomScoreAdjust", 400);
 pref("hal.processPriorityManager.gonk.BACKGROUND_PERCEIVABLE.KillUnderKB", 7168);
-pref("hal.processPriorityManager.gonk.BACKGROUND_PERCEIVABLE.cgroup", "apps/bg_perceivable");
+pref("hal.processPriorityManager.gonk.BACKGROUND_PERCEIVABLE.Nice", 7);
 
 pref("hal.processPriorityManager.gonk.BACKGROUND_HOMESCREEN.OomScoreAdjust", 534);
 pref("hal.processPriorityManager.gonk.BACKGROUND_HOMESCREEN.KillUnderKB", 8192);
-pref("hal.processPriorityManager.gonk.BACKGROUND_HOMESCREEN.cgroup", "apps/bg_non_interactive");
+pref("hal.processPriorityManager.gonk.BACKGROUND_HOMESCREEN.Nice", 18);
 
 pref("hal.processPriorityManager.gonk.BACKGROUND.OomScoreAdjust", 667);
 pref("hal.processPriorityManager.gonk.BACKGROUND.KillUnderKB", 20480);
-pref("hal.processPriorityManager.gonk.BACKGROUND.cgroup", "apps/bg_non_interactive");
-
-// Control group definitions (i.e., CPU priority groups) for B2G processes.
-//
-// memory_swappiness -   0 - The kernel will swap only to avoid an out of memory condition
-// memory_swappiness -  60 - The default value.
-// memory_swappiness - 100 - The kernel will swap aggressively.
-
-// Foreground apps
-pref("hal.processPriorityManager.gonk.cgroups.apps.cpu_shares", 1024);
-pref("hal.processPriorityManager.gonk.cgroups.apps.cpu_notify_on_migrate", 1);
-pref("hal.processPriorityManager.gonk.cgroups.apps.memory_swappiness", 10);
+pref("hal.processPriorityManager.gonk.BACKGROUND.Nice", 18);
 
-// Foreground apps with high priority, 16x more CPU than foreground ones
-pref("hal.processPriorityManager.gonk.cgroups.apps/critical.cpu_shares", 16384);
-pref("hal.processPriorityManager.gonk.cgroups.apps/critical.cpu_notify_on_migrate", 1);
-pref("hal.processPriorityManager.gonk.cgroups.apps/critical.memory_swappiness", 0);
-
-// Background perceivable apps, ~10x less CPU than foreground ones
-pref("hal.processPriorityManager.gonk.cgroups.apps/bg_perceivable.cpu_shares", 103);
-pref("hal.processPriorityManager.gonk.cgroups.apps/bg_perceivable.cpu_notify_on_migrate", 0);
-pref("hal.processPriorityManager.gonk.cgroups.apps/bg_perceivable.memory_swappiness", 60);
-
-// Background apps, ~20x less CPU than foreground ones and ~2x less than perceivable ones
-pref("hal.processPriorityManager.gonk.cgroups.apps/bg_non_interactive.cpu_shares", 52);
-pref("hal.processPriorityManager.gonk.cgroups.apps/bg_non_interactive.cpu_notify_on_migrate", 0);
-pref("hal.processPriorityManager.gonk.cgroups.apps/bg_non_interactive.memory_swappiness", 100);
+// Processes get this niceness when they have low CPU priority.
+pref("hal.processPriorityManager.gonk.LowCPUNice", 18);
 
 // By default the compositor thread on gonk runs without real-time priority.  RT
 // priority can be enabled by setting this pref to a value between 1 and 99.
 // Note that audio processing currently runs at RT priority 2 or 3 at most.
 //
 // If RT priority is disabled, then the compositor nice value is used. We prefer
 // to use a nice value of -4, which matches Android's preferences. Setting a preference
 // of RT priority 1 would mean it is higher than audio, which is -16. The compositor
--- a/b2g/components/LogCapture.jsm
+++ b/b2g/components/LogCapture.jsm
@@ -1,59 +1,72 @@
 /* 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/. */
 /* jshint moz: true */
 /* global Uint8Array, Components, dump */
 
-'use strict';
+"use strict";
+
+const Cu = Components.utils;
+const Ci = Components.interfaces;
+const Cc = Components.classes;
 
-this.EXPORTED_SYMBOLS = ['LogCapture'];
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+
+XPCOMUtils.defineLazyModuleGetter(this, "Promise", "resource://gre/modules/Promise.jsm");
+
+this.EXPORTED_SYMBOLS = ["LogCapture"];
 
 const SYSTEM_PROPERTY_KEY_MAX = 32;
 const SYSTEM_PROPERTY_VALUE_MAX = 92;
 
 function debug(msg) {
-  dump('LogCapture.jsm: ' + msg + '\n');
+  dump("LogCapture.jsm: " + msg + "\n");
 }
 
 let LogCapture = {
   ensureLoaded: function() {
     if (!this.ctypes) {
       this.load();
     }
   },
 
   load: function() {
     // load in everything on first use
-    Components.utils.import('resource://gre/modules/ctypes.jsm', this);
+    Cu.import("resource://gre/modules/ctypes.jsm", this);
 
-    this.libc = this.ctypes.open(this.ctypes.libraryName('c'));
+    this.libc = this.ctypes.open(this.ctypes.libraryName("c"));
 
-    this.read = this.libc.declare('read',
+    this.read = this.libc.declare("read",
       this.ctypes.default_abi,
       this.ctypes.int,       // bytes read (out)
       this.ctypes.int,       // file descriptor (in)
       this.ctypes.voidptr_t, // buffer to read into (in)
       this.ctypes.size_t     // size_t size of buffer (in)
     );
 
-    this.open = this.libc.declare('open',
+    this.open = this.libc.declare("open",
       this.ctypes.default_abi,
       this.ctypes.int,      // file descriptor (returned)
       this.ctypes.char.ptr, // path
       this.ctypes.int       // flags
     );
 
-    this.close = this.libc.declare('close',
+    this.close = this.libc.declare("close",
       this.ctypes.default_abi,
       this.ctypes.int, // error code (returned)
       this.ctypes.int  // file descriptor
     );
 
+    this.getpid = this.libc.declare("getpid",
+      this.ctypes.default_abi,
+      this.ctypes.int  // PID
+    );
+
     this.property_find_nth =
       this.libc.declare("__system_property_find_nth",
                         this.ctypes.default_abi,
                         this.ctypes.voidptr_t,     // return value: nullable prop_info*
                         this.ctypes.unsigned_int); // n: the index of the property to return
 
     this.property_read =
       this.libc.declare("__system_property_read",
@@ -148,12 +161,32 @@ let LogCapture = {
       let key = this.key_buf.readString();;
       let value = this.value_buf.readString()
 
       propertyDict[key] = value;
       n++;
     }
 
     return propertyDict;
+  },
+
+  /**
+   * Dumping about:memory to a file in /data/local/tmp/, returning a Promise.
+   * Will be resolved with the dumped file name.
+   */
+  readAboutMemory: function() {
+    this.ensureLoaded();
+    let deferred = Promise.defer();
+
+    // Perform the dump
+    let dumper = Cc["@mozilla.org/memory-info-dumper;1"]
+                    .getService(Ci.nsIMemoryInfoDumper);
+
+    let file = "/data/local/tmp/logshake-about_memory-" + this.getpid() + ".json.gz";
+    dumper.dumpMemoryReportsToNamedFile(file, function() {
+      deferred.resolve(file);
+    }, null, false);
+
+    return deferred.promise;
   }
 };
 
 this.LogCapture = LogCapture;
--- a/b2g/components/LogShake.jsm
+++ b/b2g/components/LogShake.jsm
@@ -16,54 +16,54 @@
 /* enable Mozilla javascript extensions and global strictness declaration,
  * disable valid this checking */
 /* jshint moz: true */
 /* jshint -W097 */
 /* jshint -W040 */
 /* global Services, Components, dump, LogCapture, LogParser,
    OS, Promise, volumeService, XPCOMUtils, SystemAppProxy */
 
-'use strict';
+"use strict";
 
 const Cu = Components.utils;
 const Ci = Components.interfaces;
 
-Cu.import('resource://gre/modules/XPCOMUtils.jsm');
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
-XPCOMUtils.defineLazyModuleGetter(this, 'LogCapture', 'resource://gre/modules/LogCapture.jsm');
-XPCOMUtils.defineLazyModuleGetter(this, 'LogParser', 'resource://gre/modules/LogParser.jsm');
-XPCOMUtils.defineLazyModuleGetter(this, 'OS', 'resource://gre/modules/osfile.jsm');
-XPCOMUtils.defineLazyModuleGetter(this, 'Promise', 'resource://gre/modules/Promise.jsm');
-XPCOMUtils.defineLazyModuleGetter(this, 'Services', 'resource://gre/modules/Services.jsm');
-XPCOMUtils.defineLazyModuleGetter(this, 'SystemAppProxy', 'resource://gre/modules/SystemAppProxy.jsm');
+XPCOMUtils.defineLazyModuleGetter(this, "LogCapture", "resource://gre/modules/LogCapture.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "LogParser", "resource://gre/modules/LogParser.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "OS", "resource://gre/modules/osfile.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "Promise", "resource://gre/modules/Promise.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "Services", "resource://gre/modules/Services.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "SystemAppProxy", "resource://gre/modules/SystemAppProxy.jsm");
 
-XPCOMUtils.defineLazyServiceGetter(this, 'powerManagerService',
-                                   '@mozilla.org/power/powermanagerservice;1',
-                                   'nsIPowerManagerService');
+XPCOMUtils.defineLazyServiceGetter(this, "powerManagerService",
+                                   "@mozilla.org/power/powermanagerservice;1",
+                                   "nsIPowerManagerService");
 
-XPCOMUtils.defineLazyServiceGetter(this, 'volumeService',
-                                   '@mozilla.org/telephony/volume-service;1',
-                                   'nsIVolumeService');
+XPCOMUtils.defineLazyServiceGetter(this, "volumeService",
+                                   "@mozilla.org/telephony/volume-service;1",
+                                   "nsIVolumeService");
 
-this.EXPORTED_SYMBOLS = ['LogShake'];
+this.EXPORTED_SYMBOLS = ["LogShake"];
 
 function debug(msg) {
-  dump('LogShake.jsm: '+msg+'\n');
+  dump("LogShake.jsm: "+msg+"\n");
 }
 
 /**
  * An empirically determined amount of acceleration corresponding to a
  * shake
  */
 const EXCITEMENT_THRESHOLD = 500;
-const DEVICE_MOTION_EVENT = 'devicemotion';
-const SCREEN_CHANGE_EVENT = 'screenchange';
-const CAPTURE_LOGS_START_EVENT = 'capture-logs-start';
-const CAPTURE_LOGS_ERROR_EVENT = 'capture-logs-error';
-const CAPTURE_LOGS_SUCCESS_EVENT = 'capture-logs-success';
+const DEVICE_MOTION_EVENT = "devicemotion";
+const SCREEN_CHANGE_EVENT = "screenchange";
+const CAPTURE_LOGS_START_EVENT = "capture-logs-start";
+const CAPTURE_LOGS_ERROR_EVENT = "capture-logs-error";
+const CAPTURE_LOGS_SUCCESS_EVENT = "capture-logs-success";
 
 let LogShake = {
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver]),
   /**
    * If LogShake is listening for device motion events. Required due to lag
    * between HAL layer of device motion events and listening for device motion
    * events.
    */
@@ -74,27 +74,28 @@ let LogShake = {
    * debouncing.
    */
   captureRequested: false,
 
   /**
    * Map of files which have log-type information to their parsers
    */
   LOGS_WITH_PARSERS: {
-    '/dev/log/main': LogParser.prettyPrintLogArray,
-    '/dev/log/system': LogParser.prettyPrintLogArray,
-    '/dev/log/radio': LogParser.prettyPrintLogArray,
-    '/dev/log/events': LogParser.prettyPrintLogArray,
-    '/proc/cmdline': LogParser.prettyPrintArray,
-    '/proc/kmsg': LogParser.prettyPrintArray,
-    '/proc/meminfo': LogParser.prettyPrintArray,
-    '/proc/uptime': LogParser.prettyPrintArray,
-    '/proc/version': LogParser.prettyPrintArray,
-    '/proc/vmallocinfo': LogParser.prettyPrintArray,
-    '/proc/vmstat': LogParser.prettyPrintArray
+    "/dev/log/main": LogParser.prettyPrintLogArray,
+    "/dev/log/system": LogParser.prettyPrintLogArray,
+    "/dev/log/radio": LogParser.prettyPrintLogArray,
+    "/dev/log/events": LogParser.prettyPrintLogArray,
+    "/proc/cmdline": LogParser.prettyPrintArray,
+    "/proc/kmsg": LogParser.prettyPrintArray,
+    "/proc/meminfo": LogParser.prettyPrintArray,
+    "/proc/uptime": LogParser.prettyPrintArray,
+    "/proc/version": LogParser.prettyPrintArray,
+    "/proc/vmallocinfo": LogParser.prettyPrintArray,
+    "/proc/vmstat": LogParser.prettyPrintArray,
+    "/system/b2g/application.ini": LogParser.prettyPrintArray
   },
 
   /**
    * Start existing, observing motion events if the screen is turned on.
    */
   init: function() {
     // TODO: no way of querying screen state from power manager
     // this.handleScreenChangeEvent({ detail: {
@@ -104,17 +105,17 @@ let LogShake = {
     // However, the screen is always on when we are being enabled because it is
     // either due to the phone starting up or a user enabling us directly.
     this.handleScreenChangeEvent({ detail: {
       screenEnabled: true
     }});
 
     SystemAppProxy.addEventListener(SCREEN_CHANGE_EVENT, this, false);
 
-    Services.obs.addObserver(this, 'xpcom-shutdown', false);
+    Services.obs.addObserver(this, "xpcom-shutdown", false);
   },
 
   /**
    * Handle an arbitrary event, passing it along to the proper function
    */
   handleEvent: function(event) {
     switch (event.type) {
     case DEVICE_MOTION_EVENT:
@@ -129,17 +130,17 @@ let LogShake = {
       break;
     }
   },
 
   /**
    * Handle an observation from Services.obs
    */
   observe: function(subject, topic) {
-    if (topic === 'xpcom-shutdown') {
+    if (topic === "xpcom-shutdown") {
       this.uninit();
     }
   },
 
   startDeviceMotionListener: function() {
     if (!this.deviceMotionEnabled) {
       SystemAppProxy.addEventListener(DEVICE_MOTION_EVENT, this, false);
       this.deviceMotionEnabled = true;
@@ -147,18 +148,18 @@ let LogShake = {
   },
 
   stopDeviceMotionListener: function() {
     SystemAppProxy.removeEventListener(DEVICE_MOTION_EVENT, this, false);
     this.deviceMotionEnabled = false;
   },
 
   /**
-   * Handle a motion event, keeping track of 'excitement', the magnitude
-   * of the device's acceleration.
+   * Handle a motion event, keeping track of "excitement", the magnitude
+   * of the device"s acceleration.
    */
   handleDeviceMotionEvent: function(event) {
     // There is a lag between disabling the event listener and event arrival
     // ceasing.
     if (!this.deviceMotionEnabled) {
       return;
     }
 
@@ -212,21 +213,43 @@ let LogShake = {
 
     try {
       logArrays["properties"] =
         LogParser.prettyPrintPropertiesArray(LogCapture.readProperties());
     } catch (ex) {
       Cu.reportError("Unable to get device properties: " + ex);
     }
 
+    // Let Gecko perfom the dump to a file, and just collect it
+    try {
+      LogCapture.readAboutMemory().then(aboutMemory => {
+        let file = OS.Path.basename(aboutMemory);
+        let logArray;
+        try {
+          logArray = LogCapture.readLogFile(aboutMemory);
+          if (!logArray) {
+            debug("LogCapture.readLogFile() returned nothing about:memory ");
+          }
+          // We need to remove the dumped file, now that we have it in memory
+          OS.File.remove(aboutMemory);
+        } catch (ex) {
+          Cu.reportError("Unable to handle about:memory dump: " + ex);
+        }
+        logArrays[file] = LogParser.prettyPrintArray(logArray);
+      });
+    } catch (ex) {
+      Cu.reportError("Unable to get about:memory dump: " + ex);
+    }
+
     for (let loc in this.LOGS_WITH_PARSERS) {
       let logArray;
       try {
         logArray = LogCapture.readLogFile(loc);
         if (!logArray) {
+          debug("LogCapture.readLogFile() returned nothing for: " + loc);
           continue;
         }
       } catch (ex) {
         Cu.reportError("Unable to LogCapture.readLogFile('" + loc + "'): " + ex);
         continue;
       }
 
       try {
@@ -240,96 +263,118 @@ let LogShake = {
   },
 
   /**
    * Stop logshake, removing all listeners
    */
   uninit: function() {
     this.stopDeviceMotionListener();
     SystemAppProxy.removeEventListener(SCREEN_CHANGE_EVENT, this, false);
-    Services.obs.removeObserver(this, 'xpcom-shutdown');
+    Services.obs.removeObserver(this, "xpcom-shutdown");
   }
 };
 
 function getLogFilename(logLocation) {
   // sanitize the log location
-  let logName = logLocation.replace(/\//g, '-');
-  if (logName[0] === '-') {
+  let logName = logLocation.replace(/\//g, "-");
+  if (logName[0] === "-") {
     logName = logName.substring(1);
   }
-  return logName + '.log';
+
+  // If no extension is provided, default to forcing .log
+  let extension = ".log";
+  let logLocationExt = logLocation.split(".");
+  if (logLocationExt.length > 1) {
+    // otherwise, just append nothing
+    extension = "";
+  }
+
+  return logName + extension;
 }
 
 function getSdcardPrefix() {
-  return volumeService.getVolumeByName('sdcard').mountPoint;
+  return volumeService.getVolumeByName("sdcard").mountPoint;
 }
 
 function getLogDirectoryRoot() {
-  return 'logs';
+  return "logs";
 }
 
 function getLogDirectory() {
   let d = new Date();
   d = new Date(d.getTime() - d.getTimezoneOffset() * 60000);
-  let timestamp = d.toISOString().slice(0, -5).replace(/[:T]/g, '-');
-  // return directory name of format 'logs/timestamp/'
+  let timestamp = d.toISOString().slice(0, -5).replace(/[:T]/g, "-");
   return timestamp;
 }
 
 /**
  * Save the formatted arrays of log files to an sdcard if available
  */
 function saveLogs(logArrays) {
   if (!logArrays || Object.keys(logArrays).length === 0) {
     return Promise.resolve({
       logFilenames: [],
-      logPrefix: ''
+      logPrefix: ""
     });
   }
 
   let sdcardPrefix, dirNameRoot, dirName;
   try {
     sdcardPrefix = getSdcardPrefix();
     dirNameRoot = getLogDirectoryRoot();
     dirName = getLogDirectory();
   } catch(e) {
     // Return promise failed with exception e
     // Handles missing sdcard
     return Promise.reject(e);
   }
 
-  debug('making a directory all the way from '+sdcardPrefix+' to '+(sdcardPrefix + '/' + dirNameRoot + '/' + dirName));
+  debug("making a directory all the way from " + sdcardPrefix + " to " + (sdcardPrefix + "/" + dirNameRoot + "/" + dirName) );
   let logsRoot = OS.Path.join(sdcardPrefix, dirNameRoot);
   return OS.File.makeDir(logsRoot, {from: sdcardPrefix}).then(
     function() {
+      debug("First OS.File.makeDir done");
       let logsDir = OS.Path.join(logsRoot, dirName);
+      debug("Creating " + logsDir);
       return OS.File.makeDir(logsDir, {ignoreExisting: false}).then(
         function() {
+          debug("Created: " + logsDir);
           // Now the directory is guaranteed to exist, save the logs
           let logFilenames = [];
           let saveRequests = [];
 
+          debug("Will now traverse logArrays: " + logArrays.length);
+
           for (let logLocation in logArrays) {
-            debug('requesting save of ' + logLocation);
+            debug("requesting save of " + logLocation);
             let logArray = logArrays[logLocation];
             // The filename represents the relative path within the SD card, not the
             // absolute path because Gaia will refer to it using the DeviceStorage
             // API
             let filename = OS.Path.join(dirNameRoot, dirName, getLogFilename(logLocation));
             logFilenames.push(filename);
             let saveRequest = OS.File.writeAtomic(OS.Path.join(sdcardPrefix, filename), logArray);
             saveRequests.push(saveRequest);
           }
 
           return Promise.all(saveRequests).then(
             function() {
-              debug('returning logfilenames: '+logFilenames.toSource());
+              debug("returning logfilenames: "+logFilenames.toSource());
               return {
                 logFilenames: logFilenames,
                 logPrefix: OS.Path.join(dirNameRoot, dirName)
               };
+            }, function(err) {
+              debug("Error at some save request: " + err);
+              return Promise.reject(err);
             });
+        }, function(err) {
+          debug("Error at OS.File.makeDir for " + logsDir + ": " + err);
+          return Promise.reject(err);
         });
+    }, function(err) {
+      debug("Error at first OS.File.makeDir: " + err);
+      return Promise.reject(err);
     });
 }
 
 LogShake.init();
 this.LogShake = LogShake;
--- a/b2g/components/test/unit/test_logcapture.js
+++ b/b2g/components/test/unit/test_logcapture.js
@@ -1,30 +1,13 @@
-/* Any copyright is dedicated to the Public Domain.
-   http://creativecommons.org/publicdomain/zero/1.0/ */
-
-
 /**
- * Test that LogCapture successfully reads from the /dev/log devices, returning
- * a Uint8Array of some length, including zero. This tests a few standard
- * log devices
+ * Testing non Gonk-specific code path
  */
 function run_test() {
   Components.utils.import("resource:///modules/LogCapture.jsm");
-
-  function verifyLog(log) {
-    // log exists
-    notEqual(log, null);
-    // log has a length and it is non-negative (is probably array-like)
-    ok(log.length >= 0);
-  }
+  run_next_test();
+}
 
-  let propertiesLog = LogCapture.readProperties();
-  notEqual(propertiesLog, null, "Properties should not be null");
-  notEqual(propertiesLog, undefined, "Properties should not be undefined");
-  equal(propertiesLog["ro.kernel.qemu"], "1", "QEMU property should be 1");
-
-  let mainLog = LogCapture.readLogFile("/dev/log/main");
-  verifyLog(mainLog);
-
-  let meminfoLog = LogCapture.readLogFile("/proc/meminfo");
-  verifyLog(meminfoLog);
-}
+// Trivial test just to make sure we have no syntax error
+add_test(function test_logCapture_loads() {
+  ok(LogCapture, "LogCapture object exists");
+  run_next_test();
+});
new file mode 100644
--- /dev/null
+++ b/b2g/components/test/unit/test_logcapture_gonk.js
@@ -0,0 +1,61 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+
+/**
+ * Test that LogCapture successfully reads from the /dev/log devices, returning
+ * a Uint8Array of some length, including zero. This tests a few standard
+ * log devices
+ */
+function run_test() {
+  Components.utils.import("resource:///modules/LogCapture.jsm");
+  run_next_test();
+}
+
+function verifyLog(log) {
+  // log exists
+  notEqual(log, null);
+  // log has a length and it is non-negative (is probably array-like)
+  ok(log.length >= 0);
+}
+
+add_test(function test_readLogFile() {
+  let mainLog = LogCapture.readLogFile("/dev/log/main");
+  verifyLog(mainLog);
+
+  let meminfoLog = LogCapture.readLogFile("/proc/meminfo");
+  verifyLog(meminfoLog);
+
+  run_next_test();
+});
+
+add_test(function test_readProperties() {
+  let propertiesLog = LogCapture.readProperties();
+  notEqual(propertiesLog, null, "Properties should not be null");
+  notEqual(propertiesLog, undefined, "Properties should not be undefined");
+  equal(propertiesLog["ro.kernel.qemu"], "1", "QEMU property should be 1");
+
+  run_next_test();
+});
+
+add_test(function test_readAppIni() {
+  let appIni = LogCapture.readLogFile("/system/b2g/application.ini");
+  verifyLog(appIni);
+
+  run_next_test();
+});
+
+
+add_test(function test_get_about_memory() {
+  let memLog = LogCapture.readAboutMemory();
+
+  ok(memLog, "Should have returned a valid Promise object");
+
+  memLog.then(file => {
+    ok(file, "Should have returned a filename");
+    run_next_test();
+  }, error => {
+    ok(false, "Dumping about:memory promise rejected: " + error);
+    run_next_test();
+  });
+});
new file mode 100644
--- /dev/null
+++ b/b2g/components/test/unit/test_logshake_gonk.js
@@ -0,0 +1,121 @@
+/**
+ * Test the log capturing capabilities of LogShake.jsm, checking
+ * for Gonk-specific parts
+ */
+
+/* jshint moz: true */
+/* global Components, LogCapture, LogShake, ok, add_test, run_next_test, dump */
+/* exported run_test */
+
+/* disable use strict warning */
+/* jshint -W097 */
+
+"use strict";
+
+const Cu = Components.utils;
+const Ci = Components.interfaces;
+const Cc = Components.classes;
+
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+
+XPCOMUtils.defineLazyServiceGetter(this, "volumeService",
+                                   "@mozilla.org/telephony/volume-service;1",
+                                   "nsIVolumeService");
+
+let sdcard;
+
+function run_test() {
+  Cu.import("resource://gre/modules/LogShake.jsm");
+  Cu.import("resource://gre/modules/Promise.jsm");
+  Cu.import("resource://gre/modules/osfile.jsm");
+  do_get_profile();
+  debug("Starting");
+  run_next_test();
+}
+
+function debug(msg) {
+  var timestamp = Date.now();
+  dump("LogShake: " + timestamp + ": " + msg + "\n");
+}
+
+add_test(function setup_fs() {
+  OS.File.makeDir("/data/local/tmp/sdcard/", {from: "/data"}).then(function() {
+    run_next_test();
+  });
+});
+
+add_test(function setup_sdcard() {
+  let volName = "sdcard";
+  let mountPoint = "/data/local/tmp/sdcard";
+  volumeService.createFakeVolume(volName, mountPoint);
+
+  let vol = volumeService.getVolumeByName(volName);
+  ok(vol, "volume shouldn't be null");
+  equal(volName, vol.name, "name");
+
+  volumeService.SetFakeVolumeState(volName, Ci.nsIVolume.STATE_MOUNTED);
+  equal(Ci.nsIVolume.STATE_MOUNTED, vol.state, "state");
+
+  run_next_test();
+});
+
+add_test(function test_ensure_sdcard() {
+  sdcard = volumeService.getVolumeByName("sdcard").mountPoint;
+  ok(sdcard, "Should have a valid sdcard mountpoint");
+  run_next_test();
+});
+
+add_test(function test_logShake_captureLogs_returns() {
+  // Enable LogShake
+  LogShake.init();
+
+  LogShake.captureLogs().then(logResults => {
+    LogShake.uninit();
+
+    ok(logResults.logFilenames.length > 0, "Should have filenames");
+    ok(logResults.logPrefix.length > 0, "Should have prefix");
+
+    run_next_test();
+  },
+  error => {
+    LogShake.uninit();
+
+    ok(false, "Should not have received error: " + error);
+
+    run_next_test();
+  });
+});
+
+add_test(function test_logShake_captureLogs_writes() {
+  // Enable LogShake
+  LogShake.init();
+
+  let expectedFiles = [];
+
+  LogShake.captureLogs().then(logResults => {
+    LogShake.uninit();
+
+    logResults.logFilenames.forEach(f => {
+      let p = OS.Path.join(sdcard, f);
+      ok(p, "Should have a valid result path: " + p);
+
+      let t = OS.File.exists(p).then(rv => {
+        ok(rv, "File exists: " + p);
+      });
+
+      expectedFiles.push(t);
+    });
+
+    Promise.all(expectedFiles).then(() => {
+      ok(true, "Completed all files checks");
+      run_next_test();
+    });
+  },
+  error => {
+    LogShake.uninit();
+
+    ok(false, "Should not have received error: " + error);
+
+    run_next_test();
+  });
+});
--- a/b2g/components/test/unit/xpcshell.ini
+++ b/b2g/components/test/unit/xpcshell.ini
@@ -9,15 +9,22 @@ support-files =
 
 [test_bug832946.js]
 
 [test_fxaccounts.js]
 [test_signintowebsite.js]
 head = head_identity.js
 tail =
 
+# testing non gonk-specific stuff
 [test_logcapture.js]
+
+[test_logcapture_gonk.js]
 # only run on b2g builds due to requiring b2g-specific log files to exist
 skip-if = toolkit != "gonk"
 
 [test_logparser.js]
 
 [test_logshake.js]
+
+[test_logshake_gonk.js]
+# only run on b2g builds due to requiring b2g-specific log files to exist
+skip-if = ((toolkit != "gonk") || ((toolkit == "gonk") && (debug == true))) # bug 1125989: disabled because of race condition in OS.File.makeDir
--- a/b2g/config/dolphin/sources.xml
+++ b/b2g/config/dolphin/sources.xml
@@ -10,17 +10,17 @@
   <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="e06971db7acf7a35c32eb74d675a4e12e288e6be">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="1eedbee8f26efbaa4a113e002c46f64e9b90249d"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="1d53fb07984298253aad64bfa4236b7167ee3d4d"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2262d4a77d4f46ab230fd747bb91e9b77bad36cb"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="d6a27295acb0a25926bf6290dd2532a7f9027864"/>
@@ -110,17 +110,17 @@
   <project name="platform/libcore" path="libcore" revision="e195beab082c09217318fc19250caeaf4c1bd800"/>
   <project name="platform/libnativehelper" path="libnativehelper" revision="feeb36c2bd4adfe285f98f5de92e0f3771b2c115"/>
   <project name="platform/ndk" path="ndk" revision="e58ef003be4306bb53a8c11331146f39e4eab31f"/>
   <project name="platform_prebuilts_misc" path="prebuilts/misc" remote="b2g" revision="0e7c060db684b409616fe67ea433ef19f5634c60"/>
   <project name="platform/prebuilts/ndk" path="prebuilts/ndk" revision="c792f0bd9fff7aea2887c60bbb3a9bbdb534ffa3"/>
   <project name="platform_prebuilts_qemu-kernel" path="prebuilts/qemu-kernel" remote="b2g" revision="f7d9bf71cf6693474f3f2a81a4ba62c0fc5646aa"/>
   <project name="platform/prebuilts/sdk" path="prebuilts/sdk" revision="cfcef469537869947abb9aa1d656774cc2678d4c"/>
   <project name="platform/prebuilts/tools" path="prebuilts/tools" revision="5a48c04c4bb5f079bc757e29864a42427378e051"/>
-  <project name="platform_system_bluetoothd" path="system/bluetoothd" remote="b2g" revision="dcb7c6ba2c6aec23a76d95094c4cbc17eeca5d44"/>
+  <project name="platform_system_bluetoothd" path="system/bluetoothd" remote="b2g" revision="a3a900615b89cbd67acfb8b750baa43b321ef68b"/>
   <project name="platform/system/extras" path="system/extras" revision="10e78a05252b3de785f88c2d0b9ea8a428009c50"/>
   <project name="platform/system/media" path="system/media" revision="7ff72c2ea2496fa50b5e8a915e56e901c3ccd240"/>
   <project name="platform_system_libfdio" path="system/libfdio" remote="b2g" revision="8fcd25d64f0f67d1a6f7037a4c83ce6d95466770"/>
   <project name="platform/system/netd" path="system/netd" revision="3ae56364946d4a5bf5a5f83f12f9a45a30398e33"/>
   <project name="platform/system/security" path="system/security" revision="ee8068b9e7bfb2770635062fc9c2035be2142bd8"/>
   <project name="platform/system/vold" path="system/vold" revision="2e43efe1b30d0b98574d293059556aebd2f46454"/>
   <!--original fetch url was http://sprdsource.spreadtrum.com:8085/b2g/android-->
   <remote fetch="https://git.mozilla.org/external/sprd-aosp" name="sprd-aosp"/>
--- a/b2g/config/emulator-ics/sources.xml
+++ b/b2g/config/emulator-ics/sources.xml
@@ -14,17 +14,17 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="refs/tags/android-4.0.4_r2.1" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="df362ace56338da8173d30d3e09e08c42c1accfa">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="1eedbee8f26efbaa4a113e002c46f64e9b90249d"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="1d53fb07984298253aad64bfa4236b7167ee3d4d"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2262d4a77d4f46ab230fd747bb91e9b77bad36cb"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="d5d3f93914558b6f168447b805cd799c8233e300"/>
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="6fa7a4936414ceb4055fd27f7a30e76790f834fb"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="d6a27295acb0a25926bf6290dd2532a7f9027864"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
--- a/b2g/config/emulator-jb/sources.xml
+++ b/b2g/config/emulator-jb/sources.xml
@@ -12,17 +12,17 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="0e94c080bee081a50aa2097527b0b40852f9143f">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="1eedbee8f26efbaa4a113e002c46f64e9b90249d"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="1d53fb07984298253aad64bfa4236b7167ee3d4d"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2262d4a77d4f46ab230fd747bb91e9b77bad36cb"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="d6a27295acb0a25926bf6290dd2532a7f9027864"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="5c45f43419d5582949284eee9cef0c43d866e03b"/>
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="3748b4168e7bd8d46457d4b6786003bc6a5223ce"/>
@@ -112,17 +112,17 @@
   <project name="platform/libnativehelper" path="libnativehelper" revision="4792069e90385889b0638e97ae62c67cdf274e22"/>
   <project name="platform/ndk" path="ndk" revision="7666b97bbaf1d645cdd6b4430a367b7a2bb53369"/>
   <project name="platform/prebuilts/misc" path="prebuilts/misc" revision="f6ab40b3257abc07741188fd173ac392575cc8d2"/>
   <project name="platform/prebuilts/ndk" path="prebuilts/ndk" revision="e52099755d0bd3a579130eefe8e58066cc6c0cb6"/>
   <project name="platform_prebuilts_qemu-kernel" path="prebuilts/qemu-kernel" remote="b2g" revision="02c32feb2fe97037be0ac4dace3a6a5025ac895d"/>
   <project name="platform/prebuilts/sdk" path="prebuilts/sdk" revision="842e33e43a55ea44833b9e23e4d180fa17c843af"/>
   <project name="platform/prebuilts/tools" path="prebuilts/tools" revision="5db24726f0f42124304195a6bdea129039eeeaeb"/>
   <project name="platform/system/bluetooth" path="system/bluetooth" revision="930ae098543881f47eac054677726ee4b998b2f8"/>
-  <project name="platform_system_bluetoothd" path="system/bluetoothd" remote="b2g" revision="dcb7c6ba2c6aec23a76d95094c4cbc17eeca5d44"/>
+  <project name="platform_system_bluetoothd" path="system/bluetoothd" remote="b2g" revision="a3a900615b89cbd67acfb8b750baa43b321ef68b"/>
   <project name="platform_system_core" path="system/core" remote="b2g" revision="542d1f59dc331b472307e5bd043101d14d5a3a3e"/>
   <project name="platform/system/extras" path="system/extras" revision="18c1180e848e7ab8691940481f5c1c8d22c37b3e"/>
   <project name="platform_system_libfdio" path="system/libfdio" remote="b2g" revision="8fcd25d64f0f67d1a6f7037a4c83ce6d95466770"/>
   <project name="platform/system/media" path="system/media" revision="d90b836f66bf1d9627886c96f3a2d9c3007fbb80"/>
   <project name="platform/system/netd" path="system/netd" revision="56112dd7b811301b718d0643a82fd5cac9522073"/>
   <project name="platform/system/security" path="system/security" revision="f48ff68fedbcdc12b570b7699745abb6e7574907"/>
   <project name="platform/system/vold" path="system/vold" revision="8de05d4a52b5a91e7336e6baa4592f945a6ddbea"/>
   <default remote="caf" revision="refs/tags/android-4.3_r2.1" sync-j="4"/>
@@ -130,12 +130,12 @@
   <project name="android-development" path="development" remote="b2g" revision="dab55669da8f48b6e57df95d5af9f16b4a87b0b1"/>
   <project name="device/generic/armv7-a-neon" path="device/generic/armv7-a-neon" revision="3a9a17613cc685aa232432566ad6cc607eab4ec1"/>
   <project name="device_generic_goldfish" path="device/generic/goldfish" remote="b2g" revision="197cd9492b9fadaa915c5daf36ff557f8f4a8d1c"/>
   <project name="platform/external/libnfc-nci" path="external/libnfc-nci" revision="7d33aaf740bbf6c7c6e9c34a92b371eda311b66b"/>
   <project name="libnfcemu" path="external/libnfcemu" remote="b2g" revision="125ccf9bd5986c7728ea44508b3e1d1185ac028b"/>
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="c5f8d282efe4a4e8b1e31a37300944e338e60e4f"/>
   <project name="platform/external/wpa_supplicant_8" path="external/wpa_supplicant_8" revision="0e56e450367cd802241b27164a2979188242b95f"/>
   <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="9f28c4faea3b2f01db227b2467b08aeba96d9bec"/>
-  <project name="platform_system_nfcd" path="system/nfcd" remote="b2g" revision="13374490fc0c989347448f0b2d6b220adff5e630"/>
+  <project name="platform_system_nfcd" path="system/nfcd" remote="b2g" revision="d19dad5844e8803d5e88d1577a2742b4f5cbc467"/>
   <project name="android-sdk" path="sdk" remote="b2g" revision="8b1365af38c9a653df97349ee53a3f5d64fd590a"/>
   <project name="darwinstreamingserver" path="system/darwinstreamingserver" remote="b2g" revision="cf85968c7f85e0ec36e72c87ceb4837a943b8af6"/>
 </manifest>
--- a/b2g/config/emulator-kk/sources.xml
+++ b/b2g/config/emulator-kk/sources.xml
@@ -10,17 +10,17 @@
   <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="e06971db7acf7a35c32eb74d675a4e12e288e6be">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="1eedbee8f26efbaa4a113e002c46f64e9b90249d"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="1d53fb07984298253aad64bfa4236b7167ee3d4d"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2262d4a77d4f46ab230fd747bb91e9b77bad36cb"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="d6a27295acb0a25926bf6290dd2532a7f9027864"/>
@@ -110,17 +110,17 @@
   <project name="platform/libcore" path="libcore" revision="9877ade9617bb0db6e59aa2a54719a9bc92600f3"/>
   <project name="platform/libnativehelper" path="libnativehelper" revision="46c96ace65eb1ccab05bf15b9bf8e53e443039af"/>
   <project name="platform/ndk" path="ndk" revision="cb5519af32ae7b4a9c334913a612462ecd04c5d0"/>
   <project name="platform_prebuilts_misc" path="prebuilts/misc" remote="b2g" revision="0e7c060db684b409616fe67ea433ef19f5634c60"/>
   <project name="platform/prebuilts/ndk" path="prebuilts/ndk" revision="6aa61f8557a22039a30b42b7f283996381fd625d"/>
   <project name="platform_prebuilts_qemu-kernel" path="prebuilts/qemu-kernel" remote="b2g" revision="f7d9bf71cf6693474f3f2a81a4ba62c0fc5646aa"/>
   <project name="platform/prebuilts/sdk" path="prebuilts/sdk" revision="b562b01c93de9578d5db537b6a602a38e1aaa0ce"/>
   <project name="platform/prebuilts/tools" path="prebuilts/tools" revision="387f03e815f57d536dd922706db1622bddba8d81"/>
-  <project name="platform_system_bluetoothd" path="system/bluetoothd" remote="b2g" revision="dcb7c6ba2c6aec23a76d95094c4cbc17eeca5d44"/>
+  <project name="platform_system_bluetoothd" path="system/bluetoothd" remote="b2g" revision="a3a900615b89cbd67acfb8b750baa43b321ef68b"/>
   <project name="platform/system/extras" path="system/extras" revision="5356165f67f4a81c2ef28671c13697f1657590df"/>
   <project name="platform/system/media" path="system/media" revision="be0e2fe59a8043fa5200f75697df9220a99abe9d"/>
   <project name="platform_system_libfdio" path="system/libfdio" remote="b2g" revision="8fcd25d64f0f67d1a6f7037a4c83ce6d95466770"/>
   <project name="platform/system/netd" path="system/netd" revision="36704b0da24debcab8090156568ac236315036bb"/>
   <project name="platform/system/security" path="system/security" revision="583374f69f531ba68fc3dcbff1f74893d2a96406"/>
   <project name="platform/system/vold" path="system/vold" revision="d4455b8cf361f8353e8aebac15ffd64b4aedd2b9"/>
   <project name="platform/external/icu4c" path="external/icu4c" remote="aosp" revision="b4c6379528887dc25ca9991a535a8d92a61ad6b6"/>
   <project name="platform_frameworks_av" path="frameworks/av" remote="b2g" revision="f3cedd7fd9b1649aa5107d466be9078bb7602af6"/>
--- a/b2g/config/emulator/sources.xml
+++ b/b2g/config/emulator/sources.xml
@@ -14,17 +14,17 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="refs/tags/android-4.0.4_r2.1" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="df362ace56338da8173d30d3e09e08c42c1accfa">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="1eedbee8f26efbaa4a113e002c46f64e9b90249d"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="1d53fb07984298253aad64bfa4236b7167ee3d4d"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2262d4a77d4f46ab230fd747bb91e9b77bad36cb"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="d5d3f93914558b6f168447b805cd799c8233e300"/>
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="6fa7a4936414ceb4055fd27f7a30e76790f834fb"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="d6a27295acb0a25926bf6290dd2532a7f9027864"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
--- a/b2g/config/flame-kk/sources.xml
+++ b/b2g/config/flame-kk/sources.xml
@@ -10,17 +10,17 @@
   <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="e06971db7acf7a35c32eb74d675a4e12e288e6be">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="1eedbee8f26efbaa4a113e002c46f64e9b90249d"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="1d53fb07984298253aad64bfa4236b7167ee3d4d"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2262d4a77d4f46ab230fd747bb91e9b77bad36cb"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="d6a27295acb0a25926bf6290dd2532a7f9027864"/>
@@ -105,17 +105,17 @@
   <project name="platform/libcore" path="libcore" revision="baf7d8068dd501cfa338d3a8b1b87216d6ce0571"/>
   <project name="platform/libnativehelper" path="libnativehelper" revision="50c4430e32849530ced32680fd6ee98963b3f7ac"/>
   <project name="platform/ndk" path="ndk" revision="e58ef003be4306bb53a8c11331146f39e4eab31f"/>
   <project name="platform_prebuilts_misc" path="prebuilts/misc" remote="b2g" revision="0e7c060db684b409616fe67ea433ef19f5634c60"/>
   <project name="platform/prebuilts/ndk" path="prebuilts/ndk" revision="c792f0bd9fff7aea2887c60bbb3a9bbdb534ffa3"/>
   <project name="platform_prebuilts_qemu-kernel" path="prebuilts/qemu-kernel" remote="b2g" revision="f7d9bf71cf6693474f3f2a81a4ba62c0fc5646aa"/>
   <project name="platform/prebuilts/sdk" path="prebuilts/sdk" revision="69d524e80cdf3981006627c65ac85f3a871238a3"/>
   <project name="platform/prebuilts/tools" path="prebuilts/tools" revision="5a48c04c4bb5f079bc757e29864a42427378e051"/>
-  <project name="platform_system_bluetoothd" path="system/bluetoothd" remote="b2g" revision="dcb7c6ba2c6aec23a76d95094c4cbc17eeca5d44"/>
+  <project name="platform_system_bluetoothd" path="system/bluetoothd" remote="b2g" revision="a3a900615b89cbd67acfb8b750baa43b321ef68b"/>
   <project name="platform/system/extras" path="system/extras" revision="576f57b6510de59c08568b53c0fb60588be8689e"/>
   <project name="platform_system_libfdio" path="system/libfdio" remote="b2g" revision="8fcd25d64f0f67d1a6f7037a4c83ce6d95466770"/>
   <project name="platform/system/netd" path="system/netd" revision="a6531f7befb49b1c81bc0de7e51c5482b308e1c5"/>
   <project name="platform/system/security" path="system/security" revision="ee8068b9e7bfb2770635062fc9c2035be2142bd8"/>
   <project name="platform/system/vold" path="system/vold" revision="42fa2a0f14f965970a4b629a176bbd2666edf017"/>
   <project name="platform/external/curl" path="external/curl" revision="e68addd988448959ea8157c5de637346b4180c33"/>
   <project name="platform/external/icu4c" path="external/icu4c" revision="d3ec7428eb276db43b7ed0544e09344a6014806c"/>
   <project name="platform/system/media" path="system/media" revision="c1332c21c608f4932a6d7e83450411cde53315ef"/>
@@ -140,14 +140,14 @@
   <project name="platform/hardware/qcom/audio" path="hardware/qcom/audio" revision="8d7676dfb68ee0cd069affedd5d1e97316a184ba"/>
   <project name="platform/hardware/qcom/camera" path="hardware/qcom/camera" revision="2a1ded216a91bf62a72b1640cf01ab4998f37028"/>
   <project name="platform/hardware/qcom/display" path="hardware/qcom/display" revision="a74adcf8d88320d936daa8d20ce88ca0107fb916"/>
   <project name="platform/hardware/qcom/gps" path="hardware/qcom/gps" revision="9883ea57b0668d8f60dba025d4522dfa69a1fbfa"/>
   <project name="platform/hardware/qcom/media" path="hardware/qcom/media" revision="a558dc844bf5144fc38603fd8f4df8d9557052a5"/>
   <project name="platform/hardware/qcom/wlan" path="hardware/qcom/wlan" revision="57ee1320ed7b4a1a1274d8f3f6c177cd6b9becb2"/>
   <project name="platform/hardware/ril" path="hardware/ril" revision="12b1977cc704b35f2e9db2bb423fa405348bc2f3"/>
   <project name="platform/system/bluetooth" path="system/bluetooth" revision="985bf15264d865fe7b9c5b45f61c451cbaafa43d"/>
-  <project name="platform/system/core" path="system/core" revision="350eac5403124dacb2a5fd9e28ac290a59fc3b8e"/>
-  <project name="platform_system_nfcd" path="system/nfcd" remote="b2g" revision="13374490fc0c989347448f0b2d6b220adff5e630"/>
+  <project name="platform/system/core" path="system/core" revision="42839aedcf70bf6bc92a3b7ea4a5cc9bf9aef3f9"/>
+  <project name="platform_system_nfcd" path="system/nfcd" remote="b2g" revision="d19dad5844e8803d5e88d1577a2742b4f5cbc467"/>
   <project name="platform/system/qcom" path="system/qcom" revision="63e3f6f176caad587d42bba4c16b66d953fb23c2"/>
   <project name="platform/vendor/qcom-opensource/wlan/prima" path="vendor/qcom/opensource/wlan/prima" revision="d8952a42771045fca73ec600e2b42a4c7129d723"/>
   <project name="platform/vendor/qcom/msm8610" path="device/qcom/msm8610" revision="4c187c1f3a0dffd8e51a961735474ea703535b99"/>
 </manifest>
--- a/b2g/config/flame/sources.xml
+++ b/b2g/config/flame/sources.xml
@@ -12,17 +12,17 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="0e94c080bee081a50aa2097527b0b40852f9143f">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="1eedbee8f26efbaa4a113e002c46f64e9b90249d"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="1d53fb07984298253aad64bfa4236b7167ee3d4d"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2262d4a77d4f46ab230fd747bb91e9b77bad36cb"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="d6a27295acb0a25926bf6290dd2532a7f9027864"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="e95b4ce22c825da44d14299e1190ea39a5260bde"/>
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="471afab478649078ad7c75ec6b252481a59e19b8"/>
@@ -140,13 +140,13 @@
   <project name="platform/hardware/qcom/camera" path="hardware/qcom/camera" revision="5e110615212302c5d798a3c223dcee458817651c"/>
   <project name="platform/hardware/qcom/display" path="hardware/qcom/display" revision="fa9ffd47948eb24466de227e48fe9c4a7c5e7711"/>
   <project name="platform/hardware/qcom/gps" path="hardware/qcom/gps" revision="cd76b19aafd4229ccf83853d02faef8c51ca8b34"/>
   <project name="platform/hardware/qcom/media" path="hardware/qcom/media" revision="8a0d0b0d9889ef99c4c6317c810db4c09295f15a"/>
   <project name="platform/hardware/qcom/wlan" path="hardware/qcom/wlan" revision="2208fa3537ace873b8f9ec2355055761c79dfd5f"/>
   <project name="platform/hardware/ril" path="hardware/ril" revision="c4e2ac95907a5519a0e09f01a0d8e27fec101af0"/>
   <project name="platform/system/bluetooth" path="system/bluetooth" revision="e1eb226fa3ad3874ea7b63c56a9dc7012d7ff3c2"/>
   <project name="platform/system/core" path="system/core" revision="adc485d8755af6a61641d197de7cfef667722580"/>
-  <project name="platform_system_nfcd" path="system/nfcd" remote="b2g" revision="13374490fc0c989347448f0b2d6b220adff5e630"/>
+  <project name="platform_system_nfcd" path="system/nfcd" remote="b2g" revision="d19dad5844e8803d5e88d1577a2742b4f5cbc467"/>
   <project name="platform/system/qcom" path="system/qcom" revision="1cdab258b15258b7f9657da70e6f06ebd5a2fc25"/>
   <project name="platform/vendor/qcom/msm8610" path="device/qcom/msm8610" revision="4ae5df252123591d5b941191790e7abed1bce5a4"/>
   <project name="platform/vendor/qcom-opensource/wlan/prima" path="vendor/qcom/opensource/wlan/prima" revision="ce18b47b4a4f93a581d672bbd5cb6d12fe796ca9"/>
 </manifest>
--- a/b2g/config/gaia.json
+++ b/b2g/config/gaia.json
@@ -1,9 +1,9 @@
 {
     "git": {
-        "git_revision": "1eedbee8f26efbaa4a113e002c46f64e9b90249d", 
+        "git_revision": "1d53fb07984298253aad64bfa4236b7167ee3d4d", 
         "remote": "https://git.mozilla.org/releases/gaia.git", 
         "branch": ""
     }, 
-    "revision": "080bbea403be57fffcbb800eb6f7e2fcd0b4c7d2", 
+    "revision": "08a288892d8f0b41a960104150fba34f113629e6", 
     "repo_path": "integration/gaia-central"
 }
--- a/b2g/config/hamachi/sources.xml
+++ b/b2g/config/hamachi/sources.xml
@@ -12,17 +12,17 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="b2g/ics_strawberry" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="df362ace56338da8173d30d3e09e08c42c1accfa">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="1eedbee8f26efbaa4a113e002c46f64e9b90249d"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="1d53fb07984298253aad64bfa4236b7167ee3d4d"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2262d4a77d4f46ab230fd747bb91e9b77bad36cb"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="d6a27295acb0a25926bf6290dd2532a7f9027864"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
   <project name="platform_bionic" path="bionic" remote="b2g" revision="1a2a32eda22ef2cd18f57f423a5e7b22a105a6f8"/>
   <project name="platform/bootable/recovery" path="bootable/recovery" revision="746bc48f34f5060f90801925dcdd964030c1ab6d"/>
--- a/b2g/config/helix/sources.xml
+++ b/b2g/config/helix/sources.xml
@@ -10,17 +10,17 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <default remote="caf" revision="b2g/ics_strawberry" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="df362ace56338da8173d30d3e09e08c42c1accfa">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="1eedbee8f26efbaa4a113e002c46f64e9b90249d"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="1d53fb07984298253aad64bfa4236b7167ee3d4d"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2262d4a77d4f46ab230fd747bb91e9b77bad36cb"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
   <project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
   <project name="platform_bionic" path="bionic" remote="b2g" revision="1a2a32eda22ef2cd18f57f423a5e7b22a105a6f8"/>
--- a/b2g/config/nexus-4/sources.xml
+++ b/b2g/config/nexus-4/sources.xml
@@ -12,17 +12,17 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="0e94c080bee081a50aa2097527b0b40852f9143f">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="1eedbee8f26efbaa4a113e002c46f64e9b90249d"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="1d53fb07984298253aad64bfa4236b7167ee3d4d"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2262d4a77d4f46ab230fd747bb91e9b77bad36cb"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="d6a27295acb0a25926bf6290dd2532a7f9027864"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="5c45f43419d5582949284eee9cef0c43d866e03b"/>
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="3748b4168e7bd8d46457d4b6786003bc6a5223ce"/>
@@ -112,30 +112,30 @@
   <project name="platform/libnativehelper" path="libnativehelper" revision="4792069e90385889b0638e97ae62c67cdf274e22"/>
   <project name="platform/ndk" path="ndk" revision="7666b97bbaf1d645cdd6b4430a367b7a2bb53369"/>
   <project name="platform/prebuilts/misc" path="prebuilts/misc" revision="f6ab40b3257abc07741188fd173ac392575cc8d2"/>
   <project name="platform/prebuilts/ndk" path="prebuilts/ndk" revision="e52099755d0bd3a579130eefe8e58066cc6c0cb6"/>
   <project name="platform_prebuilts_qemu-kernel" path="prebuilts/qemu-kernel" remote="b2g" revision="02c32feb2fe97037be0ac4dace3a6a5025ac895d"/>
   <project name="platform/prebuilts/sdk" path="prebuilts/sdk" revision="842e33e43a55ea44833b9e23e4d180fa17c843af"/>
   <project name="platform/prebuilts/tools" path="prebuilts/tools" revision="5db24726f0f42124304195a6bdea129039eeeaeb"/>
   <project name="platform/system/bluetooth" path="system/bluetooth" revision="930ae098543881f47eac054677726ee4b998b2f8"/>
-  <project name="platform_system_bluetoothd" path="system/bluetoothd" remote="b2g" revision="dcb7c6ba2c6aec23a76d95094c4cbc17eeca5d44"/>
+  <project name="platform_system_bluetoothd" path="system/bluetoothd" remote="b2g" revision="a3a900615b89cbd67acfb8b750baa43b321ef68b"/>
   <project name="platform_system_core" path="system/core" remote="b2g" revision="542d1f59dc331b472307e5bd043101d14d5a3a3e"/>
   <project name="platform/system/extras" path="system/extras" revision="18c1180e848e7ab8691940481f5c1c8d22c37b3e"/>
   <project name="platform_system_libfdio" path="system/libfdio" remote="b2g" revision="8fcd25d64f0f67d1a6f7037a4c83ce6d95466770"/>
   <project name="platform/system/media" path="system/media" revision="d90b836f66bf1d9627886c96f3a2d9c3007fbb80"/>
   <project name="platform/system/netd" path="system/netd" revision="56112dd7b811301b718d0643a82fd5cac9522073"/>
   <project name="platform/system/security" path="system/security" revision="f48ff68fedbcdc12b570b7699745abb6e7574907"/>
   <project name="platform/system/vold" path="system/vold" revision="8de05d4a52b5a91e7336e6baa4592f945a6ddbea"/>
   <default remote="caf" revision="refs/tags/android-4.3_r2.1" sync-j="4"/>
   <!-- Nexus 4 specific things -->
   <project name="device-mako" path="device/lge/mako" remote="b2g" revision="78d17f0c117f0c66dd55ee8d5c5dde8ccc93ecba"/>
   <project name="device/generic/armv7-a-neon" path="device/generic/armv7-a-neon" revision="3a9a17613cc685aa232432566ad6cc607eab4ec1"/>
   <project name="device/lge/mako-kernel" path="device/lge/mako-kernel" revision="d1729e53d71d711c8fde25eab8728ff2b9b4df0e"/>
-  <project name="platform_system_nfcd" path="system/nfcd" remote="b2g" revision="13374490fc0c989347448f0b2d6b220adff5e630"/>
+  <project name="platform_system_nfcd" path="system/nfcd" remote="b2g" revision="d19dad5844e8803d5e88d1577a2742b4f5cbc467"/>
   <project name="platform/external/libnfc-nci" path="external/libnfc-nci" revision="7d33aaf740bbf6c7c6e9c34a92b371eda311b66b"/>
   <project name="platform/external/wpa_supplicant_8" path="external/wpa_supplicant_8" revision="0e56e450367cd802241b27164a2979188242b95f"/>
   <project name="platform/hardware/broadcom/wlan" path="hardware/broadcom/wlan" revision="0e1929fa3aa38bf9d40e9e953d619fab8164c82e"/>
   <project name="platform/hardware/qcom/audio" path="hardware/qcom/audio" revision="b0a528d839cfd9d170d092fe3743b5252b4243a6"/>
   <project name="platform/hardware/qcom/bt" path="hardware/qcom/bt" revision="380945eaa249a2dbdde0daa4c8adb8ca325edba6"/>
   <project name="platform/hardware/qcom/display" path="hardware/qcom/display" revision="6f3b0272cefaffeaed2a7d2bb8f633059f163ddc"/>
   <project name="platform/hardware/qcom/keymaster" path="hardware/qcom/keymaster" revision="16da8262c997a5a0d797885788a64a0771b26910"/>
   <project name="platform/hardware/qcom/media" path="hardware/qcom/media" revision="689b476ba3eb46c34b81343295fe144a0e81a18e"/>
--- a/b2g/config/wasabi/sources.xml
+++ b/b2g/config/wasabi/sources.xml
@@ -12,17 +12,17 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="ics_chocolate_rb4.2" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="df362ace56338da8173d30d3e09e08c42c1accfa">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="1eedbee8f26efbaa4a113e002c46f64e9b90249d"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="1d53fb07984298253aad64bfa4236b7167ee3d4d"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2262d4a77d4f46ab230fd747bb91e9b77bad36cb"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="d6a27295acb0a25926bf6290dd2532a7f9027864"/>
   <project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
--- a/browser/config/mozconfigs/win64/l10n-mozconfig
+++ b/browser/config/mozconfigs/win64/l10n-mozconfig
@@ -1,9 +1,10 @@
 . "$topsrcdir/browser/config/mozconfigs/common"
+. "$topsrcdir/browser/config/mozconfigs/win64/common-win64"
 
 ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
 ac_add_options --enable-update-packaging
 ac_add_options --with-l10n-base=../../l10n
 ac_add_options --with-windows-version=603
 
 export MOZILLA_OFFICIAL=1
 
--- a/configure.in
+++ b/configure.in
@@ -4101,33 +4101,16 @@ fi
 if test "$BUILDING_RELEASE"; then
   # Override value in defines.sh, if any
   EARLY_BETA_OR_EARLIER=
 elif test "$EARLY_BETA_OR_EARLIER"; then
   AC_DEFINE(EARLY_BETA_OR_EARLIER)
 fi
 AC_SUBST(EARLY_BETA_OR_EARLIER)
 
-# Allow the application to provide a subconfigure script
-if test -f "${srcdir}/${MOZ_BUILD_APP}/configure.in" ; then
-  do_output_subdirs() {
-    if test -n "$_subconfigure_subdirs"; then
-      AC_MSG_ERROR([Cannot specify more than one sub-sub-configure])
-     fi
-    _subconfigure_subdir="$1"
-    _subconfigure_config_args="$ac_configure_args"
-  }
-  tmpscript=`$PYTHON -c 'import os, tempfile; print tempfile.mktemp(prefix="subscript.").replace(os.sep, "/")'` || exit 1
-  m4 "${srcdir}/build/autoconf/subconfigure.m4" \
-     "${srcdir}/build/autoconf/altoptions.m4" \
-     "${srcdir}/${MOZ_BUILD_APP}/configure.in" > $tmpscript
-  . $tmpscript
-  rm -f $tmpscript
-fi
-
 # Allow someone to change MOZ_APP_NAME and MOZ_APP_BASENAME in mozconfig
 MOZ_ARG_WITH_STRING(app-name,
 [--with-app-name=APPNAME sets MOZ_APP_NAME to APPNAME],
 WITH_APP_NAME=$withval,
 )
 
 if test -n "$WITH_APP_NAME" ; then
     MOZ_APP_NAME="$WITH_APP_NAME"
@@ -5959,17 +5942,16 @@ if test -n "$MOZ_ANGLE_RENDERER"; then
           MOZ_DIRECTX_SDK_PATH=
         fi
       else
         AC_MSG_RESULT([Couldn't determine the D3DX9 version for the DirectX SDK.])
         MOZ_DIRECTX_SDK_PATH=
       fi
     else
       AC_MSG_RESULT([Couldn't find an acceptable DirectX SDK for ANGLE, needed for d3dcompiler_43.])
-      AC_MSG_RESULT([  Either ignore, install DirectX SDK (June 2010 version or newer), or reconfigure with --disable-webgl.])
     fi
   fi
 
   ######################################
   # Check that we found what we needed.
   MOZ_FOUND_A_D3D_COMPILER=
   MOZ_FOUND_BOTH_D3D_COMPILERS=1
 
@@ -5985,17 +5967,16 @@ if test -n "$MOZ_ANGLE_RENDERER"; then
     AC_MSG_RESULT([Found d3dcompiler DLL for XP: $MOZ_D3DCOMPILER_XP_DLL])
   else
     MOZ_FOUND_BOTH_D3D_COMPILERS=
   fi
 
   if test -z "$CROSS_COMPILE"; then
     if test -z "MOZ_FOUND_A_D3D_COMPILER"; then
       AC_MSG_ERROR([Couldn't find an acceptable D3D compiler DLL.])
-      AC_MSG_ERROR([  Either install Windows SDK 8.0+, install DirectX SDK (June 2010 version or newer), or reconfigure with --disable-webgl.])
     fi
 
     if test -n "$MOZ_REQUIRE_ALL_D3DCS" -a -z "$MOZ_FOUND_BOTH_D3D_COMPILERS"; then
       AC_MSG_ERROR([Both D3D compilers _43 and _46+ are required by --enable-require-d3d-compilers.])
       AC_MSG_ERROR([  Install Windows SDK 8.0+, as well as DirectX SDK (June 2010 version or newer), or reconfigure without this flag.])
     fi
   fi
 fi
@@ -7252,16 +7233,35 @@ fi # MOZ_MEMORY
 AC_SUBST(MOZ_MEMORY)
 AC_SUBST(MOZ_JEMALLOC3)
 AC_SUBST(MOZ_NATIVE_JEMALLOC)
 AC_SUBST(MOZ_CRT)
 export MOZ_CRT
 AC_SUBST(MOZ_GLUE_IN_PROGRAM)
 AC_SUBST_LIST(WIN32_CRT_LIBS)
 
+# Allow the application to provide a subconfigure script.
+# This should be after 'export MOZ_NO_DEBUG_RTL=1' since
+# ldap/c-sdk/configure refers to the enviroment value.
+if test -f "${srcdir}/${MOZ_BUILD_APP}/configure.in" ; then
+  do_output_subdirs() {
+    if test -n "$_subconfigure_subdirs"; then
+      AC_MSG_ERROR([Cannot specify more than one sub-sub-configure])
+     fi
+    _subconfigure_subdir="$1"
+    _subconfigure_config_args="$ac_configure_args"
+  }
+  tmpscript=`$PYTHON -c 'import os, tempfile; print tempfile.mktemp(prefix="subscript.").replace(os.sep, "/")'` || exit 1
+  m4 "${srcdir}/build/autoconf/subconfigure.m4" \
+     "${srcdir}/build/autoconf/altoptions.m4" \
+     "${srcdir}/${MOZ_BUILD_APP}/configure.in" > $tmpscript
+  . $tmpscript
+  rm -f $tmpscript
+fi
+
 dnl We need to wrap dlopen and related functions on Android because we use
 dnl our own linker.
 if test "$OS_TARGET" = Android; then
     MOZ_GLUE_WRAP_LDFLAGS="${MOZ_GLUE_WRAP_LDFLAGS} -Wl,--wrap=PR_GetEnv,--wrap=PR_SetEnv"
     if test "$MOZ_WIDGET_TOOLKIT" = gonk -a -n "$MOZ_NUWA_PROCESS"; then
         MOZ_GLUE_WRAP_LDFLAGS="${MOZ_GLUE_WRAP_LDFLAGS} -Wl,--wrap=pthread_create,--wrap=epoll_wait,--wrap=poll,--wrap=pthread_cond_timedwait,--wrap=pthread_cond_wait,--wrap=epoll_create,--wrap=epoll_ctl,--wrap=close,--wrap=pthread_key_create,--wrap=pthread_key_delete,--wrap=socketpair,--wrap=pthread_self,--wrap=pthread_mutex_lock,--wrap=pthread_join,--wrap=pipe,--wrap=pipe2"
     fi
     if test "$MOZ_WIDGET_TOOLKIT" = android; then
--- a/dom/base/nsJSUtils.h
+++ b/dom/base/nsJSUtils.h
@@ -12,16 +12,17 @@
  * The goal of the utility functions is to cut down on the size of
  * the generated code itself.
  */
 
 #include "mozilla/Assertions.h"
 
 #include "jsapi.h"
 #include "jsfriendapi.h"
+#include "js/Conversions.h"
 #include "nsString.h"
 
 class nsIScriptContext;
 class nsIScriptGlobalObject;
 
 namespace mozilla {
 namespace dom {
 class AutoJSAPI;
--- a/dom/bindings/BindingUtils.h
+++ b/dom/bindings/BindingUtils.h
@@ -4,16 +4,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_BindingUtils_h__
 #define mozilla_dom_BindingUtils_h__
 
 #include "jsfriendapi.h"
 #include "jswrapper.h"
+#include "js/Conversions.h"
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/Alignment.h"
 #include "mozilla/Array.h"
 #include "mozilla/Assertions.h"
 #include "mozilla/dom/BindingDeclarations.h"
 #include "mozilla/dom/CallbackObject.h"
 #include "mozilla/dom/DOMJSClass.h"
 #include "mozilla/dom/DOMJSProxyHandler.h"
--- a/dom/bindings/PrimitiveConversions.h
+++ b/dom/bindings/PrimitiveConversions.h
@@ -11,16 +11,17 @@
 #ifndef mozilla_dom_PrimitiveConversions_h
 #define mozilla_dom_PrimitiveConversions_h
 
 #include <limits>
 #include <math.h>
 #include <stdint.h>
 
 #include "jsapi.h"
+#include "js/Conversions.h"
 #include "mozilla/Assertions.h"
 #include "mozilla/ErrorResult.h"
 #include "mozilla/FloatingPoint.h"
 
 namespace mozilla {
 namespace dom {
 
 template<typename T>
--- a/dom/bluetooth/bluedroid/BluetoothDaemonHelpers.cpp
+++ b/dom/bluetooth/bluedroid/BluetoothDaemonHelpers.cpp
@@ -1595,17 +1595,17 @@ UnpackPDU(BluetoothDaemonPDU& aPDU, nsDe
   // of 1 ensures we consume the \0 byte. With 'str' pointing to
   // the string in the PDU, we can copy the actual bytes.
 
   const char* str = reinterpret_cast<const char*>(aPDU.Consume(1));
   if (NS_WARN_IF(!str)) {
     return NS_ERROR_ILLEGAL_VALUE; // end of PDU
   }
 
-  const char* end = static_cast<char*>(memchr(str, '\0', aPDU.GetSize()));
+  const char* end = static_cast<char*>(memchr(str, '\0', aPDU.GetSize() + 1));
   if (NS_WARN_IF(!end)) {
     return NS_ERROR_ILLEGAL_VALUE; // no string terminator
   }
 
   ptrdiff_t len = end - str;
 
   const uint8_t* rest = aPDU.Consume(len);
   if (NS_WARN_IF(!rest)) {
--- a/dom/bluetooth2/bluedroid/BluetoothUtils.cpp
+++ b/dom/bluetooth2/bluedroid/BluetoothUtils.cpp
@@ -111,17 +111,17 @@ BroadcastSystemMessage(const nsAString& 
 
   JS::Rooted<JS::Value> value(cx);
   if (aData.type() == BluetoothValue::TnsString) {
     JSString* jsData = JS_NewUCStringCopyN(cx,
                                            aData.get_nsString().BeginReading(),
                                            aData.get_nsString().Length());
     value = STRING_TO_JSVAL(jsData);
   } else if (aData.type() == BluetoothValue::TArrayOfBluetoothNamedValue) {
-    JS::Rooted<JSObject*> obj(cx, JS_NewPlainObject(cx)));
+    JS::Rooted<JSObject*> obj(cx, JS_NewPlainObject(cx));
     if (!obj) {
       BT_WARNING("Failed to new JSObject for system message!");
       return false;
     }
 
     if (!SetJsObject(cx, aData, obj)) {
       BT_WARNING("Failed to set properties of system message!");
       return false;
--- a/dom/canvas/CanvasRenderingContext2D.cpp
+++ b/dom/canvas/CanvasRenderingContext2D.cpp
@@ -63,16 +63,17 @@
 #include "nsIMemoryReporter.h"
 #include "nsStyleUtil.h"
 #include "CanvasImageCache.h"
 
 #include <algorithm>
 
 #include "jsapi.h"
 #include "jsfriendapi.h"
+#include "js/Conversions.h"
 
 #include "mozilla/Alignment.h"
 #include "mozilla/Assertions.h"
 #include "mozilla/CheckedInt.h"
 #include "mozilla/DebugOnly.h"
 #include "mozilla/dom/ContentParent.h"
 #include "mozilla/dom/ImageData.h"
 #include "mozilla/dom/PBrowserParent.h"
@@ -4815,20 +4816,20 @@ CanvasRenderingContext2D::GetImageData(J
     return nullptr;
   }
 
   if (!aSw || !aSh) {
     error.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
     return nullptr;
   }
 
-  int32_t x = JS_DoubleToInt32(aSx);
-  int32_t y = JS_DoubleToInt32(aSy);
-  int32_t wi = JS_DoubleToInt32(aSw);
-  int32_t hi = JS_DoubleToInt32(aSh);
+  int32_t x = JS::ToInt32(aSx);
+  int32_t y = JS::ToInt32(aSy);
+  int32_t wi = JS::ToInt32(aSw);
+  int32_t hi = JS::ToInt32(aSh);
 
   // Handle negative width and height by flipping the rectangle over in the
   // relevant direction.
   uint32_t w, h;
   if (aSw < 0) {
     w = -wi;
     x -= w;
   } else {
@@ -5011,39 +5012,39 @@ CanvasRenderingContext2D::FillRuleChange
 void
 CanvasRenderingContext2D::PutImageData(ImageData& imageData, double dx,
                                        double dy, ErrorResult& error)
 {
   dom::Uint8ClampedArray arr;
   DebugOnly<bool> inited = arr.Init(imageData.GetDataObject());
   MOZ_ASSERT(inited);
 
-  error = PutImageData_explicit(JS_DoubleToInt32(dx), JS_DoubleToInt32(dy),
+  error = PutImageData_explicit(JS::ToInt32(dx), JS::ToInt32(dy),
                                 imageData.Width(), imageData.Height(),
                                 &arr, false, 0, 0, 0, 0);
 }
 
 void
 CanvasRenderingContext2D::PutImageData(ImageData& imageData, double dx,
                                        double dy, double dirtyX,
                                        double dirtyY, double dirtyWidth,
                                        double dirtyHeight,
                                        ErrorResult& error)
 {
   dom::Uint8ClampedArray arr;
   DebugOnly<bool> inited = arr.Init(imageData.GetDataObject());
   MOZ_ASSERT(inited);
 
-  error = PutImageData_explicit(JS_DoubleToInt32(dx), JS_DoubleToInt32(dy),
+  error = PutImageData_explicit(JS::ToInt32(dx), JS::ToInt32(dy),
                                 imageData.Width(), imageData.Height(),
                                 &arr, true,
-                                JS_DoubleToInt32(dirtyX),
-                                JS_DoubleToInt32(dirtyY),
-                                JS_DoubleToInt32(dirtyWidth),
-                                JS_DoubleToInt32(dirtyHeight));
+                                JS::ToInt32(dirtyX),
+                                JS::ToInt32(dirtyY),
+                                JS::ToInt32(dirtyWidth),
+                                JS::ToInt32(dirtyHeight));
 }
 
 // void putImageData (in ImageData d, in float x, in float y);
 // void putImageData (in ImageData d, in double x, in double y, in double dirtyX, in double dirtyY, in double dirtyWidth, in double dirtyHeight);
 
 nsresult
 CanvasRenderingContext2D::PutImageData_explicit(int32_t x, int32_t y, uint32_t w, uint32_t h,
                                                 dom::Uint8ClampedArray* aArray,
@@ -5201,18 +5202,18 @@ already_AddRefed<ImageData>
 CanvasRenderingContext2D::CreateImageData(JSContext* cx, double sw,
                                           double sh, ErrorResult& error)
 {
   if (!sw || !sh) {
     error.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
     return nullptr;
   }
 
-  int32_t wi = JS_DoubleToInt32(sw);
-  int32_t hi = JS_DoubleToInt32(sh);
+  int32_t wi = JS::ToInt32(sw);
+  int32_t hi = JS::ToInt32(sh);
 
   uint32_t w = Abs(wi);
   uint32_t h = Abs(hi);
   return mozilla::dom::CreateImageData(cx, this, w, h, error);
 }
 
 already_AddRefed<ImageData>
 CanvasRenderingContext2D::CreateImageData(JSContext* cx,
--- a/dom/events/Event.h
+++ b/dom/events/Event.h
@@ -27,16 +27,22 @@ class nsPresContext;
 namespace mozilla {
 namespace dom {
 
 class EventTarget;
 class WantsPopupControlCheck;
 #define GENERATED_EVENT(EventClass_) class EventClass_;
 #include "mozilla/dom/GeneratedEventList.h"
 #undef GENERATED_EVENT
+// ExtendableEvent and InstallEvent are ServiceWorker events that are not
+// autogenerated since they have some extra methods.
+namespace workers {
+class ExtendableEvent;
+class InstallEvent;
+} // namespace workers
 
 // Dummy class so we can cast through it to get from nsISupports to
 // Event subclasses with only two non-ambiguous static casts.
 class EventBase : public nsIDOMEvent
 {
 };
 
 class Event : public EventBase,
@@ -99,16 +105,28 @@ public:
 #define GENERATED_EVENT(EventClass_) \
   virtual EventClass_* As##EventClass_()  \
   {                                       \
     return nullptr;                       \
   }
 #include "mozilla/dom/GeneratedEventList.h"
 #undef GENERATED_EVENT
 
+  // ExtendableEvent and InstallEvent are ServiceWorker events that are not
+  // autogenerated since they have some extra methods.
+  virtual workers::ExtendableEvent* AsExtendableEvent()
+  {
+    return nullptr;
+  }
+
+  virtual workers::InstallEvent* AsInstallEvent()
+  {
+    return nullptr;
+  }
+
   // nsIDOMEvent Interface
   NS_DECL_NSIDOMEVENT
 
   void InitPresContextData(nsPresContext* aPresContext);
 
   // Returns true if the event should be trusted.
   bool Init(EventTarget* aGlobal);
 
--- a/dom/media/eme/CDMProxy.cpp
+++ b/dom/media/eme/CDMProxy.cpp
@@ -410,16 +410,17 @@ CDMProxy::OnResolveLoadSessionPromise(ui
 }
 
 static dom::MediaKeyMessageType
 ToMediaKeyMessageType(GMPSessionMessageType aMessageType) {
   switch (aMessageType) {
     case kGMPLicenseRequest: return dom::MediaKeyMessageType::License_request;
     case kGMPLicenseRenewal: return dom::MediaKeyMessageType::License_renewal;
     case kGMPLicenseRelease: return dom::MediaKeyMessageType::License_release;
+    case kGMPIndividualizationRequest: return dom::MediaKeyMessageType::Individualization_request;
     default: return dom::MediaKeyMessageType::License_request;
   };
 };
 
 void
 CDMProxy::OnSessionMessage(const nsAString& aSessionId,
                            GMPSessionMessageType aMessageType,
                            nsTArray<uint8_t>& aMessage)
--- a/dom/media/fmp4/MP4Stream.cpp
+++ b/dom/media/fmp4/MP4Stream.cpp
@@ -23,22 +23,25 @@ MP4Stream::~MP4Stream()
   MOZ_ASSERT(mPinCount == 0);
 }
 
 bool
 MP4Stream::BlockingReadIntoCache(int64_t aOffset, size_t aCount, Monitor* aToUnlock)
 {
   MOZ_ASSERT(mPinCount > 0);
   CacheBlock block(aOffset, aCount);
+  if (!block.Init()) {
+    return false;
+  }
 
   uint32_t sum = 0;
   uint32_t bytesRead = 0;
   do {
     uint64_t offset = aOffset + sum;
-    char* buffer = reinterpret_cast<char*>(block.mBuffer.get()) + sum;
+    char* buffer = block.Buffer() + sum;
     uint32_t toRead = aCount - sum;
     MonitorAutoUnlock unlock(*aToUnlock);
     nsresult rv = mResource->ReadAt(offset, buffer, toRead, &bytesRead);
     if (NS_FAILED(rv)) {
       return false;
     }
     sum += bytesRead;
   } while (sum < aCount && bytesRead > 0);
@@ -71,17 +74,17 @@ MP4Stream::ReadAt(int64_t aOffset, void*
 
 bool
 MP4Stream::CachedReadAt(int64_t aOffset, void* aBuffer, size_t aCount,
                         size_t* aBytesRead)
 {
   // First, check our local cache.
   for (size_t i = 0; i < mCache.Length(); ++i) {
     if (mCache[i].mOffset == aOffset && mCache[i].mCount >= aCount) {
-      memcpy(aBuffer, mCache[i].mBuffer, aCount);
+      memcpy(aBuffer, mCache[i].Buffer(), aCount);
       *aBytesRead = aCount;
       return true;
     }
   }
 
   nsresult rv = mResource->ReadFromCache(reinterpret_cast<char*>(aBuffer),
                                          aOffset, aCount);
   if (NS_FAILED(rv)) {
--- a/dom/media/fmp4/MP4Stream.h
+++ b/dom/media/fmp4/MP4Stream.h
@@ -6,16 +6,17 @@
 
 #ifndef MP4_STREAM_H_
 #define MP4_STREAM_H_
 
 #include "mp4_demuxer/mp4_demuxer.h"
 
 #include "MediaResource.h"
 
+#include "mozilla/fallible.h"
 #include "mozilla/Maybe.h"
 #include "mozilla/Monitor.h"
 
 namespace mozilla {
 
 class Monitor;
 
 class MP4Stream : public mp4_demuxer::Stream {
@@ -65,19 +66,33 @@ public:
 
 private:
   nsRefPtr<MediaResource> mResource;
   Maybe<ReadRecord> mFailedRead;
   uint32_t mPinCount;
 
   struct CacheBlock {
     CacheBlock(int64_t aOffset, size_t aCount)
-      : mOffset(aOffset), mCount(aCount), mBuffer(new uint8_t[aCount]) {}
+      : mOffset(aOffset), mCount(aCount), mBuffer(nullptr) {}
     int64_t mOffset;
     size_t mCount;
-    nsAutoArrayPtr<uint8_t> mBuffer;
+
+    bool Init()
+    {
+      mBuffer = new ((fallible_t())) char[mCount];
+      return !!mBuffer;
+    }
+
+    char* Buffer()
+    {
+      MOZ_ASSERT(mBuffer.get());
+      return mBuffer.get();
+    }
+
+  private:
+    nsAutoArrayPtr<char> mBuffer;
   };
   nsTArray<CacheBlock> mCache;
 };
 
 }
 
 #endif
--- a/dom/media/gmp-plugin/fake.info
+++ b/dom/media/gmp-plugin/fake.info
@@ -1,5 +1,5 @@
 Name: fake
 Description: Fake GMP Plugin
 Version: 1.0
-APIs: encode-video[h264], decode-video[h264], eme-decrypt-v3[fake]
+APIs: encode-video[h264], decode-video[h264], eme-decrypt-v4[fake]
 Libraries: dxva2.dll
--- a/dom/media/gmp/gmp-api/gmp-decryption.h
+++ b/dom/media/gmp/gmp-api/gmp-decryption.h
@@ -67,17 +67,18 @@ enum GMPDOMException {
   kGMPQuotaExceededError = 22,
   kGMPTimeoutError = 23
 };
 
 enum GMPSessionMessageType {
   kGMPLicenseRequest = 0,
   kGMPLicenseRenewal = 1,
   kGMPLicenseRelease = 2,
-  kGMPMessageInvalid = 3 // Must always be last.
+  kGMPIndividualizationRequest = 3,
+  kGMPMessageInvalid = 4 // Must always be last.
 };
 
 // Time in milliseconds, as offset from epoch, 1 Jan 1970.
 typedef int64_t GMPTimestamp;
 
 // Capability definitions. The capabilities of the EME GMP are reported
 // to Gecko by calling the GMPDecryptorCallback::SetCapabilities()
 // callback and specifying the logical OR of the GMP_EME_CAP_* flags below.
@@ -214,17 +215,17 @@ public:
 };
 
 enum GMPSessionType {
   kGMPTemporySession = 0,
   kGMPPersistentSession = 1,
   kGMPSessionInvalid = 2 // Must always be last.
 };
 
-#define GMP_API_DECRYPTOR "eme-decrypt-v3"
+#define GMP_API_DECRYPTOR "eme-decrypt-v4"
 
 // API exposed by plugin library to manage decryption sessions.
 // When the Host requests this by calling GMPGetAPIFunc().
 //
 // API name macro: GMP_API_DECRYPTOR
 // Host API: GMPDecryptorHost
 class GMPDecryptor {
 public:
--- a/dom/media/gstreamer/GStreamerReader.h
+++ b/dom/media/gstreamer/GStreamerReader.h
@@ -36,36 +36,36 @@ class AbstractMediaDecoder;
 class GStreamerReader : public MediaDecoderReader
 {
   typedef gfx::IntRect IntRect;
 
 public:
   explicit GStreamerReader(AbstractMediaDecoder* aDecoder);
   virtual ~GStreamerReader();
 
-  virtual nsresult Init(MediaDecoderReader* aCloneDonor);
-  virtual nsresult ResetDecode();
-  virtual bool DecodeAudioData();
+  virtual nsresult Init(MediaDecoderReader* aCloneDonor) MOZ_OVERRIDE;
+  virtual nsresult ResetDecode() MOZ_OVERRIDE;
+  virtual bool DecodeAudioData() MOZ_OVERRIDE;
   virtual bool DecodeVideoFrame(bool &aKeyframeSkip,
-                                int64_t aTimeThreshold);
+                                int64_t aTimeThreshold) MOZ_OVERRIDE;
   virtual nsresult ReadMetadata(MediaInfo* aInfo,
-                                MetadataTags** aTags);
+                                MetadataTags** aTags) MOZ_OVERRIDE;
   virtual nsRefPtr<SeekPromise>
   Seek(int64_t aTime, int64_t aEndTime) MOZ_OVERRIDE;
-  virtual nsresult GetBuffered(dom::TimeRanges* aBuffered);
+  virtual nsresult GetBuffered(dom::TimeRanges* aBuffered) MOZ_OVERRIDE;
 
   virtual void NotifyDataArrived(const char *aBuffer,
                                  uint32_t aLength,
                                  int64_t aOffset) MOZ_OVERRIDE;
 
-  virtual bool HasAudio() {
+  virtual bool HasAudio() MOZ_OVERRIDE {
     return mInfo.HasAudio();
   }
 
-  virtual bool HasVideo() {
+  virtual bool HasVideo() MOZ_OVERRIDE {
     return mInfo.HasVideo();
   }
 
   layers::ImageContainer* GetImageContainer() { return mDecoder->GetImageContainer(); }
 
   virtual bool IsMediaSeekable() MOZ_OVERRIDE;
 
 private:
--- a/dom/plugins/ipc/PluginModuleParent.h
+++ b/dom/plugins/ipc/PluginModuleParent.h
@@ -226,17 +226,17 @@ protected:
     virtual nsresult BeginUpdateBackground(NPP instance,
                                            const nsIntRect& aRect,
                                            gfxContext** aCtx) MOZ_OVERRIDE;
     virtual nsresult EndUpdateBackground(NPP instance,
                                          gfxContext* aCtx,
                                          const nsIntRect& aRect) MOZ_OVERRIDE;
 
 #if defined(XP_UNIX) && !defined(XP_MACOSX) && !defined(MOZ_WIDGET_GONK)
-    virtual nsresult NP_Initialize(NPNetscapeFuncs* bFuncs, NPPluginFuncs* pFuncs, NPError* error);
+    virtual nsresult NP_Initialize(NPNetscapeFuncs* bFuncs, NPPluginFuncs* pFuncs, NPError* error) MOZ_OVERRIDE;
 #else
     virtual nsresult NP_Initialize(NPNetscapeFuncs* bFuncs, NPError* error) MOZ_OVERRIDE;
 #endif
     virtual nsresult NP_Shutdown(NPError* error) MOZ_OVERRIDE;
 
     virtual nsresult NP_GetMIMEDescription(const char** mimeDesc) MOZ_OVERRIDE;
     virtual nsresult NP_GetValue(void *future, NPPVariable aVariable,
                                  void *aValue, NPError* error) MOZ_OVERRIDE;
--- a/dom/system/gonk/AutoMounter.cpp
+++ b/dom/system/gonk/AutoMounter.cpp
@@ -101,16 +101,17 @@ namespace system {
 #define SYS_USB_CONFIG          "sys.usb.config"
 #define PERSIST_SYS_USB_CONFIG  "persist.sys.usb.config"
 
 #define USB_FUNC_ADB    "adb"
 #define USB_FUNC_MTP    "mtp"
 #define USB_FUNC_NONE   "none"
 #define USB_FUNC_RNDIS  "rndis"
 #define USB_FUNC_UMS    "mass_storage"
+#define USB_FUNC_DEFAULT    "default"
 
 class AutoMounter;
 
 static void SetAutoMounterStatus(int32_t aStatus);
 
 /***************************************************************************/
 
 inline const char* SwitchStateStr(const SwitchEvent& aEvent)
@@ -547,16 +548,19 @@ SetUsbFunction(const char* aUsbFunc)
 
   if (strcmp(aUsbFunc, USB_FUNC_MTP) == 0) {
     // We're enabling MTP. For this we'll wind up using mtp, or mtp,adb
     strlcpy(newSysUsbConfig, USB_FUNC_MTP, sizeof(newSysUsbConfig));
   } else if (strcmp(aUsbFunc, USB_FUNC_UMS) == 0) {
     // We're enabling UMS. For this we make the assumption that the persisted
     // property has mass_storage enabled.
     property_get(PERSIST_SYS_USB_CONFIG, newSysUsbConfig, "");
+  } else if (strcmp(aUsbFunc, USB_FUNC_DEFAULT) == 0) {
+    // Set the property as PERSIST_SYS_USB_CONFIG
+    property_get(PERSIST_SYS_USB_CONFIG, newSysUsbConfig, "");
   } else {
     printf_stderr("AutoMounter::SetUsbFunction Unrecognized aUsbFunc '%s'\n", aUsbFunc);
     MOZ_ASSERT(0);
     return;
   }
 
   // Make sure the new value that we write into sys.usb.config keeps the adb
   // (or non-adb) of the current string.
@@ -621,16 +625,17 @@ AutoMounter::StartMtpServer()
     LOG("Sleeping...");
     sleep(1);
   }
   LOG("Sleep done");
 #endif
 
   sMozMtpServer = new MozMtpServer();
   if (!sMozMtpServer->Init()) {
+    sMozMtpServer = nullptr;
     return false;
   }
 
   VolumeArray::index_type volIndex;
   VolumeArray::size_type  numVolumes = VolumeManager::NumVolumes();
   for (volIndex = 0; volIndex < numVolumes; volIndex++) {
     RefPtr<Volume> vol = VolumeManager::GetVolume(volIndex);
     nsRefPtr<MozMtpStorage> storage = new MozMtpStorage(vol, sMozMtpServer);
@@ -781,19 +786,25 @@ AutoMounter::UpdateState()
         if (mtpConfigured) {
           // The USB layer has already been configured. Now we can go ahead
           // and start the MTP server. This particular codepath will not
           // normally be taken, but it could happen if you stop and restart
           // b2g while sys.usb.config is set to enable mtp.
           if (StartMtpServer()) {
             SetState(STATE_MTP_STARTED);
           } else {
-            // Unable to start MTP. Go back to UMS.
-            SetUsbFunction(USB_FUNC_UMS);
-            SetState(STATE_UMS_CONFIGURING);
+            if (umsAvail) {
+              // Unable to start MTP. Go back to UMS.
+              LOG("UpdateState: StartMtpServer failed, switch to UMS");
+              SetUsbFunction(USB_FUNC_UMS);
+              SetState(STATE_UMS_CONFIGURING);
+            } else {
+              LOG("UpdateState: StartMtpServer failed, keep idle state");
+              SetUsbFunction(USB_FUNC_DEFAULT);
+            }
           }
         } else {
           // We need to configure USB to use mtp. Wait for it to be configured
           // before we start the MTP server.
           SetUsbFunction(USB_FUNC_MTP);
           SetState(STATE_MTP_CONFIGURING);
         }
       } else if (umsConfigured) {
@@ -844,16 +855,20 @@ AutoMounter::UpdateState()
         break;
       }
       if (umsAvail) {
         // Switch back to UMS
         SetUsbFunction(USB_FUNC_UMS);
         SetState(STATE_UMS_CONFIGURING);
         break;
       }
+
+      // if ums/rndis is not available and mtp is disable,
+      // restore the usb function as PERSIST_SYS_USB_CONFIG.
+      SetUsbFunction(USB_FUNC_DEFAULT);
       SetState(STATE_IDLE);
       break;
 
     case STATE_UMS_CONFIGURING:
       // While configuring, the USB configuration state will change from
       // CONFIGURED -> CONNECTED -> DISCONNECTED -> CONNECTED -> CONFIGURED
       // so we don't check for cable unplugged here. However, having said
       // that, we'll often sit in this state while the cable is unplugged,
--- a/dom/system/gonk/MozMtpServer.cpp
+++ b/dom/system/gonk/MozMtpServer.cpp
@@ -227,17 +227,17 @@ MozMtpServer::GetMozMtpDatabase()
 bool
 MozMtpServer::Init()
 {
   MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop());
 
   const char *mtpUsbFilename = "/dev/mtp_usb";
   mMtpUsbFd = open(mtpUsbFilename, O_RDWR);
   if (mMtpUsbFd.get() < 0) {
-    MTP_ERR("open of '%s' failed", mtpUsbFilename);
+    MTP_ERR("open of '%s' failed((%s))", mtpUsbFilename, strerror(errno));
     return false;
   }
   MTP_LOG("Opened '%s' fd %d", mtpUsbFilename, mMtpUsbFd.get());
 
   mMozMtpDatabase = new MozMtpDatabase();
   mMtpServer = new RefCountedMtpServer(mMtpUsbFd.get(),        // fd
                                        mMozMtpDatabase.get(), // MtpDatabase
                                        false,                 // ptp?
--- a/dom/webidl/InstallEvent.webidl
+++ b/dom/webidl/InstallEvent.webidl
@@ -11,11 +11,11 @@
  Exposed=ServiceWorker]
 interface InstallEvent : ExtendableEvent {
   readonly attribute ServiceWorker? activeWorker;
   void replace();
 };
 
 // Should be in the spec soon to satisfy conventions about events.
 // https://github.com/slightlyoff/ServiceWorker/issues/216.
-dictionary InstallEventInit : EventInit {
+dictionary InstallEventInit : ExtendableEventInit {
   ServiceWorker? activeWorker = null;
 };
--- a/dom/webidl/MediaKeyMessageEvent.webidl
+++ b/dom/webidl/MediaKeyMessageEvent.webidl
@@ -8,17 +8,18 @@
  *
  * Copyright © 2014 W3C® (MIT, ERCIM, Keio, Beihang), All Rights Reserved.
  * W3C liability, trademark and document use rules apply.
  */
 
 enum MediaKeyMessageType {
   "license-request",
   "license-renewal",
-  "license-release"
+  "license-release",
+  "individualization-request"
 };
 
 [Pref="media.eme.enabled", Constructor(DOMString type, optional MediaKeyMessageEventInit eventInitDict)]
 interface MediaKeyMessageEvent : Event {
   readonly attribute MediaKeyMessageType messageType;
   [Throws]
   readonly attribute ArrayBuffer message;
 };
--- a/dom/webidl/MozNFCTag.webidl
+++ b/dom/webidl/MozNFCTag.webidl
@@ -14,17 +14,18 @@
 enum NFCTechType {
   "NFC-A",  // NFCForum-TS-DigitalProtocol-1.1 NFC-A.
   "NFC-B",  // NFCForum-TS-DigitalProtocol-1.1 NFC-B.
   "NFC-F",  // NFCForum-TS-DigitalProtocol-1.1 NFC-F.
   "NFC-V",  // ISO 15693.
   "ISO-DEP",  // NFCForum-TS-DigitalProtocol-1.1 ISO-DEP.
   "MIFARE-Classic",  // MIFARE Classic from NXP.
   "MIFARE-Ultralight",  // MIFARE Ultralight from NXP.
-  "NFC-Barcode" // NFC Barcode from Kovio.
+  "NFC-Barcode", // NFC Barcode from Kovio.
+  "Unknown"
 };
 
 /**
  * The enumeration of the types of the tag, the type of a tag could be either
  * one of those types defined in NFC Forum Tag Types (Type1 ~ Type 4), or it
  * could be a NXP-specific tag, like MIFARE Classic.
  */
 enum NFCTagType {
--- a/dom/webidl/SVGClipPathElement.webidl
+++ b/dom/webidl/SVGClipPathElement.webidl
@@ -6,14 +6,16 @@
  * The origin of this IDL file is
  * http://www.w3.org/TR/SVG2/
  *
  * Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
  * liability, trademark and document use rules apply.
  */
 
 interface SVGClipPathElement : SVGElement {
+  [Constant]
   readonly attribute SVGAnimatedEnumeration clipPathUnits;
+  [Constant]
   readonly attribute SVGAnimatedTransformList transform;
 };
 
 SVGClipPathElement implements SVGUnitTypes;
 
--- a/dom/webidl/SVGComponentTransferFunctionElement.webidl
+++ b/dom/webidl/SVGComponentTransferFunctionElement.webidl
@@ -14,16 +14,23 @@ interface SVGComponentTransferFunctionEl
   // Component Transfer Types
   const unsigned short SVG_FECOMPONENTTRANSFER_TYPE_UNKNOWN = 0;
   const unsigned short SVG_FECOMPONENTTRANSFER_TYPE_IDENTITY = 1;
   const unsigned short SVG_FECOMPONENTTRANSFER_TYPE_TABLE = 2;
   const unsigned short SVG_FECOMPONENTTRANSFER_TYPE_DISCRETE = 3;
   const unsigned short SVG_FECOMPONENTTRANSFER_TYPE_LINEAR = 4;
   const unsigned short SVG_FECOMPONENTTRANSFER_TYPE_GAMMA = 5;
 
+  [Constant]
   readonly attribute SVGAnimatedEnumeration type;
+  [Constant]
   readonly attribute SVGAnimatedNumberList tableValues;
+  [Constant]
   readonly attribute SVGAnimatedNumber slope;
+  [Constant]
   readonly attribute SVGAnimatedNumber intercept;
+  [Constant]
   readonly attribute SVGAnimatedNumber amplitude;
+  [Constant]
   readonly attribute SVGAnimatedNumber exponent;
+  [Constant]
   readonly attribute SVGAnimatedNumber offset;
 };
--- a/dom/webidl/SVGDocument.webidl
+++ b/dom/webidl/SVGDocument.webidl
@@ -5,11 +5,11 @@
  *
  * The origin of this IDL file is:
  * dom/interfaces/svg/nsIDOMSVGDocument.idl
  */
 
 interface SVGDocument : Document {
   [Throws]
   readonly attribute DOMString domain;
-  [Throws]
+  [Pure, Throws]
   readonly attribute SVGElement? rootElement;
 };
--- a/dom/webidl/SVGElement.webidl
+++ b/dom/webidl/SVGElement.webidl
@@ -10,16 +10,17 @@
  * liability, trademark and document use rules apply.
  */
 
 interface SVGElement : Element {
            attribute DOMString id;
 /*           [SetterThrows]
            attribute DOMString xmlbase; */
 
+  [Constant]
   readonly attribute SVGAnimatedString className;
   [PutForwards=cssText, Constant]
   readonly attribute CSSStyleDeclaration style;
 
   /*[SetterThrows]
   attribute DOMString xmllang;
   [SetterThrows]
   attribute DOMString xmlspace;*/
--- a/dom/webidl/SVGFEBlendElement.webidl
+++ b/dom/webidl/SVGFEBlendElement.webidl
@@ -25,14 +25,17 @@ interface SVGFEBlendElement : SVGElement
   const unsigned short SVG_FEBLEND_MODE_HARD_LIGHT = 9;
   const unsigned short SVG_FEBLEND_MODE_SOFT_LIGHT = 10;
   const unsigned short SVG_FEBLEND_MODE_DIFFERENCE = 11;
   const unsigned short SVG_FEBLEND_MODE_EXCLUSION = 12;
   const unsigned short SVG_FEBLEND_MODE_HUE = 13;
   const unsigned short SVG_FEBLEND_MODE_SATURATION = 14;
   const unsigned short SVG_FEBLEND_MODE_COLOR = 15;
   const unsigned short SVG_FEBLEND_MODE_LUMINOSITY = 16;
+  [Constant]
   readonly attribute SVGAnimatedString in1;
+  [Constant]
   readonly attribute SVGAnimatedString in2;
+  [Constant]
   readonly attribute SVGAnimatedEnumeration mode;
 };
 
 SVGFEBlendElement implements SVGFilterPrimitiveStandardAttributes;
--- a/dom/webidl/SVGFEColorMatrixElement.webidl
+++ b/dom/webidl/SVGFEColorMatrixElement.webidl
@@ -14,14 +14,17 @@ interface SVGFEColorMatrixElement : SVGE
 
   // Color Matrix Types
   const unsigned short SVG_FECOLORMATRIX_TYPE_UNKNOWN = 0;
   const unsigned short SVG_FECOLORMATRIX_TYPE_MATRIX = 1;
   const unsigned short SVG_FECOLORMATRIX_TYPE_SATURATE = 2;
   const unsigned short SVG_FECOLORMATRIX_TYPE_HUEROTATE = 3;
   const unsigned short SVG_FECOLORMATRIX_TYPE_LUMINANCETOALPHA = 4;
 
+  [Constant]
   readonly attribute SVGAnimatedString in1;
+  [Constant]
   readonly attribute SVGAnimatedEnumeration type;
+  [Constant]
   readonly attribute SVGAnimatedNumberList values;
 };
 
 SVGFEColorMatrixElement implements SVGFilterPrimitiveStandardAttributes;
--- a/dom/webidl/SVGFEComponentTransferElement.webidl
+++ b/dom/webidl/SVGFEComponentTransferElement.webidl
@@ -6,12 +6,13 @@
  * The origin of this IDL file is
  * http://www.w3.org/TR/SVG2/
  *
  * Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
  * liability, trademark and document use rules apply.
  */
 
 interface SVGFEComponentTransferElement : SVGElement {
+  [Constant]
   readonly attribute SVGAnimatedString in1;
 };
 
 SVGFEComponentTransferElement implements SVGFilterPrimitiveStandardAttributes;
--- a/dom/webidl/SVGFECompositeElement.webidl
+++ b/dom/webidl/SVGFECompositeElement.webidl
@@ -16,18 +16,25 @@ interface SVGFECompositeElement : SVGEle
   const unsigned short SVG_FECOMPOSITE_OPERATOR_UNKNOWN = 0;
   const unsigned short SVG_FECOMPOSITE_OPERATOR_OVER = 1;
   const unsigned short SVG_FECOMPOSITE_OPERATOR_IN = 2;
   const unsigned short SVG_FECOMPOSITE_OPERATOR_OUT = 3;
   const unsigned short SVG_FECOMPOSITE_OPERATOR_ATOP = 4;
   const unsigned short SVG_FECOMPOSITE_OPERATOR_XOR = 5;
   const unsigned short SVG_FECOMPOSITE_OPERATOR_ARITHMETIC = 6;
 
+  [Constant]
   readonly attribute SVGAnimatedString in1;
+  [Constant]
   readonly attribute SVGAnimatedString in2;
+  [Constant]
   readonly attribute SVGAnimatedEnumeration operator;
+  [Constant]
   readonly attribute SVGAnimatedNumber k1;
+  [Constant]
   readonly attribute SVGAnimatedNumber k2;
+  [Constant]
   readonly attribute SVGAnimatedNumber k3;
+  [Constant]
   readonly attribute SVGAnimatedNumber k4;
 };
 
 SVGFECompositeElement implements SVGFilterPrimitiveStandardAttributes;
--- a/dom/webidl/SVGFEConvolveMatrixElement.webidl
+++ b/dom/webidl/SVGFEConvolveMatrixElement.webidl
@@ -13,23 +13,35 @@
 interface SVGFEConvolveMatrixElement : SVGElement {
 
   // Edge Mode Values
   const unsigned short SVG_EDGEMODE_UNKNOWN = 0;
   const unsigned short SVG_EDGEMODE_DUPLICATE = 1;
   const unsigned short SVG_EDGEMODE_WRAP = 2;
   const unsigned short SVG_EDGEMODE_NONE = 3;
 
+  [Constant]
   readonly attribute SVGAnimatedString in1;
+  [Constant]
   readonly attribute SVGAnimatedInteger orderX;
+  [Constant]
   readonly attribute SVGAnimatedInteger orderY;
+  [Constant]
   readonly attribute SVGAnimatedNumberList kernelMatrix;
+  [Constant]
   readonly attribute SVGAnimatedNumber divisor;
+  [Constant]
   readonly attribute SVGAnimatedNumber bias;
+  [Constant]
   readonly attribute SVGAnimatedInteger targetX;
+  [Constant]
   readonly attribute SVGAnimatedInteger targetY;
+  [Constant]
   readonly attribute SVGAnimatedEnumeration edgeMode;
+  [Constant]
   readonly attribute SVGAnimatedNumber kernelUnitLengthX;
+  [Constant]
   readonly attribute SVGAnimatedNumber kernelUnitLengthY;
+  [Constant]
   readonly attribute SVGAnimatedBoolean preserveAlpha;
 };
 
 SVGFEConvolveMatrixElement implements SVGFilterPrimitiveStandardAttributes;
--- a/dom/webidl/SVGFEDiffuseLightingElement.webidl
+++ b/dom/webidl/SVGFEDiffuseLightingElement.webidl
@@ -6,16 +6,21 @@
  * The origin of this IDL file is
  * http://www.w3.org/TR/SVG2/
  *
  * Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
  * liability, trademark and document use rules apply.
  */
 
 interface SVGFEDiffuseLightingElement : SVGElement {
+  [Constant]
   readonly attribute SVGAnimatedString in1;
+  [Constant]
   readonly attribute SVGAnimatedNumber surfaceScale;
+  [Constant]
   readonly attribute SVGAnimatedNumber diffuseConstant;
+  [Constant]
   readonly attribute SVGAnimatedNumber kernelUnitLengthX;
+  [Constant]
   readonly attribute SVGAnimatedNumber kernelUnitLengthY;
 };
 
 SVGFEDiffuseLightingElement implements SVGFilterPrimitiveStandardAttributes;
--- a/dom/webidl/SVGFEDisplacementMapElement.webidl
+++ b/dom/webidl/SVGFEDisplacementMapElement.webidl
@@ -14,16 +14,21 @@ interface SVGFEDisplacementMapElement : 
 
   // Channel Selectors
   const unsigned short SVG_CHANNEL_UNKNOWN = 0;
   const unsigned short SVG_CHANNEL_R = 1;
   const unsigned short SVG_CHANNEL_G = 2;
   const unsigned short SVG_CHANNEL_B = 3;
   const unsigned short SVG_CHANNEL_A = 4;
 
+  [Constant]
   readonly attribute SVGAnimatedString in1;
+  [Constant]
   readonly attribute SVGAnimatedString in2;
+  [Constant]
   readonly attribute SVGAnimatedNumber scale;
+  [Constant]
   readonly attribute SVGAnimatedEnumeration xChannelSelector;
+  [Constant]
   readonly attribute SVGAnimatedEnumeration yChannelSelector;
 };
 
 SVGFEDisplacementMapElement implements SVGFilterPrimitiveStandardAttributes;
--- a/dom/webidl/SVGFEDistantLightElement.webidl
+++ b/dom/webidl/SVGFEDistantLightElement.webidl
@@ -6,11 +6,13 @@
  * The origin of this IDL file is
  * http://www.w3.org/TR/SVG2/
  *
  * Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
  * liability, trademark and document use rules apply.
  */
 
 interface SVGFEDistantLightElement : SVGElement {
+  [Constant]
   readonly attribute SVGAnimatedNumber azimuth;
+  [Constant]
   readonly attribute SVGAnimatedNumber elevation;
 };
--- a/dom/webidl/SVGFEDropShadowElement.webidl
+++ b/dom/webidl/SVGFEDropShadowElement.webidl
@@ -6,18 +6,23 @@
  * The origin of this IDL file is
  * http://www.w3.org/TR/SVG2/
  *
  * Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
  * liability, trademark and document use rules apply.
  */
 
 interface SVGFEDropShadowElement : SVGElement {
+  [Constant]
   readonly attribute SVGAnimatedString in1;
+  [Constant]
   readonly attribute SVGAnimatedNumber dx;
+  [Constant]
   readonly attribute SVGAnimatedNumber dy;
+  [Constant]
   readonly attribute SVGAnimatedNumber stdDeviationX;
+  [Constant]
   readonly attribute SVGAnimatedNumber stdDeviationY;
 
   void setStdDeviation(float stdDeviationX, float stdDeviationY);
 };
 
 SVGFEDropShadowElement implements SVGFilterPrimitiveStandardAttributes;
--- a/dom/webidl/SVGFEGaussianBlurElement.webidl
+++ b/dom/webidl/SVGFEGaussianBlurElement.webidl
@@ -6,16 +6,19 @@
  * The origin of this IDL file is
  * http://www.w3.org/TR/SVG2/
  *
  * Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
  * liability, trademark and document use rules apply.
  */
 
 interface SVGFEGaussianBlurElement : SVGElement {
+  [Constant]
   readonly attribute SVGAnimatedString in1;
+  [Constant]
   readonly attribute SVGAnimatedNumber stdDeviationX;
+  [Constant]
   readonly attribute SVGAnimatedNumber stdDeviationY;
 
   void setStdDeviation(float stdDeviationX, float stdDeviationY);
 };
 
 SVGFEGaussianBlurElement implements SVGFilterPrimitiveStandardAttributes;
--- a/dom/webidl/SVGFEImageElement.webidl
+++ b/dom/webidl/SVGFEImageElement.webidl
@@ -6,13 +6,14 @@
  * The origin of this IDL file is
  * http://www.w3.org/TR/SVG2/
  *
  * Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
  * liability, trademark and document use rules apply.
  */
 
 interface SVGFEImageElement : SVGElement {
+  [Constant]
   readonly attribute SVGAnimatedPreserveAspectRatio preserveAspectRatio;
 };
 
 SVGFEImageElement implements SVGFilterPrimitiveStandardAttributes;
 SVGFEImageElement implements SVGURIReference;
--- a/dom/webidl/SVGFEMergeNodeElement.webidl
+++ b/dom/webidl/SVGFEMergeNodeElement.webidl
@@ -6,10 +6,11 @@
  * The origin of this IDL file is
  * http://www.w3.org/TR/SVG2/
  *
  * Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
  * liability, trademark and document use rules apply.
  */
 
 interface SVGFEMergeNodeElement : SVGElement {
+  [Constant]
   readonly attribute SVGAnimatedString in1;
 };
--- a/dom/webidl/SVGFEMorphologyElement.webidl
+++ b/dom/webidl/SVGFEMorphologyElement.webidl
@@ -12,15 +12,19 @@
 
 interface SVGFEMorphologyElement : SVGElement {
 
   // Morphology Operators
   const unsigned short SVG_MORPHOLOGY_OPERATOR_UNKNOWN = 0;
   const unsigned short SVG_MORPHOLOGY_OPERATOR_ERODE = 1;
   const unsigned short SVG_MORPHOLOGY_OPERATOR_DILATE = 2;
 
+  [Constant]
   readonly attribute SVGAnimatedString in1;
+  [Constant]
   readonly attribute SVGAnimatedEnumeration operator;
+  [Constant]
   readonly attribute SVGAnimatedNumber radiusX;
+  [Constant]
   readonly attribute SVGAnimatedNumber radiusY;
 };
 
 SVGFEMorphologyElement implements SVGFilterPrimitiveStandardAttributes;
--- a/dom/webidl/SVGFEOffsetElement.webidl
+++ b/dom/webidl/SVGFEOffsetElement.webidl
@@ -6,14 +6,17 @@
  * The origin of this IDL file is
  * http://www.w3.org/TR/SVG2/
  *
  * Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
  * liability, trademark and document use rules apply.
  */
 
 interface SVGFEOffsetElement : SVGElement {
+  [Constant]
   readonly attribute SVGAnimatedString in1;
+  [Constant]
   readonly attribute SVGAnimatedNumber dx;
+  [Constant]
   readonly attribute SVGAnimatedNumber dy;
 };
 
 SVGFEOffsetElement implements SVGFilterPrimitiveStandardAttributes;
--- a/dom/webidl/SVGFEPointLightElement.webidl
+++ b/dom/webidl/SVGFEPointLightElement.webidl
@@ -6,12 +6,15 @@
  * The origin of this IDL file is
  * http://www.w3.org/TR/SVG2/
  *
  * Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
  * liability, trademark and document use rules apply.
  */
 
 interface SVGFEPointLightElement : SVGElement {
+  [Constant]
   readonly attribute SVGAnimatedNumber x;
+  [Constant]
   readonly attribute SVGAnimatedNumber y;
+  [Constant]
   readonly attribute SVGAnimatedNumber z;
 };
--- a/dom/webidl/SVGFESpecularLightingElement.webidl
+++ b/dom/webidl/SVGFESpecularLightingElement.webidl
@@ -6,17 +6,23 @@
  * The origin of this IDL file is
  * http://www.w3.org/TR/SVG2/
  *
  * Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
  * liability, trademark and document use rules apply.
  */
 
 interface SVGFESpecularLightingElement : SVGElement {
+  [Constant]
   readonly attribute SVGAnimatedString in1;
+  [Constant]
   readonly attribute SVGAnimatedNumber surfaceScale;
+  [Constant]
   readonly attribute SVGAnimatedNumber specularConstant;
+  [Constant]
   readonly attribute SVGAnimatedNumber specularExponent;
+  [Constant]
   readonly attribute SVGAnimatedNumber kernelUnitLengthX;
+  [Constant]
   readonly attribute SVGAnimatedNumber kernelUnitLengthY;
 };
 
 SVGFESpecularLightingElement implements SVGFilterPrimitiveStandardAttributes;
--- a/dom/webidl/SVGFESpotLightElement.webidl
+++ b/dom/webidl/SVGFESpotLightElement.webidl
@@ -6,17 +6,25 @@
  * The origin of this IDL file is
  * http://www.w3.org/TR/SVG2/
  *
  * Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
  * liability, trademark and document use rules apply.
  */
 
 interface SVGFESpotLightElement : SVGElement {
+  [Constant]
   readonly attribute SVGAnimatedNumber x;
+  [Constant]
   readonly attribute SVGAnimatedNumber y;
+  [Constant]
   readonly attribute SVGAnimatedNumber z;
+  [Constant]
   readonly attribute SVGAnimatedNumber pointsAtX;
+  [Constant]
   readonly attribute SVGAnimatedNumber pointsAtY;
+  [Constant]
   readonly attribute SVGAnimatedNumber pointsAtZ;
+  [Constant]
   readonly attribute SVGAnimatedNumber specularExponent;
+  [Constant]
   readonly attribute SVGAnimatedNumber limitingConeAngle;
 };
--- a/dom/webidl/SVGFETileElement.webidl
+++ b/dom/webidl/SVGFETileElement.webidl
@@ -6,12 +6,13 @@
  * The origin of this IDL file is
  * http://www.w3.org/TR/SVG2/
  *
  * Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
  * liability, trademark and document use rules apply.
  */
 
 interface SVGFETileElement : SVGElement {
+  [Constant]
   readonly attribute SVGAnimatedString in1;
 };
 
 SVGFETileElement implements SVGFilterPrimitiveStandardAttributes;
--- a/dom/webidl/SVGFETurbulenceElement.webidl
+++ b/dom/webidl/SVGFETurbulenceElement.webidl
@@ -17,17 +17,23 @@ interface SVGFETurbulenceElement : SVGEl
   const unsigned short SVG_TURBULENCE_TYPE_FRACTALNOISE = 1;
   const unsigned short SVG_TURBULENCE_TYPE_TURBULENCE = 2;
 
   // Stitch Options
   const unsigned short SVG_STITCHTYPE_UNKNOWN = 0;
   const unsigned short SVG_STITCHTYPE_STITCH = 1;
   const unsigned short SVG_STITCHTYPE_NOSTITCH = 2;
 
+  [Constant]
   readonly attribute SVGAnimatedNumber baseFrequencyX;
+  [Constant]
   readonly attribute SVGAnimatedNumber baseFrequencyY;
+  [Constant]
   readonly attribute SVGAnimatedInteger numOctaves;
+  [Constant]
   readonly attribute SVGAnimatedNumber seed;
+  [Constant]
   readonly attribute SVGAnimatedEnumeration stitchTiles;
+  [Constant]
   readonly attribute SVGAnimatedEnumeration type;
 };
 
 SVGFETurbulenceElement implements SVGFilterPrimitiveStandardAttributes;
--- a/dom/webidl/SVGFilterElement.webidl
+++ b/dom/webidl/SVGFilterElement.webidl
@@ -6,21 +6,27 @@
  * The origin of this IDL file is
  * http://www.w3.org/TR/SVG2/
  *
  * Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
  * liability, trademark and document use rules apply.
  */
 
 interface SVGFilterElement : SVGElement {
+  [Constant]
   readonly attribute SVGAnimatedEnumeration filterUnits;
+  [Constant]
   readonly attribute SVGAnimatedEnumeration primitiveUnits;
+  [Constant]
   readonly attribute SVGAnimatedLength x;
+  [Constant]
   readonly attribute SVGAnimatedLength y;
+  [Constant]
   readonly attribute SVGAnimatedLength width;
+  [Constant]
   readonly attribute SVGAnimatedLength height;
 
   // ImageData apply(ImageData source);
 };
 
 SVGFilterElement implements SVGURIReference;
 SVGFilterElement implements SVGUnitTypes;
 
--- a/dom/webidl/SVGFilterPrimitiveStandardAttributes.webidl
+++ b/dom/webidl/SVGFilterPrimitiveStandardAttributes.webidl
@@ -7,14 +7,19 @@
  * http://www.w3.org/TR/SVG2/
  *
  * Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
  * liability, trademark and document use rules apply.
  */
 
 [NoInterfaceObject]
 interface SVGFilterPrimitiveStandardAttributes {
+  [Constant]
   readonly attribute SVGAnimatedLength x;
+  [Constant]
   readonly attribute SVGAnimatedLength y;
+  [Constant]
   readonly attribute SVGAnimatedLength width;
+  [Constant]
   readonly attribute SVGAnimatedLength height;
+  [Constant]
   readonly attribute SVGAnimatedString result;
 };
--- a/dom/webidl/SVGGradientElement.webidl
+++ b/dom/webidl/SVGGradientElement.webidl
@@ -13,15 +13,18 @@
 interface SVGGradientElement : SVGElement {
 
   // Spread Method Types
   const unsigned short SVG_SPREADMETHOD_UNKNOWN = 0;
   const unsigned short SVG_SPREADMETHOD_PAD = 1;
   const unsigned short SVG_SPREADMETHOD_REFLECT = 2;
   const unsigned short SVG_SPREADMETHOD_REPEAT = 3;
 
+  [Constant]
   readonly attribute SVGAnimatedEnumeration gradientUnits;
+  [Constant]
   readonly attribute SVGAnimatedTransformList gradientTransform;
+  [Constant]
   readonly attribute SVGAnimatedEnumeration spreadMethod;
 };
 
 SVGGradientElement implements SVGURIReference;
 SVGGradientElement implements SVGUnitTypes;
--- a/dom/webidl/SVGLinearGradientElement.webidl
+++ b/dom/webidl/SVGLinearGradientElement.webidl
@@ -6,13 +6,17 @@
  * The origin of this IDL file is
  * https://svgwg.org/svg2-draft/
  *
  * Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
  * liability, trademark and document use rules apply.
  */
 
 interface SVGLinearGradientElement : SVGGradientElement {
+  [Constant]
   readonly attribute SVGAnimatedLength x1;
+  [Constant]
   readonly attribute SVGAnimatedLength y1;
+  [Constant]
   readonly attribute SVGAnimatedLength x2;
+  [Constant]
   readonly attribute SVGAnimatedLength y2;
 };
--- a/dom/webidl/SVGMarkerElement.webidl
+++ b/dom/webidl/SVGMarkerElement.webidl
@@ -17,22 +17,29 @@ interface SVGMarkerElement : SVGElement 
   const unsigned short SVG_MARKERUNITS_USERSPACEONUSE = 1;
   const unsigned short SVG_MARKERUNITS_STROKEWIDTH = 2;
 
   // Marker Orientation Types
   const unsigned short SVG_MARKER_ORIENT_UNKNOWN = 0;
   const unsigned short SVG_MARKER_ORIENT_AUTO = 1;
   const unsigned short SVG_MARKER_ORIENT_ANGLE = 2;
 
+  [Constant]
   readonly attribute SVGAnimatedLength refX;
+  [Constant]
   readonly attribute SVGAnimatedLength refY;
+  [Constant]
   readonly attribute SVGAnimatedEnumeration markerUnits;
+  [Constant]
   readonly attribute SVGAnimatedLength markerWidth;
+  [Constant]
   readonly attribute SVGAnimatedLength markerHeight;
+  [Constant]
   readonly attribute SVGAnimatedEnumeration orientType;
+  [Constant]
   readonly attribute SVGAnimatedAngle orientAngle;
 
   void setOrientToAuto();
   [Throws]
   void setOrientToAngle(SVGAngle angle);
 };
 
 SVGMarkerElement implements SVGFitToViewBox;
--- a/dom/webidl/SVGMaskElement.webidl
+++ b/dom/webidl/SVGMaskElement.webidl
@@ -11,18 +11,24 @@
  */
 
 interface SVGMaskElement : SVGElement {
 
   // Mask Types
   const unsigned short SVG_MASKTYPE_LUMINANCE = 0;
   const unsigned short SVG_MASKTYPE_ALPHA = 1;
 
+  [Constant]
   readonly attribute SVGAnimatedEnumeration maskUnits;
+  [Constant]
   readonly attribute SVGAnimatedEnumeration maskContentUnits;
+  [Constant]
   readonly attribute SVGAnimatedLength x;
+  [Constant]
   readonly attribute SVGAnimatedLength y;
+  [Constant]
   readonly attribute SVGAnimatedLength width;
+  [Constant]
   readonly attribute SVGAnimatedLength height;
 };
 
 SVGMaskElement implements SVGUnitTypes;
 
--- a/dom/webidl/SVGPathElement.webidl
+++ b/dom/webidl/SVGPathElement.webidl
@@ -6,16 +6,17 @@
  * The origin of this IDL file is
  * http://www.w3.org/TR/SVG2/
  *
  * Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
  * liability, trademark and document use rules apply.
  */
 interface SVGPathElement : SVGGraphicsElement {
 
+  [Constant]
   readonly attribute SVGAnimatedNumber pathLength;
 
   float getTotalLength();
   [NewObject, Throws]
   SVGPoint getPointAtLength(float distance);
   unsigned long getPathSegAtLength(float distance);
   [NewObject]
   SVGPathSegClosePath createSVGPathSegClosePath();
--- a/dom/webidl/SVGPathSeg.webidl
+++ b/dom/webidl/SVGPathSeg.webidl
@@ -29,17 +29,19 @@ interface SVGPathSeg {
   const unsigned short PATHSEG_LINETO_HORIZONTAL_REL = 13;
   const unsigned short PATHSEG_LINETO_VERTICAL_ABS = 14;
   const unsigned short PATHSEG_LINETO_VERTICAL_REL = 15;
   const unsigned short PATHSEG_CURVETO_CUBIC_SMOOTH_ABS = 16;
   const unsigned short PATHSEG_CURVETO_CUBIC_SMOOTH_REL = 17;
   const unsigned short PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS = 18;
   const unsigned short PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL = 19;
 
+  [Pure]
   readonly attribute unsigned short pathSegType;
+  [Pure]
   readonly attribute DOMString pathSegTypeAsLetter;
 };
 
 interface SVGPathSegClosePath : SVGPathSeg {
 };
 
 interface SVGPathSegMovetoAbs : SVGPathSeg {
   [SetterThrows]
--- a/dom/webidl/SVGRadialGradientElement.webidl
+++ b/dom/webidl/SVGRadialGradientElement.webidl
@@ -6,15 +6,20 @@
  * The origin of this IDL file is
  * https://svgwg.org/svg2-draft/
  *
  * Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
  * liability, trademark and document use rules apply.
  */
 
 interface SVGRadialGradientElement : SVGGradientElement {
+  [Constant]
   readonly attribute SVGAnimatedLength cx;
+  [Constant]
   readonly attribute SVGAnimatedLength cy;
+  [Constant]
   readonly attribute SVGAnimatedLength r;
+  [Constant]
   readonly attribute SVGAnimatedLength fx;
+  [Constant]
   readonly attribute SVGAnimatedLength fy;
   // readonly attribute SVGAnimatedLength fr;
 };
--- a/dom/webidl/SVGSVGElement.webidl
+++ b/dom/webidl/SVGSVGElement.webidl
@@ -9,19 +9,23 @@
  * Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
  * liability, trademark and document use rules apply.
  */
 
 interface SVGViewSpec;
 
 interface SVGSVGElement : SVGGraphicsElement {
 
+  [Constant]
   readonly attribute SVGAnimatedLength x;
+  [Constant]
   readonly attribute SVGAnimatedLength y;
+  [Constant]
   readonly attribute SVGAnimatedLength width;
+  [Constant]
   readonly attribute SVGAnimatedLength height;
   // readonly attribute SVGRect viewport;
   [Constant]
   readonly attribute float pixelUnitToMillimeterX;
   [Constant]
   readonly attribute float pixelUnitToMillimeterY;
   [Constant]
   readonly attribute float screenPixelToMillimeterX;
--- a/dom/webidl/SVGStopElement.webidl
+++ b/dom/webidl/SVGStopElement.webidl
@@ -6,11 +6,12 @@
  * The origin of this IDL file is
  * http://www.w3.org/TR/SVG2/
  *
  * Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
  * liability, trademark and document use rules apply.
  */
 
 interface SVGStopElement : SVGElement {
+  [Constant]
   readonly attribute SVGAnimatedNumber offset;
 };
 
--- a/dom/webidl/SVGTextContentElement.webidl
+++ b/dom/webidl/SVGTextContentElement.webidl
@@ -12,17 +12,19 @@
 
 interface SVGTextContentElement : SVGGraphicsElement {
 
   // lengthAdjust Types
   const unsigned short LENGTHADJUST_UNKNOWN = 0;
   const unsigned short LENGTHADJUST_SPACING = 1;
   const unsigned short LENGTHADJUST_SPACINGANDGLYPHS = 2;
 
+  [Constant]
   readonly attribute SVGAnimatedLength textLength;
+  [Constant]
   readonly attribute SVGAnimatedEnumeration lengthAdjust;
 
   long getNumberOfChars();
   float getComputedTextLength();
   [Throws]
   float getSubStringLength(unsigned long charnum, unsigned long nchars);
   [Throws]
   SVGPoint getStartPositionOfChar(unsigned long charnum);
--- a/dom/webidl/SVGTextPathElement.webidl
+++ b/dom/webidl/SVGTextPathElement.webidl
@@ -17,15 +17,18 @@ interface SVGTextPathElement : SVGTextCo
   const unsigned short TEXTPATH_METHODTYPE_ALIGN = 1;
   const unsigned short TEXTPATH_METHODTYPE_STRETCH = 2;
 
   // textPath Spacing Types
   const unsigned short TEXTPATH_SPACINGTYPE_UNKNOWN = 0;
   const unsigned short TEXTPATH_SPACINGTYPE_AUTO = 1;
   const unsigned short TEXTPATH_SPACINGTYPE_EXACT = 2;
 
+  [Constant]
   readonly attribute SVGAnimatedLength startOffset;
+  [Constant]
   readonly attribute SVGAnimatedEnumeration method;
+  [Constant]
   readonly attribute SVGAnimatedEnumeration spacing;
 };
 
 SVGTextPathElement implements SVGURIReference;
 
--- a/dom/webidl/SVGTextPositioningElement.webidl
+++ b/dom/webidl/SVGTextPositioningElement.webidl
@@ -6,15 +6,20 @@
  * The origin of this IDL file is
  * http://www.w3.org/TR/SVG2/
  *
  * Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
  * liability, trademark and document use rules apply.
  */
 
 interface SVGTextPositioningElement : SVGTextContentElement {
+  [Constant]
   readonly attribute SVGAnimatedLengthList x;
+  [Constant]
   readonly attribute SVGAnimatedLengthList y;
+  [Constant]
   readonly attribute SVGAnimatedLengthList dx;
+  [Constant]
   readonly attribute SVGAnimatedLengthList dy;
+  [Constant]
   readonly attribute SVGAnimatedNumberList rotate;
 };
 
--- a/dom/webidl/SVGURIReference.webidl
+++ b/dom/webidl/SVGURIReference.webidl
@@ -7,11 +7,12 @@
  * http://www.w3.org/TR/SVG2/
  *
  * Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
  * liability, trademark and document use rules apply.
  */
 
 [NoInterfaceObject]
 interface SVGURIReference {
+  [Constant]
   readonly attribute SVGAnimatedString href;
 };
 
--- a/dom/workers/ServiceWorkerContainer.cpp
+++ b/dom/workers/ServiceWorkerContainer.cpp
@@ -51,17 +51,20 @@ ServiceWorkerContainer::DisconnectFromOw
 
 void
 ServiceWorkerContainer::RemoveReadyPromise()
 {
   nsCOMPtr<nsPIDOMWindow> window = GetOwner();
   if (window) {
     nsCOMPtr<nsIServiceWorkerManager> swm =
       mozilla::services::GetServiceWorkerManager();
-    MOZ_ASSERT(swm);
+    if (!swm) {
+      // If the browser is shutting down, we don't need to remove the promise.
+      return;
+    }
 
     swm->RemoveReadyPromise(window);
   }
 }
 
 JSObject*
 ServiceWorkerContainer::WrapObject(JSContext* aCx)
 {
--- a/dom/workers/ServiceWorkerEvents.h
+++ b/dom/workers/ServiceWorkerEvents.h
@@ -64,16 +64,21 @@ public:
   WaitUntil(Promise& aPromise);
 
   already_AddRefed<Promise>
   GetPromise() const
   {
     nsRefPtr<Promise> p = mPromise;
     return p.forget();
   }
+
+  virtual ExtendableEvent* AsExtendableEvent() MOZ_OVERRIDE
+  {
+    return this;
+  }
 };
 
 class InstallEvent MOZ_FINAL : public ExtendableEvent
 {
   // FIXME(nsm): Bug 982787 will allow actually populating this.
   nsRefPtr<ServiceWorker> mActiveWorker;
   bool mActivateImmediately;
 
@@ -127,12 +132,17 @@ public:
     mActivateImmediately = true;
   };
 
   bool
   ActivateImmediately() const
   {
     return mActivateImmediately;
   }
+
+  InstallEvent* AsInstallEvent() MOZ_OVERRIDE
+  {
+    return this;
+  }
 };
 
 END_WORKERS_NAMESPACE
 #endif /* mozilla_dom_workers_serviceworkerevents_h__ */
--- a/dom/workers/ServiceWorkerManager.cpp
+++ b/dom/workers/ServiceWorkerManager.cpp
@@ -101,36 +101,16 @@ ServiceWorkerRegistrationInfo::ServiceWo
 
 ServiceWorkerRegistrationInfo::~ServiceWorkerRegistrationInfo()
 {
   if (IsControllingDocuments()) {
     NS_WARNING("ServiceWorkerRegistrationInfo is still controlling documents. This can be a bug or a leak in ServiceWorker API or in any other API that takes the document alive.");
   }
 }
 
-class QueueFireUpdateFoundRunnable MOZ_FINAL : public nsRunnable
-{
-  nsRefPtr<ServiceWorkerRegistrationInfo> mRegistration;
-public:
-  explicit QueueFireUpdateFoundRunnable(ServiceWorkerRegistrationInfo* aReg)
-    : mRegistration(aReg)
-  {
-    MOZ_ASSERT(aReg);
-  }
-
-  NS_IMETHOD
-  Run()
-  {
-    nsRefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
-    swm->FireEventOnServiceWorkerRegistrations(mRegistration,
-                                               NS_LITERAL_STRING("updatefound"));
-    return NS_OK;
-  }
-};
-
 //////////////////////////
 // ServiceWorkerManager //
 //////////////////////////
 
 NS_IMPL_ADDREF(ServiceWorkerManager)
 NS_IMPL_RELEASE(ServiceWorkerManager)
 
 NS_INTERFACE_MAP_BEGIN(ServiceWorkerManager)
@@ -158,70 +138,118 @@ ServiceWorkerManager::CleanupServiceWork
                                                       void *aUnused)
 {
   aDomainInfo->mServiceWorkerRegistrationInfos.Clear();
   return PL_DHASH_NEXT;
 }
 
 class ServiceWorkerRegisterJob;
 
-class FinishInstallRunnable MOZ_FINAL : public nsRunnable
+class ContinueLifecycleTask : public nsISupports
+{
+  NS_DECL_ISUPPORTS
+
+protected:
+  virtual ~ContinueLifecycleTask()
+  { }
+
+public:
+  virtual void ContinueAfterWorkerEvent(bool aSuccess,
+                                        bool aActivateImmediately) = 0;
+};
+
+NS_IMPL_ISUPPORTS0(ContinueLifecycleTask);
+
+class ContinueInstallTask MOZ_FINAL : public ContinueLifecycleTask
 {
-  nsMainThreadPtrHandle<nsISupports> mJob;
+  nsRefPtr<ServiceWorkerRegisterJob> mJob;
+
+public:
+  explicit ContinueInstallTask(ServiceWorkerRegisterJob* aJob)
+    : mJob(aJob)
+  { }
+
+  void ContinueAfterWorkerEvent(bool aSuccess, bool aActivateImmediately) MOZ_OVERRIDE;
+};
+
+class ContinueActivateTask MOZ_FINAL : public ContinueLifecycleTask
+{
+  nsRefPtr<ServiceWorkerRegistrationInfo> mRegistration;
+
+public:
+  explicit ContinueActivateTask(ServiceWorkerRegistrationInfo* aReg)
+    : mRegistration(aReg)
+  { }
+
+  void
+  ContinueAfterWorkerEvent(bool aSuccess, bool aActivateImmediately /* unused */) MOZ_OVERRIDE
+  {
+    mRegistration->FinishActivate(aSuccess);
+  }
+};
+
+class ContinueLifecycleRunnable MOZ_FINAL : public nsRunnable
+{
+  nsMainThreadPtrHandle<ContinueLifecycleTask> mTask;
   bool mSuccess;
   bool mActivateImmediately;
 
 public:
-  explicit FinishInstallRunnable(const nsMainThreadPtrHandle<nsISupports>& aJob,
-                                 bool aSuccess,
-                                 bool aActivateImmediately)
-    : mJob(aJob)
+  ContinueLifecycleRunnable(const nsMainThreadPtrHandle<ContinueLifecycleTask>& aTask,
+                            bool aSuccess,
+                            bool aActivateImmediately)
+    : mTask(aTask)
     , mSuccess(aSuccess)
     , mActivateImmediately(aActivateImmediately)
   {
     MOZ_ASSERT(!NS_IsMainThread());
   }
 
   NS_IMETHOD
-  Run() MOZ_OVERRIDE;
+  Run() MOZ_OVERRIDE
+  {
+    AssertIsOnMainThread();
+    mTask->ContinueAfterWorkerEvent(mSuccess, mActivateImmediately);
+    return NS_OK;
+  }
 };
 
 /*
  * Fires 'install' event on the ServiceWorkerGlobalScope. Modifies busy count
  * since it fires the event. This is ok since there can't be nested
  * ServiceWorkers, so the parent thread -> worker thread requirement for
  * runnables is satisfied.
  */
-class InstallEventRunnable MOZ_FINAL : public WorkerRunnable
+class LifecycleEventWorkerRunnable MOZ_FINAL : public WorkerRunnable
 {
-  nsMainThreadPtrHandle<nsISupports> mJob;
-  nsCString mScope;
+  nsString mEventName;
+  nsMainThreadPtrHandle<ContinueLifecycleTask> mTask;
 
 public:
-  InstallEventRunnable(WorkerPrivate* aWorkerPrivate,
-                       const nsMainThreadPtrHandle<nsISupports>& aJob,
-                       const nsCString& aScope)
-      : WorkerRunnable(aWorkerPrivate, WorkerThreadModifyBusyCount),
-        mJob(aJob),
-        mScope(aScope)
+  LifecycleEventWorkerRunnable(WorkerPrivate* aWorkerPrivate,
+                               const nsString& aEventName,
+                               const nsMainThreadPtrHandle<ContinueLifecycleTask>& aTask)
+      : WorkerRunnable(aWorkerPrivate, WorkerThreadModifyBusyCount)
+      , mEventName(aEventName)
+      , mTask(aTask)
   {
     AssertIsOnMainThread();
     MOZ_ASSERT(aWorkerPrivate);
   }
 
   bool
-  WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
+  WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) MOZ_OVERRIDE
   {
     MOZ_ASSERT(aWorkerPrivate);
-    return DispatchInstallEvent(aCx, aWorkerPrivate);
+    return DispatchLifecycleEvent(aCx, aWorkerPrivate);
   }
 
 private:
   bool
-  DispatchInstallEvent(JSContext* aCx, WorkerPrivate* aWorkerPrivate);
+  DispatchLifecycleEvent(JSContext* aCx, WorkerPrivate* aWorkerPrivate);
 
 };
 
 class ServiceWorkerUpdateFinishCallback
 {
 protected:
   virtual ~ServiceWorkerUpdateFinishCallback()
   { }
@@ -351,17 +379,17 @@ public:
 
     return true;
   }
 };
 
 class ServiceWorkerRegisterJob MOZ_FINAL : public ServiceWorkerJob,
                                            public nsIStreamLoaderObserver
 {
-  friend class FinishInstallRunnable;
+  friend class ContinueInstallTask;
 
   nsCString mScope;
   nsCString mScriptSpec;
   nsRefPtr<ServiceWorkerRegistrationInfo> mRegistration;
   nsRefPtr<ServiceWorkerUpdateFinishCallback> mCallback;
 
   ~ServiceWorkerRegisterJob()
   { }
@@ -499,18 +527,17 @@ public:
   }
 
   // Public so our error handling code can use it.
   void
   Fail(const ErrorEventInit& aError)
   {
     MOZ_ASSERT(mCallback);
     mCallback->UpdateFailed(aError);
-    mCallback = nullptr;
-    Done(NS_ERROR_DOM_JS_EXCEPTION);
+    FailCommon(NS_ERROR_DOM_JS_EXCEPTION);
   }
 
   // Public so our error handling code can continue with a successful worker.
   void
   ContinueInstall()
   {
     nsRefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
     nsRefPtr<ServiceWorkerManager::ServiceWorkerDomainInfo> domainInfo =
@@ -526,39 +553,38 @@ public:
 
     swm->InvalidateServiceWorkerRegistrationWorker(mRegistration,
                                                    WhichServiceWorker::INSTALLING_WORKER);
     mRegistration->mInstallingWorker = new ServiceWorkerInfo(mRegistration, mRegistration->mScriptSpec);
     mRegistration->mInstallingWorker->UpdateState(ServiceWorkerState::Installing);
 
     Succeed();
 
-    nsRefPtr<QueueFireUpdateFoundRunnable> upr =
-      new QueueFireUpdateFoundRunnable(mRegistration);
+    nsCOMPtr<nsIRunnable> upr =
+      NS_NewRunnableMethodWithArg<ServiceWorkerRegistrationInfo*>(swm,
+                                                                  &ServiceWorkerManager::FireUpdateFound,
+                                                                  mRegistration);
     NS_DispatchToMainThread(upr);
 
-    // XXXnsm this leads to double fetches right now, ideally we'll be able to
-    // use the persistent cache later.
-    nsRefPtr<ServiceWorkerJob> upcasted = this;
-    nsMainThreadPtrHandle<nsISupports> handle(
-        new nsMainThreadPtrHolder<nsISupports>(upcasted));
+    nsMainThreadPtrHandle<ContinueLifecycleTask> handle(
+        new nsMainThreadPtrHolder<ContinueLifecycleTask>(new ContinueInstallTask(this)));
 
     nsRefPtr<ServiceWorker> serviceWorker;
     nsresult rv =
       swm->CreateServiceWorker(mRegistration->mInstallingWorker->ScriptSpec(),
                                mRegistration->mScope,
                                getter_AddRefs(serviceWorker));
 
     if (NS_WARN_IF(NS_FAILED(rv))) {
       ContinueAfterInstallEvent(false /* success */, false /* activate immediately */);
       return;
     }
 
-    nsRefPtr<InstallEventRunnable> r =
-      new InstallEventRunnable(serviceWorker->GetWorkerPrivate(), handle, mRegistration->mScope);
+    nsRefPtr<LifecycleEventWorkerRunnable> r =
+      new LifecycleEventWorkerRunnable(serviceWorker->GetWorkerPrivate(), NS_LITERAL_STRING("install"), handle);
 
     AutoJSAPI jsapi;
     jsapi.Init();
     r->Dispatch(jsapi.cx());
   }
 
 private:
   void
@@ -629,26 +655,49 @@ private:
   void
   Succeed()
   {
     MOZ_ASSERT(mCallback);
     mCallback->UpdateSucceeded(mRegistration);
     mCallback = nullptr;
   }
 
+  void
+  FailCommon(nsresult aRv)
+  {
+    mCallback = nullptr;
+    MaybeRemoveRegistration();
+    // Ensures that the job can't do anything useful from this point on.
+    mRegistration = nullptr;
+    Done(aRv);
+  }
+
   // This MUST only be called when the job is still performing actions related
   // to registration or update. After the spec resolves the update promise, use
   // Done() with the failure code instead.
   void
-  Fail(nsresult rv)
+  Fail(nsresult aRv)
   {
     MOZ_ASSERT(mCallback);
-    mCallback->UpdateFailed(rv);
-    mCallback = nullptr;
-    Done(rv);
+    mCallback->UpdateFailed(aRv);
+    FailCommon(aRv);
+  }
+
+  void
+  MaybeRemoveRegistration()
+  {
+    MOZ_ASSERT(mRegistration);
+    nsRefPtr<ServiceWorkerInfo> newest = mRegistration->Newest();
+    if (!newest) {
+      nsRefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
+      nsRefPtr<ServiceWorkerManager::ServiceWorkerDomainInfo> domainInfo =
+        swm->GetDomainInfo(mRegistration->mScope);
+      MOZ_ASSERT(domainInfo);
+      domainInfo->RemoveRegistration(mRegistration);
+    }
   }
 
   void
   ContinueAfterInstallEvent(bool aSuccess, bool aActivateImmediately)
   {
     // By this point the callback should've been notified about success or fail
     // and nulled.
     MOZ_ASSERT(!mCallback);
@@ -661,16 +710,17 @@ private:
     nsRefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
 
     // "If installFailed is true"
     if (!aSuccess) {
       mRegistration->mInstallingWorker->UpdateState(ServiceWorkerState::Redundant);
       mRegistration->mInstallingWorker = nullptr;
       swm->InvalidateServiceWorkerRegistrationWorker(mRegistration,
                                                      WhichServiceWorker::INSTALLING_WORKER);
+      MaybeRemoveRegistration();
       return Done(NS_ERROR_DOM_ABORT_ERR);
     }
 
     // "If registration's waiting worker is not null"
     if (mRegistration->mWaitingWorker) {
       // FIXME(nsm): Terminate
       mRegistration->mWaitingWorker->UpdateState(ServiceWorkerState::Redundant);
     }
@@ -700,16 +750,22 @@ ContinueUpdateRunnable::Run()
 {
   AssertIsOnMainThread();
   nsRefPtr<ServiceWorkerJob> job = static_cast<ServiceWorkerJob*>(mJob.get());
   nsRefPtr<ServiceWorkerRegisterJob> upjob = static_cast<ServiceWorkerRegisterJob*>(job.get());
   upjob->ContinueInstall();
   return NS_OK;
 }
 
+void
+ContinueInstallTask::ContinueAfterWorkerEvent(bool aSuccess, bool aActivateImmediately)
+{
+  mJob->ContinueAfterInstallEvent(aSuccess, aActivateImmediately);
+}
+
 // If we return an error code here, the ServiceWorkerContainer will
 // automatically reject the Promise.
 NS_IMETHODIMP
 ServiceWorkerManager::Register(nsIDOMWindow* aWindow,
                                const nsAString& aScope,
                                const nsAString& aScriptURL,
                                nsISupports** aPromise)
 {
@@ -848,82 +904,86 @@ ServiceWorkerManager::Register(nsIDOMWin
   nsRefPtr<ServiceWorkerRegisterJob> job =
     new ServiceWorkerRegisterJob(queue, cleanedScope, spec, cb);
   queue->Append(job);
 
   promise.forget(aPromise);
   return NS_OK;
 }
 
-NS_IMETHODIMP
-FinishInstallRunnable::Run()
+/*
+ * Used to handle ExtendableEvent::waitUntil() and proceed with
+ * installation/activation.
+ */
+class LifecycleEventPromiseHandler MOZ_FINAL : public PromiseNativeHandler
 {
-  AssertIsOnMainThread();
-  nsRefPtr<ServiceWorkerJob> job = static_cast<ServiceWorkerJob*>(mJob.get());
-  nsRefPtr<ServiceWorkerRegisterJob> upjob = static_cast<ServiceWorkerRegisterJob*>(job.get());
-  MOZ_ASSERT(upjob);
-  upjob->ContinueAfterInstallEvent(mSuccess, mActivateImmediately);
-  return NS_OK;
-}
-
-/*
- * Used to handle InstallEvent::waitUntil() and proceed with installation.
- */
-class FinishInstallHandler MOZ_FINAL : public PromiseNativeHandler
-{
-  nsMainThreadPtrHandle<nsISupports> mJob;
+  nsMainThreadPtrHandle<ContinueLifecycleTask> mTask;
   bool mActivateImmediately;
 
   virtual
-  ~FinishInstallHandler()
+  ~LifecycleEventPromiseHandler()
   { }
 
 public:
-  FinishInstallHandler(const nsMainThreadPtrHandle<nsISupports>& aJob,
-                       bool aActivateImmediately)
-    : mJob(aJob)
+  LifecycleEventPromiseHandler(const nsMainThreadPtrHandle<ContinueLifecycleTask>& aTask,
+                               bool aActivateImmediately)
+    : mTask(aTask)
     , mActivateImmediately(aActivateImmediately)
   {
     MOZ_ASSERT(!NS_IsMainThread());
   }
 
   void
   ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) MOZ_OVERRIDE
   {
     WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
     MOZ_ASSERT(workerPrivate);
     workerPrivate->AssertIsOnWorkerThread();
 
-    nsRefPtr<FinishInstallRunnable> r = new FinishInstallRunnable(mJob, true, mActivateImmediately);
+    nsRefPtr<ContinueLifecycleRunnable> r =
+      new ContinueLifecycleRunnable(mTask, true /* success */, mActivateImmediately);
     NS_DispatchToMainThread(r);
   }
 
   void
   RejectedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) MOZ_OVERRIDE
   {
-    nsRefPtr<FinishInstallRunnable> r = new FinishInstallRunnable(mJob, false, mActivateImmediately);
+    WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
+    MOZ_ASSERT(workerPrivate);
+    workerPrivate->AssertIsOnWorkerThread();
+
+    nsRefPtr<ContinueLifecycleRunnable> r =
+      new ContinueLifecycleRunnable(mTask, false /* success */, mActivateImmediately);
     NS_DispatchToMainThread(r);
   }
 };
 
 bool
-InstallEventRunnable::DispatchInstallEvent(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
+LifecycleEventWorkerRunnable::DispatchLifecycleEvent(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
 {
   aWorkerPrivate->AssertIsOnWorkerThread();
   MOZ_ASSERT(aWorkerPrivate->IsServiceWorker());
-  InstallEventInit init;
-  init.mBubbles = false;
-  init.mCancelable = true;
+
+  nsRefPtr<ExtendableEvent> event;
+  nsRefPtr<EventTarget> target = aWorkerPrivate->GlobalScope();
 
-  // FIXME(nsm): Bug 982787 pass previous active worker.
-
-  // FIXME(nsm): Set error handler so we can grab handler errors.
-  nsRefPtr<EventTarget> target = aWorkerPrivate->GlobalScope();
-  nsRefPtr<InstallEvent> event =
-    InstallEvent::Constructor(target, NS_LITERAL_STRING("install"), init);
+  if (mEventName.EqualsASCII("install")) {
+    // FIXME(nsm): Bug 982787 pass previous active worker.
+    InstallEventInit init;
+    init.mBubbles = false;
+    init.mCancelable = true;
+    event = InstallEvent::Constructor(target, mEventName, init);
+  } else if (mEventName.EqualsASCII("activate")) {
+    ExtendableEventInit init;
+    init.mBubbles = false;
+    init.mCancelable = true;
+    event = ExtendableEvent::Constructor(target, mEventName, init);
+  } else {
+    MOZ_CRASH("Unexpected lifecycle event");
+  }
 
   event->SetTrusted(true);
 
   nsRefPtr<Promise> waitUntilPromise;
 
   ErrorResult result;
   result = target->DispatchDOMEvent(nullptr, event, nullptr, nullptr);
 
@@ -947,145 +1007,31 @@ InstallEventRunnable::DispatchInstallEve
     waitUntilPromise = Promise::Reject(sgo, aCx,
                                        JS::UndefinedHandleValue, result);
   }
 
   if (result.Failed()) {
     return false;
   }
 
-  nsRefPtr<FinishInstallHandler> handler =
-    new FinishInstallHandler(mJob, event->ActivateImmediately());
+  // activateimmediately is only relevant to "install" event.
+  bool activateImmediately = false;
+  InstallEvent* installEvent = event->AsInstallEvent();
+  if (installEvent) {
+    activateImmediately = installEvent->ActivateImmediately();
+    // FIXME(nsm): Set activeWorker to the correct thing.
+    // FIXME(nsm): Install error handler for any listener errors.
+  }
+
+  nsRefPtr<LifecycleEventPromiseHandler> handler =
+    new LifecycleEventPromiseHandler(mTask, activateImmediately);
   waitUntilPromise->AppendNativeHandler(handler);
   return true;
 }
 
-class FinishActivationRunnable MOZ_FINAL : public nsRunnable
-{
-  bool mSuccess;
-  nsMainThreadPtrHandle<ServiceWorkerRegistrationInfo> mRegistration;
-
-public:
-  FinishActivationRunnable(bool aSuccess,
-                           const nsMainThreadPtrHandle<ServiceWorkerRegistrationInfo>& aRegistration)
-    : mSuccess(aSuccess)
-    , mRegistration(aRegistration)
-  {
-    MOZ_ASSERT(!NS_IsMainThread());
-  }
-
-  NS_IMETHODIMP
-  Run()
-  {
-    AssertIsOnMainThread();
-
-    mRegistration->FinishActivate(mSuccess);
-    return NS_OK;
-  }
-};
-
-class FinishActivateHandler MOZ_FINAL : public PromiseNativeHandler
-{
-  nsMainThreadPtrHandle<ServiceWorkerRegistrationInfo> mRegistration;
-
-public:
-  explicit FinishActivateHandler(const nsMainThreadPtrHandle<ServiceWorkerRegistrationInfo>& aRegistration)
-    : mRegistration(aRegistration)
-  {
-    MOZ_ASSERT(!NS_IsMainThread());
-  }
-
-  virtual
-  ~FinishActivateHandler()
-  { }
-
-  void
-  ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) MOZ_OVERRIDE
-  {
-    nsRefPtr<FinishActivationRunnable> r = new FinishActivationRunnable(true /* success */, mRegistration);
-    NS_DispatchToMainThread(r);
-  }
-
-  void
-  RejectedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) MOZ_OVERRIDE
-  {
-    nsRefPtr<FinishActivationRunnable> r = new FinishActivationRunnable(false /* success */, mRegistration);
-    NS_DispatchToMainThread(r);
-  }
-};
-
-class ActivateEventRunnable : public WorkerRunnable
-{
-  nsMainThreadPtrHandle<ServiceWorkerRegistrationInfo> mRegistration;
-
-public:
-  ActivateEventRunnable(WorkerPrivate* aWorkerPrivate,
-                        const nsMainThreadPtrHandle<ServiceWorkerRegistrationInfo>& aRegistration)
-      : WorkerRunnable(aWorkerPrivate, WorkerThreadModifyBusyCount),
-        mRegistration(aRegistration)
-  {
-    MOZ_ASSERT(aWorkerPrivate);
-  }
-
-  bool
-  WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
-  {
-    MOZ_ASSERT(aWorkerPrivate);
-    return DispatchActivateEvent(aCx, aWorkerPrivate);
-  }
-
-private:
-  bool
-  DispatchActivateEvent(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
-  {
-    MOZ_ASSERT(aWorkerPrivate->IsServiceWorker());
-    nsRefPtr<EventTarget> target = do_QueryObject(aWorkerPrivate->GlobalScope());
-
-    // FIXME(nsm): Set activeWorker to the correct thing.
-    EventInit init;
-    init.mBubbles = false;
-    init.mCancelable = true;
-    nsRefPtr<ExtendableEvent> event =
-      ExtendableEvent::Constructor(target, NS_LITERAL_STRING("activate"), init);
-
-    event->SetTrusted(true);
-
-    nsRefPtr<Promise> waitUntilPromise;
-
-    // FIXME(nsm): Install error handler for any listener errors.
-    ErrorResult result;
-    result = target->DispatchDOMEvent(nullptr, event, nullptr, nullptr);
-    WidgetEvent* internalEvent = event->GetInternalNSEvent();
-    if (!result.Failed() && !internalEvent->mFlags.mExceptionHasBeenRisen) {
-      waitUntilPromise = event->GetPromise();
-      if (!waitUntilPromise) {
-        nsCOMPtr<nsIGlobalObject> global =
-          do_QueryObject(aWorkerPrivate->GlobalScope());
-        waitUntilPromise =
-          Promise::Resolve(global,
-                           aCx, JS::UndefinedHandleValue, result);
-      }
-    } else {
-      nsCOMPtr<nsIGlobalObject> global =
-        do_QueryObject(aWorkerPrivate->GlobalScope());
-      // Continue with a canceled install.
-      waitUntilPromise = Promise::Reject(global, aCx,
-                                         JS::UndefinedHandleValue, result);
-    }
-
-    if (result.Failed()) {
-      return false;
-    }
-
-    nsRefPtr<FinishActivateHandler> handler = new FinishActivateHandler(mRegistration);
-    waitUntilPromise->AppendNativeHandler(handler);
-    return true;
-  }
-};
-
 void
 ServiceWorkerRegistrationInfo::TryToActivate()
 {
   mWaitingToActivate = true;
   if (!IsControllingDocuments()) {
     Activate();
   }
 }
@@ -1133,21 +1079,21 @@ ServiceWorkerRegistrationInfo::Activate(
     swm->CreateServiceWorker(mActiveWorker->ScriptSpec(),
                              mScope,
                              getter_AddRefs(serviceWorker));
   if (NS_WARN_IF(NS_FAILED(rv))) {
     FinishActivate(false /* success */);
     return;
   }
 
-  nsMainThreadPtrHandle<ServiceWorkerRegistrationInfo> handle(
-    new nsMainThreadPtrHolder<ServiceWorkerRegistrationInfo>(this));
+  nsMainThreadPtrHandle<ContinueLifecycleTask> handle(
+    new nsMainThreadPtrHolder<ContinueLifecycleTask>(new ContinueActivateTask(this)));
 
-  nsRefPtr<ActivateEventRunnable> r =
-    new ActivateEventRunnable(serviceWorker->GetWorkerPrivate(), handle);
+  nsRefPtr<LifecycleEventWorkerRunnable> r =
+    new LifecycleEventWorkerRunnable(serviceWorker->GetWorkerPrivate(), NS_LITERAL_STRING("activate"), handle);
 
   AutoJSAPI jsapi;
   jsapi.Init();
   r->Dispatch(jsapi.cx());
 }
 
 /*
  * Implements the async aspects of the getRegistrations algorithm.
@@ -1470,95 +1416,127 @@ ServiceWorkerManager::CheckReadyPromise(
       new ServiceWorkerRegistration(aWindow, scope);
     aPromise->MaybeResolve(swr);
     return true;
   }
 
   return false;
 }
 
+class ServiceWorkerUnregisterJob MOZ_FINAL : public ServiceWorkerJob
+{
+  nsRefPtr<ServiceWorkerRegistrationInfo> mRegistration;
+  const nsCString mScope;
+  nsCOMPtr<nsIServiceWorkerUnregisterCallback> mCallback;
+
+  ~ServiceWorkerUnregisterJob()
+  { }
+
+public:
+  ServiceWorkerUnregisterJob(ServiceWorkerJobQueue* aQueue,
+                             const nsACString& aScope,
+                             nsIServiceWorkerUnregisterCallback* aCallback)
+    : ServiceWorkerJob(aQueue)
+    , mScope(aScope)
+    , mCallback(aCallback)
+  {
+    AssertIsOnMainThread();
+  }
+
+  void
+  Start() MOZ_OVERRIDE
+  {
+    AssertIsOnMainThread();
+    nsCOMPtr<nsIRunnable> r =
+      NS_NewRunnableMethod(this, &ServiceWorkerUnregisterJob::UnregisterAndDone);
+    MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToMainThread(r)));
+  }
+
+private:
+  // You probably want UnregisterAndDone().
+  nsresult
+  Unregister()
+  {
+    AssertIsOnMainThread();
+
+    nsRefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
+
+    nsRefPtr<ServiceWorkerManager::ServiceWorkerDomainInfo> domainInfo =
+      swm->GetDomainInfo(mScope);
+    MOZ_ASSERT(domainInfo);
+
+    // "Let registration be the result of running [[Get Registration]]
+    // algorithm passing scope as the argument."
+    nsRefPtr<ServiceWorkerRegistrationInfo> registration;
+    if (!domainInfo->mServiceWorkerRegistrationInfos.Get(mScope,
+                                                         getter_AddRefs(registration))) {
+      // "If registration is null, then, resolve promise with false."
+      return mCallback->UnregisterSucceeded(false);
+    }
+
+    MOZ_ASSERT(registration);
+
+    // "Set registration's uninstalling flag."
+    registration->mPendingUninstall = true;
+    // "Resolve promise with true"
+    nsresult rv = mCallback->UnregisterSucceeded(true);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
+
+    // "If no service worker client is using registration..."
+    if (!registration->IsControllingDocuments()) {
+      // "If registration's uninstalling flag is set.."
+      if (!registration->mPendingUninstall) {
+        return NS_OK;
+      }
+
+      // "Invoke [[Clear Registration]]..."
+      registration->Clear();
+      domainInfo->RemoveRegistration(registration);
+    }
+
+    return NS_OK;
+  }
+
+  // The unregister job is done irrespective of success or failure of any sort.
+  void
+  UnregisterAndDone()
+  {
+    Done(Unregister());
+  }
+};
+
 NS_IMETHODIMP
 ServiceWorkerManager::Unregister(nsIServiceWorkerUnregisterCallback* aCallback,
                                  const nsAString& aScope)
 {
   AssertIsOnMainThread();
   MOZ_ASSERT(aCallback);
 
+// This is not accessible by content, and callers should always ensure scope is
+// a correct URI, so this is wrapped in DEBUG
+#ifdef DEBUG
   nsCOMPtr<nsIURI> scopeURI;
   nsresult rv = NS_NewURI(getter_AddRefs(scopeURI), aScope, nullptr, nullptr);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return NS_ERROR_DOM_SECURITY_ERR;
   }
-
-  /*
-   * Implements the async aspects of the unregister algorithm.
-   */
-  class UnregisterRunnable : public nsRunnable
-  {
-    nsCOMPtr<nsIServiceWorkerUnregisterCallback> mCallback;
-    nsCOMPtr<nsIURI> mScopeURI;
-
-  public:
-    UnregisterRunnable(nsIServiceWorkerUnregisterCallback* aCallback,
-                       nsIURI* aScopeURI)
-      : mCallback(aCallback), mScopeURI(aScopeURI)
-    {
-      AssertIsOnMainThread();
-    }
-
-    NS_IMETHODIMP
-    Run()
-    {
-      AssertIsOnMainThread();
-
-      nsRefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
-
-      nsRefPtr<ServiceWorkerManager::ServiceWorkerDomainInfo> domainInfo =
-        swm->GetDomainInfo(mScopeURI);
-      MOZ_ASSERT(domainInfo);
-
-      nsCString spec;
-      nsresult rv = mScopeURI->GetSpecIgnoringRef(spec);
-      if (NS_WARN_IF(NS_FAILED(rv))) {
-        return mCallback->UnregisterFailed();
-      }
+#endif
 
-      nsRefPtr<ServiceWorkerRegistrationInfo> registration;
-      if (!domainInfo->mServiceWorkerRegistrationInfos.Get(spec,
-                                                           getter_AddRefs(registration))) {
-        return mCallback->UnregisterSucceeded(false);
-      }
-
-      MOZ_ASSERT(registration);
-
-      registration->mPendingUninstall = true;
-      rv = mCallback->UnregisterSucceeded(true);
-      if (NS_WARN_IF(NS_FAILED(rv))) {
-        return rv;
-      }
+  NS_ConvertUTF16toUTF8 scope(aScope);
+  nsRefPtr<ServiceWorkerManager::ServiceWorkerDomainInfo> domainInfo =
+    GetDomainInfo(scope);
+  ServiceWorkerJobQueue* queue = domainInfo->GetOrCreateJobQueue(scope);
+  MOZ_ASSERT(queue);
 
-      // The "Wait until no document is using registration" can actually be
-      // handled by [[HandleDocumentUnload]] in Bug 1041340, so we simply check
-      // if the document is currently in use here.
-      if (!registration->IsControllingDocuments()) {
-        if (!registration->mPendingUninstall) {
-          return NS_OK;
-        }
-
-        registration->Clear();
-        domainInfo->RemoveRegistration(registration);
-      }
-
-      return NS_OK;
-    }
-  };
-
-  nsRefPtr<nsIRunnable> unregisterRunnable =
-    new UnregisterRunnable(aCallback, scopeURI);
-  return NS_DispatchToCurrentThread(unregisterRunnable);
+  nsRefPtr<ServiceWorkerUnregisterJob> job =
+    new ServiceWorkerUnregisterJob(queue, scope, aCallback);
+  queue->Append(job);
+  return NS_OK;
 }
 
 /* static */
 already_AddRefed<ServiceWorkerManager>
 ServiceWorkerManager::GetInstance()
 {
   nsCOMPtr<nsIServiceWorkerManager> swm = mozilla::services::GetServiceWorkerManager();
   nsRefPtr<ServiceWorkerManager> concrete = do_QueryObject(swm);
@@ -2242,18 +2220,18 @@ ServiceWorkerManager::Update(const nsASt
   }
 
   ServiceWorkerJobQueue* queue = domainInfo->GetOrCreateJobQueue(scope);
   MOZ_ASSERT(queue);
 
   nsRefPtr<ServiceWorkerUpdateFinishCallback> cb =
     new ServiceWorkerUpdateFinishCallback();
 
-  nsRefPtr<ServiceWorkerRegisterJob> job
-    = new ServiceWorkerRegisterJob(queue, registration, cb);
+  nsRefPtr<ServiceWorkerRegisterJob> job =
+    new ServiceWorkerRegisterJob(queue, registration, cb);
   queue->Append(job);
   return NS_OK;
 }
 
 namespace {
 
 class MOZ_STACK_CLASS FilterRegistrationData
 {
--- a/dom/workers/ServiceWorkerManager.h
+++ b/dom/workers/ServiceWorkerManager.h
@@ -270,17 +270,17 @@ class ServiceWorkerManager MOZ_FINAL : p
 {
   friend class ActivationRunnable;
   friend class ServiceWorkerRegistrationInfo;
   friend class ServiceWorkerRegisterJob;
   friend class GetReadyPromiseRunnable;
   friend class GetRegistrationsRunnable;
   friend class GetRegistrationRunnable;
   friend class QueueFireUpdateFoundRunnable;
-  friend class UnregisterRunnable;
+  friend class ServiceWorkerUnregisterJob;
 
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSISERVICEWORKERMANAGER
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_SERVICEWORKERMANAGER_IMPL_IID)
 
   static ServiceWorkerManager* FactoryCreate()
   {
@@ -457,16 +457,23 @@ private:
   QueueFireEventOnServiceWorkerRegistrations(ServiceWorkerRegistrationInfo* aRegistration,
                                              const nsAString& aName);
 
   void
   FireEventOnServiceWorkerRegistrations(ServiceWorkerRegistrationInfo* aRegistration,
                                         const nsAString& aName);
 
   void
+  FireUpdateFound(ServiceWorkerRegistrationInfo* aRegistration)
+  {
+    FireEventOnServiceWorkerRegistrations(aRegistration,
+                                          NS_LITERAL_STRING("updatefound"));
+  }
+
+  void
   FireControllerChange(ServiceWorkerRegistrationInfo* aRegistration);
 
   void
   StorePendingReadyPromise(nsPIDOMWindow* aWindow, nsIURI* aURI, Promise* aPromise);
 
   void
   CheckPendingReadyPromises();
 
--- a/dom/workers/ServiceWorkerRegistration.cpp
+++ b/dom/workers/ServiceWorkerRegistration.cpp
@@ -159,32 +159,33 @@ ServiceWorkerRegistration::Unregister(Er
   nsCOMPtr<nsIDocument> document = GetOwner()->GetExtantDoc();
   if (!document) {
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
 
   nsCOMPtr<nsIURI> scopeURI;
   nsCOMPtr<nsIURI> baseURI = document->GetBaseURI();
+  // "If the origin of scope is not client's origin..."
   nsresult rv = NS_NewURI(getter_AddRefs(scopeURI), mScope, nullptr, baseURI);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
     return nullptr;
   }
 
   nsCOMPtr<nsIPrincipal> documentPrincipal = document->NodePrincipal();
   rv = documentPrincipal->CheckMayLoad(scopeURI, true /* report */,
                                        false /* allowIfInheritsPrinciple */);
   if (NS_FAILED(rv)) {
     aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
     return nullptr;
   }
 
   nsAutoCString uriSpec;
-  aRv = scopeURI->GetSpec(uriSpec);
+  aRv = scopeURI->GetSpecIgnoringRef(uriSpec);
   if (NS_WARN_IF(aRv.Failed())) {
     return nullptr;
   }
 
   nsCOMPtr<nsIServiceWorkerManager> swm =
     do_GetService(SERVICEWORKERMANAGER_CONTRACTID, &rv);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     aRv.Throw(rv);
--- a/dom/workers/test/serviceworkers/mochitest.ini
+++ b/dom/workers/test/serviceworkers/mochitest.ini
@@ -22,14 +22,13 @@ support-files =
 [test_unregister.html]
 skip-if = true # bug 1094375
 [test_installation_simple.html]
 skip-if = true # bug 1094375
 [test_get_serviced.html]
 [test_install_event.html]
 [test_navigator.html]
 [test_scopes.html]
-skip-if = true # bug 1124743
 [test_controller.html]
 [test_workerUpdate.html]
 skip-if = true # Enable after Bug 982726 postMessage is landed.
 [test_workerUnregister.html]
 skip-if = true # Enable after Bug 982726 postMessage is landed.
--- a/dom/workers/test/serviceworkers/test_installation_simple.html
+++ b/dom/workers/test/serviceworkers/test_installation_simple.html
@@ -101,16 +101,20 @@
         ok(e.name === "NetworkError", "Should fail with NetworkError");
       });
   }
 
   function parseError() {
     var p = navigator.serviceWorker.register("parse_error_worker.js", { scope: "parse_error/" });
     return p.then(function(wr) {
       ok(false, "Registration should fail with parse error");
+      return navigator.serviceWorker.getRegistration("parse_error/").then(function(swr) {
+        // See https://github.com/slightlyoff/ServiceWorker/issues/547
+        is(swr, undefined, "A failed registration for a scope with no prior controllers should clear itself");
+      });
     }, function(e) {
     info("NSM " + e.name);
       ok(e instanceof Error, "Registration should fail with parse error");
     });
   }
 
   // FIXME(nsm): test for parse error when Update step doesn't happen (directly from register).
 
--- a/dom/workers/test/serviceworkers/test_unregister.html
+++ b/dom/workers/test/serviceworkers/test_unregister.html
@@ -81,35 +81,19 @@
 
     return testPromise.then(function() {
       div.removeChild(ifr);
     });
   }
 
   function runTest() {
     simpleRegister()
-      .then(function(v) {
-        info("simpleRegister() promise resolved");
-      })
       .then(testControlled)
-      .then(function(v) {
-        info("testControlled() promise resolved");
-      }, function(e) {
-        info("testControlled() promise rejected " + e);
-      })
       .then(unregister)
-      .then(function(v) {
-        info("unregister() promise resolved");
-      })
       .then(testUncontrolled)
-      .then(function(v) {
-        info("testUncontrolled() promise resolved");
-      }, function(e) {
-        info("testUncontrolled() promise rejected " + e);
-      })
       .then(function() {
         SimpleTest.finish();
       }).catch(function(e) {
         ok(false, "Some test failed with error " + e);
         SimpleTest.finish();
       });
   }
 
--- a/gfx/layers/client/TextureClient.h
+++ b/gfx/layers/client/TextureClient.h
@@ -454,17 +454,17 @@ public:
   /**
    * Set AsyncTransactionTracker of RemoveTextureFromCompositableAsync() transaction.
    */
   virtual void SetRemoveFromCompositableTracker(AsyncTransactionTracker* aTracker) {}
 
   /**
    * This function waits until the buffer is no longer being used.
    */
-  virtual void WaitForBufferOwnership() {}
+  virtual void WaitForBufferOwnership(bool aWaitReleaseFence = true) {}
 
   /**
    * Track how much of this texture is wasted.
    * For example we might allocate a 256x256 tile but only use 10x10.
    */
    void SetWaste(int aWasteArea) {
      mWasteTracker.Update(aWasteArea, BytesPerPixel(GetFormat()));
    }
--- a/gfx/layers/opengl/GrallocTextureClient.cpp
+++ b/gfx/layers/opengl/GrallocTextureClient.cpp
@@ -83,23 +83,27 @@ GrallocTextureClientOGL::ToSurfaceDescri
 
 void
 GrallocTextureClientOGL::SetRemoveFromCompositableTracker(AsyncTransactionTracker* aTracker)
 {
   mRemoveFromCompositableTracker = aTracker;
 }
 
 void
-GrallocTextureClientOGL::WaitForBufferOwnership()
+GrallocTextureClientOGL::WaitForBufferOwnership(bool aWaitReleaseFence)
 {
   if (mRemoveFromCompositableTracker) {
     mRemoveFromCompositableTracker->WaitComplete();
     mRemoveFromCompositableTracker = nullptr;
   }
 
+  if (!aWaitReleaseFence) {
+    return;
+  }
+
 #if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
    if (mReleaseFenceHandle.IsValid()) {
      android::sp<Fence> fence = mReleaseFenceHandle.mFence;
 #if ANDROID_VERSION == 17
      fence->waitForever(1000, "GrallocTextureClientOGL::Lock");
      // 1000 is what Android uses. It is a warning timeout in ms.
      // This timeout was removed in ANDROID_VERSION 18.
 #else
@@ -117,26 +121,42 @@ GrallocTextureClientOGL::Lock(OpenMode a
   if (!IsValid() || !IsAllocated()) {
     return false;
   }
 
   if (mMappedBuffer) {
     return true;
   }
 
+#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 21
+  WaitForBufferOwnership(false /* aWaitReleaseFence */);
+#else
   WaitForBufferOwnership();
+#endif
 
   uint32_t usage = 0;
   if (aMode & OpenMode::OPEN_READ) {
     usage |= GRALLOC_USAGE_SW_READ_OFTEN;
   }
   if (aMode & OpenMode::OPEN_WRITE) {
     usage |= GRALLOC_USAGE_SW_WRITE_OFTEN;
   }
-  int32_t rv = mGraphicBuffer->lock(usage, reinterpret_cast<void**>(&mMappedBuffer));
+#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 21
+  android::sp<Fence> fence = android::Fence::NO_FENCE;
+  if (mReleaseFenceHandle.IsValid()) {
+    fence = mReleaseFenceHandle.mFence;
+  }
+  mReleaseFenceHandle = FenceHandle();
+  int32_t rv = mGraphicBuffer->lockAsync(usage,
+                                         reinterpret_cast<void**>(&mMappedBuffer),
+                                         fence->dup());
+#else
+  int32_t rv = mGraphicBuffer->lock(usage,
+                                    reinterpret_cast<void**>(&mMappedBuffer));
+#endif
   if (rv) {
     mMappedBuffer = nullptr;
     NS_WARNING("Couldn't lock graphic buffer");
     return false;
   }
   return BufferTextureClient::Lock(aMode);
 }
 
--- a/gfx/layers/opengl/GrallocTextureClient.h
+++ b/gfx/layers/opengl/GrallocTextureClient.h
@@ -53,17 +53,17 @@ public:
   virtual bool HasInternalBuffer() const MOZ_OVERRIDE { return false; }
 
   virtual bool IsAllocated() const MOZ_OVERRIDE;
 
   virtual bool ToSurfaceDescriptor(SurfaceDescriptor& aOutDescriptor) MOZ_OVERRIDE;
 
   virtual void SetRemoveFromCompositableTracker(AsyncTransactionTracker* aTracker) MOZ_OVERRIDE;
 
-  virtual void WaitForBufferOwnership() MOZ_OVERRIDE;
+  virtual void WaitForBufferOwnership(bool aWaitReleaseFence = true) MOZ_OVERRIDE;
 
   void InitWith(MaybeMagicGrallocBufferHandle aDesc, gfx::IntSize aSize);
 
   void SetTextureFlags(TextureFlags aFlags) { AddFlags(aFlags); }
 
   gfx::IntSize GetSize() const MOZ_OVERRIDE { return mSize; }
 
   android::sp<android::GraphicBuffer> GetGraphicBuffer()
--- a/gfx/layers/opengl/MacIOSurfaceTextureHostOGL.cpp
+++ b/gfx/layers/opengl/MacIOSurfaceTextureHostOGL.cpp
@@ -22,17 +22,29 @@ MacIOSurfaceTextureHostOGL::MacIOSurface
 bool
 MacIOSurfaceTextureHostOGL::Lock()
 {
   if (!mCompositor || !mSurface) {
     return false;
   }
 
   if (!mTextureSource) {
-    mTextureSource = new MacIOSurfaceTextureSourceOGL(mCompositor, mSurface);
+    GLuint textureHandle;
+    gl::GLContext* gl = mCompositor->gl();
+    gl->fGenTextures(1, &textureHandle);
+    gl->fBindTexture(LOCAL_GL_TEXTURE_RECTANGLE_ARB, textureHandle);
+    gl->fTexParameteri(LOCAL_GL_TEXTURE_RECTANGLE_ARB, LOCAL_GL_TEXTURE_WRAP_T, LOCAL_GL_CLAMP_TO_EDGE);
+    gl->fTexParameteri(LOCAL_GL_TEXTURE_RECTANGLE_ARB, LOCAL_GL_TEXTURE_WRAP_S, LOCAL_GL_CLAMP_TO_EDGE);
+    mSurface->CGLTexImageIOSurface2D(gl::GLContextCGL::Cast(gl)->GetCGLContext());
+
+    mTextureSource = new GLTextureSource(mCompositor, textureHandle, LOCAL_GL_TEXTURE_RECTANGLE_ARB,
+                                         gfx::IntSize(mSurface->GetDevicePixelWidth(),
+                                                      mSurface->GetDevicePixelHeight()),
+                                         mSurface->HasAlpha() ? gfx::SurfaceFormat::R8G8B8A8:
+                                                                gfx::SurfaceFormat::R8G8B8X8);
   }
   return true;
 }
 
 void
 MacIOSurfaceTextureHostOGL::SetCompositor(Compositor* aCompositor)
 {
   CompositorOGL* glCompositor = static_cast<CompositorOGL*>(aCompositor);
--- a/gfx/layers/opengl/MacIOSurfaceTextureHostOGL.h
+++ b/gfx/layers/opengl/MacIOSurfaceTextureHostOGL.h
@@ -89,16 +89,16 @@ public:
   virtual gfx::IntSize GetSize() const MOZ_OVERRIDE;
 
 #ifdef MOZ_LAYERS_HAVE_LOG
   virtual const char* Name() MOZ_OVERRIDE { return "MacIOSurfaceTextureHostOGL"; }
 #endif
 
 protected:
   RefPtr<CompositorOGL> mCompositor;
-  RefPtr<MacIOSurfaceTextureSourceOGL> mTextureSource;
+  RefPtr<GLTextureSource> mTextureSource;
   RefPtr<MacIOSurface> mSurface;
 };
 
 }
 }
 
 #endif // MOZILLA_GFX_MACIOSURFACETEXTUREHOSTOGL_H
--- a/gfx/thebes/gfxPangoFonts.cpp
+++ b/gfx/thebes/gfxPangoFonts.cpp
@@ -200,18 +200,18 @@ public:
     {
         cairo_font_face_set_user_data(mFontFace,
                                       &sFontEntryKey,
                                       nullptr,
                                       nullptr);
         cairo_font_face_destroy(mFontFace);
     }
 
-    virtual void ForgetHBFace();
-    virtual void ReleaseGrFace(gr_face* aFace);
+    virtual void ForgetHBFace() MOZ_OVERRIDE;
+    virtual void ReleaseGrFace(gr_face* aFace) MOZ_OVERRIDE;
 
 protected:
     virtual nsresult
     CopyFontTable(uint32_t aTableTag, FallibleTArray<uint8_t>& aBuffer) MOZ_OVERRIDE;
 
     void MaybeReleaseFTFace();
 
 private:
@@ -666,22 +666,22 @@ public:
 
 #ifdef USE_SKIA
     virtual mozilla::TemporaryRef<mozilla::gfx::GlyphRenderingOptions>
         GetGlyphRenderingOptions(const TextRunDrawParams* aRunParams = nullptr) MOZ_OVERRIDE;
 #endif
 
     // return a cloned font resized and offset to simulate sub/superscript glyphs
     virtual already_AddRefed<gfxFont>
-    GetSubSuperscriptFont(int32_t aAppUnitsPerDevPixel);
+    GetSubSuperscriptFont(int32_t aAppUnitsPerDevPixel) MOZ_OVERRIDE;
 
 protected:
     virtual already_AddRefed<gfxFont> MakeScaledFont(gfxFontStyle *aFontStyle,
                                                      gfxFloat aFontScale);
-    virtual already_AddRefed<gfxFont> GetSmallCapsFont();
+    virtual already_AddRefed<gfxFont> GetSmallCapsFont() MOZ_OVERRIDE;
 
 private:
     gfxFcFont(cairo_scaled_font_t *aCairoFont, gfxFcFontEntry *aFontEntry,
               const gfxFontStyle *aFontStyle);
 
     // key for locating a gfxFcFont corresponding to a cairo_scaled_font
     static cairo_user_data_key_t sGfxFontKey;
 };
--- a/gfx/thebes/gfxPlatform.cpp
+++ b/gfx/thebes/gfxPlatform.cpp
@@ -164,17 +164,17 @@ public:
 /// this gets called to be large - it is meant for critical errors only.
 
 class CrashStatsLogForwarder: public mozilla::gfx::LogForwarder
 {
 public:
   explicit CrashStatsLogForwarder(const char* aKey);
   virtual void Log(const std::string& aString) MOZ_OVERRIDE;
 
-  virtual std::vector<std::pair<int32_t,std::string> > StringsVectorCopy();
+  virtual std::vector<std::pair<int32_t,std::string> > StringsVectorCopy() MOZ_OVERRIDE;
 
   void SetCircularBufferSize(uint32_t aCapacity);
 
 private:
   // Helpers for the Log()
   bool UpdateStringsVector(const std::string& aString);
   void UpdateCrashReport();
 
--- a/hal/gonk/GonkHal.cpp
+++ b/hal/gonk/GonkHal.cpp
@@ -19,17 +19,16 @@
 #include <errno.h>
 #include <fcntl.h>
 #include <linux/android_alarm.h>
 #include <math.h>
 #include <regex.h>
 #include <sched.h>
 #include <stdio.h>
 #include <sys/klog.h>
-#include <sys/stat.h>
 #include <sys/syscall.h>
 #include <sys/resource.h>
 #include <time.h>
 #include <unistd.h>
 
 #include "mozilla/DebugOnly.h"
 
 #include "android/log.h"
@@ -43,17 +42,16 @@
 #include "utils/threads.h"
 
 #include "base/message_loop.h"
 
 #include "Hal.h"
 #include "HalImpl.h"
 #include "HalLog.h"
 #include "mozilla/ArrayUtils.h"
-#include "mozilla/ClearOnShutdown.h"
 #include "mozilla/dom/battery/Constants.h"
 #include "mozilla/DebugOnly.h"
 #include "mozilla/FileUtils.h"
 #include "mozilla/Monitor.h"
 #include "mozilla/RefPtr.h"
 #include "mozilla/Services.h"
 #include "mozilla/StaticPtr.h"
 #include "mozilla/Preferences.h"
@@ -625,16 +623,38 @@ GetCurrentBatteryInformation(hal::Batter
   }
 }
 
 namespace {
 
 /**
  * RAII class to help us remember to close file descriptors.
  */
+const char *wakeLockFilename = "/sys/power/wake_lock";
+const char *wakeUnlockFilename = "/sys/power/wake_unlock";
+
+template<ssize_t n>
+bool ReadFromFile(const char *filename, char (&buf)[n])
+{
+  int fd = open(filename, O_RDONLY);
+  ScopedClose autoClose(fd);
+  if (fd < 0) {
+    HAL_LOG("Unable to open file %s.", filename);
+    return false;
+  }
+
+  ssize_t numRead = read(fd, buf, n);
+  if (numRead < 0) {
+    HAL_LOG("Error reading from file %s.", filename);
+    return false;
+  }
+
+  buf[std::min(numRead, n - 1)] = '\0';
+  return true;
+}
 
 bool WriteToFile(const char *filename, const char *toWrite)
 {
   int fd = open(filename, O_WRONLY);
   ScopedClose autoClose(fd);
   if (fd < 0) {
     HAL_LOG("Unable to open file %s.", filename);
     return false;
@@ -750,19 +770,16 @@ SetScreenBrightness(double brightness)
   }
 }
 
 static Monitor* sInternalLockCpuMonitor = nullptr;
 
 static void
 UpdateCpuSleepState()
 {
-  const char *wakeLockFilename = "/sys/power/wake_lock";
-  const char *wakeUnlockFilename = "/sys/power/wake_unlock";
-
   sInternalLockCpuMonitor->AssertCurrentThreadOwns();
   bool allowed = sCpuSleepAllowed && !sInternalLockCpuCount;
   WriteToFile(allowed ? wakeUnlockFilename : wakeLockFilename, "gecko");
 }
 
 static void
 InternalLockCpu() {
   MonitorAutoLock monitor(*sInternalLockCpuMonitor);
@@ -1264,16 +1281,17 @@ OomVictimLogger::Observe(
          after_float == ']') {
       if (lineTimestamp <= mLastLineChecked) {
         continue;
       }
 
       lineTimestampFound = true;
       mLastLineChecked = lineTimestamp;
     }
+      
 
     // Log interesting lines
     for (size_t i = 0; i < regex_count; i++) {
       int matching = !regexec(&(mRegexes[i]), line_begin, 0, NULL, 0);
       if (matching) {
         // Log content of kernel message. We try to skip the ], but if for
         // some reason (most likely due to buffer overflow/wraparound), we
         // can't find the ] then we just log the entire line.
@@ -1289,357 +1307,16 @@ OomVictimLogger::Observe(
         break;
       }
     }
   }
 
   return NS_OK;
 }
 
-/**
- * Wraps a particular ProcessPriority, giving us easy access to the prefs that
- * are relevant to it.
- *
- * Creating a PriorityClass also ensures that the control group is created.
- */
-class PriorityClass
-{
-public:
-  /**
-   * Create a PriorityClass for the given ProcessPriority.  This implicitly
-   * reads the relevant prefs and opens the cgroup.procs file of the relevant
-   * control group caching its file descriptor for later use.
-   */
-  PriorityClass(ProcessPriority aPriority);
-
-  /**
-   * Closes the file descriptor for the cgroup.procs file of the associated
-   * control group.
-   */
-  ~PriorityClass();
-
-  PriorityClass(const PriorityClass& aOther);
-  PriorityClass& operator=(const PriorityClass& aOther);
-
-  ProcessPriority Priority()
-  {
-    return mPriority;
-  }
-
-  int32_t OomScoreAdj()
-  {
-    return clamped<int32_t>(mOomScoreAdj, OOM_SCORE_ADJ_MIN, OOM_SCORE_ADJ_MAX);
-  }
-
-  int32_t KillUnderKB()
-  {
-    return mKillUnderKB;
-  }
-
-  nsCString CGroup()
-  {
-    return mGroup;
-  }
-
-  /**
-   * Adds a process to this priority class, this moves the process' PID into
-   * the associated control group.
-   *
-   * @param aPid The PID of the process to be added.
-   */
-  void AddProcess(int aPid);
-
-private:
-  ProcessPriority mPriority;
-  int32_t mOomScoreAdj;
-  int32_t mKillUnderKB;
-  int mCpuCGroupProcsFd;
-  int mMemCGroupProcsFd;
-  nsCString mGroup;
-
-  /**
-   * Return a string that identifies where we can find the value of aPref
-   * that's specific to mPriority.  For example, we might return
-   * "hal.processPriorityManager.gonk.FOREGROUND_HIGH.oomScoreAdjust".
-   */
-  nsCString PriorityPrefName(const char* aPref)
-  {
-    return nsPrintfCString("hal.processPriorityManager.gonk.%s.%s",
-                           ProcessPriorityToString(mPriority), aPref);
-  }
-
-  /**
-   * Get the full path of the cgroup.procs file associated with the group.
-   */
-  nsCString CpuCGroupProcsFilename()
-  {
-    nsCString cgroupName = mGroup;
-
-    /* If mGroup is empty, our cgroup.procs file is the root procs file,
-     * located at /dev/cpuctl/cgroup.procs.  Otherwise our procs file is
-     * /dev/cpuctl/NAME/cgroup.procs. */
-
-    if (!mGroup.IsEmpty()) {
-      cgroupName.AppendLiteral("/");
-    }
-
-    return NS_LITERAL_CSTRING("/dev/cpuctl/") + cgroupName +
-           NS_LITERAL_CSTRING("cgroup.procs");
-  }
-
-  nsCString MemCGroupProcsFilename()
-  {
-    nsCString cgroupName = mGroup;
-
-    /* If mGroup is empty, our cgroup.procs file is the root procs file,
-     * located at /sys/fs/cgroup/memory/cgroup.procs.  Otherwise our procs
-     * file is /sys/fs/cgroup/memory/NAME/cgroup.procs. */
-
-    if (!mGroup.IsEmpty()) {
-      cgroupName.AppendLiteral("/");
-    }
-
-    return NS_LITERAL_CSTRING("/sys/fs/cgroup/memory/") + cgroupName +
-           NS_LITERAL_CSTRING("cgroup.procs");
-  }
-
-  int OpenCpuCGroupProcs()
-  {
-    return open(CpuCGroupProcsFilename().get(), O_WRONLY);
-  }
-
-  int OpenMemCGroupProcs()
-  {
-    return open(MemCGroupProcsFilename().get(), O_WRONLY);
-  }
-};
-
-/**
- * Creates a directory and parents (essentially mkdir -p, but
- * this only create the directories within the cgroup name).
- */
-static bool MakeCGroupDir(const nsACString& aRootDir,
-                          const nsACString& aGroupName)
-{
-  NS_NAMED_LITERAL_CSTRING(kSlash, "/");
-
-  // Create directories contained within aGroupName
-  nsCString cgroupIter = aGroupName + kSlash;
-
-  int32_t offset = 0;
-  while ((offset = cgroupIter.FindChar('/', offset)) != -1) {
-    nsAutoCString path = aRootDir + Substring(cgroupIter, 0, offset);
-    int rv = mkdir(path.get(), 0744);
-
-    if (rv == -1 && errno != EEXIST) {
-      HAL_LOG("Could not create the %s control group.", path.get());
-      return false;
-    }
-
-    offset++;
-  }
-  return true;
-}
-
-/**
- * Try to create the cgroup for the given PriorityClass, if it doesn't already
- * exist.  This essentially implements mkdir -p; that is, we create parent
- * cgroups as necessary.  The group parameters are also set according to
- * the corresponding preferences.
- *
- * @param aGroup The name of the group.
- * @return true if we successfully created the cgroup, or if it already
- * exists.  Otherwise, return false.
- */
-static bool
-EnsureCpuCGroupExists(const nsACString& aGroup)
-{
-  NS_NAMED_LITERAL_CSTRING(kDevCpuCtl, "/dev/cpuctl/");
-  NS_NAMED_LITERAL_CSTRING(kSlash, "/");
-
-  nsAutoCString prefPrefix("hal.processPriorityManager.gonk.cgroups.");
-
-  /* If cgroup is not empty, append the cgroup name and a dot to obtain the
-   * group specific preferences. */
-  if (!aGroup.IsEmpty()) {
-    prefPrefix += aGroup + NS_LITERAL_CSTRING(".");
-  }
-
-  nsAutoCString cpuSharesPref(prefPrefix + NS_LITERAL_CSTRING("cpu_shares"));
-  int cpuShares = Preferences::GetInt(cpuSharesPref.get());
-
-  nsAutoCString cpuNotifyOnMigratePref(prefPrefix
-    + NS_LITERAL_CSTRING("cpu_notify_on_migrate"));
-  int cpuNotifyOnMigrate = Preferences::GetInt(cpuNotifyOnMigratePref.get());
-
-  if (!MakeCGroupDir(kDevCpuCtl, aGroup)) {
-    return false;
-  }
-
-  nsAutoCString pathPrefix(kDevCpuCtl + aGroup + kSlash);
-  nsAutoCString cpuSharesPath(pathPrefix + NS_LITERAL_CSTRING("cpu.shares"));
-  if (cpuShares && !WriteToFile(cpuSharesPath.get(),
-                                nsPrintfCString("%d", cpuShares).get())) {
-    HAL_LOG("Could not set the cpu share for group %s", cpuSharesPath.get());
-    return false;
-  }
-
-  nsAutoCString notifyOnMigratePath(pathPrefix
-    + NS_LITERAL_CSTRING("cpu.notify_on_migrate"));
-  if (!WriteToFile(notifyOnMigratePath.get(),
-                   nsPrintfCString("%d", cpuNotifyOnMigrate).get())) {
-    HAL_LOG("Could not set the cpu migration notification flag for group %s",
-            notifyOnMigratePath.get());
-    return false;
-  }
-
-  return true;
-}
-
-static bool
-EnsureMemCGroupExists(const nsACString& aGroup)
-{
-  NS_NAMED_LITERAL_CSTRING(kMemCtl, "/sys/fs/cgroup/memory/");
-  NS_NAMED_LITERAL_CSTRING(kSlash, "/");
-
-  nsAutoCString prefPrefix("hal.processPriorityManager.gonk.cgroups.");
-
-  /* If cgroup is not empty, append the cgroup name and a dot to obtain the
-   * group specific preferences. */
-  if (!aGroup.IsEmpty()) {
-    prefPrefix += aGroup + NS_LITERAL_CSTRING(".");
-  }
-
-  nsAutoCString memSwappinessPref(prefPrefix +
-                                  NS_LITERAL_CSTRING("memory_swappiness"));
-  int memSwappiness = Preferences::GetInt(memSwappinessPref.get());
-
-  if (!MakeCGroupDir(kMemCtl, aGroup)) {
-    return false;
-  }
-
-  nsAutoCString pathPrefix(kMemCtl + aGroup + kSlash);
-  nsAutoCString memSwappinessPath(pathPrefix +
-                                  NS_LITERAL_CSTRING("memory.swappiness"));
-  if (!WriteToFile(memSwappinessPath.get(),
-                   nsPrintfCString("%d", memSwappiness).get())) {
-    HAL_LOG("Could not set the memory.swappiness for group %s",
-            memSwappinessPath.get());
-    return false;
-  }
-  return true;
-}
-
-PriorityClass::PriorityClass(ProcessPriority aPriority)
-  : mPriority(aPriority)
-  , mOomScoreAdj(0)
-  , mKillUnderKB(0)
-  , mCpuCGroupProcsFd(-1)
-  , mMemCGroupProcsFd(-1)
-{
-  DebugOnly<nsresult> rv;
-
-  rv = Preferences::GetInt(PriorityPrefName("OomScoreAdjust").get(),
-                           &mOomScoreAdj);
-  MOZ_ASSERT(NS_SUCCEEDED(rv), "Missing oom_score_adj preference");
-
-  rv = Preferences::GetInt(PriorityPrefName("KillUnderKB").get(),
-                           &mKillUnderKB);
-
-  rv = Preferences::GetCString(PriorityPrefName("cgroup").get(), &mGroup);
-  MOZ_ASSERT(NS_SUCCEEDED(rv), "Missing control group preference");
-
-  if (EnsureCpuCGroupExists(mGroup)) {
-    mCpuCGroupProcsFd = OpenCpuCGroupProcs();
-  }
-  if (EnsureMemCGroupExists(mGroup)) {
-    mMemCGroupProcsFd = OpenMemCGroupProcs();
-  }
-}
-
-PriorityClass::~PriorityClass()
-{
-  MOZ_TEMP_FAILURE_RETRY(close(mCpuCGroupProcsFd));
-  MOZ_TEMP_FAILURE_RETRY(close(mMemCGroupProcsFd));
-}
-
-PriorityClass::PriorityClass(const PriorityClass& aOther)
-  : mPriority(aOther.mPriority)
-  , mOomScoreAdj(aOther.mOomScoreAdj)
-  , mKillUnderKB(aOther.mKillUnderKB)
-  , mGroup(aOther.mGroup)
-{
-  mCpuCGroupProcsFd = OpenCpuCGroupProcs();
-  mMemCGroupProcsFd = OpenMemCGroupProcs();
-}
-
-PriorityClass& PriorityClass::operator=(const PriorityClass& aOther)
-{
-  mPriority = aOther.mPriority;
-  mOomScoreAdj = aOther.mOomScoreAdj;
-  mKillUnderKB = aOther.mKillUnderKB;
-  mGroup = aOther.mGroup;
-  mCpuCGroupProcsFd = OpenCpuCGroupProcs();
-  mMemCGroupProcsFd = OpenMemCGroupProcs();
-  return *this;
-}
-
-void PriorityClass::AddProcess(int aPid)
-{
-  if (mCpuCGroupProcsFd >= 0) {
-    nsPrintfCString str("%d", aPid);
-
-    if (write(mCpuCGroupProcsFd, str.get(), str.Length()) < 0) {
-      HAL_ERR("Couldn't add PID %d to the %s cpu control group",
-              aPid, mGroup.get());
-    }
-  }
-
-  if (mMemCGroupProcsFd >= 0) {
-    nsPrintfCString str("%d", aPid);
-
-    if (write(mMemCGroupProcsFd, str.get(), str.Length()) < 0) {
-      HAL_ERR("Couldn't add PID %d to the %s memory control group",
-              aPid, mGroup.get());
-    }
-  }
-}
-
-/**
- * Get the PriorityClass associated with the given ProcessPriority.
- *
- * If you pass an invalid ProcessPriority value, we return null.
- *
- * The pointers returned here are owned by GetPriorityClass (don't free them
- * yourself).  They are guaranteed to stick around until shutdown.
- */
-PriorityClass*
-GetPriorityClass(ProcessPriority aPriority)
-{
-  static StaticAutoPtr<nsTArray<PriorityClass>> priorityClasses;
-
-  // Initialize priorityClasses if this is the first time we're running this
-  // method.
-  if (!priorityClasses) {
-    priorityClasses = new nsTArray<PriorityClass>();
-    ClearOnShutdown(&priorityClasses);
-
-    for (int32_t i = 0; i < NUM_PROCESS_PRIORITY; i++) {
-      priorityClasses->AppendElement(PriorityClass(ProcessPriority(i)));
-    }
-  }
-
-  if (aPriority < 0 ||
-      static_cast<uint32_t>(aPriority) >= priorityClasses->Length()) {
-    return nullptr;
-  }
-
-  return &(*priorityClasses)[aPriority];
-}
-
 static void
 EnsureKernelLowMemKillerParamsSet()
 {
   static bool kernelLowMemKillerParamsSet;
   if (kernelLowMemKillerParamsSet) {
     return;
   }
   kernelLowMemKillerParamsSet = true;
@@ -1670,22 +1347,31 @@ EnsureKernelLowMemKillerParamsSet()
   int32_t countOfLowmemorykillerParametersSets = 0;
 
   long page_size = sysconf(_SC_PAGESIZE);
 
   for (int i = NUM_PROCESS_PRIORITY - 1; i >= 0; i--) {
     // The system doesn't function correctly if we're missing these prefs, so
     // crash loudly.
 
-    PriorityClass* pc = GetPriorityClass(static_cast<ProcessPriority>(i));
+    ProcessPriority priority = static_cast<ProcessPriority>(i);
 
-    int32_t oomScoreAdj = pc->OomScoreAdj();
-    int32_t killUnderKB = pc->KillUnderKB();
+    int32_t oomScoreAdj;
+    if (!NS_SUCCEEDED(Preferences::GetInt(
+          nsPrintfCString("hal.processPriorityManager.gonk.%s.OomScoreAdjust",
+                          ProcessPriorityToString(priority)).get(),
+          &oomScoreAdj))) {
+      MOZ_CRASH();
+    }
 
-    if (killUnderKB == 0) {
+    int32_t killUnderKB;
+    if (!NS_SUCCEEDED(Preferences::GetInt(
+          nsPrintfCString("hal.processPriorityManager.gonk.%s.KillUnderKB",
+                          ProcessPriorityToString(priority)).get(),
+          &killUnderKB))) {
       // ProcessPriority values like PROCESS_PRIORITY_FOREGROUND_KEYBOARD,
       // which has only OomScoreAdjust but lacks KillUnderMB value, will not
       // create new LMK parameters.
       continue;
     }
 
     // The LMK in kernel silently malfunctions if we assign the parameters
     // in non-increasing order, so we add this assertion here. See bug 887192.
@@ -1706,18 +1392,17 @@ EnsureKernelLowMemKillerParamsSet()
     countOfLowmemorykillerParametersSets++;
   }
 
   // Strip off trailing commas.
   adjParams.Cut(adjParams.Length() - 1, 1);
   minfreeParams.Cut(minfreeParams.Length() - 1, 1);
   if (!adjParams.IsEmpty() && !minfreeParams.IsEmpty()) {
     WriteToFile("/sys/module/lowmemorykiller/parameters/adj", adjParams.get());
-    WriteToFile("/sys/module/lowmemorykiller/parameters/minfree",
-                minfreeParams.get());
+    WriteToFile("/sys/module/lowmemorykiller/parameters/minfree", minfreeParams.get());
   }
 
   // Set the low-memory-notification threshold.
   int32_t lowMemNotifyThresholdKB;
   if (NS_SUCCEEDED(Preferences::GetInt(
         "hal.processPriorityManager.gonk.notifyLowMemUnderKB",
         &lowMemNotifyThresholdKB))) {
 
@@ -1729,16 +1414,158 @@ EnsureKernelLowMemKillerParamsSet()
   // Ensure OOM events appear in logcat
   nsRefPtr<OomVictimLogger> oomLogger = new OomVictimLogger();
   nsCOMPtr<nsIObserverService> os = services::GetObserverService();
   if (os) {
     os->AddObserver(oomLogger, "ipc:content-shutdown", false);
   }
 }
 
+static void
+SetNiceForPid(int aPid, int aNice)
+{
+  errno = 0;
+  int origProcPriority = getpriority(PRIO_PROCESS, aPid);
+  if (errno) {
+    HAL_LOG("Unable to get nice for pid=%d; error %d.  SetNiceForPid bailing.",
+            aPid, errno);
+    return;
+  }
+
+  int rv = setpriority(PRIO_PROCESS, aPid, aNice);
+  if (rv) {
+    HAL_LOG("Unable to set nice for pid=%d; error %d.  SetNiceForPid bailing.",
+            aPid, errno);
+    return;
+  }
+
+  // On Linux, setpriority(aPid) modifies the priority only of the main
+  // thread of that process.  We have to modify the priorities of all of the
+  // process's threads as well, so iterate over all the threads and increase
+  // each of their priorites by aNice - origProcPriority (and also ensure that
+  // none of the tasks has a lower priority than the main thread).
+  //
+  // This is horribly racy.
+
+  DIR* tasksDir = opendir(nsPrintfCString("/proc/%d/task/", aPid).get());
+  if (!tasksDir) {
+    HAL_LOG("Unable to open /proc/%d/task.  SetNiceForPid bailing.", aPid);
+    return;
+  }
+
+  // Be careful not to leak tasksDir; after this point, we must call closedir().
+
+  while (struct dirent* de = readdir(tasksDir)) {
+    char* endptr = nullptr;
+    long tidlong = strtol(de->d_name, &endptr, /* base */ 10);
+    if (*endptr || tidlong < 0 || tidlong > INT32_MAX || tidlong == aPid) {
+      // if dp->d_name was not an integer, was negative (?!) or too large, or
+      // was the same as aPid, we're not interested.
+      //
+      // (The |tidlong == aPid| check is very important; without it, we'll
+      // renice aPid twice, and the second renice will be relative to the
+      // priority set by the first renice.)
+      continue;
+    }
+
+    int tid = static_cast<int>(tidlong);
+
+    // Do not set the priority of threads running with a real-time policy
+    // as part of the bulk process adjustment.  These threads need to run
+    // at their specified priority in order to meet timing guarantees.
+    int schedPolicy = sched_getscheduler(tid);
+    if (schedPolicy == SCHED_FIFO || schedPolicy == SCHED_RR) {
+      continue;
+    }
+
+    errno = 0;
+    // Get and set the task's new priority.
+    int origtaskpriority = getpriority(PRIO_PROCESS, tid);
+    if (errno) {
+      HAL_LOG("Unable to get nice for tid=%d (pid=%d); error %d.  This isn't "
+              "necessarily a problem; it could be a benign race condition.",
+              tid, aPid, errno);
+      continue;
+    }
+
+    int newtaskpriority =
+      std::max(origtaskpriority - origProcPriority + aNice, aNice);
+
+    // Do not reduce priority of threads already running at priorities greater
+    // than normal.  These threads are likely special service threads that need
+    // elevated priorities to process audio, display composition, etc.
+    if (newtaskpriority > origtaskpriority &&
+        origtaskpriority < ANDROID_PRIORITY_NORMAL) {
+      continue;
+    }
+
+    rv = setpriority(PRIO_PROCESS, tid, newtaskpriority);
+
+    if (rv) {
+      HAL_LOG("Unable to set nice for tid=%d (pid=%d); error %d.  This isn't "
+              "necessarily a problem; it could be a benign race condition.",
+              tid, aPid, errno);
+      continue;
+    }
+  }
+
+  HAL_LOG("Changed nice for pid %d from %d to %d.",
+          aPid, origProcPriority, aNice);
+
+  closedir(tasksDir);
+}
+
+/*
+ * Used to store the nice value adjustments and oom_adj values for the various
+ * process priority levels.
+ */
+struct ProcessPriorityPrefs {
+  bool initialized;
+  int lowPriorityNice;
+  struct {
+    int nice;
+    int oomScoreAdj;
+  } priorities[NUM_PROCESS_PRIORITY];
+};
+
+/*
+ * Reads the preferences for the various process priority levels and sets up
+ * watchers so that if they're dynamically changed the change is reflected on
+ * the appropriate variables.
+ */
+void
+EnsureProcessPriorityPrefs(ProcessPriorityPrefs* prefs)
+{
+  if (prefs->initialized) {
+    return;
+  }
+
+  // Read the preferences for process priority levels
+  for (int i = PROCESS_PRIORITY_BACKGROUND; i < NUM_PROCESS_PRIORITY; i++) {
+    ProcessPriority priority = static_cast<ProcessPriority>(i);
+
+    // Read the nice values
+    const char* processPriorityStr = ProcessPriorityToString(priority);
+    nsPrintfCString niceStr("hal.processPriorityManager.gonk.%s.Nice",
+                            processPriorityStr);
+    Preferences::AddIntVarCache(&prefs->priorities[i].nice, niceStr.get());
+
+    // Read the oom_adj scores
+    nsPrintfCString oomStr("hal.processPriorityManager.gonk.%s.OomScoreAdjust",
+                           processPriorityStr);
+    Preferences::AddIntVarCache(&prefs->priorities[i].oomScoreAdj,
+                                oomStr.get());
+  }
+
+  Preferences::AddIntVarCache(&prefs->lowPriorityNice,
+                              "hal.processPriorityManager.gonk.LowCPUNice");
+
+  prefs->initialized = true;
+}
+
 void
 SetProcessPriority(int aPid,
                    ProcessPriority aPriority,
                    ProcessCPUPriority aCPUPriority,
                    uint32_t aBackgroundLRU)
 {
   HAL_LOG("SetProcessPriority(pid=%d, priority=%d, cpuPriority=%d, LRU=%u)",
           aPid, aPriority, aCPUPriority, aBackgroundLRU);
@@ -1747,33 +1574,59 @@ SetProcessPriority(int aPid,
   // OOM parameters according to our prefs.
   //
   // We could/should do this on startup instead of waiting for the first
   // SetProcessPriorityCall.  But in practice, the master process needs to set
   // its priority early in the game, so we can reasonably rely on
   // SetProcessPriority being called early in startup.
   EnsureKernelLowMemKillerParamsSet();
 
-  PriorityClass* pc = GetPriorityClass(aPriority);
+  static ProcessPriorityPrefs prefs = { 0 };
+  EnsureProcessPriorityPrefs(&prefs);
 
-  int oomScoreAdj = pc->OomScoreAdj();
+  int oomScoreAdj = prefs.priorities[aPriority].oomScoreAdj;
 
   RoundOomScoreAdjUpWithBackroundLRU(oomScoreAdj, aBackgroundLRU);
 
+  int clampedOomScoreAdj = clamped<int>(oomScoreAdj, OOM_SCORE_ADJ_MIN,
+                                                     OOM_SCORE_ADJ_MAX);
+  if (clampedOomScoreAdj != oomScoreAdj) {
+    HAL_LOG("Clamping OOM adjustment for pid %d to %d", aPid,
+            clampedOomScoreAdj);
+  } else {
+    HAL_LOG("Setting OOM adjustment for pid %d to %d", aPid,
+            clampedOomScoreAdj);
+  }
+
   // We try the newer interface first, and fall back to the older interface
   // on failure.
+
   if (!WriteToFile(nsPrintfCString("/proc/%d/oom_score_adj", aPid).get(),
-                   nsPrintfCString("%d", oomScoreAdj).get()))
+                   nsPrintfCString("%d", clampedOomScoreAdj).get()))
   {
+    int oomAdj = OomAdjOfOomScoreAdj(clampedOomScoreAdj);
+
     WriteToFile(nsPrintfCString("/proc/%d/oom_adj", aPid).get(),
-                nsPrintfCString("%d", OomAdjOfOomScoreAdj(oomScoreAdj)).get());
+                nsPrintfCString("%d", oomAdj).get());
   }
 
-  HAL_LOG("Assigning pid %d to cgroup %s", aPid, pc->CGroup().get());
-  pc->AddProcess(aPid);
+  int nice = 0;
+
+  if (aCPUPriority == PROCESS_CPU_PRIORITY_NORMAL) {
+    nice = prefs.priorities[aPriority].nice;
+  } else if (aCPUPriority == PROCESS_CPU_PRIORITY_LOW) {
+    nice = prefs.lowPriorityNice;
+  } else {
+    HAL_ERR("Unknown aCPUPriority value %d", aCPUPriority);
+    MOZ_ASSERT(false);
+    return;
+  }
+
+  HAL_LOG("Setting nice for pid %d to %d", aPid, nice);
+  SetNiceForPid(aPid, nice);
 }
 
 static bool
 IsValidRealTimePriority(int aValue, int aSchedulePolicy)
 {
   return (aValue >= sched_get_priority_min(aSchedulePolicy)) &&
          (aValue <= sched_get_priority_max(aSchedulePolicy));
 }
--- a/js/public/Conversions.h
+++ b/js/public/Conversions.h
@@ -10,20 +10,238 @@
 #define js_Conversions_h
 
 #include "mozilla/Casting.h"
 #include "mozilla/FloatingPoint.h"
 #include "mozilla/TypeTraits.h"
 
 #include <math.h>
 
+#include "jspubtd.h"
+
+#include "js/RootingAPI.h"
+#include "js/Value.h"
+
+struct JSContext;
+
+namespace js {
+
+/* DO NOT CALL THIS. Use JS::ToBoolean. */
+extern JS_PUBLIC_API(bool)
+ToBooleanSlow(JS::HandleValue v);
+
+/* DO NOT CALL THIS.  Use JS::ToNumber. */
+extern JS_PUBLIC_API(bool)
+ToNumberSlow(JSContext *cx, JS::Value v, double *dp);
+
+/* DO NOT CALL THIS. Use JS::ToInt32. */
+extern JS_PUBLIC_API(bool)
+ToInt32Slow(JSContext *cx, JS::HandleValue v, int32_t *out);
+
+/* DO NOT CALL THIS. Use JS::ToUint32. */
+extern JS_PUBLIC_API(bool)
+ToUint32Slow(JSContext *cx, JS::HandleValue v, uint32_t *out);
+
+/* DO NOT CALL THIS. Use JS::ToUint16. */
+extern JS_PUBLIC_API(bool)
+ToUint16Slow(JSContext *cx, JS::HandleValue v, uint16_t *out);
+
+/* DO NOT CALL THIS. Use JS::ToInt64. */
+extern JS_PUBLIC_API(bool)
+ToInt64Slow(JSContext *cx, JS::HandleValue v, int64_t *out);
+
+/* DO NOT CALL THIS. Use JS::ToUint64. */
+extern JS_PUBLIC_API(bool)
+ToUint64Slow(JSContext *cx, JS::HandleValue v, uint64_t *out);
+
+/* DO NOT CALL THIS. Use JS::ToString. */
+extern JS_PUBLIC_API(JSString*)
+ToStringSlow(JSContext *cx, JS::HandleValue v);
+
+/* DO NOT CALL THIS. Use JS::ToObject. */
+extern JS_PUBLIC_API(JSObject*)
+ToObjectSlow(JSContext *cx, JS::HandleValue v, bool reportScanStack);
+
+} // namespace js
+
 namespace JS {
 
 namespace detail {
 
+#ifdef JS_DEBUG
+/*
+ * Assert that we're not doing GC on cx, that we're in a request as
+ * needed, and that the compartments for cx and v are correct.
+ * Also check that GC would be safe at this point.
+ */
+extern JS_PUBLIC_API(void)
+AssertArgumentsAreSane(JSContext *cx, HandleValue v);
+#else
+inline void AssertArgumentsAreSane(JSContext *cx, HandleValue v)
+{}
+#endif /* JS_DEBUG */
+
+} // namespace detail
+
+/*
+ * ES6 draft 20141224, 7.1.1, second algorithm.
+ *
+ * Most users shouldn't call this -- use JS::ToBoolean, ToNumber, or ToString
+ * instead.  This will typically only be called from custom convert hooks that
+ * wish to fall back to the ES6 default conversion behavior shared by most
+ * objects in JS, codified as OrdinaryToPrimitive.
+ */
+extern JS_PUBLIC_API(bool)
+OrdinaryToPrimitive(JSContext *cx, HandleObject obj, JSType type, MutableHandleValue vp);
+
+/* ES6 draft 20141224, 7.1.2. */
+MOZ_ALWAYS_INLINE bool
+ToBoolean(HandleValue v)
+{
+    if (v.isBoolean())
+        return v.toBoolean();
+    if (v.isInt32())
+        return v.toInt32() != 0;
+    if (v.isNullOrUndefined())
+        return false;
+    if (v.isDouble()) {
+        double d = v.toDouble();
+        return !mozilla::IsNaN(d) && d != 0;
+    }
+    if (v.isSymbol())
+        return true;
+
+    /* The slow path handles strings and objects. */
+    return js::ToBooleanSlow(v);
+}
+
+/* ES6 draft 20141224, 7.1.3. */
+MOZ_ALWAYS_INLINE bool
+ToNumber(JSContext *cx, HandleValue v, double *out)
+{
+    detail::AssertArgumentsAreSane(cx, v);
+
+    if (v.isNumber()) {
+        *out = v.toNumber();
+        return true;
+    }
+    return js::ToNumberSlow(cx, v, out);
+}
+
+/* ES6 draft 20141224, ToInteger (specialized for doubles). */
+inline double
+ToInteger(double d)
+{
+    if (d == 0)
+        return d;
+
+    if (!mozilla::IsFinite(d)) {
+        if (mozilla::IsNaN(d))
+            return 0;
+        return d;
+    }
+
+    return d < 0 ? ceil(d) : floor(d);
+}
+
+/* ES6 draft 20141224, 7.1.5. */
+MOZ_ALWAYS_INLINE bool
+ToInt32(JSContext *cx, JS::HandleValue v, int32_t *out)
+{
+    detail::AssertArgumentsAreSane(cx, v);
+
+    if (v.isInt32()) {
+        *out = v.toInt32();
+        return true;
+    }
+    return js::ToInt32Slow(cx, v, out);
+}
+
+/* ES6 draft 20141224, 7.1.6. */
+MOZ_ALWAYS_INLINE bool
+ToUint32(JSContext *cx, HandleValue v, uint32_t *out)
+{
+    detail::AssertArgumentsAreSane(cx, v);
+
+    if (v.isInt32()) {
+        *out = uint32_t(v.toInt32());
+        return true;
+    }
+    return js::ToUint32Slow(cx, v, out);
+}
+
+/* ES6 draft 20141224, 7.1.8. */
+MOZ_ALWAYS_INLINE bool
+ToUint16(JSContext *cx, HandleValue v, uint16_t *out)
+{
+    detail::AssertArgumentsAreSane(cx, v);
+
+    if (v.isInt32()) {
+        *out = uint16_t(v.toInt32());
+        return true;
+    }
+    return js::ToUint16Slow(cx, v, out);
+}
+
+/*
+ * Non-standard, with behavior similar to that of ToInt32, except in its
+ * producing an int64_t.
+ */
+MOZ_ALWAYS_INLINE bool
+ToInt64(JSContext *cx, HandleValue v, int64_t *out)
+{
+    detail::AssertArgumentsAreSane(cx, v);
+
+    if (v.isInt32()) {
+        *out = int64_t(v.toInt32());
+        return true;
+    }
+    return js::ToInt64Slow(cx, v, out);
+}
+
+/*
+ * Non-standard, with behavior similar to that of ToUint32, except in its
+ * producing a uint64_t.
+ */
+MOZ_ALWAYS_INLINE bool
+ToUint64(JSContext *cx, HandleValue v, uint64_t *out)
+{
+    detail::AssertArgumentsAreSane(cx, v);
+
+    if (v.isInt32()) {
+        *out = uint64_t(v.toInt32());
+        return true;
+    }
+    return js::ToUint64Slow(cx, v, out);
+}
+
+/* ES6 draft 20141224, 7.1.12. */
+MOZ_ALWAYS_INLINE JSString*
+ToString(JSContext *cx, HandleValue v)
+{
+    detail::AssertArgumentsAreSane(cx, v);
+
+    if (v.isString())
+        return v.toString();
+    return js::ToStringSlow(cx, v);
+}
+
+/* ES6 draft 20141224, 7.1.13. */
+inline JSObject *
+ToObject(JSContext *cx, HandleValue v)
+{
+    detail::AssertArgumentsAreSane(cx, v);
+
+    if (v.isObject())
+        return &v.toObject();
+    return js::ToObjectSlow(cx, v, false);
+}
+
+namespace detail {
+
 /*
  * Convert a double value to ResultType (an unsigned integral type) using
  * ECMAScript-style semantics (that is, in like manner to how ECMAScript's
  * ToInt32 converts to int32_t).
  *
  *   If d is infinite or NaN, return 0.
  *   Otherwise compute d2 = sign(d) * floor(abs(d)), and return the ResultType
  *   value congruent to d2 mod 2**(bit width of ResultType).
@@ -273,27 +491,11 @@ ToInt64(double d)
 
 /* WEBIDL 4.2.11 */
 inline uint64_t
 ToUint64(double d)
 {
     return detail::ToUintWidth<uint64_t>(d);
 }
 
-/* ES5 9.4 ToInteger (specialized for doubles). */
-inline double
-ToInteger(double d)
-{
-    if (d == 0)
-        return d;
-
-    if (!mozilla::IsFinite(d)) {
-        if (mozilla::IsNaN(d))
-            return 0;
-        return d;
-    }
-
-    return d < 0 ? ceil(d) : floor(d);
-}
-
 } // namespace JS
 
 #endif /* js_Conversions_h */
--- a/js/src/builtin/Intl.cpp
+++ b/js/src/builtin/Intl.cpp
@@ -664,19 +664,25 @@ js::intl_Collator(JSContext *cx, unsigne
     // intl_Collator is an intrinsic for self-hosted JavaScript, so it cannot
     // be used with "new", but it still has to be treated as a constructor.
     return Collator(cx, args, true);
 }
 
 static void
 collator_finalize(FreeOp *fop, JSObject *obj)
 {
-    UCollator *coll = static_cast<UCollator*>(obj->as<NativeObject>().getReservedSlot(UCOLLATOR_SLOT).toPrivate());
-    if (coll)
-        ucol_close(coll);
+    // This is-undefined check shouldn't be necessary, but for internal
+    // brokenness in object allocation code.  For the moment, hack around it by
+    // explicitly guarding against the possibility of the reserved slot not
+    // containing a private.  See bug 949220.
+    const Value &slot = obj->as<NativeObject>().getReservedSlot(UCOLLATOR_SLOT);
+    if (!slot.isUndefined()) {
+        if (UCollator *coll = static_cast<UCollator*>(slot.toPrivate()))
+            ucol_close(coll);
+    }
 }
 
 static JSObject *
 InitCollatorClass(JSContext *cx, HandleObject Intl, Handle<GlobalObject*> global)
 {
     RootedFunction ctor(cx, global->createConstructor(cx, &Collator, cx->names().Collator, 0));
     if (!ctor)
         return nullptr;
@@ -1151,20 +1157,25 @@ js::intl_NumberFormat(JSContext *cx, uns
     // cannot be used with "new", but it still has to be treated as a
     // constructor.
     return NumberFormat(cx, args, true);
 }
 
 static void
 numberFormat_finalize(FreeOp *fop, JSObject *obj)
 {
-    UNumberFormat *nf =
-        static_cast<UNumberFormat*>(obj->as<NativeObject>().getReservedSlot(UNUMBER_FORMAT_SLOT).toPrivate());
-    if (nf)
-        unum_close(nf);
+    // This is-undefined check shouldn't be necessary, but for internal
+    // brokenness in object allocation code.  For the moment, hack around it by
+    // explicitly guarding against the possibility of the reserved slot not
+    // containing a private.  See bug 949220.
+    const Value &slot = obj->as<NativeObject>().getReservedSlot(UNUMBER_FORMAT_SLOT);
+    if (!slot.isUndefined()) {
+        if (UNumberFormat *nf = static_cast<UNumberFormat*>(slot.toPrivate()))
+            unum_close(nf);
+    }
 }
 
 static JSObject *
 InitNumberFormatClass(JSContext *cx, HandleObject Intl, Handle<GlobalObject*> global)
 {
     RootedFunction ctor(cx, global->createConstructor(cx, &NumberFormat, cx->names().NumberFormat, 0));
     if (!ctor)
         return nullptr;
@@ -1605,19 +1616,25 @@ js::intl_DateTimeFormat(JSContext *cx, u
     // cannot be used with "new", but it still has to be treated as a
     // constructor.
     return DateTimeFormat(cx, args, true);
 }
 
 static void
 dateTimeFormat_finalize(FreeOp *fop, JSObject *obj)
 {
-    UDateFormat *df = static_cast<UDateFormat*>(obj->as<NativeObject>().getReservedSlot(UDATE_FORMAT_SLOT).toPrivate());
-    if (df)
-        udat_close(df);
+    // This is-undefined check shouldn't be necessary, but for internal
+    // brokenness in object allocation code.  For the moment, hack around it by
+    // explicitly guarding against the possibility of the reserved slot not
+    // containing a private.  See bug 949220.
+    const Value &slot = obj->as<NativeObject>().getReservedSlot(UDATE_FORMAT_SLOT);
+    if (!slot.isUndefined()) {
+        if (UDateFormat *df = static_cast<UDateFormat*>(slot.toPrivate()))
+            udat_close(df);
+    }
 }
 
 static JSObject *
 InitDateTimeFormatClass(JSContext *cx, HandleObject Intl, Handle<GlobalObject*> global)
 {
     RootedFunction ctor(cx, global->createConstructor(cx, &DateTimeFormat, cx->names().DateTimeFormat, 0));
     if (!ctor)
         return nullptr;
--- a/js/src/frontend/FullParseHandler.h
+++ b/js/src/frontend/FullParseHandler.h
@@ -2,16 +2,17 @@
  * vim: set ts=8 sts=4 et sw=4 tw=99:
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef frontend_FullParseHandler_h
 #define frontend_FullParseHandler_h
 
+#include "mozilla/Attributes.h"
 #include "mozilla/PodOperations.h"
 
 #include "frontend/ParseNode.h"
 #include "frontend/SharedContext.h"
 
 namespace js {
 namespace frontend {
 
@@ -537,18 +538,40 @@ class FullParseHandler
 
     ParseNode *newLexicalScope(ObjectBox *blockBox) {
         return new_<LexicalScopeNode>(blockBox, pos());
     }
     void setLexicalScopeBody(ParseNode *block, ParseNode *body) {
         block->pn_expr = body;
     }
 
-    bool isOperationWithoutParens(ParseNode *pn, ParseNodeKind kind) {
-        return pn->isKind(kind) && !pn->isInParens();
+    ParseNode *newAssignment(ParseNodeKind kind, ParseNode *lhs, ParseNode *rhs,
+                             ParseContext<FullParseHandler> *pc, JSOp op)
+    {
+        return newBinaryOrAppend(kind, lhs, rhs, pc, op);
+    }
+
+    bool isUnparenthesizedYieldExpression(ParseNode *node) {
+        return node->isKind(PNK_YIELD) && !node->isInParens();
+    }
+
+    bool isUnparenthesizedCommaExpression(ParseNode *node) {
+        return node->isKind(PNK_COMMA) && !node->isInParens();
+    }
+
+    bool isUnparenthesizedAssignment(Node node) {
+        if (node->isKind(PNK_ASSIGN) && !node->isInParens()) {
+            // PNK_ASSIGN is also (mis)used for things like |var name = expr;|.
+            // But this method is only called on actual expressions, so we can
+            // just assert the node's op is the one used for plain assignment.
+            MOZ_ASSERT(node->isOp(JSOP_NOP));
+            return true;
+        }
+
+        return false;
     }
 
     inline bool finishInitializerAssignment(ParseNode *pn, ParseNode *init, JSOp op);
 
     void setBeginPosition(ParseNode *pn, ParseNode *oth) {
         setBeginPosition(pn, oth->pn_pos.begin);
     }
     void setBeginPosition(ParseNode *pn, uint32_t begin) {
@@ -575,43 +598,44 @@ class FullParseHandler
         return new_<ListNode>(kind, op, pos());
     }
 
     /* New list with one initial child node. kid must be non-null. */
     ParseNode *newList(ParseNodeKind kind, ParseNode *kid, JSOp op = JSOP_NOP) {
         return new_<ListNode>(kind, op, kid);
     }
 
-    void addList(ParseNode *pn, ParseNode *kid) {
-        pn->append(kid);
+
+    ParseNode *newCommaExpressionList(ParseNode *kid) {
+        return newList(PNK_COMMA, kid, JSOP_NOP);
     }
 
-    bool isUnparenthesizedYield(ParseNode *pn) {
-        return pn->isKind(PNK_YIELD) && !pn->isInParens();
+    void addList(ParseNode *list, ParseNode *kid) {
+        list->append(kid);
     }
 
     void setOp(ParseNode *pn, JSOp op) {
         pn->setOp(op);
     }
     void setBlockId(ParseNode *pn, unsigned blockid) {
         pn->pn_blockid = blockid;
     }
     void setFlag(ParseNode *pn, unsigned flag) {
         pn->pn_dflags |= flag;
     }
     void setListFlag(ParseNode *pn, unsigned flag) {
         MOZ_ASSERT(pn->isArity(PN_LIST));
         pn->pn_xflags |= flag;
     }
-    ParseNode *setInParens(ParseNode *pn) {
+    MOZ_WARN_UNUSED_RESULT ParseNode *parenthesize(ParseNode *pn) {
         pn->setInParens(true);
         return pn;
     }
-    ParseNode *setLikelyIIFE(ParseNode *pn) {
-        return setInParens(pn);
+    MOZ_WARN_UNUSED_RESULT ParseNode *setLikelyIIFE(ParseNode *pn) {
+        return parenthesize(pn);
     }
     void setPrologue(ParseNode *pn) {
         pn->pn_prologue = true;
     }
 
     bool isConstant(ParseNode *pn) {
         return pn->isConstant();
     }
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -2879,20 +2879,19 @@ Parser<ParseHandler>::condition()
 {
     MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_BEFORE_COND);
     Node pn = exprInParens();
     if (!pn)
         return null();
     MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_COND);
 
     /* Check for (a = b) and warn about possible (a == b) mistype. */
-    if (handler.isOperationWithoutParens(pn, PNK_ASSIGN) &&
-        !report(ParseExtraWarning, false, null(), JSMSG_EQUAL_AS_ASSIGN))
-    {
-        return null();
+    if (handler.isUnparenthesizedAssignment(pn)) {
+        if (!report(ParseExtraWarning, false, null(), JSMSG_EQUAL_AS_ASSIGN))
+            return null();
     }
     return pn;
 }
 
 template <typename ParseHandler>
 bool
 Parser<ParseHandler>::matchLabel(MutableHandle<PropertyName*> label)
 {
@@ -5912,21 +5911,21 @@ Parser<ParseHandler>::expr(InvokedPredic
     Node pn = assignExpr(invoked);
     if (!pn)
         return null();
 
     bool matched;
     if (!tokenStream.matchToken(&matched, TOK_COMMA))
         return null();
     if (matched) {
-        Node seq = handler.newList(PNK_COMMA, pn);
+        Node seq = handler.newCommaExpressionList(pn);
         if (!seq)
             return null();
         while (true) {
-            if (handler.isUnparenthesizedYield(pn)) {
+            if (handler.isUnparenthesizedYieldExpression(pn)) {
                 report(ParseError, false, pn, JSMSG_BAD_GENERATOR_SYNTAX, js_yield_str);
                 return null();
             }
 
             pn = assignExpr();
             if (!pn)
                 return null();
             handler.addList(seq, pn);
@@ -6291,17 +6290,17 @@ Parser<ParseHandler>::assignExpr(Invoked
     AssignmentFlavor flavor = kind == PNK_ASSIGN ? PlainAssignment : CompoundAssignment;
     if (!checkAndMarkAsAssignmentLhs(lhs, flavor))
         return null();
 
     Node rhs = assignExpr();
     if (!rhs)
         return null();
 
-    return handler.newBinaryOrAppend(kind, lhs, rhs, pc, op);
+    return handler.newAssignment(kind, lhs, rhs, pc, op);
 }
 
 static const char incop_name_str[][10] = {"increment", "decrement"};
 
 template <>
 bool
 Parser<FullParseHandler>::checkAndMarkAsIncOperand(ParseNode *kid, TokenKind tt, bool preorder)
 {
@@ -7275,20 +7274,19 @@ Parser<ParseHandler>::comprehensionIf(Ge
 
     MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_BEFORE_COND);
     Node cond = assignExpr();
     if (!cond)
         return null();
     MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_COND);
 
     /* Check for (a = b) and warn about possible (a == b) mistype. */
-    if (handler.isOperationWithoutParens(cond, PNK_ASSIGN) &&
-        !report(ParseExtraWarning, false, null(), JSMSG_EQUAL_AS_ASSIGN))
-    {
-        return null();
+    if (handler.isUnparenthesizedAssignment(cond)) {
+        if (!report(ParseExtraWarning, false, null(), JSMSG_EQUAL_AS_ASSIGN))
+            return null();
     }
 
     Node then = comprehensionTail(comprehensionKind);
     if (!then)
         return null();
 
     return handler.newIfStatement(begin, cond, then, null());
 }
@@ -7318,17 +7316,17 @@ Parser<ParseHandler>::comprehensionTail(
 
     if (comprehensionKind == NotGenerator)
         return handler.newUnary(PNK_ARRAYPUSH, JSOP_ARRAYPUSH, begin, bodyExpr);
 
     MOZ_ASSERT(comprehensionKind == StarGenerator);
     Node yieldExpr = newYieldExpression(begin, bodyExpr);
     if (!yieldExpr)
         return null();
-    handler.setInParens(yieldExpr);
+    yieldExpr = handler.parenthesize(yieldExpr);
 
     return handler.newExprStatement(yieldExpr, pos().end);
 }
 
 // Parse an ES6 generator or array comprehension, starting at the first 'for'.
 // The caller is responsible for matching the ending TOK_RP or TOK_RB.
 template <typename ParseHandler>
 typename ParseHandler::Node
@@ -7441,17 +7439,17 @@ Parser<ParseHandler>::argumentList(Node 
         if (!argNode)
             return false;
         if (spread) {
             argNode = handler.newUnary(PNK_SPREAD, JSOP_NOP, begin, argNode);
             if (!argNode)
                 return false;
         }
 
-        if (handler.isOperationWithoutParens(argNode, PNK_YIELD)) {
+        if (handler.isUnparenthesizedYieldExpression(argNode)) {
             TokenKind tt;
             if (!tokenStream.peekToken(&tt))
                 return false;
             if (tt == TOK_COMMA) {
                 report(ParseError, false, argNode, JSMSG_BAD_GENERATOR_SYNTAX, js_yield_str);
                 return false;
             }
         }
@@ -8274,17 +8272,17 @@ Parser<ParseHandler>::parenExprOrGenerat
     if (!tokenStream.matchToken(&matched, TOK_FOR))
         return null();
     if (matched) {
         if (pc->lastYieldOffset != startYieldOffset) {
             reportWithOffset(ParseError, false, pc->lastYieldOffset,
                              JSMSG_BAD_GENEXP_BODY, js_yield_str);
             return null();
         }
-        if (handler.isOperationWithoutParens(pn, PNK_COMMA)) {
+        if (handler.isUnparenthesizedCommaExpression(pn)) {
             report(ParseError, false, null(),
                    JSMSG_BAD_GENERATOR_SYNTAX, js_generator_str);
             return null();
         }
         pn = legacyGeneratorExpr(pn);
         if (!pn)
             return null();
         handler.setBeginPosition(pn, begin);
@@ -8292,22 +8290,21 @@ Parser<ParseHandler>::parenExprOrGenerat
         if (!tokenStream.getToken(&tt))
             return null();
         if (tt != TOK_RP) {
             report(ParseError, false, null(),
                    JSMSG_BAD_GENERATOR_SYNTAX, js_generator_str);
             return null();
         }
         handler.setEndPosition(pn, pos().end);
-        handler.setInParens(pn);
-        return pn;
+        return handler.parenthesize(pn);
     }
 #endif /* JS_HAS_GENERATOR_EXPRS */
 
-    pn = handler.setInParens(pn);
+    pn = handler.parenthesize(pn);
 
     MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_IN_PAREN);
 
     return pn;
 }
 
 // Legacy generator comprehensions can sometimes appear without parentheses.
 // For example:
@@ -8353,17 +8350,17 @@ Parser<ParseHandler>::exprInParens()
     if (!tokenStream.matchToken(&matched, TOK_FOR))
         return null();
     if (matched) {
         if (pc->lastYieldOffset != startYieldOffset) {
             reportWithOffset(ParseError, false, pc->lastYieldOffset,
                              JSMSG_BAD_GENEXP_BODY, js_yield_str);
             return null();
         }
-        if (handler.isOperationWithoutParens(pn, PNK_COMMA)) {
+        if (handler.isUnparenthesizedCommaExpression(pn)) {
             report(ParseError, false, null(),
                    JSMSG_BAD_GENERATOR_SYNTAX, js_generator_str);
             return null();
         }
         pn = legacyGeneratorExpr(pn);
         if (!pn)
             return null();
         handler.setBeginPosition(pn, begin);
--- a/js/src/frontend/SyntaxParseHandler.h
+++ b/js/src/frontend/SyntaxParseHandler.h
@@ -2,16 +2,18 @@
  * vim: set ts=8 sts=4 et sw=4 tw=99:
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef frontend_SyntaxParseHandler_h
 #define frontend_SyntaxParseHandler_h
 
+#include "mozilla/Attributes.h"
+
 #include "frontend/ParseNode.h"
 #include "frontend/TokenStream.h"
 
 namespace js {
 namespace frontend {
 
 template <typename ParseHandler>
 class Parser;
@@ -34,22 +36,71 @@ class SyntaxParseHandler
     TokenStream &tokenStream;
 
   public:
     enum Node {
         NodeFailure = 0,
         NodeGeneric,
         NodeName,
         NodeGetProp,
-        NodeString,
         NodeStringExprStatement,
-        NodeLValue
+        NodeLValue,
+
+        // In rare cases a parenthesized |node| doesn't have the same semantics
+        // as |node|.  Each such node has a special Node value, and we use a
+        // different Node value to represent the parenthesized form.  See also
+        // isUnparenthesized*(Node), newExprStatement(Node, uint32_t),
+        // parenthesize(Node), and meaningMightChangeIfParenthesized(Node).
+
+        // The directive prologue at the start of a FunctionBody or ScriptBody
+        // is the longest sequence (possibly empty) of string literal
+        // expression statements at the start of a function.  Thus we need this
+        // to treat |"use strict";| as a possible Use Strict Directive and
+        // |("use strict");| as a useless statement.
+        NodeUnparenthesizedString,
+
+        // Legacy generator expressions of the form |(expr for (...))| and
+        // array comprehensions of the form |[expr for (...)]|) don't permit
+        // |expr| to be a comma expression.  Thus we need this to treat
+        // |(a(), b for (x in []))| as a syntax error and
+        // |((a(), b) for (x in []))| as a generator that calls |a| and then
+        // yields |b| each time it's resumed.
+        NodeUnparenthesizedCommaExpr,
+
+        // Yield expressions currently (but not in ES6 -- a SpiderMonkey bug to
+        // fix) must generally be parenthesized.  (See the uses of
+        // isUnparenthesizedYieldExpression in Parser.cpp for the rare
+        // exceptions.)  Thus we need this to treat |yield 1, 2;| as a syntax
+        // error and |(yield 1), 2;| as a comma expression that will yield 1,
+        // then evaluate to 2.
+        NodeUnparenthesizedYieldExpr,
+
+        // Assignment expressions in condition contexts could be typos for
+        // equality checks.  (Think |if (x = y)| versus |if (x == y)|.)  Thus
+        // we need this to treat |if (x = y)| as a possible typo and
+        // |if ((x = y))| as a deliberate assignment within a condition.
+        //
+        // (Technically this isn't needed, as these are *only* extraWarnings
+        // warnings, and parsing with that option disables syntax parsing.  But
+        // it seems best to be consistent, and perhaps the syntax parser will
+        // eventually enforce extraWarnings and will require this then.)
+        NodeUnparenthesizedAssignment
     };
     typedef Definition::Kind DefinitionNode;
 
+  private:
+    static bool meaningMightChangeIfParenthesized(Node node) {
+        return node == NodeUnparenthesizedString ||
+               node == NodeUnparenthesizedCommaExpr ||
+               node == NodeUnparenthesizedYieldExpr ||
+               node == NodeUnparenthesizedAssignment;
+    }
+
+
+  public:
     SyntaxParseHandler(ExclusiveContext *cx, LifoAlloc &alloc,
                        TokenStream &tokenStream, bool foldConstants,
                        Parser<SyntaxParseHandler> *syntaxParser, LazyScript *lazyOuterFunction)
       : lastAtom(nullptr),
         tokenStream(tokenStream)
     {}
 
     static Node null() { return NodeFailure; }
@@ -64,24 +115,24 @@ class SyntaxParseHandler
     Node newComputedName(Node expr, uint32_t start, uint32_t end) {
         return NodeName;
     }
 
     DefinitionNode newPlaceholder(JSAtom *atom, uint32_t blockid, const TokenPos &pos) {
         return Definition::PLACEHOLDER;
     }
 
-    Node newIdentifier(JSAtom *atom, const TokenPos &pos) { return NodeString; }
+    Node newIdentifier(JSAtom *atom, const TokenPos &pos) { return NodeName; }
     Node newNumber(double value, DecimalPoint decimalPoint, const TokenPos &pos) { return NodeGeneric; }
     Node newBooleanLiteral(bool cond, const TokenPos &pos) { return NodeGeneric; }
 
     Node newStringLiteral(JSAtom *atom, const TokenPos &pos) {
         lastAtom = atom;
         lastStringPos = pos;
-        return NodeString;
+        return NodeUnparenthesizedString;
     }
 
     Node newTemplateStringLiteral(JSAtom *atom, const TokenPos &pos) {
         return NodeGeneric;
     }
 
     Node newCallSiteObject(uint32_t begin, unsigned blockidGen) {
         return NodeGeneric;
@@ -130,28 +181,28 @@ class SyntaxParseHandler
     bool addElision(Node literal, const TokenPos &pos) { return true; }
     bool addSpreadElement(Node literal, uint32_t begin, Node inner) { return true; }
     bool addArrayElement(Node literal, Node element) { return true; }
 
     Node newObjectLiteral(uint32_t begin) { return NodeGeneric; }
     bool addPrototypeMutation(Node literal, uint32_t begin, Node expr) { return true; }
     bool addPropertyDefinition(Node literal, Node name, Node expr, bool isShorthand = false) { return true; }
     bool addMethodDefinition(Node literal, Node name, Node fn, JSOp op) { return true; }
-    Node newYieldExpression(uint32_t begin, Node value, Node gen) { return NodeGeneric; }
+    Node newYieldExpression(uint32_t begin, Node value, Node gen) { return NodeUnparenthesizedYieldExpr; }
     Node newYieldStarExpression(uint32_t begin, Node value, Node gen) { return NodeGeneric; }
 
     // Statements
 
     Node newStatementList(unsigned blockid, const TokenPos &pos) { return NodeGeneric; }
     void addStatementToList(Node list, Node stmt, ParseContext<SyntaxParseHandler> *pc) {}
     bool prependInitialYield(Node stmtList, Node gen) { return true; }
     Node newEmptyStatement(const TokenPos &pos) { return NodeGeneric; }
 
     Node newExprStatement(Node expr, uint32_t end) {
-        return expr == NodeString ? NodeStringExprStatement : NodeGeneric;
+        return expr == NodeUnparenthesizedString ? NodeStringExprStatement : NodeGeneric;
     }
 
     Node newIfStatement(uint32_t begin, Node cond, Node then, Node else_) { return NodeGeneric; }
     Node newDoWhileStatement(Node body, Node cond, const TokenPos &pos) { return NodeGeneric; }
     Node newWhileStatement(uint32_t begin, Node cond, Node body) { return NodeGeneric; }
     Node newSwitchStatement(uint32_t begin, Node discriminant, Node caseList) { return NodeGeneric; }
     Node newCaseOrDefault(uint32_t begin, Node expr, Node body) { return NodeGeneric; }
     Node newContinueStatement(PropertyName *label, const TokenPos &pos) { return NodeGeneric; }
@@ -190,23 +241,16 @@ class SyntaxParseHandler
 
     Node newForHead(ParseNodeKind kind, Node decls, Node lhs, Node rhs, const TokenPos &pos) {
         return NodeGeneric;
     }
 
     Node newLexicalScope(ObjectBox *blockbox) { return NodeGeneric; }
     void setLexicalScopeBody(Node block, Node body) {}
 
-    bool isOperationWithoutParens(Node pn, ParseNodeKind kind) {
-        // It is OK to return false here, callers should only use this method
-        // for reporting strict option warnings and parsing code which the
-        // syntax parser does not handle.
-        return false;
-    }
-
     bool finishInitializerAssignment(Node pn, Node init, JSOp op) { return true; }
 
     void setBeginPosition(Node pn, Node oth) {}
     void setBeginPosition(Node pn, uint32_t begin) {}
 
     void setEndPosition(Node pn, Node oth) {}
     void setEndPosition(Node pn, uint32_t end) {}
 
@@ -217,29 +261,58 @@ class SyntaxParseHandler
     }
 
     Node newList(ParseNodeKind kind, JSOp op = JSOP_NOP) {
         return NodeGeneric;
     }
     Node newList(ParseNodeKind kind, Node kid, JSOp op = JSOP_NOP) {
         return NodeGeneric;
     }
-    void addList(Node pn, Node kid) {}
-    bool isUnparenthesizedYield(Node pn) { return false; }
+
+    Node newCommaExpressionList(Node kid) {
+        return NodeUnparenthesizedCommaExpr;
+    }
+
+    void addList(Node list, Node kid) {
+        MOZ_ASSERT(list == NodeGeneric || list == NodeUnparenthesizedCommaExpr);
+    }
+
+    Node newAssignment(ParseNodeKind kind, Node lhs, Node rhs,
+                       ParseContext<SyntaxParseHandler> *pc, JSOp op)
+    {
+        if (kind == PNK_ASSIGN)
+            return NodeUnparenthesizedAssignment;
+        return newBinaryOrAppend(kind, lhs, rhs, pc, op);
+    }
+
+    bool isUnparenthesizedYieldExpression(Node node) {
+        return node == NodeUnparenthesizedYieldExpr;
+    }
+
+    bool isUnparenthesizedCommaExpression(Node node) {
+        return node == NodeUnparenthesizedCommaExpr;
+    }
+
+    bool isUnparenthesizedAssignment(Node node) {
+        return node == NodeUnparenthesizedAssignment;
+    }
 
     void setOp(Node pn, JSOp op) {}
     void setBlockId(Node pn, unsigned blockid) {}
     void setFlag(Node pn, unsigned flag) {}
     void setListFlag(Node pn, unsigned flag) {}
-    Node setInParens(Node pn) {
-        // String literals enclosed by parentheses are ignored during
-        // strict mode parsing.
-        return (pn == NodeString) ? NodeGeneric : pn;
+    MOZ_WARN_UNUSED_RESULT Node parenthesize(Node node) {
+        if (meaningMightChangeIfParenthesized(node))
+            return NodeGeneric;
+
+        // In all other cases, the parenthesized form of |node| is equivalent
+        // to the unparenthesized form: return |node| unchanged.
+        return node;
     }
-    Node setLikelyIIFE(Node pn) {
+    MOZ_WARN_UNUSED_RESULT Node setLikelyIIFE(Node pn) {
         return pn; // Remain in syntax-parse mode.
     }
     void setPrologue(Node pn) {}
 
     bool isConstant(Node pn) { return false; }
     PropertyName *isName(Node pn) {
         return (pn == NodeName) ? lastAtom->asPropertyName() : nullptr;
     }
--- a/js/src/gc/Verifier.cpp
+++ b/js/src/gc/Verifier.cpp
@@ -214,17 +214,16 @@ gc::GCRuntime::startVerifyPreBarriers()
     trc->term = trc->edgeptr + size;
 
     if (!trc->nodemap.init())
         goto oom;
 
     /* Create the root node. */
     trc->curnode = MakeNode(trc, nullptr, JSGCTraceKind(0));
 
-    /* We want MarkRuntime to save the roots to gcSavedRoots. */
     incrementalState = MARK_ROOTS;
 
     /* Make all the roots be edges emanating from the root node. */
     markRuntime(trc);
 
     VerifyNode *node;
     node = trc->curnode;
     if (trc->edgeptr == trc->term)
--- a/js/src/jit-test/tests/basic/hypot-approx.js
+++ b/js/src/jit-test/tests/basic/hypot-approx.js
@@ -16,10 +16,19 @@ assertNear(Math.hypot(1e-3, 1e-3, 1e-3),
 
 assertNear(Math.hypot(1e300, 1e300), 1.4142135623730952e+300);
 assertNear(Math.hypot(1e100, 1e200, 1e300), 1e300);
 
 assertNear(Math.hypot(1e3, 1e-3), 1000.0000000005);
 assertNear(Math.hypot(1e-300, 1e300), 1e300);
 assertNear(Math.hypot(1e3, 1e-3, 1e3, 1e-3), 1414.2135623738021555);
 
-for (var i = 1, j = 1; i < 2; i += 0.05, j += 0.05)
+assertNear(Math.hypot(1e1, 1e2, 1e3), Math.sqrt(1e2 + 1e4 + 1e6));
+assertNear(Math.hypot(1e1, 1e2, 1e3, 1e4), Math.sqrt(1e2 + 1e4 + 1e6 + 1e8));
+
+for (var i = 1, j = 2; i < 2; i += 0.05, j += 0.05)
     assertNear(Math.hypot(i, j), Math.sqrt(i * i + j * j));
+
+for (var i = 1, j = 2, k = 3; i < 2; i += 0.05, j += 0.05, k += 0.05)
+    assertNear(Math.hypot(i, j, k), Math.sqrt(i * i + j * j + k * k));
+
+for (var i = 1, j = 2, k = 3, l = 4; i < 2; i += 0.05, j += 0.05, k += 0.05, l += 0.5)
+    assertNear(Math.hypot(i, j, k, l), Math.sqrt(i * i + j * j + k * k + l * l));
--- a/js/src/jit-test/tests/basic/hypot-exact.js
+++ b/js/src/jit-test/tests/basic/hypot-exact.js
@@ -23,35 +23,52 @@ for (var inf of [Infinity, -Infinity]) {
     assertEq(Math.hypot(0, 0, inf), Infinity);
 
     assertEq(Math.hypot(inf, NaN), Infinity);
     assertEq(Math.hypot(NaN, inf), Infinity);
 
     assertEq(Math.hypot(inf, NaN, NaN), Infinity);
     assertEq(Math.hypot(NaN, inf, NaN), Infinity);
     assertEq(Math.hypot(NaN, NaN, inf), Infinity);
+
+    assertEq(Math.hypot(inf, NaN, NaN, NaN), Infinity);
+    assertEq(Math.hypot(NaN, inf, NaN, NaN), Infinity);
+    assertEq(Math.hypot(NaN, NaN, inf, NaN), Infinity);
+    assertEq(Math.hypot(NaN, NaN, NaN, inf), Infinity);
 }
 
 // If no argument is +∞ or −∞, and any argument is NaN, the result is NaN.
 assertEq(Math.hypot(NaN), NaN);
 
 assertEq(Math.hypot(NaN, 0), NaN);
 assertEq(Math.hypot(0, NaN), NaN);
 
 assertEq(Math.hypot(NaN, NaN), NaN);
 
 assertEq(Math.hypot(NaN, 0, 0), NaN);
 assertEq(Math.hypot(0, NaN, 0), NaN);
 assertEq(Math.hypot(0, 0, NaN), NaN);
 
+assertEq(Math.hypot(NaN, 0, 0, 0), NaN);
+assertEq(Math.hypot(0, NaN, 0, 0), NaN);
+assertEq(Math.hypot(0, 0, NaN, 0), NaN);
+assertEq(Math.hypot(0, 0, 0, NaN), NaN);
+
 assertEq(Math.hypot(Number.MAX_VALUE, Number.MIN_VALUE, NaN), NaN);
+assertEq(Math.hypot(Number.MAX_VALUE, Number.MIN_VALUE, Number.MIN_VALUE, NaN), NaN);
 
 // If all arguments are either +0 or -0, the result is +0.
 assertEq(Math.hypot(-0, -0), +0);
 assertEq(Math.hypot(+0, -0), +0);
 
 assertEq(Math.hypot(-0, -0, -0), +0);
 assertEq(Math.hypot(+0, -0, -0), +0);
 assertEq(Math.hypot(-0, +0, -0), +0);
 assertEq(Math.hypot(+0, +0, -0), +0);
 
+assertEq(Math.hypot(-0, -0, -0, -0), +0);
+assertEq(Math.hypot(+0, -0, -0, -0), +0);
+assertEq(Math.hypot(-0, -0, +0, -0), +0);
+assertEq(Math.hypot(+0, +0, +0, -0), +0);
+assertEq(Math.hypot(-0, -0, -0, +0), +0);
+
 // The length property of the hypot function is 2.
 assertEq(Math.hypot.length, 2);
--- a/js/src/jit-test/tests/ion/dce-with-rinstructions.js
+++ b/js/src/jit-test/tests/ion/dce-with-rinstructions.js
@@ -1057,38 +1057,91 @@ function rtrunc_to_int32_object(i) {
 var uceFault_trunc_to_int32_string = eval(uneval(uceFault).replace('uceFault', 'uceFault_trunc_to_int32_string'));
 function rtrunc_to_int32_string(i) {
     var x = (i + "0") | 0;
     if (uceFault_trunc_to_int32_string(i) || uceFault_trunc_to_int32_string(i))
         assertEq(x, (i + "0") | 0);
     return i;
 }
 
-var uceFault_hypot_number = eval(uneval(uceFault).replace('uceFault', 'uceFault_hypot_number'));
-function rhypot_number(i) {
+var uceFault_hypot_number_2args = eval(uneval(uceFault).replace('uceFault', 'uceFault_hypot_number_2args'));
+function rhypot_number_2args(i) {
     var x = Math.hypot(i, i + 1);
-    if (uceFault_hypot_number(i) || uceFault_hypot_number(i))
+    if (uceFault_hypot_number_2args(i) || uceFault_hypot_number_2args(i))
         assertEq(x, Math.sqrt(i * i + (i + 1) * (i + 1)));
     return i;
 }
 
-var uceFault_hypot_object = eval(uneval(uceFault).replace('uceFault', 'uceFault_hypot_object'));
-function rhypot_object(i) {
+var uceFault_hypot_number_3args = eval(uneval(uceFault).replace('uceFault', 'uceFault_hypot_number_3args'));
+function rhypot_number_3args(i) {
+    var x = Math.hypot(i, i + 1, i + 2);
+    if (uceFault_hypot_number_3args(i) || uceFault_hypot_number_3args(i))
+        assertEq(x, Math.sqrt(i * i + (i + 1) * (i + 1) + (i + 2) * (i + 2)));
+    return i;
+}
+
+var uceFault_hypot_number_4args = eval(uneval(uceFault).replace('uceFault', 'uceFault_hypot_number_4args'));
+function rhypot_number_4args(i) {
+    var x = Math.hypot(i, i + 1, i + 2, i + 3);
+    if (uceFault_hypot_number_4args(i) || uceFault_hypot_number_4args(i))
+        assertEq(x, Math.sqrt(i * i + (i + 1) * (i + 1) + (i + 2) * (i + 2) + (i + 3) * (i + 3)));
+    return i;
+}
+
+var uceFault_hypot_object_2args = eval(uneval(uceFault).replace('uceFault', 'uceFault_hypot_object_2args'));
+function rhypot_object_2args(i) {
     var t0 = i;
     var t1 = i + 1;
     var o0 = { valueOf: function () { return t0; } };
     var o1 = { valueOf: function () { return t1; } };
     var x = Math.hypot(o0, o1);
     t0 = 1000;
     t1 = 2000;
-    if (uceFault_hypot_object(i) || uceFault_hypot_object(i) )
+    if (uceFault_hypot_object_2args(i) || uceFault_hypot_object_2args(i) )
         assertEq(x, Math.sqrt(i * i + (i + 1) * (i + 1)));
     return i;
 }
 
+var uceFault_hypot_object_3args = eval(uneval(uceFault).replace('uceFault', 'uceFault_hypot_object_3args'));
+function rhypot_object_3args(i) {
+    var t0 = i;
+    var t1 = i + 1;
+    var t2 = i + 2;
+    var o0 = { valueOf: function () { return t0; } };
+    var o1 = { valueOf: function () { return t1; } };
+    var o2 = { valueOf: function () { return t2; } };
+    var x = Math.hypot(o0, o1, o2);
+    t0 = 1000;
+    t1 = 2000;
+    t2 = 3000;
+    if (uceFault_hypot_object_3args(i) || uceFault_hypot_object_3args(i) )
+        assertEq(x, Math.sqrt(i * i + (i + 1) * (i + 1) + (i + 2) * (i + 2)));
+    return i;
+}
+
+var uceFault_hypot_object_4args = eval(uneval(uceFault).replace('uceFault', 'uceFault_hypot_object_4args'));
+function rhypot_object_4args(i) {
+    var t0 = i;
+    var t1 = i + 1;
+    var t2 = i + 2;
+    var t3 = i + 3;
+    var o0 = { valueOf: function () { return t0; } };
+    var o1 = { valueOf: function () { return t1; } };
+    var o2 = { valueOf: function () { return t2; } };
+    var o3 = { valueOf: function () { return t3; } };
+    var x = Math.hypot(o0, o1, o2, o3);
+    t0 = 1000;
+    t1 = 2000;
+    t2 = 3000;
+    t3 = 4000;
+    if (uceFault_hypot_object_4args(i) || uceFault_hypot_object_4args(i) )
+        assertEq(x, Math.sqrt(i * i + (i + 1) * (i + 1) + (i + 2) * (i + 2) + (i + 3) * (i + 3)));
+    return i;
+}
+
 var uceFault_sin_number = eval(uneval(uceFault).replace('uceFault', 'uceFault_sin_number'));
 function rsin_number(i) {
     var x = Math.sin(i);
     if (uceFault_sin_number(i) || uceFault_sin_number(i))
         assertEq(x, Math.sin(i));
     return i;
 }
 
@@ -1219,18 +1272,22 @@ for (i = 0; i < 100; i++) {
     rtypeof(i);
     rtodouble_value(i);
     rtodouble_number(i);
     rtofloat32_number(i);
     rtofloat32_object(i);
     rtrunc_to_int32_number(i);
     rtrunc_to_int32_object(i);
     rtrunc_to_int32_string(i);
-    rhypot_number(i);
-    rhypot_object(i);
+    rhypot_number_2args(i);
+    rhypot_number_3args(i);
+    rhypot_number_4args(i);
+    rhypot_object_2args(i);
+    rhypot_object_3args(i);
+    rhypot_object_4args(i);
     rsin_number(i);
     rsin_object(i);
     rlog_number(i);
     rlog_object(i);
 }
 
 // Test that we can refer multiple time to the same recover instruction, as well
 // as chaining recover instructions.
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -3903,24 +3903,35 @@ CodeGenerator::visitAtan2D(LAtan2D *lir)
 
     MOZ_ASSERT(ToFloatRegister(lir->output()) == ReturnDoubleReg);
 }
 
 void
 CodeGenerator::visitHypot(LHypot *lir)
 {
     Register temp = ToRegister(lir->temp());
-    FloatRegister x = ToFloatRegister(lir->x());
-    FloatRegister y = ToFloatRegister(lir->y());
-
-    masm.setupUnalignedABICall(2, temp);
-    masm.passABIArg(x, MoveOp::DOUBLE);
-    masm.passABIArg(y, MoveOp::DOUBLE);
-    masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, ecmaHypot), MoveOp::DOUBLE);
-
+    uint32_t numArgs = lir->numArgs();
+    masm.setupUnalignedABICall(numArgs, temp);
+
+    for (uint32_t i = 0 ; i < numArgs; ++i)
+        masm.passABIArg(ToFloatRegister(lir->getOperand(i)), MoveOp::DOUBLE);
+
+    switch(numArgs) {
+      case 2:
+        masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, ecmaHypot), MoveOp::DOUBLE);
+        break;
+      case 3:
+        masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, hypot3), MoveOp::DOUBLE);
+        break;
+      case 4:
+        masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, hypot4), MoveOp::DOUBLE);
+        break;
+      default:
+        MOZ_CRASH("Unexpected number of arguments to hypot function.");
+    }
     MOZ_ASSERT(ToFloatRegister(lir->output()) == ReturnDoubleReg);
 }
 
 void
 CodeGenerator::visitNewArray(LNewArray *lir)
 {
     Register objReg = ToRegister(lir->output());
     Register tempReg = ToRegister(lir->temp());
--- a/js/src/jit/IonTypes.h
+++ b/js/src/jit/IonTypes.h
@@ -631,17 +631,24 @@ enum ABIFunctionType
     // double f(int, double)
     Args_Double_IntDouble = Args_Double_None |
         (ArgType_Double << (ArgType_Shift * 1)) |
         (ArgType_General << (ArgType_Shift * 2)),
 
     // int f(int, double)
     Args_Int_IntDouble = Args_General0 |
         (ArgType_Double << (ArgType_Shift * 1)) |
-        (ArgType_General << (ArgType_Shift * 2))
+        (ArgType_General << (ArgType_Shift * 2)),
+
+    // double f(double, double, double)
+    Args_Double_DoubleDoubleDouble = Args_Double_DoubleDouble | (ArgType_Double << (ArgType_Shift * 3)),
+
+    // double f(double, double, double, double)
+    Args_Double_DoubleDoubleDoubleDouble = Args_Double_DoubleDoubleDouble | (ArgType_Double << (ArgType_Shift * 4))
+
 };
 
 enum class BarrierKind : uint32_t {
     // No barrier is needed.
     NoBarrier,
 
     // The barrier only has to check the value's type tag is in the TypeSet.
     // Specific object types don't have to be checked.
--- a/js/src/jit/LIR-Common.h
+++ b/js/src/jit/LIR-Common.h
@@ -2960,26 +2960,50 @@ class LAtan2D : public LCallInstructionH
         return getTemp(0);
     }
 
     const LDefinition *output() {
         return getDef(0);
     }
 };
 
-class LHypot : public LCallInstructionHelper<1, 2, 1>
-{
+class LHypot : public LCallInstructionHelper<1, 4, 1>
+{
+    uint32_t numOperands_;
   public:
     LIR_HEADER(Hypot)
-    LHypot(const LAllocation &x, const LAllocation &y, const LDefinition &temp) {
+    LHypot(const LAllocation &x, const LAllocation &y, const LDefinition &temp)
+      : numOperands_(2)
+    {
         setOperand(0, x);
         setOperand(1, y);
         setTemp(0, temp);
     }
 
+    LHypot(const LAllocation &x, const LAllocation &y, const LAllocation &z, const LDefinition &temp)
+      : numOperands_(3)
+    {
+        setOperand(0, x);
+        setOperand(1, y);
+        setOperand(2, z);
+        setTemp(0, temp);
+    }
+
+    LHypot(const LAllocation &x, const LAllocation &y, const LAllocation &z, const LAllocation &w, const LDefinition &temp)
+      : numOperands_(4)
+    {
+        setOperand(0, x);
+        setOperand(1, y);
+        setOperand(2, z);
+        setOperand(3, w);
+        setTemp(0, temp);
+    }
+
+    uint32_t numArgs() const { return numOperands_; }
+
     const LAllocation *x() {
         return getOperand(0);
     }
 
     const LAllocation *y() {
         return getOperand(1);
     }
 
--- a/js/src/jit/Lowering.cpp
+++ b/js/src/jit/Lowering.cpp
@@ -1301,23 +1301,44 @@ LIRGenerator::visitAtan2(MAtan2 *ins)
     LAtan2D *lir = new(alloc()) LAtan2D(useRegisterAtStart(y), useRegisterAtStart(x),
                                         tempFixed(CallTempReg0));
     defineReturn(lir, ins);
 }
 
 void
 LIRGenerator::visitHypot(MHypot *ins)
 {
-    MDefinition *x = ins->x();
-    MOZ_ASSERT(x->type() == MIRType_Double);
-
-    MDefinition *y = ins->y();
-    MOZ_ASSERT(y->type() == MIRType_Double);
-
-    LHypot *lir = new(alloc()) LHypot(useRegisterAtStart(x), useRegisterAtStart(y), tempFixed(CallTempReg0));
+    LHypot *lir = nullptr;
+    uint32_t length = ins->numOperands();
+    for (uint32_t i = 0; i < length; ++i)
+        MOZ_ASSERT(ins->getOperand(i)->type() == MIRType_Double);
+
+    switch(length) {
+      case 2:
+        lir = new(alloc()) LHypot(useRegisterAtStart(ins->getOperand(0)),
+                                  useRegisterAtStart(ins->getOperand(1)),
+                                  tempFixed(CallTempReg0));
+        break;
+      case 3:
+        lir = new(alloc()) LHypot(useRegisterAtStart(ins->getOperand(0)),
+                                  useRegisterAtStart(ins->getOperand(1)),
+                                  useRegisterAtStart(ins->getOperand(2)),
+                                  tempFixed(CallTempReg0));
+        break;
+      case 4:
+        lir = new(alloc()) LHypot(useRegisterAtStart(ins->getOperand(0)),
+                                  useRegisterAtStart(ins->getOperand(1)),
+                                  useRegisterAtStart(ins->getOperand(2)),
+                                  useRegisterAtStart(ins->getOperand(3)),
+                                  tempFixed(CallTempReg0));
+        break;
+      default:
+        MOZ_CRASH("Unexpected number of arguments to LHypot.");
+    }
+
     defineReturn(lir, ins);
 }
 
 void
 LIRGenerator::visitPow(MPow *ins)
 {
     MDefinition *input = ins->input();
     MOZ_ASSERT(input->type() == MIRType_Double);
--- a/js/src/jit/MCallOptimize.cpp
+++ b/js/src/jit/MCallOptimize.cpp
@@ -997,31 +997,40 @@ IonBuilder::inlineMathAtan2(CallInfo &ca
 }
 
 IonBuilder::InliningStatus
 IonBuilder::inlineMathHypot(CallInfo &callInfo)
 {
     if (callInfo.constructing())
         return InliningStatus_NotInlined;
 
-    if (callInfo.argc() != 2)
+    uint32_t argc = callInfo.argc();
+    if (argc < 2 || argc > 4)
         return InliningStatus_NotInlined;
 
     if (getInlineReturnType() != MIRType_Double)
         return InliningStatus_NotInlined;
 
-    MIRType argType0 = callInfo.getArg(0)->type();
-    MIRType argType1 = callInfo.getArg(1)->type();
-
-    if (!IsNumberType(argType0) || !IsNumberType(argType1))
+    MDefinitionVector vector(alloc());
+    if (!vector.reserve(argc))
         return InliningStatus_NotInlined;
 
+    for (uint32_t i = 0; i < argc; ++i) {
+        MDefinition * arg = callInfo.getArg(i);
+        if (!IsNumberType(arg->type()))
+            return InliningStatus_NotInlined;
+        vector.infallibleAppend(arg);
+    }
+
     callInfo.setImplicitlyUsedUnchecked();
-
-    MHypot *hypot = MHypot::New(alloc(), callInfo.getArg(0), callInfo.getArg(1));
+    MHypot *hypot = MHypot::New(alloc(), vector);
+
+    if (!hypot)
+        return InliningStatus_NotInlined;
+
     current->add(hypot);
     current->push(hypot);
     return InliningStatus_Inlined;
 }
 
 IonBuilder::InliningStatus
 IonBuilder::inlineMathPow(CallInfo &callInfo)
 {
--- a/js/src/jit/MIR.cpp
+++ b/js/src/jit/MIR.cpp
@@ -2226,16 +2226,28 @@ MMathFunction::trySpecializeFloat32(Temp
             ConvertDefinitionToDouble<0>(alloc, input(), this);
         return;
     }
 
     setResultType(MIRType_Float32);
     setPolicyType(MIRType_Float32);
 }
 
+MHypot *MHypot::New(TempAllocator &alloc, const MDefinitionVector & vector)
+{
+    uint32_t length = vector.length();
+    MHypot * hypot = new(alloc) MHypot;
+    if (!hypot->init(alloc, length))
+        return nullptr;
+
+    for (uint32_t i = 0; i < length; ++i)
+        hypot->initOperand(i, vector[i]);
+    return hypot;
+}
+
 bool
 MAdd::fallible() const
 {
     // the add is fallible if range analysis does not say that it is finite, AND
     // either the truncation analysis shows that there are non-truncated uses.
     if (truncateKind() >= IndirectTruncate)
         return false;
     if (range() && range()->hasInt32Bounds())
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -4789,18 +4789,18 @@ class MTruncateToInt32
     void computeRange(TempAllocator &alloc) MOZ_OVERRIDE;
     TruncateKind operandTruncateKind(size_t index) const MOZ_OVERRIDE;
 # ifdef DEBUG
     bool isConsistentFloat32Use(MUse *use) const MOZ_OVERRIDE {
         return true;
     }
 #endif
 
-    bool writeRecoverData(CompactBufferWriter &writer) const;
-    bool canRecoverOnBailout() const {
+    bool writeRecoverData(CompactBufferWriter &writer) const MOZ_OVERRIDE;
+    bool canRecoverOnBailout() const MOZ_OVERRIDE {
         return input()->type() < MIRType_Symbol;
     }
 
     ALLOW_CLONE(MTruncateToInt32)
 };
 
 // Converts any type to a string
 class MToString :
@@ -5502,39 +5502,28 @@ class MAtan2
         return true;
     }
 
     ALLOW_CLONE(MAtan2)
 };
 
 // Inline implementation of Math.hypot().
 class MHypot
-  : public MBinaryInstruction,
-    public MixPolicy<DoublePolicy<0>, DoublePolicy<1> >::Data
-{
-    MHypot(MDefinition *y, MDefinition *x)
-      : MBinaryInstruction(x, y)
+  : public MVariadicInstruction,
+    public AllDoublePolicy::Data
+{
+    MHypot()
     {
         setResultType(MIRType_Double);
         setMovable();
     }
 
   public:
     INSTRUCTION_HEADER(Hypot)
-    static MHypot *New(TempAllocator &alloc, MDefinition *x, MDefinition *y) {
-        return new(alloc) MHypot(y, x);
-    }
-
-    MDefinition *x() const {
-        return getOperand(0);
-    }
-
-    MDefinition *y() const {
-        return getOperand(1);
-    }
+    static MHypot *New(TempAllocator &alloc, const MDefinitionVector &vector);
 
     bool congruentTo(const MDefinition *ins) const MOZ_OVERRIDE {
         return congruentIfOperandsEqual(ins);
     }
 
     AliasSet getAliasSet() const MOZ_OVERRIDE {
         return AliasSet::None();
     }
@@ -5543,17 +5532,23 @@ class MHypot
         return true;
     }
 
     bool writeRecoverData(CompactBufferWriter &writer) const MOZ_OVERRIDE;
     bool canRecoverOnBailout() const MOZ_OVERRIDE {
         return true;
     }
 
-    ALLOW_CLONE(MHypot)
+    bool canClone() const {
+        return true;
+    }
+
+    MInstruction *clone(TempAllocator &alloc, const MDefinitionVector &inputs) const {
+       return MHypot::New(alloc, inputs);
+    }
 };
 
 // Inline implementation of Math.pow().
 class MPow
   : public MBinaryInstruction,
     public PowPolicy::Data
 {
     MPow(MDefinition *input, MDefinition *power, MIRType powerType)
--- a/js/src/jit/Recover.cpp
+++ b/js/src/jit/Recover.cpp
@@ -869,33 +869,34 @@ RAtan2::recover(JSContext *cx, SnapshotI
     return true;
 }
 
 bool
 MHypot::writeRecoverData(CompactBufferWriter &writer) const
 {
     MOZ_ASSERT(canRecoverOnBailout());
     writer.writeUnsigned(uint32_t(RInstruction::Recover_Hypot));
+    writer.writeUnsigned(uint32_t(numOperands()));
     return true;
 }
 
 RHypot::RHypot(CompactBufferReader &reader)
+    : numOperands_(reader.readUnsigned())
 { }
 
 bool
 RHypot::recover(JSContext *cx, SnapshotIterator &iter) const
 {
     JS::AutoValueVector vec(cx);
 
-    // currently, only 2 args can be saved in MIR
-    if (!vec.reserve(2))
+    if (!vec.reserve(numOperands_))
         return false;
 
-    vec.infallibleAppend(iter.read());
-    vec.infallibleAppend(iter.read());
+    for (uint32_t i = 0 ; i < numOperands_ ; ++i)
+       vec.infallibleAppend(iter.read());
 
     RootedValue result(cx);
 
     if(!js::math_hypot_handle(cx, vec, &result))
         return false;
 
     iter.storeInstructionResult(result);
     return true;
--- a/js/src/jit/Recover.h
+++ b/js/src/jit/Recover.h
@@ -472,21 +472,24 @@ class RAtan2 MOZ_FINAL : public RInstruc
         return 2;
     }
 
     bool recover(JSContext *cx, SnapshotIterator &iter) const;
 };
 
 class RHypot MOZ_FINAL : public RInstruction
 {
+   private:
+     uint32_t numOperands_;
+
    public:
      RINSTRUCTION_HEADER_(Hypot)
 
      virtual uint32_t numOperands() const {
-         return 2;
+         return numOperands_;
      }
 
      bool recover(JSContext *cx, SnapshotIterator &iter) const;
 };
 
 class RMathFunction MOZ_FINAL : public RInstruction
 {
   private:
--- a/js/src/jit/TypePolicy.cpp
+++ b/js/src/jit/TypePolicy.cpp
@@ -90,16 +90,36 @@ ArithPolicy::adjustInputs(TempAllocator 
         if (!replace->typePolicy()->adjustInputs(alloc, replace))
             return false;
     }
 
     return true;
 }
 
 bool
+AllDoublePolicy::adjustInputs(TempAllocator &alloc, MInstruction *ins)
+{
+    for (size_t i = 0, e = ins->numOperands(); i < e; i++) {
+        MDefinition *in = ins->getOperand(i);
+        if (in->type() == MIRType_Double)
+            continue;
+
+        MInstruction *replace = MToDouble::New(alloc, in);
+
+        ins->block()->insertBefore(ins, replace);
+        ins->replaceOperand(i, replace);
+
+        if (!replace->typePolicy()->adjustInputs(alloc, replace))
+            return false;
+    }
+
+    return true;
+}
+
+bool
 ComparePolicy::adjustInputs(TempAllocator &alloc, MInstruction *def)
 {
     MOZ_ASSERT(def->isCompare());
     MCompare *compare = def->toCompare();
 
     // Convert Float32 operands to doubles
     for (size_t i = 0; i < 2; i++) {
         MDefinition *in = def->getOperand(i);
@@ -1020,16 +1040,17 @@ FilterTypeSetPolicy::adjustInputs(TempAl
     _(FilterTypeSetPolicy)                      \
     _(InstanceOfPolicy)                         \
     _(PowPolicy)                                \
     _(StoreTypedArrayElementStaticPolicy)       \
     _(StoreTypedArrayHolePolicy)                \
     _(StoreTypedArrayPolicy)                    \
     _(StoreUnboxedObjectOrNullPolicy)           \
     _(TestPolicy)                               \
+    _(AllDoublePolicy)                          \
     _(ToDoublePolicy)                           \
     _(ToInt32Policy)                            \
     _(ToStringPolicy)                           \
     _(TypeBarrierPolicy)
 
 #define TEMPLATE_TYPE_POLICY_LIST(_)                                    \
     _(BoxExceptPolicy<0, MIRType_String>)                               \
     _(BoxPolicy<0>)                                                     \
--- a/js/src/jit/TypePolicy.h
+++ b/js/src/jit/TypePolicy.h
@@ -88,16 +88,23 @@ class BoxInputsPolicy MOZ_FINAL : public
 
 class ArithPolicy MOZ_FINAL : public TypePolicy
 {
   public:
     SPECIALIZATION_DATA_;
     virtual bool adjustInputs(TempAllocator &alloc, MInstruction *def) MOZ_OVERRIDE;
 };
 
+class AllDoublePolicy MOZ_FINAL : public TypePolicy
+{
+  public:
+    EMPTY_DATA_;
+    bool adjustInputs(TempAllocator &alloc, MInstruction *def);
+};
+
 class BitwisePolicy MOZ_FINAL : public TypePolicy
 {
   public:
     SPECIALIZATION_DATA_;
     virtual bool adjustInputs(TempAllocator &alloc, MInstruction *def) MOZ_OVERRIDE;
 };
 
 class ComparePolicy MOZ_FINAL : public TypePolicy
--- a/js/src/jit/arm/MacroAssembler-arm.cpp
+++ b/js/src/jit/arm/MacroAssembler-arm.cpp
@@ -4155,16 +4155,18 @@ AssertValidABIFunctionType(uint32_t pass
       case Args_Int_Double:
       case Args_Float32_Float32:
       case Args_Double_Double:
       case Args_Double_Int:
       case Args_Double_DoubleInt:
       case Args_Double_DoubleDouble:
       case Args_Double_IntDouble:
       case Args_Int_IntDouble:
+      case Args_Double_DoubleDoubleDouble:
+      case Args_Double_DoubleDoubleDoubleDouble:
         break;
       default:
         MOZ_CRASH("Unexpected type");
     }
 }
 #endif
 
 void
--- a/js/src/jit/arm/Simulator-arm.cpp
+++ b/js/src/jit/arm/Simulator-arm.cpp
@@ -1445,16 +1445,25 @@ Simulator::getFpArgs(double *x, double *
     } else {
         *x = get_double_from_register_pair(0);
         *y = get_double_from_register_pair(2);
         *z = get_register(2);
     }
 }
 
 void
+Simulator::getFpFromStack(int32_t *stack, double *x)
+{
+    MOZ_ASSERT(stack && x);
+    char buffer[2 * sizeof(stack[0])];
+    memcpy(buffer, stack, 2 * sizeof(stack[0]));
+    memcpy(x, buffer, 2 * sizeof(stack[0]));
+}
+
+void
 Simulator::setCallResultDouble(double result)
 {
     // The return value is either in r0/r1 or d0.
     if (UseHardFpABI()) {
         char buffer[2 * sizeof(vfp_registers_[0])];
         memcpy(buffer, &result, sizeof(buffer));
         // Copy result to d0.
         memcpy(vfp_registers_, buffer, sizeof(buffer));
@@ -2073,16 +2082,19 @@ typedef double (*Prototype_Double_Int)(i
 typedef int32_t (*Prototype_Int_Double)(double arg0);
 typedef float (*Prototype_Float32_Float32)(float arg0);
 
 typedef double (*Prototype_DoubleInt)(double arg0, int32_t arg1);
 typedef double (*Prototype_Double_IntDouble)(int32_t arg0, double arg1);
 typedef double (*Prototype_Double_DoubleDouble)(double arg0, double arg1);
 typedef int32_t (*Prototype_Int_IntDouble)(int32_t arg0, double arg1);
 
+typedef double (*Prototype_Double_DoubleDoubleDouble)(double arg0, double arg1, double arg2);
+typedef double (*Prototype_Double_DoubleDoubleDoubleDouble)(double arg0, double arg1,
+                                                            double arg2, double arg3);
 
 // Fill the volatile registers with scratch values.
 //
 // Some of the ABI calls assume that the float registers are not scratched, even
 // though the ABI defines them as volatile - a performance optimization. These
 // are all calls passing operands in integer registers, so for now the simulator
 // does not scratch any float registers for these calls. Should try to narrow it
 // further in future.
@@ -2294,16 +2306,41 @@ Simulator::softwareInterrupt(SimInstruct
             else
                 dval0 = get_double_from_register_pair(2);
             Prototype_Int_IntDouble target = reinterpret_cast<Prototype_Int_IntDouble>(external);
             int32_t result = target(ival, dval0);
             scratchVolatileRegisters(/* scratchFloat = true */);
             set_register(r0, result);
             break;
           }
+          case Args_Double_DoubleDoubleDouble: {
+            double dval0, dval1, dval2;
+            int32_t ival;
+            getFpArgs(&dval0, &dval1, &ival);
+            // the last argument is on stack
+            getFpFromStack(stack_pointer, &dval2);
+            Prototype_Double_DoubleDoubleDouble target = reinterpret_cast<Prototype_Double_DoubleDoubleDouble>(external);
+            double dresult = target(dval0, dval1, dval2);
+            scratchVolatileRegisters(/* scratchFloat = true */);
+            setCallResultDouble(dresult);
+            break;
+         }
+         case Args_Double_DoubleDoubleDoubleDouble: {
+            double dval0, dval1, dval2, dval3;
+            int32_t ival;
+            getFpArgs(&dval0, &dval1, &ival);
+            // the two last arguments are on stack
+            getFpFromStack(stack_pointer, &dval2);
+            getFpFromStack(stack_pointer + 2, &dval3);
+            Prototype_Double_DoubleDoubleDoubleDouble target = reinterpret_cast<Prototype_Double_DoubleDoubleDoubleDouble>(external);
+            double dresult = target(dval0, dval1, dval2, dval3);
+            scratchVolatileRegisters(/* scratchFloat = true */);
+            setCallResultDouble(dresult);
+            break;
+          }
           default:
             MOZ_CRASH("call");
         }
 
         if (single_stepping_)
             single_step_callback_(single_step_callback_arg_, this, nullptr);
 
         set_register(lr, saved_lr);
--- a/js/src/jit/arm/Simulator-arm.h
+++ b/js/src/jit/arm/Simulator-arm.h
@@ -284,16 +284,17 @@ class Simulator
     bool skipCalleeSavedRegsCheck;
 
     // Runtime call support.
     static void *RedirectNativeFunction(void *nativeFunction, ABIFunctionType type);
 
   private:
     // Handle arguments and return value for runtime FP functions.
     void getFpArgs(double *x, double *y, int32_t *z);
+    void getFpFromStack(int32_t *stack, double *x1);
     void setCallResultDouble(double result);
     void setCallResultFloat(float result);
     void setCallResult(int64_t res);
     void scratchVolatileRegisters(bool scratchFloat = true);
 
     template<class ReturnType, int register_size>
     ReturnType getFromVFPRegister(int reg_index);
 
--- a/js/src/jit/mips/Assembler-mips.cpp
+++ b/js/src/jit/mips/Assembler-mips.cpp
@@ -964,26 +964,26 @@ BufferOffset
 Assembler::as_clz(Register rd, Register rs)
 {
     return writeInst(InstReg(op_special2, rs, rd, rd, ff_clz).encode());
 }
 
 BufferOffset
 Assembler::as_ins(Register rt, Register rs, uint16_t pos, uint16_t size)
 {
-    MOZ_ASSERT(pos < 32 && size != 0 && size <= 32 && pos + size != 0 && pos + size >= 32);
+    MOZ_ASSERT(pos < 32 && size != 0 && size <= 32 && pos + size != 0 && pos + size <= 32);
     Register rd;
     rd = Register::FromCode(pos + size - 1);
     return writeInst(InstReg(op_special3, rs, rt, rd, pos, ff_ins).encode());
 }
 
 BufferOffset
 Assembler::as_ext(Register rt, Register rs, uint16_t pos, uint16_t size)
 {
-    MOZ_ASSERT(pos < 32 && size != 0 && size <= 32 && pos + size != 0 && pos + size >= 32);
+    MOZ_ASSERT(pos < 32 && size != 0 && size <= 32 && pos + size != 0 && pos + size <= 32);
     Register rd;
     rd = Register::FromCode(size - 1);
     return writeInst(InstReg(op_special3, rs, rt, rd, pos, ff_ext).encode());
 }
 
 // FP instructions
 BufferOffset
 Assembler::as_ld(FloatRegister fd, Register base, int32_t off)
--- a/js/src/jit/mips/MacroAssembler-mips.cpp
+++ b/js/src/jit/mips/MacroAssembler-mips.cpp
@@ -3467,16 +3467,18 @@ AssertValidABIFunctionType(uint32_t pass
       case Args_Int_Double:
       case Args_Float32_Float32:
       case Args_Double_Double:
       case Args_Double_Int:
       case Args_Double_DoubleInt:
       case Args_Double_DoubleDouble:
       case Args_Double_IntDouble:
       case Args_Int_IntDouble:
+      case Args_Double_DoubleDoubleDouble:
+      case Args_Double_DoubleDoubleDoubleDouble:
         break;
       default:
         MOZ_CRASH("Unexpected type");
     }
 }
 #endif
 
 void
--- a/js/src/jit/mips/MacroAssembler-mips.h
+++ b/js/src/jit/mips/MacroAssembler-mips.h
@@ -227,17 +227,17 @@ class MacroAssemblerMIPS : public Assemb
     void ma_b(Register lhs, Register rhs, Label *l, Condition c, JumpKind jumpKind = LongJump);
     void ma_b(Register lhs, Imm32 imm, Label *l, Condition c, JumpKind jumpKind = LongJump);
     void ma_b(Register lhs, ImmPtr imm, Label *l, Condition c, JumpKind jumpKind = LongJump) {
         ma_b(lhs, Imm32(uint32_t(imm.value)), l, c, jumpKind);
     }
     void ma_b(Register lhs, ImmGCPtr imm, Label *l, Condition c, JumpKind jumpKind = LongJump) {
         MOZ_ASSERT(lhs != ScratchRegister);
         ma_li(ScratchRegister, imm);
-        ma_b(lhs, Imm32(uint32_t(imm.value)), l, c, jumpKind);
+        ma_b(lhs, ScratchRegister, l, c, jumpKind);
     }
     void ma_b(Register lhs, Address addr, Label *l, Condition c, JumpKind jumpKind = LongJump);
     void ma_b(Address addr, Imm32 imm, Label *l, Condition c, JumpKind jumpKind = LongJump);
     void ma_b(Address addr, Register rhs, Label *l, Condition c, JumpKind jumpKind = LongJump) {
         MOZ_ASSERT(rhs != ScratchRegister);
         ma_lw(ScratchRegister, addr);
         ma_b(ScratchRegister, rhs, l, c, jumpKind);
     }
--- a/js/src/jit/mips/Simulator-mips.cpp
+++ b/js/src/jit/mips/Simulator-mips.cpp
@@ -1546,16 +1546,24 @@ void
 Simulator::getFpArgs(double *x, double *y, int32_t *z)
 {
     *x = getFpuRegisterDouble(12);
     *y = getFpuRegisterDouble(14);
     *z = getRegister(a2);
 }
 
 void
+Simulator::getFpFromStack(int32_t *stack, double *x)
+{
+    MOZ_ASSERT(stack);
+    MOZ_ASSERT(x);
+    memcpy(x, stack, sizeof(double));
+}
+
+void
 Simulator::setCallResultDouble(double result)
 {
     setFpuRegisterDouble(f0, result);
 }
 
 void
 Simulator::setCallResultFloat(float result)
 {
@@ -1852,16 +1860,20 @@ typedef double (*Prototype_Double_Int)(i
 typedef int32_t (*Prototype_Int_Double)(double arg0);
 typedef float (*Prototype_Float32_Float32)(float arg0);
 
 typedef double (*Prototype_DoubleInt)(double arg0, int32_t arg1);
 typedef double (*Prototype_Double_IntDouble)(int32_t arg0, double arg1);
 typedef double (*Prototype_Double_DoubleDouble)(double arg0, double arg1);
 typedef int32_t (*Prototype_Int_IntDouble)(int32_t arg0, double arg1);
 
+typedef double (*Prototype_Double_DoubleDoubleDouble)(double arg0, double arg1, double arg2);
+typedef double (*Prototype_Double_DoubleDoubleDoubleDouble)(double arg0, double arg1,
+                                                            double arg2, double arg3);
+
 // Software interrupt instructions are used by the simulator to call into C++.
 void
 Simulator::softwareInterrupt(SimInstruction *instr)
 {
     int32_t func = instr->functionFieldRaw();
     uint32_t code = (func == ff_break) ? instr->bits(25, 6) : -1;
 
     // We first check if we met a call_rt_redirected.
@@ -2017,16 +2029,39 @@ Simulator::softwareInterrupt(SimInstruct
           case Args_Int_IntDouble: {
             int32_t ival = getRegister(a0);
             double dval0 = getDoubleFromRegisterPair(a2);
             Prototype_Int_IntDouble target = reinterpret_cast<Prototype_Int_IntDouble>(external);
             int32_t result = target(ival, dval0);
             setRegister(v0, result);
             break;
           }
+          case Args_Double_DoubleDoubleDouble: {
+            double dval0, dval1, dval2;
+            int32_t ival;
+            getFpArgs(&dval0, &dval1, &ival);
+            // the last argument is on stack
+            getFpFromStack(stack_pointer + 4, &dval2);
+            Prototype_Double_DoubleDoubleDouble target = reinterpret_cast<Prototype_Double_DoubleDoubleDouble>(external);
+            double dresult = target(dval0, dval1, dval2);
+            setCallResultDouble(dresult);
+            break;
+         }
+         case Args_Double_DoubleDoubleDoubleDouble: {
+            double dval0, dval1, dval2, dval3;
+            int32_t ival;
+            getFpArgs(&dval0, &dval1, &ival);
+            // the two last arguments are on stack
+            getFpFromStack(stack_pointer + 4, &dval2);
+            getFpFromStack(stack_pointer + 6, &dval3);
+            Prototype_Double_DoubleDoubleDoubleDouble target = reinterpret_cast<Prototype_Double_DoubleDoubleDoubleDouble>(external);
+            double dresult = target(dval0, dval1, dval2, dval3);
+            setCallResultDouble(dresult);
+            break;
+          }
           default:
             MOZ_CRASH("call");
         }
 
         setRegister(ra, saved_ra);
         set_pc(getRegister(ra));
 #endif
     } else if (func == ff_break && code <= kMaxStopCode) {
--- a/js/src/jit/mips/Simulator-mips.h
+++ b/js/src/jit/mips/Simulator-mips.h
@@ -292,16 +292,17 @@ class Simulator {
     };
     int16_t exceptions[kNumExceptions];
 
     // Exceptions.
     void signalExceptions();
 
     // Handle arguments and return value for runtime FP functions.
     void getFpArgs(double *x, double *y, int32_t *z);
+    void getFpFromStack(int32_t *stack, double *x);
 
     void setCallResultDouble(double result);
     void setCallResultFloat(float result);
     void setCallResult(int64_t res);
 
     void callInternal(uint8_t *entry);
 
     // Architecture state.
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -447,28 +447,16 @@ JS_ValueToSource(JSContext *cx, HandleVa
 }
 
 JS_PUBLIC_API(bool)
 JS_DoubleIsInt32(double d, int32_t *ip)
 {
     return mozilla::NumberIsInt32(d, ip);
 }
 
-JS_PUBLIC_API(int32_t)
-JS_DoubleToInt32(double d)
-{
-    return ToInt32(d);
-}
-
-JS_PUBLIC_API(uint32_t)
-JS_DoubleToUint32(double d)
-{
-    return ToUint32(d);
-}
-
 JS_PUBLIC_API(JSType)
 JS_TypeOfValue(JSContext *cx, HandleValue value)
 {
     AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, value);
     return TypeOfValue(value);
 }
@@ -5937,25 +5925,25 @@ AutoGCRooter::AutoGCRooter(ContextFriend
   : down(cx->autoGCRooters),
     tag_(tag),
     stackTop(&cx->autoGCRooters)
 {
     MOZ_ASSERT(this != *stackTop);
     *stackTop = this;
 }
 
-#ifdef DEBUG
+#ifdef JS_DEBUG
 JS_PUBLIC_API(void)
-JS::AssertArgumentsAreSane(JSContext *cx, HandleValue value)
+JS::detail::AssertArgumentsAreSane(JSContext *cx, HandleValue value)
 {
     AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, value);
 }
-#endif /* DEBUG */
+#endif /* JS_DEBUG */
 
 JS_PUBLIC_API(void *)
 JS_EncodeScript(JSContext *cx, HandleScript scriptArg, uint32_t *lengthp)
 {
     XDREncoder encoder(cx);
     RootedScript script(cx, scriptArg);
     if (!encoder.codeScript(&script))
         return nullptr;
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -56,30 +56,16 @@ class JS_PUBLIC_API(AutoCheckRequestDept
 
 #else
 
 # define CHECK_REQUEST(cx) \
     ((void) 0)
 
 #endif /* JS_DEBUG */
 
-#ifdef JS_DEBUG
-/*
- * Assert that we're not doing GC on cx, that we're in a request as
- * needed, and that the compartments for cx and v are correct.
- * Also check that GC would be safe at this point.
- */
-JS_PUBLIC_API(void)
-AssertArgumentsAreSane(JSContext *cx, JS::HandleValue v);
-#else
-inline void AssertArgumentsAreSane(JSContext *cx, JS::HandleValue v) {
-    /* Do nothing */
-}
-#endif /* JS_DEBUG */
-
 /* AutoValueArray roots an internal fixed-size array of Values. */
 template <size_t N>
 class AutoValueArray : public AutoGCRooter
 {
     const size_t length_;
     Value elements_[N];
 
   public:
@@ -1105,207 +1091,19 @@ extern JS_PUBLIC_API(JSFunction *)
 JS_ValueToFunction(JSContext *cx, JS::HandleValue v);
 
 extern JS_PUBLIC_API(JSFunction *)
 JS_ValueToConstructor(JSContext *cx, JS::HandleValue v);
 
 extern JS_PUBLIC_API(JSString *)
 JS_ValueToSource(JSContext *cx, JS::Handle<JS::Value> v);
 
-namespace js {
-/*
- * DO NOT CALL THIS.  Use JS::ToNumber
- */
-extern JS_PUBLIC_API(bool)
-ToNumberSlow(JSContext *cx, JS::Value v, double *dp);
-
-/*
- * DO NOT CALL THIS. Use JS::ToBoolean
- */
-extern JS_PUBLIC_API(bool)
-ToBooleanSlow(JS::HandleValue v);
-
-/*
- * DO NOT CALL THIS. Use JS::ToString
- */
-extern JS_PUBLIC_API(JSString*)
-ToStringSlow(JSContext *cx, JS::HandleValue v);
-
-/*
- * DO NOT CALL THIS. Use JS::ToObject.
- */
-extern JS_PUBLIC_API(JSObject*)
-ToObjectSlow(JSContext *cx, JS::HandleValue vp, bool reportScanStack);
-
-} /* namespace js */
-
-namespace JS {
-
-/* ES5 9.3 ToNumber. */
-MOZ_ALWAYS_INLINE bool
-ToNumber(JSContext *cx, HandleValue v, double *out)
-{
-    AssertArgumentsAreSane(cx, v);
-
-    if (v.isNumber()) {
-        *out = v.toNumber();
-        return true;
-    }
-    return js::ToNumberSlow(cx, v, out);
-}
-
-MOZ_ALWAYS_INLINE bool
-ToBoolean(HandleValue v)
-{
-    if (v.isBoolean())
-        return v.toBoolean();
-    if (v.isInt32())
-        return v.toInt32() != 0;
-    if (v.isNullOrUndefined())
-        return false;
-    if (v.isDouble()) {
-        double d = v.toDouble();
-        return !mozilla::IsNaN(d) && d != 0;
-    }
-    if (v.isSymbol())
-        return true;
-
-    /* The slow path handles strings and objects. */
-    return js::ToBooleanSlow(v);
-}
-
-MOZ_ALWAYS_INLINE JSString*
-ToString(JSContext *cx, HandleValue v)
-{
-    if (v.isString())
-        return v.toString();
-    return js::ToStringSlow(cx, v);
-}
-
-/* ES5 9.9 ToObject. */
-MOZ_ALWAYS_INLINE JSObject*
-ToObject(JSContext *cx, HandleValue vp)
-{
-    if (vp.isObject())
-        return &vp.toObject();
-    return js::ToObjectSlow(cx, vp, false);
-}
-
-/*
- * Implements ES6 draft rev 28 (2014 Oct 14) 7.1.1, second algorithm.
- *
- * Most users should not call this -- use JS::ToNumber, ToBoolean, or ToString
- * instead. This should only be called from custom convert hooks. It implements
- * the default conversion behavior shared by most objects in JS, so it's useful
- * as a fallback.
- */
-extern JS_PUBLIC_API(bool)
-OrdinaryToPrimitive(JSContext *cx, JS::HandleObject obj, JSType type,
-                    JS::MutableHandleValue vp);
-
-} /* namespace JS */
-
 extern JS_PUBLIC_API(bool)
 JS_DoubleIsInt32(double d, int32_t *ip);
 
-extern JS_PUBLIC_API(int32_t)
-JS_DoubleToInt32(double d);
-
-extern JS_PUBLIC_API(uint32_t)
-JS_DoubleToUint32(double d);
-
-
-namespace js {
-/* DO NOT CALL THIS. Use JS::ToUint16. */
-extern JS_PUBLIC_API(bool)
-ToUint16Slow(JSContext *cx, JS::HandleValue v, uint16_t *out);
-
-/* DO NOT CALL THIS. Use JS::ToInt32. */
-extern JS_PUBLIC_API(bool)
-ToInt32Slow(JSContext *cx, JS::HandleValue v, int32_t *out);
-
-/* DO NOT CALL THIS. Use JS::ToUint32. */
-extern JS_PUBLIC_API(bool)
-ToUint32Slow(JSContext *cx, JS::HandleValue v, uint32_t *out);
-
-/* DO NOT CALL THIS. Use JS::ToInt64. */
-extern JS_PUBLIC_API(bool)
-ToInt64Slow(JSContext *cx, JS::HandleValue v, int64_t *out);
-
-/* DO NOT CALL THIS. Use JS::ToUint64. */
-extern JS_PUBLIC_API(bool)
-ToUint64Slow(JSContext *cx, JS::HandleValue v, uint64_t *out);
-} /* namespace js */
-
-namespace JS {
-
-MOZ_ALWAYS_INLINE bool
-ToUint16(JSContext *cx, JS::HandleValue v, uint16_t *out)
-{
-    AssertArgumentsAreSane(cx, v);
-
-    if (v.isInt32()) {
-        *out = uint16_t(v.toInt32());
-        return true;
-    }
-    return js::ToUint16Slow(cx, v, out);
-}
-
-MOZ_ALWAYS_INLINE bool
-ToInt32(JSContext *cx, JS::HandleValue v, int32_t *out)
-{
-    AssertArgumentsAreSane(cx, v);
-
-    if (v.isInt32()) {
-        *out = v.toInt32();
-        return true;
-    }
-    return js::ToInt32Slow(cx, v, out);
-}
-
-MOZ_ALWAYS_INLINE bool
-ToUint32(JSContext *cx, JS::HandleValue v, uint32_t *out)
-{
-    AssertArgumentsAreSane(cx, v);
-
-    if (v.isInt32()) {
-        *out = uint32_t(v.toInt32());
-        return true;
-    }
-    return js::ToUint32Slow(cx, v, out);
-}
-
-MOZ_ALWAYS_INLINE bool
-ToInt64(JSContext *cx, JS::HandleValue v, int64_t *out)
-{
-    AssertArgumentsAreSane(cx, v);
-
-    if (v.isInt32()) {
-        *out = int64_t(v.toInt32());
-        return true;
-    }
-    return js::ToInt64Slow(cx, v, out);
-}
-
-MOZ_ALWAYS_INLINE bool
-ToUint64(JSContext *cx, JS::HandleValue v, uint64_t *out)
-{
-    AssertArgumentsAreSane(cx, v);
-
-    if (v.isInt32()) {
-        /* Account for sign extension of negatives into the longer 64bit space. */
-        *out = uint64_t(int64_t(v.toInt32()));
-        return true;
-    }
-    return js::ToUint64Slow(cx, v, out);
-}
-
-
-} /* namespace JS */
-
 extern JS_PUBLIC_API(JSType)
 JS_TypeOfValue(JSContext *cx, JS::Handle<JS::Value> v);
 
 extern JS_PUBLIC_API(bool)
 JS_StrictlyEqual(JSContext *cx, jsval v1, jsval v2, bool *equal);
 
 extern JS_PUBLIC_API(bool)
 JS_LooselyEqual(JSContext *cx, JS::Handle<JS::Value> v1, JS::Handle<JS::Value> v2, bool *equal);
--- a/js/src/jsmath.cpp
+++ b/js/src/jsmath.cpp
@@ -1373,16 +1373,60 @@ js::ecmaHypot(double x, double y)
      */
     if (mozilla::IsInfinite(x) || mozilla::IsInfinite(y)) {
         return mozilla::PositiveInfinity<double>();
     }
 #endif
     return hypot(x, y);
 }
 
+static inline
+void
+hypot_step(double &scale, double &sumsq, double x)
+{
+    double xabs = mozilla::Abs(x);
+    if (scale < xabs) {
+        sumsq = 1 + sumsq * (scale / xabs) * (scale / xabs);
+        scale = xabs;
+    } else if (scale != 0) {
+        sumsq += (xabs / scale) * (xabs / scale);
+    }
+}
+
+double
+js::hypot4(double x, double y, double z, double w)
+{
+    /* Check for infinity or NaNs so that we can return immediatelly.
+     * Does not need to be WIN_XP specific as ecmaHypot
+     */
+    if (mozilla::IsInfinite(x) || mozilla::IsInfinite(y) ||
+            mozilla::IsInfinite(z) || mozilla::IsInfinite(w))
+        return mozilla::PositiveInfinity<double>();
+
+    if (mozilla::IsNaN(x) || mozilla::IsNaN(y) || mozilla::IsNaN(z) ||
+            mozilla::IsNaN(w))
+        return GenericNaN();
+
+    double scale = 0;
+    double sumsq = 1;
+
+    hypot_step(scale, sumsq, x);
+    hypot_step(scale, sumsq, y);
+    hypot_step(scale, sumsq, z);
+    hypot_step(scale, sumsq, w);
+
+    return scale * sqrt(sumsq);
+}
+
+double
+js::hypot3(double x, double y, double z)
+{
+    return hypot4(x, y, z, 0.0);
+}
+
 bool
 js::math_hypot(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     return math_hypot_handle(cx, args, args.rval());
 }
 
 bool
@@ -1413,24 +1457,17 @@ js::math_hypot_handle(JSContext *cx, Han
         if (!ToNumber(cx, args[i], &x))
             return false;
 
         isInfinite |= mozilla::IsInfinite(x);
         isNaN |= mozilla::IsNaN(x);
         if (isInfinite || isNaN)
             continue;
 
-        double xabs = mozilla::Abs(x);
-
-        if (scale < xabs) {
-            sumsq = 1 + sumsq * (scale / xabs) * (scale / xabs);
-            scale = xabs;
-        } else if (scale != 0) {
-            sumsq += (xabs / scale) * (xabs / scale);
-        }
+        hypot_step(scale, sumsq, x);
     }
 
     double result = isInfinite ? PositiveInfinity<double>() :
                     isNaN ? GenericNaN() :
                     scale * sqrt(sumsq);
     res.setNumber(result);
     return true;
 }
--- a/js/src/jsmath.h
+++ b/js/src/jsmath.h
@@ -240,16 +240,22 @@ extern bool
 math_asinh(JSContext *cx, unsigned argc, js::Value *vp);
 
 extern bool
 math_atanh(JSContext *cx, unsigned argc, js::Value *vp);
 
 extern double
 ecmaHypot(double x, double y);
 
+extern double
+hypot3(double x, double y, double z);
+
+extern double
+hypot4(double x, double y, double z, double w);
+
 extern bool
 math_hypot(JSContext *cx, unsigned argc, Value *vp);
 
 extern bool
 math_hypot_handle(JSContext *cx, HandleValueArray args, MutableHandleValue res);
 
 extern bool
 math_trunc(JSContext *cx, unsigned argc, Value *vp);
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -3555,17 +3555,17 @@ js::PrimitiveToObject(JSContext *cx, con
 /*
  * Invokes the ES5 ToObject algorithm on vp, returning the result. If vp might
  * already be an object, use ToObject. reportCantConvert controls how null and
  * undefined errors are reported.
  *
  * Callers must handle the already-object case.
  */
 JSObject *
-js::ToObjectSlow(JSContext *cx, HandleValue val, bool reportScanStack)
+js::ToObjectSlow(JSContext *cx, JS::HandleValue val, bool reportScanStack)
 {
     MOZ_ASSERT(!val.isMagic());
     MOZ_ASSERT(!val.isObject());
 
     if (val.isNullOrUndefined()) {
         if (reportScanStack) {
             js_ReportIsNullOrUndefined(cx, JSDVG_SEARCH_STACK, val, NullPtr());
         } else {
--- a/js/src/jsobj.h
+++ b/js/src/jsobj.h
@@ -15,16 +15,17 @@
  * values, called slots.  The map/slot pointer pair is GC'ed, while the map
  * is reference counted and the slot vector is malloc'ed.
  */
 
 #include "mozilla/MemoryReporting.h"
 
 #include "gc/Barrier.h"
 #include "gc/Marking.h"
+#include "js/Conversions.h"
 #include "js/GCAPI.h"
 #include "js/HeapAPI.h"
 #include "vm/Shape.h"
 #include "vm/String.h"
 #include "vm/Xdr.h"
 
 namespace JS {
 struct ClassInfo;
--- a/js/src/shell/OSObject.cpp
+++ b/js/src/shell/OSObject.cpp
@@ -16,16 +16,18 @@
 #else
 #include <sys/wait.h>
 #include <unistd.h>
 #endif
 
 // For JSFunctionSpecWithHelp
 #include "jsfriendapi.h"
 
+#include "js/Conversions.h"
+
 using namespace JS;
 
 static bool
 os_getenv(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     if (args.length() < 1) {
         JS_ReportError(cx, "os.getenv requires 1 argument");
--- a/js/src/tests/ecma_6/Comprehensions/error-messages.js
+++ b/js/src/tests/ecma_6/Comprehensions/error-messages.js
@@ -26,72 +26,74 @@ const GENERIC              = error("(for
 const BAD_GENERATOR_SYNTAX = error("(for (x of []) x, 1)").message;
 const MISSING_SEMI         = error("yield 1").message;
 const MISSING_PAREN        = error("(yield 1)").message;
 const PAREN_PAREN          = error("(foo").message;
 const FOR_OF_PAREN         = error("(for (x of y, z) w)").message;
 
 const cases = [
 // Expressions involving yield without a value, not currently implemented.  Many
-// of these errors would need to be updated.
-//{ expr: "yield",        top: TOP_YIELD, fun: null,              gen: GENEXP_YIELD, desc: "simple yield" },
-//{ expr: "1, yield",     top: TOP_YIELD, fun: null,              gen: GENEXP_YIELD, desc: "simple yield at end of list" },
-//{ expr: "yield, 1",     top: TOP_YIELD, fun: YIELD_PAREN, gen: YIELD_PAREN,  desc: "simple yield in list" },
-//{ expr: "(yield)",      top: TOP_YIELD, fun: null,              gen: GENEXP_YIELD, desc: "simple yield, parenthesized" },
-//{ expr: "(1, yield)",   top: TOP_YIELD, fun: null,              gen: GENEXP_YIELD, desc: "simple yield at end of list, parenthesized" },
-//{ expr: "(yield, 1)",   top: TOP_YIELD, fun: YIELD_PAREN, gen: YIELD_PAREN,  desc: "simple yield in list, parenthesized" },
-//{ expr: "((((yield))))",   top: TOP_YIELD, fun: null, gen: GENEXP_YIELD, desc: "deeply nested yield" },
-//{ expr: "(for (x of []) yield)",           top: TOP_YIELD, fun: GENERIC,      gen: GENERIC,      desc: "simple yield in genexp" },
-//{ expr: "(for (x of []) yield, 1)",        top: TOP_YIELD, fun: YIELD_PAREN,  gen: YIELD_PAREN,  desc: "simple yield in list in genexp" },
-//{ expr: "(for (x of []) 1, yield)",        top: TOP_YIELD, fun: GENERIC,      gen: GENERIC,      desc: "simple yield at end of list in genexp" },
-//{ expr: "(for (x of []) (yield))",         top: TOP_YIELD, fun: GENEXP_YIELD, gen: GENEXP_YIELD, desc: "simple yield, parenthesized in genexp" },
-//{ expr: "(for (x of []) 1, (yield))",      top: TOP_YIELD, fun: GENEXP_YIELD, gen: GENEXP_YIELD, desc: "simple yield, parenthesized in list in genexp" },
-//{ expr: "(for (x of []) (1, yield))",      top: TOP_YIELD, fun: GENEXP_YIELD, gen: GENEXP_YIELD, desc: "simple yield at end of list, parenthesized in genexp" },
-//{ expr: "(for (x of []) 1, (2, yield))",   top: TOP_YIELD, fun: GENEXP_YIELD, gen: GENEXP_YIELD, desc: "simple yield at end of list, parenthesized in list in genexp" },
-//{ expr: "(for (x of []) (yield, 1))",      top: TOP_YIELD, fun: YIELD_PAREN,  gen: YIELD_PAREN,  desc: "simple yield in list, parenthesized in genexp" },
-//{ expr: "(for (x of []) 1, (yield, 2))",   top: TOP_YIELD, fun: YIELD_PAREN,  gen: YIELD_PAREN,  desc: "simple yield in list, parenthesized in list in genexp" },
+// of these errors would need to be updated.  (Note: line numbers below might be
+// mere placeholders, not actually the expected correct behavior -- check before
+// blindly uncommenting.)
+//{ expr: "yield",        top: [TOP_YIELD, 777], fun: null,              gen: [GENEXP_YIELD, 2], desc: "simple yield" },
+//{ expr: "1, yield",     top: [TOP_YIELD, 777], fun: null,              gen: [GENEXP_YIELD, 2], desc: "simple yield at end of list" },
+//{ expr: "yield, 1",     top: [TOP_YIELD, 777], fun: [YIELD_PAREN, 2], gen: [YIELD_PAREN, 2],  desc: "simple yield in list" },
+//{ expr: "(yield)",      top: [TOP_YIELD, 777], fun: null,              gen: [GENEXP_YIELD, 2], desc: "simple yield, parenthesized" },
+//{ expr: "(1, yield)",   top: [TOP_YIELD, 777], fun: null,              gen: [GENEXP_YIELD, 2], desc: "simple yield at end of list, parenthesized" },
+//{ expr: "(yield, 1)",   top: [TOP_YIELD, 777], fun: [YIELD_PAREN, 2], gen: [YIELD_PAREN, 2],  desc: "simple yield in list, parenthesized" },
+//{ expr: "((((yield))))",   top: [TOP_YIELD, 777], fun: null, gen: [GENEXP_YIELD, 2], desc: "deeply nested yield" },
+//{ expr: "(for (x of []) yield)",           top: [TOP_YIELD, 777], fun: [GENERIC, 777],      gen: [GENERIC, 777],      desc: "simple yield in genexp" },
+//{ expr: "(for (x of []) yield, 1)",        top: [TOP_YIELD, 777], fun: [YIELD_PAREN, 2],  gen: [YIELD_PAREN, 2],  desc: "simple yield in list in genexp" },
+//{ expr: "(for (x of []) 1, yield)",        top: [TOP_YIELD, 777], fun: [GENERIC, 777],      gen: [GENERIC, 777],      desc: "simple yield at end of list in genexp" },
+//{ expr: "(for (x of []) (yield))",         top: [TOP_YIELD, 777], fun: [GENEXP_YIELD, 2], gen: [GENEXP_YIELD, 2], desc: "simple yield, parenthesized in genexp" },
+//{ expr: "(for (x of []) 1, (yield))",      top: [TOP_YIELD, 777], fun: [GENEXP_YIELD, 2], gen: [GENEXP_YIELD, 2], desc: "simple yield, parenthesized in list in genexp" },
+//{ expr: "(for (x of []) (1, yield))",      top: [TOP_YIELD, 777], fun: [GENEXP_YIELD, 2], gen: [GENEXP_YIELD, 2], desc: "simple yield at end of list, parenthesized in genexp" },
+//{ expr: "(for (x of []) 1, (2, yield))",   top: [TOP_YIELD, 777], fun: [GENEXP_YIELD, 2], gen: [GENEXP_YIELD, 2], desc: "simple yield at end of list, parenthesized in list in genexp" },
+//{ expr: "(for (x of []) (yield, 1))",      top: [TOP_YIELD, 777], fun: [YIELD_PAREN, 2],  gen: [YIELD_PAREN, 2],  desc: "simple yield in list, parenthesized in genexp" },
+//{ expr: "(for (x of []) 1, (yield, 2))",   top: [TOP_YIELD, 777], fun: [YIELD_PAREN, 2],  gen: [YIELD_PAREN, 2],  desc: "simple yield in list, parenthesized in list in genexp" },
 //{ expr: "(for (x of []) (function*() { yield }))",           top: null, fun: null, gen: null, desc: "legal yield in nested function" },
 
   // yield expressions
-  { expr: "yield 1",      top: MISSING_SEMI, fun: MISSING_SEMI, gen: null, genexp: GENEXP_YIELD, desc: "yield w/ arg" },
-  { expr: "1, yield 2",   top: MISSING_SEMI, fun: MISSING_SEMI, gen: null, genexp: FOR_OF_PAREN, desc: "yield w/ arg at end of list" },
-  { expr: "yield 1, 2",   top: MISSING_SEMI, fun: MISSING_SEMI, gen: null, genexp: FOR_OF_PAREN, desc: "yield w/ arg in list" },
-  { expr: "(yield 1)",    top: MISSING_PAREN, fun: MISSING_PAREN, gen: null, genexp: GENEXP_YIELD, desc: "yield w/ arg, parenthesized" },
-  { expr: "(1, yield 2)", top: MISSING_PAREN, fun: MISSING_PAREN, gen: null, genexp: GENEXP_YIELD, desc: "yield w/ arg at end of list, parenthesized" },
-  { expr: "(yield 1, 2)", top: MISSING_PAREN, fun: MISSING_PAREN, gen: null, genexp: YIELD_PAREN, desc: "yield w/ arg in list, parenthesized" },
+  { expr: "yield 1",      top: [MISSING_SEMI, 2], fun: [MISSING_SEMI, 2], gen: null, genexp: [GENEXP_YIELD, 2], desc: "yield w/ arg" },
+  { expr: "1, yield 2",   top: [MISSING_SEMI, 2], fun: [MISSING_SEMI, 2], gen: null, genexp: [FOR_OF_PAREN, 1], desc: "yield w/ arg at end of list" },
+  { expr: "yield 1, 2",   top: [MISSING_SEMI, 2], fun: [MISSING_SEMI, 2], gen: [YIELD_PAREN, 3], genexp: [FOR_OF_PAREN, 3], desc: "yield w/ arg in list" },
+  { expr: "(yield 1)",    top: [MISSING_PAREN, 2], fun: [MISSING_PAREN, 2], gen: null, genexp: [GENEXP_YIELD, 2], desc: "yield w/ arg, parenthesized" },
+  { expr: "(1, yield 2)", top: [MISSING_PAREN, 2], fun: [MISSING_PAREN, 2], gen: null, genexp: [GENEXP_YIELD, 2], desc: "yield w/ arg at end of list, parenthesized" },
+  { expr: "(yield 1, 2)", top: [MISSING_PAREN, 2], fun: [MISSING_PAREN, 2], gen: [YIELD_PAREN, 3], genexp: [YIELD_PAREN, 2], desc: "yield w/ arg in list, parenthesized" },
 
   // deeply nested yield expressions
-  { expr: "((((yield 1))))", top: MISSING_PAREN, fun: MISSING_PAREN, gen: null, genexp: GENEXP_YIELD, desc: "deeply nested yield w/ arg" },
+  { expr: "((((yield 1))))", top: [MISSING_PAREN, 2], fun: [MISSING_PAREN, 2], gen: null, genexp: [GENEXP_YIELD, 2], desc: "deeply nested yield w/ arg" },
 
   // arguments
   { expr: "arguments",    top: null, fun: null, gen: null, genexp: null, desc: "arguments in list" },
-  { expr: "1, arguments", top: null, fun: null, gen: null, genexp: FOR_OF_PAREN, desc: "arguments in list" },
+  { expr: "1, arguments", top: null, fun: null, gen: null, genexp: [FOR_OF_PAREN, 1], desc: "arguments in list" },
 
   // yield in generator expressions
-  { expr: "(for (x of []) yield 1)",         top: GENEXP_YIELD, fun: GENEXP_YIELD, gen: GENEXP_YIELD, genexp: GENEXP_YIELD, desc: "yield w/ arg in genexp" },
-  { expr: "(for (x of []) yield 1, 2)",      top: GENEXP_YIELD, fun: GENEXP_YIELD,  gen: GENEXP_YIELD, genexp: GENEXP_YIELD, desc: "yield w/ arg in list in genexp" },
-  { expr: "(for (x of []) 1, yield 2)",      top: PAREN_PAREN, fun: PAREN_PAREN,  gen: PAREN_PAREN, genexp: PAREN_PAREN, desc: "yield w/ arg at end of list in genexp" },
-  { expr: "(for (x of []) (yield 1))",       top: GENEXP_YIELD, fun: GENEXP_YIELD, gen: GENEXP_YIELD, genexp: GENEXP_YIELD, desc: "yield w/ arg, parenthesized in genexp" },
-  { expr: "(for (x of []) 1, (yield 2))",    top: PAREN_PAREN, fun: PAREN_PAREN, gen: PAREN_PAREN, genexp: PAREN_PAREN, desc: "yield w/ arg, parenthesized in list in genexp" },
-  { expr: "(for (x of []) (1, yield 2))",    top: GENEXP_YIELD, fun: GENEXP_YIELD, gen: GENEXP_YIELD, genexp: GENEXP_YIELD, desc: "yield w/ arg at end of list, parenthesized in genexp" },
-  { expr: "(for (x of []) 1, (2, yield 3))", top: PAREN_PAREN, fun: PAREN_PAREN, gen: PAREN_PAREN, genexp: PAREN_PAREN, desc: "yield w/ arg at end of list, parenthesized in list in genexp" },
-  { expr: "(for (x of []) (yield 1, 2))",    top: YIELD_PAREN, fun: YIELD_PAREN, gen: YIELD_PAREN, genexp: YIELD_PAREN, desc: "yield w/ arg in list, parenthesized in genexp" },
-  { expr: "(for (x of []) 1, (yield 2, 3))", top: PAREN_PAREN, fun: PAREN_PAREN, gen: PAREN_PAREN, genexp: PAREN_PAREN, desc: "yield w/ arg in list, parenthesized in list in genexp" },
+  { expr: "(for (x of []) yield 1)",         top: [GENEXP_YIELD, 2], fun: [GENEXP_YIELD, 2], gen: [GENEXP_YIELD, 2], genexp: [GENEXP_YIELD, 2], desc: "yield w/ arg in genexp" },
+  { expr: "(for (x of []) yield 1, 2)",      top: [GENEXP_YIELD, 2], fun: [GENEXP_YIELD, 2],  gen: [GENEXP_YIELD, 2], genexp: [GENEXP_YIELD, 2], desc: "yield w/ arg in list in genexp" },
+  { expr: "(for (x of []) 1, yield 2)",      top: [PAREN_PAREN, 1], fun: [PAREN_PAREN, 1],  gen: [PAREN_PAREN, 1], genexp: [PAREN_PAREN, 1], desc: "yield w/ arg at end of list in genexp" },
+  { expr: "(for (x of []) (yield 1))",       top: [GENEXP_YIELD, 2], fun: [GENEXP_YIELD, 2], gen: [GENEXP_YIELD, 2], genexp: [GENEXP_YIELD, 2], desc: "yield w/ arg, parenthesized in genexp" },
+  { expr: "(for (x of []) 1, (yield 2))",    top: [PAREN_PAREN, 1], fun: [PAREN_PAREN, 1], gen: [PAREN_PAREN, 1], genexp: [PAREN_PAREN, 1], desc: "yield w/ arg, parenthesized in list in genexp" },
+  { expr: "(for (x of []) (1, yield 2))",    top: [GENEXP_YIELD, 2], fun: [GENEXP_YIELD, 2], gen: [GENEXP_YIELD, 2], genexp: [GENEXP_YIELD, 2], desc: "yield w/ arg at end of list, parenthesized in genexp" },
+  { expr: "(for (x of []) 1, (2, yield 3))", top: [PAREN_PAREN, 1], fun: [PAREN_PAREN, 1], gen: [PAREN_PAREN, 1], genexp: [PAREN_PAREN, 1], desc: "yield w/ arg at end of list, parenthesized in list in genexp" },
+  { expr: "(for (x of []) (yield 1, 2))",    top: [YIELD_PAREN, 2], fun: [YIELD_PAREN, 2], gen: [YIELD_PAREN, 2], genexp: [YIELD_PAREN, 2], desc: "yield w/ arg in list, parenthesized in genexp" },
+  { expr: "(for (x of []) 1, (yield 2, 3))", top: [PAREN_PAREN, 1], fun: [PAREN_PAREN, 1], gen: [PAREN_PAREN, 1], genexp: [PAREN_PAREN, 1], desc: "yield w/ arg in list, parenthesized in list in genexp" },
 
   // deeply nested yield in generator expressions
-  { expr: "(for (x of []) (((1, yield 2))))",               top: GENEXP_YIELD, fun: GENEXP_YIELD, gen: GENEXP_YIELD, genexp: GENEXP_YIELD, desc: "deeply nested yield in genexp" },
-  { expr: "(for (y of []) (for (x of []) ((1, yield 2))))", top: GENEXP_YIELD, fun: GENEXP_YIELD, gen: GENEXP_YIELD, genexp: GENEXP_YIELD, desc: "deeply nested yield in multiple genexps" },
+  { expr: "(for (x of []) (((1, yield 2))))",               top: [GENEXP_YIELD, 2], fun: [GENEXP_YIELD, 2], gen: [GENEXP_YIELD, 2], genexp: [GENEXP_YIELD, 2], desc: "deeply nested yield in genexp" },
+  { expr: "(for (y of []) (for (x of []) ((1, yield 2))))", top: [GENEXP_YIELD, 2], fun: [GENEXP_YIELD, 2], gen: [GENEXP_YIELD, 2], genexp: [GENEXP_YIELD, 2], desc: "deeply nested yield in multiple genexps" },
 
   // arguments in generator expressions
   { expr: "(for (x of []) arguments)",         top: null, fun: null, gen: null, genexp: null, desc: "simple arguments in genexp" },
-  { expr: "(for (x of []) 1, arguments)",      top: BAD_GENERATOR_SYNTAX, fun: BAD_GENERATOR_SYNTAX, gen: BAD_GENERATOR_SYNTAX, genexp: BAD_GENERATOR_SYNTAX, desc: "arguments in list in genexp" },
+  { expr: "(for (x of []) 1, arguments)",      top: [BAD_GENERATOR_SYNTAX, 1], fun: [BAD_GENERATOR_SYNTAX, 1], gen: [BAD_GENERATOR_SYNTAX, 1], genexp: [BAD_GENERATOR_SYNTAX, 1], desc: "arguments in list in genexp" },
   { expr: "(for (x of []) (arguments))",       top: null, fun: null, gen: null, genexp: null, desc: "arguments, parenthesized in genexp" },
-  { expr: "(for (x of []) 1, (arguments))",    top: BAD_GENERATOR_SYNTAX, fun: BAD_GENERATOR_SYNTAX, gen: BAD_GENERATOR_SYNTAX, genexp: BAD_GENERATOR_SYNTAX, desc: "arguments, parenthesized in list in genexp" },
+  { expr: "(for (x of []) 1, (arguments))",    top: [BAD_GENERATOR_SYNTAX, 1], fun: [BAD_GENERATOR_SYNTAX, 1], gen: [BAD_GENERATOR_SYNTAX, 1], genexp: [BAD_GENERATOR_SYNTAX, 1], desc: "arguments, parenthesized in list in genexp" },
   { expr: "(for (x of []) (1, arguments))",    top: null, fun: null, gen: null, genexp: null, desc: "arguments in list, parenthesized in genexp" },
-  { expr: "(for (x of []) 1, (2, arguments))", top: BAD_GENERATOR_SYNTAX, fun: BAD_GENERATOR_SYNTAX, gen: BAD_GENERATOR_SYNTAX, genexp: BAD_GENERATOR_SYNTAX, desc: "arguments in list, parenthesized in list in genexp" },
+  { expr: "(for (x of []) 1, (2, arguments))", top: [BAD_GENERATOR_SYNTAX, 1], fun: [BAD_GENERATOR_SYNTAX, 1], gen: [BAD_GENERATOR_SYNTAX, 1], genexp: [BAD_GENERATOR_SYNTAX, 1], desc: "arguments in list, parenthesized in list in genexp" },
 
   // deeply nested arguments in generator expressions
   { expr: "(for (x of []) (((1, arguments))))",               top: null, fun: null, gen: null, genexp: null, desc: "deeply nested arguments in genexp" },
   { expr: "(for (y of []) (for (x of []) ((1, arguments))))", top: null, fun: null, gen: null, genexp: null, desc: "deeply nested arguments in multiple genexps" },
 
   // legal yield/arguments in nested function
   { expr: "(for (x of []) (function*() { yield 1 }))",         top: null, fun: null, gen: null, genexp: null, desc: "legal yield in nested function" },
   { expr: "(for (x of []) (function() { arguments }))",       top: null, fun: null, gen: null, genexp: null, desc: "legal arguments in nested function" },
@@ -105,25 +107,24 @@ test();
 function splitKeyword(str) {
   return str.
 //         replace(/[)] yield/, ')\nyield\n').
          replace(/yield ([0-9])/, '\nyield $1\n').
          replace(/yield([^ ]|$)/, '\nyield\n$1').
          replace(/arguments/, '\narguments\n');
 }
 
-function expectError1(err, ctx, msg) {
+function expectError1(err, ctx, msg, lineNumber) {
   reportCompare('object', typeof err,     'exn for: ' + msg);
   reportCompare(ctx,      err.message,    'exn message for: ' + msg);
-  if (ctx !== BAD_GENERATOR_SYNTAX && ctx != PAREN_PAREN && ctx != FOR_OF_PAREN)
-      reportCompare(2,    err.lineNumber, 'exn token for: ' + msg);
+  reportCompare(lineNumber,    err.lineNumber, 'exn token for: ' + msg);
 }
 
-function expectError(expr, wrapCtx, expect, msg) {
-  expectError1(error(wrapCtx(expr)), expect, msg);
+function expectError(expr, wrapCtx, [expect, lineNumber], msg) {
+  expectError1(error(wrapCtx(expr)), expect, msg, lineNumber);
 }
 
 function expectSuccess(err, msg) {
   reportCompare(null, err, 'parse: ' + msg);
 }
 
 function atTop(str) { return str }
 function inFun(str) { return '(function(){' + str + '})' }
new file mode 100644
--- /dev/null
+++ b/js/src/tests/ecma_6/Expressions/delete-name-parenthesized-early-error-strict-mode.js
@@ -0,0 +1,76 @@
+// Any copyright is dedicated to the Public Domain.
+// http://creativecommons.org/licenses/publicdomain/
+
+//-----------------------------------------------------------------------------
+var BUGNUMBER = 1111101;
+var summary =
+  "delete (foo), delete ((foo)), and so on are strict mode early errors";
+
+print(BUGNUMBER + ": " + summary);
+
+/**************
+ * BEGIN TEST *
+ **************/
+
+function checkSyntaxError(code)
+{
+  function helper(maker)
+  {
+    var earlyError = false;
+    try
+    {
+      var f = maker(code);
+
+      var error = "no early error, created a function with code <" + code + ">";
+      try
+      {
+        f();
+        error += ", and the function can be called without error";
+      }
+      catch (e)
+      {
+        error +=", and calling the function throws " + e;
+      }
+
+      throw new Error(error);
+    }
+    catch (e)
+    {
+      assertEq(e instanceof SyntaxError, true,
+               "expected syntax error, got " + e);
+    }
+  }
+
+  helper(Function);
+  helper(eval);
+}
+
+checkSyntaxError("function f() { 'use strict'; delete escape; } f();");
+checkSyntaxError("function f() { 'use strict'; delete escape; }");
+checkSyntaxError("function f() { 'use strict'; delete (escape); } f();");
+checkSyntaxError("function f() { 'use strict'; delete (escape); }");
+checkSyntaxError("function f() { 'use strict'; delete ((escape)); } f();");
+checkSyntaxError("function f() { 'use strict'; delete ((escape)); }");
+
+// Meanwhile, non-strict all of these should work
+
+function checkFine(code)
+{
+  Function(code);
+  (1, eval)(code); // indirect, to be consistent w/above
+}
+
+checkFine("function f() { delete escape; } f();");
+checkFine("function f() { delete escape; }");
+checkFine("function f() { delete (escape); } f();");
+checkFine("function f() { delete (escape); }");
+checkFine("function f() { delete ((escape)); } f();");
+checkFine("function f() { delete ((escape)); }");
+
+
+/******************************************************************************/
+
+if (typeof reportCompare === "function")
+  reportCompare(true, true);
+
+print("Tests complete");
--- a/js/src/tests/ecma_6/Generators/syntax.js
+++ b/js/src/tests/ecma_6/Generators/syntax.js
@@ -29,17 +29,17 @@ function* g() { (yield 3) + (yield 4); }
 function* g() { yield; }
 function* g() { yield }
 function* g() {
     yield
 }
 function* g() { (yield) }
 function* g() { [yield] }
 function* g() { {yield} }
-function* g() { yield, yield }
+function* g() { (yield), (yield) }
 function* g() { yield; yield }
 function* g() { (yield) ? yield : yield }
 function* g() {
     (yield)
     ? yield
     : yield
 }
 
--- a/js/src/vm/Runtime.h
+++ b/js/src/vm/Runtime.h
@@ -491,32 +491,16 @@ class PerThreadData : public PerThreadDa
      * thread is associated.  This is private because accessing the
      * fields of this runtime can provoke race conditions, so the
      * intention is that access will be mediated through safe
      * functions like |runtimeFromMainThread| and |associatedWith()| below.
      */
     JSRuntime *runtime_;
 
   public:
-    /*
-     * We save all conservative scanned roots in this vector so that
-     * conservative scanning can be "replayed" deterministically. In DEBUG mode,
-     * this allows us to run a non-incremental GC after every incremental GC to
-     * ensure that no objects were missed.
-     */
-#ifdef DEBUG
-    struct SavedGCRoot {
-        void *thing;
-        JSGCTraceKind kind;
-
-        SavedGCRoot(void *thing, JSGCTraceKind kind) : thing(thing), kind(kind) {}
-    };
-    js::Vector<SavedGCRoot, 0, js::SystemAllocPolicy> gcSavedRoots;
-#endif
-
 #ifdef JS_TRACE_LOGGING
     TraceLoggerThread   *traceLogger;
 #endif
 
     /* Pointer to the current AutoFlushICache. */
     js::jit::AutoFlushICache *autoFlushICache_;
 
   public:
--- a/media/gmp-clearkey/0.1/clearkey.info
+++ b/media/gmp-clearkey/0.1/clearkey.info
@@ -1,4 +1,4 @@
 Name: clearkey
 Description: ClearKey decrypt-only GMP plugin
 Version: 0.1
-APIs: eme-decrypt-v3[org.w3.clearkey]
+APIs: eme-decrypt-v4[org.w3.clearkey]
--- a/media/mtransport/nr_socket_prsock.cpp
+++ b/media/mtransport/nr_socket_prsock.cpp
@@ -688,19 +688,67 @@ int NrSocket::read(void* buf, size_t max
     ABORT(R_EOD);
 
   *len = (size_t)status;  // Guaranteed to be > 0
   _status = 0;
 abort:
   return(_status);
 }
 
+NS_IMPL_ISUPPORTS(NrSocketIpcProxy, nsIUDPSocketInternal)
+
+nsresult
+NrSocketIpcProxy::Init(const nsRefPtr<NrSocketIpc>& socket)
+{
+  nsresult rv;
+  sts_thread_ = do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &rv);
+  if (NS_FAILED(rv)) {
+    MOZ_ASSERT(false, "Failed to get STS thread");
+    return rv;
+  }
+
+  socket_ = socket;
+  return NS_OK;
+}
+
+NrSocketIpcProxy::~NrSocketIpcProxy()
+{
+  // Send our ref to STS to be released
+  RUN_ON_THREAD(sts_thread_,
+                mozilla::WrapRelease(socket_.forget()),
+                NS_DISPATCH_NORMAL);
+}
+
+// IUDPSocketInternal interfaces
+// callback while error happened in UDP socket operation
+NS_IMETHODIMP NrSocketIpcProxy::CallListenerError(const nsACString &message,
+                                                  const nsACString &filename,
+                                                  uint32_t line_number) {
+  return socket_->CallListenerError(message, filename, line_number);
+}
+
+// callback while receiving UDP packet
+NS_IMETHODIMP NrSocketIpcProxy::CallListenerReceivedData(const nsACString &host,
+                                                         uint16_t port,
+                                                         const uint8_t *data,
+                                                         uint32_t data_length) {
+  return socket_->CallListenerReceivedData(host, port, data, data_length);
+}
+
+// callback while UDP socket is opened
+NS_IMETHODIMP NrSocketIpcProxy::CallListenerOpened() {
+  return socket_->CallListenerOpened();
+}
+
+// callback while UDP socket is closed
+NS_IMETHODIMP NrSocketIpcProxy::CallListenerClosed() {
+  return socket_->CallListenerClosed();
+}
+
 // NrSocketIpc Implementation
-NS_IMPL_ISUPPORTS(NrSocketIpc, nsIUDPSocketInternal)
-
 NrSocketIpc::NrSocketIpc(const nsCOMPtr<nsIEventTarget> &main_thread)
     : err_(false),
       state_(NR_INIT),
       main_thread_(main_thread),
       monitor_("NrSocketIpc") {
 }
 
 // IUDPSocketInternal interfaces
@@ -1017,17 +1065,25 @@ void NrSocketIpc::create_m(const nsACStr
     MOZ_ASSERT(false, "Failed to create UDPSocketChild");
     mon.NotifyAll();
     return;
   }
 
   socket_child_ = new nsMainThreadPtrHolder<nsIUDPSocketChild>(socketChild);
   socket_child_->SetFilterName(nsCString("stun"));
 
-  if (NS_FAILED(socket_child_->Bind(this, host, port,
+  nsRefPtr<NrSocketIpcProxy> proxy(new NrSocketIpcProxy);
+  rv = proxy->Init(this);
+  if (NS_FAILED(rv)) {
+    err_ = true;
+    mon.NotifyAll();
+    return;
+  }
+
+  if (NS_FAILED(socket_child_->Bind(proxy, host, port,
                                     /* reuse = */ false,
                                     /* loopback = */ false))) {
     err_ = true;
     MOZ_ASSERT(false, "Failed to create UDP socket");
     mon.NotifyAll();
     return;
   }
 }
@@ -1102,17 +1158,17 @@ static nr_socket_vtbl nr_socket_local_vt
   nr_socket_local_getaddr,
   nr_socket_local_connect,
   nr_socket_local_write,
   nr_socket_local_read,
   nr_socket_local_close
 };
 
 int nr_socket_local_create(nr_transport_addr *addr, nr_socket **sockp) {
-  NrSocketBase *sock = nullptr;
+  RefPtr<NrSocketBase> sock;
 
   // create IPC bridge for content process
   if (XRE_GetProcessType() == GeckoProcessType_Default) {
     sock = new NrSocket();
   } else {
     nsCOMPtr<nsIThread> main_thread;
     NS_GetMainThread(getter_AddRefs(main_thread));
     sock = new NrSocketIpc(main_thread.get());
@@ -1124,25 +1180,26 @@ int nr_socket_local_create(nr_transport_
   if (r)
     ABORT(r);
 
   r = nr_socket_create_int(static_cast<void *>(sock),
                            sock->vtbl(), sockp);
   if (r)
     ABORT(r);
 
-  // Add a reference so that we can delete it in destroy()
-  sock->AddRef();
-
   _status = 0;
 
+  {
+    // We will release this reference in destroy(), not exactly the normal
+    // ownership model, but it is what it is.
+    NrSocketBase* dummy = sock.forget().take();
+    (void)dummy;
+  }
+
 abort:
-  if (_status) {
-    delete sock;
-  }
   return _status;
 }
 
 
 static int nr_socket_local_destroy(void **objp) {
   if(!objp || !*objp)
     return 0;
 
--- a/media/mtransport/nr_socket_prsock.h
+++ b/media/mtransport/nr_socket_prsock.h
@@ -183,30 +183,38 @@ struct nr_udp_message {
   PRNetAddr from;
   nsAutoPtr<DataBuffer> data;
 
 private:
   ~nr_udp_message() {}
   DISALLOW_COPY_ASSIGN(nr_udp_message);
 };
 
-class NrSocketIpc : public NrSocketBase,
-                    public nsIUDPSocketInternal {
+class NrSocketIpc : public NrSocketBase {
 public:
 
   enum NrSocketIpcState {
     NR_INIT,
     NR_CONNECTING,
     NR_CONNECTED,
     NR_CLOSING,
     NR_CLOSED,
   };
 
-  NS_DECL_THREADSAFE_ISUPPORTS
-  NS_DECL_NSIUDPSOCKETINTERNAL
+  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(NrSocketIpc)
+
+  NS_IMETHODIMP CallListenerError(const nsACString &message,
+                                  const nsACString &filename,
+                                  uint32_t line_number);
+  NS_IMETHODIMP CallListenerReceivedData(const nsACString &host,
+                                         uint16_t port,
+                                         const uint8_t *data,
+                                         uint32_t data_length);
+  NS_IMETHODIMP CallListenerOpened();
+  NS_IMETHODIMP CallListenerClosed();
 
   explicit NrSocketIpc(const nsCOMPtr<nsIEventTarget> &main_thread);
 
   // Implementations of the NrSocketBase APIs
   virtual int create(nr_transport_addr *addr) MOZ_OVERRIDE;
   virtual int sendto(const void *msg, size_t len,
                      int flags, nr_transport_addr *to) MOZ_OVERRIDE;
   virtual int recvfrom(void * buf, size_t maxlen,
@@ -235,16 +243,32 @@ private:
   std::queue<RefPtr<nr_udp_message> > received_msgs_;
 
   nsMainThreadPtrHandle<nsIUDPSocketChild> socket_child_;
   nsCOMPtr<nsIEventTarget> sts_thread_;
   const nsCOMPtr<nsIEventTarget> main_thread_;
   ReentrantMonitor monitor_;
 };
 
+// The socket child holds onto one of these, which just passes callbacks
+// through and makes sure the ref to the NrSocketIpc is released on STS.
+class NrSocketIpcProxy : public nsIUDPSocketInternal {
+public:
+  NS_DECL_THREADSAFE_ISUPPORTS
+  NS_DECL_NSIUDPSOCKETINTERNAL
+
+  nsresult Init(const nsRefPtr<NrSocketIpc>& socket);
+
+private:
+  virtual ~NrSocketIpcProxy();
+
+  nsRefPtr<NrSocketIpc> socket_;
+  nsCOMPtr<nsIEventTarget> sts_thread_;
+};
+
 int nr_netaddr_to_transport_addr(const net::NetAddr *netaddr,
                                  nr_transport_addr *addr,
                                  int protocol);
 int nr_praddr_to_transport_addr(const PRNetAddr *praddr,
                                 nr_transport_addr *addr,
                                 int protocol, int keep);
 int nr_transport_addr_get_addrstring_and_port(nr_transport_addr *addr,
                                               nsACString *host, int32_t *port);
--- a/media/mtransport/runnable_utils.h
+++ b/media/mtransport/runnable_utils.h
@@ -91,11 +91,30 @@ RUN_ON_THREAD(nsIEventTarget *thread, de
       MOZ_ASSERT(NS_SUCCEEDED(rv));               \
       MOZ_ASSERT(on);                             \
     }                                           \
   } while(0)
 #else
 #define ASSERT_ON_THREAD(t)
 #endif
 
+template <class T>
+class DispatchedRelease : public detail::runnable_args_base<detail::NoResult> {
+public:
+  explicit DispatchedRelease(already_AddRefed<T>& ref) : ref_(ref) {}
+
+  NS_IMETHOD Run() {
+    ref_ = nullptr;
+    return NS_OK;
+  }
+private:
+  nsRefPtr<T> ref_;
+};
+
+template <typename T>
+DispatchedRelease<T>* WrapRelease(already_AddRefed<T>&& ref)
+{
+  return new DispatchedRelease<T>(ref);
+}
+
 } /* namespace mozilla */
 
 #endif
--- a/media/mtransport/third_party/nICEr/src/stun/stun_server_ctx.c
+++ b/media/mtransport/third_party/nICEr/src/stun/stun_server_ctx.c
@@ -104,16 +104,17 @@ static int nr_stun_server_client_create(
       ABORT(R_NO_MEMORY);
 
     if(!(clnt->username=r_strdup(user)))
       ABORT(R_NO_MEMORY);
 
     if(r=r_data_copy(&clnt->password,pass))
       ABORT(r);
 
+    r_log(NR_LOG_STUN,LOG_DEBUG,"STUN-SERVER(%s)/CLIENT(%s): Adding client for %s",ctx->label, client_label, user);
     clnt->stun_server_cb=cb;
     clnt->cb_arg=cb_arg;
 
     *clntp = clnt;
     _status=0;
  abort:
     if(_status){
       nr_stun_server_destroy_client(clnt);
--- a/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.cpp
+++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.cpp
@@ -208,16 +208,17 @@ PeerConnectionImpl* PeerConnectionImpl::
 NS_IMETHODIMP PeerConnectionMedia::ProtocolProxyQueryHandler::
 OnProxyAvailable(nsICancelable *request,
                  nsIChannel *aChannel,
                  nsIProxyInfo *proxyinfo,
                  nsresult result) {
   CSFLogInfo(logTag, "%s: Proxy Available: %d", __FUNCTION__, (int)result);
 
   if (NS_SUCCEEDED(result) && proxyinfo) {
+    CSFLogInfo(logTag, "%s: Had proxyinfo", __FUNCTION__);
     nsresult rv;
     nsCString httpsProxyHost;
     int32_t httpsProxyPort;
 
     rv = proxyinfo->GetHost(httpsProxyHost);
     if (NS_FAILED(rv)) {
       CSFLogError(logTag, "%s: Failed to get proxy server host", __FUNCTION__);
       return rv;
@@ -238,17 +239,17 @@ OnProxyAvailable(nsICancelable *request,
       CSFLogError(logTag, "%s: Failed to set proxy server (ICE ctx unavailable)",
           __FUNCTION__);
     }
   }
 
   if (result != NS_ERROR_ABORT) {
     // NS_ERROR_ABORT means that the PeerConnectionMedia is no longer waiting
     pcm_->mProxyResolveCompleted = true;
-    pcm_->GatherIfReady();
+    pcm_->FlushIceCtxOperationQueueIfReady();
   }
 
   return NS_OK;
 }
 
 NS_IMPL_ISUPPORTS(PeerConnectionMedia::ProtocolProxyQueryHandler, nsIProtocolProxyCallback)
 
 PeerConnectionMedia::PeerConnectionMedia(PeerConnectionImpl *parent)
@@ -256,17 +257,16 @@ PeerConnectionMedia::PeerConnectionMedia
       mParentHandle(parent->GetHandle()),
       mParentName(parent->GetName()),
       mAllowIceLoopback(false),
       mIceCtx(nullptr),
       mDNSResolver(new mozilla::NrIceResolver()),
       mUuidGen(MakeUnique<PCUuidGenerator>()),
       mMainThread(mParent->GetMainThread()),
       mSTSThread(mParent->GetSTSThread()),
-      mTransportsUpdated(false),
       mProxyResolveCompleted(false) {
   nsresult rv;
 
   nsCOMPtr<nsIProtocolProxyService> pps =
     do_GetService(NS_PROTOCOLPROXYSERVICE_CONTRACTID, &rv);
   if (NS_FAILED(rv)) {
     CSFLogError(logTag, "%s: Failed to get proxy service: %d", __FUNCTION__, (int)rv);
     return;
@@ -395,17 +395,16 @@ PeerConnectionMedia::UpdateTransports(co
                                pwd,
                                candidates),
                   NS_DISPATCH_NORMAL);
   }
 
 
   // TODO(bug 1017888): Need to deal properly with renegotatiation.
   // For now just start gathering.
-  mTransportsUpdated = true;
   GatherIfReady();
 }
 
 nsresult PeerConnectionMedia::UpdateMediaPipelines(
     const mozilla::JsepSession& session) {
   size_t numPairs = session.GetNegotiatedTrackPairCount();
   mozilla::MediaPipelineFactory factory(this);
   const mozilla::JsepTrackPair* pair;
@@ -462,26 +461,27 @@ PeerConnectionMedia::StartIceChecks(cons
     } else {
       CSFLogDebug(logTag, "Transport %u has %u components",
                           static_cast<unsigned>(i),
                           static_cast<unsigned>(transport->mComponents));
       numComponentsByLevel.push_back(transport->mComponents);
     }
   }
 
-  RUN_ON_THREAD(GetSTSThread(),
-                WrapRunnable(
-                  RefPtr<PeerConnectionMedia>(this),
-                  &PeerConnectionMedia::StartIceChecks_s,
-                  session.IsIceControlling(),
-                  session.RemoteIsIceLite(),
-                  // Copy, just in case API changes to return a ref
-                  std::vector<std::string>(session.GetIceOptions()),
-                  numComponentsByLevel),
-                NS_DISPATCH_NORMAL);
+  nsRefPtr<nsIRunnable> runnable(
+      WrapRunnable(
+        RefPtr<PeerConnectionMedia>(this),
+        &PeerConnectionMedia::StartIceChecks_s,
+        session.IsIceControlling(),
+        session.RemoteIsIceLite(),
+        // Copy, just in case API changes to return a ref
+        std::vector<std::string>(session.GetIceOptions()),
+        numComponentsByLevel));
+
+  PerformOrEnqueueIceCtxOperation(runnable);
 }
 
 void
 PeerConnectionMedia::StartIceChecks_s(
     bool aIsControlling,
     bool aIsIceLite,
     const std::vector<std::string>& aIceOptionsList,
     const std::vector<size_t>& aComponentCountByLevel) {
@@ -552,26 +552,52 @@ PeerConnectionMedia::AddIceCandidate_s(c
   if (NS_FAILED(rv)) {
     CSFLogError(logTag, "Couldn't process ICE candidate at level %u",
                 aMLine);
     return;
   }
 }
 
 void
+PeerConnectionMedia::FlushIceCtxOperationQueueIfReady()
+{
+  ASSERT_ON_THREAD(mMainThread);
+
+  if (IsIceCtxReady()) {
+    for (auto i = mQueuedIceCtxOperations.begin();
+         i != mQueuedIceCtxOperations.end();
+         ++i) {
+      GetSTSThread()->Dispatch(*i, NS_DISPATCH_NORMAL);
+    }
+    mQueuedIceCtxOperations.clear();
+  }
+}
+
+void
+PeerConnectionMedia::PerformOrEnqueueIceCtxOperation(
+    const nsRefPtr<nsIRunnable>& runnable)
+{
+  ASSERT_ON_THREAD(mMainThread);
+
+  if (IsIceCtxReady()) {
+    GetSTSThread()->Dispatch(runnable, NS_DISPATCH_NORMAL);
+  } else {
+    mQueuedIceCtxOperations.push_back(runnable);
+  }
+}
+
+void
 PeerConnectionMedia::GatherIfReady() {
   ASSERT_ON_THREAD(mMainThread);
 
-  if (mTransportsUpdated && mProxyResolveCompleted) {
-    RUN_ON_THREAD(GetSTSThread(),
-        WrapRunnable(
-          RefPtr<PeerConnectionMedia>(this),
-          &PeerConnectionMedia::EnsureIceGathering_s),
-        NS_DISPATCH_NORMAL);
-  }
+  nsRefPtr<nsIRunnable> runnable(WrapRunnable(
+        RefPtr<PeerConnectionMedia>(this),
+        &PeerConnectionMedia::EnsureIceGathering_s));
+
+  PerformOrEnqueueIceCtxOperation(runnable);
 }
 
 void
 PeerConnectionMedia::EnsureIceGathering_s() {
   if (mIceCtx->gathering_state() == NrIceCtx::ICE_CTX_GATHER_INIT) {
     if (mProxyServer) {
       mIceCtx->SetProxyServer(*mProxyServer);
     }
--- a/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.h
+++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.h
@@ -461,16 +461,18 @@ class PeerConnectionMedia : public sigsl
 
   // Manage ICE transports.
   void UpdateIceMediaStream_s(size_t aMLine, size_t aComponentCount,
                               bool aHasAttrs,
                               const std::string& aUfrag,
                               const std::string& aPassword,
                               const std::vector<std::string>& aCandidateList);
   void GatherIfReady();
+  void FlushIceCtxOperationQueueIfReady();
+  void PerformOrEnqueueIceCtxOperation(const nsRefPtr<nsIRunnable>& runnable);
   void EnsureIceGathering_s();
   void StartIceChecks_s(bool aIsControlling,
                         bool aIsIceLite,
                         const std::vector<std::string>& aIceOptionsList,
                         const std::vector<size_t>& aComponentCountByLevel);
 
   // Process a trickle ICE candidate.
   void AddIceCandidate_s(const std::string& aCandidate, const std::string& aMid,
@@ -492,16 +494,19 @@ class PeerConnectionMedia : public sigsl
   void IceGatheringStateChange_m(mozilla::NrIceCtx* ctx,
                                  mozilla::NrIceCtx::GatheringState state);
   void IceConnectionStateChange_m(mozilla::NrIceCtx* ctx,
                                   mozilla::NrIceCtx::ConnectionState state);
   void OnCandidateFound_m(const std::string &candidate, uint16_t aMLine);
   void EndOfLocalCandidates_m(const std::string& aDefaultAddr,
                               uint16_t aDefaultPort,
                               uint16_t aMLine);
+  bool IsIceCtxReady() const {
+    return mProxyResolveCompleted;
+  }
 
 
   // The parent PC
   PeerConnectionImpl *mParent;
   // and a loose handle on it for event driven stuff
   std::string mParentHandle;
   std::string mParentName;
 
@@ -534,18 +539,21 @@ class PeerConnectionMedia : public sigsl
   mozilla::UniquePtr<PCUuidGenerator> mUuidGen;
 
   // The main thread.
   nsCOMPtr<nsIThread> mMainThread;
 
   // The STS thread.
   nsCOMPtr<nsIEventTarget> mSTSThread;
 
-  // Used to track when transports are updated and are ready to start gathering
-  bool mTransportsUpdated;
+  // Used whenever we need to dispatch a runnable to STS to tweak something
+  // on our ICE ctx, but are not ready to do so at the moment (eg; we are
+  // waiting to get a callback with our http proxy config before we start
+  // gathering or start checking)
+  std::vector<nsRefPtr<nsIRunnable>> mQueuedIceCtxOperations;
 
   // Used to cancel any ongoing proxy request.
   nsCOMPtr<nsICancelable> mProxyRequest;
 
   // Used to track the state of the request.
   bool mProxyResolveCompleted;
 
   // Used to store the result of the request.
--- a/mozglue/build/WindowsDllBlocklist.cpp
+++ b/mozglue/build/WindowsDllBlocklist.cpp
@@ -154,16 +154,22 @@ static DllBlockInfo sWindowsDllBlocklist
   { "libredir2.dll", 0x5385B7ED, DllBlockInfo::USE_TIMESTAMP },
 
   // Crashes with RoboForm2Go written against old SDK, bug 988311
   { "rf-firefox-22.dll", ALL_VERSIONS },
 
   // Crashes with DesktopTemperature, bug 1046382
   { "dtwxsvc.dll", 0x53153234, DllBlockInfo::USE_TIMESTAMP },
 
+  // Startup crashes with Lenovo Onekey Theater, bug 1123778
+  { "activedetect32.dll", UNVERSIONED },
+  { "activedetect64.dll", UNVERSIONED },
+  { "windowsapihookdll32.dll", UNVERSIONED },
+  { "windowsapihookdll64.dll", UNVERSIONED },
+
   { nullptr, 0 }
 };
 
 #ifndef STATUS_DLL_NOT_FOUND
 #define STATUS_DLL_NOT_FOUND ((DWORD)0xC0000135L)
 #endif
 
 // define this for very verbose dll load debug spew
--- a/netwerk/cache2/CacheFile.cpp
+++ b/netwerk/cache2/CacheFile.cpp
@@ -607,18 +607,19 @@ CacheFile::OnMetadataWritten(nsresult aR
   LOG(("CacheFile::OnMetadataWritten() [this=%p, rv=0x%08x]", this, aResult));
 
   MOZ_ASSERT(mWritingMetadata);
   mWritingMetadata = false;
 
   MOZ_ASSERT(!mMemoryOnly);
   MOZ_ASSERT(!mOpeningFile);
 
-  if (NS_FAILED(aResult)) {
+  if (NS_WARN_IF(NS_FAILED(aResult))) {
     // TODO close streams with an error ???
+    SetError(aResult);
   }
 
   if (mOutput || mInputs.Length() || mChunks.Count())
     return NS_OK;
 
   if (IsDirty())
     WriteMetadataIfNeededLocked();
 
--- a/netwerk/cache2/CacheFileIOManager.cpp
+++ b/netwerk/cache2/CacheFileIOManager.cpp
@@ -701,16 +701,20 @@ public:
     nsresult rv;
 
     MOZ_EVENT_TRACER_EXEC(static_cast<nsIRunnable*>(this), "net::cache::write-background");
     if (mHandle->IsClosed()) {
       rv = NS_ERROR_NOT_INITIALIZED;
     } else {
       rv = CacheFileIOManager::gInstance->WriteInternal(
           mHandle, mOffset, mBuf, mCount, mValidate);
+      if (NS_FAILED(rv) && !mCallback) {
+        // No listener is going to handle the error, doom the file
+        CacheFileIOManager::gInstance->DoomFileInternal(mHandle);
+      }
     }
     MOZ_EVENT_TRACER_DONE(static_cast<nsIRunnable*>(this), "net::cache::write-background");
 
     MOZ_EVENT_TRACER_EXEC(static_cast<nsIRunnable*>(this), "net::cache::write-result");
     if (mCallback) {
       mCallback->OnDataWritten(mHandle, mBuf, rv);
     } else {
       free(const_cast<char *>(mBuf));
--- a/security/pkix/test/gtest/pkixbuild_tests.cpp
+++ b/security/pkix/test/gtest/pkixbuild_tests.cpp
@@ -137,17 +137,17 @@ private:
   }
 
   Result IsChainValid(const DERArray&, Time) override
   {
     return Success;
   }
 
   Result VerifySignedData(const SignedDataWithSignature& signedData,
-                          Input subjectPublicKeyInfo)
+                          Input subjectPublicKeyInfo) override
   {
     return TestVerifySignedData(signedData, subjectPublicKeyInfo);
   }
 
   Result DigestBuf(Input item, /*out*/ uint8_t *digestBuf, size_t digestBufLen)
                    override
   {
     ADD_FAILURE();
--- a/toolkit/system/dbus/nsNetworkManagerListener.h
+++ b/toolkit/system/dbus/nsNetworkManagerListener.h
@@ -15,19 +15,19 @@ class nsNetworkManagerListener : public 
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSINETWORKLINKSERVICE
 
   nsNetworkManagerListener();
 
   nsresult Init();
 
-  virtual void RegisterWithConnection(DBusConnection* connection);
-  virtual void UnregisterWithConnection(DBusConnection* connection);
-  virtual bool HandleMessage(DBusMessage* msg);
+  virtual void RegisterWithConnection(DBusConnection* connection) MOZ_OVERRIDE;
+  virtual void UnregisterWithConnection(DBusConnection* connection) MOZ_OVERRIDE;
+  virtual bool HandleMessage(DBusMessage* msg) MOZ_OVERRIDE;
 
   /**
    * This gets called when NetworkManager sends us a StateChange signal,
    * or when we receive a reply to our inquiry.
    * The message contains the current NMState.
    */
   void UpdateNetworkStatus(DBusMessage* message);
 
--- a/xpcom/base/SystemMemoryReporter.cpp
+++ b/xpcom/base/SystemMemoryReporter.cpp
@@ -154,17 +154,17 @@ public:
       }                                                                       \
     }                                                                         \
   } while (0)
 
 #define REPORT(_path, _amount, _desc) \
   REPORT_WITH_CLEANUP(_path, UNITS_BYTES, _amount, _desc, (void)0)
 
   NS_IMETHOD CollectReports(nsIHandleReportCallback* aHandleReport,
-                            nsISupports* aData, bool aAnonymize)
+                            nsISupports* aData, bool aAnonymize) MOZ_OVERRIDE
   {
     // There is lots of privacy-sensitive data in /proc. Just skip this
     // reporter entirely when anonymization is required.
     if (aAnonymize) {
       return NS_OK;
     }
 
     if (!Preferences::GetBool("memory.system_memory_reporter")) {
--- a/xpcom/base/nsMemoryReporterManager.cpp
+++ b/xpcom/base/nsMemoryReporterManager.cpp
@@ -550,17 +550,17 @@ PrivateDistinguishedAmount(int64_t* aN)
 class VsizeMaxContiguousReporter MOZ_FINAL : public nsIMemoryReporter
 {
   ~VsizeMaxContiguousReporter() {}
 
 public:
   NS_DECL_ISUPPORTS
 
   NS_METHOD CollectReports(nsIHandleReportCallback* aHandleReport,
-                           nsISupports* aData, bool aAnonymize)
+                           nsISupports* aData, bool aAnonymize) MOZ_OVERRIDE
   {
     int64_t amount;
     nsresult rv = VsizeMaxContiguousDistinguishedAmount(&amount);
     NS_ENSURE_SUCCESS(rv, rv);
     return MOZ_COLLECT_REPORT(
       "vsize-max-contiguous", KIND_OTHER, UNITS_BYTES, amount,
       "Size of the maximum contiguous block of available virtual "
       "memory.");
@@ -573,17 +573,17 @@ NS_IMPL_ISUPPORTS(VsizeMaxContiguousRepo
 class PrivateReporter MOZ_FINAL : public nsIMemoryReporter
 {
   ~PrivateReporter() {}
 
 public:
   NS_DECL_ISUPPORTS
 
   NS_METHOD CollectReports(nsIHandleReportCallback* aHandleReport,
-                           nsISupports* aData, bool aAnonymize)
+                           nsISupports* aData, bool aAnonymize) MOZ_OVERRIDE
   {
     int64_t amount;
     nsresult rv = PrivateDistinguishedAmount(&amount);
     NS_ENSURE_SUCCESS(rv, rv);
     return MOZ_COLLECT_REPORT(
       "private", KIND_OTHER, UNITS_BYTES, amount,
 "Memory that cannot be shared with other processes, including memory that is "
 "committed and marked MEM_PRIVATE, data that is not mapped, and executable "
@@ -917,17 +917,17 @@ namespace mozilla {
 namespace dmd {
 
 class DMDReporter MOZ_FINAL : public nsIMemoryReporter
 {
 public:
   NS_DECL_ISUPPORTS
 
   NS_IMETHOD CollectReports(nsIHandleReportCallback* aHandleReport,
-                            nsISupports* aData, bool aAnonymize)
+                            nsISupports* aData, bool aAnonymize) MOZ_OVERRIDE
   {
     dmd::Sizes sizes;
     dmd::SizeOf(&sizes);
 
 #define REPORT(_path, _amount, _desc)                                         \
   do {                                                                        \
     nsresult rv;                                                              \
     rv = aHandleReport->Callback(EmptyCString(), NS_LITERAL_CSTRING(_path),   \