Merge mozilla-central to fx-team
authorCarsten Book <cbook@mozilla.com>
Tue, 15 Sep 2015 15:11:04 +0200
changeset 296868 04d0b5249c1ce14c9c3708dc6e3e1a9d5f220ed6
parent 296867 3c30e2768d9d28ea5bc0c26d4dec76e531a9162e (current diff)
parent 296861 5d61714cf5c3ec2440e9491ba30893ac37ca06c2 (diff)
child 296869 f76ad9b2ec289476a016393f068ded2ffa8e6e49
push id962
push userjlund@mozilla.com
push dateFri, 04 Dec 2015 23:28:54 +0000
treeherdermozilla-release@23a2d286e80f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone43.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge mozilla-central to fx-team
extensions/spellcheck/hunspell/src/PRemoteSpellcheckEngine.ipdl
extensions/spellcheck/hunspell/src/RemoteSpellCheckEngineChild.cpp
extensions/spellcheck/hunspell/src/RemoteSpellCheckEngineChild.h
extensions/spellcheck/hunspell/src/RemoteSpellCheckEngineParent.cpp
extensions/spellcheck/hunspell/src/RemoteSpellCheckEngineParent.h
extensions/spellcheck/hunspell/src/hunspell_alloc_hooks.h
extensions/spellcheck/hunspell/src/hunspell_fopen_hooks.h
extensions/spellcheck/hunspell/src/mozHunspell.cpp
extensions/spellcheck/hunspell/src/mozHunspell.h
extensions/spellcheck/hunspell/src/mozHunspellAllocator.h
extensions/spellcheck/hunspell/src/mozHunspellDirProvider.cpp
extensions/spellcheck/hunspell/src/mozHunspellDirProvider.h
testing/talos/talos/sample.2.config
testing/web-platform/meta/2dcontext/drawing-images-to-the-canvas/2d.drawImage.negativedest.html.ini
testing/web-platform/meta/2dcontext/drawing-images-to-the-canvas/2d.drawImage.negativedir.html.ini
testing/web-platform/meta/2dcontext/drawing-images-to-the-canvas/2d.drawImage.negativesource.html.ini
testing/web-platform/meta/2dcontext/drawing-images-to-the-canvas/drawimage_canvas_8.html.ini
toolkit/locales/en-US/chrome/mozapps/plugins/plugins.dtd
toolkit/mozapps/plugins/content/pluginFinderBinding.css
toolkit/mozapps/plugins/content/pluginProblem.xml
toolkit/mozapps/plugins/content/pluginProblemBinding.css
toolkit/mozapps/plugins/content/pluginProblemContent.css
toolkit/mozapps/plugins/jar.mn
toolkit/mozapps/plugins/moz.build
toolkit/mozapps/plugins/pluginGlue.manifest
--- a/accessible/jsat/AccessFu.jsm
+++ b/accessible/jsat/AccessFu.jsm
@@ -853,21 +853,22 @@ var Input = {
 
   androidScroll: function androidScroll(aDirection) {
     let mm = Utils.getMessageManager(Utils.CurrentBrowser);
     mm.sendAsyncMessage('AccessFu:AndroidScroll',
                         { direction: aDirection, origin: 'top' });
   },
 
   moveByGranularity: function moveByGranularity(aDetails) {
-    const MOVEMENT_GRANULARITY_PARAGRAPH = 8;
+    const GRANULARITY_PARAGRAPH = 8;
+    const GRANULARITY_LINE = 4;
 
     if (!this.editState.editing) {
-      if (aDetails.granularity === MOVEMENT_GRANULARITY_PARAGRAPH) {
-        this.moveCursor('move' + aDetails.direction, 'Paragraph', 'gesture');
+      if (aDetails.granularity & (GRANULARITY_PARAGRAPH | GRANULARITY_LINE)) {
+        this.moveCursor('move' + aDetails.direction, 'Simple', 'gesture');
         return;
       }
     } else {
       aDetails.atStart = this.editState.atStart;
       aDetails.atEnd = this.editState.atEnd;
     }
 
     let mm = Utils.getMessageManager(Utils.CurrentBrowser);
--- a/accessible/xpcom/moz.build
+++ b/accessible/xpcom/moz.build
@@ -42,11 +42,8 @@ elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'co
         '/accessible/mac',
     ]
 else:
     LOCAL_INCLUDES += [
         '/accessible/other',
     ]
 
 FINAL_LIBRARY = 'xul'
-
-if not CONFIG['GNU_CXX']:
-    ALLOW_COMPILER_WARNINGS = True
--- a/aclocal.m4
+++ b/aclocal.m4
@@ -28,16 +28,17 @@ builtin(include, build/autoconf/zlib.m4)
 builtin(include, build/autoconf/linux.m4)dnl
 builtin(include, build/autoconf/python-virtualenv.m4)dnl
 builtin(include, build/autoconf/winsdk.m4)dnl
 builtin(include, build/autoconf/icu.m4)dnl
 builtin(include, build/autoconf/ffi.m4)dnl
 builtin(include, build/autoconf/clang-plugin.m4)dnl
 builtin(include, build/autoconf/alloc.m4)dnl
 builtin(include, build/autoconf/ios.m4)dnl
+builtin(include, build/autoconf/jemalloc.m4)dnl
 
 MOZ_PROG_CHECKMSYS()
 
 # Read the user's .mozconfig script.  We can't do this in
 # configure.in: autoconf puts the argument parsing code above anything
 # expanded from configure.in, and we need to get the configure options
 # from .mozconfig in place before that argument parsing code.
 MOZ_READ_MOZCONFIG(.)
--- a/b2g/chrome/content/devtools/hud.js
+++ b/b2g/chrome/content/devtools/hud.js
@@ -760,66 +760,100 @@ developerHUD.registerWatcher(eventLoopLa
  * to the app-launch epoch and emits an "app-start-time-<performance mark name>"
  * event containing the delta.
  */
 let performanceEntriesWatcher = {
   _client: null,
   _fronts: new Map(),
   _appLaunchName: null,
   _appLaunchStartTime: null,
+  _supported: [
+    'contentInteractive',
+    'navigationInteractive',
+    'navigationLoaded',
+    'visuallyLoaded',
+    'fullyLoaded',
+    'mediaEnumerated',
+    'scanEnd'
+  ],
 
   init(client) {
     this._client = client;
+    let setting = 'devtools.telemetry.supported_performance_marks';
+    let defaultValue = this._supported.join(',');
+
+    SettingsListener.observe(setting, defaultValue, supported => {
+      let value = supported || defaultValue;
+      this._supported = value.split(',');
+    });
   },
 
   trackTarget(target) {
     // The performanceEntries watcher doesn't register a metric because
     // currently the metrics generated are not displayed in
     // in the front-end.
 
     let front = new PerformanceEntriesFront(this._client, target.actor);
     this._fronts.set(target, front);
 
     // User timings are always gathered; there is no setting to enable/
     // disable.
     front.start();
 
     front.on('entry', detail => {
-      if (detail.type === 'mark') {
-        let name = detail.name;
-        let epoch = detail.epoch;
+
+      // Only process performance marks.
+      if (detail.type !== 'mark') {
+        return;
+      }
+
+      let name = detail.name;
+      let epoch = detail.epoch;
+
+      // FIXME There is a potential race condition that can result
+      // in some performance entries being disregarded. See bug 1189942.
+      //
+      // If this is an "app launch" mark, record the app that was
+      // launched and the epoch of when it was launched.
+      if (name.indexOf('appLaunch') !== -1) {
         let CHARS_UNTIL_APP_NAME = 7; // '@app://'
+        let startPos = name.indexOf('@app') + CHARS_UNTIL_APP_NAME;
+        let endPos = name.indexOf('.');
+        this._appLaunchName = name.slice(startPos, endPos);
+        this._appLaunchStartTime = epoch;
+        return;
+      }
 
-        // FIXME There is a potential race condition that can result
-        // in some performance entries being disregarded. See bug 1189942.
-        if (name.indexOf('appLaunch') != -1) {
-          let appStartPos = name.indexOf('@app') + CHARS_UNTIL_APP_NAME;
-          let length = (name.indexOf('.') - appStartPos);
-          this._appLaunchName = name.substr(appStartPos, length);
-          this._appLaunchStartTime = epoch;
-        } else {
-          let origin = detail.origin;
-          origin = origin.substr(0, origin.indexOf('.'));
-          if (this._appLaunchName === origin) {
-            let time = epoch - this._appLaunchStartTime;
-            let eventName = 'app-startup-time-' + name;
+      // Only process supported performance marks
+      if (this._supported.indexOf(name) === -1) {
+        return;
+      }
+
+      let origin = detail.origin;
+      origin = origin.slice(0, origin.indexOf('.'));
+
+      // Continue if the performance mark corresponds to the app
+      // for which we have recorded app launch information.
+      if (this._appLaunchName !== origin) {
+        return;
+      }
 
-            // Events based on performance marks are for telemetry only, they are
-            // not displayed in the HUD front end.
-            target._logHistogram({name: eventName, value: time});
+      let time = epoch - this._appLaunchStartTime;
+      let eventName = 'app_startup_time_' + name;
+
+      // Events based on performance marks are for telemetry only, they are
+      // not displayed in the HUD front end.
+      target._logHistogram({name: eventName, value: time});
 
-            memoryWatcher.front(target).residentUnique().then(value => {
-              eventName = 'app-memory-' + name;
-              target._logHistogram({name: eventName, value: value});
-            }, err => {
-              console.error(err);
-            });
-          }
-        }
-      }
+      memoryWatcher.front(target).residentUnique().then(value => {
+        eventName = 'app_memory_' + name;
+        target._logHistogram({name: eventName, value: value});
+      }, err => {
+        console.error(err);
+      });
     });
   },
 
   untrackTarget(target) {
     let fronts = this._fronts;
     if (fronts.has(target)) {
       fronts.get(target).destroy();
       fronts.delete(target);
--- a/b2g/chrome/content/settings.js
+++ b/b2g/chrome/content/settings.js
@@ -568,16 +568,20 @@ let settingsToObserve = {
   'devtools.discovery.device': {
     prefName: 'dom.presentation.device.name',
     defaultValue: 'Firefox OS'
   },
   'devtools.eventlooplag.threshold': 100,
   'devtools.remote.wifi.visible': {
     resetToPref: true
   },
+  'devtools.telemetry.supported_performance_marks': {
+    resetToPref: true
+  },
+
   'dom.mozApps.use_reviewer_certs': false,
   'dom.mozApps.signed_apps_installable_from': 'https://marketplace.firefox.com',
   'dom.presentation.discovery.enabled': false,
   'dom.presentation.discoverable': false,
   'dom.serviceWorkers.interception.enabled': true,
   'dom.serviceWorkers.testing.enabled': false,
   'gfx.layerscope.enabled': false,
   'layers.draw-borders': false,
--- a/b2g/config/aries/sources.xml
+++ b/b2g/config/aries/sources.xml
@@ -10,25 +10,25 @@
   <!--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="8d83715f08b7849f16a0dfc88f78d5c3a89c0a54">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="e6994410dcc88bfead0e44620a065220b7f12290"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="d2e5c49440bf8410ae747b15c0dd11c54053ef3e"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9e2923fd6cab93cf88b4b9ada82225e44fe6635"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="f5d65f5b17d9766d7925aefd0486a1e526ae9bf0"/>
   <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="c6cace53426b5be7e56c0fd202118009689bc707"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="fb28def18ceb2516c460c4bd5825d2dc656c7818"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="95bb5b66b3ec5769c3de8d3f25d681787418e7d2"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="ebdad82e61c16772f6cd47e9f11936bf6ebe9aa0"/>
   <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" revision="8b880805d454664b3eed11d0f053cdeafa1ff06e"/>
   <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7" revision="a1e239a0bb5cd1d69680bf1075883aa9a7bf2429"/>
   <project groups="linux,x86" name="platform/prebuilts/gcc/linux-x86/x86/i686-linux-android-4.7" path="prebuilts/gcc/linux-x86/x86/i686-linux-android-4.7" revision="c7931763d41be602407ed9d71e2c0292c6597e00"/>
   <project groups="linux,x86" name="platform/prebuilts/python/linux-x86/2.7.5" path="prebuilts/python/linux-x86/2.7.5" revision="a32003194f707f66a2d8cdb913ed1869f1926c5d"/>
   <project name="device/common" path="device/common" revision="96d4d2006c4fcb2f19a3fa47ab10cb409faa017b"/>
--- a/b2g/config/dolphin/sources.xml
+++ b/b2g/config/dolphin/sources.xml
@@ -10,25 +10,25 @@
   <!--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="8d83715f08b7849f16a0dfc88f78d5c3a89c0a54">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="e6994410dcc88bfead0e44620a065220b7f12290"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="d2e5c49440bf8410ae747b15c0dd11c54053ef3e"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9e2923fd6cab93cf88b4b9ada82225e44fe6635"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="f5d65f5b17d9766d7925aefd0486a1e526ae9bf0"/>
   <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="c6cace53426b5be7e56c0fd202118009689bc707"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="fb28def18ceb2516c460c4bd5825d2dc656c7818"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="95bb5b66b3ec5769c3de8d3f25d681787418e7d2"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="ebdad82e61c16772f6cd47e9f11936bf6ebe9aa0"/>
   <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" revision="8b880805d454664b3eed11d0f053cdeafa1ff06e"/>
   <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7" revision="a1e239a0bb5cd1d69680bf1075883aa9a7bf2429"/>
   <project groups="linux,x86" name="platform/prebuilts/gcc/linux-x86/x86/i686-linux-android-4.7" path="prebuilts/gcc/linux-x86/x86/i686-linux-android-4.7" revision="c7931763d41be602407ed9d71e2c0292c6597e00"/>
   <project groups="linux,x86" name="platform/prebuilts/python/linux-x86/2.7.5" path="prebuilts/python/linux-x86/2.7.5" revision="83760d213fb3bec7b4117d266fcfbf6fe2ba14ab"/>
   <project name="device/common" path="device/common" revision="6a2995683de147791e516aae2ccb31fdfbe2ad30"/>
--- a/b2g/config/emulator-ics/sources.xml
+++ b/b2g/config/emulator-ics/sources.xml
@@ -14,17 +14,17 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="refs/tags/android-4.0.4_r2.1" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="1b0db93fb6b870b03467aff50d6419771ba0d88c">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="e6994410dcc88bfead0e44620a065220b7f12290"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="d2e5c49440bf8410ae747b15c0dd11c54053ef3e"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9e2923fd6cab93cf88b4b9ada82225e44fe6635"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="27eb2f04e149fc2c9976d881b1b5984bbe7ee089"/>
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="067c08fb3e5744b42b68d1f861245f7d507109bc"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="f5d65f5b17d9766d7925aefd0486a1e526ae9bf0"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="34ea6163f9f0e0122fb0bb03607eccdca31ced7a"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
--- a/b2g/config/emulator-jb/sources.xml
+++ b/b2g/config/emulator-jb/sources.xml
@@ -12,20 +12,20 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="660169a3d7e034a892359e39135e8c2785a6ad6f">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="e6994410dcc88bfead0e44620a065220b7f12290"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="d2e5c49440bf8410ae747b15c0dd11c54053ef3e"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9e2923fd6cab93cf88b4b9ada82225e44fe6635"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="f5d65f5b17d9766d7925aefd0486a1e526ae9bf0"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="c6cace53426b5be7e56c0fd202118009689bc707"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="fb28def18ceb2516c460c4bd5825d2dc656c7818"/>
   <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"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="9025e50b9d29b3cabbbb21e1dd94d0d13121a17e"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="b89fda71fcd0fa0cf969310e75be3ea33e048b44"/>
   <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" revision="2e7d5348f35575870b3c7e567a9a9f6d66f8d6c5"/>
--- a/b2g/config/emulator-kk/sources.xml
+++ b/b2g/config/emulator-kk/sources.xml
@@ -10,25 +10,25 @@
   <!--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="8d83715f08b7849f16a0dfc88f78d5c3a89c0a54">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="e6994410dcc88bfead0e44620a065220b7f12290"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="d2e5c49440bf8410ae747b15c0dd11c54053ef3e"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9e2923fd6cab93cf88b4b9ada82225e44fe6635"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="f5d65f5b17d9766d7925aefd0486a1e526ae9bf0"/>
   <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="c6cace53426b5be7e56c0fd202118009689bc707"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="fb28def18ceb2516c460c4bd5825d2dc656c7818"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="f92a936f2aa97526d4593386754bdbf02db07a12"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="6e47ff2790f5656b5b074407829ceecf3e6188c4"/>
   <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" revision="1950e4760fa14688b83cdbb5acaa1af9f82ef434"/>
   <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7" revision="ac6eb97a37035c09fb5ede0852f0881e9aadf9ad"/>
   <project groups="linux,x86" name="platform/prebuilts/gcc/linux-x86/x86/i686-linux-android-4.7" path="prebuilts/gcc/linux-x86/x86/i686-linux-android-4.7" revision="737f591c5f95477148d26602c7be56cbea0cdeb9"/>
   <project groups="linux,x86" name="platform/prebuilts/python/linux-x86/2.7.5" path="prebuilts/python/linux-x86/2.7.5" revision="51da9b1981be481b92a59a826d4d78dc73d0989a"/>
   <project name="device/common" path="device/common" revision="798a3664597e6041985feab9aef42e98d458bc3d"/>
--- a/b2g/config/emulator-l/sources.xml
+++ b/b2g/config/emulator-l/sources.xml
@@ -10,25 +10,25 @@
   <!--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="c9d4fe680662ee44a4bdea42ae00366f5df399cf">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="e6994410dcc88bfead0e44620a065220b7f12290"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="d2e5c49440bf8410ae747b15c0dd11c54053ef3e"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9e2923fd6cab93cf88b4b9ada82225e44fe6635"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="f5d65f5b17d9766d7925aefd0486a1e526ae9bf0"/>
   <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="c6cace53426b5be7e56c0fd202118009689bc707"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="fb28def18ceb2516c460c4bd5825d2dc656c7818"/>
   <!-- Stock Android things -->
   <project groups="pdk,linux" name="platform/prebuilts/clang/linux-x86/host/3.5" path="prebuilts/clang/linux-x86/host/3.5" revision="ffc05a232799fe8fcb3e47b7440b52b1fb4244c0"/>
   <project groups="pdk,linux,arm" name="platform/prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.8" path="prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.8" revision="337e0ef5e40f02a1ae59b90db0548976c70a7226"/>
   <project groups="pdk,linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.8" path="prebuilts/gcc/linux-x86/arm/arm-eabi-4.8" revision="8af5ff6f5dced9eb5a8127459df6c75d24342204"/>
   <project groups="pdk,linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.8" path="prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.8" revision="30915518fa7ea07166efedc191a4f40aef516fe7"/>
   <project groups="pdk,linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.11-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.11-4.6" revision="96eee58e3389fb05a835310d6a06a6ba4486097a"/>
   <project groups="pdk,linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.11-4.8" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.11-4.8" revision="7c8a46698171aa2e0be09edb43d15a6acf832770"/>
   <project groups="pdk,linux,x86" name="platform/prebuilts/gcc/linux-x86/x86/x86_64-linux-android-4.8" path="prebuilts/gcc/linux-x86/x86/x86_64-linux-android-4.8" revision="24b2038be8a636fd4a5d21f0abae1e466b07bcf7"/>
--- a/b2g/config/emulator/sources.xml
+++ b/b2g/config/emulator/sources.xml
@@ -14,17 +14,17 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="refs/tags/android-4.0.4_r2.1" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="1b0db93fb6b870b03467aff50d6419771ba0d88c">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="e6994410dcc88bfead0e44620a065220b7f12290"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="d2e5c49440bf8410ae747b15c0dd11c54053ef3e"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9e2923fd6cab93cf88b4b9ada82225e44fe6635"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="27eb2f04e149fc2c9976d881b1b5984bbe7ee089"/>
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="067c08fb3e5744b42b68d1f861245f7d507109bc"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="f5d65f5b17d9766d7925aefd0486a1e526ae9bf0"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="34ea6163f9f0e0122fb0bb03607eccdca31ced7a"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
--- a/b2g/config/flame-kk/sources.xml
+++ b/b2g/config/flame-kk/sources.xml
@@ -10,25 +10,25 @@
   <!--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="8d83715f08b7849f16a0dfc88f78d5c3a89c0a54">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="e6994410dcc88bfead0e44620a065220b7f12290"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="d2e5c49440bf8410ae747b15c0dd11c54053ef3e"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9e2923fd6cab93cf88b4b9ada82225e44fe6635"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="f5d65f5b17d9766d7925aefd0486a1e526ae9bf0"/>
   <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="c6cace53426b5be7e56c0fd202118009689bc707"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="fb28def18ceb2516c460c4bd5825d2dc656c7818"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="95bb5b66b3ec5769c3de8d3f25d681787418e7d2"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="ebdad82e61c16772f6cd47e9f11936bf6ebe9aa0"/>
   <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" revision="8b880805d454664b3eed11d0f053cdeafa1ff06e"/>
   <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7" revision="a1e239a0bb5cd1d69680bf1075883aa9a7bf2429"/>
   <project groups="linux,x86" name="platform/prebuilts/gcc/linux-x86/x86/i686-linux-android-4.7" path="prebuilts/gcc/linux-x86/x86/i686-linux-android-4.7" revision="c7931763d41be602407ed9d71e2c0292c6597e00"/>
   <project groups="linux,x86" name="platform/prebuilts/python/linux-x86/2.7.5" path="prebuilts/python/linux-x86/2.7.5" revision="a32003194f707f66a2d8cdb913ed1869f1926c5d"/>
   <project name="device/common" path="device/common" revision="96d4d2006c4fcb2f19a3fa47ab10cb409faa017b"/>
--- a/b2g/config/gaia.json
+++ b/b2g/config/gaia.json
@@ -1,9 +1,9 @@
 {
     "git": {
-        "git_revision": "e6994410dcc88bfead0e44620a065220b7f12290", 
+        "git_revision": "d2e5c49440bf8410ae747b15c0dd11c54053ef3e", 
         "remote": "https://git.mozilla.org/releases/gaia.git", 
         "branch": ""
     }, 
-    "revision": "0611acb452ed9c34d02ccdf24850677490b716d1", 
+    "revision": "4b08f8a2624bc83d1f839f79b4969671417c42d6", 
     "repo_path": "integration/gaia-central"
 }
--- a/b2g/config/nexus-4/sources.xml
+++ b/b2g/config/nexus-4/sources.xml
@@ -12,20 +12,20 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="660169a3d7e034a892359e39135e8c2785a6ad6f">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="e6994410dcc88bfead0e44620a065220b7f12290"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="d2e5c49440bf8410ae747b15c0dd11c54053ef3e"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9e2923fd6cab93cf88b4b9ada82225e44fe6635"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="f5d65f5b17d9766d7925aefd0486a1e526ae9bf0"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="c6cace53426b5be7e56c0fd202118009689bc707"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="fb28def18ceb2516c460c4bd5825d2dc656c7818"/>
   <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"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="9025e50b9d29b3cabbbb21e1dd94d0d13121a17e"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="b89fda71fcd0fa0cf969310e75be3ea33e048b44"/>
   <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" revision="2e7d5348f35575870b3c7e567a9a9f6d66f8d6c5"/>
--- a/b2g/config/nexus-5-l/sources.xml
+++ b/b2g/config/nexus-5-l/sources.xml
@@ -10,25 +10,25 @@
   <!--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="c9d4fe680662ee44a4bdea42ae00366f5df399cf">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="e6994410dcc88bfead0e44620a065220b7f12290"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="d2e5c49440bf8410ae747b15c0dd11c54053ef3e"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9e2923fd6cab93cf88b4b9ada82225e44fe6635"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="f5d65f5b17d9766d7925aefd0486a1e526ae9bf0"/>
   <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="c6cace53426b5be7e56c0fd202118009689bc707"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="fb28def18ceb2516c460c4bd5825d2dc656c7818"/>
   <!-- Stock Android things -->
   <project groups="pdk,linux" name="platform/prebuilts/clang/linux-x86/host/3.5" path="prebuilts/clang/linux-x86/host/3.5" revision="ffc05a232799fe8fcb3e47b7440b52b1fb4244c0"/>
   <project groups="pdk,linux,arm" name="platform/prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.8" path="prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.8" revision="337e0ef5e40f02a1ae59b90db0548976c70a7226"/>
   <project groups="pdk,linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.8" path="prebuilts/gcc/linux-x86/arm/arm-eabi-4.8" revision="8af5ff6f5dced9eb5a8127459df6c75d24342204"/>
   <project groups="pdk,linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.8" path="prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.8" revision="30915518fa7ea07166efedc191a4f40aef516fe7"/>
   <project groups="pdk,linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.11-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.11-4.6" revision="96eee58e3389fb05a835310d6a06a6ba4486097a"/>
   <project groups="pdk,linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.11-4.8" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.11-4.8" revision="7c8a46698171aa2e0be09edb43d15a6acf832770"/>
   <project groups="pdk,linux,x86" name="platform/prebuilts/gcc/linux-x86/x86/x86_64-linux-android-4.8" path="prebuilts/gcc/linux-x86/x86/x86_64-linux-android-4.8" revision="24b2038be8a636fd4a5d21f0abae1e466b07bcf7"/>
new file mode 100644
--- /dev/null
+++ b/build/autoconf/jemalloc.m4
@@ -0,0 +1,100 @@
+dnl This Source Code Form is subject to the terms of the Mozilla Public
+dnl License, v. 2.0. If a copy of the MPL was not distributed with this
+dnl file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+AC_DEFUN([MOZ_SUBCONFIGURE_JEMALLOC], [
+
+if test -z "$BUILDING_JS" -o -n "$JS_STANDALONE"; then
+
+  # Run jemalloc configure script
+
+  if test -z "$MOZ_NATIVE_JEMALLOC" -a "$MOZ_MEMORY" && test -n "$MOZ_JEMALLOC4" -o -n "$MOZ_REPLACE_MALLOC"; then
+    ac_configure_args="--build=$build --host=$target --enable-stats --with-jemalloc-prefix=je_ --disable-valgrind"
+    # We're using memalign for _aligned_malloc in memory/build/mozmemory_wrap.c
+    # on Windows, so just export memalign on all platforms.
+    ac_configure_args="$ac_configure_args ac_cv_func_memalign=yes"
+    if test -n "$MOZ_REPLACE_MALLOC"; then
+      # When using replace_malloc, we always want valloc exported from jemalloc.
+      ac_configure_args="$ac_configure_args ac_cv_func_valloc=yes"
+      if test "${OS_ARCH}" = Darwin; then
+        # We also need to enable pointer validation on Mac because jemalloc's
+        # zone allocator is not used.
+        ac_configure_args="$ac_configure_args --enable-ivsalloc"
+      fi
+    fi
+    if test -n "$MOZ_JEMALLOC4"; then
+      case "${OS_ARCH}" in
+        WINNT|Darwin)
+          # We want jemalloc functions to be kept hidden on both Mac and Windows
+          # See memory/build/mozmemory_wrap.h for details.
+          ac_configure_args="$ac_configure_args --without-export"
+          ;;
+      esac
+      if test "${OS_ARCH}" = WINNT; then
+        # Lazy lock initialization doesn't play well with lazy linking of
+        # mozglue.dll on Windows XP (leads to startup crash), so disable it.
+        ac_configure_args="$ac_configure_args --disable-lazy-lock"
+      fi
+    elif test "${OS_ARCH}" = Darwin; then
+      # When building as a replace-malloc lib, disabling the zone allocator
+      # forces to use pthread_atfork.
+      ac_configure_args="$ac_configure_args --disable-zone-allocator"
+    fi
+    _MANGLE="malloc posix_memalign aligned_alloc calloc realloc free memalign valloc malloc_usable_size"
+    JEMALLOC_WRAPPER=
+    if test -z "$MOZ_REPLACE_MALLOC"; then
+      case "$OS_ARCH" in
+        Linux|DragonFly|FreeBSD|NetBSD|OpenBSD)
+          MANGLE=$_MANGLE
+          ;;
+      esac
+    elif test -z "$MOZ_JEMALLOC4"; then
+      MANGLE=$_MANGLE
+      JEMALLOC_WRAPPER=replace_
+    fi
+    if test -n "$MANGLE"; then
+      MANGLED=
+      for mangle in ${MANGLE}; do
+        if test -n "$MANGLED"; then
+          MANGLED="$mangle:$JEMALLOC_WRAPPER$mangle,$MANGLED"
+        else
+          MANGLED="$mangle:$JEMALLOC_WRAPPER$mangle"
+        fi
+      done
+      ac_configure_args="$ac_configure_args --with-mangling=$MANGLED"
+    fi
+    unset CONFIG_FILES
+    if test -z "$MOZ_TLS"; then
+      ac_configure_args="$ac_configure_args --disable-tls"
+    fi
+    EXTRA_CFLAGS="$CFLAGS"
+    for var in AS CC CXX CPP LD AR RANLIB STRIP CPPFLAGS EXTRA_CFLAGS LDFLAGS; do
+      ac_configure_args="$ac_configure_args $var='`eval echo \\${${var}}`'"
+    done
+    # Force disable DSS support in jemalloc.
+    ac_configure_args="$ac_configure_args ac_cv_func_sbrk=false"
+
+    # Make Linux builds munmap freed chunks instead of recycling them.
+    ac_configure_args="$ac_configure_args --enable-munmap"
+
+    # Disable cache oblivious behavior that appears to have a performance
+    # impact on Firefox.
+    ac_configure_args="$ac_configure_args --disable-cache-oblivious"
+
+    if ! test -e memory/jemalloc; then
+      mkdir -p memory/jemalloc
+    fi
+
+    # jemalloc's configure runs git to determine the version. But when building
+    # from a gecko git clone, the git commands it uses is going to pick gecko's
+    # information, not jemalloc's, which is useless. So pretend we don't have git
+    # at all. That will make jemalloc's configure pick the in-tree VERSION file.
+    (PATH="$srcdir/memory/jemalloc/helper:$PATH";
+    AC_OUTPUT_SUBDIRS(memory/jemalloc/src)
+    ) || exit 1
+    ac_configure_args="$_SUBDIR_CONFIG_ARGS"
+  fi
+
+fi
+
+])
--- a/configure.in
+++ b/configure.in
@@ -9135,105 +9135,17 @@ fi
 AC_SUBST(JS_SHARED_LIBRARY)
 
 MOZ_CREATE_CONFIG_STATUS()
 
 # No need to run subconfigures when building with LIBXUL_SDK_DIR
 if test "$COMPILE_ENVIRONMENT" -a -z "$LIBXUL_SDK_DIR"; then
   MOZ_SUBCONFIGURE_ICU()
   MOZ_SUBCONFIGURE_FFI()
-fi
-
-# Run jemalloc configure script
-
-if test -z "$MOZ_NATIVE_JEMALLOC" -a "$MOZ_MEMORY" && test -n "$MOZ_JEMALLOC4" -o -n "$MOZ_REPLACE_MALLOC"; then
-  ac_configure_args="--build=$build --host=$target --enable-stats --with-jemalloc-prefix=je_ --disable-valgrind"
-  # We're using memalign for _aligned_malloc in memory/build/mozmemory_wrap.c
-  # on Windows, so just export memalign on all platforms.
-  ac_configure_args="$ac_configure_args ac_cv_func_memalign=yes"
-  if test -n "$MOZ_REPLACE_MALLOC"; then
-    # When using replace_malloc, we always want valloc exported from jemalloc.
-    ac_configure_args="$ac_configure_args ac_cv_func_valloc=yes"
-    if test "${OS_ARCH}" = Darwin; then
-      # We also need to enable pointer validation on Mac because jemalloc's
-      # zone allocator is not used.
-      ac_configure_args="$ac_configure_args --enable-ivsalloc"
-    fi
-  fi
-  if test -n "$MOZ_JEMALLOC4"; then
-    case "${OS_ARCH}" in
-      WINNT|Darwin)
-        # We want jemalloc functions to be kept hidden on both Mac and Windows
-        # See memory/build/mozmemory_wrap.h for details.
-        ac_configure_args="$ac_configure_args --without-export"
-        ;;
-    esac
-    if test "${OS_ARCH}" = WINNT; then
-      # Lazy lock initialization doesn't play well with lazy linking of
-      # mozglue.dll on Windows XP (leads to startup crash), so disable it.
-      ac_configure_args="$ac_configure_args --disable-lazy-lock"
-    fi
-  elif test "${OS_ARCH}" = Darwin; then
-    # When building as a replace-malloc lib, disabling the zone allocator
-    # forces to use pthread_atfork.
-    ac_configure_args="$ac_configure_args --disable-zone-allocator"
-  fi
-  _MANGLE="malloc posix_memalign aligned_alloc calloc realloc free memalign valloc malloc_usable_size"
-  JEMALLOC_WRAPPER=
-  if test -z "$MOZ_REPLACE_MALLOC"; then
-    case "$OS_ARCH" in
-      Linux|DragonFly|FreeBSD|NetBSD|OpenBSD)
-        MANGLE=$_MANGLE
-        ;;
-    esac
-  elif test -z "$MOZ_JEMALLOC4"; then
-    MANGLE=$_MANGLE
-    JEMALLOC_WRAPPER=replace_
-  fi
-  if test -n "$MANGLE"; then
-    MANGLED=
-    for mangle in ${MANGLE}; do
-      if test -n "$MANGLED"; then
-        MANGLED="$mangle:$JEMALLOC_WRAPPER$mangle,$MANGLED"
-      else
-        MANGLED="$mangle:$JEMALLOC_WRAPPER$mangle"
-      fi
-    done
-    ac_configure_args="$ac_configure_args --with-mangling=$MANGLED"
-  fi
-  unset CONFIG_FILES
-  if test -z "$MOZ_TLS"; then
-    ac_configure_args="$ac_configure_args --disable-tls"
-  fi
-  EXTRA_CFLAGS="$CFLAGS"
-  for var in AS CC CXX CPP LD AR RANLIB STRIP CPPFLAGS EXTRA_CFLAGS LDFLAGS; do
-    ac_configure_args="$ac_configure_args $var='`eval echo \\${${var}}`'"
-  done
-  # Force disable DSS support in jemalloc.
-  ac_configure_args="$ac_configure_args ac_cv_func_sbrk=false"
-
-  # Make Linux builds munmap freed chunks instead of recycling them.
-  ac_configure_args="$ac_configure_args --enable-munmap"
-
-  # Disable cache oblivious behavior that appears to have a performance
-  # impact on Firefox.
-  ac_configure_args="$ac_configure_args --disable-cache-oblivious"
-
-  if ! test -e memory/jemalloc; then
-    mkdir -p memory/jemalloc
-  fi
-
-  # jemalloc's configure runs git to determine the version. But when building
-  # from a gecko git clone, the git commands it uses is going to pick gecko's
-  # information, not jemalloc's, which is useless. So pretend we don't have git
-  # at all. That will make jemalloc's configure pick the in-tree VERSION file.
-  (PATH="$srcdir/memory/jemalloc/helper:$PATH";
-  AC_OUTPUT_SUBDIRS(memory/jemalloc/src)
-  ) || exit 1
-  ac_configure_args="$_SUBDIR_CONFIG_ARGS"
+  MOZ_SUBCONFIGURE_JEMALLOC()
 fi
 
 # Run freetype configure script
 
 if test "$MOZ_TREE_FREETYPE"; then
    export CFLAGS="$CFLAGS $MOZ_DEBUG_FLAGS -std=c99"
    export CPPFLAGS="$CPPFLAGS $MOZ_DEBUG_FLAGS"
    export CXXFLAGS="$CXXFLAGS $MOZ_DEBUG_FLAGS"
--- a/dom/animation/test/mochitest.ini
+++ b/dom/animation/test/mochitest.ini
@@ -62,8 +62,10 @@ support-files = css-transitions/file_ele
 support-files = css-transitions/file_timeline-get-animations.html
 [document-timeline/test_document-timeline.html]
 support-files = document-timeline/file_document-timeline.html
 [document-timeline/test_request_animation_frame.html]
 skip-if = buildapp == 'mulet'
 [mozilla/test_deferred_start.html]
 support-files = mozilla/file_deferred_start.html
 skip-if = (toolkit == 'gonk' && debug)
+[mozilla/test_hide_and_show.html]
+support-files = mozilla/file_hide_and_show.html
new file mode 100644
--- /dev/null
+++ b/dom/animation/test/mozilla/file_hide_and_show.html
@@ -0,0 +1,75 @@
+<!doctype html>
+<meta charset=utf-8>
+<script src="../testcommon.js"></script>
+<style>
+@keyframes move {
+  100% {
+    transform: translateX(100px);
+  }
+}
+
+</style>
+<body>
+<script>
+'use strict';
+
+test(function(t) {
+  var div = addDiv(t, { style: 'animation: move 100s infinite' });
+  assert_equals(div.getAnimations().length, 1,
+                'display:initial element has animations');
+
+  div.style.display = 'none';
+  assert_equals(div.getAnimations().length, 0,
+                'display:none element has no animations');
+}, 'Animation stops playing when the element style display is set to "none"');
+
+test(function(t) {
+  var parentElement = addDiv(t);
+  var div = addDiv(t, { style: 'animation: move 100s infinite' });
+  parentElement.appendChild(div);
+  assert_equals(div.getAnimations().length, 1,
+                'display:initial element has animations');
+
+  parentElement.style.display = 'none';
+  assert_equals(div.getAnimations().length, 0,
+                'Element in display:none subtree has no animations');
+}, 'Animation stops playing when its parent element style display is set ' +
+   'to "none"');
+
+test(function(t) {
+  var div = addDiv(t, { style: 'animation: move 100s infinite' });
+  assert_equals(div.getAnimations().length, 1,
+                'display:initial element has animations');
+
+  div.style.display = 'none';
+  assert_equals(div.getAnimations().length, 0,
+                'display:none element has no animations');
+
+  div.style.display = '';
+  assert_equals(div.getAnimations().length, 1,
+                'Element which is no longer display:none has animations ' +
+                'again');
+}, 'Animation starts playing when the element gets shown from ' +
+   '"display:none" state');
+
+test(function(t) {
+  var parentElement = addDiv(t);
+  var div = addDiv(t, { style: 'animation: move 100s infinite' });
+  parentElement.appendChild(div);
+  assert_equals(div.getAnimations().length, 1,
+                'display:initial element has animations');
+
+  parentElement.style.display = 'none';
+  assert_equals(div.getAnimations().length, 0,
+                'Element in display:none subtree has no animations');
+
+  parentElement.style.display = '';
+  assert_equals(div.getAnimations().length, 1,
+                'Element which is no longer in display:none subtree has ' +
+                'animations again');
+}, 'Animation starts playing when its parent element is shown from ' +
+   '"display:none" state');
+
+done();
+</script>
+</body>
new file mode 100644
--- /dev/null
+++ b/dom/animation/test/mozilla/test_hide_and_show.html
@@ -0,0 +1,14 @@
+<!doctype html>
+<meta charset=utf-8>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+'use strict';
+setup({explicit_done: true});
+SpecialPowers.pushPrefEnv(
+  { "set": [["dom.animations-api.core.enabled", true]]},
+  function() {
+    window.open("file_hide_and_show.html");
+  });
+</script>
new file mode 100644
--- /dev/null
+++ b/dom/apps/AndroidUtils.jsm
@@ -0,0 +1,123 @@
+/* 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/. */
+
+const { interfaces: Ci, utils: Cu } = Components;
+
+this.EXPORTED_SYMBOLS = ["AndroidUtils"];
+
+Cu.import("resource://gre/modules/AppsUtils.jsm");
+Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+
+XPCOMUtils.defineLazyModuleGetter(this, "Messaging",
+                                  "resource://gre/modules/Messaging.jsm");
+
+let appsRegistry = null;
+
+function debug() {
+  //dump("-*- AndroidUtils " + Array.slice(arguments) + "\n");
+}
+
+// Helper functions to manage Android native apps. We keep them in the
+// registry with a `kind` equals to "android-native" and we also store
+// the package name and class name in the registry.
+// Communication with the android side happens through json messages.
+
+this.AndroidUtils = {
+  init: function(aRegistry) {
+    appsRegistry = aRegistry;
+    Services.obs.addObserver(this, "Android:Apps:Installed", false);
+    Services.obs.addObserver(this, "Android:Apps:Uninstalled", false);
+  },
+
+  uninit: function() {
+    Services.obs.removeObserver(this, "Android:Apps:Installed");
+    Services.obs.removeObserver(this, "Android:Apps:Uninstalled");
+  },
+
+  getOriginAndManifestURL: function(aPackageName) {
+    let origin = "android://" + aPackageName.toLowerCase();
+    let manifestURL = origin + "/manifest.webapp";
+    return [origin, manifestURL];
+  },
+
+  getPackageAndClassFromManifestURL: function(aManifestURL) {
+    debug("getPackageAndClassFromManifestURL " + aManifestURL);
+    let app = appsRegistry.getAppByManifestURL(aManifestURL);
+    if (!app) {
+      debug("No app for " + aManifestURL);
+      return [];
+    }
+    return [app.android_packagename, app.android_classname];
+  },
+
+  buildAndroidAppData: function(aApp) {
+    // Use the package and class name to get a unique origin.
+    // We put the version with the normal case as part of the manifest url.
+    let [origin, manifestURL] =
+      this.getOriginAndManifestURL(aApp.packagename);
+    // TODO: Bug 1204557 to improve the icons support.
+    let manifest = {
+      name: aApp.name,
+      icons: { "96": aApp.icon }
+    }
+    debug("Origin is " + origin);
+    let appData = {
+      app: {
+        installOrigin: origin,
+        origin: origin,
+        manifest: manifest,
+        manifestURL: manifestURL,
+        manifestHash: AppsUtils.computeHash(JSON.stringify(manifest)),
+        appStatus: Ci.nsIPrincipal.APP_STATUS_INSTALLED,
+        removable: aApp.removable,
+        android_packagename: aApp.packagename,
+        android_classname: aApp.classname
+      },
+      isBrowser: false,
+      isPackage: false
+    };
+
+    return appData;
+  },
+
+  installAndroidApps: function() {
+    return Messaging.sendRequestForResult({ type: "Apps:GetList" }).then(
+      aApps => {
+        debug("Got " + aApps.apps.length + " android apps.");
+        let promises = [];
+        aApps.apps.forEach(app => {
+          debug("App is " + app.name + " removable? " + app.removable);
+          let p = new Promise((aResolveInstall, aRejectInstall) => {
+            let appData = this.buildAndroidAppData(app);
+            appsRegistry.confirmInstall(appData, null, aResolveInstall);
+          });
+          promises.push(p);
+        });
+
+        // Wait for all apps to be installed.
+        return Promise.all(promises);
+      }
+    ).then(appsRegistry._saveApps.bind(appsRegistry));
+  },
+
+  observe: function(aSubject, aTopic, aData) {
+    let data;
+    try {
+      data = JSON.parse(aData);
+    } catch(e) {
+      debug(e);
+      return;
+    }
+
+    if (aTopic == "Android:Apps:Installed") {
+      let appData = this.buildAndroidAppData(data);
+      appsRegistry.confirmInstall(appData);
+    } else if (aTopic == "Android:Apps:Uninstalled") {
+      let [origin, manifestURL] =
+        this.getOriginAndManifestURL(data.packagename);
+      appsRegistry.uninstall(manifestURL);
+    }
+  },
+}
--- a/dom/apps/AppsUtils.jsm
+++ b/dom/apps/AppsUtils.jsm
@@ -125,16 +125,20 @@ function _setAppProperties(aObj, aApp) {
   aObj.storeId = aApp.storeId || "";
   aObj.storeVersion = aApp.storeVersion || 0;
   aObj.role = aApp.role || "";
   aObj.redirects = aApp.redirects;
   aObj.widgetPages = aApp.widgetPages || [];
   aObj.kind = aApp.kind;
   aObj.enabled = aApp.enabled !== undefined ? aApp.enabled : true;
   aObj.sideloaded = aApp.sideloaded;
+#ifdef MOZ_B2GDROID
+  aObj.android_packagename = aApp.android_packagename;
+  aObj.android_classname = aApp.android_classname;
+#endif
 }
 
 this.AppsUtils = {
   // Clones a app, without the manifest.
   cloneAppObject: function(aApp) {
     let obj = {};
     _setAppProperties(obj, aApp);
     return obj;
--- a/dom/apps/Webapps.jsm
+++ b/dom/apps/Webapps.jsm
@@ -86,16 +86,19 @@ XPCOMUtils.defineLazyModuleGetter(this, 
                                   "resource://gre/modules/Langpacks.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "ImportExport",
                                   "resource://gre/modules/ImportExport.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "AppConstants",
                                   "resource://gre/modules/AppConstants.jsm");
 
+XPCOMUtils.defineLazyModuleGetter(this, "Messaging",
+                                  "resource://gre/modules/Messaging.jsm");
+
 #ifdef MOZ_WIDGET_GONK
 XPCOMUtils.defineLazyGetter(this, "libcutils", function() {
   Cu.import("resource://gre/modules/systemlibs.js");
   return libcutils;
 });
 #endif
 
 #ifdef MOZ_WIDGET_ANDROID
@@ -190,16 +193,17 @@ XPCOMUtils.defineLazyGetter(this, "permM
 // store even by error.
 const STORE_ID_PENDING_PREFIX = "#unknownID#";
 
 this.DOMApplicationRegistry = {
   // pseudo-constants for the different application kinds.
   get kPackaged()       "packaged",
   get kHosted()         "hosted",
   get kHostedAppcache() "hosted-appcache",
+  get kAndroid()        "android-native",
 
   // Path to the webapps.json file where we store the registry data.
   appsFile: null,
   webapps: { },
   allAppsLaunchable: false,
   _updateHandlers: [ ],
   _pendingUninstalls: {},
   _contentActions: new Map(),
@@ -254,16 +258,21 @@ this.DOMApplicationRegistry = {
 
     this.loadAndUpdateApps();
 
     Langpacks.registerRegistryFunctions(MessageBroadcaster.broadcastMessage.bind(MessageBroadcaster),
                                         this._appIdForManifestURL.bind(this),
                                         this.getFullAppByManifestURL.bind(this));
 
     MessageBroadcaster.init(this.getAppByManifestURL);
+
+    if (AppConstants.MOZ_B2GDROID) {
+      Cu.import("resource://gre/modules/AndroidUtils.jsm");
+      AndroidUtils.init(this);
+    }
   },
 
   // loads the current registry, that could be empty on first run.
   loadCurrentRegistry: function() {
     return AppsUtils.loadJSONAsync(this.appsFile).then((aData) => {
       if (!aData) {
         return;
       }
@@ -459,17 +468,19 @@ this.DOMApplicationRegistry = {
     // Create or Update the DataStore for this app
     let results = yield this._readManifests([{ id: aId }]);
     let app = this.webapps[aId];
     this.updateDataStore(app.localId, app.origin, app.manifestURL,
                          results[0].manifest, app.appStatus);
   }),
 
   appKind: function(aApp, aManifest) {
-    if (aApp.origin.startsWith("app://")) {
+    if (aApp.origin.startsWith("android://")) {
+      return this.kAndroid;
+    } if (aApp.origin.startsWith("app://")) {
       return this.kPackaged;
     } else {
       // Hosted apps, can be appcached or not.
       let kind = this.kHosted;
       if (aManifest.appcache_path) {
         kind = this.kHostedAppcache;
       }
       return kind;
@@ -517,17 +528,20 @@ this.DOMApplicationRegistry = {
           appcache_path: fullAppcachePath
         });
       }
     });
   },
 
   // Installs a 3rd party app.
   installPreinstalledApp: function installPreinstalledApp(aId) {
-#ifdef MOZ_WIDGET_GONK
+    if (!AppConstants.MOZ_B2GDROID && AppConstants.platform !== "gonk") {
+      return false;
+    }
+
     // In some cases, the app might be already installed under a different ID but
     // with the same manifestURL. In that case, the only content of the webapp will
     // be the id of the old version, which is the one we'll keep.
     let destId  = this.webapps[aId].oldId || aId;
     // We don't need the oldId anymore
     if (destId !== aId) {
       delete this.webapps[aId];
     }
@@ -620,17 +634,16 @@ this.DOMApplicationRegistry = {
       // If we are unable to extract the manifest, cleanup and remove this app.
       debug("Cleaning up: " + e);
       destDir.remove(true);
       delete this.webapps[destId];
     } finally {
       zipReader.close();
     }
     return isPreinstalled;
-#endif
   },
 
   // For hosted apps, uninstall an app served from http:// if we have
   // one installed from the same url with an https:// scheme.
   removeIfHttpsDuplicate: function(aId) {
 #ifdef MOZ_WIDGET_GONK
     let app = this.webapps[aId];
     if (!app || !app.origin.startsWith("http://")) {
@@ -787,29 +800,33 @@ this.DOMApplicationRegistry = {
             debug("Skipping app migration.");
           }
         }
 
         if (AppConstants.MOZ_B2GDROID || AppConstants.MOZ_B2G) {
           yield this.installSystemApps();
         }
 
+        if (AppConstants.MOZ_B2GDROID) {
+          yield AndroidUtils.installAndroidApps();
+        }
+
         // At first run, install preloaded apps and set up their permissions.
         for (let id in this.webapps) {
           let isPreinstalled = this.installPreinstalledApp(id);
           this.removeIfHttpsDuplicate(id);
           if (!this.webapps[id]) {
             continue;
           }
           this.updateOfflineCacheForApp(id);
           this.updatePermissionsForApp(id, isPreinstalled);
         }
         // Need to update the persisted list of apps since
         // installPreinstalledApp() removes the ones failing to install.
-        this._saveApps();
+        yield this._saveApps();
 
         Services.prefs.setBoolPref("dom.apps.reset-permissions", true);
       }
 
       // DataStores must be initialized at startup.
       for (let id in this.webapps) {
         yield this.updateDataStoreForApp(id);
       }
@@ -1190,16 +1207,19 @@ this.DOMApplicationRegistry = {
   observe: function(aSubject, aTopic, aData) {
     if (aTopic == "xpcom-shutdown") {
       this.messages.forEach((function(msgName) {
         ppmm.removeMessageListener(msgName, this);
       }).bind(this));
       Services.obs.removeObserver(this, "xpcom-shutdown");
       cpmm = null;
       ppmm = null;
+      if (AppConstants.MOZ_B2GDROID) {
+        AndroidUtils.uninit();
+      }
     } else if (aTopic == "memory-pressure") {
       // Clear the manifest cache on memory pressure.
       this._manifestCache = {};
     }
   },
 
   formatMessage: function(aData) {
     let msg = aData;
@@ -1299,32 +1319,32 @@ this.DOMApplicationRegistry = {
       return;
     }
 
     // For all the rest (asynchronous), we wait till the registry is ready
     // before processing the message.
     this.registryReady.then( () => {
       switch (aMessage.name) {
         case "Webapps:Install": {
-#ifdef MOZ_WIDGET_ANDROID
-          Services.obs.notifyObservers(mm, "webapps-runtime-install", JSON.stringify(msg));
-#else
-          this.doInstall(msg, mm);
-#endif
+          if (AppConstants.platform == "android" && !AppConstants.MOZ_B2GDROID) {
+            Services.obs.notifyObservers(mm, "webapps-runtime-install", JSON.stringify(msg));
+          } else {
+            this.doInstall(msg, mm);
+          }
           break;
         }
         case "Webapps:GetSelf":
           this.getSelf(msg, mm);
           break;
         case "Webapps:Uninstall":
-#ifdef MOZ_WIDGET_ANDROID
-          Services.obs.notifyObservers(mm, "webapps-runtime-uninstall", JSON.stringify(msg));
-#else
-          this.doUninstall(msg, mm);
-#endif
+          if (AppConstants.platform == "android" && !AppConstants.MOZ_B2GDROID) {
+            Services.obs.notifyObservers(mm, "webapps-runtime-uninstall", JSON.stringify(msg));
+          } else {
+            this.doUninstall(msg, mm);
+          }
           break;
         case "Webapps:Launch":
           this.doLaunch(msg, mm);
           break;
         case "Webapps:LocationChange":
           this.onLocationChange(msg.oid);
           break;
         case "Webapps:CheckInstalled":
@@ -1332,21 +1352,21 @@ this.DOMApplicationRegistry = {
           break;
         case "Webapps:GetInstalled":
           this.getInstalled(msg, mm);
           break;
         case "Webapps:GetNotInstalled":
           this.getNotInstalled(msg, mm);
           break;
         case "Webapps:InstallPackage": {
-#ifdef MOZ_WIDGET_ANDROID
-          Services.obs.notifyObservers(mm, "webapps-runtime-install-package", JSON.stringify(msg));
-#else
-          this.doInstallPackage(msg, mm);
-#endif
+          if (AppConstants.platform == "android" && !AppConstants.MOZ_B2GDROID) {
+            Services.obs.notifyObservers(mm, "webapps-runtime-install-package", JSON.stringify(msg));
+          } else {
+            this.doInstallPackage(msg, mm);
+          }
           break;
         }
         case "Webapps:Download":
           this.startDownload(msg.manifestURL);
           break;
         case "Webapps:CancelDownload":
           this.cancelDownload(msg.manifestURL);
           break;
@@ -1597,16 +1617,29 @@ this.DOMApplicationRegistry = {
 
     // Fire an error when trying to launch an app that is not
     // yet fully installed.
     if (app.installState == "pending") {
       aOnFailure("PENDING_APP_NOT_LAUNCHABLE");
       return;
     }
 
+    // Delegate native android apps launch.
+    if (this.kAndroid == app.kind) {
+      debug("Launching android app " + app.origin);
+      let [packageName, className] =
+        AndroidUtils.getPackageAndClassFromManifestURL(aManifestURL);
+      debug("  " + packageName + " " + className);
+      Messaging.sendRequest({ type: "Apps:Launch",
+                              packagename: packageName,
+                              classname: className });
+      aOnSuccess();
+      return;
+    }
+
     // We have to clone the app object as nsIDOMApplication objects are
     // stringified as an empty object. (see bug 830376)
     let appClone = AppsUtils.cloneAppObject(app);
     appClone.startPoint = aStartPoint;
     appClone.timestamp = aTimeStamp;
     Services.obs.notifyObservers(null, "webapps-launch", JSON.stringify(appClone));
     aOnSuccess();
   },
@@ -2041,18 +2074,19 @@ this.DOMApplicationRegistry = {
 
     // We may be able to remove this when Bug 839071 is fixed.
     if (app.downloading) {
       sendError("APP_IS_DOWNLOADING");
       return;
     }
 
     // If the app is packaged and its manifestURL has an app:// scheme,
-    // then we can't have an update.
-    if (app.kind == this.kPackaged && app.manifestURL.startsWith("app://")) {
+    // or if it's a native Android app then we can't have an update.
+    if (app.kind == this.kAndroid ||
+        (app.kind == this.kPackaged && app.manifestURL.startsWith("app://"))) {
       sendError("NOT_UPDATABLE");
       return;
     }
 
     // For non-removable hosted apps that lives in the core apps dir we
     // only check the appcache because we can't modify the manifest even
     // if it has changed.
     let onlyCheckAppCache = false;
@@ -2774,18 +2808,20 @@ this.DOMApplicationRegistry = {
         this.revertDownloadPackage(id, oldApp, newApp, false, ex);
       }
     }
   }),
 
   _setupApp: function(aData, aId) {
     let app = aData.app;
 
-    // app can be uninstalled
-    app.removable = true;
+    // app can be uninstalled by default.
+    if (app.removable === undefined) {
+      app.removable = true;
+    }
 
     if (aData.isPackage) {
       // Override the origin with the correct id.
       app.origin = "app://" + aId;
     }
 
     app.id = aId;
     app.installTime = Date.now();
@@ -2808,17 +2844,18 @@ this.DOMApplicationRegistry = {
       appObject.downloadSize = 0;
       appObject.readyToApplyDownload = false;
     } else if (appObject.kind == this.kPackaged) {
       appObject.installState = "pending";
       appObject.downloadAvailable = true;
       appObject.downloading = true;
       appObject.downloadSize = aLocaleManifest.size;
       appObject.readyToApplyDownload = false;
-    } else if (appObject.kind == this.kHosted) {
+    } else if (appObject.kind == this.kHosted ||
+               appObject.kind == this.kAndroid) {
       appObject.installState = "installed";
       appObject.downloadAvailable = false;
       appObject.downloading = false;
       appObject.readyToApplyDownload = false;
     } else {
       debug("Unknown app kind: " + appObject.kind);
       throw Error("Unknown app kind: " + appObject.kind);
     }
@@ -2864,18 +2901,16 @@ this.DOMApplicationRegistry = {
 
     app.csp = aManifest.csp || "";
 
     let aLocaleManifest = new ManifestHelper(aManifest, app.origin, app.manifestURL);
     this._saveWidgetsFullPath(aLocaleManifest, app);
 
     app.appStatus = AppsUtils.getAppManifestStatus(aManifest);
 
-    app.removable = true;
-
     // Reuse the app ID if the scheme is "app".
     let uri = Services.io.newURI(app.origin, null, null);
     if (uri.scheme == "app") {
       app.id = uri.host;
     } else {
       app.id = this.makeAppId();
     }
 
@@ -2955,16 +2990,17 @@ this.DOMApplicationRegistry = {
       new ManifestHelper(jsonManifest, app.origin, app.manifestURL);
 
     // Set the application kind.
     app.kind = this.appKind(app, manifest);
 
     let appObject = this._cloneApp(aData, app, manifest, jsonManifest, id, localId);
 
     this.webapps[id] = appObject;
+    this._manifestCache[id] = jsonManifest;
 
     // For package apps, the permissions are not in the mini-manifest, so
     // don't update the permissions yet.
     if (!aData.isPackage) {
       if (supportUseCurrentProfile()) {
         try {
           if (Services.prefs.getBoolPref("dom.apps.developer_mode")) {
             this.webapps[id].appStatus =
@@ -4059,22 +4095,34 @@ this.DOMApplicationRegistry = {
     // leaking the whole page associationed with the message manager.
     aMm = Cu.getWeakReference(aMm);
 
     let response = "Webapps:Uninstall:Return:OK";
 
     try {
       aData.app = yield this._getAppWithManifest(aData.manifestURL);
 
-      let prefName = "dom.mozApps.auto_confirm_uninstall";
-      if (Services.prefs.prefHasUserValue(prefName) &&
-          Services.prefs.getBoolPref(prefName)) {
-        yield this._uninstallApp(aData.app);
+      if (this.kAndroid == aData.app.kind) {
+        debug("Uninstalling android app " + aData.app.origin);
+        let [packageName, className] =
+          AndroidUtils.getPackageAndClassFromManifestURL(aData.manifestURL);
+        Messaging.sendRequest({ type: "Apps:Uninstall",
+                                packagename: packageName,
+                                classname: className });
+        // We have to wait for Android's uninstall before sending the
+        // uninstall event, so fake an error here.
+        response = "Webapps:Uninstall:Return:KO";
       } else {
-        yield this._promptForUninstall(aData);
+        let prefName = "dom.mozApps.auto_confirm_uninstall";
+        if (Services.prefs.prefHasUserValue(prefName) &&
+            Services.prefs.getBoolPref(prefName)) {
+          yield this._uninstallApp(aData.app);
+        } else {
+          yield this._promptForUninstall(aData);
+        }
       }
     } catch (error) {
       aData.error = error;
       response = "Webapps:Uninstall:Return:KO";
     }
 
     if ((aMm = aMm.get())) {
       aMm.sendAsyncMessage(response, this.formatMessage(aData));
--- a/dom/apps/moz.build
+++ b/dom/apps/moz.build
@@ -37,16 +37,21 @@ EXTRA_JS_MODULES += [
     'MessageBroadcaster.jsm',
     'OfflineCacheInstaller.jsm',
     'PermissionsInstaller.jsm',
     'PermissionsTable.jsm',
     'StoreTrustAnchor.jsm',
     'UserCustomizations.jsm',
 ]
 
+if CONFIG['MOZ_B2GDROID']:
+    EXTRA_JS_MODULES += [
+        'AndroidUtils.jsm',
+    ]
+
 EXTRA_PP_JS_MODULES += [
     'AppsUtils.jsm',
     'ImportExport.jsm',
     'InterAppCommService.jsm',
     'OperatorApps.jsm',
     'ScriptPreloader.jsm',
     'Webapps.jsm',
 ]
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -4774,65 +4774,16 @@ static bool SchemeIs(nsIURI* aURI, const
 {
   nsCOMPtr<nsIURI> baseURI = NS_GetInnermostURI(aURI);
   NS_ENSURE_TRUE(baseURI, false);
 
   bool isScheme = false;
   return NS_SUCCEEDED(baseURI->SchemeIs(aScheme, &isScheme)) && isScheme;
 }
 
-/* static */
-nsresult
-nsContentUtils::CheckSecurityBeforeLoad(nsIURI* aURIToLoad,
-                                        nsIPrincipal* aLoadingPrincipal,
-                                        uint32_t aCheckLoadFlags,
-                                        bool aAllowData,
-                                        uint32_t aContentPolicyType,
-                                        nsISupports* aContext,
-                                        const nsAFlatCString& aMimeGuess,
-                                        nsISupports* aExtra)
-{
-  NS_PRECONDITION(aLoadingPrincipal, "Must have a loading principal here");
-
-  if (aLoadingPrincipal == sSystemPrincipal) {
-    return NS_OK;
-  }
-  
-  // XXXbz do we want to fast-path skin stylesheets loading XBL here somehow?
-  // CheckLoadURIWithPrincipal
-  nsresult rv = sSecurityManager->
-    CheckLoadURIWithPrincipal(aLoadingPrincipal, aURIToLoad, aCheckLoadFlags);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  // Content Policy
-  int16_t shouldLoad = nsIContentPolicy::ACCEPT;
-  rv = NS_CheckContentLoadPolicy(aContentPolicyType,
-                                 aURIToLoad,
-                                 aLoadingPrincipal,
-                                 aContext,
-                                 aMimeGuess,
-                                 aExtra,
-                                 &shouldLoad,
-                                 GetContentPolicy(),
-                                 sSecurityManager);
-  NS_ENSURE_SUCCESS(rv, rv);
-  if (NS_CP_REJECTED(shouldLoad)) {
-    return NS_ERROR_CONTENT_BLOCKED;
-  }
-
-  // Same Origin
-  if ((aAllowData && SchemeIs(aURIToLoad, "data")) ||
-      ((aCheckLoadFlags & nsIScriptSecurityManager::ALLOW_CHROME) &&
-       SchemeIs(aURIToLoad, "chrome"))) {
-    return NS_OK;
-  }
-
-  return aLoadingPrincipal->CheckMayLoad(aURIToLoad, true, false);
-}
-
 bool
 nsContentUtils::IsSystemPrincipal(nsIPrincipal* aPrincipal)
 {
   MOZ_ASSERT(IsInitialized());
   return aPrincipal == sSystemPrincipal;
 }
 
 bool
--- a/dom/base/nsContentUtils.h
+++ b/dom/base/nsContentUtils.h
@@ -1362,48 +1362,16 @@ public:
   /*
    * Notify when the first XUL menu is opened and when the all XUL menus are
    * closed. At opening, aInstalling should be TRUE, otherwise, it should be
    * FALSE.
    */
   static void NotifyInstalledMenuKeyboardListener(bool aInstalling);
 
   /**
-   * Do security checks before loading a resource. Does the following checks:
-   *   nsIScriptSecurityManager::CheckLoadURIWithPrincipal
-   *   NS_CheckContentLoadPolicy
-   *   nsIScriptSecurityManager::CheckSameOriginURI
-   *
-   * You will still need to do at least SameOrigin checks before on redirects.
-   *
-   * @param aURIToLoad         URI that is getting loaded.
-   * @param aLoadingPrincipal  Principal of the resource that is initiating
-   *                           the load
-   * @param aCheckLoadFlags    Flags to be passed to
-   *                           nsIScriptSecurityManager::CheckLoadURIWithPrincipal
-   *                           NOTE: If this contains ALLOW_CHROME the
-   *                                 CheckSameOriginURI check will be skipped if
-   *                                 aURIToLoad is a chrome uri.
-   * @param aAllowData         Set to true to skip CheckSameOriginURI check when
-                               aURIToLoad is a data uri.
-   * @param aContentPolicyType Type     \
-   * @param aContext           Context   |- to be passed to
-   * @param aMimeGuess         Mimetype  |      NS_CheckContentLoadPolicy
-   * @param aExtra             Extra    /
-   */
-  static nsresult CheckSecurityBeforeLoad(nsIURI* aURIToLoad,
-                                          nsIPrincipal* aLoadingPrincipal,
-                                          uint32_t aCheckLoadFlags,
-                                          bool aAllowData,
-                                          uint32_t aContentPolicyType,
-                                          nsISupports* aContext,
-                                          const nsAFlatCString& aMimeGuess = EmptyCString(),
-                                          nsISupports* aExtra = nullptr);
-
-  /**
    * Returns true if aPrincipal is the system principal.
    */
   static bool IsSystemPrincipal(nsIPrincipal* aPrincipal);
 
   /**
    * Returns true if aPrincipal is an nsExpandedPrincipal.
    */
   static bool IsExpandedPrincipal(nsIPrincipal* aPrincipal);
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -9297,17 +9297,20 @@ nsDocument::OnPageHide(bool aPersisted,
     // move us around.
     mIsShowing = false;
   }
 
   if (mAnimationController) {
     mAnimationController->OnPageHide();
   }
 
-  if (aPersisted) {
+  // We do not stop the animations (bug 1024343)
+  // when the page is refreshing while being dragged out
+  nsDocShell* docShell = mDocumentContainer.get();
+  if (aPersisted && !(docShell && docShell->InFrameSwap())) {
     SetImagesNeedAnimating(false);
   }
 
   MozExitPointerLock();
 
   // Now send out a PageHide event.
   nsCOMPtr<EventTarget> target = aDispatchStartTarget;
   if (!target) {
--- a/dom/canvas/CanvasRenderingContext2D.cpp
+++ b/dom/canvas/CanvasRenderingContext2D.cpp
@@ -2473,33 +2473,55 @@ CanvasRenderingContext2D::UpdateFilter()
       gfxRect(0, 0, mWidth, mHeight),
       CurrentState().filterAdditionalImages);
 }
 
 //
 // rects
 //
 
+// bug 1074733
+// The canvas spec does not forbid rects with negative w or h, so given
+// corners (x, y), (x+w, y), (x+w, y+h), and (x, y+h) we must generate
+// the appropriate rect by flipping negative dimensions. This prevents
+// draw targets from receiving "empty" rects later on.
+static void
+NormalizeRect(double& aX, double& aY, double& aWidth, double& aHeight)
+{
+  if (aWidth < 0) {
+    aWidth = -aWidth;
+    aX -= aWidth;
+  }
+  if (aHeight < 0) {
+    aHeight = -aHeight;
+    aY -= aHeight;
+  }
+}
+
 void
 CanvasRenderingContext2D::ClearRect(double x, double y, double w,
                                     double h)
 {
+  NormalizeRect(x, y, w, h);
+
   EnsureTarget();
 
   mTarget->ClearRect(mgfx::Rect(x, y, w, h));
 
   RedrawUser(gfxRect(x, y, w, h));
 }
 
 void
 CanvasRenderingContext2D::FillRect(double x, double y, double w,
                                    double h)
 {
   const ContextState &state = CurrentState();
 
+  NormalizeRect(x, y, w, h);
+
   if (state.patternStyles[Style::FILL]) {
     CanvasPattern::RepeatMode repeat =
       state.patternStyles[Style::FILL]->mRepeat;
     // In the FillRect case repeat modes are easy to deal with.
     bool limitx = repeat == CanvasPattern::RepeatMode::NOREPEAT || repeat == CanvasPattern::RepeatMode::REPEATY;
     bool limity = repeat == CanvasPattern::RepeatMode::NOREPEAT || repeat == CanvasPattern::RepeatMode::REPEATX;
 
     IntSize patternSize =
@@ -2563,16 +2585,17 @@ CanvasRenderingContext2D::StrokeRect(dou
 {
   const ContextState &state = CurrentState();
 
   mgfx::Rect bounds;
 
   if (!w && !h) {
     return;
   }
+  NormalizeRect(x, y, w, h);
 
   EnsureTarget();
   if (!IsTargetValid()) {
     return;
   }
 
   if (NeedToCalculateBounds()) {
     bounds = mgfx::Rect(x - state.lineWidth / 2.0f, y - state.lineWidth / 2.0f,
@@ -4287,16 +4310,35 @@ CanvasRenderingContext2D::CachedSurfaceF
 
   return res;
 }
 
 //
 // image
 //
 
+static void
+ClipImageDimension(double& aSourceCoord, double& aSourceSize, int32_t aImageSize,
+                   double& aDestCoord, double& aDestSize)
+{
+  double scale = aDestSize / aSourceSize;
+  if (aSourceCoord < 0.0) {
+    double destEnd = aDestCoord + aDestSize;
+    aDestCoord -= aSourceCoord * scale;
+    aDestSize = destEnd - aDestCoord;
+    aSourceSize += aSourceCoord;
+    aSourceCoord = 0.0;
+  }
+  double delta = aImageSize - (aSourceCoord + aSourceSize);
+  if (delta < 0.0) {
+    aDestSize += delta * scale;
+    aSourceSize = aImageSize - aSourceCoord;
+  }
+}
+
 // drawImage(in HTMLImageElement image, in float dx, in float dy);
 //   -- render image from 0,0 at dx,dy top-left coords
 // drawImage(in HTMLImageElement image, in float dx, in float dy, in float sw, in float sh);
 //   -- render image from 0,0 at dx,dy top-left coords clipping it to sw,sh
 // drawImage(in HTMLImageElement image, in float sx, in float sy, in float sw, in float sh, in float dx, in float dy, in float dw, in float dh);
 //   -- render the region defined by (sx,sy,sw,wh) in image-local space into the region (dx,dy,dw,dh) on the canvas
 
 // If only dx and dy are passed in then optional_argc should be 0. If only
@@ -4313,16 +4355,21 @@ CanvasRenderingContext2D::DrawImage(cons
                                     ErrorResult& error)
 {
   if (mDrawObserver) {
     mDrawObserver->DidDrawCall(CanvasDrawObserver::DrawCallType::DrawImage);
   }
 
   MOZ_ASSERT(optional_argc == 0 || optional_argc == 2 || optional_argc == 6);
 
+  if (optional_argc == 6) {
+    NormalizeRect(sx, sy, sw, sh);
+    NormalizeRect(dx, dy, dw, dh);
+  }
+
   RefPtr<SourceSurface> srcSurf;
   gfx::IntSize imgSize;
 
   Element* element = nullptr;
 
   EnsureTarget();
   if (image.IsHTMLCanvasElement()) {
     HTMLCanvasElement* canvas = &image.GetAsHTMLCanvasElement();
@@ -4519,28 +4566,22 @@ CanvasRenderingContext2D::DrawImage(cons
     sh = (double) imgSize.height;
   }
 
   if (sw == 0.0 || sh == 0.0) {
     error.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
     return;
   }
 
-  if (dw == 0.0 || dh == 0.0) {
-    // not really failure, but nothing to do --
-    // and noone likes a divide-by-zero
-    return;
-  }
-
-  if (sx < 0.0 || sy < 0.0 ||
-      sw < 0.0 || sw > (double) imgSize.width ||
-      sh < 0.0 || sh > (double) imgSize.height ||
-      dw < 0.0 || dh < 0.0) {
-    // XXX - Unresolved spec issues here, for now return error.
-    error.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
+  ClipImageDimension(sx, sw, imgSize.width, dx, dw);
+  ClipImageDimension(sy, sh, imgSize.height, dy, dh);
+
+  if (sw <= 0.0 || sh <= 0.0 ||
+      dw <= 0.0 || dh <= 0.0) {
+    // source and/or destination are fully clipped, so nothing is painted
     return;
   }
 
   Filter filter;
 
   if (CurrentState().imageSmoothingEnabled)
     filter = mgfx::Filter::LINEAR;
   else
--- a/dom/canvas/test/test_canvas.html
+++ b/dom/canvas/test/test_canvas.html
@@ -3121,17 +3121,17 @@ isPixel(ctx, 48,48, 0,255,0,255, 2);
 isPixel(ctx, 51,1, 0,255,0,255, 2);
 isPixel(ctx, 51,48, 0,255,0,255, 2);
 isPixel(ctx, 25,25, 0,255,0,255, 2);
 isPixel(ctx, 75,25, 0,255,0,255, 2);
 
 } catch (e) {
     _thrown_outer = true;
 }
-todo(!_thrown_outer, 'should not throw exception');
+ok(!_thrown_outer, 'should not throw exception');
 
 
 }
 </script>
 <img src="image_ggrr-256x256.png" id="ggrr-256x256_1.png" class="resource">
 
 <!-- [[[ test_2d.drawImage.negativesource.html ]]] -->
 
@@ -3161,17 +3161,17 @@ isPixel(ctx, 48,48, 0,255,0,255, 2);
 isPixel(ctx, 51,1, 0,255,0,255, 2);
 isPixel(ctx, 51,48, 0,255,0,255, 2);
 isPixel(ctx, 25,25, 0,255,0,255, 2);
 isPixel(ctx, 75,25, 0,255,0,255, 2);
 
 } catch (e) {
     _thrown_outer = true;
 }
-todo(!_thrown_outer, 'should not throw exception');
+ok(!_thrown_outer, 'should not throw exception');
 
 
 }
 </script>
 <img src="image_ggrr-256x256.png" id="ggrr-256x256_2.png" class="resource">
 
 <!-- [[[ test_2d.drawImage.nonfinite.html ]]] -->
 
@@ -3546,72 +3546,16 @@ var _thrown = undefined; try {
   ctx.drawImage(null, 0, 0);
 } catch (e) { _thrown = e };
 
 ok(_thrown && _thrown.name == "TypeError", "should throw TypeError");
 
 }
 </script>
 
-<!-- [[[ test_2d.drawImage.outsidesource.html ]]] -->
-
-<p>Canvas test: 2d.drawImage.outsidesource</p>
-<canvas id="c122" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
-<script>
-
-
-
-function test_2d_drawImage_outsidesource() {
-
-var canvas = document.getElementById('c122');
-var ctx = canvas.getContext('2d');
-
-var _thrown_outer = false;
-try {
-
-ctx.drawImage(document.getElementById('green_7.png'), 10.5, 10.5, 89.5, 39.5, 0, 0, 100, 50);
-ctx.drawImage(document.getElementById('green_7.png'), 5.5, 5.5, -5.5, -5.5, 0, 0, 100, 50);
-ctx.drawImage(document.getElementById('green_7.png'), 100, 50, -5, -5, 0, 0, 100, 50);
-var _thrown = undefined; try {
-  ctx.drawImage(document.getElementById('red_11.png'), -0.001, 0, 100, 50, 0, 0, 100, 50);
-} catch (e) { _thrown = e }; ok(_thrown && _thrown.name == "IndexSizeError" && _thrown.code == DOMException.INDEX_SIZE_ERR, "should throw IndexSizeError");
-var _thrown = undefined; try {
-  ctx.drawImage(document.getElementById('red_11.png'), 0, -0.001, 100, 50, 0, 0, 100, 50);
-} catch (e) { _thrown = e }; ok(_thrown && _thrown.name == "IndexSizeError" && _thrown.code == DOMException.INDEX_SIZE_ERR, "should throw IndexSizeError");
-var _thrown = undefined; try {
-  ctx.drawImage(document.getElementById('red_11.png'), 0, 0, 100.001, 50, 0, 0, 100, 50);
-} catch (e) { _thrown = e }; ok(_thrown && _thrown.name == "IndexSizeError" && _thrown.code == DOMException.INDEX_SIZE_ERR, "should throw IndexSizeError");
-var _thrown = undefined; try {
-  ctx.drawImage(document.getElementById('red_11.png'), 0, 0, 100, 50.001, 0, 0, 100, 50);
-} catch (e) { _thrown = e }; ok(_thrown && _thrown.name == "IndexSizeError" && _thrown.code == DOMException.INDEX_SIZE_ERR, "should throw IndexSizeError");
-var _thrown = undefined; try {
-  ctx.drawImage(document.getElementById('red_11.png'), 50, 0, 50.001, 50, 0, 0, 100, 50);
-} catch (e) { _thrown = e }; todo(_thrown && _thrown.name == "IndexSizeError" && _thrown.code == DOMException.INDEX_SIZE_ERR, "should throw IndexSizeError");
-var _thrown = undefined; try {
-  ctx.drawImage(document.getElementById('red_11.png'), 0, 0, -5, 5, 0, 0, 100, 50);
-} catch (e) { _thrown = e }; ok(_thrown && _thrown.name == "IndexSizeError" && _thrown.code == DOMException.INDEX_SIZE_ERR, "should throw IndexSizeError");
-var _thrown = undefined; try {
-  ctx.drawImage(document.getElementById('red_11.png'), 0, 0, 5, -5, 0, 0, 100, 50);
-} catch (e) { _thrown = e }; ok(_thrown && _thrown.name == "IndexSizeError" && _thrown.code == DOMException.INDEX_SIZE_ERR, "should throw IndexSizeError");
-var _thrown = undefined; try {
-  ctx.drawImage(document.getElementById('red_11.png'), 110, 60, -20, -20, 0, 0, 100, 50);
-} catch (e) { _thrown = e }; ok(_thrown && _thrown.name == "IndexSizeError" && _thrown.code == DOMException.INDEX_SIZE_ERR, "should throw IndexSizeError");
-todo_isPixel(ctx, 50,25, 0,255,0,255, 2);
-
-} catch (e) {
-    _thrown_outer = true;
-}
-todo(!_thrown_outer, 'should not throw exception');
-
-
-}
-</script>
-<img src="image_green.png" id="green_7.png" class="resource">
-<img src="image_red.png" id="red_11.png" class="resource">
-
 <!-- [[[ test_2d.drawImage.path.html ]]] -->
 
 <p>Canvas test: 2d.drawImage.path</p>
 <canvas id="c123" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
 <script>
 
 
 function test_2d_drawImage_path() {
@@ -22123,21 +22067,16 @@ function runTests() {
   ok(false, "unexpected exception thrown in: test_2d_drawImage_nowrap");
  }
  try {
   test_2d_drawImage_null();
  } catch (e) {
   ok(false, "unexpected exception thrown in: test_2d_drawImage_null");
  }
  try {
-  test_2d_drawImage_outsidesource();
- } catch (e) {
-  ok(false, "unexpected exception thrown in: test_2d_drawImage_outsidesource");
- }
- try {
   test_2d_drawImage_path();
  } catch (e) {
   ok(false, "unexpected exception thrown in: test_2d_drawImage_path");
  }
  try {
   test_2d_drawImage_self_1();
  } catch (e) {
   ok(false, "unexpected exception thrown in: test_2d_drawImage_self_1");
--- a/dom/inputmethod/Keyboard.jsm
+++ b/dom/inputmethod/Keyboard.jsm
@@ -40,18 +40,20 @@ let Utils = {
   }
 };
 
 this.Keyboard = {
   _formMM: null,      // The current web page message manager.
   _keyboardMM: null,  // The keyboard app message manager.
   _keyboardID: -1,    // The keyboard app's ID number. -1 = invalid
   _nextKeyboardID: 0, // The ID number counter.
-  _systemMessageName: [
-    'SetValue', 'RemoveFocus', 'SetSelectedOption', 'SetSelectedOptions'
+  _supportsSwitchingTypes: [],
+  _systemMessageNames: [
+    'SetValue', 'RemoveFocus', 'SetSelectedOption', 'SetSelectedOptions',
+    'SetSupportsSwitchingTypes'
   ],
 
   _messageNames: [
     'RemoveFocus',
     'SetSelectionRange', 'ReplaceSurroundingText', 'ShowInputMethodPicker',
     'SwitchToNextInputMethod', 'HideInputMethod',
     'GetText', 'SendKey', 'GetContext',
     'SetComposition', 'EndComposition',
@@ -65,16 +67,22 @@ this.Keyboard = {
     return null;
   },
 
   set formMM(mm) {
     this._formMM = mm;
   },
 
   sendToForm: function(name, data) {
+    if (!this.formMM) {
+      dump("Keyboard.jsm: Attempt to send message " + name +
+        " to form but no message manager exists.\n");
+
+      return;
+    }
     try {
       this.formMM.sendAsyncMessage(name, data);
     } catch(e) { }
   },
 
   sendToKeyboard: function(name, data) {
     try {
       this._keyboardMM.sendAsyncMessage(name, data);
@@ -86,17 +94,17 @@ this.Keyboard = {
     Services.obs.addObserver(this, 'remote-browser-shown', false);
     Services.obs.addObserver(this, 'oop-frameloader-crashed', false);
     Services.obs.addObserver(this, 'message-manager-close', false);
 
     for (let name of this._messageNames) {
       ppmm.addMessageListener('Keyboard:' + name, this);
     }
 
-    for (let name of this._systemMessageName) {
+    for (let name of this._systemMessageNames) {
       ppmm.addMessageListener('System:' + name, this);
     }
 
     this.inputRegistryGlue = new InputRegistryGlue();
   },
 
   observe: function keyboardObserve(subject, topic, data) {
     let frameLoader = null;
@@ -105,17 +113,17 @@ this.Keyboard = {
     if (topic == 'message-manager-close') {
       mm = subject;
     } else {
       frameLoader = subject.QueryInterface(Ci.nsIFrameLoader);
       mm = frameLoader.messageManager;
     }
 
     if (topic == 'oop-frameloader-crashed' ||
-	topic == 'message-manager-close') {
+	      topic == 'message-manager-close') {
       if (this.formMM == mm) {
         // The application has been closed unexpectingly. Let's tell the
         // keyboard app that the focus has been lost.
         this.sendToKeyboard('Keyboard:Blur', {});
         // Notify system app to hide keyboard.
         SystemAppProxy.dispatchEvent({
           type: 'inputmethod-contextchange',
           inputType: 'blur'
@@ -147,38 +155,36 @@ this.Keyboard = {
     mm.addMessageListener('Forms:SetComposition:Result:OK', this);
     mm.addMessageListener('Forms:EndComposition:Result:OK', this);
   },
 
   receiveMessage: function keyboardReceiveMessage(msg) {
     // If we get a 'Keyboard:XXX'/'System:XXX' message, check that the sender
     // has the required permission.
     let mm;
-    let isKeyboardRegistration = msg.name == "Keyboard:Register" ||
-                                 msg.name == "Keyboard:Unregister";
-    if (msg.name.indexOf("Keyboard:") === 0 ||
-        msg.name.indexOf("System:") === 0) {
-      if (!this.formMM && !isKeyboardRegistration) {
+
+    // Assert the permission based on the prefix of the message.
+    let permName;
+    if (msg.name.startsWith("Keyboard:")) {
+      permName = "input";
+    } else if (msg.name.startsWith("System:")) {
+      permName = "input-manage";
+    }
+
+    // There is no permission to check (nor we need to get the mm)
+    // for Form: messages.
+    if (permName) {
+      mm = Utils.getMMFromMessage(msg);
+      if (!mm) {
+        dump("Keyboard.jsm: Message " + msg.name + " has no message manager.");
         return;
       }
-
-      mm = Utils.getMMFromMessage(msg);
-
-      // That should never happen.
-      if (!mm) {
-        dump("!! No message manager found for " + msg.name);
-        return;
-      }
-
-      let perm = (msg.name.indexOf("Keyboard:") === 0) ? "input"
-                                                       : "input-manage";
-
-      if (!isKeyboardRegistration && !Utils.checkPermissionForMM(mm, perm)) {
-        dump("Keyboard message " + msg.name +
-        " from a content process with no '" + perm + "' privileges.");
+      if (!Utils.checkPermissionForMM(mm, permName)) {
+        dump("Keyboard.jsm: Message " + msg.name +
+          " from a content process with no '" + permName + "' privileges.");
         return;
       }
     }
 
     // we don't process kb messages (other than register)
     // if they come from a kb that we're currently not regsitered for.
     // this decision is made with the kbID kept by us and kb app
     let kbID = null;
@@ -224,16 +230,19 @@ this.Keyboard = {
         this.removeFocus();
         break;
       case 'System:SetSelectedOption':
         this.setSelectedOption(msg);
         break;
       case 'System:SetSelectedOptions':
         this.setSelectedOption(msg);
         break;
+      case 'System:SetSupportsSwitchingTypes':
+        this.setSupportsSwitchingTypes(msg);
+        break;
       case 'Keyboard:SetSelectionRange':
         this.setSelectionRange(msg);
         break;
       case 'Keyboard:ReplaceSurroundingText':
         this.replaceSurroundingText(msg);
         break;
       case 'Keyboard:SwitchToNextInputMethod':
         this.switchToNextInputMethod();
@@ -336,16 +345,20 @@ this.Keyboard = {
     this.sendToForm('Forms:SetSelectionRange', msg.data);
   },
 
   setValue: function keyboardSetValue(msg) {
     this.sendToForm('Forms:Input:Value', msg.data);
   },
 
   removeFocus: function keyboardRemoveFocus() {
+    if (!this.formMM) {
+      return;
+    }
+
     this.sendToForm('Forms:Select:Blur', {});
   },
 
   replaceSurroundingText: function keyboardReplaceSurroundingText(msg) {
     this.sendToForm('Forms:ReplaceSurroundingText', msg.data);
   },
 
   showInputMethodPicker: function keyboardShowInputMethodPicker() {
@@ -364,42 +377,57 @@ this.Keyboard = {
     this.sendToForm('Forms:GetText', msg.data);
   },
 
   sendKey: function keyboardSendKey(msg) {
     this.sendToForm('Forms:Input:SendKey', msg.data);
   },
 
   getContext: function keyboardGetContext(msg) {
-    if (this._layouts) {
-      this.sendToKeyboard('Keyboard:LayoutsChange', this._layouts);
+    if (!this.formMM) {
+      return;
     }
 
+    this.sendToKeyboard('Keyboard:SupportsSwitchingTypesChange', {
+      types: this._supportsSwitchingTypes
+    });
+
     this.sendToForm('Forms:GetContext', msg.data);
   },
 
   setComposition: function keyboardSetComposition(msg) {
     this.sendToForm('Forms:SetComposition', msg.data);
   },
 
   endComposition: function keyboardEndComposition(msg) {
     this.sendToForm('Forms:EndComposition', msg.data);
   },
 
-  /**
-   * Get the number of keyboard layouts active from keyboard_manager
-   */
-  _layouts: null,
-  setLayouts: function keyboardSetLayoutCount(layouts) {
+  setSupportsSwitchingTypes: function setSupportsSwitchingTypes(msg) {
+    this._supportsSwitchingTypes = msg.data.types;
+    this.sendToKeyboard('Keyboard:SupportsSwitchingTypesChange', msg.data);
+  },
+  // XXX: To be removed with mozContentEvent support from shell.js
+  setLayouts: function keyboardSetLayouts(layouts) {
     // The input method plugins may not have loaded yet,
     // cache the layouts so on init we can respond immediately instead
     // of going back and forth between keyboard_manager
-    this._layouts = layouts;
+    var types = [];
 
-    this.sendToKeyboard('Keyboard:LayoutsChange', layouts);
+    Object.keys(layouts).forEach((type) => {
+      if (layouts[type] > 1) {
+        types.push(type);
+      }
+    });
+
+    this._supportsSwitchingTypes = types;
+
+    this.sendToKeyboard('Keyboard:SupportsSwitchingTypesChange', {
+      types: types
+    });
   }
 };
 
 function InputRegistryGlue() {
   this._messageId = 0;
   this._msgMap = new Map();
 
   ppmm.addMessageListener('InputRegistry:Add', this);
--- a/dom/inputmethod/MozKeyboard.js
+++ b/dom/inputmethod/MozKeyboard.js
@@ -131,17 +131,17 @@ let cpmmSendAsyncMessageWithKbID = funct
  * InputMethodManager
  * ==============================================
  */
 function MozInputMethodManager(win) {
   this._window = win;
 }
 
 MozInputMethodManager.prototype = {
-  _supportsSwitching: false,
+  supportsSwitchingForCurrentInputContext: false,
   _window: null,
 
   classID: Components.ID("{7e9d7280-ef86-11e2-b778-0800200c9a66}"),
 
   QueryInterface: XPCOMUtils.generateQI([]),
 
   showAll: function() {
     if (!WindowMap.isActive(this._window)) {
@@ -156,40 +156,46 @@ MozInputMethodManager.prototype = {
     }
     cpmmSendAsyncMessageWithKbID(this, 'Keyboard:SwitchToNextInputMethod', {});
   },
 
   supportsSwitching: function() {
     if (!WindowMap.isActive(this._window)) {
       return false;
     }
-    return this._supportsSwitching;
+    return this.supportsSwitchingForCurrentInputContext;
   },
 
   hide: function() {
     if (!WindowMap.isActive(this._window)) {
       return;
     }
     cpmmSendAsyncMessageWithKbID(this, 'Keyboard:RemoveFocus', {});
+  },
+
+  setSupportsSwitchingTypes: function(types) {
+    cpmm.sendAsyncMessage('System:SetSupportsSwitchingTypes', {
+      types: types
+    });
   }
 };
 
 /**
  * ==============================================
  * InputMethod
  * ==============================================
  */
 function MozInputMethod() { }
 
 MozInputMethod.prototype = {
   __proto__: DOMRequestIpcHelper.prototype,
 
   _inputcontext: null,
   _wrappedInputContext: null,
-  _layouts: {},
+  _supportsSwitchingTypes: [],
   _window: null,
 
   classID: Components.ID("{4607330d-e7d2-40a4-9eb8-43967eae0142}"),
 
   QueryInterface: XPCOMUtils.generateQI([
     Ci.nsIDOMGlobalPropertyInitializer,
     Ci.nsIObserver,
     Ci.nsISupportsWeakReference
@@ -203,30 +209,30 @@ MozInputMethod.prototype = {
                             .currentInnerWindowID;
 
     Services.obs.addObserver(this, "inner-window-destroyed", false);
 
     cpmm.addWeakMessageListener('Keyboard:Focus', this);
     cpmm.addWeakMessageListener('Keyboard:Blur', this);
     cpmm.addWeakMessageListener('Keyboard:SelectionChange', this);
     cpmm.addWeakMessageListener('Keyboard:GetContext:Result:OK', this);
-    cpmm.addWeakMessageListener('Keyboard:LayoutsChange', this);
+    cpmm.addWeakMessageListener('Keyboard:SupportsSwitchingTypesChange', this);
     cpmm.addWeakMessageListener('InputRegistry:Result:OK', this);
     cpmm.addWeakMessageListener('InputRegistry:Result:Error', this);
   },
 
   uninit: function mozInputMethodUninit() {
     this._window = null;
     this._mgmt = null;
 
     cpmm.removeWeakMessageListener('Keyboard:Focus', this);
     cpmm.removeWeakMessageListener('Keyboard:Blur', this);
     cpmm.removeWeakMessageListener('Keyboard:SelectionChange', this);
     cpmm.removeWeakMessageListener('Keyboard:GetContext:Result:OK', this);
-    cpmm.removeWeakMessageListener('Keyboard:LayoutsChange', this);
+    cpmm.removeWeakMessageListener('Keyboard:SupportsSwitchingTypesChange', this);
     cpmm.removeWeakMessageListener('InputRegistry:Result:OK', this);
     cpmm.removeWeakMessageListener('InputRegistry:Result:Error', this);
     this.setActive(false);
   },
 
   receiveMessage: function mozInputMethodReceiveMsg(msg) {
     if (!msg.name.startsWith('InputRegistry') &&
         !WindowMap.isActive(this._window)) {
@@ -248,18 +254,18 @@ MozInputMethod.prototype = {
       case 'Keyboard:SelectionChange':
         if (this.inputcontext) {
           this._inputcontext.updateSelectionContext(data, false);
         }
         break;
       case 'Keyboard:GetContext:Result:OK':
         this.setInputContext(data);
         break;
-      case 'Keyboard:LayoutsChange':
-        this._layouts = data;
+      case 'Keyboard:SupportsSwitchingTypesChange':
+        this._supportsSwitchingTypes = data.types;
         break;
 
       case 'InputRegistry:Result:OK':
         resolver.resolve();
 
         break;
 
       case 'InputRegistry:Result:Error':
@@ -294,23 +300,22 @@ MozInputMethod.prototype = {
     return this.__DOM_IMPL__.getEventHandler("oninputcontextchange");
   },
 
   setInputContext: function mozKeyboardContextChange(data) {
     if (this._inputcontext) {
       this._inputcontext.destroy();
       this._inputcontext = null;
       this._wrappedInputContext = null;
-      this._mgmt._supportsSwitching = false;
+      this._mgmt.supportsSwitchingForCurrentInputContext = false;
     }
 
     if (data) {
-      this._mgmt._supportsSwitching = this._layouts[data.inputType] ?
-        this._layouts[data.inputType] > 1 :
-        false;
+      this._mgmt.supportsSwitchingForCurrentInputContext =
+        (this._supportsSwitchingTypes.indexOf(data.inputType) !== -1);
 
       this._inputcontext = new MozInputContext(data);
       this._inputcontext.init(this._window);
       // inputcontext will be exposed as a WebIDL object. Create its
       // content-side object explicitly to avoid Bug 1001325.
       this._wrappedInputContext =
         this._window.MozInputContext._create(this._window, this._inputcontext);
     }
--- a/dom/inputmethod/mochitest/mochitest.ini
+++ b/dom/inputmethod/mochitest/mochitest.ini
@@ -16,14 +16,15 @@ support-files =
 [test_bug953044.html]
 [test_bug960946.html]
 [test_bug978918.html]
 [test_bug1026997.html]
 [test_bug1043828.html]
 [test_bug1059163.html]
 [test_bug1066515.html]
 [test_bug1175399.html]
+[test_bug1137557.html]
 [test_sendkey_cancel.html]
+[test_setSupportsSwitching.html]
 [test_sync_edit.html]
 [test_two_inputs.html]
 [test_two_selects.html]
 [test_unload.html]
-[test_bug1137557.html]
new file mode 100644
--- /dev/null
+++ b/dom/inputmethod/mochitest/test_setSupportsSwitching.html
@@ -0,0 +1,134 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1197682
+-->
+<head>
+  <title>Test inputcontext#inputType and MozInputMethodManager#supportsSwitching()</title>
+  <script type="application/javascript;version=1.7" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="application/javascript;version=1.7" src="inputmethod_common.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1197682">Mozilla Bug 1197682</a>
+<p id="display"></p>
+<pre id="test">
+<script class="testbody" type="application/javascript;version=1.7">
+
+inputmethod_setup(function() {
+  runTest();
+});
+
+let appFrameScript = function appFrameScript() {
+  let input = content.document.body.firstElementChild;
+
+  let i = 1;
+
+  input.focus();
+
+  addMessageListener('test:next', function() {
+    i++;
+    switch (i) {
+      case 2:
+        content.document.body.children[1].focus();
+        i++; // keep the same count with the parent frame.
+
+        break;
+
+      case 4:
+        content.document.body.lastElementChild.focus();
+        i++; // keep the same count with the parent frame.
+
+        break;
+
+      case 6:
+        content.document.body.lastElementChild.blur();
+
+        break;
+    }
+  });
+};
+
+function runTest() {
+  let im = navigator.mozInputMethod;
+
+  let i = 0;
+  im.oninputcontextchange = function(evt) {
+    var inputcontext = navigator.mozInputMethod.inputcontext;
+
+    i++;
+    switch (i) {
+      case 1:
+        ok(!!inputcontext, '1) Receving the input context');
+        is(inputcontext.inputType, 'text', '1) input type');
+        is(im.mgmt.supportsSwitching(), true, '1) supports switching');
+
+        mm.sendAsyncMessage('test:next');
+        break;
+
+      case 2:
+        is(inputcontext, null, '2) Receving null inputcontext');
+
+        break;
+
+      case 3:
+        ok(!!inputcontext, '3) Receving the input context');
+        is(inputcontext.inputType, 'number', '3) input type');
+        is(im.mgmt.supportsSwitching(), false, '3) supports switching');
+
+        mm.sendAsyncMessage('test:next');
+        break;
+
+      case 4:
+        is(inputcontext, null, '4) Receving null inputcontext');
+
+        break;
+
+      case 5:
+        ok(!!inputcontext, '5) Receving the input context');
+        is(inputcontext.inputType, 'password', '5) input type');
+        is(im.mgmt.supportsSwitching(), true, '5) supports switching');
+
+        mm.sendAsyncMessage('test:next');
+        break;
+
+      case 6:
+        is(inputcontext, null, '6) Receving null inputcontext');
+        is(im.mgmt.supportsSwitching(), false, '6) supports switching');
+
+        inputmethod_cleanup();
+        break;
+
+      default:
+        ok(false, 'Receving extra inputcontextchange calls');
+        inputmethod_cleanup();
+
+        break;
+    }
+  };
+
+  // Set current page as an input method.
+  SpecialPowers.wrap(im).setActive(true);
+  // Set text and password inputs as supports switching (and not supported for number type)
+  im.mgmt.setSupportsSwitchingTypes(['text', 'password']);
+
+  let iframe = document.createElement('iframe');
+  iframe.src = 'data:text/html,<html><body>' +
+    '<input type="text">' +
+    '<input type="number">' +
+    '<input type="password">' +
+    '</body></html>';
+  iframe.setAttribute('mozbrowser', true);
+  document.body.appendChild(iframe);
+
+  let mm = SpecialPowers.getBrowserFrameMessageManager(iframe);
+
+  iframe.addEventListener('mozbrowserloadend', function() {
+    mm.loadFrameScript('data:,(' + encodeURIComponent(appFrameScript.toString()) + ')();', false);
+  });
+}
+
+</script>
+</pre>
+</body>
+</html>
--- a/dom/media/MediaDecoder.cpp
+++ b/dom/media/MediaDecoder.cpp
@@ -344,18 +344,16 @@ bool MediaDecoder::IsInfinite()
 {
   MOZ_ASSERT(NS_IsMainThread());
   return mInfiniteStream;
 }
 
 MediaDecoder::MediaDecoder() :
   mWatchManager(this, AbstractThread::MainThread()),
   mDormantSupported(false),
-  mDecoderPosition(0),
-  mPlaybackPosition(0),
   mLogicalPosition(0.0),
   mDuration(std::numeric_limits<double>::quiet_NaN()),
   mMediaSeekable(true),
   mReentrantMonitor("media.decoder"),
   mIgnoreProgressData(false),
   mInfiniteStream(false),
   mOwner(nullptr),
   mPlaybackStatistics(new MediaChannelStatistics()),
@@ -379,16 +377,18 @@ MediaDecoder::MediaDecoder() :
             "MediaDecoder::mBuffered (Mirror)"),
   mNextFrameStatus(AbstractThread::MainThread(),
                    MediaDecoderOwner::NEXT_FRAME_UNINITIALIZED,
                    "MediaDecoder::mNextFrameStatus (Mirror)"),
   mCurrentPosition(AbstractThread::MainThread(), 0,
                    "MediaDecoder::mCurrentPosition (Mirror)"),
   mStateMachineDuration(AbstractThread::MainThread(), NullableTimeUnit(),
                         "MediaDecoder::mStateMachineDuration (Mirror)"),
+  mPlaybackPosition(AbstractThread::MainThread(), 0,
+                    "MediaDecoder::mPlaybackPosition (Mirror)"),
   mVolume(AbstractThread::MainThread(), 0.0,
           "MediaDecoder::mVolume (Canonical)"),
   mPlaybackRate(AbstractThread::MainThread(), 1.0,
                 "MediaDecoder::mPlaybackRate (Canonical)"),
   mPreservesPitch(AbstractThread::MainThread(), true,
                   "MediaDecoder::mPreservesPitch (Canonical)"),
   mEstimatedDuration(AbstractThread::MainThread(), NullableTimeUnit(),
                      "MediaDecoder::mEstimatedDuration (Canonical)"),
@@ -396,17 +396,23 @@ MediaDecoder::MediaDecoder() :
                     "MediaDecoder::mExplicitDuration (Canonical)"),
   mPlayState(AbstractThread::MainThread(), PLAY_STATE_LOADING,
              "MediaDecoder::mPlayState (Canonical)"),
   mNextState(AbstractThread::MainThread(), PLAY_STATE_PAUSED,
              "MediaDecoder::mNextState (Canonical)"),
   mLogicallySeeking(AbstractThread::MainThread(), false,
                     "MediaDecoder::mLogicallySeeking (Canonical)"),
   mSameOriginMedia(AbstractThread::MainThread(), false,
-                   "MediaDecoder::mSameOriginMedia (Canonical)")
+                   "MediaDecoder::mSameOriginMedia (Canonical)"),
+  mPlaybackBytesPerSecond(AbstractThread::MainThread(), 0.0,
+                          "MediaDecoder::mPlaybackBytesPerSecond (Canonical)"),
+  mPlaybackRateReliable(AbstractThread::MainThread(), true,
+                        "MediaDecoder::mPlaybackRateReliable (Canonical)"),
+  mDecoderPosition(AbstractThread::MainThread(), 0,
+                   "MediaDecoder::mDecoderPosition (Canonical)")
 {
   MOZ_COUNT_CTOR(MediaDecoder);
   MOZ_ASSERT(NS_IsMainThread());
   MediaMemoryTracker::AddMediaDecoder(this);
 
   mAudioChannel = AudioChannelService::GetDefaultAudioChannel();
 
   //
@@ -811,73 +817,69 @@ void MediaDecoder::PlaybackEnded()
   if (IsInfinite()) {
     SetInfinite(false);
   }
 }
 
 MediaStatistics
 MediaDecoder::GetStatistics()
 {
-  MediaStatistics result;
-
+  MOZ_ASSERT(NS_IsMainThread());
   ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
-  if (mResource) {
-    result.mDownloadRate =
-      mResource->GetDownloadRate(&result.mDownloadRateReliable);
-    result.mDownloadPosition =
-      mResource->GetCachedDataEnd(mDecoderPosition);
-    result.mTotalBytes = mResource->GetLength();
-    result.mPlaybackRate = ComputePlaybackRate(&result.mPlaybackRateReliable);
-    result.mDecoderPosition = mDecoderPosition;
-    result.mPlaybackPosition = mPlaybackPosition;
-  }
-  else {
-    result.mDownloadRate = 0;
-    result.mDownloadRateReliable = true;
-    result.mPlaybackRate = 0;
-    result.mPlaybackRateReliable = true;
-    result.mDecoderPosition = 0;
-    result.mPlaybackPosition = 0;
-    result.mDownloadPosition = 0;
-    result.mTotalBytes = 0;
-  }
+  MOZ_ASSERT(mResource);
 
+  MediaStatistics result;
+  result.mDownloadRate = mResource->GetDownloadRate(&result.mDownloadRateReliable);
+  result.mDownloadPosition = mResource->GetCachedDataEnd(mDecoderPosition);
+  result.mTotalBytes = mResource->GetLength();
+  result.mPlaybackRate = mPlaybackBytesPerSecond;
+  result.mPlaybackRateReliable = mPlaybackRateReliable;
+  result.mDecoderPosition = mDecoderPosition;
+  result.mPlaybackPosition = mPlaybackPosition;
   return result;
 }
 
-double MediaDecoder::ComputePlaybackRate(bool* aReliable)
+void
+MediaDecoder::ComputePlaybackRate()
 {
-  GetReentrantMonitor().AssertCurrentThreadIn();
-  MOZ_ASSERT(NS_IsMainThread() || OnStateMachineTaskQueue() || OnDecodeTaskQueue());
+  MOZ_ASSERT(NS_IsMainThread());
+  ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
+  MOZ_ASSERT(mResource);
 
-  int64_t length = mResource ? mResource->GetLength() : -1;
+  int64_t length = mResource->GetLength();
   if (!IsNaN(mDuration) && !mozilla::IsInfinite<double>(mDuration) && length >= 0) {
-    *aReliable = true;
-    return length / mDuration;
+    mPlaybackRateReliable = true;
+    mPlaybackBytesPerSecond = length / mDuration;
+    return;
   }
-  return mPlaybackStatistics->GetRateAtLastStop(aReliable);
+
+  bool reliable = false;
+  mPlaybackBytesPerSecond = mPlaybackStatistics->GetRateAtLastStop(&reliable);
+  mPlaybackRateReliable = reliable;
 }
 
-void MediaDecoder::UpdatePlaybackRate()
+void
+MediaDecoder::UpdatePlaybackRate()
 {
   MOZ_ASSERT(NS_IsMainThread());
   GetReentrantMonitor().AssertCurrentThreadIn();
-  if (!mResource)
-    return;
-  bool reliable;
-  uint32_t rate = uint32_t(ComputePlaybackRate(&reliable));
-  if (reliable) {
+  MOZ_ASSERT(mResource);
+
+  ComputePlaybackRate();
+  uint32_t rate = mPlaybackBytesPerSecond;
+
+  if (mPlaybackRateReliable) {
     // Avoid passing a zero rate
     rate = std::max(rate, 1u);
-  }
-  else {
+  } else {
     // Set a minimum rate of 10,000 bytes per second ... sometimes we just
     // don't have good data
     rate = std::max(rate, 10000u);
   }
+
   mResource->SetPlaybackRate(rate);
 }
 
 void MediaDecoder::NotifySuspendedStatusChanged()
 {
   MOZ_ASSERT(NS_IsMainThread());
   if (mResource && mOwner) {
     bool suspended = mResource->IsSuspendedByCache();
@@ -1177,22 +1179,16 @@ void MediaDecoder::Resume(bool aForceBuf
 void MediaDecoder::SetLoadInBackground(bool aLoadInBackground)
 {
   MOZ_ASSERT(NS_IsMainThread());
   if (mResource) {
     mResource->SetLoadInBackground(aLoadInBackground);
   }
 }
 
-void MediaDecoder::UpdatePlaybackOffset(int64_t aOffset)
-{
-  GetReentrantMonitor().AssertCurrentThreadIn();
-  mPlaybackPosition = aOffset;
-}
-
 bool MediaDecoder::OnStateMachineTaskQueue() const
 {
   return mDecoderStateMachine->OnTaskQueue();
 }
 
 void MediaDecoder::SetPlaybackRate(double aPlaybackRate)
 {
   MOZ_ASSERT(NS_IsMainThread());
@@ -1230,22 +1226,24 @@ MediaDecoder::SetStateMachine(MediaDecod
   mDecoderStateMachine = aStateMachine;
 
   if (mDecoderStateMachine) {
     mStateMachineDuration.Connect(mDecoderStateMachine->CanonicalDuration());
     mBuffered.Connect(mDecoderStateMachine->CanonicalBuffered());
     mStateMachineIsShutdown.Connect(mDecoderStateMachine->CanonicalIsShutdown());
     mNextFrameStatus.Connect(mDecoderStateMachine->CanonicalNextFrameStatus());
     mCurrentPosition.Connect(mDecoderStateMachine->CanonicalCurrentPosition());
+    mPlaybackPosition.Connect(mDecoderStateMachine->CanonicalPlaybackOffset());
   } else {
     mStateMachineDuration.DisconnectIfConnected();
     mBuffered.DisconnectIfConnected();
     mStateMachineIsShutdown.DisconnectIfConnected();
     mNextFrameStatus.DisconnectIfConnected();
     mCurrentPosition.DisconnectIfConnected();
+    mPlaybackPosition.DisconnectIfConnected();
   }
 }
 
 ReentrantMonitor& MediaDecoder::GetReentrantMonitor() {
   return mReentrantMonitor;
 }
 
 ImageContainer* MediaDecoder::GetImageContainer()
--- a/dom/media/MediaDecoder.h
+++ b/dom/media/MediaDecoder.h
@@ -563,23 +563,25 @@ public:
       NS_NewRunnableFunction([self] () { self->mPlaybackStatistics->Start(); });
     AbstractThread::MainThread()->Dispatch(r.forget());
   }
 
   // Used to estimate rates of data passing through the decoder's channel.
   // Records activity stopping on the channel.
   void DispatchPlaybackStopped() {
     nsRefPtr<MediaDecoder> self = this;
-    nsCOMPtr<nsIRunnable> r =
-      NS_NewRunnableFunction([self] () { self->mPlaybackStatistics->Stop(); });
+    nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction([self] () {
+      self->mPlaybackStatistics->Stop();
+      self->ComputePlaybackRate();
+    });
     AbstractThread::MainThread()->Dispatch(r.forget());
   }
 
   // The actual playback rate computation. The monitor must be held.
-  virtual double ComputePlaybackRate(bool* aReliable);
+  void ComputePlaybackRate();
 
   // Returns true if we can play the entire media through without stopping
   // to buffer, given the current download and playback rates.
   bool CanPlayThrough();
 
   void SetAudioChannel(dom::AudioChannel aChannel) { mAudioChannel = aChannel; }
   dom::AudioChannel GetAudioChannel() { return mAudioChannel; }
 
@@ -647,20 +649,16 @@ public:
     MOZ_ASSERT(NS_IsMainThread());
     UpdateLogicalPosition(MediaDecoderEventVisibility::Observable);
   }
 
   // Find the end of the cached data starting at the current decoder
   // position.
   int64_t GetDownloadPosition();
 
-  // Updates the approximate byte offset which playback has reached. This is
-  // used to calculate the readyState transitions.
-  void UpdatePlaybackOffset(int64_t aOffset);
-
   // Provide access to the state machine object
   MediaDecoderStateMachine* GetStateMachine() const;
 
   // Drop reference to state machine.  Only called during shutdown dance.
   virtual void BreakCycles();
 
   // Notifies the element that decoding has failed.
   virtual void DecodeError();
@@ -874,27 +872,16 @@ protected:
 
   /******
    * The following members should be accessed with the decoder lock held.
    ******/
 
   // Whether the decoder implementation supports dormant mode.
   bool mDormantSupported;
 
-  // Current decoding position in the stream. This is where the decoder
-  // is up to consuming the stream. This is not adjusted during decoder
-  // seek operations, but it's updated at the end when we start playing
-  // back again.
-  int64_t mDecoderPosition;
-  // Current playback position in the stream. This is (approximately)
-  // where we're up to playing back the stream. This is not adjusted
-  // during decoder seek operations, but it's updated at the end when we
-  // start playing back again.
-  int64_t mPlaybackPosition;
-
   // The logical playback position of the media resource in units of
   // seconds. This corresponds to the "official position" in HTML5. Note that
   // we need to store this as a double, rather than an int64_t (like
   // mCurrentPosition), so that |v.currentTime = foo; v.currentTime == foo|
   // returns true without being affected by rounding errors.
   double mLogicalPosition;
 
   // The current playback position of the underlying playback infrastructure.
@@ -1046,16 +1033,22 @@ protected:
   Mirror<MediaDecoderOwner::NextFrameStatus> mNextFrameStatus;
 
   // NB: Don't use mCurrentPosition directly, but rather CurrentPosition().
   Mirror<int64_t> mCurrentPosition;
 
   // Duration of the media resource according to the state machine.
   Mirror<media::NullableTimeUnit> mStateMachineDuration;
 
+  // Current playback position in the stream. This is (approximately)
+  // where we're up to playing back the stream. This is not adjusted
+  // during decoder seek operations, but it's updated at the end when we
+  // start playing back again.
+  Mirror<int64_t> mPlaybackPosition;
+
   // Volume of playback.  0.0 = muted. 1.0 = full volume.
   Canonical<double> mVolume;
 
   // PlaybackRate and pitch preservation status we should start at.
   Canonical<double> mPlaybackRate;
 
   Canonical<bool> mPreservesPitch;
 
@@ -1083,16 +1076,28 @@ protected:
 
   // True if the decoder is seeking.
   Canonical<bool> mLogicallySeeking;
 
   // True if the media is same-origin with the element. Data can only be
   // passed to MediaStreams when this is true.
   Canonical<bool> mSameOriginMedia;
 
+  // Estimate of the current playback rate (bytes/second).
+  Canonical<double> mPlaybackBytesPerSecond;
+
+  // True if mPlaybackBytesPerSecond is a reliable estimate.
+  Canonical<bool> mPlaybackRateReliable;
+
+  // Current decoding position in the stream. This is where the decoder
+  // is up to consuming the stream. This is not adjusted during decoder
+  // seek operations, but it's updated at the end when we start playing
+  // back again.
+  Canonical<int64_t> mDecoderPosition;
+
 public:
   AbstractCanonical<media::NullableTimeUnit>* CanonicalDurationOrNull() override;
   AbstractCanonical<double>* CanonicalVolume() {
     return &mVolume;
   }
   AbstractCanonical<double>* CanonicalPlaybackRate() {
     return &mPlaybackRate;
   }
@@ -1112,13 +1117,22 @@ public:
     return &mNextState;
   }
   AbstractCanonical<bool>* CanonicalLogicallySeeking() {
     return &mLogicallySeeking;
   }
   AbstractCanonical<bool>* CanonicalSameOriginMedia() {
     return &mSameOriginMedia;
   }
+  AbstractCanonical<double>* CanonicalPlaybackBytesPerSecond() {
+    return &mPlaybackBytesPerSecond;
+  }
+  AbstractCanonical<bool>* CanonicalPlaybackRateReliable() {
+    return &mPlaybackRateReliable;
+  }
+  AbstractCanonical<int64_t>* CanonicalDecoderPosition() {
+    return &mDecoderPosition;
+  }
 };
 
 } // namespace mozilla
 
 #endif
--- a/dom/media/MediaDecoderStateMachine.cpp
+++ b/dom/media/MediaDecoderStateMachine.cpp
@@ -36,17 +36,16 @@
 
 #include "AudioSegment.h"
 #include "DOMMediaStream.h"
 #include "ImageContainer.h"
 #include "MediaDecoder.h"
 #include "MediaDecoderReader.h"
 #include "MediaDecoderStateMachine.h"
 #include "MediaShutdownManager.h"
-#include "MediaStatistics.h"
 #include "MediaTimer.h"
 #include "TimeUnits.h"
 #include "VideoSegment.h"
 #include "VideoUtils.h"
 
 namespace mozilla {
 
 using namespace mozilla::dom;
@@ -239,24 +238,32 @@ MediaDecoderStateMachine::MediaDecoderSt
                     "MediaDecoderStateMachine::mLogicallySeeking (Mirror)"),
   mVolume(mTaskQueue, 1.0, "MediaDecoderStateMachine::mVolume (Mirror)"),
   mLogicalPlaybackRate(mTaskQueue, 1.0,
                        "MediaDecoderStateMachine::mLogicalPlaybackRate (Mirror)"),
   mPreservesPitch(mTaskQueue, true,
                   "MediaDecoderStateMachine::mPreservesPitch (Mirror)"),
   mSameOriginMedia(mTaskQueue, false,
                    "MediaDecoderStateMachine::mSameOriginMedia (Mirror)"),
+  mPlaybackBytesPerSecond(mTaskQueue, 0.0,
+                          "MediaDecoderStateMachine::mPlaybackBytesPerSecond (Mirror)"),
+  mPlaybackRateReliable(mTaskQueue, true,
+                        "MediaDecoderStateMachine::mPlaybackRateReliable (Mirror)"),
+  mDecoderPosition(mTaskQueue, 0,
+                   "MediaDecoderStateMachine::mDecoderPosition (Mirror)"),
   mDuration(mTaskQueue, NullableTimeUnit(),
             "MediaDecoderStateMachine::mDuration (Canonical"),
   mIsShutdown(mTaskQueue, false,
               "MediaDecoderStateMachine::mIsShutdown (Canonical)"),
   mNextFrameStatus(mTaskQueue, MediaDecoderOwner::NEXT_FRAME_UNINITIALIZED,
                    "MediaDecoderStateMachine::mNextFrameStatus (Canonical)"),
   mCurrentPosition(mTaskQueue, 0,
-                   "MediaDecoderStateMachine::mCurrentPosition (Canonical)")
+                   "MediaDecoderStateMachine::mCurrentPosition (Canonical)"),
+  mPlaybackOffset(mTaskQueue, 0,
+                  "MediaDecoderStateMachine::mPlaybackOffset (Canonical)")
 {
   MOZ_COUNT_CTOR(MediaDecoderStateMachine);
   NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
 
   // Dispatch initialization that needs to happen on that task queue.
   nsCOMPtr<nsIRunnable> r = NS_NewRunnableMethod(this, &MediaDecoderStateMachine::InitializationTask);
   mTaskQueue->Dispatch(r.forget());
 
@@ -319,16 +326,19 @@ MediaDecoderStateMachine::Initialization
   mExplicitDuration.Connect(mDecoder->CanonicalExplicitDuration());
   mPlayState.Connect(mDecoder->CanonicalPlayState());
   mNextPlayState.Connect(mDecoder->CanonicalNextPlayState());
   mLogicallySeeking.Connect(mDecoder->CanonicalLogicallySeeking());
   mVolume.Connect(mDecoder->CanonicalVolume());
   mLogicalPlaybackRate.Connect(mDecoder->CanonicalPlaybackRate());
   mPreservesPitch.Connect(mDecoder->CanonicalPreservesPitch());
   mSameOriginMedia.Connect(mDecoder->CanonicalSameOriginMedia());
+  mPlaybackBytesPerSecond.Connect(mDecoder->CanonicalPlaybackBytesPerSecond());
+  mPlaybackRateReliable.Connect(mDecoder->CanonicalPlaybackRateReliable());
+  mDecoderPosition.Connect(mDecoder->CanonicalDecoderPosition());
 
   // Initialize watchers.
   mWatchManager.Watch(mBuffered, &MediaDecoderStateMachine::BufferedRangeUpdated);
   mWatchManager.Watch(mState, &MediaDecoderStateMachine::UpdateNextFrameStatus);
   mWatchManager.Watch(mAudioCompleted, &MediaDecoderStateMachine::UpdateNextFrameStatus);
   mWatchManager.Watch(mVolume, &MediaDecoderStateMachine::VolumeChanged);
   mWatchManager.Watch(mLogicalPlaybackRate, &MediaDecoderStateMachine::LogicalPlaybackRateChanged);
   mWatchManager.Watch(mPreservesPitch, &MediaDecoderStateMachine::PreservesPitchChanged);
@@ -681,27 +691,27 @@ MediaDecoderStateMachine::PushFront(Medi
   UpdateNextFrameStatus();
 }
 
 void
 MediaDecoderStateMachine::OnAudioPopped(const nsRefPtr<MediaData>& aSample)
 {
   MOZ_ASSERT(OnTaskQueue());
   ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
-  mDecoder->UpdatePlaybackOffset(std::max<int64_t>(0, aSample->mOffset));
+  mPlaybackOffset = std::max(mPlaybackOffset.Ref(), aSample->mOffset);
   UpdateNextFrameStatus();
   DispatchAudioDecodeTaskIfNeeded();
 }
 
 void
 MediaDecoderStateMachine::OnVideoPopped(const nsRefPtr<MediaData>& aSample)
 {
   MOZ_ASSERT(OnTaskQueue());
   ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
-  mDecoder->UpdatePlaybackOffset(aSample->mOffset);
+  mPlaybackOffset = std::max(mPlaybackOffset.Ref(), aSample->mOffset);
   UpdateNextFrameStatus();
   DispatchVideoDecodeTaskIfNeeded();
 }
 
 void
 MediaDecoderStateMachine::OnNotDecoded(MediaData::Type aType,
                                        MediaDecoderReader::NotDecodedReason aReason)
 {
@@ -2188,20 +2198,25 @@ MediaDecoderStateMachine::FinishShutdown
   mExplicitDuration.DisconnectIfConnected();
   mPlayState.DisconnectIfConnected();
   mNextPlayState.DisconnectIfConnected();
   mLogicallySeeking.DisconnectIfConnected();
   mVolume.DisconnectIfConnected();
   mLogicalPlaybackRate.DisconnectIfConnected();
   mPreservesPitch.DisconnectIfConnected();
   mSameOriginMedia.DisconnectIfConnected();
+  mPlaybackBytesPerSecond.DisconnectIfConnected();
+  mPlaybackRateReliable.DisconnectIfConnected();
+  mDecoderPosition.DisconnectIfConnected();
+
   mDuration.DisconnectAll();
   mIsShutdown.DisconnectAll();
   mNextFrameStatus.DisconnectAll();
   mCurrentPosition.DisconnectAll();
+  mPlaybackOffset.DisconnectAll();
 
   // Shut down the watch manager before shutting down our task queue.
   mWatchManager.Shutdown();
 
   MOZ_ASSERT(mState == DECODER_STATE_SHUTDOWN,
              "How did we escape from the shutdown state?");
   // We must daisy-chain these events to destroy the decoder. We must
   // destroy the decoder on the main thread, but we can't destroy the
@@ -2428,16 +2443,18 @@ MediaDecoderStateMachine::Reset()
 
   mMetadataRequest.DisconnectIfExists();
   mAudioDataRequest.DisconnectIfExists();
   mAudioWaitRequest.DisconnectIfExists();
   mVideoDataRequest.DisconnectIfExists();
   mVideoWaitRequest.DisconnectIfExists();
   mSeekRequest.DisconnectIfExists();
 
+  mPlaybackOffset = 0;
+
   nsCOMPtr<nsIRunnable> resetTask =
     NS_NewRunnableMethod(mReader, &MediaDecoderReader::ResetDecode);
   DecodeTaskQueue()->Dispatch(resetTask.forget());
 }
 
 bool MediaDecoderStateMachine::CheckFrameValidity(VideoData* aData)
 {
   MOZ_ASSERT(OnTaskQueue());
@@ -2785,17 +2802,32 @@ bool MediaDecoderStateMachine::JustExite
     mQuickBuffering &&
     (TimeStamp::Now() - mDecodeStartTime) < TimeDuration::FromMicroseconds(QUICK_BUFFER_THRESHOLD_USECS);
 }
 
 bool
 MediaDecoderStateMachine::CanPlayThrough()
 {
   MOZ_ASSERT(OnTaskQueue());
-  return IsRealTime() || mDecoder->GetStatistics().CanPlayThrough();
+  return IsRealTime() || GetStatistics().CanPlayThrough();
+}
+
+MediaStatistics
+MediaDecoderStateMachine::GetStatistics()
+{
+  MOZ_ASSERT(OnTaskQueue());
+  MediaStatistics result;
+  result.mDownloadRate = mResource->GetDownloadRate(&result.mDownloadRateReliable);
+  result.mDownloadPosition = mResource->GetCachedDataEnd(mDecoderPosition);
+  result.mTotalBytes = mResource->GetLength();
+  result.mPlaybackRate = mPlaybackBytesPerSecond;
+  result.mPlaybackRateReliable = mPlaybackRateReliable;
+  result.mDecoderPosition = mDecoderPosition;
+  result.mPlaybackPosition = mPlaybackOffset;
+  return result;
 }
 
 void MediaDecoderStateMachine::StartBuffering()
 {
   MOZ_ASSERT(OnTaskQueue());
   ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
 
   if (mState != DECODER_STATE_DECODING) {
@@ -2818,17 +2850,17 @@ void MediaDecoderStateMachine::StartBuff
   mQuickBuffering =
     !JustExitedQuickBuffering() &&
     decodeDuration < UsecsToDuration(QUICK_BUFFER_THRESHOLD_USECS);
   mBufferingStart = TimeStamp::Now();
 
   SetState(DECODER_STATE_BUFFERING);
   DECODER_LOG("Changed state from DECODING to BUFFERING, decoded for %.3lfs",
               decodeDuration.ToSeconds());
-  MediaStatistics stats = mDecoder->GetStatistics();
+  MediaStatistics stats = GetStatistics();
   DECODER_LOG("Playback rate: %.1lfKB/s%s download rate: %.1lfKB/s%s",
               stats.mPlaybackRate/1024, stats.mPlaybackRateReliable ? "" : " (unreliable)",
               stats.mDownloadRate/1024, stats.mDownloadRateReliable ? "" : " (unreliable)");
 }
 
 void MediaDecoderStateMachine::ScheduleStateMachineWithLockAndWakeDecoder()
 {
   MOZ_ASSERT(OnTaskQueue());
--- a/dom/media/MediaDecoderStateMachine.h
+++ b/dom/media/MediaDecoderStateMachine.h
@@ -88,16 +88,17 @@ hardware (via AudioStream).
 #include "mozilla/StateMirroring.h"
 
 #include "nsThreadUtils.h"
 #include "MediaDecoder.h"
 #include "MediaDecoderReader.h"
 #include "MediaDecoderOwner.h"
 #include "MediaEventSource.h"
 #include "MediaMetadataManager.h"
+#include "MediaStatistics.h"
 #include "MediaTimer.h"
 #include "ImageContainer.h"
 
 namespace mozilla {
 
 namespace media {
 class MediaSink;
 }
@@ -203,16 +204,18 @@ public:
 private:
   // Causes the state machine to switch to buffering state, and to
   // immediately stop playback and buffer downloaded data. Called on
   // the state machine thread.
   void StartBuffering();
 
   bool CanPlayThrough();
 
+  MediaStatistics GetStatistics();
+
 public:
   void DispatchStartBuffering()
   {
     nsCOMPtr<nsIRunnable> runnable =
       NS_NewRunnableMethod(this, &MediaDecoderStateMachine::StartBuffering);
     OwnerThread()->Dispatch(runnable.forget());
   }
 
@@ -1278,45 +1281,60 @@ private:
 
   // Pitch preservation for the playback rate.
   Mirror<bool> mPreservesPitch;
 
   // True if the media is same-origin with the element. Data can only be
   // passed to MediaStreams when this is true.
   Mirror<bool> mSameOriginMedia;
 
+  // Estimate of the current playback rate (bytes/second).
+  Mirror<double> mPlaybackBytesPerSecond;
+
+  // True if mPlaybackBytesPerSecond is a reliable estimate.
+  Mirror<bool> mPlaybackRateReliable;
+
+  // Current decoding position in the stream.
+  Mirror<int64_t> mDecoderPosition;
+
   // Duration of the media. This is guaranteed to be non-null after we finish
   // decoding the first frame.
   Canonical<media::NullableTimeUnit> mDuration;
 
   // Whether we're currently in or transitioning to shutdown state.
   Canonical<bool> mIsShutdown;
 
   // The status of our next frame. Mirrored on the main thread and used to
   // compute ready state.
   Canonical<NextFrameStatus> mNextFrameStatus;
 
   // The time of the current frame in microseconds, corresponding to the "current
   // playback position" in HTML5. This is referenced from 0, which is the initial
   // playback position.
   Canonical<int64_t> mCurrentPosition;
 
+  // Current playback position in the stream in bytes.
+  Canonical<int64_t> mPlaybackOffset;
+
 public:
   AbstractCanonical<media::TimeIntervals>* CanonicalBuffered() {
     return mReader->CanonicalBuffered();
   }
   AbstractCanonical<media::NullableTimeUnit>* CanonicalDuration() {
     return &mDuration;
   }
   AbstractCanonical<bool>* CanonicalIsShutdown() {
     return &mIsShutdown;
   }
   AbstractCanonical<NextFrameStatus>* CanonicalNextFrameStatus() {
     return &mNextFrameStatus;
   }
   AbstractCanonical<int64_t>* CanonicalCurrentPosition() {
     return &mCurrentPosition;
   }
+  AbstractCanonical<int64_t>* CanonicalPlaybackOffset() {
+    return &mPlaybackOffset;
+  }
 };
 
 } // namespace mozilla
 
 #endif
--- a/dom/media/gmp/rlz/moz.build
+++ b/dom/media/gmp/rlz/moz.build
@@ -14,11 +14,8 @@ USE_STATIC_LIBS = True
 UNIFIED_SOURCES += [
     'lib/string_utils.cc',
     'win/lib/machine_id_win.cc',
 ]
 
 LOCAL_INCLUDES += [
     '..',
 ]
-
-if not CONFIG['GNU_CXX']:
-    ALLOW_COMPILER_WARNINGS = True
--- a/dom/media/platforms/gonk/GonkVideoDecoderManager.cpp
+++ b/dom/media/platforms/gonk/GonkVideoDecoderManager.cpp
@@ -478,17 +478,17 @@ void GonkVideoDecoderManager::ReleaseVid
 void
 GonkVideoDecoderManager::codecReserved()
 {
   GVDM_LOG("codecReserved");
   sp<AMessage> format = new AMessage;
   sp<Surface> surface;
   status_t rv = OK;
   // Fixed values
-  GVDM_LOG("Configure video mime type: %s, widht:%d, height:%d", mMimeType.get(), mVideoWidth, mVideoHeight);
+  GVDM_LOG("Configure video mime type: %s, width:%d, height:%d", mMimeType.get(), mVideoWidth, mVideoHeight);
   format->setString("mime", mMimeType.get());
   format->setInt32("width", mVideoWidth);
   format->setInt32("height", mVideoHeight);
   if (mNativeWindow != nullptr) {
     surface = new Surface(mNativeWindow->getBufferQueue());
   }
   mDecoder->configure(format, surface, nullptr, 0);
   mDecoder->Prepare();
--- a/dom/media/webaudio/blink/DynamicsCompressorKernel.cpp
+++ b/dom/media/webaudio/blink/DynamicsCompressorKernel.cpp
@@ -162,17 +162,17 @@ float DynamicsCompressorKernel::slopeAt(
 }
 
 float DynamicsCompressorKernel::kAtSlope(float desiredSlope)
 {
     float xDb = m_dbThreshold + m_dbKnee;
     float x = WebAudioUtils::ConvertDecibelsToLinear(xDb);
 
     // Approximate k given initial values.
-    float minK = 0.1;
+    float minK = 0.1f;
     float maxK = 10000;
     float k = 5;
 
     for (int i = 0; i < 15; ++i) {
         // A high value for k will more quickly asymptotically approach a slope of 0.
         float slope = slopeAt(x, k);
 
         if (slope < desiredSlope) {
--- a/dom/media/webaudio/blink/PeriodicWave.cpp
+++ b/dom/media/webaudio/blink/PeriodicWave.cpp
@@ -232,17 +232,17 @@ void PeriodicWave::createBandLimitedTabl
 
         // Apply normalization scale.
         AudioBufferInPlaceScale(data, normalizationScale, m_periodicWaveSize);
     }
 }
 
 void PeriodicWave::generateBasicWaveform(OscillatorType shape)
 {
-    const float piFloat = M_PI;
+    const float piFloat = float(M_PI);
     unsigned fftSize = periodicWaveSize();
     unsigned halfSize = fftSize / 2;
 
     AudioFloatArray real(halfSize);
     AudioFloatArray imag(halfSize);
     float* realP = real.Elements();
     float* imagP = imag.Elements();
 
--- a/dom/media/webaudio/blink/moz.build
+++ b/dom/media/webaudio/blink/moz.build
@@ -25,11 +25,8 @@ UNIFIED_SOURCES += [
 ]
 
 include('/ipc/chromium/chromium-config.mozbuild')
 
 FINAL_LIBRARY = 'xul'
 LOCAL_INCLUDES += [
     '/dom/media/webaudio',
 ]
-
-if not CONFIG['GNU_CXX']:
-    ALLOW_COMPILER_WARNINGS = True
--- a/dom/notification/NotificationStorage.js
+++ b/dom/notification/NotificationStorage.js
@@ -1,15 +1,15 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
-const DEBUG = true;
+const DEBUG = false;
 function debug(s) { dump("-*- NotificationStorage.js: " + s + "\n"); }
 
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 const Cu = Components.utils;
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
--- a/dom/plugins/test/testplugin/moz.build
+++ b/dom/plugins/test/testplugin/moz.build
@@ -3,13 +3,10 @@
 # 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/.
 
 DIRS += ['secondplugin', 'javaplugin', 'thirdplugin', 'flashplugin']
 
 SharedLibrary('nptest')
 
-if CONFIG['_MSC_VER']:
-    ALLOW_COMPILER_WARNINGS = True
-
 relative_path = '.'
 include('testplugin.mozbuild')
--- a/dom/security/nsContentSecurityManager.cpp
+++ b/dom/security/nsContentSecurityManager.cpp
@@ -27,80 +27,76 @@ ValidateSecurityFlags(nsILoadInfo* aLoad
       securityMode != nsILoadInfo::SEC_REQUIRE_CORS_DATA_INHERITS) {
     MOZ_ASSERT(false, "can not use cors-with-credentials without cors");
     return NS_ERROR_FAILURE;
   }
   // all good, found the right security flags
   return NS_OK;
 }
 
-nsresult
-DoSOPChecks(nsIURI* aURI, nsILoadInfo* aLoadInfo)
+static bool SchemeIs(nsIURI* aURI, const char* aScheme)
 {
-  nsSecurityFlags securityMode = aLoadInfo->GetSecurityMode();
+  nsCOMPtr<nsIURI> baseURI = NS_GetInnermostURI(aURI);
+  NS_ENSURE_TRUE(baseURI, false);
 
-  // if none of the REQUIRE_SAME_ORIGIN flags are set, then SOP does not apply
-  if ((securityMode != nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_DATA_INHERITS) &&
-      (securityMode != nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_DATA_IS_BLOCKED)) {
-    return NS_OK;
-  }
-
-  nsIPrincipal* loadingPrincipal = aLoadInfo->LoadingPrincipal();
-  bool sameOriginDataInherits =
-    securityMode == nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_DATA_INHERITS;
-  return loadingPrincipal->CheckMayLoad(aURI,
-                                        true, // report to console
-                                        sameOriginDataInherits);
+  bool isScheme = false;
+  return NS_SUCCEEDED(baseURI->SchemeIs(aScheme, &isScheme)) && isScheme;
 }
 
 nsresult
 DoCheckLoadURIChecks(nsIURI* aURI, nsILoadInfo* aLoadInfo)
 {
   nsresult rv = NS_OK;
-  nsSecurityFlags securityMode = aLoadInfo->GetSecurityMode();
-  // Please note that checkLoadURIWithPrincipal should only be enforced for
-  // cross origin requests. If the flag SEC_REQUIRE_CORS_DATA_INHERITS is set
-  // within the loadInfo, then then CheckLoadURIWithPrincipal is performed
-  // within nsCorsListenerProxy
-  if ((securityMode != nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_INHERITS) &&
-      (securityMode != nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL)) {
-    return NS_OK;
+
+  nsCOMPtr<nsIPrincipal> loadingPrincipal = aLoadInfo->LoadingPrincipal();
+  uint32_t flags = nsIScriptSecurityManager::STANDARD;
+  if (aLoadInfo->GetAllowChrome()) {
+    flags |= nsIScriptSecurityManager::ALLOW_CHROME;
   }
 
-  nsCOMPtr<nsIPrincipal> loadingPrincipal = aLoadInfo->LoadingPrincipal();
-  // XXX: @arg nsIScriptSecurityManager::STANDARD
-  // lets use STANDARD for now and evaluate on a callsite basis, see also:
-  // http://mxr.mozilla.org/mozilla-central/source/caps/nsIScriptSecurityManager.idl#62
   rv = nsContentUtils::GetSecurityManager()->
     CheckLoadURIWithPrincipal(loadingPrincipal,
                               aURI,
-                              nsIScriptSecurityManager::STANDARD);
+                              flags);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // If the loadingPrincipal and the triggeringPrincipal are different, then make
   // sure the triggeringPrincipal is allowed to access that URI.
   nsCOMPtr<nsIPrincipal> triggeringPrincipal = aLoadInfo->TriggeringPrincipal();
   if (loadingPrincipal != triggeringPrincipal) {
     rv = nsContentUtils::GetSecurityManager()->
            CheckLoadURIWithPrincipal(triggeringPrincipal,
                                      aURI,
-                                     nsIScriptSecurityManager::STANDARD);
+                                     flags);
     NS_ENSURE_SUCCESS(rv, rv);
   }
   return NS_OK;
 }
 
 nsresult
+DoSOPChecks(nsIURI* aURI, nsILoadInfo* aLoadInfo)
+{
+  if (aLoadInfo->GetAllowChrome() && SchemeIs(aURI, "chrome")) {
+    // Enforce same-origin policy, except to chrome.
+    return DoCheckLoadURIChecks(aURI, aLoadInfo);
+  }
+
+  nsIPrincipal* loadingPrincipal = aLoadInfo->LoadingPrincipal();
+  bool sameOriginDataInherits =
+    aLoadInfo->GetSecurityMode() == nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_DATA_INHERITS;
+  return loadingPrincipal->CheckMayLoad(aURI,
+                                        true, // report to console
+                                        sameOriginDataInherits);
+}
+
+nsresult
 DoCORSChecks(nsIChannel* aChannel, nsILoadInfo* aLoadInfo,
              nsCOMPtr<nsIStreamListener>& aInAndOutListener)
 {
-  if (aLoadInfo->GetSecurityMode() != nsILoadInfo::SEC_REQUIRE_CORS_DATA_INHERITS) {
-    return NS_OK;
-  }
-
+  MOZ_ASSERT(aInAndOutListener, "can not perform CORS checks without a listener");
   nsIPrincipal* loadingPrincipal = aLoadInfo->LoadingPrincipal();
   nsRefPtr<nsCORSListenerProxy> corsListener =
     new nsCORSListenerProxy(aInAndOutListener,
                             loadingPrincipal,
                             aLoadInfo->GetRequireCorsWithCredentials());
   // XXX: @arg: DataURIHandling::Allow
   // lets use  DataURIHandling::Allow for now and then decide on callsite basis. see also:
   // http://mxr.mozilla.org/mozilla-central/source/dom/security/nsCORSListenerProxy.h#33
@@ -139,19 +135,24 @@ DoContentSecurityChecks(nsIURI* aURI, ns
       mimeTypeGuess = NS_LITERAL_CSTRING("text/html");
       requestingContext = aLoadInfo->LoadingNode();
       MOZ_ASSERT(!requestingContext ||
                  requestingContext->NodeType() == nsIDOMNode::DOCUMENT_NODE,
                  "type_subdocument requires requestingContext of type Document");
       break;
     }
 
-    case nsIContentPolicy::TYPE_REFRESH:
+    case nsIContentPolicy::TYPE_REFRESH: {
+      MOZ_ASSERT(false, "contentPolicyType not supported yet");
+      break;
+    }
+
     case nsIContentPolicy::TYPE_XBL: {
-      MOZ_ASSERT(false, "contentPolicyType not supported yet");
+      mimeTypeGuess = EmptyCString();
+      requestingContext = aLoadInfo->LoadingNode();
       break;
     }
 
     case nsIContentPolicy::TYPE_PING: {
       mimeTypeGuess = EmptyCString();
       requestingContext = aLoadInfo->LoadingNode();
       break;
     }
@@ -302,32 +303,45 @@ nsContentSecurityManager::doContentSecur
   // we just set the flag again.
   rv = loadInfo->SetEnforceSecurity(true);
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsCOMPtr<nsIURI> finalChannelURI;
   rv = NS_GetFinalChannelURI(aChannel, getter_AddRefs(finalChannelURI));
   NS_ENSURE_SUCCESS(rv, rv);
 
-  // Perform Same Origin Policy check
-  rv = DoSOPChecks(finalChannelURI, loadInfo);
-  NS_ENSURE_SUCCESS(rv, rv);
+  nsSecurityFlags securityMode = loadInfo->GetSecurityMode();
+
+  // if none of the REQUIRE_SAME_ORIGIN flags are set, then SOP does not apply
+  if ((securityMode == nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_DATA_INHERITS) ||
+      (securityMode == nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_DATA_IS_BLOCKED)) {
+    rv = DoSOPChecks(finalChannelURI, loadInfo);
+    NS_ENSURE_SUCCESS(rv, rv);
+  }
 
   // if dealing with a redirected channel then we only enforce SOP
   // and can return at this point.
   if (initialSecurityCheckDone) {
     return NS_OK;
   }
 
-  rv = DoCheckLoadURIChecks(finalChannelURI, loadInfo);
-  NS_ENSURE_SUCCESS(rv, rv);
+  if ((securityMode == nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_INHERITS) ||
+      (securityMode == nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL)) {
+    // Please note that DoCheckLoadURIChecks should only be enforced for
+    // cross origin requests. If the flag SEC_REQUIRE_CORS_DATA_INHERITS is set
+    // within the loadInfo, then then CheckLoadURIWithPrincipal is performed
+    // within nsCorsListenerProxy
+    rv = DoCheckLoadURIChecks(finalChannelURI, loadInfo);
+    NS_ENSURE_SUCCESS(rv, rv);
+  }
 
-  // Check if CORS needs to be set up
-  rv = DoCORSChecks(aChannel, loadInfo, aInAndOutListener);
-  NS_ENSURE_SUCCESS(rv, rv);
+  if (securityMode == nsILoadInfo::SEC_REQUIRE_CORS_DATA_INHERITS) {
+    rv = DoCORSChecks(aChannel, loadInfo, aInAndOutListener);
+    NS_ENSURE_SUCCESS(rv, rv);
+  }
 
   // Perform all ContentPolicy checks (MixedContent, CSP, ...)
   rv = DoContentSecurityChecks(finalChannelURI, loadInfo);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // all security checks passed - lets allow the load
   return NS_OK;
 }
--- a/dom/settings/SettingsService.js
+++ b/dom/settings/SettingsService.js
@@ -46,37 +46,35 @@ const nsISettingsServiceLock         = C
 function makeSettingsServiceRequest(aCallback, aName, aValue) {
   return {
     callback: aCallback,
     name: aName,
     value: aValue
   };
 };
 
+const kLockListeners = ["Settings:Get:OK", "Settings:Get:KO",
+                        "Settings:Clear:OK", "Settings:Clear:KO",
+                        "Settings:Set:OK", "Settings:Set:KO",
+                        "Settings:Finalize:OK", "Settings:Finalize:KO"];
+
 function SettingsServiceLock(aSettingsService, aTransactionCallback) {
   if (VERBOSE) debug("settingsServiceLock constr!");
   this._open = true;
   this._settingsService = aSettingsService;
   this._id = uuidgen.generateUUID().toString();
   this._transactionCallback = aTransactionCallback;
   this._requests = {};
   let closeHelper = function() {
     if (VERBOSE) debug("closing lock " + this._id);
     this._open = false;
     this.runOrFinalizeQueries();
   }.bind(this);
 
-  let msgs =   ["Settings:Get:OK", "Settings:Get:KO",
-                "Settings:Clear:OK", "Settings:Clear:KO",
-                "Settings:Set:OK", "Settings:Set:KO",
-                "Settings:Finalize:OK", "Settings:Finalize:KO"];
-
-  for (let msg in msgs) {
-    cpmm.addMessageListener(msgs[msg], this);
-  }
+  this.addListeners();
 
   let createLockPayload = {
     lockID: this._id,
     isServiceLock: true,
     windowID: undefined,
     lockStack: (new Error).stack
   };
 
@@ -84,16 +82,28 @@ function SettingsServiceLock(aSettingsSe
   Services.tm.currentThread.dispatch(closeHelper, Ci.nsIThread.DISPATCH_NORMAL);
 }
 
 SettingsServiceLock.prototype = {
   get closed() {
     return !this._open;
   },
 
+  addListeners: function() {
+    for (let msg of kLockListeners) {
+      cpmm.addMessageListener(msg, this);
+    }
+  },
+
+  removeListeners: function() {
+    for (let msg of kLockListeners) {
+      cpmm.removeMessageListener(msg, this);
+    }
+  },
+
   returnMessage: function(aMessage, aData) {
     SettingsRequestManager.receiveMessage({
       name: aMessage,
       data: aData,
       target: undefined,
       principal: Services.scriptSecurityManager.getSystemPrincipal()
     });
   },
@@ -301,16 +311,17 @@ SettingsService.prototype = {
     this._createdLocks++;
   },
 
   unregisterLock: function(aLockID) {
     let lock_index = this._locks.indexOf(aLockID);
     if (lock_index != -1) {
       if (VERBOSE) debug("Unregistering lock " + aLockID);
       this._locks.splice(lock_index, 1);
+      this._serviceLocks[aLockID].removeListeners();
       this._serviceLocks[aLockID] = null;
       delete this._serviceLocks[aLockID];
       this._unregisteredLocks++;
     }
   },
 
   collectReports: function(aCallback, aData, aAnonymize) {
     aCallback.callback("",
--- a/dom/system/gonk/MozMtpDatabase.cpp
+++ b/dom/system/gonk/MozMtpDatabase.cpp
@@ -17,16 +17,18 @@
 #include "nsIFile.h"
 #include "nsIObserverService.h"
 #include "nsPrintfCString.h"
 #include "nsString.h"
 #include "prio.h"
 
 #include <dirent.h>
 #include <libgen.h>
+#include <utime.h>
+#include <sys/stat.h>
 
 using namespace android;
 using namespace mozilla;
 
 namespace mozilla {
 MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE(ScopedCloseDir, PRDir, PR_CloseDir)
 }
 
@@ -58,29 +60,40 @@ static const char *
 ObjectPropertyAsStr(MtpObjectProperty aProperty)
 {
   switch (aProperty) {
     case MTP_PROPERTY_STORAGE_ID:         return "MTP_PROPERTY_STORAGE_ID";
     case MTP_PROPERTY_OBJECT_FORMAT:      return "MTP_PROPERTY_OBJECT_FORMAT";
     case MTP_PROPERTY_PROTECTION_STATUS:  return "MTP_PROPERTY_PROTECTION_STATUS";
     case MTP_PROPERTY_OBJECT_SIZE:        return "MTP_PROPERTY_OBJECT_SIZE";
     case MTP_PROPERTY_OBJECT_FILE_NAME:   return "MTP_PROPERTY_OBJECT_FILE_NAME";
+    case MTP_PROPERTY_DATE_CREATED:       return "MTP_PROPERTY_DATE_CREATED";
     case MTP_PROPERTY_DATE_MODIFIED:      return "MTP_PROPERTY_DATE_MODIFIED";
     case MTP_PROPERTY_PARENT_OBJECT:      return "MTP_PROPERTY_PARENT_OBJECT";
     case MTP_PROPERTY_PERSISTENT_UID:     return "MTP_PROPERTY_PERSISTENT_UID";
     case MTP_PROPERTY_NAME:               return "MTP_PROPERTY_NAME";
     case MTP_PROPERTY_DATE_ADDED:         return "MTP_PROPERTY_DATE_ADDED";
     case MTP_PROPERTY_WIDTH:              return "MTP_PROPERTY_WIDTH";
     case MTP_PROPERTY_HEIGHT:             return "MTP_PROPERTY_HEIGHT";
     case MTP_PROPERTY_IMAGE_BIT_DEPTH:    return "MTP_PROPERTY_IMAGE_BIT_DEPTH";
     case MTP_PROPERTY_DISPLAY_NAME:       return "MTP_PROPERTY_DISPLAY_NAME";
   }
   return "MTP_PROPERTY_???";
 }
 
+static char*
+FormatDate(time_t aTime, char *aDateStr, size_t aDateStrSize)
+{
+  struct tm tm;
+  localtime_r(&aTime, &tm);
+  MTP_LOG("(%ld) tm_zone = %s off = %ld", aTime, tm.tm_zone, tm.tm_gmtoff);
+  strftime(aDateStr, aDateStrSize, "%Y%m%dT%H%M%S", &tm);
+  return aDateStr;
+}
+
 MozMtpDatabase::MozMtpDatabase()
   : mMutex("MozMtpDatabase::mMutex"),
     mDb(mMutex),
     mStorage(mMutex),
     mBeginSendObjectCalled(false)
 {
   MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop());
 
@@ -217,19 +230,31 @@ MozMtpDatabase::UpdateEntry(MtpObjectHan
 {
   MutexAutoLock lock(mMutex);
 
   RefPtr<DbEntry> entry = mDb[aHandle];
 
   int64_t fileSize = 0;
   aFile->mFile->GetFileSize(&fileSize);
   entry->mObjectSize = fileSize;
-  aFile->mFile->GetLastModifiedTime(&entry->mDateCreated);
-  entry->mDateModified = entry->mDateCreated;
-  MTP_DBG("UpdateEntry (0x%08x file %s)", entry->mHandle, entry->mPath.get());
+
+  PRTime dateModifiedMsecs;
+  // GetLastModifiedTime returns msecs
+  aFile->mFile->GetLastModifiedTime(&dateModifiedMsecs);
+  entry->mDateModified = dateModifiedMsecs / PR_MSEC_PER_SEC;
+  entry->mDateCreated = entry->mDateModified;
+  entry->mDateAdded = entry->mDateModified;
+
+  #if USE_DEBUG
+  char dateStr[20];
+  MTP_DBG("UpdateEntry (0x%08x file %s) modified (%ld) %s",
+          entry->mHandle, entry->mPath.get(),
+          entry->mDateModified,
+          FormatDate(entry->mDateModified, dateStr, sizeof(dateStr)));
+  #endif
 }
 
 
 class FileWatcherNotifyRunnable final : public nsRunnable
 {
 public:
   FileWatcherNotifyRunnable(nsACString& aStorageName,
                             nsACString& aPath,
@@ -449,24 +474,29 @@ MozMtpDatabase::CreateEntryForFileAndNot
     if (slash == kNotFound) {
       // No slash - this is the file component
       entry->mObjectFormat = MTP_FORMAT_DEFINED;
 
       int64_t fileSize = 0;
       aFile->mFile->GetFileSize(&fileSize);
       entry->mObjectSize = fileSize;
 
-      aFile->mFile->GetLastModifiedTime(&entry->mDateCreated);
+      // Note: Even though PRTime records usec, GetLastModifiedTime returns
+      //       msecs.
+      PRTime dateModifiedMsecs;
+      aFile->mFile->GetLastModifiedTime(&dateModifiedMsecs);
+      entry->mDateModified = dateModifiedMsecs / PR_MSEC_PER_SEC;
     } else {
       // Found a slash, this makes this a directory component
       entry->mObjectFormat = MTP_FORMAT_ASSOCIATION;
       entry->mObjectSize = 0;
-      entry->mDateCreated = PR_Now();
+      time(&entry->mDateModified);
     }
-    entry->mDateModified = entry->mDateCreated;
+    entry->mDateCreated = entry->mDateModified;
+    entry->mDateAdded = entry->mDateModified;
 
     AddEntryAndNotify(entry, aMtpServer);
     MTP_LOG("About to call sendObjectAdded Handle 0x%08x file %s", entry->mHandle, entry->mPath.get());
 
     parent = entry->mHandle;
     offset = slash + 1;
   } while (slash != kNotFound);
 
@@ -498,18 +528,21 @@ MozMtpDatabase::AddDirectory(MtpStorageI
 
     RefPtr<DbEntry> entry = new DbEntry;
 
     entry->mStorageID = aStorageID;
     entry->mParent = aParent;
     entry->mObjectName = dirEntry->name;
     entry->mDisplayName = dirEntry->name;
     entry->mPath = filename;
-    entry->mDateCreated = fileInfo.creationTime;
-    entry->mDateModified = fileInfo.modifyTime;
+
+    // PR_GetFileInfo64 returns timestamps in usecs
+    entry->mDateModified = fileInfo.modifyTime / PR_USEC_PER_SEC;
+    entry->mDateCreated = fileInfo.creationTime / PR_USEC_PER_SEC;
+    time(&entry->mDateAdded);
 
     if (fileInfo.type == PR_FILE_FILE) {
       entry->mObjectFormat = MTP_FORMAT_DEFINED;
       //TODO: Check how 64-bit filesize are dealt with
       entry->mObjectSize = fileInfo.size;
       AddEntry(entry);
     } else if (fileInfo.type == PR_FILE_DIRECTORY) {
       entry->mObjectFormat = MTP_FORMAT_ASSOCIATION;
@@ -648,19 +681,81 @@ MozMtpDatabase::beginSendObject(const ch
   entry->mStorageID = aStorageID;
   entry->mParent = aParent;
   entry->mPath = aPath;
   entry->mObjectName = BaseName(entry->mPath);
   entry->mDisplayName = entry->mObjectName;
   entry->mObjectFormat = aFormat;
   entry->mObjectSize = aSize;
 
+  if (aModified != 0) {
+    // Currently, due to the way that parseDateTime is coded in
+    // frameworks/av/media/mtp/MtpUtils.cpp, aModified winds up being the number
+    // of seconds from the epoch in local time, rather than UTC time. So we
+    // need to convert it back to being relative to UTC since that's what linux
+    // expects time_t to contain.
+    //
+    // In more concrete testable terms, if the host parses 2015-08-02 02:22:00
+    // as a local time in the Pacific timezone, aModified will come to us as
+    // 1438482120.
+    //
+    // What we want is what mktime would pass us with the same date. Using python
+    // (because its simple) with the current timezone set to be America/Vancouver:
+    //
+    // >>> import time
+    // >>> time.mktime((2015, 8, 2, 2, 22, 0, 0, 0, -1))
+    // 1438507320.0
+    // >>> time.localtime(1438507320)
+    // time.struct_time(tm_year=2015, tm_mon=8, tm_mday=2, tm_hour=2, tm_min=22, tm_sec=0, tm_wday=6, tm_yday=214, tm_isdst=1)
+    //
+    // Currently, when a file has a modification time of 2015-08-22 02:22:00 PDT
+    // then aModified will come in as 1438482120 which corresponds to
+    // 2015-08-22 02:22:00 UTC
+
+    struct tm tm;
+    if (gmtime_r(&aModified, &tm) != NULL) {
+      // GMT always comes back with tm_isdst = 0, so we set it to -1 in order
+      // to have mktime figure out dst based on the date.
+      tm.tm_isdst = -1;
+      aModified = mktime(&tm);
+      if (aModified == (time_t)-1) {
+        aModified = 0;
+      }
+    } else {
+      aModified = 0;
+    }
+  }
+  if (aModified == 0) {
+    // The ubuntu host doesn't pass in the modified/created times in the
+    // SENDOBJECT packet, so aModified winds up being zero. About the best
+    // we can do with that is to use the current time.
+    time(&aModified);
+  }
+
+  // And just an FYI for anybody else looking at timestamps. Under OSX you
+  // need to use the Android File Transfer program to copy files into the
+  // phone. That utility passes in both date modified and date created
+  // timestamps, but they're both equal to the time that the file was copied
+  // and not the times that are associated with the files.
+
+  // Now we have aModified in a traditional time_t format, which is the number
+  // of seconds from the UTC epoch.
+
+  entry->mDateModified = aModified;
+  entry->mDateCreated = entry->mDateModified;
+  entry->mDateAdded = entry->mDateModified;
+
   AddEntry(entry);
 
-  MTP_LOG("Handle: 0x%08x Parent: 0x%08x Path: '%s'", entry->mHandle, aParent, aPath);
+  #if USE_DEBUG
+  char dateStr[20];
+  MTP_LOG("Handle: 0x%08x Parent: 0x%08x Path: '%s' aModified %ld %s",
+          entry->mHandle, aParent, aPath, aModified,
+          FormatDate(entry->mDateModified, dateStr, sizeof(dateStr)));
+  #endif
 
   mBeginSendObjectCalled = true;
   return entry->mHandle;
 }
 
 // called to report success or failure of the SendObject file transfer
 // success should signal a notification of the new object's creation,
 // failure should remove the database entry created in beginSendObject
@@ -672,16 +767,32 @@ MozMtpDatabase::endSendObject(const char
                               MtpObjectFormat aFormat,
                               bool aSucceeded)
 {
   MTP_LOG("Handle: 0x%08x Path: '%s'", aHandle, aPath);
 
   if (aSucceeded) {
     RefPtr<DbEntry> entry = GetEntry(aHandle);
     if (entry) {
+      // The android MTP server only copies the data in, it doesn't set the
+      // modified timestamp, so we do that here.
+
+      struct utimbuf new_times;
+      struct stat sb;
+
+      char dateStr[20];
+      MTP_LOG("Path: '%s' setting modified time to (%ld) %s",
+              entry->mPath.get(), entry->mDateModified,
+              FormatDate(entry->mDateModified, dateStr, sizeof(dateStr)));
+
+      stat(entry->mPath.get(), &sb);
+      new_times.actime = sb.st_atime;   // Preserve atime
+      new_times.modtime = entry->mDateModified;
+      utime(entry->mPath.get(), &new_times);
+
       FileWatcherNotify(entry, "modified");
     }
   } else {
     RemoveEntry(aHandle);
   }
   mBeginSendObjectCalled = false;
 }
 
@@ -789,16 +900,17 @@ MozMtpDatabase::getSupportedCaptureForma
 static const MtpObjectProperty sSupportedObjectProperties[] =
 {
   MTP_PROPERTY_STORAGE_ID,
   MTP_PROPERTY_OBJECT_FORMAT,
   MTP_PROPERTY_PROTECTION_STATUS,   // UINT16 - always 0
   MTP_PROPERTY_OBJECT_SIZE,
   MTP_PROPERTY_OBJECT_FILE_NAME,    // just the filename - no directory
   MTP_PROPERTY_NAME,
+  MTP_PROPERTY_DATE_CREATED,
   MTP_PROPERTY_DATE_MODIFIED,
   MTP_PROPERTY_PARENT_OBJECT,
   MTP_PROPERTY_PERSISTENT_UID,
   MTP_PROPERTY_DATE_ADDED,
 };
 
 //virtual
 MtpObjectPropertyList*
@@ -869,16 +981,17 @@ GetTypeOfObjectProp(MtpObjectProperty aP
   };
 
   static const PropertyTableEntry kObjectPropertyTable[] = {
     {MTP_PROPERTY_STORAGE_ID,        MTP_TYPE_UINT32  },
     {MTP_PROPERTY_OBJECT_FORMAT,     MTP_TYPE_UINT16  },
     {MTP_PROPERTY_PROTECTION_STATUS, MTP_TYPE_UINT16  },
     {MTP_PROPERTY_OBJECT_SIZE,       MTP_TYPE_UINT64  },
     {MTP_PROPERTY_OBJECT_FILE_NAME,  MTP_TYPE_STR     },
+    {MTP_PROPERTY_DATE_CREATED,      MTP_TYPE_STR     },
     {MTP_PROPERTY_DATE_MODIFIED,     MTP_TYPE_STR     },
     {MTP_PROPERTY_PARENT_OBJECT,     MTP_TYPE_UINT32  },
     {MTP_PROPERTY_DISPLAY_NAME,      MTP_TYPE_STR     },
     {MTP_PROPERTY_NAME,              MTP_TYPE_STR     },
     {MTP_PROPERTY_PERSISTENT_UID,    MTP_TYPE_UINT128 },
     {MTP_PROPERTY_DATE_ADDED,        MTP_TYPE_STR     },
   };
 
@@ -1125,16 +1238,18 @@ MozMtpDatabase::getObjectPropertyList(Mt
     numObjectProperties = 1;
     objectProperty = aProperty;
     objectPropertyList = &objectProperty;
   }
 
   UnprotectedDbArray::size_type numEntries = result.Length();
   UnprotectedDbArray::index_type entryIdx;
 
+  char dateStr[20];
+
   aPacket.putUInt32(numObjectProperties * numEntries);
   for (entryIdx = 0; entryIdx < numEntries; entryIdx++) {
     RefPtr<DbEntry> entry = result[entryIdx];
 
     for (size_t propertyIdx = 0; propertyIdx < numObjectProperties; propertyIdx++) {
       aPacket.putUInt32(entry->mHandle);
       MtpObjectProperty prop = objectPropertyList[propertyIdx];
       aPacket.putUInt16(prop);
@@ -1173,33 +1288,34 @@ MozMtpDatabase::getObjectPropertyList(Mt
           aPacket.putString(entry->mObjectName.get());
           break;
 
         case MTP_PROPERTY_PROTECTION_STATUS:
           aPacket.putUInt16(MTP_TYPE_UINT16);
           aPacket.putUInt16(0); // 0 = No Protection
           break;
 
+        case MTP_PROPERTY_DATE_CREATED: {
+          aPacket.putUInt16(MTP_TYPE_STR);
+          aPacket.putString(FormatDate(entry->mDateCreated, dateStr, sizeof(dateStr)));
+          MTP_LOG("mDateCreated: (%ld) %s", entry->mDateCreated, dateStr);
+          break;
+        }
+
         case MTP_PROPERTY_DATE_MODIFIED: {
           aPacket.putUInt16(MTP_TYPE_STR);
-          PRExplodedTime explodedTime;
-          PR_ExplodeTime(entry->mDateModified, PR_LocalTimeParameters, &explodedTime);
-          char dateStr[20];
-          PR_FormatTime(dateStr, sizeof(dateStr), "%Y%m%dT%H%M%S", &explodedTime);
-          aPacket.putString(dateStr);
+          aPacket.putString(FormatDate(entry->mDateModified, dateStr, sizeof(dateStr)));
+          MTP_LOG("mDateModified: (%ld) %s", entry->mDateModified, dateStr);
           break;
         }
 
         case MTP_PROPERTY_DATE_ADDED: {
           aPacket.putUInt16(MTP_TYPE_STR);
-          PRExplodedTime explodedTime;
-          PR_ExplodeTime(entry->mDateCreated, PR_LocalTimeParameters, &explodedTime);
-          char dateStr[20];
-          PR_FormatTime(dateStr, sizeof(dateStr), "%Y%m%dT%H%M%S", &explodedTime);
-          aPacket.putString(dateStr);
+          aPacket.putString(FormatDate(entry->mDateAdded, dateStr, sizeof(dateStr)));
+          MTP_LOG("mDateAdded: (%ld) %s", entry->mDateAdded, dateStr);
           break;
         }
 
         default:
           MTP_ERR("Unrecognized property code: %u", prop);
           return MTP_RESPONSE_GENERAL_ERROR;
       }
     }
@@ -1238,21 +1354,24 @@ MozMtpDatabase::getObjectInfo(MtpObjectH
   aInfo.mImagePixWidth = 0;
   aInfo.mImagePixHeight = 0;
   aInfo.mImagePixDepth = 0;
   aInfo.mParent = entry->mParent;
   aInfo.mAssociationType = 0;
   aInfo.mAssociationDesc = 0;
   aInfo.mSequenceNumber = 0;
   aInfo.mName = ::strdup(entry->mObjectName.get());
+  aInfo.mDateCreated = entry->mDateCreated;
+  aInfo.mDateModified = entry->mDateModified;
 
-  // entry->mDateXxxx is a PRTime stores the time as microseconds from the epoch.
-  // aInfo.mDateXxxx is time_t which stores the time as seconds from the epoch.
-  aInfo.mDateCreated = entry->mDateCreated / PR_USEC_PER_SEC;
-  aInfo.mDateModified = entry->mDateModified / PR_USEC_PER_SEC;
+  MTP_LOG("aInfo.mDateCreated = %ld entry->mDateCreated = %ld",
+          aInfo.mDateCreated, entry->mDateCreated);
+  MTP_LOG("aInfo.mDateModified = %ld entry->mDateModified = %ld",
+          aInfo.mDateModified, entry->mDateModified);
+
   aInfo.mKeywords = ::strdup("fxos,touch");
 
   return MTP_RESPONSE_OK;
 }
 
 //virtual
 void*
 MozMtpDatabase::getThumbnail(MtpObjectHandle aHandle, size_t& aOutThumbSize)
@@ -1378,16 +1497,17 @@ MozMtpDatabase::getObjectPropertyDesc(Mt
       break;
     case MTP_PROPERTY_DISPLAY_NAME:
     case MTP_PROPERTY_NAME:
       result = new MtpProperty(aProperty, MTP_TYPE_STR);
       break;
     case MTP_PROPERTY_OBJECT_FILE_NAME:
       result = new MtpProperty(aProperty, MTP_TYPE_STR, true);
       break;
+    case MTP_PROPERTY_DATE_CREATED:
     case MTP_PROPERTY_DATE_MODIFIED:
     case MTP_PROPERTY_DATE_ADDED:
       result = new MtpProperty(aProperty, MTP_TYPE_STR);
       result->setFormDateTime();
       break;
     case MTP_PROPERTY_PERSISTENT_UID:
       result = new MtpProperty(aProperty, MTP_TYPE_UINT128);
       break;
--- a/dom/system/gonk/MozMtpDatabase.h
+++ b/dom/system/gonk/MozMtpDatabase.h
@@ -128,30 +128,32 @@ private:
   {
     DbEntry()
       : mHandle(0),
         mStorageID(0),
         mObjectFormat(MTP_FORMAT_DEFINED),
         mParent(0),
         mObjectSize(0),
         mDateCreated(0),
-        mDateModified(0) {}
+        mDateModified(0),
+        mDateAdded(0) {}
 
     NS_INLINE_DECL_THREADSAFE_REFCOUNTING(DbEntry)
 
     MtpObjectHandle mHandle;        // uint32_t
     MtpStorageID    mStorageID;     // uint32_t
     nsCString       mObjectName;
     MtpObjectFormat mObjectFormat;  // uint16_t
     MtpObjectHandle mParent;        // uint32_t
     uint64_t        mObjectSize;
     nsCString       mDisplayName;
     nsCString       mPath;
-    PRTime          mDateCreated;
-    PRTime          mDateModified;
+    time_t          mDateCreated;
+    time_t          mDateModified;
+    time_t          mDateAdded;
 
   protected:
     ~DbEntry() {}
   };
 
   template<class T>
   class ProtectedTArray : private nsTArray<T>
   {
--- a/dom/system/gonk/ril_worker.js
+++ b/dom/system/gonk/ril_worker.js
@@ -14455,17 +14455,26 @@ ICCContactHelperObject.prototype = {
       if (!pbr[field]) {
         updateField.call(this);
         return;
       }
 
       this.updateContactField(pbr, contact, field, (fieldEntry) => {
         contactField = Object.assign(contactField, fieldEntry);
         updateField.call(this);
-      }, onerror);
+      }, (errorMsg) => {
+        // Bug 1194149, there are some sim cards without sufficient
+        // Type 2 USIM contact fields record. We allow user continue
+        // importing contacts.
+        if (errorMsg === CONTACT_ERR_NO_FREE_RECORD_FOUND) {
+          updateField.call(this);
+          return;
+        }
+        onerror(errorMsg);
+      });
     }).call(this);
   },
 
   /**
    * Update contact's field from USIM.
    *
    * @param pbr           The phonebook reference file.
    * @param contact       The contact needs to be updated.
--- a/dom/system/gonk/tests/test_ril_worker_icc_ICCContactHelper.js
+++ b/dom/system/gonk/tests/test_ril_worker_icc_ICCContactHelper.js
@@ -602,16 +602,121 @@ add_test(function test_update_icc_contac
     do_test(CARD_APPTYPE_RUIM, GECKO_CARDCONTACT_TYPE_FDN, contact, "1234",
             null, true);
   }
 
   run_next_test();
 });
 
 /**
+ * Verify ICCContactHelper.updateICCContact with appType is CARD_APPTYPE_USIM and
+ * insufficient space to store Type 2 USIM contact fields.
+ */
+add_test(function test_update_icc_contact_full_email_and_anr_field() {
+  const ADN_RECORD_ID   = 100;
+  const ADN_SFI         = 1;
+  const IAP_FILE_ID     = 0x4f17;
+  const EMAIL_FILE_ID   = 0x4f50;
+  const EMAIL_RECORD_ID = 20;
+  const ANR0_FILE_ID    = 0x4f11;
+  const ANR0_RECORD_ID  = 30;
+
+  let worker = newUint8Worker();
+  let context = worker.ContextPool._contexts[0];
+  let recordHelper = context.ICCRecordHelper;
+  let contactHelper = context.ICCContactHelper;
+  let ril = context.RIL;
+
+  function do_test(aSimType, aContactType, aContact, aPin2) {
+    ril.appType = CARD_APPTYPE_USIM;
+    ril.iccInfoPrivate.sst = [0x2, 0x0, 0x0, 0x0, 0x0];
+
+    recordHelper.readPBR = function(onsuccess, onerror) {
+      onsuccess([{
+        adn:   {fileId: ICC_EF_ADN,
+                sfi: ADN_SFI},
+        iap:   {fileId: IAP_FILE_ID},
+        email: {fileId: EMAIL_FILE_ID,
+                fileType: ICC_USIM_TYPE2_TAG,
+                indexInIAP: 0},
+        anr0:  {fileId: ANR0_FILE_ID,
+                fileType: ICC_USIM_TYPE2_TAG,
+                indexInIAP: 1}
+      }]);
+    };
+
+    recordHelper.updateADNLike = function(fileId, contact, pin2, onsuccess, onerror) {
+      if (aContactType === GECKO_CARDCONTACT_TYPE_ADN) {
+        equal(fileId, ICC_EF_ADN);
+      }
+      equal(pin2, aPin2);
+      equal(contact.alphaId, aContact.alphaId);
+      equal(contact.number, aContact.number);
+      onsuccess({alphaId: contact.alphaId,
+                  number: contact.number});
+    };
+
+    recordHelper.readIAP = function(fileId, recordNumber, onsuccess, onerror) {
+      equal(fileId, IAP_FILE_ID);
+      equal(recordNumber, ADN_RECORD_ID);
+      onsuccess([0xff, 0xff]);
+    };
+
+    recordHelper.updateIAP = function(fileId, recordNumber, iap, onsuccess, onerror) {
+      equal(fileId, IAP_FILE_ID);
+      equal(recordNumber, ADN_RECORD_ID);
+      onsuccess();
+    };
+
+    recordHelper.findFreeRecordId = function(fileId, onsuccess, onerror) {
+      let recordId = 0;
+      // emulate email and anr don't have free record.
+      if (fileId === EMAIL_FILE_ID || fileId === ANR0_FILE_ID) {
+        onerror(CONTACT_ERR_NO_FREE_RECORD_FOUND);
+      } else {
+        onsuccess(recordId);
+      }
+    };
+
+    let isSuccess = false;
+    let onsuccess = function onsuccess(updatedContact) {
+      equal(ADN_RECORD_ID, updatedContact.recordId);
+      equal(aContact.alphaId, updatedContact.alphaId);
+      equal(updatedContact.email, null);
+      equal(updatedContact.anr, null);
+
+      do_print("updateICCContact success");
+      isSuccess = true;
+    };
+
+    let onerror = function onerror(errorMsg) {
+      do_print("updateICCContact failed: " + errorMsg);
+    };
+
+    contactHelper.updateICCContact(aSimType, aContactType, aContact, aPin2, onsuccess, onerror);
+    ok(isSuccess);
+  }
+
+  let contact = {
+      pbrIndex: 0,
+      recordId: ADN_RECORD_ID,
+      alphaId:  "test",
+      number:   "123456",
+      email:    "test@mail.com",
+      anr:      ["+654321"]
+    };
+
+  // USIM
+  do_print("Test update USIM adn contacts");
+  do_test(CARD_APPTYPE_USIM, GECKO_CARDCONTACT_TYPE_ADN, contact, null);
+
+  run_next_test();
+});
+
+/**
  * Verify updateICCContact with removal of anr and email with File Type 1.
  */
 add_test(function test_update_icc_contact_with_remove_type1_attr() {
   const ADN_RECORD_ID   = 100;
   const IAP_FILE_ID     = 0x4f17;
   const EMAIL_FILE_ID   = 0x4f50;
   const EMAIL_RECORD_ID = 20;
   const ANR0_FILE_ID    = 0x4f11;
--- a/dom/telephony/Telephony.cpp
+++ b/dom/telephony/Telephony.cpp
@@ -57,18 +57,23 @@ public:
   Disconnect()
   {
     MOZ_ASSERT(mTelephony);
     mTelephony = nullptr;
   }
 };
 
 Telephony::Telephony(nsPIDOMWindow* aOwner)
-  : DOMEventTargetHelper(aOwner)
+  : DOMEventTargetHelper(aOwner),
+    mAudioAgentNotify(nsIAudioChannelAgent::AUDIO_AGENT_NOTIFY),
+    mIsAudioStartPlaying(false),
+    mHaveDispatchedInterruptBeginEvent(false),
+    mMuted(AudioChannelService::IsAudioChannelMutedByDefault())
 {
+  MOZ_ASSERT(aOwner);
   nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aOwner);
   MOZ_ASSERT(global);
 
   ErrorResult rv;
   nsRefPtr<Promise> promise = Promise::Create(global, rv);
   MOZ_ASSERT(!rv.Failed());
 
   mReadyPromise = promise;
@@ -513,16 +518,83 @@ Telephony::StopTone(const Optional<uint3
   if (!IsValidServiceId(serviceId)) {
     aRv.Throw(NS_ERROR_INVALID_ARG);
     return;
   }
 
   aRv = mService->StopTone(serviceId);
 }
 
+void
+Telephony::OwnAudioChannel(ErrorResult& aRv)
+{
+  if (mAudioAgent) {
+    return;
+  }
+
+  mAudioAgent = do_CreateInstance("@mozilla.org/audiochannelagent;1");
+  MOZ_ASSERT(mAudioAgent);
+  aRv = mAudioAgent->Init(GetParentObject(),
+                         (int32_t)AudioChannel::Telephony, this);
+  if (NS_WARN_IF(aRv.Failed())) {
+    return;
+  }
+  aRv = HandleAudioAgentState();
+  if (NS_WARN_IF(aRv.Failed())) {
+    return;
+  }
+}
+
+nsresult
+Telephony::HandleAudioAgentState()
+{
+  if (!mAudioAgent) {
+    return NS_OK;
+  }
+
+  Nullable<OwningTelephonyCallOrTelephonyCallGroup> activeCall;
+  GetActive(activeCall);
+  nsresult rv;
+  // Only stop the agent when there's no call.
+  if ((!mCalls.Length() && !mGroup->CallsArray().Length()) &&
+       mIsAudioStartPlaying) {
+    mIsAudioStartPlaying = false;
+    rv = mAudioAgent->NotifyStoppedPlaying(mAudioAgentNotify);
+    mAudioAgent = nullptr;
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
+  } else if (!activeCall.IsNull() && !mIsAudioStartPlaying) {
+    mIsAudioStartPlaying = true;
+    float volume;
+    bool muted;
+    rv = mAudioAgent->NotifyStartedPlaying(mAudioAgentNotify, &volume, &muted);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
+
+    // In B2G, the system app manages audio playback policy. If there is a new
+    // sound want to be playback, it must wait for the permission from the
+    // system app. It means that the sound would be muted first, and then be
+    // unmuted. For telephony, the behaviors are hold() first, then resume().
+    // However, the telephony service can't handle all these requests within a
+    // short period. The telephony service would reject our resume request,
+    // because the modem have not changed the call state yet. It causes that
+    // the telephony can't be resumed. Therefore, we don't mute the telephony
+    // at the beginning.
+    volume = 1.0;
+    muted = false;
+    rv = WindowVolumeChanged(volume, muted);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
+  }
+  return NS_OK;
+}
+
 bool
 Telephony::GetMuted(ErrorResult& aRv) const
 {
   bool muted = false;
   aRv = mService->GetMicrophoneMuted(&muted);
 
   return muted;
 }
@@ -586,23 +658,87 @@ Telephony::GetReady(ErrorResult& aRv) co
     aRv.Throw(NS_ERROR_UNEXPECTED);
     return nullptr;
   }
 
   nsRefPtr<Promise> promise = mReadyPromise;
   return promise.forget();
 }
 
+// nsIAudioChannelAgentCallback
+
+NS_IMETHODIMP
+Telephony::WindowVolumeChanged(float aVolume, bool aMuted)
+{
+  // It's impossible to put all the calls on-hold in the multi-call case.
+  if (mCalls.Length() > 1 ||
+     (mCalls.Length() == 1 && mGroup->CallsArray().Length())) {
+    return NS_ERROR_FAILURE;
+  }
+
+  ErrorResult rv;
+  nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(GetOwner());
+  nsRefPtr<Promise> promise = Promise::Create(global, rv);
+  if (NS_WARN_IF(rv.Failed())) {
+    return rv.StealNSResult();
+  }
+
+  bool isSingleCall = mCalls.Length();
+  nsCOMPtr<nsITelephonyCallback> callback = new TelephonyCallback(promise);
+  if (isSingleCall) {
+    rv = aMuted ? mCalls[0]->Hold(callback) : mCalls[0]->Resume(callback);
+  } else {
+    rv = aMuted ? mGroup->Hold(callback) : mGroup->Resume(callback);
+  }
+  if (NS_WARN_IF(rv.Failed())) {
+    return rv.StealNSResult();
+  }
+
+  // These events will be triggered when the telephony is interrupted by other
+  // audio channel.
+  if (mMuted != aMuted) {
+    mMuted = aMuted;
+    // We should not dispatch "mozinterruptend" when the system app initializes
+    // the telephony audio from muted to unmuted at the first time. The event
+    // "mozinterruptend" must be dispatched after the "mozinterruptbegin".
+    if (!mHaveDispatchedInterruptBeginEvent && mMuted) {
+      DispatchTrustedEvent(NS_LITERAL_STRING("mozinterruptbegin"));
+      mHaveDispatchedInterruptBeginEvent = mMuted;
+    } else if (mHaveDispatchedInterruptBeginEvent && !mMuted) {
+      DispatchTrustedEvent(NS_LITERAL_STRING("mozinterruptend"));
+      mHaveDispatchedInterruptBeginEvent = mMuted;
+    }
+  }
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+Telephony::WindowAudioCaptureChanged()
+{
+  // Do nothing, it's useless for the telephony object.
+  return NS_OK;
+}
+
 // nsITelephonyListener
 
 NS_IMETHODIMP
 Telephony::CallStateChanged(uint32_t aLength, nsITelephonyCallInfo** aAllInfo)
 {
+  nsresult rv;
   for (uint32_t i = 0; i < aLength; ++i) {
-    HandleCallInfo(aAllInfo[i]);
+    rv = HandleCallInfo(aAllInfo[i]);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
+  }
+
+  rv = HandleAudioAgentState();
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
   }
   return NS_OK;
 }
 
 NS_IMETHODIMP
 Telephony::EnumerateCallState(nsITelephonyCallInfo* aInfo)
 {
   return HandleCallInfo(aInfo);
@@ -628,16 +764,17 @@ Telephony::EnumerateCallStateComplete()
         callState = nsITelephonyService::CALL_STATE_UNKNOWN;
         break;
       }
     }
 
     mGroup->ChangeState(callState);
   }
 
+  HandleAudioAgentState();
   if (mReadyPromise) {
     mReadyPromise->MaybeResolve(JS::UndefinedHandleValue);
   }
 
   if (NS_FAILED(mService->RegisterListener(mListener))) {
     NS_WARNING("Failed to register listener!");
   }
   return NS_OK;
--- a/dom/telephony/Telephony.h
+++ b/dom/telephony/Telephony.h
@@ -2,16 +2,18 @@
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_telephony_telephony_h__
 #define mozilla_dom_telephony_telephony_h__
 
+#include "AudioChannelService.h"
+
 #include "mozilla/dom/BindingDeclarations.h"
 #include "mozilla/dom/Promise.h"
 #include "mozilla/dom/telephony/TelephonyCommon.h"
 
 #include "nsITelephonyCallInfo.h"
 #include "nsITelephonyService.h"
 
 // Need to include TelephonyCall.h because we have inline methods that
@@ -26,41 +28,50 @@ namespace telephony {
 
 class TelephonyDialCallback;
 
 } // namespace telephony
 
 class OwningTelephonyCallOrTelephonyCallGroup;
 
 class Telephony final : public DOMEventTargetHelper,
+                        public nsIAudioChannelAgentCallback,
                         private nsITelephonyListener
 {
   /**
    * Class Telephony doesn't actually expose nsITelephonyListener.
    * Instead, it owns an nsITelephonyListener derived instance mListener
    * and passes it to nsITelephonyService. The onreceived events are first
    * delivered to mListener and then forwarded to its owner, Telephony. See
    * also bug 775997 comment #51.
    */
   class Listener;
 
   friend class telephony::TelephonyDialCallback;
 
+  // The audio agent is needed to communicate with the audio channel service.
+  nsCOMPtr<nsIAudioChannelAgent> mAudioAgent;
   nsCOMPtr<nsITelephonyService> mService;
   nsRefPtr<Listener> mListener;
 
   nsTArray<nsRefPtr<TelephonyCall> > mCalls;
   nsRefPtr<CallsList> mCallsList;
 
   nsRefPtr<TelephonyCallGroup> mGroup;
 
   nsRefPtr<Promise> mReadyPromise;
 
+  uint32_t mAudioAgentNotify;
+  bool mIsAudioStartPlaying;
+  bool mHaveDispatchedInterruptBeginEvent;
+  bool mMuted;
+
 public:
   NS_DECL_ISUPPORTS_INHERITED
+  NS_DECL_NSIAUDIOCHANNELAGENTCALLBACK
   NS_DECL_NSITELEPHONYLISTENER
   NS_REALLY_FORWARD_NSIDOMEVENTTARGET(DOMEventTargetHelper)
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(Telephony,
                                            DOMEventTargetHelper)
 
   nsPIDOMWindow*
   GetParentObject() const
   {
@@ -89,16 +100,25 @@ public:
 
   void
   StartTone(const nsAString& aDTMFChar, const Optional<uint32_t>& aServiceId,
             ErrorResult& aRv);
 
   void
   StopTone(const Optional<uint32_t>& aServiceId, ErrorResult& aRv);
 
+  // In the audio channel architecture, the system app needs to know the state
+  // of every audio channel, including the telephony. Therefore, when a
+  // telephony call is activated , the audio channel service would notify the
+  // system app about that. And we need an agent to communicate with the audio
+  // channel service. We would follow the call states to make a correct
+  // notification.
+  void
+  OwnAudioChannel(ErrorResult& aRv);
+
   bool
   GetMuted(ErrorResult& aRv) const;
 
   void
   SetMuted(bool aMuted, ErrorResult& aRv);
 
   bool
   GetSpeakerEnabled(ErrorResult& aRv) const;
@@ -208,14 +228,18 @@ private:
   already_AddRefed<TelephonyCall>
   GetCall(uint32_t aServiceId, uint32_t aCallIndex);
 
   already_AddRefed<TelephonyCall>
   GetCallFromEverywhere(uint32_t aServiceId, uint32_t aCallIndex);
 
   nsresult
   HandleCallInfo(nsITelephonyCallInfo* aInfo);
+
+  // Check the call states to decide whether need to send the notificaiton.
+  nsresult
+  HandleAudioAgentState();
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_telephony_telephony_h__
--- a/dom/telephony/TelephonyCall.cpp
+++ b/dom/telephony/TelephonyCall.cpp
@@ -319,74 +319,101 @@ TelephonyCall::HangUp(ErrorResult& aRv)
 already_AddRefed<Promise>
 TelephonyCall::Hold(ErrorResult& aRv)
 {
   nsRefPtr<Promise> promise = CreatePromise(aRv);
   if (!promise) {
     return nullptr;
   }
 
-  if (mCallState != nsITelephonyService::CALL_STATE_CONNECTED) {
-    NS_WARNING(nsPrintfCString("Hold non-connected call is rejected!"
-                               " (State: %u)", mCallState).get());
-    promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR);
-    return promise.forget();
-  }
-
-  if (mGroup) {
-    NS_WARNING("Hold a call in conference is rejected!");
-    promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR);
-    return promise.forget();
-  }
-
-  if (!mSwitchable) {
-    NS_WARNING("Hold a non-switchable call is rejected!");
-    promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR);
-    return promise.forget();
-  }
-
   nsCOMPtr<nsITelephonyCallback> callback = new TelephonyCallback(promise);
-  aRv = mTelephony->Service()->HoldCall(mServiceId, mCallIndex, callback);
-  NS_ENSURE_TRUE(!aRv.Failed(), nullptr);
-
-  if (mSecondId) {
-    // No state transition when we switch two numbers within one TelephonyCall
-    // object. Otherwise, the state here will be inconsistent with the backend
-    // RIL and will never be right.
-    return promise.forget();
+  aRv = Hold(callback);
+  if (NS_WARN_IF(aRv.Failed() &&
+                 !aRv.ErrorCodeIs(NS_ERROR_DOM_INVALID_STATE_ERR))) {
+    return nullptr;
   }
 
   return promise.forget();
 }
 
 already_AddRefed<Promise>
 TelephonyCall::Resume(ErrorResult& aRv)
 {
   nsRefPtr<Promise> promise = CreatePromise(aRv);
   if (!promise) {
     return nullptr;
   }
 
-  if (mCallState != nsITelephonyService::CALL_STATE_HELD) {
-    NS_WARNING(nsPrintfCString("Resume non-held call is rejected!"
+  nsCOMPtr<nsITelephonyCallback> callback = new TelephonyCallback(promise);
+  aRv = Resume(callback);
+  if (NS_WARN_IF(aRv.Failed() &&
+                 !aRv.ErrorCodeIs(NS_ERROR_DOM_INVALID_STATE_ERR))) {
+    return nullptr;
+  }
+
+  return promise.forget();
+}
+
+nsresult
+TelephonyCall::Hold(nsITelephonyCallback* aCallback)
+{
+  if (mCallState != nsITelephonyService::CALL_STATE_CONNECTED) {
+    NS_WARNING(nsPrintfCString("Hold non-connected call is rejected!"
                                " (State: %u)", mCallState).get());
-    promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR);
-    return promise.forget();
+    aCallback->NotifyError(NS_LITERAL_STRING("InvalidStateError"));
+    return NS_ERROR_DOM_INVALID_STATE_ERR;
+  }
+
+  if (mGroup) {
+    NS_WARNING("Hold a call in conference is rejected!");
+    aCallback->NotifyError(NS_LITERAL_STRING("InvalidStateError"));
+    return NS_ERROR_DOM_INVALID_STATE_ERR;
+  }
+
+  if (!mSwitchable) {
+    NS_WARNING("Hold a non-switchable call is rejected!");
+    aCallback->NotifyError(NS_LITERAL_STRING("InvalidStateError"));
+    return NS_ERROR_DOM_INVALID_STATE_ERR;
+  }
+
+  nsresult rv = mTelephony->Service()->HoldCall(mServiceId, mCallIndex, aCallback);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return NS_ERROR_FAILURE;
+  }
+
+  if (mSecondId) {
+    // No state transition when we switch two numbers within one TelephonyCall
+    // object. Otherwise, the state here will be inconsistent with the backend
+    // RIL and will never be right.
+    return NS_OK;
+  }
+
+  return NS_OK;
+}
+
+nsresult
+TelephonyCall::Resume(nsITelephonyCallback* aCallback)
+{
+  if (mCallState != nsITelephonyService::CALL_STATE_HELD) {
+    NS_WARNING("Resume non-held call is rejected!");
+    aCallback->NotifyError(NS_LITERAL_STRING("InvalidStateError"));
+    return NS_ERROR_DOM_INVALID_STATE_ERR;
   }
 
   if (mGroup) {
     NS_WARNING("Resume a call in conference is rejected!");
-    promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR);
-    return promise.forget();
+    aCallback->NotifyError(NS_LITERAL_STRING("InvalidStateError"));
+    return NS_ERROR_DOM_INVALID_STATE_ERR;
   }
 
   if (!mSwitchable) {
     NS_WARNING("Resume a non-switchable call is rejected!");
-    promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR);
-    return promise.forget();
+    aCallback->NotifyError(NS_LITERAL_STRING("InvalidStateError"));
+    return NS_ERROR_DOM_INVALID_STATE_ERR;
   }
 
-  nsCOMPtr<nsITelephonyCallback> callback = new TelephonyCallback(promise);
-  aRv = mTelephony->Service()->ResumeCall(mServiceId, mCallIndex, callback);
-  NS_ENSURE_TRUE(!aRv.Failed(), nullptr);
+  nsresult rv = mTelephony->Service()->ResumeCall(mServiceId, mCallIndex, aCallback);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return NS_ERROR_FAILURE;
+  }
 
-  return promise.forget();
-}
+  return NS_OK;
+}
\ No newline at end of file
--- a/dom/telephony/TelephonyCall.h
+++ b/dom/telephony/TelephonyCall.h
@@ -8,16 +8,18 @@
 #define mozilla_dom_telephony_telephonycall_h__
 
 #include "mozilla/dom/DOMError.h"
 #include "mozilla/dom/Promise.h"
 #include "mozilla/dom/TelephonyCallBinding.h"
 #include "mozilla/dom/TelephonyCallId.h"
 #include "mozilla/dom/telephony/TelephonyCommon.h"
 
+#include "nsITelephonyService.h"
+
 class nsPIDOMWindow;
 
 namespace mozilla {
 namespace dom {
 
 class TelephonyCall final : public DOMEventTargetHelper
 {
   nsRefPtr<Telephony> mTelephony;
@@ -180,16 +182,22 @@ public:
   void
   ChangeGroup(TelephonyCallGroup* aGroup);
 
 private:
   explicit TelephonyCall(nsPIDOMWindow* aOwner);
 
   ~TelephonyCall();
 
+  nsresult
+  Hold(nsITelephonyCallback* aCallback);
+
+  nsresult
+  Resume(nsITelephonyCallback* aCallback);
+
   void
   ChangeStateInternal(uint16_t aCallState, bool aFireEvents);
 
   nsresult
   DispatchCallEvent(const nsAString& aType,
                     TelephonyCall* aCall);
 
   already_AddRefed<Promise>
--- a/dom/telephony/TelephonyCallGroup.cpp
+++ b/dom/telephony/TelephonyCallGroup.cpp
@@ -342,43 +342,73 @@ TelephonyCallGroup::Hold(ErrorResult& aR
 {
   MOZ_ASSERT(!mCalls.IsEmpty());
 
   nsRefPtr<Promise> promise = CreatePromise(aRv);
   if (!promise) {
     return nullptr;
   }
 
-  if (mCallState != nsITelephonyService::CALL_STATE_CONNECTED) {
-    NS_WARNING("Holding a non-connected call is rejected!");
-    promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR);
-    return promise.forget();
+  nsCOMPtr<nsITelephonyCallback> callback = new TelephonyCallback(promise);
+  aRv = Hold(callback);
+  if (NS_WARN_IF(aRv.Failed() &&
+                 !aRv.ErrorCodeIs(NS_ERROR_DOM_INVALID_STATE_ERR))) {
+    return nullptr;
   }
 
-  nsCOMPtr<nsITelephonyCallback> callback = new TelephonyCallback(promise);
-  aRv = mTelephony->Service()->HoldConference(mCalls[0]->ServiceId(),
-                                              callback);
-  NS_ENSURE_TRUE(!aRv.Failed(), nullptr);
   return promise.forget();
 }
 
 already_AddRefed<Promise>
 TelephonyCallGroup::Resume(ErrorResult& aRv)
 {
   MOZ_ASSERT(!mCalls.IsEmpty());
 
   nsRefPtr<Promise> promise = CreatePromise(aRv);
   if (!promise) {
     return nullptr;
   }
 
-  if (mCallState != nsITelephonyService::CALL_STATE_HELD) {
-    NS_WARNING("Resuming a non-held call is rejected!");
-    promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR);
-    return promise.forget();
+  nsCOMPtr<nsITelephonyCallback> callback = new TelephonyCallback(promise);
+  aRv = Resume(callback);
+  if (NS_WARN_IF(aRv.Failed() &&
+                 !aRv.ErrorCodeIs(NS_ERROR_DOM_INVALID_STATE_ERR))) {
+    return nullptr;
+  }
+
+  return promise.forget();
+}
+
+nsresult
+TelephonyCallGroup::Hold(nsITelephonyCallback* aCallback)
+{
+  if (mCallState != nsITelephonyService::CALL_STATE_CONNECTED) {
+    NS_WARNING("Holding a non-connected call is rejected!");
+    aCallback->NotifyError(NS_LITERAL_STRING("InvalidStateError"));
+    return NS_ERROR_DOM_INVALID_STATE_ERR;
   }
 
-  nsCOMPtr<nsITelephonyCallback> callback = new TelephonyCallback(promise);
-  aRv = mTelephony->Service()->ResumeConference(mCalls[0]->ServiceId(),
-                                                callback);
-  NS_ENSURE_TRUE(!aRv.Failed(), nullptr);
-  return promise.forget();
+  nsresult rv = mTelephony->Service()->HoldConference(mCalls[0]->ServiceId(),
+                                                      aCallback);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return NS_ERROR_FAILURE;
+  }
+
+  return NS_OK;
 }
+
+nsresult
+TelephonyCallGroup::Resume(nsITelephonyCallback* aCallback)
+{
+  if (mCallState != nsITelephonyService::CALL_STATE_HELD) {
+    NS_WARNING("Resuming a non-held call is rejected!");
+    aCallback->NotifyError(NS_LITERAL_STRING("InvalidStateError"));
+    return NS_ERROR_DOM_INVALID_STATE_ERR;
+  }
+
+  nsresult rv = mTelephony->Service()->ResumeConference(mCalls[0]->ServiceId(),
+                                                        aCallback);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return NS_ERROR_FAILURE;
+  }
+
+  return NS_OK;
+}
--- a/dom/telephony/TelephonyCallGroup.h
+++ b/dom/telephony/TelephonyCallGroup.h
@@ -25,16 +25,18 @@ class TelephonyCallGroup final : public 
 
   uint16_t mCallState;
 
 public:
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(TelephonyCallGroup,
                                            DOMEventTargetHelper)
 
+  friend class Telephony;
+
   nsPIDOMWindow*
   GetParentObject() const
   {
     return GetOwner();
   }
 
   // WrapperCache
   virtual JSObject*
@@ -104,16 +106,22 @@ public:
   nsresult
   NotifyError(const nsAString& aName, const nsAString& aMessage);
 
 private:
   explicit TelephonyCallGroup(nsPIDOMWindow* aOwner);
   ~TelephonyCallGroup();
 
   nsresult
+  Hold(nsITelephonyCallback* aCallback);
+
+  nsresult
+  Resume(nsITelephonyCallback* aCallback);
+
+  nsresult
   NotifyCallsChanged(TelephonyCall* aCall);
 
   nsresult
   DispatchCallEvent(const nsAString& aType,
                     TelephonyCall* aCall);
 
   already_AddRefed<Promise>
   CreatePromise(ErrorResult& aRv);
--- a/dom/webidl/InputMethod.webidl
+++ b/dom/webidl/InputMethod.webidl
@@ -114,48 +114,62 @@ interface MozInputMethod : EventTarget {
   void setSelectedOptions(sequence<long> indexes);
 };
 
 /**
  * InputMethodManager contains a few of the global methods for the input app.
  */
 [JSImplementation="@mozilla.org/b2g-imm;1",
  Pref="dom.mozInputMethod.enabled",
- CheckAnyPermissions="input"]
+ CheckAnyPermissions="input input-manage"]
 interface MozInputMethodManager {
   /**
    * Ask the OS to show a list of available inputs for users to switch from.
    * OS should sliently ignore this request if the app is currently not the
    * active one.
    */
+  [CheckAllPermissions="input"]
   void showAll();
 
   /**
    * Ask the OS to switch away from the current active input app.
    * OS should sliently ignore this request if the app is currently not the
    * active one.
    */
+  [CheckAllPermissions="input"]
   void next();
 
   /**
-   * If this method returns true, it is recommented that the input app provides
+   * If this method returns true, it is recommended that the input app provides
    * a shortcut that would invoke the next() method above, for easy switching
    * between inputs -- i.e. show a "global" button on screen if the input app
    * implements an on-screen virtual keyboard.
    *
    * The returning value is depend on the inputType of the current input context.
    */
+  [CheckAllPermissions="input"]
   boolean supportsSwitching();
 
   /**
    * Ask the OS to remove the input focus, will cause the lost of input context.
    * OS should sliently ignore this request if the app is currently not the
    * active one.
    */
+  [CheckAllPermissions="input"]
   void hide();
+
+  /**
+   * Update Gecko with information on the input types which supportsSwitching()
+   * should return ture.
+   *
+   * @param types Array of input types in which supportsSwitching() should
+   *              return true.
+   */
+  [CheckAllPermissions="input-manage"]
+  void setSupportsSwitchingTypes(sequence<MozInputMethodInputContextInputTypes> types);
 };
 
 /**
  * The input context, which consists of attributes and information of current
  * input field. It also hosts the methods available to the keyboard app to
  * mutate the input field represented. An "input context" gets void when the
  * app is no longer allowed to interact with the text field,
  * e.g., the text field does no longer exist, the app is being switched to
--- a/dom/webidl/Telephony.webidl
+++ b/dom/webidl/Telephony.webidl
@@ -44,16 +44,22 @@ interface Telephony : EventTarget {
   Promise<void> sendTones(DOMString tones, optional unsigned long pauseDuration = 3000, optional unsigned long toneDuration = 70, optional unsigned long serviceId);
 
   [Throws]
   void startTone(DOMString tone, optional unsigned long serviceId);
 
   [Throws]
   void stopTone(optional unsigned long serviceId);
 
+  // Calling this method, the app will be treated as owner of the telephony
+  // calls from the AudioChannel policy.
+  [Throws,
+   CheckAllPermissions="audio-channel-telephony"]
+  void ownAudioChannel();
+
   [Throws]
   attribute boolean muted;
 
   [Throws]
   attribute boolean speakerEnabled;
 
   readonly attribute (TelephonyCall or TelephonyCallGroup)? active;
 
--- a/dom/wifi/test/marionette/manifest.ini
+++ b/dom/wifi/test/marionette/manifest.ini
@@ -5,18 +5,21 @@ qemu = true
 
 [test_wifi_enable.js]
 [test_wifi_scan.js]
 [test_wifi_associate.js]
 [test_wifi_associate_wo_connect.js]
 [test_wifi_auto_connect.js]
 [test_wifi_static_ip.js]
 [test_wifi_tethering_wifi_disabled.js]
+skip-if = android_version > '15' # Bug 1203075
 [test_wifi_tethering_wifi_inactive.js]
+skip-if = android_version > '15' # Bug 1203075
 [test_wifi_tethering_wifi_active.js]
+skip-if = android_version > '15' # Bug 1203075
 [test_wifi_manage_server_certificate.js]
 [test_wifi_manage_user_certificate.js]
 [test_wifi_manage_pkcs12_certificate.js]
 [test_wifi_associate_WPA_EAP_PEAP.js]
 disabled = Bug 1173697
 [test_wifi_associate_WPA_EAP_TTLS.js]
 disabled = Bug 1173697
 [test_wifi_associate_WPA_EAP_TLS.js]
--- a/dom/xbl/nsXBLService.cpp
+++ b/dom/xbl/nsXBLService.cpp
@@ -372,33 +372,29 @@ nsXBLStreamListener::HandleEvent(nsIDOME
 
   target->RemoveEventListener(NS_LITERAL_STRING("load"), this, false);
 
   return rv;
 }
 
 // Implementation /////////////////////////////////////////////////////////////////
 
-// Static member variable initialization
-bool nsXBLService::gAllowDataURIs = false;
-
 // Implement our nsISupports methods
 NS_IMPL_ISUPPORTS(nsXBLService, nsISupportsWeakReference)
 
 void
 nsXBLService::Init()
 {
   gInstance = new nsXBLService();
   NS_ADDREF(gInstance);
 }
 
 // Constructors/Destructors
 nsXBLService::nsXBLService(void)
 {
-  Preferences::AddBoolVarCache(&gAllowDataURIs, "layout.debug.enable_data_xbl");
 }
 
 nsXBLService::~nsXBLService(void)
 {
 }
 
 // static
 bool
@@ -842,91 +838,38 @@ nsXBLService::GetBinding(nsIContent* aBo
     }
 
     NS_ADDREF(*aResult = newBinding);
   }
 
   return NS_OK;
 }
 
-static bool SchemeIs(nsIURI* aURI, const char* aScheme)
-{
-  nsCOMPtr<nsIURI> baseURI = NS_GetInnermostURI(aURI);
-  NS_ENSURE_TRUE(baseURI, false);
-
-  bool isScheme = false;
-  return NS_SUCCEEDED(baseURI->SchemeIs(aScheme, &isScheme)) && isScheme;
-}
-
-static bool
-IsSystemOrChromeURLPrincipal(nsIPrincipal* aPrincipal)
-{
-  if (nsContentUtils::IsSystemPrincipal(aPrincipal)) {
-    return true;
-  }
-
-  nsCOMPtr<nsIURI> uri;
-  aPrincipal->GetURI(getter_AddRefs(uri));
-  NS_ENSURE_TRUE(uri, false);
-
-  bool isChrome = false;
-  return NS_SUCCEEDED(uri->SchemeIs("chrome", &isChrome)) && isChrome;
-}
-
 nsresult
 nsXBLService::LoadBindingDocumentInfo(nsIContent* aBoundElement,
                                       nsIDocument* aBoundDocument,
                                       nsIURI* aBindingURI,
                                       nsIPrincipal* aOriginPrincipal,
                                       bool aForceSyncLoad,
                                       nsXBLDocumentInfo** aResult)
 {
   NS_PRECONDITION(aBindingURI, "Must have a binding URI");
   NS_PRECONDITION(!aOriginPrincipal || aBoundDocument,
                   "If we're doing a security check, we better have a document!");
 
-  nsresult rv;
-  if (aOriginPrincipal) {
-    // Security check - Enforce same-origin policy, except to chrome.
-    // We have to be careful to not pass aContent as the context here.
-    // Otherwise, if there is a JS-implemented content policy, we will attempt
-    // to wrap the content node, which will try to load XBL bindings for it, if
-    // any. Since we're not done loading this binding yet, that will reenter
-    // this method and we'll end up creating a binding and then immediately
-    // clobbering it in our table.  That makes things very confused, leading to
-    // misbehavior and crashes.
-    rv = nsContentUtils::
-      CheckSecurityBeforeLoad(aBindingURI, aOriginPrincipal,
-                              nsIScriptSecurityManager::ALLOW_CHROME,
-                              gAllowDataURIs,
-                              nsIContentPolicy::TYPE_XBL,
-                              aBoundDocument);
-    NS_ENSURE_SUCCESS(rv, NS_ERROR_XBL_BLOCKED);
-
-    if (!IsSystemOrChromeURLPrincipal(aOriginPrincipal)) {
-      // Also make sure that we're same-origin with the bound document
-      // except if the stylesheet has the system principal.
-      if (!(gAllowDataURIs && SchemeIs(aBindingURI, "data")) &&
-          !SchemeIs(aBindingURI, "chrome")) {
-        rv = aBoundDocument->NodePrincipal()->CheckMayLoad(aBindingURI,
-                                                           true, false);
-        NS_ENSURE_SUCCESS(rv, NS_ERROR_XBL_BLOCKED);
-      }
-
-      // Finally check if this document is allowed to use XBL at all.
-      NS_ENSURE_TRUE(aBoundDocument->AllowXULXBL(),
-                     NS_ERROR_XBL_BLOCKED);
-    }
+  *aResult = nullptr;
+  if (aOriginPrincipal && !nsContentUtils::IsSystemPrincipal(aOriginPrincipal)) {
+    NS_ENSURE_TRUE(!aBoundDocument || aBoundDocument->AllowXULXBL(),
+                   NS_ERROR_XBL_BLOCKED);
   }
 
-  *aResult = nullptr;
   nsRefPtr<nsXBLDocumentInfo> info;
 
   nsCOMPtr<nsIURI> documentURI;
-  rv = aBindingURI->CloneIgnoringRef(getter_AddRefs(documentURI));
+  nsresult rv = aBindingURI->CloneIgnoringRef(getter_AddRefs(documentURI));
   NS_ENSURE_SUCCESS(rv, rv);
 
 #ifdef MOZ_XUL
   // We've got a file.  Check our XBL document cache.
   nsXULPrototypeCache* cache = nsXULPrototypeCache::GetInstance();
   bool useXULCache = cache && cache->IsEnabled();
 
   if (useXULCache) {
@@ -1000,19 +943,20 @@ nsXBLService::LoadBindingDocumentInfo(ns
       // document.
 
       // Always load chrome synchronously
       bool chrome;
       if (NS_SUCCEEDED(documentURI->SchemeIs("chrome", &chrome)) && chrome)
         aForceSyncLoad = true;
 
       nsCOMPtr<nsIDocument> document;
-      FetchBindingDocument(aBoundElement, aBoundDocument, documentURI,
-                           aBindingURI, aOriginPrincipal, aForceSyncLoad,
-                           getter_AddRefs(document));
+      rv = FetchBindingDocument(aBoundElement, aBoundDocument, documentURI,
+                                aBindingURI, aOriginPrincipal, aForceSyncLoad,
+                                getter_AddRefs(document));
+      NS_ENSURE_SUCCESS(rv, rv);
 
       if (document) {
         nsBindingManager *xblDocBindingManager = document->BindingManager();
         info = xblDocBindingManager->GetXBLDocumentInfo(documentURI);
         if (!info) {
           NS_ERROR("An XBL file is malformed.  Did you forget the XBL namespace on the bindings tag?");
           return NS_ERROR_FAILURE;
         }
@@ -1076,40 +1020,37 @@ nsXBLService::FetchBindingDocument(nsICo
   // set to null (to bypass security checks) when calling LoadBindingDocumentInfo() which calls
   // FetchBindingDocument().  LoadInfo will end up with no principal or node in those cases,
   // so we use systemPrincipal.  This achieves the same result of bypassing security checks,
   // but it gives the wrong information to potential future consumers of loadInfo.
   nsCOMPtr<nsIChannel> channel;
 
   if (aOriginPrincipal) {
     // if there is an originPrincipal we should also have aBoundDocument
-    NS_ASSERTION(aBoundDocument, "can not create a channel without aBoundDocument");
+    MOZ_ASSERT(aBoundDocument, "can not create a channel without aBoundDocument");
+
     rv = NS_NewChannelWithTriggeringPrincipal(getter_AddRefs(channel),
                                               aDocumentURI,
                                               aBoundDocument,
                                               aOriginPrincipal,
-                                              nsILoadInfo::SEC_NORMAL,
-                                              nsIContentPolicy::TYPE_OTHER,
+                                              nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_DATA_INHERITS |
+                                              nsILoadInfo::SEC_ALLOW_CHROME,
+                                              nsIContentPolicy::TYPE_XBL,
                                               loadGroup);
   }
   else {
     rv = NS_NewChannel(getter_AddRefs(channel),
                        aDocumentURI,
                        nsContentUtils::GetSystemPrincipal(),
-                       nsILoadInfo::SEC_NORMAL,
-                       nsIContentPolicy::TYPE_OTHER,
+                       nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_DATA_INHERITS,
+                       nsIContentPolicy::TYPE_XBL,
                        loadGroup);
   }
-
   NS_ENSURE_SUCCESS(rv, rv);
 
-  nsCOMPtr<nsIInterfaceRequestor> sameOriginChecker = nsContentUtils::SameOriginChecker();
-
-  channel->SetNotificationCallbacks(sameOriginChecker);
-
   if (!aForceSyncLoad) {
     // We can be asynchronous
     nsXBLStreamListener* xblListener =
       new nsXBLStreamListener(aBoundDocument, xblSink, doc);
 
     // Add ourselves to the list of loading docs.
     nsBindingManager *bindingManager;
     if (aBoundDocument)
@@ -1121,17 +1062,17 @@ nsXBLService::FetchBindingDocument(nsICo
       bindingManager->PutLoadingDocListener(aDocumentURI, xblListener);
 
     // Add our request.
     nsXBLBindingRequest* req = new nsXBLBindingRequest(aBindingURI,
                                                        aBoundElement);
     xblListener->AddRequest(req);
 
     // Now kick off the async read.
-    rv = channel->AsyncOpen(xblListener, nullptr);
+    rv = channel->AsyncOpen2(xblListener);
     if (NS_FAILED(rv)) {
       // Well, we won't be getting a load.  Make sure to clean up our stuff!
       if (bindingManager) {
         bindingManager->RemoveLoadingDocListener(aDocumentURI);
       }
     }
     return NS_OK;
   }
@@ -1143,17 +1084,17 @@ nsXBLService::FetchBindingDocument(nsICo
                               nullptr,
                               getter_AddRefs(listener),
                               true,
                               xblSink);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Now do a blocking synchronous parse of the file.
   nsCOMPtr<nsIInputStream> in;
-  rv = channel->Open(getter_AddRefs(in));
+  rv = channel->Open2(getter_AddRefs(in));
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = nsSyncLoadService::PushSyncStreamToListener(in, listener, channel);
   NS_ENSURE_SUCCESS(rv, rv);
 
   doc.swap(*aResult);
 
   return NS_OK;
--- a/dom/xbl/test/file_bug379959_cross.html
+++ b/dom/xbl/test/file_bug379959_cross.html
@@ -11,15 +11,22 @@
   -moz-binding: url(http://example.com/tests/dom/xbl/test/file_bug379959_xbl.xml#xbltest);
 }
 </style>
 <body>
 <div id="div1"></div>
 <div id="div2"></div>
 <script>
 onload = function() {
-  nodes = SpecialPowers.wrap(document).getAnonymousNodes(document.getElementById('div1'));
-  parent.postMessage(nodes ? nodes.length : 0, "http://mochi.test:8888");
-  nodes = SpecialPowers.wrap(document).getAnonymousNodes(document.getElementById('div2'));
-  parent.postMessage(nodes ? nodes.length : 0, "http://mochi.test:8888");
+  // same origin should be allowed
+  var nodes1 = SpecialPowers.wrap(document).getAnonymousNodes(document.getElementById('div1'));
+  parent.postMessage({test: "sameOriginIsAllowed",
+                      result: nodes1 ? nodes1.length : 0,
+                      senderURL: "http://mochi.test:8888"}, "*");
+
+  // cross origin should be blocked
+  var nodes2 = SpecialPowers.wrap(document).getAnonymousNodes(document.getElementById('div2'));
+  parent.postMessage({test: "crossOriginIsBlocked",
+                      result: nodes2 ? nodes2.length : 0,
+                      senderURL: "http://mochi.test:8888"}, "*");
 }
 </script>
 </html>
--- a/dom/xbl/test/file_bug379959_data.html
+++ b/dom/xbl/test/file_bug379959_data.html
@@ -6,13 +6,15 @@
   color: green;
   -moz-binding: url(data:text/xml;charset=utf-8,%3C%3Fxml%20version%3D%221.0%22%3F%3E%0A%3Cbindings%20id%3D%22xbltestBindings%22%20xmlns%3D%22http%3A//www.mozilla.org/xbl%22%3E%0A%20%20%3Cbinding%20id%3D%22xbltest%22%3E%3Ccontent%3EPASS%3C/content%3E%3C/binding%3E%0A%3C/bindings%3E%0A);
 }
 </style>
 <body>
 <div id="d"></div>
 <script>
 onload = function() {
-  nodes = SpecialPowers.wrap(document).getAnonymousNodes(document.getElementById('d'));
-  parent.postMessage(nodes ? nodes.length : 0, "http://mochi.test:8888");
+  var nodes = SpecialPowers.wrap(document).getAnonymousNodes(document.getElementById('d'));
+  parent.postMessage({test: "dataIsAllowed",
+                      result: nodes ? nodes.length : 0,
+                      senderURL: "http://mochi.test:8888"}, "*");
 }
 </script>
 </html>
--- a/dom/xbl/test/test_bug379959.html
+++ b/dom/xbl/test/test_bug379959.html
@@ -12,86 +12,58 @@ https://bugzilla.mozilla.org/show_bug.cg
   <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=379959">Mozilla Bug 379959</a>
   <p id="display">
     Note: In order to re-run this test correctly you need to shift-reload
     rather than simply reload. If you just reload we will restore the
     previous url in the iframe which will result in an extra unexpected
     message.
   </p>
   <div id="content" style="display: none"></div>
-  <iframe id="f"></iframe>
+  <iframe id="dataFrame"></iframe>
+  <iframe id="originFrame"></iframe>
 
   <pre id="test">
     <script class="testbody" type="application/javascript;version=1.7">
+
 SimpleTest.waitForExplicitFinish();
 
-var messages = 0;
+var seenData = false;
+var seenSameOrigin = false;
+var seenCrossOrign = false;
 
 function receiveMessage(e) {
   is(e.origin, "http://mochi.test:8888", "wrong sender!");
-  messages++;
 
-  switch (messages) {
-    case 1:
-      receiveMessage1(e.data);
-      break;
-    case 2:
-      receiveMessage2(e.data);
-      break;
-    case 3:
-      receiveMessage3(e.data);
-      break;
-    case 4:
-      receiveMessage4(e.data);
-      break;
-    default:
-      ok(false, "should not be reached");
-      Simpletest.finish();
+  if (e.data.test === "dataIsAllowed") {
+    is(e.data.result, 1, "data-url load should have succeeded");
+    seenData = true;
+  }
+  else if (e.data.test === "sameOriginIsAllowed") {
+    is(e.data.result, 1, "same site load should have succeeded");
+    seenSameOrigin = true;
+  }
+  else if (e.data.test === "crossOriginIsBlocked") {
+    is(e.data.result, 0, "cross site load should have failed");
+    seenCrossOrign = true;
+  }
+  else {
+    ok (false, "unrecognized test");
+  }
+
+  if (seenData && seenSameOrigin && seenCrossOrign) {
+    window.removeEventListener("message", receiveMessage, false);
+    SimpleTest.finish();
   }
 }
 
 window.addEventListener("message", receiveMessage, false);
 
-var iframe = document.getElementById('f');
-
 function runTest() {
-  // Test with data-urls off
-  SpecialPowers.pushPrefEnv({"set": [["layout.debug.enable_data_xbl", false]]}, runTest1);
-}
-
-function runTest1() {
-  iframe.src = "file_bug379959_data.html";
-}
-
-function receiveMessage1(aData) {
-  is(aData, 0, "data-url load should have failed");
-  // Test with data-urls on
-  SpecialPowers.pushPrefEnv({"set": [["layout.debug.enable_data_xbl", true]]}, runTest2);
-}
-
-function runTest2() {
-  iframe.src = "file_bug379959_data.html";
-}
-
-function receiveMessage2(aData) {
-  is(aData, 1, "data-url load should have been successful");
-  // Try a cross-site load
-  iframe.src = "file_bug379959_cross.html";
-}
-
-function receiveMessage3(aData) {
-  is(aData, 1, "same site load should have succeeded");
-}
-
-function receiveMessage4(aData) {
-  is(aData, 0, "cross site load should have failed");
-
-  // Check that we got the right number of messages to make sure that
-  // the right message has aligned with the right test
-  is(messages, 4, "wrong number of messages");
-
-  SimpleTest.finish();
+  // make sure data: is allowed
+  document.getElementById('dataFrame').src = "file_bug379959_data.html";
+  // make sure same-origin is allowed but cross site is blocked
+  document.getElementById('originFrame').src = "file_bug379959_cross.html";
 }
 
     </script>
   </pre>
 </body>
 </html>
--- a/editor/composer/test/chrome.ini
+++ b/editor/composer/test/chrome.ini
@@ -1,10 +1,11 @@
 [DEFAULT]
 skip-if = buildapp == 'b2g' || os == 'android'
 
 [test_async_UpdateCurrentDictionary.html]
 [test_bug338427.html]
 [test_bug434998.xul]
 [test_bug678842.html]
+[test_abug697981.html]
 [test_bug717433.html]
 [test_bug1204147.html]
 [test_bug1200533.html]
--- a/editor/composer/test/de-DE/de_DE.dic
+++ b/editor/composer/test/de-DE/de_DE.dic
@@ -1,4 +1,6 @@
-3
-Mary
-Paul
-Peter
+5
+ein
+guter
+heute
+ist
+Tag
new file mode 100644
--- /dev/null
+++ b/editor/composer/test/test_abug697981.html
@@ -0,0 +1,126 @@
+<!DOCTYPE html>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=697981
+-->
+<head>
+  <title>Test for Bug 697981</title>
+  <script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" />
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=697981">Mozilla Bug 697981</a>
+<p id="display"></p>
+</div>
+
+<textarea id="de-DE" lang="de-DE" onfocus="deFocus()">German heute ist ein guter Tag</textarea>
+<textarea id="en-US" lang="en-US" onfocus="enFocus()">Nogoodword today is a nice day</textarea>
+
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+function getMisspelledWords(editor) {
+  return editor.selectionController.getSelection(Components.interfaces.nsISelectionController.SELECTION_SPELLCHECK).toString();
+}
+
+var elem_de;
+var editor_de;
+var de_DE;
+var hunspell;
+
+/** Test for Bug 697981 **/
+/*
+ * Note the hack: This test fails of there are content preferences left behind from previous tests.
+ * That's why this test resides in a file "test_abug697981.html" so it runs first.
+ * We will fix this later.
+ */
+SimpleTest.waitForExplicitFinish();
+SimpleTest.waitForFocus(function() {
+  Components.utils.import("resource://gre/modules/AsyncSpellCheckTestHelper.jsm");
+
+  var dir = Components.classes["@mozilla.org/file/directory_service;1"]
+                      .getService(Components.interfaces.nsIProperties)
+                      .get("CurWorkD", Components.interfaces.nsIFile);
+  dir.append("tests");
+  dir.append("editor");
+  dir.append("composer");
+  dir.append("test");
+
+  hunspell = Components.classes["@mozilla.org/spellchecker/engine;1"]
+                       .getService(Components.interfaces.mozISpellCheckingEngine);
+
+  // Install de-DE dictionary.
+  de_DE = dir.clone();
+  de_DE.append("de-DE");
+  is(de_DE.exists(), true, "true expected (de_DE directory should exist)");
+  hunspell.addDirectory(de_DE);
+
+  document.getElementById('de-DE').focus();
+});
+
+function deFocus() {
+  elem_de = document.getElementById('de-DE');
+  editor_de = elem_de.QueryInterface(Components.interfaces.nsIDOMNSEditableElement).editor;
+  editor_de.setSpellcheckUserOverride(true);
+  var inlineSpellChecker = editor_de.getInlineSpellChecker(true);
+
+  onSpellCheck(elem_de, function () {
+    var spellchecker = inlineSpellChecker.spellChecker;
+    try {
+      var currentDictonary = spellchecker.GetCurrentDictionary();
+    } catch(e) {}
+
+    // Check that the German dictionary is loaded and that the spell check has worked.
+    is(currentDictonary, "de-DE", "expected de-DE");
+    is(getMisspelledWords(editor_de), "German", "one misspelled word expected: German");
+
+    // Now focus the other textarea, which requires English spelling.
+    document.getElementById('en-US').focus();
+  });
+}
+
+function enFocus() {
+  var elem_en = document.getElementById('en-US');
+  var editor_en = elem_en.QueryInterface(Components.interfaces.nsIDOMNSEditableElement).editor;
+  editor_en.setSpellcheckUserOverride(true);
+  var inlineSpellChecker = editor_en.getInlineSpellChecker(true);
+
+  onSpellCheck(elem_en, function () {
+    var spellchecker = inlineSpellChecker.spellChecker;
+    try {
+      currentDictonary = spellchecker.GetCurrentDictionary();
+    } catch(e) {}
+
+    // Check that the English dictionary is loaded and that the spell check has worked.
+    is(currentDictonary, "en-US", "expected en-US");
+    is(getMisspelledWords(editor_en), "Nogoodword", "one misspelled word expected: Nogoodword");
+
+    // So far all was boring. The important thing is whether the spell check result
+    // in the de-DE editor is still the same. After losing focus, no spell check
+    // updates should take place there.
+    is(getMisspelledWords(editor_de), "German", "one misspelled word expected: German");
+
+    // Remove the fake de_DE dictionary again.
+    hunspell.removeDirectory(de_DE);
+
+    // After removal, the de_DE editor should refresh the spelling with en-US.
+    onSpellCheck(elem_de, function () {
+      spellchecker = inlineSpellChecker.spellChecker;
+      try {
+        currentDictonary = spellchecker.GetCurrentDictionary();
+      } catch(e) {}
+
+      // Check that the default English dictionary is loaded and that the spell check has worked.
+      is(currentDictonary, "en-US", "expected en-US");
+      is(getMisspelledWords(editor_de), "heute" + "ist" + "ein" + "guter",
+         "some misspelled words expected: heute ist ein guter");
+
+      SimpleTest.finish();
+    });
+  });
+}
+
+</script>
+</pre>
+</body>
+</html>
--- a/editor/libeditor/nsEditor.cpp
+++ b/editor/libeditor/nsEditor.cpp
@@ -143,16 +143,17 @@ nsEditor::nsEditor()
 ,  mDocDirtyState(-1)
 ,  mSpellcheckCheckboxState(eTriUnset)
 ,  mShouldTxnSetSelection(true)
 ,  mDidPreDestroy(false)
 ,  mDidPostCreate(false)
 ,  mDispatchInputEvent(true)
 ,  mIsInEditAction(false)
 ,  mHidingCaret(false)
+,  mObservingDictionaryUpdates(false)
 {
 }
 
 nsEditor::~nsEditor()
 {
   NS_ASSERTION(!mDocWeak || mDidPreDestroy, "Why PreDestroy hasn't been called?");
 
   if (mComposition) {
@@ -302,17 +303,17 @@ nsEditor::PostCreate()
 
     // update the UI with our state
     NotifyDocumentListeners(eDocumentCreated);
     NotifyDocumentListeners(eDocumentStateChanged);
 
     nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
     if (obs) {
       obs->AddObserver(this,
-                       SPELLCHECK_DICTIONARY_UPDATE_NOTIFICATION,
+                       SPELLCHECK_DICTIONARY_REMOVE_NOTIFICATION,
                        false);
     }
   }
 
   // update nsTextStateManager and caret if we have focus
   nsCOMPtr<nsIContent> focusedContent = GetFocusedContent();
   if (focusedContent) {
     nsCOMPtr<nsIDOMEventTarget> target = do_QueryInterface(focusedContent);
@@ -446,16 +447,18 @@ nsEditor::PreDestroy(bool aDestroyingFra
     return NS_OK;
 
   IMEStateManager::OnEditorDestroying(this);
 
   nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
   if (obs) {
     obs->RemoveObserver(this,
                         SPELLCHECK_DICTIONARY_UPDATE_NOTIFICATION);
+    obs->RemoveObserver(this,
+                        SPELLCHECK_DICTIONARY_REMOVE_NOTIFICATION);
   }
 
   // Let spellchecker clean up its observers etc. It is important not to
   // actually free the spellchecker here, since the spellchecker could have
   // caused flush notifications, which could have gotten here if a textbox
   // is being removed. Setting the spellchecker to nullptr could free the
   // object that is still in use! It will be freed when the editor is
   // destroyed.
@@ -1310,17 +1313,19 @@ NS_IMETHODIMP nsEditor::GetInlineSpellCh
 
   return NS_OK;
 }
 
 NS_IMETHODIMP nsEditor::Observe(nsISupports* aSubj, const char *aTopic,
                                 const char16_t *aData)
 {
   NS_ASSERTION(!strcmp(aTopic,
-                       SPELLCHECK_DICTIONARY_UPDATE_NOTIFICATION),
+                       SPELLCHECK_DICTIONARY_UPDATE_NOTIFICATION) ||
+               !strcmp(aTopic,
+                       SPELLCHECK_DICTIONARY_REMOVE_NOTIFICATION),
                "Unexpected observer topic");
 
   // When mozInlineSpellChecker::CanEnableInlineSpellChecking changes
   SyncRealTimeSpell();
 
   // When nsIEditorSpellCheck::GetCurrentDictionary changes
   if (mInlineSpellChecker) {
     // if the current dictionary is no longer available, find another one
@@ -5197,16 +5202,39 @@ void
 nsEditor::OnFocus(nsIDOMEventTarget* aFocusEventTarget)
 {
   InitializeSelection(aFocusEventTarget);
   if (mInlineSpellChecker) {
     mInlineSpellChecker->UpdateCurrentDictionary();
   }
 }
 
+void
+nsEditor::StartWatchingDictionaryChanges()
+{
+  if (!mObservingDictionaryUpdates) {
+    nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
+    if (obs) {
+      obs->AddObserver(this, SPELLCHECK_DICTIONARY_UPDATE_NOTIFICATION, false);
+    }
+    mObservingDictionaryUpdates = true;
+  }
+}
+
+void
+nsEditor::StopWatchingDictionaryChanges()
+{
+  // Removing an observer that wasn't added doesn't cause any harm.
+  nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
+  if (obs) {
+    obs->RemoveObserver(this, SPELLCHECK_DICTIONARY_UPDATE_NOTIFICATION);
+  }
+  mObservingDictionaryUpdates = false;
+}
+
 NS_IMETHODIMP
 nsEditor::GetSuppressDispatchingInputEvent(bool *aSuppressed)
 {
   NS_ENSURE_ARG_POINTER(aSuppressed);
   *aSuppressed = !mDispatchInputEvent;
   return NS_OK;
 }
 
--- a/editor/libeditor/nsEditor.h
+++ b/editor/libeditor/nsEditor.h
@@ -244,16 +244,19 @@ public:
 
   // IME event handlers
   virtual nsresult BeginIMEComposition(mozilla::WidgetCompositionEvent* aEvent);
   virtual nsresult UpdateIMEComposition(nsIDOMEvent* aDOMTextEvent) = 0;
   void EndIMEComposition();
 
   void SwitchTextDirectionTo(uint32_t aDirection);
 
+  void StartWatchingDictionaryChanges();
+  void StopWatchingDictionaryChanges();
+
 protected:
   nsresult DetermineCurrentDirection();
   void FireInputEvent();
 
   /** Create a transaction for setting aAttribute to aValue on aElement.  Never
     * returns null.
     */
   already_AddRefed<mozilla::dom::ChangeAttributeTxn>
@@ -886,16 +889,17 @@ protected:
   uint8_t           mSpellcheckCheckboxState; // a Tristate value
 
   bool mShouldTxnSetSelection;  // turn off for conservative selection adjustment by txns
   bool mDidPreDestroy;    // whether PreDestroy has been called
   bool mDidPostCreate;    // whether PostCreate has been called
   bool mDispatchInputEvent;
   bool mIsInEditAction;   // true while the instance is handling an edit action
   bool mHidingCaret;      // whether caret is hidden forcibly.
+  bool mObservingDictionaryUpdates;  // whether the editor is observing dictionary changes.
 
   friend bool NSCanUnload(nsISupports* serviceMgr);
   friend class nsAutoTxnsConserveSelection;
   friend class nsAutoSelectionReset;
   friend class nsAutoRules;
   friend class nsRangeUpdater;
 };
 
--- a/editor/libeditor/nsEditorEventListener.cpp
+++ b/editor/libeditor/nsEditorEventListener.cpp
@@ -1109,32 +1109,36 @@ nsEditorEventListener::Focus(nsIDOMEvent
       nsCOMPtr<nsIDOMElement> element;
       fm->GetFocusedElement(getter_AddRefs(element));
       if (!SameCOMIdentity(element, target)) {
         return NS_OK;
       }
     }
   }
 
+  mEditor->StartWatchingDictionaryChanges();
+
   mEditor->OnFocus(target);
 
   nsCOMPtr<nsIPresShell> ps = GetPresShell();
   NS_ENSURE_TRUE(ps, NS_OK);
   nsCOMPtr<nsIContent> focusedContent = mEditor->GetFocusedContentForIME();
   IMEStateManager::OnFocusInEditor(ps->GetPresContext(), focusedContent,
                                    mEditor);
 
   return NS_OK;
 }
 
 nsresult
 nsEditorEventListener::Blur(nsIDOMEvent* aEvent)
 {
   NS_ENSURE_TRUE(aEvent, NS_OK);
 
+  mEditor->StopWatchingDictionaryChanges();
+
   // check if something else is focused. If another element is focused, then
   // we should not change the selection.
   nsIFocusManager* fm = nsFocusManager::GetFocusManager();
   NS_ENSURE_TRUE(fm, NS_OK);
 
   nsCOMPtr<nsIDOMElement> element;
   fm->GetFocusedElement(getter_AddRefs(element));
   if (!element) {
rename from extensions/spellcheck/hunspell/src/PRemoteSpellcheckEngine.ipdl
rename to extensions/spellcheck/hunspell/glue/PRemoteSpellcheckEngine.ipdl
rename from extensions/spellcheck/hunspell/src/RemoteSpellCheckEngineChild.cpp
rename to extensions/spellcheck/hunspell/glue/RemoteSpellCheckEngineChild.cpp
rename from extensions/spellcheck/hunspell/src/RemoteSpellCheckEngineChild.h
rename to extensions/spellcheck/hunspell/glue/RemoteSpellCheckEngineChild.h
rename from extensions/spellcheck/hunspell/src/RemoteSpellCheckEngineParent.cpp
rename to extensions/spellcheck/hunspell/glue/RemoteSpellCheckEngineParent.cpp
rename from extensions/spellcheck/hunspell/src/RemoteSpellCheckEngineParent.h
rename to extensions/spellcheck/hunspell/glue/RemoteSpellCheckEngineParent.h
rename from extensions/spellcheck/hunspell/src/hunspell_alloc_hooks.h
rename to extensions/spellcheck/hunspell/glue/hunspell_alloc_hooks.h
rename from extensions/spellcheck/hunspell/src/hunspell_fopen_hooks.h
rename to extensions/spellcheck/hunspell/glue/hunspell_fopen_hooks.h
copy from extensions/spellcheck/hunspell/src/moz.build
copy to extensions/spellcheck/hunspell/glue/moz.build
--- a/extensions/spellcheck/hunspell/src/moz.build
+++ b/extensions/spellcheck/hunspell/glue/moz.build
@@ -6,51 +6,30 @@
 
 SOURCES += [
     'mozHunspell.cpp',
     'mozHunspellDirProvider.cpp',
     'RemoteSpellCheckEngineChild.cpp',
     'RemoteSpellCheckEngineParent.cpp',
 ]
 
-if not CONFIG['MOZ_NATIVE_HUNSPELL']:
-    SOURCES += [
-        'affentry.cxx',
-        'affixmgr.cxx',
-        'csutil.cxx',
-        'dictmgr.cxx',
-        'filemgr.cxx',
-        'hashmgr.cxx',
-        'hunspell.cxx',
-        'hunzip.cxx',
-        'phonet.cxx',
-        'replist.cxx',
-        'suggestmgr.cxx',
-    ]
-    # This variable is referenced in configure.in.  Make sure to change that file
-    # too if you need to change this variable.
-    DEFINES['HUNSPELL_STATIC'] = True
-else:
-    CXXFLAGS += CONFIG['MOZ_HUNSPELL_CFLAGS']
+CXXFLAGS += CONFIG['MOZ_HUNSPELL_CFLAGS']
 
 FINAL_LIBRARY = 'xul'
 
 LOCAL_INCLUDES += [
+    '../src',
     '/dom/base',
     '/editor/libeditor',
     '/extensions/spellcheck/src',
 ]
 
-# XXX: This directory is a mix of Mozilla code and third-party code. We should
-# put the Mozilla code in a separate directory and disallow compiler warnings
-# there (bug 1200065). Until then, allow warnings for all of the code.
-ALLOW_COMPILER_WARNINGS = True
-
 include('/ipc/chromium/chromium-config.mozbuild')
 
 IPDL_SOURCES = [
     'PRemoteSpellcheckEngine.ipdl',
 ]
 
 EXPORTS.mozilla += [
      'RemoteSpellCheckEngineChild.h',
      'RemoteSpellCheckEngineParent.h',
 ]
+
rename from extensions/spellcheck/hunspell/src/mozHunspell.cpp
rename to extensions/spellcheck/hunspell/glue/mozHunspell.cpp
--- a/extensions/spellcheck/hunspell/src/mozHunspell.cpp
+++ b/extensions/spellcheck/hunspell/glue/mozHunspell.cpp
@@ -599,10 +599,16 @@ NS_IMETHODIMP mozHunspell::AddDirectory(
   LoadDictionaryList(true);
   return NS_OK;
 }
 
 NS_IMETHODIMP mozHunspell::RemoveDirectory(nsIFile *aDir)
 {
   mDynamicDirectories.RemoveObject(aDir);
   LoadDictionaryList(true);
+  nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
+  if (obs) {
+    obs->NotifyObservers(nullptr,
+                         SPELLCHECK_DICTIONARY_REMOVE_NOTIFICATION,
+                         nullptr);
+  }
   return NS_OK;
 }
rename from extensions/spellcheck/hunspell/src/mozHunspell.h
rename to extensions/spellcheck/hunspell/glue/mozHunspell.h
rename from extensions/spellcheck/hunspell/src/mozHunspellAllocator.h
rename to extensions/spellcheck/hunspell/glue/mozHunspellAllocator.h
rename from extensions/spellcheck/hunspell/src/mozHunspellDirProvider.cpp
rename to extensions/spellcheck/hunspell/glue/mozHunspellDirProvider.cpp
rename from extensions/spellcheck/hunspell/src/mozHunspellDirProvider.h
rename to extensions/spellcheck/hunspell/glue/mozHunspellDirProvider.h
--- a/extensions/spellcheck/hunspell/moz.build
+++ b/extensions/spellcheck/hunspell/moz.build
@@ -1,10 +1,12 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # 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/.
 
-DIRS += ['src']
+DIRS += ['glue']
+if not CONFIG['MOZ_NATIVE_HUNSPELL']:
+    DIRS += ['src']
 
 if CONFIG['ENABLE_TESTS']:
-    XPCSHELL_TESTS_MANIFESTS += ['tests/unit/xpcshell.ini']
+    XPCSHELL_TESTS_MANIFESTS += ['tests/unit/xpcshell.ini']    
--- a/extensions/spellcheck/hunspell/src/moz.build
+++ b/extensions/spellcheck/hunspell/src/moz.build
@@ -1,56 +1,34 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # 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/.
 
 SOURCES += [
-    'mozHunspell.cpp',
-    'mozHunspellDirProvider.cpp',
-    'RemoteSpellCheckEngineChild.cpp',
-    'RemoteSpellCheckEngineParent.cpp',
+    'affentry.cxx',
+    'affixmgr.cxx',
+    'csutil.cxx',
+    'dictmgr.cxx',
+    'filemgr.cxx',
+    'hashmgr.cxx',
+    'hunspell.cxx',
+    'hunzip.cxx',
+    'phonet.cxx',
+    'replist.cxx',
+    'suggestmgr.cxx',
 ]
 
-if not CONFIG['MOZ_NATIVE_HUNSPELL']:
-    SOURCES += [
-        'affentry.cxx',
-        'affixmgr.cxx',
-        'csutil.cxx',
-        'dictmgr.cxx',
-        'filemgr.cxx',
-        'hashmgr.cxx',
-        'hunspell.cxx',
-        'hunzip.cxx',
-        'phonet.cxx',
-        'replist.cxx',
-        'suggestmgr.cxx',
-    ]
-    # This variable is referenced in configure.in.  Make sure to change that file
-    # too if you need to change this variable.
-    DEFINES['HUNSPELL_STATIC'] = True
-else:
-    CXXFLAGS += CONFIG['MOZ_HUNSPELL_CFLAGS']
+# This variable is referenced in configure.in.  Make sure to change that file
+# too if you need to change this variable.
+DEFINES['HUNSPELL_STATIC'] = True
 
 FINAL_LIBRARY = 'xul'
 
 LOCAL_INCLUDES += [
-    '/dom/base',
-    '/editor/libeditor',
-    '/extensions/spellcheck/src',
+    '../glue',
 ]
 
-# XXX: This directory is a mix of Mozilla code and third-party code. We should
-# put the Mozilla code in a separate directory and disallow compiler warnings
-# there (bug 1200065). Until then, allow warnings for all of the code.
 ALLOW_COMPILER_WARNINGS = True
 
 include('/ipc/chromium/chromium-config.mozbuild')
 
-IPDL_SOURCES = [
-    'PRemoteSpellcheckEngine.ipdl',
-]
-
-EXPORTS.mozilla += [
-     'RemoteSpellCheckEngineChild.h',
-     'RemoteSpellCheckEngineParent.h',
-]
--- a/extensions/spellcheck/idl/mozISpellCheckingEngine.idl
+++ b/extensions/spellcheck/idl/mozISpellCheckingEngine.idl
@@ -99,9 +99,11 @@ interface mozISpellCheckingEngine : nsIS
 };
 
 %{C++
 #define DICTIONARY_SEARCH_DIRECTORY "DictD"
 #define DICTIONARY_SEARCH_DIRECTORY_LIST "DictDL"
 
 #define SPELLCHECK_DICTIONARY_UPDATE_NOTIFICATION \
   "spellcheck-dictionary-update"
+#define SPELLCHECK_DICTIONARY_REMOVE_NOTIFICATION \
+  "spellcheck-dictionary-remove"
 %}
--- a/extensions/spellcheck/src/moz.build
+++ b/extensions/spellcheck/src/moz.build
@@ -14,15 +14,16 @@ SOURCES += [
     'mozSpellChecker.cpp',
     'mozSpellCheckerFactory.cpp',
     'mozSpellI18NManager.cpp',
 ]
 
 FINAL_LIBRARY = 'xul'
 
 LOCAL_INCLUDES += [
+    '../hunspell/glue',
     '../hunspell/src',
     '/dom/base',
     '/editor/libeditor',
 ]
 EXPORTS.mozilla += [
      'mozSpellChecker.h',
 ]
--- a/gfx/layers/ipc/CompositorParent.cpp
+++ b/gfx/layers/ipc/CompositorParent.cpp
@@ -1631,17 +1631,16 @@ class CrossProcessCompositorParent final
                                            public ShadowLayersManager
 {
   friend class CompositorParent;
 
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING_WITH_MAIN_THREAD_DESTRUCTION(CrossProcessCompositorParent)
 public:
   explicit CrossProcessCompositorParent(Transport* aTransport)
     : mTransport(aTransport)
-    , mCompositorThreadHolder(sCompositorThreadHolder)
     , mNotifyAfterRemotePaint(false)
   {
     MOZ_ASSERT(NS_IsMainThread());
   }
 
   // IToplevelProtocol::CloneToplevel()
   virtual IToplevelProtocol*
   CloneToplevel(const InfallibleTArray<mozilla::ipc::ProtocolFdMapping>& aFds,
@@ -1721,16 +1720,18 @@ public:
                                       const nsTArray<ScrollableLayerGuid>& aTargets) override;
 
   virtual AsyncCompositionManager* GetCompositionManager(LayerTransactionParent* aParent) override;
 
   void DidComposite(uint64_t aId,
                     TimeStamp& aCompositeStart,
                     TimeStamp& aCompositeEnd);
 
+protected:
+  void OnChannelConnected(int32_t pid) override { mCompositorThreadHolder = sCompositorThreadHolder; }
 private:
   // Private destructor, to discourage deletion outside of Release():
   virtual ~CrossProcessCompositorParent();
 
   void DeferredDestroy();
 
   // There can be many CPCPs, and IPDL-generated code doesn't hold a
   // reference to top-level actors.  So we hold a reference to
--- a/gfx/layers/ipc/ImageBridgeParent.cpp
+++ b/gfx/layers/ipc/ImageBridgeParent.cpp
@@ -53,17 +53,16 @@ MessageLoop* ImageBridgeParent::sMainLoo
 CompositorThreadHolder* GetCompositorThreadHolder();
 
 ImageBridgeParent::ImageBridgeParent(MessageLoop* aLoop,
                                      Transport* aTransport,
                                      ProcessId aChildProcessId)
   : mMessageLoop(aLoop)
   , mTransport(aTransport)
   , mSetChildThreadPriority(false)
-  , mCompositorThreadHolder(GetCompositorThreadHolder())
 {
   MOZ_ASSERT(NS_IsMainThread());
   sMainLoop = MessageLoop::current();
 
   // top-level actors must be destroyed on the main thread.
   SetMessageLoopToPostDestructionTo(sMainLoop);
 
   // creates the map only if it has not been created already, so it is safe
@@ -380,16 +379,22 @@ ImageBridgeParent::CloneToplevel(const I
       bridge->CloneManagees(this, aCtx);
       bridge->IToplevelProtocol::SetTransport(transport);
       return bridge;
     }
   }
   return nullptr;
 }
 
+void
+ImageBridgeParent::OnChannelConnected(int32_t aPid)
+{
+  mCompositorThreadHolder = GetCompositorThreadHolder();
+}
+
 bool ImageBridgeParent::IsSameProcess() const
 {
   return OtherPid() == base::GetCurrentProcId();
 }
 
 void
 ImageBridgeParent::ReplyRemoveTexture(const OpReplyRemoveTexture& aReply)
 {
--- a/gfx/layers/ipc/ImageBridgeParent.h
+++ b/gfx/layers/ipc/ImageBridgeParent.h
@@ -146,16 +146,19 @@ public:
   static bool NotifyImageComposites(nsTArray<ImageCompositeNotification>& aNotifications);
 
   // Overriden from IToplevelProtocol
   IToplevelProtocol*
   CloneToplevel(const InfallibleTArray<ProtocolFdMapping>& aFds,
                 base::ProcessHandle aPeerProcess,
                 mozilla::ipc::ProtocolCloneContext* aCtx) override;
 
+protected:
+  void OnChannelConnected(int32_t pid) override;
+
 private:
   void DeferredDestroy();
   MessageLoop* mMessageLoop;
   Transport* mTransport;
   // This keeps us alive until ActorDestroy(), at which point we do a
   // deferred destruction of ourselves.
   nsRefPtr<ImageBridgeParent> mSelfRef;
 
--- a/gfx/vr/moz.build
+++ b/gfx/vr/moz.build
@@ -32,15 +32,12 @@ SOURCES += [
 #CXXFLAGS += ["-Ic:/proj/ovr/OculusSDK-0.6.0-beta/LibOVR/Include"]
 #CFLAGS += ["-Ic:/proj/ovr/OculusSDK-0.6.0-beta/LibOVR/Include"]
 
 CXXFLAGS += CONFIG['MOZ_CAIRO_CFLAGS']
 CXXFLAGS += CONFIG['TK_CFLAGS']
 CFLAGS += CONFIG['MOZ_CAIRO_CFLAGS']
 CFLAGS += CONFIG['TK_CFLAGS']
 
-if CONFIG['_MSC_VER']:
-    ALLOW_COMPILER_WARNINGS = True
-
 include('/ipc/chromium/chromium-config.mozbuild')
 
 FINAL_LIBRARY = 'xul'
 
--- a/ipc/app/moz.build
+++ b/ipc/app/moz.build
@@ -108,17 +108,13 @@ LDFLAGS += [CONFIG['MOZ_ALLOW_HEAP_EXECU
 #
 # The default heap size is 1MB on Win32.
 # The heap will grow if need be.
 #
 # Set it to 256k.  See bug 127069.
 if CONFIG['OS_ARCH'] == 'WINNT' and not CONFIG['GNU_CC']:
     LDFLAGS += ['/HEAP:0x40000']
 
-# Windows builds have dll linkage warnings due to msvcrt static linkage
-if CONFIG['OS_ARCH'] == 'WINNT':
-    ALLOW_COMPILER_WARNINGS = True
-
 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
     OS_LIBS += [
         'binder',
         'utils',
     ]
--- a/js/public/ProfilingStack.h
+++ b/js/public/ProfilingStack.h
@@ -62,18 +62,21 @@ class ProfileEntry
         // This ProfileEntry is a dummy entry indicating the start of a run
         // of JS pseudostack entries.
         BEGIN_PSEUDO_JS = 0x04,
 
         // This flag is used to indicate that an interpreter JS entry has OSR-ed
         // into baseline.
         OSR = 0x08,
 
+        // Union of all flags.
+        ALL = IS_CPP_ENTRY|FRAME_LABEL_COPY|BEGIN_PSEUDO_JS|OSR,
+
         // Mask for removing all flags except the category information.
-        CATEGORY_MASK = ~IS_CPP_ENTRY & ~FRAME_LABEL_COPY & ~BEGIN_PSEUDO_JS & ~OSR
+        CATEGORY_MASK = ~ALL
     };
 
     // Keep these in sync with browser/devtools/performance/modules/global.js
     enum class Category : uint32_t {
         OTHER    = 0x10,
         CSS      = 0x20,
         JS       = 0x40,
         GC       = 0x80,
@@ -82,16 +85,19 @@ class ProfileEntry
         GRAPHICS = 0x400,
         STORAGE  = 0x800,
         EVENTS   = 0x1000,
 
         FIRST    = OTHER,
         LAST     = EVENTS
     };
 
+    static_assert((static_cast<int>(Category::FIRST) & Flags::ALL) == 0,
+                  "The category bitflags should not intersect with the other flags!");
+
     // All of these methods are marked with the 'volatile' keyword because SPS's
     // representation of the stack is stored such that all ProfileEntry
     // instances are volatile. These methods would not be available unless they
     // were marked as volatile as well.
 
     bool isCpp() const volatile { return hasFlag(IS_CPP_ENTRY); }
     bool isJs() const volatile { return !isCpp(); }
 
--- a/js/public/UbiNodeCensus.h
+++ b/js/public/UbiNodeCensus.h
@@ -4,16 +4,18 @@
  * 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 js_UbiNodeCensus_h
 #define js_UbiNodeCensus_h
 
 #include "mozilla/Move.h"
 
+#include "jsapi.h"
+
 #include "js/UbiNode.h"
 #include "js/UbiNodeTraverse.h"
 
 // A census is a ubi::Node traversal that assigns each node to one or more
 // buckets, and returns a report with the size of each bucket.
 //
 // We summarize the results of a census with counts broken down according to
 // criteria selected by the API consumer code that is requesting the census. For
--- a/js/src/aclocal.m4
+++ b/js/src/aclocal.m4
@@ -26,16 +26,17 @@ builtin(include, ../../build/autoconf/an
 builtin(include, ../../build/autoconf/zlib.m4)dnl
 builtin(include, ../../build/autoconf/linux.m4)dnl
 builtin(include, ../../build/autoconf/python-virtualenv.m4)dnl
 builtin(include, ../../build/autoconf/winsdk.m4)dnl
 builtin(include, ../../build/autoconf/icu.m4)dnl
 builtin(include, ../../build/autoconf/ffi.m4)dnl
 builtin(include, ../../build/autoconf/clang-plugin.m4)dnl
 builtin(include, ../../build/autoconf/alloc.m4)dnl
+builtin(include, ../../build/autoconf/jemalloc.m4)dnl
 
 define([__MOZ_AC_INIT_PREPARE], defn([AC_INIT_PREPARE]))
 define([AC_INIT_PREPARE],
 [if test -z "$srcdir"; then
   srcdir=`dirname "[$]0"`
 fi
 srcdir="$srcdir/../.."
 __MOZ_AC_INIT_PREPARE($1)
--- a/js/src/asmjs/AsmJSValidate.cpp
+++ b/js/src/asmjs/AsmJSValidate.cpp
@@ -12371,22 +12371,22 @@ CheckModule(ExclusiveContext* cx, AsmJSP
         return false;
 
     if (!CheckModuleProcessingDirectives(m))
         return false;
 
     if (!CheckModuleGlobals(m))
         return false;
 
+    m.startFunctionBodies();
+
 #if !defined(ENABLE_SHARED_ARRAY_BUFFER)
     MOZ_ASSERT(!m.module().hasArrayView() || !m.module().isSharedView());
 #endif
 
-    m.startFunctionBodies();
-
     ScopedJSDeletePtr<ModuleCompileResults> mcd;
     if (!CheckFunctions(m, &mcd))
         return false;
 
     if (!m.finishFunctionBodies(&mcd))
         return false;
 
     if (!CheckFuncPtrTables(m))
--- a/js/src/configure.in
+++ b/js/src/configure.in
@@ -2397,16 +2397,17 @@ if test "$ac_cv_clock_monotonic" != "no"
     AC_DEFINE(HAVE_CLOCK_MONOTONIC)
     AC_SUBST(HAVE_CLOCK_MONOTONIC)
     AC_SUBST_LIST(REALTIME_LIBS)
 fi
 
 dnl Checks for math functions.
 dnl ========================================================
 AC_CHECK_LIB(m, sin)
+AC_CHECK_LIB(m, __sincos, AC_DEFINE(HAVE_SINCOS))
 AC_CHECK_FUNCS([log2 log1p expm1 sqrt1pm1 acosh asinh atanh cbrt])
 
 
 dnl check for wcrtomb/mbrtowc
 dnl =======================================================================
 if test -z "$MACOS_DEPLOYMENT_TARGET" || test "$MACOS_DEPLOYMENT_TARGET" -ge "100300"; then
 AC_LANG_SAVE
 AC_LANG_CPLUSPLUS
@@ -2976,16 +2977,20 @@ if test "$MOZ_MEMORY"; then
     AC_DEFINE(MOZ_MEMORY_WINDOWS)
     ;;
   *)
     AC_MSG_ERROR([--enable-jemalloc not supported on ${target}])
     ;;
   esac
 fi
 AC_SUBST(MOZ_MEMORY)
+AC_SUBST(MOZ_JEMALLOC4)
+if test -n "$MOZ_JEMALLOC4"; then
+  AC_DEFINE(MOZ_JEMALLOC4)
+fi
 AC_SUBST(MOZ_CRT)
 AC_SUBST(MOZ_GLUE_IN_PROGRAM)
 AC_SUBST_LIST(MOZ_GLUE_WRAP_LDFLAGS)
 
 dnl ========================================================
 dnl = Use malloc wrapper lib
 dnl ========================================================
 MOZ_ARG_ENABLE_BOOL(wrap-malloc,
@@ -3824,16 +3829,17 @@ fi
 AC_SUBST(JS_LIBRARY_NAME)
 AC_SUBST(JS_CONFIG_MOZ_JS_LIBS)
 AC_SUBST(JS_CONFIG_LIBS)
 
 if test -n "$MOZ_BUILD_NSPR"; then
     MOZ_SUBCONFIGURE_NSPR()
 fi
 MOZ_SUBCONFIGURE_FFI()
+MOZ_SUBCONFIGURE_JEMALLOC()
 
 dnl Spit out some output
 dnl ========================================================
 MOZ_CREATE_CONFIG_STATUS()
 
 if test "$JS_STANDALONE"; then
   MOZ_RUN_CONFIG_STATUS()
 fi
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/ion/bug984018.js
@@ -0,0 +1,62 @@
+var x = 0;
+function test() {
+    function sincos1(a, b) {
+        var sa = Math.sin(a);
+        var sb = Math.sin(b);
+        var ca = Math.cos(a);
+        var cb = Math.cos(b);
+        var ra = sa * sa + ca * ca;
+        var rb = sb * sb + cb * cb;
+        var dec = 100000;
+
+        assertEq(Math.round(ra * dec) / dec, Math.round(rb * dec) / dec);
+
+        ca = Math.cos(a);
+        cb = Math.cos(b);
+        sa = Math.sin(a);
+        sb = Math.sin(b);
+
+        var ra = sa * sa + ca * ca;
+        var rb = sb * sb + cb * cb;
+
+        assertEq(Math.round(ra * dec) / dec, Math.round(rb * dec) / dec);
+        return ra;
+    }
+
+    function sincos2(x) {
+        var s1 = Math.sin(x);
+        var c1 = Math.cos(x);
+
+        var c2 = Math.cos(x);
+        var s2 = Math.sin(x);
+        
+        return (s1 * s1 + c1 * c1) - (s2 * s2 + c2 * c2); 
+    }
+
+    function bailoutHere() { bailout(); }
+
+    function sincos3(x) {
+        var s = Math.sin(x);
+        bailoutHere();
+        var c = Math.cos(x);
+        assertEq(Math.round(s * s + c * c), 1);
+        return s;
+    }
+
+    function sincos4(x) {
+        if (x < 2500)
+            x = Math.sin(x);
+        else
+            x = Math.cos(x);
+        return x;
+    }
+
+    for (var i=0; i<5000; i++) {
+        x += sincos1(x, x + 1);
+        x += sincos2(x);
+        x += sincos3(x);
+        x += sincos4(i);
+    }
+}
+x += 1;
+test();
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -6395,16 +6395,52 @@ CodeGenerator::visitFromCharCode(LFromCh
                   ool->entry());
 
     masm.movePtr(ImmPtr(&GetJitContext()->runtime->staticStrings().unitStaticTable), output);
     masm.loadPtr(BaseIndex(output, code, ScalePointer), output);
 
     masm.bind(ool->rejoin());
 }
 
+void
+CodeGenerator::visitSinCos(LSinCos *lir)
+{
+    Register temp = ToRegister(lir->temp());
+    Register params = ToRegister(lir->temp2());
+    FloatRegister input = ToFloatRegister(lir->input());
+    FloatRegister outputSin = ToFloatRegister(lir->outputSin());
+    FloatRegister outputCos = ToFloatRegister(lir->outputCos());
+
+    masm.reserveStack(sizeof(double) * 2);
+    masm.movePtr(masm.getStackPointer(), params);
+
+    const MathCache* mathCache = lir->mir()->cache();
+
+    masm.setupUnalignedABICall(temp);
+    if (mathCache) {
+        masm.movePtr(ImmPtr(mathCache), temp);
+        masm.passABIArg(temp);
+    }
+
+#define MAYBE_CACHED_(fcn) (mathCache ? (void*)fcn ## _impl : (void*)fcn ## _uncached)
+
+    masm.passABIArg(input, MoveOp::DOUBLE);
+    masm.passABIArg(MoveOperand(params, sizeof(double), MoveOperand::EFFECTIVE_ADDRESS),
+                                MoveOp::GENERAL);
+    masm.passABIArg(MoveOperand(params, 0, MoveOperand::EFFECTIVE_ADDRESS),
+                                MoveOp::GENERAL);
+
+    masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, MAYBE_CACHED_(js::math_sincos)));
+#undef MAYBE_CACHED_
+
+    masm.loadDouble(Address(masm.getStackPointer(), 0), outputCos);
+    masm.loadDouble(Address(masm.getStackPointer(), sizeof(double)), outputSin);
+    masm.freeStack(sizeof(double) * 2);
+}
+
 typedef JSObject* (*StringSplitFn)(JSContext*, HandleObjectGroup, HandleString, HandleString);
 static const VMFunction StringSplitInfo = FunctionInfo<StringSplitFn>(js::str_split_string);
 
 void
 CodeGenerator::visitStringSplit(LStringSplit* lir)
 {
     pushArg(ToRegister(lir->separator()));
     pushArg(ToRegister(lir->string()));
--- a/js/src/jit/CodeGenerator.h
+++ b/js/src/jit/CodeGenerator.h
@@ -237,16 +237,17 @@ class CodeGenerator : public CodeGenerat
     void visitIsNullOrLikeUndefinedV(LIsNullOrLikeUndefinedV* lir);
     void visitIsNullOrLikeUndefinedT(LIsNullOrLikeUndefinedT* lir);
     void visitIsNullOrLikeUndefinedAndBranchV(LIsNullOrLikeUndefinedAndBranchV* lir);
     void visitIsNullOrLikeUndefinedAndBranchT(LIsNullOrLikeUndefinedAndBranchT* lir);
     void emitConcat(LInstruction* lir, Register lhs, Register rhs, Register output);
     void visitConcat(LConcat* lir);
     void visitCharCodeAt(LCharCodeAt* lir);
     void visitFromCharCode(LFromCharCode* lir);
+    void visitSinCos(LSinCos *lir);
     void visitStringSplit(LStringSplit* lir);
     void visitFunctionEnvironment(LFunctionEnvironment* lir);
     void visitCallGetProperty(LCallGetProperty* lir);
     void visitCallGetElement(LCallGetElement* lir);
     void visitCallSetElement(LCallSetElement* lir);
     void visitCallInitElementArray(LCallInitElementArray* lir);
     void visitThrow(LThrow* lir);
     void visitTypeOfV(LTypeOfV* lir);
--- a/js/src/jit/Ion.cpp
+++ b/js/src/jit/Ion.cpp
@@ -1373,16 +1373,121 @@ jit::ToggleBarriers(JS::Zone* zone, bool
         if (comp->jitCompartment())
             comp->jitCompartment()->toggleBarriers(needs);
     }
 }
 
 namespace js {
 namespace jit {
 
+static void
+OptimizeSinCos(MIRGenerator *mir, MIRGraph &graph)
+{
+    // Now, we are looking for:
+    // var y = sin(x);
+    // var z = cos(x);
+    // Graph before:
+    // - 1 op
+    // - 6 mathfunction op1 Sin
+    // - 7 mathfunction op1 Cos
+    // Graph will look like:
+    // - 1 op
+    // - 5 sincos op1
+    // - 6 mathfunction sincos5 Sin
+    // - 7 mathfunction sincos5 Cos
+    for (MBasicBlockIterator block(graph.begin()); block != graph.end(); block++) {
+        for (MInstructionIterator iter(block->begin()), end(block->end()); iter != end; ) {
+            MInstruction *ins = *iter++;
+            if (!ins->isMathFunction() || ins->isRecoveredOnBailout())
+                continue;
+
+            MMathFunction *insFunc = ins->toMathFunction();
+            if (insFunc->function() != MMathFunction::Sin && insFunc->function() != MMathFunction::Cos)
+                continue;
+
+            // Check if sin/cos is already optimized.
+            if (insFunc->getOperand(0)->type() == MIRType_SinCosDouble)
+                continue;
+
+            // insFunc is either a |sin(x)| or |cos(x)| instruction. The
+            // following loop iterates over the uses of |x| to check if both
+            // |sin(x)| and |cos(x)| instructions exist.
+            bool hasSin = false;
+            bool hasCos = false;
+            for (MUseDefIterator uses(insFunc->input()); uses; uses++)
+            {
+                if (!uses.def()->isInstruction())
+                    continue;
+
+                // We should replacing the argument of the sin/cos just when it
+                // is dominated by the |block|.
+                if (!block->dominates(uses.def()->block()))
+                    continue;
+
+                MInstruction *insUse = uses.def()->toInstruction();
+                if (!insUse->isMathFunction() || insUse->isRecoveredOnBailout())
+                    continue;
+
+                MMathFunction *mathIns = insUse->toMathFunction();
+                if (!hasSin && mathIns->function() == MMathFunction::Sin) {
+                    hasSin = true;
+                    JitSpew(JitSpew_Sincos, "Found sin in block %d.", mathIns->block()->id());
+                }
+                else if (!hasCos && mathIns->function() == MMathFunction::Cos) {
+                    hasCos = true;
+                    JitSpew(JitSpew_Sincos, "Found cos in block %d.", mathIns->block()->id());
+                }
+
+                if (hasCos && hasSin)
+                    break;
+            }
+
+            if (!hasCos || !hasSin) {
+                JitSpew(JitSpew_Sincos, "No sin/cos pair found.");
+                continue;
+            }
+
+            JitSpew(JitSpew_Sincos, "Found, at least, a pair sin/cos. Adding sincos in block %d",
+                    block->id());
+            // Adding the MSinCos and replacing the parameters of the
+            // sin(x)/cos(x) to sin(sincos(x))/cos(sincos(x)).
+            MSinCos *insSinCos = MSinCos::New(graph.alloc(),
+                                              insFunc->input(),
+                                              insFunc->toMathFunction()->cache());
+            insSinCos->setImplicitlyUsedUnchecked();
+            block->insertBefore(insFunc, insSinCos);
+            for (MUseDefIterator uses(insFunc->input()); uses; )
+            {
+                MDefinition* def = uses.def();
+                uses++;
+                if (!def->isInstruction())
+                    continue;
+
+                // We should replacing the argument of the sin/cos just when it
+                // is dominated by the |block|.
+                if (!block->dominates(def->block()))
+                    continue;
+
+                MInstruction *insUse = def->toInstruction();
+                if (!insUse->isMathFunction() || insUse->isRecoveredOnBailout())
+                    continue;
+
+                MMathFunction *mathIns = insUse->toMathFunction();
+                if (mathIns->function() != MMathFunction::Sin && mathIns->function() != MMathFunction::Cos)
+                    continue;
+
+                mathIns->replaceOperand(0, insSinCos);
+                JitSpew(JitSpew_Sincos, "Replacing %s by sincos in block %d",
+                        mathIns->function() == MMathFunction::Sin ? "sin" : "cos",
+                        mathIns->block()->id());
+            }
+        }
+    }
+}
+
 bool
 OptimizeMIR(MIRGenerator* mir)
 {
     MIRGraph& graph = mir->graph();
     GraphSpewer& gs = mir->graphSpewer();
     TraceLoggerThread* logger;
     if (GetJitContext()->runtime->onMainThread())
         logger = TraceLoggerForMainThread(GetJitContext()->runtime);
@@ -1648,16 +1753,26 @@ OptimizeMIR(MIRGenerator* mir)
             return false;
         gs.spewPass("Effective Address Analysis");
         AssertExtendedGraphCoherency(graph);
 
         if (mir->shouldCancel("Effective Address Analysis"))
             return false;
     }
 
+    if (mir->optimizationInfo().sincosEnabled()) {
+        AutoTraceLog log(logger, TraceLogger_Sincos);
+        OptimizeSinCos(mir, graph);
+        gs.spewPass("Sincos optimization");
+        AssertExtendedGraphCoherency(graph);
+
+        if (mir->shouldCancel("Sincos optimization"))
+            return false;
+    }
+
     {
         AutoTraceLog log(logger, TraceLogger_EliminateDeadCode);
         if (!EliminateDeadCode(mir, graph))
             return false;
         gs.spewPass("DCE");
         AssertExtendedGraphCoherency(graph);
 
         if (mir->shouldCancel("DCE"))
--- a/js/src/jit/IonAnalysis.cpp
+++ b/js/src/jit/IonAnalysis.cpp
@@ -2089,16 +2089,17 @@ IsResumableMIRType(MIRType type)
       case MIRType_ObjectOrNull:
       case MIRType_None:
       case MIRType_Slots:
       case MIRType_Elements:
       case MIRType_Pointer:
       case MIRType_Shape:
       case MIRType_ObjectGroup:
       case MIRType_Doublex2: // NYI, see also RSimdBox::recover
+      case MIRType_SinCosDouble:
         return false;
     }
     MOZ_CRASH("Unknown MIRType.");
 }
 
 static void
 AssertResumableOperands(MNode* node)
 {
--- a/js/src/jit/IonOptimizationLevels.cpp
+++ b/js/src/jit/IonOptimizationLevels.cpp
@@ -30,16 +30,17 @@ OptimizationInfo::initNormalOptimization
     inlineNative_ = true;
     eagerSimdUnbox_ = true;
     gvn_ = true;
     licm_ = true;
     rangeAnalysis_ = true;
     loopUnrolling_ = true;
     reordering_ = true;
     autoTruncate_ = true;
+    sincos_ = true;
     sink_ = true;
     registerAllocator_ = RegisterAllocator_Backtracking;
 
     inlineMaxBytecodePerCallSiteMainThread_ = 500;
     inlineMaxBytecodePerCallSiteOffThread_ = 1000;
     inlineMaxCalleeInlinedBytecodeLength_ = 3000;
     inlineMaxTotalBytecodeLength_ = 80000;
     inliningMaxCallerBytecodeLength_ = 1500;
@@ -61,16 +62,17 @@ OptimizationInfo::initAsmjsOptimizationI
     initNormalOptimizationInfo();
 
     ama_ = true;
     level_ = Optimization_AsmJS;
     eagerSimdUnbox_ = false;           // AsmJS has no boxing / unboxing.
     edgeCaseAnalysis_ = false;
     eliminateRedundantChecks_ = false;
     autoTruncate_ = false;
+    sincos_ = false;
     sink_ = false;
     registerAllocator_ = RegisterAllocator_Backtracking;
     scalarReplacement_ = false;        // AsmJS has no objects.
 }
 
 uint32_t
 OptimizationInfo::compilerWarmUpThreshold(JSScript* script, jsbytecode* pc) const
 {
--- a/js/src/jit/IonOptimizationLevels.h
+++ b/js/src/jit/IonOptimizationLevels.h
@@ -80,16 +80,19 @@ class OptimizationInfo
     bool loopUnrolling_;
 
     // Toggles whether instruction reordering is performed.
     bool reordering_;
 
     // Toggles whether Truncation based on Range Analysis is used.
     bool autoTruncate_;
 
+    // Toggles whether sincos is used.
+    bool sincos_;
+
     // Toggles whether sink is used.
     bool sink_;
 
     // Describes which register allocator to use.
     IonRegisterAllocator registerAllocator_;
 
     // The maximum total bytecode size of an inline call site. We use a lower
     // value if off-thread compilation is not available, to avoid stalling the
@@ -181,16 +184,20 @@ class OptimizationInfo
     bool instructionReorderingEnabled() const {
         return reordering_ && !js_JitOptions.disableInstructionReordering;
     }
 
     bool autoTruncateEnabled() const {
         return autoTruncate_ && rangeAnalysisEnabled();
     }
 
+    bool sincosEnabled() const {
+        return sincos_ && !js_JitOptions.disableSincos;
+    }
+
     bool sinkEnabled() const {
         return sink_ && !js_JitOptions.disableSink;
     }
 
     bool eaaEnabled() const {
         return eaa_ && !js_JitOptions.disableEaa;
     }
 
--- a/js/src/jit/IonTypes.h
+++ b/js/src/jit/IonTypes.h
@@ -374,16 +374,17 @@ enum MIRType
     MIRType_Symbol,
     MIRType_Object,
     MIRType_MagicOptimizedArguments,   // JS_OPTIMIZED_ARGUMENTS magic value.
     MIRType_MagicOptimizedOut,         // JS_OPTIMIZED_OUT magic value.
     MIRType_MagicHole,                 // JS_ELEMENTS_HOLE magic value.
     MIRType_MagicIsConstructing,       // JS_IS_CONSTRUCTING magic value.
     MIRType_MagicUninitializedLexical, // JS_UNINITIALIZED_LEXICAL magic value.
     MIRType_Value,
+    MIRType_SinCosDouble,              // Optimizing a sin/cos to sincos.
     MIRType_ObjectOrNull,
     MIRType_None,                      // Invalid, used as a placeholder.
     MIRType_Slots,                     // A slots vector
     MIRType_Elements,                  // An elements vector
     MIRType_Pointer,                   // An opaque pointer that receives no special treatment
     MIRType_Shape,                     // A Shape pointer.
     MIRType_ObjectGroup,               // An ObjectGroup pointer.
     MIRType_Last = MIRType_ObjectGroup,
@@ -487,16 +488,18 @@ StringFromMIRType(MIRType type)
     case MIRType_MagicHole:
       return "MagicHole";
     case MIRType_MagicIsConstructing:
       return "MagicIsConstructing";
     case MIRType_MagicUninitializedLexical:
       return "MagicUninitializedLexical";
     case MIRType_Value:
       return "Value";
+    case MIRType_SinCosDouble:
+      return "SinCosDouble";
     case MIRType_ObjectOrNull:
       return "ObjectOrNull";
     case MIRType_None:
       return "None";
     case MIRType_Slots:
       return "Slots";
     case MIRType_Elements:
       return "Elements";
@@ -712,17 +715,30 @@ enum ABIFunctionType
     Args_Int_IntDouble = Args_General0 |
         (ArgType_Double << (ArgType_Shift * 1)) |
         (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))
+    Args_Double_DoubleDoubleDoubleDouble = Args_Double_DoubleDoubleDouble | (ArgType_Double << (ArgType_Shift * 4)),
+
+    // int f(double, int, int)
+    Args_Int_DoubleIntInt = Args_General0 |
+       (ArgType_General << (ArgType_Shift * 1)) |
+       (ArgType_General << (ArgType_Shift * 2)) |
+       (ArgType_Double  << (ArgType_Shift * 3)),
+
+    // int f(int, double, int, int)
+    Args_Int_IntDoubleIntInt = Args_General0 |
+        (ArgType_General << (ArgType_Shift * 1)) |
+        (ArgType_General << (ArgType_Shift * 2)) |
+        (ArgType_Double  << (ArgType_Shift * 3)) |
+        (ArgType_General << (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.
--- a/js/src/jit/JitOptions.cpp
+++ b/js/src/jit/JitOptions.cpp
@@ -105,16 +105,24 @@ JitOptions::JitOptions()
     SET_DEFAULT(disableRangeAnalysis, false);
 
     // Toggle whether eager scalar replacement is globally disabled.
     SET_DEFAULT(disableScalarReplacement, false);
 
     // Toggles whether shared stubs are used in Ionmonkey.
     SET_DEFAULT(disableSharedStubs, true);
 
+    // Toggles whether sincos optimization is globally disabled.
+    // See bug984018: The MacOS is the only one that has the sincos fast.
+    #if defined(XP_MACOSX)
+        SET_DEFAULT(disableSincos, false);
+    #else
+        SET_DEFAULT(disableSincos, true);
+    #endif
+
     // Toggles whether sink code motion is globally disabled.
     SET_DEFAULT(disableSink, true);
 
     // Whether functions are compiled immediately.
     SET_DEFAULT(eagerCompilation, false);
 
     // Whether IonBuilder should prefer IC generation above specialized MIR.
     SET_DEFAULT(forceInlineCaches, false);
--- a/js/src/jit/JitOptions.h
+++ b/js/src/jit/JitOptions.h
@@ -54,16 +54,17 @@ struct JitOptions
     bool disableGvn;
     bool disableInlining;
     bool disableLicm;
     bool disableLoopUnrolling;
     bool disableInstructionReordering;
     bool disableRangeAnalysis;
     bool disableScalarReplacement;
     bool disableSharedStubs;
+    bool disableSincos;
     bool disableSink;
     bool eagerCompilation;
     bool forceInlineCaches;
     bool limitScriptSize;
     bool osr;
     uint32_t baselineWarmUpThreshold;
     uint32_t exceptionBailoutThreshold;
     uint32_t frequentBailoutThreshold;
--- a/js/src/jit/JitSpewer.cpp
+++ b/js/src/jit/JitSpewer.cpp
@@ -399,16 +399,17 @@ jit::CheckLogging()
             "\n"
             "  aborts     Compilation abort messages\n"
             "  scripts    Compiled scripts\n"
             "  mir        MIR information\n"
             "  escape     Escape analysis\n"
             "  alias      Alias analysis\n"
             "  gvn        Global Value Numbering\n"
             "  licm       Loop invariant code motion\n"
+            "  sincos     Replace sin/cos by sincos\n"
             "  sink       Sink transformation\n"
             "  regalloc   Register allocation\n"
             "  inline     Inlining\n"
             "  snapshots  Snapshot information\n"
             "  codegen    Native code generation\n"
             "  bailouts   Bailouts\n"
             "  caches     Inline caches\n"
             "  osi        Invalidation\n"
@@ -450,16 +451,18 @@ jit::CheckLogging()
     if (ContainsFlag(env, "gvn"))
         EnableChannel(JitSpew_GVN);
     if (ContainsFlag(env, "range"))
         EnableChannel(JitSpew_Range);
     if (ContainsFlag(env, "unroll"))
         EnableChannel(JitSpew_Unrolling);
     if (ContainsFlag(env, "licm"))
         EnableChannel(JitSpew_LICM);
+    if (ContainsFlag(env, "sincos"))
+        EnableChannel(JitSpew_Sincos);
     if (ContainsFlag(env, "sink"))
         EnableChannel(JitSpew_Sink);
     if (ContainsFlag(env, "regalloc"))
         EnableChannel(JitSpew_RegAlloc);
     if (ContainsFlag(env, "inline"))
         EnableChannel(JitSpew_Inlining);
     if (ContainsFlag(env, "snapshots"))
         EnableChannel(JitSpew_IonSnapshots);
--- a/js/src/jit/JitSpewer.h
+++ b/js/src/jit/JitSpewer.h
@@ -21,16 +21,18 @@ namespace jit {
 // New channels may be added below.
 #define JITSPEW_CHANNEL_LIST(_)             \
     /* Information during escape analysis */\
     _(Escape)                               \
     /* Information during alias analysis */ \
     _(Alias)                                \
     /* Information during GVN */            \
     _(GVN)                                  \
+    /* Information during sincos */         \
+    _(Sincos)                               \
     /* Information during sinking */        \
     _(Sink)                                 \
     /* Information during Range analysis */ \
     _(Range)                                \
     /* Information during loop unrolling */ \
     _(Unrolling)                            \
     /* Information during LICM */           \
     _(LICM)                                 \
--- a/js/src/jit/LIR.cpp
+++ b/js/src/jit/LIR.cpp
@@ -345,16 +345,17 @@ static const char * const TypeChars[] =
     "g",            // GENERAL
     "i",            // INT32
     "o",            // OBJECT
     "s",            // SLOTS
     "f",            // FLOAT32
     "d",            // DOUBLE
     "i32x4",        // INT32X4
     "f32x4",        // FLOAT32X4
+    "sincos",       // SINCOS
 #ifdef JS_NUNBOX32
     "t",            // TYPE
     "p"             // PAYLOAD
 #elif JS_PUNBOX64
     "x"             // BOX
 #endif
 };
 
--- a/js/src/jit/LIR.h
+++ b/js/src/jit/LIR.h
@@ -417,16 +417,17 @@ class LDefinition
         GENERAL,    // Generic, integer or pointer-width data (GPR).
         INT32,      // int32 data (GPR).
         OBJECT,     // Pointer that may be collected as garbage (GPR).
         SLOTS,      // Slots/elements pointer that may be moved by minor GCs (GPR).
         FLOAT32,    // 32-bit floating-point value (FPU).
         DOUBLE,     // 64-bit floating-point value (FPU).
         INT32X4,    // SIMD data containing four 32-bit integers (FPU).
         FLOAT32X4,  // SIMD data containing four 32-bit floats (FPU).
+        SINCOS,
 #ifdef JS_NUNBOX32
         // A type virtual register must be followed by a payload virtual
         // register, as both will be tracked as a single gcthing.
         TYPE,
         PAYLOAD
 #else
         BOX         // Joined box, for punbox systems. (GPR, gcthing)
 #endif
@@ -557,16 +558,18 @@ class LDefinition
           case MIRType_Double:
             return LDefinition::DOUBLE;
           case MIRType_Float32:
             return LDefinition::FLOAT32;
 #if defined(JS_PUNBOX64)
           case MIRType_Value:
             return LDefinition::BOX;
 #endif
+          case MIRType_SinCosDouble:
+            return LDefinition::SINCOS;
           case MIRType_Slots:
           case MIRType_Elements:
             return LDefinition::SLOTS;
           case MIRType_Pointer:
             return LDefinition::GENERAL;
           case MIRType_Int32x4:
             return LDefinition::INT32X4;
           case MIRType_Float32x4:
@@ -1823,17 +1826,20 @@ LAllocation::toRegister() const
 #  include "jit/x64/LIR-x64.h"
 # endif
 # include "jit/x86-shared/LIR-x86-shared.h"
 #elif defined(JS_CODEGEN_ARM)
 # include "jit/arm/LIR-arm.h"
 #elif defined(JS_CODEGEN_ARM64)
 # include "jit/arm64/LIR-arm64.h"
 #elif defined(JS_CODEGEN_MIPS32)
-# include "jit/mips32/LIR-mips32.h"
+# if defined(JS_CODEGEN_MIPS32)
+#  include "jit/mips32/LIR-mips32.h"
+# endif
+# include "jit/mips-shared/LIR-mips-shared.h"
 #elif defined(JS_CODEGEN_NONE)
 # include "jit/none/LIR-none.h"
 #else
 # error "Unknown architecture!"
 #endif
 
 #undef LIR_HEADER
 
--- a/js/src/jit/Lowering.cpp
+++ b/js/src/jit/Lowering.cpp
@@ -1388,17 +1388,24 @@ LIRGenerator::visitPow(MPow* ins)
     }
     defineReturn(lir, ins);
 }
 
 void
 LIRGenerator::visitMathFunction(MMathFunction* ins)
 {
     MOZ_ASSERT(IsFloatingPointType(ins->type()));
-    MOZ_ASSERT(ins->type() == ins->input()->type());
+    MOZ_ASSERT_IF(ins->input()->type() != MIRType_SinCosDouble,
+                  ins->type() == ins->input()->type());
+
+    if (ins->input()->type() == MIRType_SinCosDouble) {
+        MOZ_ASSERT(ins->type() == MIRType_Double);
+        redefine(ins, ins->input(), ins->function());
+        return;
+    }
 
     LInstruction* lir;
     if (ins->type() == MIRType_Double) {
         // Note: useRegisterAtStart is safe here, the temp is not a FP register.
         lir = new(alloc()) LMathFunctionD(useRegisterAtStart(ins->input()),
                                           tempFixed(CallTempReg0));
     } else {
         lir = new(alloc()) LMathFunctionF(useRegisterAtStart(ins->input()),
@@ -2977,16 +2984,30 @@ LIRGenerator::visitArrayJoin(MArrayJoin*
 
     LArrayJoin* lir = new(alloc()) LArrayJoin(useRegisterAtStart(ins->array()),
                                               useRegisterAtStart(ins->sep()));
     defineReturn(lir, ins);
     assignSafepoint(lir, ins);
 }
 
 void
+LIRGenerator::visitSinCos(MSinCos *ins)
+{
+    MOZ_ASSERT(ins->type() == MIRType_SinCosDouble);
+    MOZ_ASSERT(ins->input()->type() == MIRType_Double  ||
+               ins->input()->type() == MIRType_Float32 ||
+               ins->input()->type() == MIRType_Int32);
+
+    LSinCos *lir = new (alloc()) LSinCos(useRegisterAtStart(ins->input()),
+                                         tempFixed(CallTempReg0),
+                                         temp());
+    defineSinCos(lir, ins);
+}
+
+void
 LIRGenerator::visitStringSplit(MStringSplit* ins)
 {
     MOZ_ASSERT(ins->type() == MIRType_Object);
     MOZ_ASSERT(ins->string()->type() == MIRType_String);
     MOZ_ASSERT(ins->separator()->type() == MIRType_String);
 
     LStringSplit* lir = new(alloc()) LStringSplit(useRegisterAtStart(ins->string()),
                                                   useRegisterAtStart(ins->separator()));
--- a/js/src/jit/Lowering.h
+++ b/js/src/jit/Lowering.h
@@ -136,16 +136,17 @@ class LIRGenerator : public LIRGenerator
     void visitAdd(MAdd* ins);
     void visitSub(MSub* ins);
     void visitMul(MMul* ins);
     void visitDiv(MDiv* ins);
     void visitMod(MMod* ins);
     void visitConcat(MConcat* ins);
     void visitCharCodeAt(MCharCodeAt* ins);
     void visitFromCharCode(MFromCharCode* ins);
+    void visitSinCos(MSinCos *ins);
     void visitStringSplit(MStringSplit* ins);
     void visitStart(MStart* start);
     void visitOsrEntry(MOsrEntry* entry);
     void visitNop(MNop* nop);
     void visitLimitedTruncate(MLimitedTruncate* nop);
     void visitOsrValue(MOsrValue* value);
     void visitOsrScopeChain(MOsrScopeChain* object);
     void visitOsrReturnValue(MOsrReturnValue* value);
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -6114,16 +6114,18 @@ class MMathFunction
 
     bool isFloat32Commutative() const override {
         return function_ == Floor || function_ == Ceil || function_ == Round;
     }
     void trySpecializeFloat32(TempAllocator& alloc) override;
     void computeRange(TempAllocator& alloc) override;
     bool writeRecoverData(CompactBufferWriter& writer) const override;
     bool canRecoverOnBailout() const override {
+        if (input()->type() == MIRType_SinCosDouble)
+            return false;
         switch(function_) {
           case Sin:
           case Log:
           case Round:
             return true;
           default:
             return false;
         }
@@ -6621,16 +6623,50 @@ class MFromCharCode
     bool writeRecoverData(CompactBufferWriter& writer) const override;
     bool canRecoverOnBailout() const override {
         return true;
     }
 
     ALLOW_CLONE(MFromCharCode)
 };
 
+class MSinCos
+  : public MUnaryInstruction,
+    public FloatingPointPolicy<0>::Data
+{
+    const MathCache* cache_;
+
+    MSinCos(MDefinition *input, const MathCache *cache) : MUnaryInstruction(input), cache_(cache)
+    {
+        setResultType(MIRType_SinCosDouble);
+        specialization_ = MIRType_Double;
+        setMovable();
+    }
+
+  public:
+    INSTRUCTION_HEADER(SinCos)
+
+    static MSinCos *New(TempAllocator &alloc, MDefinition *input, const MathCache *cache)
+    {
+        return new (alloc) MSinCos(input, cache);
+    }
+    AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+    bool congruentTo(const MDefinition *ins) const override {
+        return congruentIfOperandsEqual(ins);
+    }
+    bool possiblyCalls() const override {
+        return true;
+    }
+    const MathCache* cache() const {
+        return cache_;
+    }
+};
+
 class MStringSplit
   : public MTernaryInstruction,
     public MixPolicy<StringPolicy<0>, StringPolicy<1> >::Data
 {
     MStringSplit(CompilerConstraintList* constraints, MDefinition* string, MDefinition* sep,
                  MConstant* templateObject)
       : MTernaryInstruction(string, sep, templateObject)
     {
--- a/js/src/jit/MOpcodes.h
+++ b/js/src/jit/MOpcodes.h
@@ -94,16 +94,17 @@ namespace jit {
     _(Add)                                                                  \
     _(Sub)                                                                  \
     _(Mul)                                                                  \
     _(Div)                                                                  \
     _(Mod)                                                                  \
     _(Concat)                                                               \
     _(CharCodeAt)                                                           \
     _(FromCharCode)                                                         \
+    _(SinCos)                                                               \
     _(StringSplit)                                                          \
     _(Substr)                                                               \
     _(Return)                                                               \
     _(Throw)                                                                \
     _(Box)                                                                  \
     _(Unbox)                                                                \
     _(GuardObject)                                                          \
     _(GuardString)                                                          \
--- a/js/src/jit/MacroAssembler-inl.h
+++ b/js/src/jit/MacroAssembler-inl.h
@@ -145,16 +145,18 @@ MacroAssembler::signature() const
       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_Int_DoubleIntInt:
+      case Args_Int_IntDoubleIntInt:
       case Args_Double_DoubleDoubleDouble:
       case Args_Double_DoubleDoubleDoubleDouble:
         break;
       default:
         MOZ_CRASH("Unexpected type");
     }
 #endif // DEBUG
 
--- a/js/src/jit/StackSlotAllocator.h
+++ b/js/src/jit/StackSlotAllocator.h
@@ -92,16 +92,17 @@ class StackSlotAllocator
 #ifdef JS_PUNBOX64
           case LDefinition::BOX:
 #endif
 #ifdef JS_NUNBOX32
           case LDefinition::TYPE:
           case LDefinition::PAYLOAD:
 #endif
           case LDefinition::DOUBLE:    return 8;
+          case LDefinition::SINCOS:
           case LDefinition::FLOAT32X4:
           case LDefinition::INT32X4:   return 16;
         }
         MOZ_CRASH("Unknown slot type");
     }
 
     void freeSlot(LDefinition::Type type, uint32_t index) {
         switch (width(type)) {
--- a/js/src/jit/TypePolicy.cpp
+++ b/js/src/jit/TypePolicy.cpp
@@ -488,17 +488,17 @@ TruncateToInt32Policy<Op>::staticAdjustI
 template bool TruncateToInt32Policy<2>::staticAdjustInputs(TempAllocator& alloc, MInstruction* def);
 template bool TruncateToInt32Policy<3>::staticAdjustInputs(TempAllocator& alloc, MInstruction* def);
 
 template <unsigned Op>
 bool
 DoublePolicy<Op>::staticAdjustInputs(TempAllocator& alloc, MInstruction* def)
 {
     MDefinition* in = def->getOperand(Op);
-    if (in->type() == MIRType_Double)
+    if (in->type() == MIRType_Double || in->type() == MIRType_SinCosDouble)
         return true;
 
     MToDouble* replace = MToDouble::New(alloc, in);
     def->block()->insertBefore(def, replace);
     def->replaceOperand(Op, replace);
 
     return replace->typePolicy()->adjustInputs(alloc, replace);
 }
--- a/js/src/jit/arm/Simulator-arm.cpp
+++ b/js/src/jit/arm/Simulator-arm.cpp
@@ -2057,16 +2057,19 @@ typedef int64_t (*Prototype_General7)(in
                                       int32_t arg4, int32_t arg5, int32_t arg6);
 typedef int64_t (*Prototype_General8)(int32_t arg0, int32_t arg1, int32_t arg2, int32_t arg3,
                                       int32_t arg4, int32_t arg5, int32_t arg6, int32_t arg7);
 
 typedef double (*Prototype_Double_None)();
 typedef double (*Prototype_Double_Double)(double arg0);
 typedef double (*Prototype_Double_Int)(int32_t arg0);
 typedef int32_t (*Prototype_Int_Double)(double arg0);
+typedef int32_t (*Prototype_Int_DoubleIntInt)(double arg0, int32_t arg1, int32_t arg2);
+typedef int32_t (*Prototype_Int_IntDoubleIntInt)(int32_t arg0, double arg1, int32_t arg2,
+                                                 int32_t arg3);
 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);
@@ -2288,16 +2291,46 @@ 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_Int_DoubleIntInt: {
+            double dval;
+            int32_t result;
+            Prototype_Int_DoubleIntInt target = reinterpret_cast<Prototype_Int_DoubleIntInt>(external);
+            if (UseHardFpABI()) {
+                dval = get_double_from_d_register(0);
+                result = target(dval, arg0, arg1);
+            } else {
+                dval = get_double_from_register_pair(0);
+                result = target(dval, arg2, arg3);
+            }
+            scratchVolatileRegisters(/* scratchFloat = true */);
+            set_register(r0, result);
+            break;
+          }
+          case Args_Int_IntDoubleIntInt: {
+            double dval;
+            int32_t result;
+            Prototype_Int_IntDoubleIntInt target = reinterpret_cast<Prototype_Int_IntDoubleIntInt>(external);
+            if (UseHardFpABI()) {
+                dval = get_double_from_d_register(0);
+                result = target(arg0, dval, arg1, arg2);
+            } else {
+                dval = get_double_from_register_pair(2);
+                result = target(arg0, dval, arg4, arg5);
+            }
+            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);
--- a/js/src/jit/arm64/vixl/MozSimulator-vixl.cpp
+++ b/js/src/jit/arm64/vixl/MozSimulator-vixl.cpp
@@ -462,16 +462,19 @@ typedef int64_t (*Prototype_General6)(in
                                       int64_t arg4, int64_t arg5);
 typedef int64_t (*Prototype_General7)(int64_t arg0, int64_t arg1, int64_t arg2, int64_t arg3,
                                       int64_t arg4, int64_t arg5, int64_t arg6);
 typedef int64_t (*Prototype_General8)(int64_t arg0, int64_t arg1, int64_t arg2, int64_t arg3,
                                       int64_t arg4, int64_t arg5, int64_t arg6, int64_t arg7);
 
 typedef int64_t (*Prototype_Int_Double)(double arg0);
 typedef int64_t (*Prototype_Int_IntDouble)(int32_t arg0, double arg1);
+typedef int64_t (*Prototype_Int_DoubleIntInt)(double arg0, uint64_t arg1, uint64_t arg2);
+typedef int64_t (*Prototype_Int_IntDoubleIntInt)(uint64_t arg0, double arg1,
+                                                 uint64_t arg2, uint64_t arg3);
 
 typedef float (*Prototype_Float32_Float32)(float arg0);
 
 typedef double (*Prototype_Double_None)();
 typedef double (*Prototype_Double_Double)(double arg0);
 typedef double (*Prototype_Double_Int)(int32_t arg0);
 typedef double (*Prototype_Double_DoubleInt)(double arg0, int64_t arg1);
 typedef double (*Prototype_Double_IntDouble)(int64_t arg0, double arg1);
@@ -587,16 +590,28 @@ Simulator::VisitCallRedirection(const In
       break;
     }
     case js::jit::Args_Int_IntDouble: {
       int64_t ret = reinterpret_cast<Prototype_Int_IntDouble>(nativeFn)(x0, d0);
       setGPR64Result(ret);
       break;
     }
 
+    case js::jit::Args_Int_IntDoubleIntInt: {
+      int64_t ret = reinterpret_cast<Prototype_Int_IntDoubleIntInt>(nativeFn)(x0, d0, x1, x2);
+      setGPR64Result(ret);
+      break;
+    }
+
+    case js::jit::Args_Int_DoubleIntInt: {
+      int64_t ret = reinterpret_cast<Prototype_Int_DoubleIntInt>(nativeFn)(d0, x0, x1);
+      setGPR64Result(ret);
+      break;
+    }
+
     // Cases with float return type.
     case js::jit::Args_Float32_Float32: {
       float ret = reinterpret_cast<Prototype_Float32_Float32>(nativeFn)(s0);
       setFP32Result(ret);
       break;
     }
 
     // Cases with double return type.
copy from js/src/jit/mips32/LIR-mips32.h
copy to js/src/jit/mips-shared/LIR-mips-shared.h
--- a/js/src/jit/mips32/LIR-mips32.h
+++ b/js/src/jit/mips-shared/LIR-mips-shared.h
@@ -1,86 +1,20 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * 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 jit_mips32_LIR_mips32_h
-#define jit_mips32_LIR_mips32_h
+#ifndef jit_mips_shared_LIR_mips_shared_h
+#define jit_mips_shared_LIR_mips_shared_h
 
 namespace js {
 namespace jit {
 
-class LBoxFloatingPoint : public LInstructionHelper<2, 1, 1>
-{
-    MIRType type_;
-
-  public:
-    LIR_HEADER(BoxFloatingPoint);
-
-    LBoxFloatingPoint(const LAllocation& in, const LDefinition& temp, MIRType type)
-      : type_(type)
-    {
-        setOperand(0, in);
-        setTemp(0, temp);
-    }
-
-    MIRType type() const {
-        return type_;
-    }
-    const char* extraName() const {
-        return StringFromMIRType(type_);
-    }
-};
-
-class LUnbox : public LInstructionHelper<1, 2, 0>
-{
-  public:
-    LIR_HEADER(Unbox);
-
-    MUnbox* mir() const {
-        return mir_->toUnbox();
-    }
-    const LAllocation* payload() {
-        return getOperand(0);
-    }
-    const LAllocation* type() {
-        return getOperand(1);
-    }
-    const char* extraName() const {
-        return StringFromMIRType(mir()->type());
-    }
-};
-
-class LUnboxFloatingPoint : public LInstructionHelper<1, 2, 0>
-{
-    MIRType type_;
-
-  public:
-    LIR_HEADER(UnboxFloatingPoint);
-
-    static const size_t Input = 0;
-
-    LUnboxFloatingPoint(MIRType type)
-      : type_(type)
-    { }
-
-    MUnbox* mir() const {
-        return mir_->toUnbox();
-    }
-
-    MIRType type() const {
-        return type_;
-    }
-    const char* extraName() const {
-        return StringFromMIRType(type_);
-    }
-};
-
 // Convert a 32-bit unsigned integer to a double.
 class LAsmJSUInt32ToDouble : public LInstructionHelper<1, 1, 0>
 {
   public:
     LIR_HEADER(AsmJSUInt32ToDouble)
 
     LAsmJSUInt32ToDouble(const LAllocation& input) {
         setOperand(0, input);
@@ -365,9 +299,9 @@ class LRandom : public LCallInstructionH
     const LDefinition* temp2() {
         return getTemp(1);
     }
 };
 
 } // namespace jit
 } // namespace js
 
-#endif /* jit_mips32_LIR_mips32_h */
+#endif /* jit_mips_shared_LIR_mips_shared_h */
--- a/js/src/jit/mips32/LIR-mips32.h
+++ b/js/src/jit/mips32/LIR-mips32.h
@@ -71,303 +71,12 @@ class LUnboxFloatingPoint : public LInst
     MIRType type() const {
         return type_;
     }
     const char* extraName() const {
         return StringFromMIRType(type_);
     }
 };
 
-// Convert a 32-bit unsigned integer to a double.
-class LAsmJSUInt32ToDouble : public LInstructionHelper<1, 1, 0>
-{
-  public:
-    LIR_HEADER(AsmJSUInt32ToDouble)
-
-    LAsmJSUInt32ToDouble(const LAllocation& input) {
-        setOperand(0, input);
-    }
-};
-
-// Convert a 32-bit unsigned integer to a float32.
-class LAsmJSUInt32ToFloat32 : public LInstructionHelper<1, 1, 0>
-{
-  public:
-    LIR_HEADER(AsmJSUInt32ToFloat32)
-
-    LAsmJSUInt32ToFloat32(const LAllocation& input) {
-        setOperand(0, input);
-    }
-};
-
-
-class LDivI : public LBinaryMath<1>
-{
-  public:
-    LIR_HEADER(DivI);
-
-    LDivI(const LAllocation& lhs, const LAllocation& rhs,
-          const LDefinition& temp) {
-        setOperand(0, lhs);
-        setOperand(1, rhs);
-        setTemp(0, temp);
-    }
-
-    MDiv* mir() const {
-        return mir_->toDiv();
-    }
-};
-
-class LDivPowTwoI : public LInstructionHelper<1, 1, 1>
-{
-    const int32_t shift_;
-
-  public:
-    LIR_HEADER(DivPowTwoI)
-
-    LDivPowTwoI(const LAllocation& lhs, int32_t shift, const LDefinition& temp)
-      : shift_(shift)
-    {
-        setOperand(0, lhs);
-        setTemp(0, temp);
-    }
-
-    const LAllocation* numerator() {
-        return getOperand(0);
-    }
-
-    int32_t shift() {
-        return shift_;
-    }
-
-    MDiv* mir() const {
-        return mir_->toDiv();
-    }
-};
-
-class LModI : public LBinaryMath<1>
-{
-  public:
-    LIR_HEADER(ModI);
-
-    LModI(const LAllocation& lhs, const LAllocation& rhs,
-          const LDefinition& callTemp)
-    {
-        setOperand(0, lhs);
-        setOperand(1, rhs);
-        setTemp(0, callTemp);
-    }
-
-    const LDefinition* callTemp() {
-        return getTemp(0);
-    }
-
-    MMod* mir() const {
-        return mir_->toMod();
-    }
-};
-
-class LModPowTwoI : public LInstructionHelper<1, 1, 0>
-{
-    const int32_t shift_;
-
-  public:
-    LIR_HEADER(ModPowTwoI);
-    int32_t shift()
-    {
-        return shift_;
-    }
-
-    LModPowTwoI(const LAllocation& lhs, int32_t shift)
-      : shift_(shift)
-    {
-        setOperand(0, lhs);
-    }
-
-    MMod* mir() const {
-        return mir_->toMod();
-    }
-};
-
-class LModMaskI : public LInstructionHelper<1, 1, 2>
-{
-    const int32_t shift_;
-
-  public:
-    LIR_HEADER(ModMaskI);
-
-    LModMaskI(const LAllocation& lhs, const LDefinition& temp0, const LDefinition& temp1,
-              int32_t shift)
-      : shift_(shift)
-    {
-        setOperand(0, lhs);
-        setTemp(0, temp0);
-        setTemp(1, temp1);
-    }
-
-    int32_t shift() const {
-        return shift_;
-    }
-
-    MMod* mir() const {
-        return mir_->toMod();
-    }
-};
-
-// Takes a tableswitch with an integer to decide
-class LTableSwitch : public LInstructionHelper<0, 1, 2>
-{
-  public:
-    LIR_HEADER(TableSwitch);
-
-    LTableSwitch(const LAllocation& in, const LDefinition& inputCopy,
-                 const LDefinition& jumpTablePointer, MTableSwitch* ins) {
-        setOperand(0, in);
-        setTemp(0, inputCopy);
-        setTemp(1, jumpTablePointer);
-        setMir(ins);
-    }
-
-    MTableSwitch* mir() const {
-        return mir_->toTableSwitch();
-    }
-
-    const LAllocation* index() {
-        return getOperand(0);
-    }
-    const LDefinition* tempInt() {
-        return getTemp(0);
-    }
-    // This is added to share the same CodeGenerator prefixes.
-    const LDefinition* tempPointer() {
-        return getTemp(1);
-    }
-};
-
-// Takes a tableswitch with an integer to decide
-class LTableSwitchV : public LInstructionHelper<0, BOX_PIECES, 3>
-{
-  public:
-    LIR_HEADER(TableSwitchV);
-
-    LTableSwitchV(const LDefinition& inputCopy, const LDefinition& floatCopy,
-                  const LDefinition& jumpTablePointer, MTableSwitch* ins)
-    {
-        setTemp(0, inputCopy);
-        setTemp(1, floatCopy);
-        setTemp(2, jumpTablePointer);
-        setMir(ins);
-    }
-
-    MTableSwitch* mir() const {
-        return mir_->toTableSwitch();
-    }
-
-    static const size_t InputValue = 0;
-
-    const LDefinition* tempInt() {
-        return getTemp(0);
-    }
-    const LDefinition* tempFloat() {
-        return getTemp(1);
-    }
-    const LDefinition* tempPointer() {
-        return getTemp(2);
-    }
-};
-
-class LGuardShape : public LInstructionHelper<0, 1, 1>
-{
-  public:
-    LIR_HEADER(GuardShape);
-
-    LGuardShape(const LAllocation& in, const LDefinition& temp) {
-        setOperand(0, in);
-        setTemp(0, temp);
-    }
-    const MGuardShape* mir() const {
-        return mir_->toGuardShape();
-    }
-    const LDefinition* tempInt() {
-        return getTemp(0);
-    }
-};
-
-class LGuardObjectGroup : public LInstructionHelper<0, 1, 1>
-{
-  public:
-    LIR_HEADER(GuardObjectGroup);
-
-    LGuardObjectGroup(const LAllocation& in, const LDefinition& temp) {
-        setOperand(0, in);
-        setTemp(0, temp);
-    }
-    const MGuardObjectGroup* mir() const {
-        return mir_->toGuardObjectGroup();
-    }
-    const LDefinition* tempInt() {
-        return getTemp(0);
-    }
-};
-
-class LMulI : public LBinaryMath<0>
-{
-  public:
-    LIR_HEADER(MulI);
-
-    MMul* mir() {
-        return mir_->toMul();
-    }
-};
-
-class LUDivOrMod : public LBinaryMath<0>
-{
-  public:
-    LIR_HEADER(UDivOrMod);
-
-    MBinaryArithInstruction* mir() const {
-        MOZ_ASSERT(mir_->isDiv() || mir_->isMod());
-        return static_cast<MBinaryArithInstruction*>(mir_);
-    }
-
-    bool canBeDivideByZero() const {
-        if (mir_->isMod())
-            return mir_->toMod()->canBeDivideByZero();
-        return mir_->toDiv()->canBeDivideByZero();
-    }
-};
-
-class LAsmJSLoadFuncPtr : public LInstructionHelper<1, 1, 0>
-{
-  public:
-    LIR_HEADER(AsmJSLoadFuncPtr);
-    LAsmJSLoadFuncPtr(const LAllocation& index) {
-        setOperand(0, index);
-    }
-    const MAsmJSLoadFuncPtr* mir() const {
-        return mir_->toAsmJSLoadFuncPtr();
-    }
-    const LAllocation* index() {
-        return getOperand(0);
-    }
-};
-
-// Math.random().
-class LRandom : public LCallInstructionHelper<1, 0, 2>
-{
-  public:
-    LIR_HEADER(Random)
-    LRandom(const LDefinition& temp, const LDefinition& temp2) {
-        setTemp(0, temp);
-        setTemp(1, temp2);
-    }
-    const LDefinition* temp() {
-        return getTemp(0);
-    }
-    const LDefinition* temp2() {
-        return getTemp(1);
-    }
-};
-
 } // namespace jit
 } // namespace js
 
 #endif /* jit_mips32_LIR_mips32_h */
--- a/js/src/jit/mips32/MacroAssembler-mips32.cpp
+++ b/js/src/jit/mips32/MacroAssembler-mips32.cpp
@@ -42,26 +42,25 @@ MacroAssemblerMIPSCompat::convertInt32To
 {
     as_mtc1(src, dest);
     as_cvtdw(dest, dest);
 }
 
 void
 MacroAssemblerMIPSCompat::convertInt32ToDouble(const Address& src, FloatRegister dest)
 {
-    ma_lw(ScratchRegister, src);
-    as_mtc1(ScratchRegister, dest);
+    ma_ls(dest, src);
     as_cvtdw(dest, dest);
 }
 
 void
 MacroAssemblerMIPSCompat::convertInt32ToDouble(const BaseIndex& src, FloatRegister dest)
 {
-    computeScaledAddress(src, SecondScratchReg);
-    convertInt32ToDouble(Address(SecondScratchReg, src.offset), dest);
+    computeScaledAddress(src, ScratchRegister);
+    convertInt32ToDouble(Address(ScratchRegister, src.offset), dest);
 }
 
 void
 MacroAssemblerMIPSCompat::convertUInt32ToDouble(Register src, FloatRegister dest)
 {
     // We use SecondScratchDoubleReg because MacroAssembler::loadFromTypedArray
     // calls with ScratchDoubleReg as dest.
     MOZ_ASSERT(dest != SecondScratchDoubleReg);
@@ -198,18 +197,17 @@ MacroAssemblerMIPSCompat::convertInt32To
 {
     as_mtc1(src, dest);
     as_cvtsw(dest, dest);
 }
 
 void
 MacroAssemblerMIPSCompat::convertInt32ToFloat32(const Address& src, FloatRegister dest)
 {
-    ma_lw(ScratchRegister, src);
-    as_mtc1(ScratchRegister, dest);
+    ma_ls(dest, src);
     as_cvtsw(dest, dest);
 }
 
 void
 MacroAssemblerMIPSCompat::addDouble(FloatRegister src, FloatRegister dest)
 {
     as_addd(dest, dest, src);
 }
@@ -261,17 +259,17 @@ MacroAssemblerMIPS::ma_move(Register rd,
 {
     as_or(rd, rs, zero);
 }
 
 void
 MacroAssemblerMIPS::ma_li(Register dest, ImmGCPtr ptr)
 {
     writeDataRelocation(ptr);
-    ma_liPatchable(dest, Imm32(uintptr_t(ptr.value)));
+    ma_liPatchable(dest, ImmPtr(ptr.value));
 }
 
 void
 MacroAssemblerMIPS::ma_li(Register dest, AbsoluteLabel* label)
 {
     MOZ_ASSERT(!label->bound());
     // Thread the patch list through the unpatched address word in the
     // instruction stream.
@@ -290,32 +288,43 @@ MacroAssemblerMIPS::ma_li(Register dest,
     } else if (Imm16::Lower(imm).encode() == 0) {
         as_lui(dest, Imm16::Upper(imm).encode());
     } else {
         as_lui(dest, Imm16::Upper(imm).encode());
         as_ori(dest, dest, Imm16::Lower(imm).encode());
     }
 }
 
+void
+MacroAssemblerMIPS::ma_li(Register dest, ImmWord imm)
+{
+    ma_li(dest, Imm32(uint32_t(imm.value)));
+}
 
 // This method generates lui and ori instruction pair that can be modified by
 // UpdateLuiOriValue, either during compilation (eg. Assembler::bind), or
 // during execution (eg. jit::PatchJump).
 void
 MacroAssemblerMIPS::ma_liPatchable(Register dest, Imm32 imm)
 {
     m_buffer.ensureSpace(2 * sizeof(uint32_t));
     as_lui(dest, Imm16::Upper(imm).encode());
     as_ori(dest, dest, Imm16::Lower(imm).encode());
 }
 
 void
 MacroAssemblerMIPS::ma_liPatchable(Register dest, ImmPtr imm)
 {
-    return ma_liPatchable(dest, Imm32(int32_t(imm.value)));
+    ma_liPatchable(dest, ImmWord(uintptr_t(imm.value)));
+}
+
+void
+MacroAssemblerMIPS::ma_liPatchable(Register dest, ImmWord imm)
+{
+    ma_liPatchable(dest, Imm32(int32_t(imm.value)));
 }
 
 // Shifts
 void
 MacroAssemblerMIPS::ma_sll(Register rd, Register rt, Imm32 shift)
 {
     as_sll(rd, rt, shift.value % 32);
 }
@@ -1551,17 +1560,17 @@ MacroAssemblerMIPSCompat::move32(Registe
 void
 MacroAssemblerMIPSCompat::movePtr(Register src, Register dest)
 {
     ma_move(dest, src);
 }
 void
 MacroAssemblerMIPSCompat::movePtr(ImmWord imm, Register dest)
 {
-    ma_li(dest, Imm32(imm.value));
+    ma_li(dest, imm);
 }
 
 void
 MacroAssemblerMIPSCompat::movePtr(ImmGCPtr imm, Register dest)
 {
     ma_li(dest, imm);
 }
 
@@ -1569,17 +1578,17 @@ void
 MacroAssemblerMIPSCompat::movePtr(ImmPtr imm, Register dest)
 {
     movePtr(ImmWord(uintptr_t(imm.value)), dest);
 }
 void
 MacroAssemblerMIPSCompat::movePtr(AsmJSImmPtr imm, Register dest)
 {
     append(AsmJSAbsoluteLink(CodeOffsetLabel(nextOffset().getOffset()), imm.kind()));
-    ma_liPatchable(dest, Imm32(-1));
+    ma_liPatchable(dest, ImmWord(-1));
 }
 
 void
 MacroAssemblerMIPSCompat::load8ZeroExtend(const Address& address, Register dest)
 {
     ma_load(dest, address, SizeByte, ZeroExtend);
 }
 
@@ -1623,55 +1632,63 @@ void
 MacroAssemblerMIPSCompat::load16SignExtend(const BaseIndex& src, Register dest)
 {
     ma_load(dest, src, SizeHalfWord, SignExtend);
 }
 
 void
 MacroAssemblerMIPSCompat::load32(const Address& address, Register dest)
 {
-    ma_lw(dest, address);
+    ma_load(dest, address, SizeWord);
 }
 
 void
 MacroAssemblerMIPSCompat::load32(const BaseIndex& address, Register dest)
 {
     ma_load(dest, address, SizeWord);
 }
 
 void
 MacroAssemblerMIPSCompat::load32(AbsoluteAddress address, Register dest)
 {
-    ma_li(ScratchRegister, Imm32((uint32_t)address.addr));
-    as_lw(dest, ScratchRegister, 0);
+    movePtr(ImmPtr(address.addr), ScratchRegister);
+    load32(Address(ScratchRegister, 0), dest);
+}
+
+void
+MacroAssemblerMIPSCompat::load32(AsmJSAbsoluteAddress address, Register dest)
+{
+    movePtr(AsmJSImmPtr(address.kind()), ScratchRegister);
+    load32(Address(ScratchRegister, 0), dest);
 }
 
 void
 MacroAssemblerMIPSCompat::loadPtr(const Address& address, Register dest)
 {
-    ma_lw(dest, address);
+    ma_load(dest, address, SizeWord);
 }
 
 void
 MacroAssemblerMIPSCompat::loadPtr(const BaseIndex& src, Register dest)
 {
-    load32(src, dest);
+    ma_load(dest, src, SizeWord);
 }
 
 void
 MacroAssemblerMIPSCompat::loadPtr(AbsoluteAddress address, Register dest)
 {
-    ma_li(ScratchRegister, Imm32((uint32_t)address.addr));
-    as_lw(dest, ScratchRegister, 0);
-}
+    movePtr(ImmPtr(address.addr), ScratchRegister);
+    loadPtr(Address(ScratchRegister, 0), dest);
+}
+
 void
 MacroAssemblerMIPSCompat::loadPtr(AsmJSAbsoluteAddress address, Register dest)
 {
     movePtr(AsmJSImmPtr(address.kind()), ScratchRegister);
-    loadPtr(Address(ScratchRegister, 0x0), dest);
+    loadPtr(Address(ScratchRegister, 0), dest);
 }
 
 void
 MacroAssemblerMIPSCompat::loadPrivate(const Address& address, Register dest)
 {
     ma_lw(dest, Address(address.base, address.offset + PAYLOAD_OFFSET));
 }
 
@@ -1763,30 +1780,31 @@ void
 MacroAssemblerMIPSCompat::store16(Register src, const BaseIndex& address)
 {
     ma_store(src, address, SizeHalfWord);
 }
 
 void
 MacroAssemblerMIPSCompat::store32(Register src, AbsoluteAddress address)
 {
-    storePtr(src, address);
+    movePtr(ImmPtr(address.addr), ScratchRegister);
+    store32(src, Address(ScratchRegister, 0));
 }
 
 void
 MacroAssemblerMIPSCompat::store32(Register src, const Address& address)
 {
-    storePtr(src, address);
+    ma_store(src, address, SizeWord);
 }
 
 void
 MacroAssemblerMIPSCompat::store32(Imm32 src, const Address& address)
 {
     move32(src, SecondScratchReg);
-    storePtr(SecondScratchReg, address);
+    ma_store(SecondScratchReg, address, SizeWord);
 }
 
 void
 MacroAssemblerMIPSCompat::store32(Imm32 imm, const BaseIndex& dest)
 {
     ma_store(imm, dest, SizeWord);
 }
 
@@ -1795,18 +1813,18 @@ MacroAssemblerMIPSCompat::store32(Regist
 {
     ma_store(src, dest, SizeWord);
 }
 
 template <typename T>
 void
 MacroAssemblerMIPSCompat::storePtr(ImmWord imm, T address)
 {
-    ma_li(SecondScratchReg, Imm32(imm.value));
-    ma_sw(SecondScratchReg, address);
+    ma_li(SecondScratchReg, imm);
+    ma_store(SecondScratchReg, address, SizeWord);
 }
 
 template void MacroAssemblerMIPSCompat::storePtr<Address>(ImmWord imm, Address address);
 template void MacroAssemblerMIPSCompat::storePtr<BaseIndex>(ImmWord imm, BaseIndex address);
 
 template <typename T>
 void
 MacroAssemblerMIPSCompat::storePtr(ImmPtr imm, T address)
@@ -1816,40 +1834,39 @@ MacroAssemblerMIPSCompat::storePtr(ImmPt
 
 template void MacroAssemblerMIPSCompat::storePtr<Address>(ImmPtr imm, Address address);
 template void MacroAssemblerMIPSCompat::storePtr<BaseIndex>(ImmPtr imm, BaseIndex address);
 
 template <typename T>
 void
 MacroAssemblerMIPSCompat::storePtr(ImmGCPtr imm, T address)
 {
-    ma_li(SecondScratchReg, imm);
-    ma_sw(SecondScratchReg, address);
+    storePtr(ImmWord(uintptr_t(imm.value)), address);
 }
 
 template void MacroAssemblerMIPSCompat::storePtr<Address>(ImmGCPtr imm, Address address);
 template void MacroAssemblerMIPSCompat::storePtr<BaseIndex>(ImmGCPtr imm, BaseIndex address);
 
 void
 MacroAssemblerMIPSCompat::storePtr(Register src, const Address& address)
 {
-    ma_sw(src, address);
+    ma_store(src, address, SizeWord);
 }
 
 void
 MacroAssemblerMIPSCompat::storePtr(Register src, const BaseIndex& address)
 {
     ma_store(src, address, SizeWord);
 }
 
 void
 MacroAssemblerMIPSCompat::storePtr(Register src, AbsoluteAddress dest)
 {
-    ma_li(ScratchRegister, Imm32((uint32_t)dest.addr));
-    as_sw(src, ScratchRegister, 0);
+    movePtr(ImmPtr(dest.addr), ScratchRegister);
+    storePtr(src, Address(ScratchRegister, 0));
 }
 
 // Note: this function clobbers the input register.
 void
 MacroAssembler::clampDoubleToUint8(FloatRegister input, Register output)
 {
     MOZ_ASSERT(input != ScratchDoubleReg);
     Label positive, done;
@@ -2799,17 +2816,17 @@ MacroAssemblerMIPSCompat::tagValue(JSVal
     if (payload != dest.payloadReg())
         ma_move(dest.payloadReg(), payload);
 }
 
 void
 MacroAssemblerMIPSCompat::pushValue(ValueOperand val)
 {
     // Allocate stack slots for type and payload. One for each.
-    ma_subu(StackPointer, StackPointer, Imm32(sizeof(Value)));
+    subPtr(Imm32(sizeof(Value)), StackPointer);
     // Store type and payload.
     storeValue(val, Address(StackPointer, 0));
 }
 
 void
 MacroAssemblerMIPSCompat::pushValue(const Address& addr)
 {
     // Allocate stack slots for type and payload. One for each.
@@ -2969,79 +2986,79 @@ MacroAssembler::restoreFrameAlignmentFor
         freeStack(aic.alignmentPadding);
 }
 
 void
 MacroAssemblerMIPSCompat::handleFailureWithHandlerTail(void* handler)
 {
     // Reserve space for exception information.
     int size = (sizeof(ResumeFromException) + ABIStackAlignment) & ~(ABIStackAlignment - 1);
-    ma_subu(StackPointer, StackPointer, Imm32(size));
+    subPtr(Imm32(size), StackPointer);
     ma_move(a0, StackPointer); // Use a0 since it is a first function argument
 
     // Call the handler.
     asMasm().setupUnalignedABICall(a1);
     asMasm().passABIArg(a0);
     asMasm().callWithABI(handler);
 
     Label entryFrame;
     Label catch_;
     Label finally;
     Label return_;
     Label bailout;
 
     // Already clobbered a0, so use it...
-    ma_lw(a0, Address(StackPointer, offsetof(ResumeFromException, kind)));
+    load32(Address(StackPointer, offsetof(ResumeFromException, kind)), a0);
     branch32(Assembler::Equal, a0, Imm32(ResumeFromException::RESUME_ENTRY_FRAME), &entryFrame);
     branch32(Assembler::Equal, a0, Imm32(ResumeFromException::RESUME_CATCH), &catch_);
     branch32(Assembler::Equal, a0, Imm32(ResumeFromException::RESUME_FINALLY), &finally);
     branch32(Assembler::Equal, a0, Imm32(ResumeFromException::RESUME_FORCED_RETURN), &return_);
     branch32(Assembler::Equal, a0, Imm32(ResumeFromException::RESUME_BAILOUT), &bailout);
 
     breakpoint(); // Invalid kind.
 
     // No exception handler. Load the error value, load the new stack pointer
     // and return from the entry frame.
     bind(&entryFrame);
     moveValue(MagicValue(JS_ION_ERROR), JSReturnOperand);
-    ma_lw(StackPointer, Address(StackPointer, offsetof(ResumeFromException, stackPointer)));
+    loadPtr(Address(StackPointer, offsetof(ResumeFromException, stackPointer)), StackPointer);
 
     // We're going to be returning by the ion calling convention
     ma_pop(ra);
     as_jr(ra);
     as_nop();
 
     // If we found a catch handler, this must be a baseline frame. Restore
     // state and jump to the catch block.
     bind(&catch_);
-    ma_lw(a0, Address(StackPointer, offsetof(ResumeFromException, target)));
-    ma_lw(BaselineFrameReg, Address(StackPointer, offsetof(ResumeFromException, framePointer)));
-    ma_lw(StackPointer, Address(StackPointer, offsetof(ResumeFromException, stackPointer)));
+    loadPtr(Address(StackPointer, offsetof(ResumeFromException, target)), a0);
+    loadPtr(Address(StackPointer, offsetof(ResumeFromException, framePointer)), BaselineFrameReg);
+    loadPtr(Address(StackPointer, offsetof(ResumeFromException, stackPointer)), StackPointer);
     jump(a0);
 
     // If we found a finally block, this must be a baseline frame. Push
     // two values expected by JSOP_RETSUB: BooleanValue(true) and the
     // exception.
     bind(&finally);
     ValueOperand exception = ValueOperand(a1, a2);
     loadValue(Address(sp, offsetof(ResumeFromException, exception)), exception);
 
-    ma_lw(a0, Address(sp, offsetof(ResumeFromException, target)));
-    ma_lw(BaselineFrameReg, Address(sp, offsetof(ResumeFromException, framePointer)));
-    ma_lw(sp, Address(sp, offsetof(ResumeFromException, stackPointer)));
+    loadPtr(Address(sp, offsetof(ResumeFromException, target)), a0);
+    loadPtr(Address(sp, offsetof(ResumeFromException, framePointer)), BaselineFrameReg);
+    loadPtr(Address(sp, offsetof(ResumeFromException, stackPointer)), sp);
 
     pushValue(BooleanValue(true));
     pushValue(exception);
     jump(a0);
 
     // Only used in debug mode. Return BaselineFrame->returnValue() to the
     // caller.
     bind(&return_);
-    ma_lw(BaselineFrameReg, Address(StackPointer, offsetof(ResumeFromException, framePointer)));
-    ma_lw(StackPointer, Address(StackPointer, offsetof(ResumeFromException, stackPointer)));
+    loadPtr(Address(StackPointer, offsetof(ResumeFromException, framePointer)), BaselineFrameReg);
+    loadPtr(Address(StackPointer, offsetof(ResumeFromException, stackPointer)), StackPointer);
     loadValue(Address(BaselineFrameReg, BaselineFrame::reverseOffsetOfReturnValue()),
               JSReturnOperand);
     ma_move(StackPointer, BaselineFrameReg);
     pop(BaselineFrameReg);
 
     // If profiling is enabled, then update the lastProfilingFrame to refer to caller
     // frame before returning.
     {
@@ -3053,19 +3070,19 @@ MacroAssemblerMIPSCompat::handleFailureW
         bind(&skipProfilingInstrumentation);
     }
 
     ret();
 
     // If we are bailing out to baseline to handle an exception, jump to
     // the bailout tail stub.
     bind(&bailout);
-    ma_lw(a2, Address(sp, offsetof(ResumeFromException, bailoutInfo)));
+    loadPtr(Address(sp, offsetof(ResumeFromException, bailoutInfo)), a2);
     ma_li(ReturnReg, Imm32(BAILOUT_RETURN_OK));
-    ma_lw(a1, Address(sp, offsetof(ResumeFromException, target)));
+    loadPtr(Address(sp, offsetof(ResumeFromException, target)), a1);
     jump(a1);
 }
 
 CodeOffsetLabel
 MacroAssemblerMIPSCompat::toggledJump(Label* label)
 {
     CodeOffsetLabel ret(nextOffset().getOffset());
     ma_b(label);
@@ -3220,17 +3237,17 @@ MacroAssembler::Push(const Imm32 imm)
     ma_li(ScratchRegister, imm);
     ma_push(ScratchRegister);
     adjustFrame(sizeof(intptr_t));
 }
 
 void
 MacroAssembler::Push(const ImmWord imm)
 {
-    ma_li(ScratchRegister, Imm32(imm.value));
+    ma_li(ScratchRegister, imm);
     ma_push(ScratchRegister);
     adjustFrame(sizeof(intptr_t));
 }
 
 void
 MacroAssembler::Push(const ImmPtr imm)
 {
     Push(ImmWord(uintptr_t(imm.value)));
@@ -3264,17 +3281,17 @@ MacroAssembler::Pop(const ValueOperand& 
     popValue(val);
     framePushed_ -= sizeof(Value);
 }
 
 void
 MacroAssembler::reserveStack(uint32_t amount)
 {
     if (amount)
-        ma_subu(StackPointer, StackPointer, Imm32(amount));
+        subPtr(Imm32(amount), StackPointer);
     adjustFrame(amount);
 }
 
 // ===============================================================
 // Simple call functions.
 
 void
 MacroAssembler::call(Register reg)
@@ -3310,53 +3327,53 @@ MacroAssembler::call(ImmPtr target)
     ma_call(target);
 }
 
 void
 MacroAssembler::call(JitCode* c)
 {
     BufferOffset bo = m_buffer.nextOffset();
     addPendingJump(bo, ImmPtr(c->raw()), Relocation::JITCODE);
-    ma_liPatchable(ScratchRegister, Imm32((uint32_t)c->raw()));
+    ma_liPatchable(ScratchRegister, ImmPtr(c->raw()));
     callJitNoProfiler(ScratchRegister);
 }
 
 void
 MacroAssembler::callAndPushReturnAddress(Register callee)
 {
     // Push return address during jalr delay slot.
-    as_addiu(StackPointer, StackPointer, -sizeof(intptr_t));
+    subPtr(Imm32(sizeof(intptr_t)), StackPointer);
     as_jalr(callee);
-    as_sw(ra, StackPointer, 0);
+    storePtr(ra, Address(StackPointer, 0));
 }
 
 void
 MacroAssembler::callAndPushReturnAddress(Label* label)
 {
     // Push return address during bal delay slot.
-    as_addiu(StackPointer, StackPointer, -sizeof(intptr_t));
+    subPtr(Imm32(sizeof(intptr_t)), StackPointer);
     ma_bal(label, DontFillDelaySlot);
-    as_sw(ra, StackPointer, 0);
+    storePtr(ra, Address(StackPointer, 0));
 }
 
 // ===============================================================
 // ABI function calls.
 
 void
 MacroAssembler::setupUnalignedABICall(Register scratch)
 {
     setupABICall();
     dynamicAlignment_ = true;
 
     ma_move(scratch, StackPointer);
 
     // Force sp to be aligned
-    ma_subu(StackPointer, StackPointer, Imm32(sizeof(uint32_t)));
+    subPtr(Imm32(sizeof(uintptr_t)), StackPointer);
     ma_and(StackPointer, StackPointer, Imm32(~(ABIStackAlignment - 1)));
-    as_sw(scratch, StackPointer, 0);
+    storePtr(scratch, Address(StackPointer, 0));
 }
 
 void
 MacroAssembler::callWithABIPre(uint32_t* stackAdjust, bool callFromAsmJS)
 {
     MOZ_ASSERT(inCall_);
     uint32_t stackForCall = abiArgs_.stackBytesConsumedSoFar();
 
@@ -3370,19 +3387,19 @@ MacroAssembler::callWithABIPre(uint32_t*
         stackForCall += ComputeByteAlignment(stackForCall + framePushed() + alignmentAtPrologue,
                                              ABIStackAlignment);
     }
 
     *stackAdjust = stackForCall;
     reserveStack(stackForCall);
 
     // Save $ra because call is going to clobber it. Restore it in
-    // callWithABIPost. NOTE: This is needed for calls from BaselineIC.
+    // callWithABIPost. NOTE: This is needed for calls from SharedIC.
     // Maybe we can do this differently.
-    ma_sw(ra, Address(StackPointer, stackForCall - sizeof(intptr_t)));
+    storePtr(ra, Address(StackPointer, stackForCall - sizeof(intptr_t)));
 
     // Position all arguments.
     {
         enoughMemory_ = enoughMemory_ && moveResolver_.resolve();
         if (!enoughMemory_)
             return;
 
         MoveEmitter emitter(*this);
@@ -3392,21 +3409,21 @@ MacroAssembler::callWithABIPre(uint32_t*
 
     assertStackAlignment(ABIStackAlignment);
 }
 
 void
 MacroAssembler::callWithABIPost(uint32_t stackAdjust, MoveOp::Type result)
 {
     // Restore ra value (as stored in callWithABIPre()).
-    ma_lw(ra, Address(StackPointer, stackAdjust - sizeof(intptr_t)));
+    loadPtr(Address(StackPointer, stackAdjust - sizeof(intptr_t)), ra);
 
     if (dynamicAlignment_) {
         // Restore sp value from stack (as stored in setupUnalignedABICall()).
-        ma_lw(StackPointer, Address(StackPointer, stackAdjust));
+        loadPtr(Address(StackPointer, stackAdjust), StackPointer);
         // Use adjustFrame instead of freeStack because we already restored sp.
         adjustFrame(-stackAdjust);
     } else {
         freeStack(stackAdjust);
     }
 
 #ifdef DEBUG
     MOZ_ASSERT(inCall_);
@@ -3426,17 +3443,17 @@ MacroAssembler::callWithABINoProfiler(Re
     call(t9);
     callWithABIPost(stackAdjust, result);
 }
 
 void
 MacroAssembler::callWithABINoProfiler(const Address& fun, MoveOp::Type result)
 {
     // Load the callee in t9, as above.
-    ma_lw(t9, Address(fun.base, fun.offset));
+    loadPtr(Address(fun.base, fun.offset), t9);
     uint32_t stackAdjust;
     callWithABIPre(&stackAdjust);
     call(t9);
     callWithABIPost(stackAdjust, result);
 }
 
 // ===============================================================
 // Jit Frames.
--- a/js/src/jit/mips32/MacroAssembler-mips32.h
+++ b/js/src/jit/mips32/MacroAssembler-mips32.h
@@ -83,17 +83,19 @@ class MacroAssemblerMIPS : public Assemb
     void ma_move(Register rd, Register rs);
 
     void ma_li(Register dest, ImmGCPtr ptr);
 
     void ma_li(Register dest, AbsoluteLabel* label);
 
     void ma_li(Register dest, Imm32 imm);
     void ma_liPatchable(Register dest, Imm32 imm);
+    void ma_li(Register dest, ImmWord imm);
     void ma_liPatchable(Register dest, ImmPtr imm);
+    void ma_liPatchable(Register dest, ImmWord imm);
 
     // Shift operations
     void ma_sll(Register rd, Register rt, Imm32 shift);
     void ma_srl(Register rd, Register rt, Imm32 shift);
     void ma_sra(Register rd, Register rt, Imm32 shift);
     void ma_ror(Register rd, Register rt, Imm32 shift);
     void ma_rol(Register rd, Register rt, Imm32 shift);
 
@@ -175,17 +177,17 @@ class MacroAssemblerMIPS : public Assemb
 
     void ma_pop(Register r);
     void ma_push(Register r);
 
     // branches when done from within mips-specific code
     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);
+        ma_b(lhs, ImmWord(uintptr_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, ScratchRegister, l, c, jumpKind);
     }
     void ma_b(Register lhs, ImmWord imm, Label* l, Condition c, JumpKind jumpKind = LongJump)
     {
@@ -196,17 +198,17 @@ class MacroAssemblerMIPS : public Assemb
         ma_b(addr, Imm32(uint32_t(imm.value)), 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, ImmGCPtr 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_load(ScratchRegister, addr, SizeWord);
         ma_b(ScratchRegister, rhs, l, c, jumpKind);
     }
 
     void ma_b(Label* l, JumpKind jumpKind = LongJump);
     void ma_bal(Label* l, DelaySlotFill delaySlotFill = FillDelaySlot);
 
     // fp instructions
     void ma_lis(FloatRegister dest, float value);
@@ -317,44 +319,44 @@ class MacroAssemblerMIPSCompat : public 
 
     void computeEffectiveAddress(const Address& address, Register dest) {
         ma_addu(dest, address.base, Imm32(address.offset));
     }
 
     void computeEffectiveAddress(const BaseIndex& address, Register dest) {
         computeScaledAddress(address, dest);
         if (address.offset) {
-            ma_addu(dest, dest, Imm32(address.offset));
+            addPtr(Imm32(address.offset), dest);
         }
     }
 
     void j(Label* dest) {
         ma_b(dest);
     }
 
     void mov(Register src, Register dest) {
-        as_or(dest, src, zero);
+        as_ori(dest, src, 0);
     }
     void mov(ImmWord imm, Register dest) {
-        ma_li(dest, Imm32(imm.value));
+        ma_li(dest, imm);
     }
     void mov(ImmPtr imm, Register dest) {
         mov(ImmWord(uintptr_t(imm.value)), dest);
     }
     void mov(Register src, Address dest) {
         MOZ_CRASH("NYI-IC");
     }
     void mov(Address src, Register dest) {
         MOZ_CRASH("NYI-IC");
     }
 
     void branch(JitCode* c) {
         BufferOffset bo = m_buffer.nextOffset();
         addPendingJump(bo, ImmPtr(c->raw()), Relocation::JITCODE);
-        ma_liPatchable(ScratchRegister, Imm32((uint32_t)c->raw()));
+        ma_liPatchable(ScratchRegister, ImmPtr(c->raw()));
         as_jr(ScratchRegister);
         as_nop();
     }
     void branch(const Register reg) {
         as_jr(reg);
         as_nop();
     }
     void nop() {
@@ -362,35 +364,35 @@ class MacroAssemblerMIPSCompat : public 
     }
     void ret() {
         ma_pop(ra);
         as_jr(ra);
         as_nop();
     }
     void retn(Imm32 n) {
         // pc <- [sp]; sp += n
-        ma_lw(ra, Address(StackPointer, 0));
-        ma_addu(StackPointer, StackPointer, n);
+        loadPtr(Address(StackPointer, 0), ra);
+        addPtr(n, StackPointer);
         as_jr(ra);
         as_nop();
     }
     void push(Imm32 imm) {
         ma_li(ScratchRegister, imm);
         ma_push(ScratchRegister);
     }
     void push(ImmWord imm) {
-        ma_li(ScratchRegister, Imm32(imm.value));
+        ma_li(ScratchRegister, imm);
         ma_push(ScratchRegister);
     }
     void push(ImmGCPtr imm) {
         ma_li(ScratchRegister, imm);
         ma_push(ScratchRegister);
     }
     void push(const Address& address) {
-        ma_lw(ScratchRegister, address);
+        loadPtr(address, ScratchRegister);
         ma_push(ScratchRegister);
     }
     void push(Register reg) {
         ma_push(reg);
     }
     void push(FloatRegister reg) {
         ma_push(reg);
     }
@@ -418,32 +420,32 @@ class MacroAssemblerMIPSCompat : public 
     CodeOffsetLabel pushWithPatch(ImmWord imm) {
         CodeOffsetLabel label = movWithPatch(imm, ScratchRegister);
         ma_push(ScratchRegister);
         return label;
     }
 
     CodeOffsetLabel movWithPatch(ImmWord imm, Register dest) {
         CodeOffsetLabel label = CodeOffsetLabel(currentOffset());
-        ma_liPatchable(dest, Imm32(imm.value));
+        ma_liPatchable(dest, imm);
         return label;
     }
     CodeOffsetLabel movWithPatch(ImmPtr imm, Register dest) {
         return movWithPatch(ImmWord(uintptr_t(imm.value)), dest);
     }
 
     void jump(Label* label) {
         ma_b(label);
     }
     void jump(Register reg) {
         as_jr(reg);
         as_nop();
     }
     void jump(const Address& address) {
-        ma_lw(ScratchRegister, address);
+        loadPtr(address, ScratchRegister);
         as_jr(ScratchRegister);
         as_nop();
     }
 
     void jump(JitCode* code) {
         branch(code);
     }
 
@@ -550,29 +552,30 @@ class MacroAssemblerMIPSCompat : public 
     void branch32(Condition cond, const Operand& lhs, Imm32 rhs, Label* label) {
         if (lhs.getTag() == Operand::REG) {
             ma_b(lhs.toReg(), rhs, label, cond);
         } else {
             branch32(cond, lhs.toAddress(), rhs, label);
         }
     }
     void branch32(Condition cond, const Address& lhs, Register rhs, Label* label) {
-        ma_lw(ScratchRegister, lhs);
-        ma_b(ScratchRegister, rhs, label, cond);
+        load32(lhs, SecondScratchReg);
+        ma_b(SecondScratchReg, rhs, label, cond);
     }
     void branch32(Condition cond, const Address& lhs, Imm32 rhs, Label* label) {
-        ma_lw(SecondScratchReg, lhs);
+        load32(lhs, SecondScratchReg);
         ma_b(SecondScratchReg, rhs, label, cond);
     }
     void branch32(Condition cond, const BaseIndex& lhs, Imm32 rhs, Label* label) {
         load32(lhs, SecondScratchReg);
         ma_b(SecondScratchReg, rhs, label, cond);
     }
     void branchPtr(Condition cond, const Address& lhs, Register rhs, Label* label) {
-        branch32(cond, lhs, rhs, label);
+        loadPtr(lhs, SecondScratchReg);
+        ma_b(SecondScratchReg, rhs, label, cond);
     }
 
     void branchPrivatePtr(Condition cond, const Address& lhs, ImmPtr ptr, Label* label) {
         branchPtr(cond, lhs, ptr, label);
     }
 
     void branchPrivatePtr(Condition cond, const Address& lhs, Register ptr, Label* label) {
         branchPtr(cond, lhs, ptr, label);
@@ -644,55 +647,62 @@ class MacroAssemblerMIPSCompat : public 
             ma_b(ScratchRegister, ScratchRegister, label, cond);
         }
     }
     void branchTest32(Condition cond, Register lhs, Imm32 imm, Label* label) {
         ma_li(ScratchRegister, imm);
         branchTest32(cond, lhs, ScratchRegister, label);
     }
     void branchTest32(Condition cond, const Address& address, Imm32 imm, Label* label) {
-        ma_lw(SecondScratchReg, address);
+        load32(address, SecondScratchReg);
         branchTest32(cond, SecondScratchReg, imm, label);
     }
     void branchTest32(Condition cond, AbsoluteAddress address, Imm32 imm, Label* label) {
-        loadPtr(address, ScratchRegister);
+        load32(address, ScratchRegister);
         branchTest32(cond, ScratchRegister, imm, label);
     }
     void branchTestPtr(Condition cond, Register lhs, Register rhs, Label* label) {
-        branchTest32(cond, lhs, rhs, label);
+        MOZ_ASSERT(cond == Zero || cond == NonZero || cond == Signed || cond == NotSigned);
+        if (lhs == rhs) {
+            ma_b(lhs, rhs, label, cond);
+        } else {
+            as_and(ScratchRegister, lhs, rhs);
+            ma_b(ScratchRegister, ScratchRegister, label, cond);
+        }
     }
     void branchTestPtr(Condition cond, Register lhs, const Imm32 rhs, Label* label) {
-        branchTest32(cond, lhs, rhs, label);
+        ma_li(ScratchRegister, rhs);
+        branchTestPtr(cond, lhs, ScratchRegister, label);
     }
     void branchTestPtr(Condition cond, const Address& lhs, Imm32 imm, Label* label) {
-        branchTest32(cond, lhs, imm, label);
+        loadPtr(lhs, SecondScratchReg);
+        branchTestPtr(cond, SecondScratchReg, imm, label);
     }
     void branchPtr(Condition cond, Register lhs, Register rhs, Label* label) {
         ma_b(lhs, rhs, label, cond);
     }
     void branchPtr(Condition cond, Register lhs, ImmGCPtr ptr, Label* label) {
-        ma_li(ScratchRegister, ptr);
-        ma_b(lhs, ScratchRegister, label, cond);
+        ma_b(lhs, ptr, label, cond);
     }
     void branchPtr(Condition cond, Register lhs, ImmWord imm, Label* label) {
-        ma_b(lhs, Imm32(imm.value), label, cond);
+        ma_b(lhs, imm, label, cond);
     }
     void branchPtr(Condition cond, Register lhs, ImmPtr imm, Label* label) {
-        branchPtr(cond, lhs, ImmWord(uintptr_t(imm.value)), label);
+        ma_b(lhs, imm, label, cond);
     }
     void branchPtr(Condition cond, Register lhs, AsmJSImmPtr imm, Label* label) {
-        movePtr(imm, ScratchRegister);
-        branchPtr(cond, lhs, ScratchRegister, label);
+        movePtr(imm, SecondScratchReg);
+        ma_b(lhs, SecondScratchReg, label, cond);
     }
     void branchPtr(Condition cond, Register lhs, Imm32 imm, Label* label) {
         ma_b(lhs, imm, label, cond);
     }
     void decBranchPtr(Condition cond, Register lhs, Imm32 imm, Label* label) {
         subPtr(imm, lhs);
-        branch32(cond, lhs, Imm32(0), label);
+        branchPtr(cond, lhs, Imm32(0), label);
     }
 
     // higher level tag testing code
     Operand ToPayload(Operand base);
     Address ToPayload(Address base) {
         return ToPayload(Operand(base)).toAddress();
     }
 
@@ -726,53 +736,51 @@ class MacroAssemblerMIPSCompat : public 
         movePtr(ptr, ScratchRegister);
         Label skipJump;
         ma_b(SecondScratchReg, ScratchRegister, &skipJump, InvertCondition(cond), ShortJump);
         CodeOffsetJump off = jumpWithPatch(label);
         bind(&skipJump);
         return off;
     }
     void branchPtr(Condition cond, Address addr, ImmGCPtr ptr, Label* label) {
-        ma_lw(SecondScratchReg, addr);
-        ma_li(ScratchRegister, ptr);
-        ma_b(SecondScratchReg, ScratchRegister, label, cond);
+        loadPtr(addr, SecondScratchReg);
+        ma_b(SecondScratchReg, ptr, label, cond);
     }
 
     void branchPtr(Condition cond, Address addr, ImmWord ptr, Label* label) {
-        ma_lw(SecondScratchReg, addr);
-        ma_b(SecondScratchReg, Imm32(ptr.value), label, cond);
+        loadPtr(addr, SecondScratchReg);
+        ma_b(SecondScratchReg, ptr, label, cond);
     }
     void branchPtr(Condition cond, Address addr, ImmPtr ptr, Label* label) {
-        branchPtr(cond, addr, ImmWord(uintptr_t(ptr.value)), label);
+        loadPtr(addr, SecondScratchReg);
+        ma_b(SecondScratchReg, ptr, label, cond);
     }
     void branchPtr(Condition cond, AbsoluteAddress addr, Register ptr, Label* label) {
-        loadPtr(addr, ScratchRegister);
-        ma_b(ScratchRegister, ptr, label, cond);
+        loadPtr(addr, SecondScratchReg);
+        ma_b(SecondScratchReg, ptr, label, cond);
     }
     void branchPtr(Condition cond, AbsoluteAddress addr, ImmWord ptr, Label* label) {
-        loadPtr(addr, ScratchRegister);
-        ma_b(ScratchRegister, Imm32(ptr.value), label, cond);
+        loadPtr(addr, SecondScratchReg);
+        ma_b(SecondScratchReg, ptr, label, cond);
     }
-    void branchPtr(Condition cond, AsmJSAbsoluteAddress addr, Register ptr,
-                   Label* label) {
-        loadPtr(addr, ScratchRegister);
-        ma_b(ScratchRegister, ptr, label, cond);
+    void branchPtr(Condition cond, AsmJSAbsoluteAddress addr, Register ptr, Label* label) {
+        loadPtr(addr, SecondScratchReg);
+        ma_b(SecondScratchReg, ptr, label, cond);
     }
     void branch32(Condition cond, AbsoluteAddress lhs, Imm32 rhs, Label* label) {
-        loadPtr(lhs, SecondScratchReg); // ma_b might use scratch
+        load32(lhs, SecondScratchReg);
         ma_b(SecondScratchReg, rhs, label, cond);
     }
     void branch32(Condition cond, AbsoluteAddress lhs, Register rhs, Label* label) {
-        loadPtr(lhs, ScratchRegister);
-        ma_b(ScratchRegister, rhs, label, cond);
+        load32(lhs, SecondScratchReg);
+        ma_b(SecondScratchReg, rhs, label, cond);
     }
-    void branch32(Condition cond, AsmJSAbsoluteAddress addr, Imm32 imm,
-                  Label* label) {
-        loadPtr(addr, ScratchRegister);
-        ma_b(ScratchRegister, imm, label, cond);
+    void branch32(Condition cond, AsmJSAbsoluteAddress addr, Imm32 imm, Label* label) {
+        load32(addr, SecondScratchReg);
+        ma_b(SecondScratchReg, imm, label, cond);
     }
 
     void loadUnboxedValue(Address address, MIRType type, AnyRegister dest) {
         if (dest.isFloat())
             loadInt32OrDouble(address, dest.fpu());
         else
             ma_lw(dest.gpr(), address);
     }
@@ -787,17 +795,17 @@ class MacroAssemblerMIPSCompat : public 
     template <typename T>
     void storeUnboxedValue(ConstantOrRegister value, MIRType valueType, const T& dest,
                            MIRType slotType);
 
     template <typename T>
     void storeUnboxedPayload(ValueOperand value, T address, size_t nbytes) {
         switch (nbytes) {
           case 4:
-            storePtr(value.payloadReg(), address);
+            store32(value.payloadReg(), address);
             return;
           case 1:
             store8(value.payloadReg(), address);
             return;
           default: MOZ_CRASH("Bad payload width");
         }
     }
 
@@ -1149,16 +1157,17 @@ class MacroAssemblerMIPSCompat : public 
     void load16SignExtend(const BaseIndex& src, Register dest);
 
     void load16ZeroExtend(const Address& address, Register dest);
     void load16ZeroExtend(const BaseIndex& src, Register dest);
 
     void load32(const Address& address, Register dest);
     void load32(const BaseIndex& address, Register dest);
     void load32(AbsoluteAddress address, Register dest);
+    void load32(AsmJSAbsoluteAddress address, Register dest);
 
     void loadPtr(const Address& address, Register dest);
     void loadPtr(const BaseIndex& src, Register dest);
     void loadPtr(AbsoluteAddress address, Register dest);
     void loadPtr(AsmJSAbsoluteAddress address, Register dest);
 
     void loadPrivate(const Address& address, Register dest);
 
@@ -1356,17 +1365,17 @@ class MacroAssemblerMIPSCompat : public 
     }
 
     void ma_storeImm(Imm32 imm, const Address& addr) {
         ma_sw(imm, addr);
     }
 
     BufferOffset ma_BoundsCheck(Register bounded) {
         BufferOffset bo = m_buffer.nextOffset();
-        ma_liPatchable(bounded, Imm32(0));
+        ma_liPatchable(bounded, ImmWord(0));
         return bo;
     }
 
     void moveFloat32(FloatRegister src, FloatRegister dest) {
         as_movs(dest, src);
     }
 
     void branchPtrInNurseryRange(Condition cond, Register ptr, Register temp, Label* label);
--- a/js/src/jit/mips32/Simulator-mips32.cpp
+++ b/js/src/jit/mips32/Simulator-mips32.cpp
@@ -1821,16 +1821,19 @@ typedef int64_t (*Prototype_General7)(in
                                       int32_t arg4, int32_t arg5, int32_t arg6);
 typedef int64_t (*Prototype_General8)(int32_t arg0, int32_t arg1, int32_t arg2, int32_t arg3,
                                       int32_t arg4, int32_t arg5, int32_t arg6, int32_t arg7);
 
 typedef double (*Prototype_Double_None)();
 typedef double (*Prototype_Double_Double)(double arg0);
 typedef double (*Prototype_Double_Int)(int32_t arg0);
 typedef int32_t (*Prototype_Int_Double)(double arg0);
+typedef int32_t (*Prototype_Int_DoubleIntInt)(double arg0, int32_t arg1, int32_t arg2);
+typedef int32_t (*Prototype_Int_IntDoubleIntInt)(int32_t arg0, double arg1, int32_t arg2,
+                                                 int32_t arg3);
 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);
@@ -1940,16 +1943,30 @@ Simulator::softwareInterrupt(SimInstruct
             double dval0, dval1;
             int32_t ival;
             getFpArgs(&dval0, &dval1, &ival);
             Prototype_Int_Double target = reinterpret_cast<Prototype_Int_Double>(external);
             int32_t res = target(dval0);
             setRegister(v0, res);
             break;
           }
+          case Args_Int_DoubleIntInt: {
+            double dval = getFpuRegisterDouble(12);
+            Prototype_Int_DoubleIntInt target = reinterpret_cast<Prototype_Int_DoubleIntInt>(external);
+            int32_t res = target(dval, arg2, arg3);
+            setRegister(v0, res);
+            break;
+          }
+          case Args_Int_IntDoubleIntInt: {
+            double dval = getDoubleFromRegisterPair(a2);
+            Prototype_Int_IntDoubleIntInt target = reinterpret_cast<Prototype_Int_IntDoubleIntInt>(external);
+            int32_t res = target(arg0, dval, arg4, arg5);
+            setRegister(v0, res);
+            break;
+          }
           case Args_Double_Double: {
             double dval0, dval1;
             int32_t ival;
             getFpArgs(&dval0, &dval1, &ival);
             Prototype_Double_Double target = reinterpret_cast<Prototype_Double_Double>(external);
             double dresult = target(dval0);
             setCallResultDouble(dresult);
             break;
--- a/js/src/jit/shared/LIR-shared.h
+++ b/js/src/jit/shared/LIR-shared.h
@@ -3306,16 +3306,48 @@ class LFromCharCode : public LInstructio
         setOperand(0, code);
     }
 
     const LAllocation* code() {
         return this->getOperand(0);
     }
 };
 
+// Calculates sincos(x) and returns two values (sin/cos).
+class LSinCos : public LCallInstructionHelper<2, 1, 2>
+{
+  public:
+    LIR_HEADER(SinCos)
+
+    LSinCos(const LAllocation &input, const LDefinition &temp, const LDefinition &temp2)
+    {
+        setOperand(0, input);
+        setTemp(0, temp);
+        setTemp(1, temp2);
+    }
+    const LAllocation *input() {
+        return getOperand(0);
+    }
+    const LDefinition *outputSin() {
+        return getDef(0);
+    }
+    const LDefinition *outputCos() {
+        return getDef(1);
+    }
+    const LDefinition *temp() {
+        return getTemp(0);
+    }
+    const LDefinition *temp2() {
+        return getTemp(1);
+    }
+    const MSinCos *mir() const {
+        return mir_->toSinCos();
+    }
+};
+
 class LStringSplit : public LCallInstructionHelper<1, 2, 0>
 {
   public:
     LIR_HEADER(StringSplit)
 
     LStringSplit(const LAllocation& string, const LAllocation& separator) {
         setOperand(0, string);
         setOperand(1, separator);
--- a/js/src/jit/shared/LOpcodes-shared.h
+++ b/js/src/jit/shared/LOpcodes-shared.h
@@ -157,16 +157,17 @@
     _(DivPowTwoI)                   \
     _(ModI)                         \
     _(ModPowTwoI)                   \
     _(ModD)                         \
     _(BinaryV)                      \
     _(Concat)                       \
     _(CharCodeAt)                   \
     _(FromCharCode)                 \
+    _(SinCos)                       \
     _(StringSplit)                  \
     _(Int32ToDouble)                \
     _(Float32ToDouble)              \
     _(DoubleToFloat32)              \
     _(Int32ToFloat32)               \
     _(ValueToDouble)                \
     _(ValueToInt32)                 \
     _(ValueToFloat32)               \
--- a/js/src/jit/shared/Lowering-shared-inl.h
+++ b/js/src/jit/shared/Lowering-shared-inl.h
@@ -171,16 +171,45 @@ LIRGeneratorShared::defineReturn(LInstru
         lir->setDef(0, LDefinition(vreg, type, LGeneralReg(ReturnReg)));
         break;
     }
 
     mir->setVirtualRegister(vreg);
     add(lir);
 }
 
+template <size_t Ops, size_t Temps> void
+LIRGeneratorShared::defineSinCos(LInstructionHelper<2, Ops, Temps> *lir, MDefinition *mir,
+                                 LDefinition::Policy policy)
+{
+    MOZ_ASSERT(lir->isCall());
+
+    uint32_t vreg = getVirtualRegister();
+    lir->setDef(0, LDefinition(vreg, LDefinition::DOUBLE, LFloatReg(ReturnDoubleReg)));
+#if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_ARM64)
+    lir->setDef(1, LDefinition(vreg + VREG_INCREMENT, LDefinition::DOUBLE, LFloatReg(d1)));
+#elif defined(JS_CODEGEN_MIPS)
+    lir->setDef(1, LDefinition(vreg + VREG_INCREMENT, LDefinition::DOUBLE, LFloatReg(f2)));
+#elif defined(JS_CODEGEN_NONE)
+    MOZ_CRASH();
+#elif defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)
+    lir->setDef(1, LDefinition(vreg + VREG_INCREMENT, LDefinition::DOUBLE, LFloatReg(xmm1)));
+#else
+#error "Unsupported architecture for SinCos"
+#endif
+
+    getVirtualRegister();
+
+    lir->setMir(mir);
+    mir->setVirtualRegister(vreg);
+    add(lir);
+
+    return;
+}
+
 // In LIR, we treat booleans and integers as the same low-level type (INTEGER).
 // When snapshotting, we recover the actual JS type from MIR. This function
 // checks that when making redefinitions, we don't accidentally coerce two
 // incompatible types.
 static inline bool
 IsCompatibleLIRCoercion(MIRType to, MIRType from)
 {
     if (to == from)
@@ -190,16 +219,40 @@ IsCompatibleLIRCoercion(MIRType to, MIRT
         return true;
     }
     // SIMD types can be coerced with from*Bits operators.
     if (IsSimdType(to) && IsSimdType(from))
         return true;
     return false;
 }
 
+
+// We can redefine the sin(x) and cos(x) function to return the sincos result.
+void
+LIRGeneratorShared::redefine(MDefinition* def, MDefinition* as, MMathFunction::Function func)
+{
+    MOZ_ASSERT(def->isMathFunction());
+    MOZ_ASSERT(def->type() == MIRType_Double && as->type() == MIRType_SinCosDouble);
+    MOZ_ASSERT(MMathFunction::Sin == func || MMathFunction::Cos == func);
+
+    ensureDefined(as);
+    MMathFunction *math = def->toMathFunction();
+
+    MOZ_ASSERT(math->function() == MMathFunction::Cos ||
+               math->function() == MMathFunction::Sin);
+
+    // The sincos returns two values:
+    // - VREG: it returns the sin's value of the sincos;
+    // - VREG + VREG_INCREMENT: it returns the cos' value of the sincos.
+    if (math->function() == MMathFunction::Sin)
+        def->setVirtualRegister(as->virtualRegister());
+    else
+        def->setVirtualRegister(as->virtualRegister() + VREG_INCREMENT);
+}
+
 void
 LIRGeneratorShared::redefine(MDefinition* def, MDefinition* as)
 {
     MOZ_ASSERT(IsCompatibleLIRCoercion(def->type(), as->type()));
 
     // Try to emit MIR marked as emitted-at-uses at, well, uses. For
     // snapshotting reasons we delay the MIRTypes match, or when we are
     // coercing between bool and int32 constants.
--- a/js/src/jit/shared/Lowering-shared.h
+++ b/js/src/jit/shared/Lowering-shared.h
@@ -137,16 +137,20 @@ class LIRGeneratorShared : public MDefin
     template <size_t Ops, size_t Temps>
     inline void defineFixed(LInstructionHelper<1, Ops, Temps>* lir, MDefinition* mir,
                             const LAllocation& output);
 
     template <size_t Ops, size_t Temps>
     inline void defineBox(LInstructionHelper<BOX_PIECES, Ops, Temps>* lir, MDefinition* mir,
                           LDefinition::Policy policy = LDefinition::REGISTER);
 
+    template <size_t Ops, size_t Temps>
+    inline void defineSinCos(LInstructionHelper<2, Ops, Temps> *lir, MDefinition *mir,
+                             LDefinition::Policy policy = LDefinition::REGISTER);
+
     inline void defineSharedStubReturn(LInstruction* lir, MDefinition* mir);
     inline void defineReturn(LInstruction* lir, MDefinition* mir);
 
     template <size_t X>
     inline void define(details::LInstructionFixedDefsTempsHelper<1, X>* lir, MDefinition* mir,
                        LDefinition::Policy policy = LDefinition::REGISTER);
     template <size_t X>
     inline void define(details::LInstructionFixedDefsTempsHelper<1, X>* lir, MDefinition* mir,
@@ -158,16 +162,19 @@ class LIRGeneratorShared : public MDefin
     // Adds a use at operand |n| of a value-typed insturction.
     inline void useBox(LInstruction* lir, size_t n, MDefinition* mir,
                        LUse::Policy policy = LUse::REGISTER, bool useAtStart = false);
 
     // Rather than defining a new virtual register, sets |ins| to have the same
     // virtual register as |as|.
     inline void redefine(MDefinition* ins, MDefinition* as);
 
+    // Redefine a sin/cos call to sincos.
+    inline void redefine(MDefinition* def, MDefinition* as, MMathFunction::Function func);
+
     TempAllocator& alloc() const {
         return graph.alloc();
     }
 
     uint32_t getVirtualRegister() {
         uint32_t vreg = lirGraph_.getVirtualRegister();
 
         // If we run out of virtual registers, mark code generation as having
--- a/js/src/jsmath.cpp
+++ b/js/src/jsmath.cpp
@@ -948,16 +948,50 @@ js::math_sin(JSContext* cx, unsigned arg
     if (args.length() == 0) {
         args.rval().setNaN();
         return true;
     }
 
     return math_sin_handle(cx, args[0], args.rval());
 }
 
+void
+js::math_sincos_uncached(double x, double *sin, double *cos)
+{
+#if defined(__GLIBC__)
+    sincos(x, sin, cos);
+#elif defined(HAVE_SINCOS)
+    __sincos(x, sin, cos);
+#else
+    *sin = js::math_sin_uncached(x);
+    *cos = js::math_cos_uncached(x);
+#endif
+}
+
+void
+js::math_sincos_impl(MathCache* mathCache, double x, double *sin, double *cos)
+{
+    unsigned indexSin;
+    unsigned indexCos;
+    bool hasSin = mathCache->isCached(x, MathCache::Sin, sin, &indexSin);
+    bool hasCos = mathCache->isCached(x, MathCache::Cos, cos, &indexCos);
+    if (!(hasSin || hasCos)) {
+        js::math_sincos_uncached(x, sin, cos);
+        mathCache->store(MathCache::Sin, x, *sin, indexSin);
+        mathCache->store(MathCache::Cos, x, *cos, indexCos);
+        return;
+    }
+
+    if (!hasSin)
+        *sin = js::math_sin_impl(mathCache, x);
+
+    if (!hasCos)
+        *cos = js::math_cos_impl(mathCache, x);
+}
+
 bool
 js::math_sqrt_handle(JSContext* cx, HandleValue number, MutableHandleValue result)
 {
     double x;
     if (!ToNumber(cx, number, &x))
         return false;
 
     MathCache* mathCache = cx->runtime()->getMathCache(cx);
--- a/js/src/jsmath.h
+++ b/js/src/jsmath.h
@@ -75,16 +75,35 @@ class MathCache
         Entry& e = table[index];
         if (e.in == x && e.id == id)
             return e.out;
         e.in = x;
         e.id = id;
         return e.out = f(x);
     }
 
+    bool isCached(double x, MathFuncId id, double *r, unsigned *index) {
+        *index = hash(x, id);
+        Entry& e = table[*index];
+        if (e.in == x && e.id == id) {
+            *r = e.out;
+            return true;
+        }
+        return false;
+    }
+
+    void store(MathFuncId id, double x, double v, unsigned index) {
+        Entry &e = table[index];
+        if (e.in == x && e.id == id)
+            return;
+        e.in = x;
+        e.id = id;
+        e.out = v;
+    }
+
     size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf);
 };
 
 /*
  * JS math functions.
  */
 
 extern JSObject*
@@ -144,16 +163,22 @@ math_pow_handle(JSContext* cx, js::Handl
 
 extern bool
 math_pow(JSContext* cx, unsigned argc, js::Value* vp);
 
 extern bool
 minmax_impl(JSContext* cx, bool max, js::HandleValue a, js::HandleValue b,
             js::MutableHandleValue res);
 
+extern void
+math_sincos_uncached(double x, double *sin, double *cos);
+
+extern void
+math_sincos_impl(MathCache* mathCache, double x, double *sin, double *cos);
+
 extern bool
 math_sqrt_handle(JSContext* cx, js::HandleValue number, js::MutableHandleValue result);
 
 extern bool
 math_imul(JSContext* cx, unsigned argc, js::Value* vp);
 
 extern bool
 RoundFloat32(JSContext* cx, HandleValue v, float* out);
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -5913,16 +5913,25 @@ SetRuntimeOptions(JSRuntime* rt, const O
         if (strcmp(str, "on") == 0)
             jit::js_JitOptions.disableRangeAnalysis = false;
         else if (strcmp(str, "off") == 0)
             jit::js_JitOptions.disableRangeAnalysis = true;
         else
             return OptionFailure("ion-range-analysis", str);
     }
 
+    if (const char *str = op.getStringOption("ion-sincos")) {
+        if (strcmp(str, "on") == 0)
+            jit::js_JitOptions.disableSincos = false;
+        else if (strcmp(str, "off") == 0)
+            jit::js_JitOptions.disableSincos = true;
+        else
+            return OptionFailure("ion-sincos", str);
+    }
+
     if (const char* str = op.getStringOption("ion-sink")) {
         if (strcmp(str, "on") == 0)
             jit::js_JitOptions.disableSink = false;
         else if (strcmp(str, "off") == 0)
             jit::js_JitOptions.disableSink = true;
         else
             return OptionFailure("ion-sink", str);
     }
@@ -6251,16 +6260,23 @@ main(int argc, char** argv, char** envp)
                                "  off: disable GVN\n"
                                "  on:  enable GVN (default)\n")
         || !op.addStringOption('\0', "ion-licm", "on/off",
                                "Loop invariant code motion (default: on, off to disable)")
         || !op.addStringOption('\0', "ion-edgecase-analysis", "on/off",
                                "Find edge cases where Ion can avoid bailouts (default: on, off to disable)")
         || !op.addStringOption('\0', "ion-range-analysis", "on/off",
                                "Range analysis (default: on, off to disable)")
+#if defined(__APPLE__)
+        || !op.addStringOption('\0', "ion-sincos", "on/off",
+                               "Replace sin(x)/cos(x) to sincos(x) (default: on, off to disable)")
+#else
+        || !op.addStringOption('\0', "ion-sincos", "on/off",
+                               "Replace sin(x)/cos(x) to sincos(x) (default: off, on to enable)")
+#endif
         || !op.addStringOption('\0', "ion-sink", "on/off",
                                "Sink code motion (default: off, on to enable)")
         || !op.addStringOption('\0', "ion-loop-unrolling", "on/off",
                                "Loop unrolling (default: off, on to enable)")
         || !op.addStringOption('\0', "ion-instruction-reordering", "on/off",
                                "Instruction reordering (default: off, on to enable)")
         || !op.addBoolOption('\0', "ion-check-range-analysis",
                                "Range analysis checking")
--- a/js/src/vm/TraceLoggingTypes.h
+++ b/js/src/vm/TraceLoggingTypes.h
@@ -44,16 +44,17 @@
     _(DominatorTree)                                  \
     _(PhiAnalysis)                                    \
     _(MakeLoopsContiguous)                            \
     _(ApplyTypes)                                     \
     _(EagerSimdUnbox)                                 \
     _(AliasAnalysis)                                  \
     _(GVN)                                            \
     _(LICM)                                           \
+    _(Sincos)                                         \
     _(RangeAnalysis)                                  \
     _(LoopUnrolling)                                  \
     _(EffectiveAddressAnalysis)                       \
     _(AlignmentMaskAnalysis)                          \
     _(EliminateDeadCode)                              \
     _(ReorderInstructions)                            \
     _(EdgeCaseAnalysis)                               \
     _(EliminateRedundantChecks)                       \
--- a/js/src/vm/UbiNodeCensus.cpp
+++ b/js/src/vm/UbiNodeCensus.cpp
@@ -1,16 +1,20 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * 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/. */
 
 #include "js/UbiNodeCensus.h"
 
+#include "jscntxt.h"
+#include "jscompartment.h"
+#include "jsobjinlines.h"
+
 using namespace js;
 
 namespace JS {
 namespace ubi {
 
 void
 CountDeleter::operator()(CountBase* ptr)
 {
--- a/layout/base/RestyleManager.cpp
+++ b/layout/base/RestyleManager.cpp
@@ -85,16 +85,17 @@ RestyleManager::RestyleManager(nsPresCon
   , mHavePendingNonAnimationRestyles(false)
   , mHoverGeneration(0)
   , mRebuildAllExtraHint(nsChangeHint(0))
   , mRebuildAllRestyleHint(nsRestyleHint(0))
   , mLastUpdateForThrottledAnimations(aPresContext->RefreshDriver()->
                                         MostRecentRefresh())
   , mAnimationGeneration(0)
   , mReframingStyleContexts(nullptr)
+  , mAnimationsWithDestroyedFrame(nullptr)
   , mPendingRestyles(ELEMENT_HAS_PENDING_RESTYLE |
                      ELEMENT_IS_POTENTIAL_RESTYLE_ROOT |
                      ELEMENT_IS_CONDITIONAL_RESTYLE_ANCESTOR)
 #ifdef DEBUG
   , mIsProcessingRestyles(false)
 #endif
 #ifdef RESTYLE_LOGGING
   , mLoggingDepth(0)
@@ -1076,16 +1077,54 @@ RestyleManager::ReframingStyleContexts::
   // Before we go away, we need to flush out any frame construction that
   // was enqueued, so that we start transitions.
   // Note that this is a little bit evil in that we're calling into code
   // that calls our member functions from our destructor, but it's at
   // the beginning of our destructor, so it shouldn't be too bad.
   mRestyleManager->mPresContext->FrameConstructor()->CreateNeededFrames();
 }
 
+RestyleManager::AnimationsWithDestroyedFrame::AnimationsWithDestroyedFrame(
+                                          RestyleManager* aRestyleManager)
+  : mRestyleManager(aRestyleManager)
+  , mRestorePointer(mRestyleManager->mAnimationsWithDestroyedFrame)
+{
+  MOZ_ASSERT(!mRestyleManager->mAnimationsWithDestroyedFrame,
+             "shouldn't construct recursively");
+  mRestyleManager->mAnimationsWithDestroyedFrame = this;
+}
+
+void
+RestyleManager::AnimationsWithDestroyedFrame::StopAnimationsForElementsWithoutFrames()
+{
+  StopAnimationsWithoutFrame(mContents,
+    nsCSSPseudoElements::ePseudo_NotPseudoElement);
+  StopAnimationsWithoutFrame(mBeforeContents,
+    nsCSSPseudoElements::ePseudo_before);
+  StopAnimationsWithoutFrame(mAfterContents,
+    nsCSSPseudoElements::ePseudo_after);
+}
+
+void
+RestyleManager::AnimationsWithDestroyedFrame::StopAnimationsWithoutFrame(
+  nsTArray<nsRefPtr<nsIContent>>& aArray,
+  nsCSSPseudoElements::Type aPseudoType)
+{
+  nsAnimationManager* animationManager =
+    mRestyleManager->PresContext()->AnimationManager();
+  for (nsIContent* content : aArray) {
+    if (content->GetPrimaryFrame()) {
+      continue;
+    }
+    dom::Element* element = content->AsElement();
+
+    animationManager->StopAnimationsForElement(element, aPseudoType);
+  }
+}
+
 static inline dom::Element*
 ElementForStyleContext(nsIContent* aParentContent,
                        nsIFrame* aFrame,
                        nsCSSPseudoElements::Type aPseudoType);
 
 // Forwarded nsIDocumentObserver method, to handle restyling (and
 // passing the notification to the frame).
 nsresult
@@ -1775,16 +1814,20 @@ RestyleManager::BeginProcessingRestyles(
   }
 }
 
 void
 RestyleManager::EndProcessingRestyles()
 {
   FlushOverflowChangedTracker();
 
+  MOZ_ASSERT(mAnimationsWithDestroyedFrame);
+  mAnimationsWithDestroyedFrame->
+    StopAnimationsForElementsWithoutFrames();
+
   // Set mInStyleRefresh to false now, since the EndUpdate call might
   // add more restyles.
   mInStyleRefresh = false;
 
   if (mInRebuildAllStyleData) {
     FinishRebuildAllStyleData();
   }
 
--- a/layout/base/RestyleManager.h
+++ b/layout/base/RestyleManager.h
@@ -44,16 +44,18 @@ public:
   explicit RestyleManager(nsPresContext* aPresContext);
 
 private:
   // Private destructor, to discourage deletion outside of Release():
   ~RestyleManager()
   {
     MOZ_ASSERT(!mReframingStyleContexts,
                "temporary member should be nulled out before destruction");
+    MOZ_ASSERT(!mAnimationsWithDestroyedFrame,
+               "leaving dangling pointers from AnimationsWithDestroyedFrame");
   }
 
 public:
   NS_INLINE_DECL_REFCOUNTING(mozilla::RestyleManager)
 
   void Disconnect() {
     mPresContext = nullptr;
   }
@@ -242,16 +244,75 @@ public:
    * For the pseudo-elements, aContent must be the anonymous content
    * that we're creating for that pseudo-element, not the real element.
    */
   static bool
   TryStartingTransition(nsPresContext* aPresContext, nsIContent* aContent,
                         nsStyleContext* aOldStyleContext,
                         nsRefPtr<nsStyleContext>* aNewStyleContext /* inout */);
 
+  // AnimationsWithDestroyedFrame is used to stop animations on elements that
+  // have no frame at the end of the restyling process.
+  // It only lives during the restyling process.
+  class MOZ_STACK_CLASS AnimationsWithDestroyedFrame final {
+  public:
+    // Construct a AnimationsWithDestroyedFrame object.  The caller must
+    // ensure that aRestyleManager lives at least as long as the
+    // object.  (This is generally easy since the caller is typically a
+    // method of RestyleManager.)
+    explicit AnimationsWithDestroyedFrame(RestyleManager* aRestyleManager);
+    ~AnimationsWithDestroyedFrame()
+    {
+    }
+
+    // This method takes the content node for the generated content for
+    // animation on ::before and ::after, rather than the content node for
+    // the real element.
+    void Put(nsIContent* aContent, nsStyleContext* aStyleContext) {
+      MOZ_ASSERT(aContent);
+      nsCSSPseudoElements::Type pseudoType = aStyleContext->GetPseudoType();
+      if (pseudoType == nsCSSPseudoElements::ePseudo_NotPseudoElement) {
+        mContents.AppendElement(aContent);
+      } else if (pseudoType == nsCSSPseudoElements::ePseudo_before) {
+        MOZ_ASSERT(aContent->NodeInfo()->NameAtom() == nsGkAtoms::mozgeneratedcontentbefore);
+        mBeforeContents.AppendElement(aContent->GetParent());
+      } else if (pseudoType == nsCSSPseudoElements::ePseudo_after) {
+        MOZ_ASSERT(aContent->NodeInfo()->NameAtom() == nsGkAtoms::mozgeneratedcontentafter);
+        mAfterContents.AppendElement(aContent->GetParent());
+      }
+    }
+
+    void StopAnimationsForElementsWithoutFrames();
+
+  private:
+    void StopAnimationsWithoutFrame(nsTArray<nsRefPtr<nsIContent>>& aArray,
+                                    nsCSSPseudoElements::Type aPseudoType);
+
+    RestyleManager* mRestyleManager;
+    AutoRestore<AnimationsWithDestroyedFrame*> mRestorePointer;
+
+    // Below three arrays might include elements that have already had their
+    // animations stopped.
+    //
+    // mBeforeContents and mAfterContents hold the real element rather than
+    // the content node for the generated content (which might change during
+    // a reframe)
+    nsTArray<nsRefPtr<nsIContent>> mContents;
+    nsTArray<nsRefPtr<nsIContent>> mBeforeContents;
+    nsTArray<nsRefPtr<nsIContent>> mAfterContents;
+  };
+
+  /**
+   * Return the current AnimationsWithDestroyedFrame struct, or null if we're
+   * not currently in a restyling operation.
+   */
+  AnimationsWithDestroyedFrame* GetAnimationsWithDestroyedFrame() {
+    return mAnimationsWithDestroyedFrame;
+  }
+
 private:
   void RestyleForEmptyChange(Element* aContainer);
 
 public:
   // Restyling for a ContentInserted (notification after insertion) or
   // for a CharacterDataChanged.  |aContainer| must be non-null; when
   // the container is null, no work is needed.
   void RestyleForInsertOrChange(Element* aContainer, nsIContent* aChild);
@@ -486,16 +547,17 @@ private:
 
   OverflowChangedTracker mOverflowChangedTracker;
 
   // The total number of animation flushes by this frame constructor.
   // Used to keep the layer and animation manager in sync.
   uint64_t mAnimationGeneration;
 
   ReframingStyleContexts* mReframingStyleContexts;
+  AnimationsWithDestroyedFrame* mAnimationsWithDestroyedFrame;
 
   RestyleTracker mPendingRestyles;
 
 #ifdef DEBUG
   bool mIsProcessingRestyles;
 #endif
 
 #ifdef RESTYLE_LOGGING
--- a/layout/base/RestyleTracker.cpp
+++ b/layout/base/RestyleTracker.cpp
@@ -220,16 +220,22 @@ RestyleTracker::DoProcessRestyles()
 
   bool isTimelineRecording = false;
   nsDocShell* docShell =
     static_cast<nsDocShell*>(mRestyleManager->PresContext()->GetDocShell());
   if (docShell) {
     docShell->GetRecordProfileTimelineMarkers(&isTimelineRecording);
   }
 
+  // Create a AnimationsWithDestroyedFrame during restyling process to
+  // stop animations on elements that have no frame at the end of the
+  // restyling process.
+  RestyleManager::AnimationsWithDestroyedFrame
+    animationsWithDestroyedFrame(mRestyleManager);
+
   // Create a ReframingStyleContexts struct on the stack and put it in our
   // mReframingStyleContexts for almost all of the remaining scope of
   // this function.
   //
   // It needs to be *in* scope during BeginProcessingRestyles, which
   // might (if mDoRebuildAllStyleData is true) do substantial amounts of
   // restyle processing.
   //
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -682,16 +682,27 @@ nsFrame::DestroyFrom(nsIFrame* aDestruct
     // specifies CSS transitions.
     RestyleManager::ReframingStyleContexts* rsc =
       presContext->RestyleManager()->GetReframingStyleContexts();
     if (rsc) {
       rsc->Put(mContent, mStyleContext);
     }
   }
 
+  if (nsLayoutUtils::HasCurrentAnimations(static_cast<nsIFrame*>(this))) {
+    // If no new frame for this element is created by the end of the
+    // restyling process, stop animations for this frame
+    RestyleManager::AnimationsWithDestroyedFrame* adf =
+      presContext->RestyleManager()->GetAnimationsWithDestroyedFrame();
+    // AnimationsWithDestroyedFrame only lives during the restyling process.
+    if (adf) {
+      adf->Put(mContent, mStyleContext);
+    }
+  }
+
   shell->NotifyDestroyingFrame(this);
 
   if (mState & NS_FRAME_EXTERNAL_REFERENCE) {
     shell->ClearFrameRefs(this);
   }
 
   if (view) {
     // Break association between view and frame
--- a/layout/reftests/bugs/1127107-1a-nowrap.html
+++ b/layout/reftests/bugs/1127107-1a-nowrap.html
@@ -3,17 +3,16 @@
 <head>
   <style>
     div.test {
       /* Author expects this to prevent wrapping, and may add
          "overflow:hidden;text-overflow:ellipsis" for nice effect: */
       white-space: nowrap;
 
       /* BUT these (combined) seem to allow wrapping: */
-      -moz-hyphens: auto;
       -ms-hyphens: auto;
       -webkit-hyphens: auto;
       hyphens: auto;
       word-break: break-all;
 
       width: 200px;
       border: 1px solid black;
     }
--- a/layout/reftests/bugs/1127107-1b-pre.html
+++ b/layout/reftests/bugs/1127107-1b-pre.html
@@ -3,17 +3,16 @@
 <head>
   <style>
     div.test {
       /* Author expects this to prevent wrapping, and may add
          "overflow:hidden;text-overflow:ellipsis" for nice effect: */
       white-space: pre;
 
       /* BUT these (combined) seem to allow wrapping: */
-      -moz-hyphens: auto;
       -ms-hyphens: auto;
       -webkit-hyphens: auto;
       hyphens: auto;
       word-break: break-all;
 
       width: 200px;
       border: 1px solid black;
     }
new file mode 100644
--- /dev/null
+++ b/layout/reftests/canvas/1074733-1-ref.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="UTF-8">
+    <script type="text/javascript">
+      function bodyonload() {
+        var canvas=document.getElementById('test');
+        var ctx = canvas.getContext("2d");
+        ctx.fillStyle = 'green';
+        ctx.fillRect(-1, 50, 151, 50); // left at -1
+        ctx.fillStyle = 'red';
+        ctx.rect(-1, 100, 151, 50); // left at -1
+        ctx.fill();
+        ctx.fillStyle = 'blue';
+        ctx.fillRect(0, 150, 150, 50); // left at 0
+      }
+    </script>
+  </head>
+  <body onload="bodyonload();">
+    <canvas id="test" width="200" height="200"></canvas>
+  </body>
+</html>
+
new file mode 100644
--- /dev/null
+++ b/layout/reftests/canvas/1074733-1.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="UTF-8">
+    <script type="text/javascript">
+      function bodyonload() {
+        var canvas=document.getElementById('test');
+        var ctx = canvas.getContext("2d");
+        ctx.fillStyle = 'green';
+        ctx.fillRect(150, 50, -151, 50); // left at -1
+        ctx.fillStyle = 'red';
+        ctx.rect(150, 100, -151, 50); // left at -1
+        ctx.fill();
+        ctx.fillStyle = 'blue';
+        ctx.fillRect(150, 150, -150, 50); // left at 0
+      }
+    </script>
+  </head>
+  <body onload="bodyonload();">
+    <canvas id="test" width="200" height="200"></canvas>
+  </body>
+</html>
+
--- a/layout/reftests/canvas/reftest.list
+++ b/layout/reftests/canvas/reftest.list
@@ -98,11 +98,12 @@ fails-if(azureQuartz&&OSX==1006) == 6726
 == transformed-path.html transformed-path.html
 
 == 749467-1.html 749467-1-ref.html
 
 # You get a little bit of rounding fuzz on OSX from transforming the paths between user space and device space
 fuzzy-if(azureQuartz,2,128) fuzzy-if(d2d,12,21) fuzzy-if(d2d&&/^Windows\x20NT\x2010\.0/.test(http.oscpu),2,141) == 784573-1.html 784573-1-ref.html
 
 == 802658-1.html 802658-1-ref.html
+== 1074733-1.html 1074733-1-ref.html
 fuzzy-if(Mulet,45,2) == 1107096-invisibles.html 1107096-invisibles-ref.html
 == 1151821-1.html 1151821-1-ref.html
 == 1201272-1.html 1201272-1-ref.html
--- a/layout/reftests/text/auto-hyphenation-1-ref.html
+++ b/layout/reftests/text/auto-hyphenation-1-ref.html
@@ -1,9 +1,9 @@
 <!DOCTYPE html>
 <html>
 <body lang="en-us">
-<div style="width: 5em; -moz-hyphens: manual; font-family:sans-serif;">
+<div style="width: 5em; hyphens: manual; font-family:sans-serif;">
 su&shy;per&shy;cal&shy;ifrag&shy;ilis&shy;tic&shy;ex&shy;pi&shy;ali&shy;do&shy;cious
 </div>
 </body>
 </html>
 
--- a/layout/reftests/text/auto-hyphenation-1.html
+++ b/layout/reftests/text/auto-hyphenation-1.html
@@ -1,10 +1,10 @@
 <!DOCTYPE html>
 <html>
 <!-- simple test for automatic hyphenation -->
 <body lang="en-us">
-<div style="width: 5em; -moz-hyphens: auto; font-family:sans-serif;">
+<div style="width: 5em; hyphens: auto; font-family:sans-serif;">
 supercalifragilisticexpialidocious
 </div>
 </body>
 </html>
 
--- a/layout/reftests/text/auto-hyphenation-10-ref.html
+++ b/layout/reftests/text/auto-hyphenation-10-ref.html
@@ -1,11 +1,11 @@
 <!DOCTYPE html>
 <html>
 <meta charset="UTF-8">
 <!-- check that hyphenation is not applied when language is not specified -->
 <body>
-<div style="width: 5em; -moz-hyphens: none;">
+<div style="width: 5em; hyphens: none;">
 supercalifragilisticexpialidocious
 </div>
 </body>
 </html>
 
--- a/layout/reftests/text/auto-hyphenation-10.html
+++ b/layout/reftests/text/auto-hyphenation-10.html
@@ -1,11 +1,11 @@
 <!DOCTYPE html>
 <html>
 <meta charset="UTF-8">
 <!-- check that hyphenation is not applied when language is not specified -->
 <body>
-<div style="width: 5em; -moz-hyphens: auto;">
+<div style="width: 5em; hyphens: auto;">
 supercalifragilisticexpialidocious
 </div>
 </body>
 </html>
 
--- a/layout/reftests/text/auto-hyphenation-1a.html
+++ b/layout/reftests/text/auto-hyphenation-1a.html
@@ -1,10 +1,10 @@
 <!DOCTYPE html>
 <html>
 <!-- adding random <span>s should not affect hyphenation -->
 <body lang="en-us">
-<div style="width: 5em; -moz-hyphens: auto; font-family:sans-serif;">
+<div style="width: 5em; hyphens: auto; font-family:sans-serif;">
 super<span>cali</span>frag<span>ili</span>sti<span>cex</span>pialidoc<span>i</span>ous
 </div>
 </body>
 </html>
 
--- a/layout/reftests/text/auto-hyphenation-2-ref.html
+++ b/layout/reftests/text/auto-hyphenation-2-ref.html
@@ -1,11 +1,11 @@
 <!DOCTYPE html>
 <html>
 <body lang="en-us">
-<div style="width: 5em; -moz-hyphens: auto; font-family:sans-serif;">
+<div style="width: 5em; hyphens: auto; font-family:sans-serif;">
 supercalifragilisticexpialidocious
-<span style="-moz-hyphens:none">super<span lang="foo">cali</span>fragilisticexpialidocious</span>
+<span style="hyphens:none">super<span lang="foo">cali</span>fragilisticexpialidocious</span>
 supercalifragilisticexpialidocious
 </div>
 </body>
 </html>
 
--- a/layout/reftests/text/auto-hyphenation-2.html
+++ b/layout/reftests/text/auto-hyphenation-2.html
@@ -1,12 +1,12 @@
 <!DOCTYPE html>
 <html>
 <!-- mixed languages in a word should inhibit automatic hyphenation -->
 <body lang="en-us">
-<div style="width: 5em; -moz-hyphens: auto; font-family:sans-serif;">
+<div style="width: 5em; hyphens: auto; font-family:sans-serif;">
 supercalifragilisticexpialidocious
 super<span lang="foo">cali</span>fragilisticexpialidocious
 supercalifragilisticexpialidocious
 </div>
 </body>
 </html>
 
--- a/layout/reftests/text/auto-hyphenation-3.html
+++ b/layout/reftests/text/auto-hyphenation-3.html
@@ -1,10 +1,10 @@
 <!DOCTYPE html>
 <html>
-<!-- check that -moz-hyphens:none prevents break at &shy; -->
+<!-- check that hyphens:none prevents break at &shy; -->
 <body lang="en-us">
-<div style="width: 5em; -moz-hyphens: none;">
+<div style="width: 5em; hyphens: none;">
 su&shy;per&shy;cal&shy;ifrag&shy;ilis&shy;tic&shy;ex&shy;pi&shy;ali&shy;do&shy;cious
 </div>
 </body>
 </html>
 
--- a/layout/reftests/text/auto-hyphenation-4-ref.html
+++ b/layout/reftests/text/auto-hyphenation-4-ref.html
@@ -1,9 +1,9 @@
 <!DOCTYPE html>
 <html>
 <body lang="x-unknown-language">
-<div style="width: 5em; -moz-hyphens: none;">
+<div style="width: 5em; hyphens: none;">
 supercalifragilisticexpialidocious
 </div>
 </body>
 </html>
 
--- a/layout/reftests/text/auto-hyphenation-4.html
+++ b/layout/reftests/text/auto-hyphenation-4.html
@@ -1,10 +1,10 @@
 <!DOCTYPE html>
 <html>
 <!-- check that hyphenation is not applied to unknown language -->
 <body lang="x-unknown-language">
-<div style="width: 5em; -moz-hyphens: auto;">
+<div style="width: 5em; hyphens: auto;">
 supercalifragilisticexpialidocious
 </div>
 </body>
 </html>
 
--- a/layout/reftests/text/auto-hyphenation-5-ref.html
+++ b/layout/reftests/text/auto-hyphenation-5-ref.html
@@ -1,17 +1,17 @@
 <!DOCTYPE html>
 <html>
 <head>
 <style type="text/css">
 div {
   margin:       10px;
   width:        10px;
   font-family:  monospace;
-  -moz-hyphens: manual;
+  hyphens: manual;
 }
 </style>
 </head>
 <!-- test some hyphenations that involve overlapping patterns -->
 <body lang="en-us">
 <div>
 photo
 </div>
--- a/layout/reftests/text/auto-hyphenation-5.html
+++ b/layout/reftests/text/auto-hyphenation-5.html
@@ -1,17 +1,17 @@
 <!DOCTYPE html>
 <html>
 <head>
 <style type="text/css">
 div {
   margin:       10px;
   width:        10px;
   font-family:  monospace;
-  -moz-hyphens: auto;
+  hyphens: auto;
 }
 </style>
 </head>
 <!-- test some hyphenations that involve overlapping patterns -->
 <body lang="en-us">
 <div>
 photo
 </div>
--- a/layout/reftests/text/auto-hyphenation-6-ref.html
+++ b/layout/reftests/text/auto-hyphenation-6-ref.html
@@ -1,9 +1,9 @@
 <!DOCTYPE html>
 <html>
 <body lang="en-us">
-<div style="width: 0; -moz-hyphens: manual;">
+<div style="width: 0; hyphens: manual;">
 hy&shy;<span style="color:red">phen&shy;</span>ation
 </div>
 </body>
 </html>
 
--- a/layout/reftests/text/auto-hyphenation-6.html
+++ b/layout/reftests/text/auto-hyphenation-6.html
@@ -1,10 +1,10 @@
 <!DOCTYPE html>
 <html>
 <!-- style changes don't break hyphenation -->
 <body lang="en-us">
-<div style="width: 0; -moz-hyphens: auto;">
+<div style="width: 0; hyphens: auto;">
 hy<span style="color:red">phen</span>ation
 </div>
 </body>
 </html>
 
--- a/layout/reftests/text/auto-hyphenation-7-ref.html
+++ b/layout/reftests/text/auto-hyphenation-7-ref.html
@@ -1,9 +1,9 @@
 <!DOCTYPE html>
 <html>
 <body lang="en-us">
-<div style="width: 0; -moz-hyphens: manual;">
+<div style="width: 0; hyphens: manual;">
 h<span style="color:red">y&shy;phen&shy;a</span>tion
 </div>
 </body>
 </html>
 
--- a/layout/reftests/text/auto-hyphenation-7.html
+++ b/layout/reftests/text/auto-hyphenation-7.html
@@ -1,10 +1,10 @@
 <!DOCTYPE html>
 <html>
 <!-- style changes don't break hyphenation -->
 <body lang="en-us">
-<div style="width: 0; -moz-hyphens: auto;">
+<div style="width: 0; hyphens: auto;">
 h<span style="color:red">yphena</span>tion
 </div>
 </body>
 </html>
 
--- a/layout/reftests/text/auto-hyphenation-8-ref.html
+++ b/layout/reftests/text/auto-hyphenation-8-ref.html
@@ -1,10 +1,10 @@
 <!DOCTYPE html>
 <html>
 <!-- check that hyphenation is not applied when language is not specified -->
 <body>
-<div style="width: 5em; -moz-hyphens: none;">
+<div style="width: 5em; hyphens: none;">
 supercalifragilisticexpialidocious
 </div>
 </body>
 </html>
 
--- a/layout/reftests/text/auto-hyphenation-8.html
+++ b/layout/reftests/text/auto-hyphenation-8.html
@@ -1,10 +1,10 @@
 <!DOCTYPE html>
 <html>
 <!-- check that hyphenation is not applied when language is not specified -->
 <body>
-<div style="width: 5em; -moz-hyphens: auto;">
+<div style="width: 5em; hyphens: auto;">
 supercalifragilisticexpialidocious
 </div>
 </body>
 </html>
 
--- a/layout/reftests/text/auto-hyphenation-9-ref.html
+++ b/layout/reftests/text/auto-hyphenation-9-ref.html
@@ -1,11 +1,11 @@
 <!DOCTYPE html>
 <html>
 <meta charset="iso-8859-1">
 <!-- check that hyphenation is not applied when language is not specified -->
 <body>
-<div style="width: 5em; -moz-hyphens: none;">
+<div style="width: 5em; hyphens: none;">
 supercalifragilisticexpialidocious
 </div>
 </body>
 </html>
 
--- a/layout/reftests/text/auto-hyphenation-9.html
+++ b/layout/reftests/text/auto-hyphenation-9.html
@@ -1,11 +1,11 @@
 <!DOCTYPE html>
 <html>
 <meta charset="iso-8859-1">
 <!-- check that hyphenation is not applied when language is not specified -->
 <body>
-<div style="width: 5em; -moz-hyphens: auto;">
+<div style="width: 5em; hyphens: auto;">
 supercalifragilisticexpialidocious
 </div>
 </body>
 </html>
 
--- a/layout/reftests/text/auto-hyphenation-af-1-ref.html
+++ b/layout/reftests/text/auto-hyphenation-af-1-ref.html
@@ -1,11 +1,11 @@
 <!DOCTYPE html>
 <html>
 <head>
 <meta http-equiv="content-type" content="text/html; charset=utf-8">
 </head>
 <body>
-<div style="width:1em; -moz-hyphens:manual;" lang="af">
+<div style="width:1em; hyphens:manual;" lang="af">
 Al&shy;le mens&shy;li&shy;ke we&shy;sens word vry, met ge&shy;ly&shy;ke waar&shy;dig&shy;heid en reg&shy;te, ge&shy;bo&shy;re.
 </div>
 </body>
 </html>
--- a/layout/reftests/text/auto-hyphenation-af-1.html
+++ b/layout/reftests/text/auto-hyphenation-af-1.html
@@ -1,11 +1,11 @@
 <!DOCTYPE html>
 <html>
 <head>
 <meta http-equiv="content-type" content="text/html; charset=utf-8">
 </head>
 <body>
-<div style="width:1em; -moz-hyphens:auto;" lang="af">
+<div style="width:1em; hyphens:auto;" lang="af">
 Alle menslike wesens word vry, met gelyke waardigheid en regte, gebore.
 </div>
 </body>
 </html>
--- a/layout/reftests/text/auto-hyphenation-bg-1-ref.html
+++ b/layout/reftests/text/auto-hyphenation-bg-1-ref.html
@@ -1,11 +1,11 @@
 <!DOCTYPE html>
 <html>
 <head>
 <meta http-equiv="content-type" content="text/html; charset=utf-8">
 </head>
 <body>
-<div style="width:1em; -moz-hyphens:manual;" lang="bg">
+<div style="width:1em; hyphens:manual;" lang="bg">
 Всич&shy;ки хо&shy;ра се раж&shy;дат сво&shy;бод&shy;ни и рав&shy;ни по дос&shy;тойн&shy;с&shy;т&shy;во и пра&shy;ва.
 </div>
 </body>
 </html>
--- a/layout/reftests/text/auto-hyphenation-bg-1.html
+++ b/layout/reftests/text/auto-hyphenation-bg-1.html
@@ -1,11 +1,11 @@
 <!DOCTYPE html>
 <html>
 <head>
 <meta http-equiv="content-type" content="text/html; charset=utf-8">
 </head>
 <body>
-<div style="width:1em; -moz-hyphens:auto;" lang="bg">
+<div style="width:1em; hyphens:auto;" lang="bg">
 Всички хора се раждат свободни и равни по достойнство и права.
 </div>
 </body>
 </html>
--- a/layout/reftests/text/auto-hyphenation-ca-1-ref.html
+++ b/layout/reftests/text/auto-hyphenation-ca-1-ref.html
@@ -1,11 +1,11 @@
 <!DOCTYPE html>
 <html>
 <head>
 <meta http-equiv="content-type" content="text/html; charset=utf-8">
 </head>
 <body>
-<div style="width:1em; -moz-hyphens:manual;" lang="ca">
+<div style="width:1em; hyphens:manual;" lang="ca">
 Tots els és&shy;sers hu&shy;mans nei&shy;xen lliu&shy;res i iguals en dig&shy;ni&shy;tat i en drets.
 </div>
 </body>
 </html>
--- a/layout/reftests/text/auto-hyphenation-ca-1.html
+++ b/layout/reftests/text/auto-hyphenation-ca-1.html
@@ -1,11 +1,11 @@
 <!DOCTYPE html>
 <html>
 <head>
 <meta http-equiv="content-type" content="text/html; charset=utf-8">
 </head>
 <body>
-<div style="width:1em; -moz-hyphens:auto;" lang="ca">
+<div style="width:1em; hyphens:auto;" lang="ca">
 Tots els éssers humans neixen lliures i iguals en dignitat i en drets.
 </div>
 </body>
 </html>
--- a/layout/reftests/text/auto-hyphenation-cy-1-ref.html
+++ b/layout/reftests/text/auto-hyphenation-cy-1-ref.html
@@ -1,11 +1,11 @@
 <!DOCTYPE html>
 <html>
 <head>
 <meta http-equiv="content-type" content="text/html; charset=utf-8">
 </head>
 <body>
-<div style="width:1em; -moz-hyphens:manual;" lang="cy">
+<div style="width:1em; hyphens:manual;" lang="cy">
 Gen&shy;ir pawb yn rhydd ac yn gyd&shy;radd â'i gil&shy;ydd mewn urdd&shy;as a hawl&shy;iau.
 </div>
 </body>
 </html>
--- a/layout/reftests/text/auto-hyphenation-cy-1.html
+++ b/layout/reftests/text/auto-hyphenation-cy-1.html
@@ -1,11 +1,11 @@
 <!DOCTYPE html>
 <html>
 <head>
 <meta http-equiv="content-type" content="text/html; charset=utf-8">
 </head>
 <body>
-<div style="width:1em; -moz-hyphens:auto;" lang="cy">
+<div style="width:1em; hyphens:auto;" lang="cy">
 Genir pawb yn rhydd ac yn gydradd â'i gilydd mewn urddas a hawliau.
 </div>
 </body>
 </html>
--- a/layout/reftests/text/auto-hyphenation-da-1-ref.html
+++ b/layout/reftests/text/auto-hyphenation-da-1-ref.html
@@ -1,11 +1,11 @@
 <!DOCTYPE html>
 <html>
 <head>
 <meta http-equiv="content-type" content="text/html; charset=utf-8">
 </head>
 <body>
-<div style="width:1em; -moz-hyphens:manual;" lang="da">
+<div style="width:1em; hyphens:manual;" lang="da">
 Al&shy;le men&shy;ne&shy;sker er født frie og li&shy;ge i vær&shy;dig&shy;hed og ret&shy;tig&shy;he&shy;der.
 </div>
 </body>
 </html>
--- a/layout/reftests/text/auto-hyphenation-da-1.html
+++ b/layout/reftests/text/auto-hyphenation-da-1.html
@@ -1,11 +1,11 @@
 <!DOCTYPE html>
 <html>
 <head>
 <meta http-equiv="content-type" content="text/html; charset=utf-8">
 </head>
 <body>
-<div style="width:1em; -moz-hyphens:auto;" lang="da">
+<div style="width:1em; hyphens:auto;" lang="da">
 Alle mennesker er født frie og lige i værdighed og rettigheder.
 </div>
 </body>
 </html>
--- a/layout/reftests/text/auto-hyphenation-de-1901-1-ref.html
+++ b/layout/reftests/text/auto-hyphenation-de-1901-1-ref.html
@@ -1,13 +1,13 @@
 <!DOCTYPE html>
 <html>
 <head>
 <meta http-equiv="content-type" content="text/html; charset=utf-8">
 </head>
 <body>
-<div style="width:1em; -moz-hyphens:manual;" lang="de-1901">
+<div style="width:1em; hyphens:manual;" lang="de-1901">
 Al&shy;le Men&shy;schen sind frei und gleich an Wür&shy;de und Rech&shy;ten ge&shy;bo&shy;ren.
 <p>
 bu&shy;sser <!-- example word that is hyphenated differently by de-1901 and de-1996 -->
 </div>
 </body>
 </html>
--- a/layout/reftests/text/auto-hyphenation-de-1901-1.html
+++ b/layout/reftests/text/auto-hyphenation-de-1901-1.html
@@ -1,13 +1,13 @@
 <!DOCTYPE html>
 <html>
 <head>
 <meta http-equiv="content-type" content="text/html; charset=utf-8">
 </head>
 <body>
-<div style="width:1em; -moz-hyphens:auto;" lang="de-1901">
+<div style="width:1em; hyphens:auto;" lang="de-1901">
 Alle Menschen sind frei und gleich an Würde und Rechten geboren.
 <p>
 busser <!-- example word that is hyphenated differently by de-1901 and de-1996 -->
 </div>
 </body>
 </html>
--- a/layout/reftests/text/auto-hyphenation-de-1996-1-ref.html
+++ b/layout/reftests/text/auto-hyphenation-de-1996-1-ref.html
@@ -1,13 +1,13 @@
 <!DOCTYPE html>
 <html>
 <head>
 <meta http-equiv="content-type" content="text/html; charset=utf-8">
 </head>
 <body>
-<div style="width:1em; -moz-hyphens:manual;" lang="de-1996">
+<div style="width:1em; hyphens:manual;" lang="de-1996">
 Al&shy;le Men&shy;schen sind frei und gleich an Wür&shy;de und Rech&shy;ten ge&shy;bo&shy;ren.
 <p>
 bus&shy;ser <!-- example word that is hyphenated differently by de-1901 and de-1996 -->
 </div>
 </body>
 </html>
--- a/layout/reftests/text/auto-hyphenation-de-1996-1.html
+++ b/layout/reftests/text/auto-hyphenation-de-1996-1.html
@@ -1,13 +1,13 @@
 <!DOCTYPE html>
 <html>
 <head>
 <meta http-equiv="content-type" content="text/html; charset=utf-8">
 </head>
 <body>
-<div style="width:1em; -moz-hyphens:auto;" lang="de-1996">
+<div style="width:1em; hyphens:auto;" lang="de-1996">
 Alle Menschen sind frei und gleich an Würde und Rechten geboren.
 <p>
 busser <!-- example word that is hyphenated differently by de-1901 and de-1996 -->
 </div>
 </body>
 </html>
--- a/layout/reftests/text/auto-hyphenation-de-ch-1-ref.html
+++ b/layout/reftests/text/auto-hyphenation-de-ch-1-ref.html
@@ -1,11 +1,11 @@
 <!DOCTYPE html>
 <html>
 <head>
 <meta http-equiv="content-type" content="text/html; charset=utf-8">
 </head>
 <body>
-<div style="width:1em; -moz-hyphens:manual;" lang="de-CH">
+<div style="width:1em; hyphens:manual;" lang="de-CH">
 Al&shy;le Men&shy;schen sind frei und gleich an Wür&shy;de und Rech&shy;ten ge&shy;bo&shy;ren.
 </div>
 </body>
 </html>
--- a/layout/reftests/text/auto-hyphenation-de-ch-1.html
+++ b/layout/reftests/text/auto-hyphenation-de-ch-1.html
@@ -1,11 +1,11 @@
 <!DOCTYPE html>
 <html>
 <head>
 <meta http-equiv="content-type" content="text/html; charset=utf-8">
 </head>
 <body>
-<div style="width:1em; -moz-hyphens:auto;" lang="de-CH">
+<div style="width:1em; hyphens:auto;" lang="de-CH">
 Alle Menschen sind frei und gleich an Würde und Rechten geboren.
 </div>
 </body>
 </html>
--- a/layout/reftests/text/auto-hyphenation-eo-1-ref.html
+++ b/layout/reftests/text/auto-hyphenation-eo-1-ref.html
@@ -1,11 +1,11 @@
 <!DOCTYPE html>
 <html>
 <head>
 <meta http-equiv="content-type" content="text/html; charset=utf-8">
 </head>
 <body>
-<div style="width:1em; -moz-hyphens:manual;" lang="eo">
+<div style="width:1em; hyphens:manual;" lang="eo">
 Ĉiuj ho&shy;moj es&shy;tas de&shy;na&shy;s&shy;ke li&shy;be&shy;raj kaj ega&shy;laj laŭ di&shy;g&shy;no kaj raj&shy;toj.
 </div>
 </body>
 </html>
--- a/layout/reftests/text/auto-hyphenation-eo-1.html
+++ b/layout/reftests/text/auto-hyphenation-eo-1.html
@@ -1,11 +1,11 @@
 <!DOCTYPE html>
 <html>
 <head>
 <meta http-equiv="content-type" content="text/html; charset=utf-8">
 </head>
 <body>
-<div style="width:1em; -moz-hyphens:auto;" lang="eo">
+<div style="width:1em; hyphens:auto;" lang="eo">
 Ĉiuj homoj estas denaske liberaj kaj egalaj laŭ digno kaj rajtoj.
 </div>
 </body>
 </html>
--- a/layout/reftests/text/auto-hyphenation-es-1-ref.html
+++ b/layout/reftests/text/auto-hyphenation-es-1-ref.html
@@ -1,11 +1,11 @@
 <!DOCTYPE html>
 <html>
 <head>
 <meta http-equiv="content-type" content="text/html; charset=utf-8">
 </head>
 <body>
-<div style="width:1em; -moz-hyphens:manual;" lang="es">
+<div style="width:1em; hyphens:manual;" lang="es">
 To&shy;dos los se&shy;res hu&shy;ma&shy;nos na&shy;cen li&shy;bres e igua&shy;les en dig&shy;ni&shy;dad y de&shy;re&shy;chos
 </div>
 </body>
 </html>
--- a/layout/reftests/text/auto-hyphenation-es-1.html
+++ b/layout/reftests/text/auto-hyphenation-es-1.html
@@ -1,11 +1,11 @@
 <!DOCTYPE html>
 <html>
 <head>
 <meta http-equiv="content-type" content="text/html; charset=utf-8">
 </head>
 <body>
-<div style="width:1em; -moz-hyphens:auto;" lang="es">
+<div style="width:1em; hyphens:auto;" lang="es">
 Todos los seres humanos nacen libres e iguales en dignidad y derechos
 </div>
 </body>
 </html>
--- a/layout/reftests/text/auto-hyphenation-et-1-ref.html
+++ b/layout/reftests/text/auto-hyphenation-et-1-ref.html
@@ -1,11 +1,11 @@
 <!DOCTYPE html>
 <html>
 <head>
 <meta http-equiv="content-type" content="text/html; charset=utf-8">
 </head>
 <body>
-<div style="width:1em; -moz-hyphens:manual;" lang="et">
+<div style="width:1em; hyphens:manual;" lang="et">
 Kõik ini&shy;me&shy;sed sün&shy;nivad va&shy;ba&shy;de&shy;na ja võrds&shy;ete&shy;na oma vää&shy;ri&shy;ku&shy;selt ja õi&shy;gus&shy;telt
 </div>
 </body>
 </html>
--- a/layout/reftests/text/auto-hyphenation-et-1.html
+++ b/layout/reftests/text/auto-hyphenation-et-1.html
@@ -1,11 +1,11 @@
 <!DOCTYPE html>
 <html>
 <head>
 <meta http-equiv="content-type" content="text/html; charset=utf-8">
 </head>
 <body>
-<div style="width:1em; -moz-hyphens:auto;" lang="et">
+<div style="width:1em; hyphens:auto;" lang="et">
 Kõik inimesed sünnivad vabadena ja võrdsetena oma väärikuselt ja õigustelt
 </div>
 </body>
 </html>
--- a/layout/reftests/text/auto-hyphenation-fi-1-ref.html
+++ b/layout/reftests/text/auto-hyphenation-fi-1-ref.html
@@ -1,11 +1,11 @@
 <!DOCTYPE html>
 <html>
 <head>
 <meta http-equiv="content-type" content="text/html; charset=utf-8">
 </head>
 <body>
-<div style="width:1em; -moz-hyphens:manual;" lang="fi">
+<div style="width:1em; hyphens:manual;" lang="fi">
 Kaik&shy;ki ih&shy;mi&shy;set syn&shy;ty&shy;vät va&shy;pai&shy;na ja ta&shy;sa&shy;ver&shy;tai&shy;si&shy;na ar&shy;vol&shy;taan ja oi&shy;keuk&shy;sil&shy;taan.
 </div>
 </body>
 </html>
--- a/layout/reftests/text/auto-hyphenation-fi-1.html
+++ b/layout/reftests/text/auto-hyphenation-fi-1.html
@@ -1,11 +1,11 @@
 <!DOCTYPE html>
 <html>
 <head>
 <meta http-equiv="content-type" content="text/html; charset=utf-8">
 </head>
 <body>
-<div style="width:1em; -moz-hyphens:auto;" lang="fi">
+<div style="width:1em; hyphens:auto;" lang="fi">
 Kaikki ihmiset syntyvät vapaina ja tasavertaisina arvoltaan ja oikeuksiltaan.
 </div>
 </body>
 </html>
--- a/layout/reftests/text/auto-hyphenation-fr-1-ref.html
+++ b/layout/reftests/text/auto-hyphenation-fr-1-ref.html
@@ -1,11 +1,11 @@
 <!DOCTYPE html>
 <html>
 <head>
 <meta http-equiv="content-type" content="text/html; charset=utf-8">
 </head>
 <body>
-<div style="width:1em; -moz-hyphens:manual;" lang="fr">
+<div style="width:1em; hyphens:manual;" lang="fr">
 Tout in&shy;di&shy;vi&shy;du a droit à la vie, à la li&shy;ber&shy;té et à la sû&shy;re&shy;té de sa per&shy;sonne.
 </div>
 </body>
 </html>
--- a/layout/reftests/text/auto-hyphenation-fr-1.html
+++ b/layout/reftests/text/auto-hyphenation-fr-1.html
@@ -1,11 +1,11 @@
 <!DOCTYPE html>
 <html>
 <head>
 <meta http-equiv="content-type" content="text/html; charset=utf-8">
 </head>
 <body>
-<div style="width:1em; -moz-hyphens:auto;" lang="fr">
+<div style="width:1em; hyphens:auto;" lang="fr">
 Tout individu a droit à la vie, à la liberté et à la sûreté de sa personne.
 </div>
 </body>
 </html>
--- a/layout/reftests/text/auto-hyphenation-gl-1-ref.html
+++ b/layout/reftests/text/auto-hyphenation-gl-1-ref.html
@@ -1,11 +1,11 @@
 <!DOCTYPE html>
 <html>
 <head>
 <meta http-equiv="content-type" content="text/html; charset=utf-8">
 </head>
 <body>
-<div style="width:1em; -moz-hyphens:manual;" lang="gl">
+<div style="width:1em; hyphens:manual;" lang="gl">
 Tó&shy;do&shy;los se&shy;res hu&shy;ma&shy;nos na&shy;cen li&shy;bres e iguais en dig&shy;ni&shy;da&shy;de e de&shy;rei&shy;tos
 </div>
 </body>
 </html>
--- a/layout/reftests/text/auto-hyphenation-gl-1.html
+++ b/layout/reftests/text/auto-hyphenation-gl-1.html
@@ -1,11 +1,11 @@
 <!DOCTYPE html>
 <html>
 <head>
 <meta http-equiv="content-type" content="text/html; charset=utf-8">
 </head>
 <body>
-<div style="width:1em; -moz-hyphens:auto;" lang="gl">
+<div style="width:1em; hyphens:auto;" lang="gl">
 Tódolos seres humanos nacen libres e iguais en dignidade e dereitos
 </div>
 </body>
 </html>
--- a/layout/reftests/text/auto-hyphenation-hr-1-ref.html
+++ b/layout/reftests/text/auto-hyphenation-hr-1-ref.html
@@ -1,11 +1,11 @@
 <!DOCTYPE html>
 <html>
 <head>
 <meta http-equiv="content-type" content="text/html; charset=utf-8">
 </head>
 <body>
-<div style="width:1em; -moz-hyphens:manual;" lang="hr">
+<div style="width:1em; hyphens:manual;" lang="hr">
 Sva ljud&shy;ska bi&shy;ća ra&shy;ća&shy;ju se slo&shy;bod&shy;na i jed&shy;na&shy;ka u dos&shy;to&shy;jans&shy;tvu i pra&shy;vi&shy;ma
 </div>
 </body>
 </html>
--- a/layout/reftests/text/auto-hyphenation-hr-1.html
+++ b/layout/reftests/text/auto-hyphenation-hr-1.html
@@ -1,11 +1,11 @@
 <!DOCTYPE html>
 <html>
 <head>
 <meta http-equiv="content-type" content="text/html; charset=utf-8">
 </head>
 <body>
-<div style="width:1em; -moz-hyphens:auto;" lang="hr">
+<div style="width:1em; hyphens:auto;" lang="hr">
 Sva ljudska bića raćaju se slobodna i jednaka u dostojanstvu i pravima
 </div>
 </body>
 </html>
--- a/layout/reftests/text/auto-hyphenation-hsb-1-ref.html
+++ b/layout/reftests/text/auto-hyphenation-hsb-1-ref.html
@@ -1,11 +1,11 @@
 <!DOCTYPE html>
 <html>
 <head>
 <meta http-equiv="content-type" content="text/html; charset=utf-8">
 </head>
 <body>
-<div style="width:1em; -moz-hyphens:manual;" lang="hsb">
+<div style="width:1em; hyphens:manual;" lang="hsb">
 Wšitcy čło&shy;wje&shy;ko&shy;jo su wot na&shy;ro&shy;da swo&shy;bod&shy;ni a su je&shy;na&shy;cy po do&shy;stoj&shy;nos&shy;ći a pra&shy;wach
 </div>
 </body>
 </html>
--- a/layout/reftests/text/auto-hyphenation-hsb-1.html
+++ b/layout/reftests/text/auto-hyphenation-hsb-1.html
@@ -1,11 +1,11 @@
 <!DOCTYPE html>
 <html>
 <head>
 <meta http-equiv="content-type" content="text/html; charset=utf-8">
 </head>
 <body>
-<div style="width:1em; -moz-hyphens:auto;" lang="hsb">
+<div style="width:1em; hyphens:auto;" lang="hsb">
 Wšitcy čłowjekojo su wot naroda swobodni a su jenacy po dostojnosći a prawach
 </div>
 </body>
 </html>
--- a/layout/reftests/text/auto-hyphenation-hu-1-ref.html
+++ b/layout/reftests/text/auto-hyphenation-hu-1-ref.html
@@ -1,11 +1,11 @@
 <!DOCTYPE html>
 <html>
 <head>
 <meta http-equiv="content-type" content="text/html; charset=utf-8">
 </head>
 <body>
-<div style="width:1em; -moz-hyphens:manual;" lang="hu">
+<div style="width:1em; hyphens:manual;" lang="hu">
 Min&shy;den em&shy;be&shy;ri lény sza&shy;ba&shy;don szü&shy;le&shy;tik és egyen&shy;lő mél&shy;tó&shy;sá&shy;ga és jo&shy;ga van.
 </div>
 </body>
 </html>
--- a/layout/reftests/text/auto-hyphenation-hu-1.html
+++ b/layout/reftests/text/auto-hyphenation-hu-1.html
@@ -1,11 +1,11 @@
 <!DOCTYPE html>
 <html>
 <head>
 <meta http-equiv="content-type" content="text/html; charset=utf-8">
 </head>
 <body>
-<div style="width:1em; -moz-hyphens:auto;" lang="hu">
+<div style="width:1em; hyphens:auto;" lang="hu">
 Minden emberi lény szabadon születik és egyenlő méltósága és joga van.
 </div>
 </body>
 </html>
--- a/layout/reftests/text/auto-hyphenation-ia-1-ref.html
+++ b/layout/reftests/text/auto-hyphenation-ia-1-ref.html
@@ -1,11 +1,11 @@
 <!DOCTYPE html>
 <html>
 <head>
 <meta http-equiv="content-type" content="text/html; charset=utf-8">
 </head>
 <body>
-<div style="width:1em; -moz-hyphens:manual;" lang="ia">
+<div style="width:1em; hyphens:manual;" lang="ia">
 To&shy;te le es&shy;se&shy;res hu&shy;man na&shy;sce li&shy;be&shy;re e equal in dig&shy;ni&shy;ta&shy;te e in de&shy;rec&shy;tos
 </div>
 </body>
 </html>
--- a/layout/reftests/text/auto-hyphenation-ia-1.html
+++ b/layout/reftests/text/auto-hyphenation-ia-1.html
@@ -1,11 +1,11 @@
 <!DOCTYPE html>
 <html>
 <head>
 <meta http-equiv="content-type" content="text/html; charset=utf-8">
 </head>
 <body>
-<div style="width:1em; -moz-hyphens:auto;" lang="ia">
+<div style="width:1em; hyphens:auto;" lang="ia">
 Tote le esseres human nasce libere e equal in dignitate e in derectos
 </div>
 </body>
 </html>
--- a/layout/reftests/text/auto-hyphenation-is-1-ref.html
+++ b/layout/reftests/text/auto-hyphenation-is-1-ref.html
@@ -1,11 +1,11 @@
 <!DOCTYPE html>
 <html>
 <head>
 <meta http-equiv="content-type" content="text/html; charset=utf-8">
 </head>
 <body>
-<div style="width:1em; -moz-hyphens:manual;" lang="is">
+<div style="width:1em; hyphens:manual;" lang="is">
 Hver mað&shy;ur er bor&shy;inn frjáls og jafn öðr&shy;um að virð&shy;ingu og rétt&shy;ind&shy;um
 </div>
 </body>
 </html>
--- a/layout/reftests/text/auto-hyphenation-is-1.html
+++ b/layout/reftests/text/auto-hyphenation-is-1.html
@@ -1,11 +1,11 @@
 <!DOCTYPE html>
 <html>
 <head>
 <meta http-equiv="content-type" content="text/html; charset=utf-8">
 </head>
 <body>
-<div style="width:1em; -moz-hyphens:auto;" l