Merge mozilla-central to b2g-inbound
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Tue, 15 Sep 2015 15:13:57 +0200
changeset 295192 63bd80f07148ab85220c0e0b44c2bb7da8a339fc
parent 295191 887b18931a4c0bc5f3cdaad7d690441d748d21f3 (current diff)
parent 295156 5d61714cf5c3ec2440e9491ba30893ac37ca06c2 (diff)
child 295193 59b2220d8229a542aeed1b9fa6fd1051409f9928
push id5245
push userraliiev@mozilla.com
push dateThu, 29 Oct 2015 11:30:51 +0000
treeherdermozilla-beta@dac831dc1bd0 [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 b2g-inbound
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
mobile/android/base/resources/drawable-hdpi/menu_light.png
mobile/android/base/resources/drawable-xhdpi/menu_light.png
mobile/android/modules/MatchstickApp.jsm
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/browser/base/content/test/newtab/browser_newtab_block.js
+++ b/browser/base/content/test/newtab/browser_newtab_block.js
@@ -8,16 +8,17 @@
  */
 
 gDirectorySource = "data:application/json," + JSON.stringify({
   "suggested": [{
     url: "http://suggested.com/",
     imageURI: "data:image/png;base64,helloWORLD3",
     title: "title",
     type: "affiliate",
+    adgroup_name: "test",
     frecent_sites: ["example0.com"]
   }]
 });
 
 function runTests() {
   let origGetFrecentSitesName = DirectoryLinksProvider.getFrecentSitesName;
   DirectoryLinksProvider.getFrecentSitesName = () => "";
   let origIsTopPlacesSite = NewTabUtils.isTopPlacesSite;
--- a/browser/base/content/test/newtab/browser_newtab_bug1145428.js
+++ b/browser/base/content/test/newtab/browser_newtab_bug1145428.js
@@ -10,16 +10,17 @@
 
 gDirectorySource = "data:application/json," + JSON.stringify({
   "suggested": [{
     url: "http://example.com/landing/page.html",
     imageURI: "data:image/png;base64,helloWORLD3",
     enhancedImageURI: "data:image/png;base64,helloWORLD2",
     title: "title",
     type: "affiliate",
+    adgroup_name: "example",
     frecent_sites: ["example0.com"],
   }]
 });
 
 function runTests() {
   let origGetFrecentSitesName = DirectoryLinksProvider.getFrecentSitesName;
   DirectoryLinksProvider.getFrecentSitesName = () => "";
 
--- a/browser/base/content/test/newtab/browser_newtab_bug1178586.js
+++ b/browser/base/content/test/newtab/browser_newtab_bug1178586.js
@@ -8,16 +8,17 @@
 
 gDirectorySource = "data:application/json," + JSON.stringify({
   "suggested": [{
     url: "http://example.com/hardlanding/page.html",
     imageURI: "data:image/png;base64,helloWORLD3",
     enhancedImageURI: "data:image/png;base64,helloWORLD2",
     title: "title",
     type: "affiliate",
+    adgroup_name: "example",
     frecent_sites: ["example0.com"],
   }]
 });
 
 function runTests() {
   let origGetFrecentSitesName = DirectoryLinksProvider.getFrecentSitesName;
   DirectoryLinksProvider.getFrecentSitesName = () => "";
 
--- a/browser/base/content/test/newtab/browser_newtab_enhanced.js
+++ b/browser/base/content/test/newtab/browser_newtab_enhanced.js
@@ -3,16 +3,17 @@
 
 const PRELOAD_PREF = "browser.newtab.preload";
 
 let suggestedLink = {
   url: "http://example1.com/2",
   imageURI: "data:image/png;base64,helloWORLD3",
   title: "title2",
   type: "affiliate",
+  adgroup_name: "Technology",
   frecent_sites: ["classroom.google.com", "codeacademy.org", "codecademy.com", "codeschool.com", "codeyear.com", "elearning.ut.ac.id", "how-to-build-websites.com", "htmlcodetutorial.com", "htmldog.com", "htmlplayground.com", "learn.jquery.com", "quackit.com", "roseindia.net", "teamtreehouse.com", "tizag.com", "tutorialspoint.com", "udacity.com", "w3schools.com", "webdevelopersnotes.com"]
 };
 
 gDirectorySource = "data:application/json," + JSON.stringify({
   "enhanced": [{
     url: "http://example.com/",
     enhancedImageURI: "data:image/png;base64,helloWORLD",
     title: "title",
@@ -134,31 +135,30 @@ function runTests() {
   yield addNewTabPageTab();
   yield customizeNewTabPage("enhanced");
 
   // Suggested link was not enhanced by directory link with same domain
   ({type, enhanced, title, suggested} = getData(0));
   is(type, "affiliate", "suggested link is affiliate");
   is(enhanced, "", "suggested link has no enhanced image");
   is(title, "title2");
-  ok(suggested.indexOf("Suggested for <strong> webdev education </strong> visitors") > -1, "Suggested for 'webdev education'");
+  ok(suggested.indexOf("Suggested for <strong> Technology </strong> visitors") > -1, "Suggested for 'Technology'");
 
   // Enhanced history link shows up second
   ({type, enhanced, title, suggested} = getData(1));
   is(type, "enhanced", "pinned history link is enhanced");
   isnot(enhanced, "", "pinned history link has enhanced image");
   is(title, "title");
   is(suggested, "", "There is no suggested explanation");
 
   is(getData(9), null, "there is a suggested link followed by an enhanced history link and the remaining history links");
 
 
 
-  // Test override category/adgroup name.
-  suggestedLink.adgroup_name = "Technology";
+  // Test no override category/adgroup name.
   Services.prefs.setCharPref(PREF_NEWTAB_DIRECTORYSOURCE,
     "data:application/json," + JSON.stringify({"suggested": [suggestedLink]}));
   yield watchLinksChangeOnce().then(TestRunner.next);
 
   yield addNewTabPageTab();
   ({type, enhanced, title, suggested} = getData(0));
   Cu.reportError("SUGGEST " + suggested);
   ok(suggested.indexOf("Suggested for <strong> Technology </strong> visitors") > -1, "Suggested for 'Technology'");
@@ -171,18 +171,18 @@ function runTests() {
   yield watchLinksChangeOnce().then(TestRunner.next);
 
   yield addNewTabPageTab();
   ({type, enhanced, title, suggested} = getData(0));
   Cu.reportError("SUGGEST " + suggested);
   ok(suggested.indexOf("Suggested for <strong> Technology </strong> enthusiasts who visit sites like <strong> classroom.google.com </strong>") > -1, "Suggested for 'Technology' enthusiasts");
 
 
-  // Test server provided explanation string without category override.
-  delete suggestedLink.adgroup_name;
+  // Test server provided explanation string with category override.
+  suggestedLink.adgroup_name = "webdev education";
   Services.prefs.setCharPref(PREF_NEWTAB_DIRECTORYSOURCE,
     "data:application/json," + encodeURIComponent(JSON.stringify({"suggested": [suggestedLink]})));
   yield watchLinksChangeOnce().then(TestRunner.next);
 
   yield addNewTabPageTab();
   ({type, enhanced, title, suggested} = getData(0));
   Cu.reportError("SUGGEST " + suggested);
   ok(suggested.indexOf("Suggested for <strong> webdev education </strong> enthusiasts who visit sites like <strong> classroom.google.com </strong>") > -1, "Suggested for 'webdev education' enthusiasts");
--- a/browser/components/extensions/ext-windows.js
+++ b/browser/components/extensions/ext-windows.js
@@ -55,17 +55,17 @@ extensions.registerAPI((extension, conte
           callback = args[0];
         } else {
           [getInfo, callback] = args;
         }
         let window = WindowManager.topWindow;
         runSafe(context, callback, WindowManager.convert(extension, window, getInfo));
       },
 
-      getAll: function(getAll, callback) {
+      getAll: function(getInfo, callback) {
         let e = Services.wm.getEnumerator("navigator:browser");
         let windows = [];
         while (e.hasMoreElements()) {
           let window = e.getNext();
           windows.push(WindowManager.convert(extension, window, getInfo));
         }
         runSafe(context, callback, windows);
       },
@@ -126,17 +126,20 @@ extensions.registerAPI((extension, conte
       },
 
       update: function(windowId, updateInfo, callback) {
         let window = WindowManager.getWindow(windowId);
         if (updateInfo.focused) {
           Services.focus.activeWindow = window;
         }
         // TODO: All the other properties...
-        runSafe(context, callback, WindowManager.convert(extension, window));
+
+        if (callback) {
+          runSafe(context, callback, WindowManager.convert(extension, window));
+        }
       },
 
       remove: function(windowId, callback) {
         let window = WindowManager.getWindow(windowId);
         window.close();
 
         let listener = () => {
           AllWindowEvents.removeListener("domwindowclosed", listener);
--- a/browser/components/extensions/test/browser/browser.ini
+++ b/browser/components/extensions/test/browser/browser.ini
@@ -1,8 +1,9 @@
 [DEFAULT]
 skip-if = os == 'android' || buildapp == 'b2g' || os == 'mac'
 
 [browser_extensions_simple.js]
 [browser_ext_browserAction_simple.js]
 [browser_ext_tabs_executeScript.js]
 [browser_ext_tabs_query.js]
 [browser_ext_tabs_update.js]
+[browser_ext_windows_update.js]
new file mode 100644
--- /dev/null
+++ b/browser/components/extensions/test/browser/browser_ext_windows_update.js
@@ -0,0 +1,51 @@
+add_task(function* () {
+  function promiseWaitForFocus(aWindow) {
+    return new Promise(function(aResolve, aReject) {
+      waitForFocus(function() {
+        ok(Services.focus.activeWindow === aWindow, "correct window focused");
+        aResolve();
+      }, aWindow);
+    });
+  }
+
+  let window1 = window;
+  let window2 = yield BrowserTestUtils.openNewBrowserWindow();
+
+  Services.focus.activeWindow = window2;
+  yield promiseWaitForFocus(window2);
+
+  let extension = ExtensionTestUtils.loadExtension({
+    manifest: {
+      "permissions": ["windows"]
+    },
+
+    background: function() {
+      browser.windows.getAll(undefined, function(wins) {
+        browser.test.assertEq(wins.length, 2, "should have two windows");
+
+        // Sort the unfocused window to the lower index.
+        wins.sort(function(win1, win2) {
+          if (win1.focused === win2.focused) {
+            return 0;
+          }
+
+          return win1.focused ? 1 : -1;
+        });
+
+        browser.windows.update(wins[0].id, {focused: true}, function() {
+          browser.test.sendMessage("check");
+        });
+
+      });
+    },
+  });
+
+  yield extension.startup();
+  yield extension.awaitMessage("check");
+
+  yield promiseWaitForFocus(window1);
+
+  yield extension.unload();
+
+  yield BrowserTestUtils.closeWindow(window2);
+});
\ No newline at end of file
--- a/browser/devtools/canvasdebugger/snapshotslist.js
+++ b/browser/devtools/canvasdebugger/snapshotslist.js
@@ -415,24 +415,25 @@ let SnapshotsListView = Heritage.extend(
         screenshot: null
       };
       let functionCalls = snapshotItem.attachment.calls;
       let thumbnails = snapshotItem.attachment.thumbnails;
       let screenshot = snapshotItem.attachment.screenshot;
 
       // Prepare all the function calls for serialization.
       yield DevToolsUtils.yieldingEach(functionCalls, (call, i) => {
-        let { type, name, file, line, argsPreview, callerPreview } = call;
+        let { type, name, file, line, timestamp, argsPreview, callerPreview } = call;
         return call.getDetails().then(({ stack }) => {
           data.calls[i] = {
             type: type,
             name: name,
             file: file,
             line: line,
             stack: stack,
+            timestamp: timestamp,
             argsPreview: argsPreview,
             callerPreview: callerPreview
           };
         });
       });
 
       // Prepare all the thumbnails for serialization.
       yield DevToolsUtils.yieldingEach(thumbnails, (thumbnail, i) => {
--- a/browser/devtools/canvasdebugger/test/browser.ini
+++ b/browser/devtools/canvasdebugger/test/browser.ini
@@ -47,8 +47,10 @@ skip-if = e10s # bug 1102301 - leaks whi
 [browser_canvas-frontend-slider-01.js]
 [browser_canvas-frontend-slider-02.js]
 [browser_canvas-frontend-snapshot-select-01.js]
 [browser_canvas-frontend-snapshot-select-02.js]
 [browser_canvas-frontend-stepping.js]
 [browser_canvas-frontend-stop-01.js]
 [browser_canvas-frontend-stop-02.js]
 [browser_canvas-frontend-stop-03.js]
+[browser_profiling-canvas.js]
+[browser_profiling-webgl.js]
new file mode 100644
--- /dev/null
+++ b/browser/devtools/canvasdebugger/test/browser_profiling-canvas.js
@@ -0,0 +1,45 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Tests if functions inside a single animation frame are recorded and stored
+ * for a canvas context profiling.
+ */
+
+function* ifTestingSupported() {
+  let currentTime = window.performance.now();
+  let { target, front } = yield initCanvasDebuggerBackend(SIMPLE_CANVAS_URL);
+
+  let navigated = once(target, "navigate");
+
+  yield front.setup({ reload: true });
+  ok(true, "The front was setup up successfully.");
+
+  yield navigated;
+  ok(true, "Target automatically navigated when the front was set up.");
+
+  let snapshotActor = yield front.recordAnimationFrame();
+  ok(snapshotActor,
+    "A snapshot actor was sent after recording.");
+
+  let animationOverview = yield snapshotActor.getOverview();
+  ok(animationOverview,
+    "An animation overview could be retrieved after recording.");
+
+  let functionCalls = animationOverview.calls;
+  ok(functionCalls,
+    "An array of function call actors was sent after recording.");
+  is(functionCalls.length, 8,
+    "The number of function call actors is correct.");
+
+  info("Check the timestamps of function calls");
+
+  for ( let i = 0; i < functionCalls.length-1; i += 2 ) {
+    ok( functionCalls[i].timestamp > 0, "The timestamp of the called function is larger than 0." );
+    ok( functionCalls[i].timestamp < currentTime, "The timestamp has been minus the frame start time." );
+    ok( functionCalls[i+1].timestamp > functionCalls[i].timestamp, "The timestamp of the called function is correct." );
+  }
+
+  yield removeTab(target.tab);
+  finish();
+}
new file mode 100644
--- /dev/null
+++ b/browser/devtools/canvasdebugger/test/browser_profiling-webgl.js
@@ -0,0 +1,45 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Tests if functions inside a single animation frame are recorded and stored
+ * for a canvas context profiling.
+ */
+
+function* ifTestingSupported() {
+  let currentTime = window.performance.now();
+  let { target, front } = yield initCanvasDebuggerBackend(WEBGL_ENUM_URL);
+
+  let navigated = once(target, "navigate");
+
+  yield front.setup({ reload: true });
+  ok(true, "The front was setup up successfully.");
+
+  yield navigated;
+  ok(true, "Target automatically navigated when the front was set up.");
+
+  let snapshotActor = yield front.recordAnimationFrame();
+  ok(snapshotActor,
+    "A snapshot actor was sent after recording.");
+
+  let animationOverview = yield snapshotActor.getOverview();
+  ok(animationOverview,
+    "An animation overview could be retrieved after recording.");
+
+  let functionCalls = animationOverview.calls;
+  ok(functionCalls,
+    "An array of function call actors was sent after recording.");
+  is(functionCalls.length, 3,
+    "The number of function call actors is correct.");
+
+  info("Check the timestamps of function calls");
+
+  for ( let i = 0; i < functionCalls.length-1; i += 2 ) {
+    ok( functionCalls[i].timestamp > 0, "The timestamp of the called function is larger than 0." );
+    ok( functionCalls[i].timestamp < currentTime, "The timestamp has been minus the frame start time." );
+    ok( functionCalls[i+1].timestamp > functionCalls[i].timestamp, "The timestamp of the called function is correct." );
+  }
+
+  yield removeTab(target.tab);
+  finish();
+}
--- a/browser/devtools/markupview/test/browser.ini
+++ b/browser/devtools/markupview/test/browser.ini
@@ -18,16 +18,17 @@ support-files =
   doc_markup_not_displayed.html
   doc_markup_pagesize_01.html
   doc_markup_pagesize_02.html
   doc_markup_search.html
   doc_markup_svg_attributes.html
   doc_markup_toggle.html
   doc_markup_tooltip.png
   doc_markup_xul.xul
+  frame-script-utils.js
   head.js
   helper_attributes_test_runner.js
   helper_events_test_runner.js
   helper_outerhtml_test_runner.js
   lib_jquery_1.0.js
   lib_jquery_1.1.js
   lib_jquery_1.2_min.js
   lib_jquery_1.3_min.js
--- a/browser/devtools/markupview/test/browser_markupview_keybindings_04.js
+++ b/browser/devtools/markupview/test/browser_markupview_keybindings_04.js
@@ -40,20 +40,38 @@ add_task(function*() {
 });
 
 function assertNodeSelected(inspector, tagName) {
   is(inspector.selection.nodeFront.tagName.toLowerCase(), tagName,
     `The <${tagName}> node is selected`);
 }
 
 function* selectWithBrowserMenu(inspector) {
-  yield BrowserTestUtils.synthesizeMouseAtCenter("div", {
-    type: "contextmenu",
-    button: 2
-  }, gBrowser.selectedBrowser);
+  // This test can't use BrowserTestUtils.synthesizeMouseAtCenter()
+  // method (see below) since it causes intermittent test failures.
+  // So, we are introducing a new "Test:MarkupView:SynthesizeMouse" event
+  // that is handled in the content scope. The main difference between
+  // this new event and BrowserTestUtils library is EventUtils library.
+  // While BrowserTestUtils is using:
+  // chrome://mochikit/content/tests/SimpleTest/EventUtils.js
+  // (see: AsyncUtilsContent.js)
+  // ... this test requires:
+  // chrome://marionette/content/EventUtils.js
+  // (see markupview/test/frame-script-utils.js)
+  // See also: https://bugzilla.mozilla.org/show_bug.cgi?id=1199180
+  yield executeInContent("Test:MarkupView:SynthesizeMouse", {
+    center: true,
+    selector: "div",
+    options: {type: "contextmenu", button: 2}
+  });
+
+  //yield BrowserTestUtils.synthesizeMouseAtCenter("div", {
+  //  type: "contextmenu",
+  //  button: 2
+  //}, gBrowser.selectedBrowser);
 
   // nsContextMenu also requires the popupNode to be set, but we can't set it to
   // node under e10s as it's a CPOW, not a DOM node. But under e10s,
   // nsContextMenu won't use the property anyway, so just try/catching is ok.
   try {
     document.popupNode = getNode("div");
   } catch (e) {}
 
@@ -65,17 +83,26 @@ function* selectWithBrowserMenu(inspecto
   contentAreaContextMenu.hidePopup();
   contextMenu.hiding();
 
   yield inspector.once("inspector-updated");
 }
 
 function* selectWithElementPicker(inspector) {
   yield inspector.toolbox.highlighterUtils.startPicker();
-  yield BrowserTestUtils.synthesizeMouseAtCenter("div", {
-    type: "mousemove",
-  }, gBrowser.selectedBrowser);
+
+  yield executeInContent("Test:MarkupView:SynthesizeMouse", {
+    center: true,
+    selector: "div",
+    options: {type: "mousemove"}
+  });
+
+  // Read comment in selectWithBrowserMenu() method.
+  //yield BrowserTestUtils.synthesizeMouseAtCenter("div", {
+  //  type: "mousemove",
+  //}, gBrowser.selectedBrowser);
+
   executeInContent("Test:SynthesizeKey", {
     key: "VK_RETURN",
     options: {}
   }, false);
   yield inspector.once("inspector-updated");
 }
new file mode 100644
--- /dev/null
+++ b/browser/devtools/markupview/test/frame-script-utils.js
@@ -0,0 +1,46 @@
+/* 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 {classes: Cc, interfaces: Ci} = Components;
+const subScriptLoader = Cc["@mozilla.org/moz/jssubscript-loader;1"]
+                          .getService(Ci.mozIJSSubScriptLoader);
+let EventUtils = {};
+subScriptLoader.loadSubScript("chrome://marionette/content/EventUtils.js", EventUtils);
+
+/**
+ * Synthesize a mouse event on an element. This handler doesn't send a message
+ * back. Consumers should listen to specific events on the inspector/highlighter
+ * to know when the event got synthesized.
+ * @param {Object} msg The msg.data part expects the following properties:
+ * - {Number} x
+ * - {Number} y
+ * - {Boolean} center If set to true, x/y will be ignored and
+ *             synthesizeMouseAtCenter will be used instead
+ * - {Object} options Other event options
+ * - {String} selector An optional selector that will be used to find the node to
+ *            synthesize the event on, if msg.objects doesn't contain the CPOW.
+ * The msg.objects part should be the element.
+ * @param {Object} data Event detail properties:
+ */
+addMessageListener("Test:MarkupView:SynthesizeMouse", function(msg) {
+  let {x, y, center, options, selector} = msg.data;
+  let {node} = msg.objects;
+
+  if (!node && selector) {
+    node = content.document.querySelector(selector);
+  }
+
+  if (center) {
+    EventUtils.synthesizeMouseAtCenter(node, options, node.ownerDocument.defaultView);
+  } else {
+    EventUtils.synthesizeMouse(node, x, y, options, node.ownerDocument.defaultView);
+  }
+
+  // Most consumers won't need to listen to this message, unless they want to
+  // wait for the mouse event to be synthesized and don't have another event
+  // to listen to instead.
+  sendAsyncMessage("Test:MarkupView:SynthesizeMouse");
+});
--- a/browser/devtools/markupview/test/head.js
+++ b/browser/devtools/markupview/test/head.js
@@ -46,16 +46,17 @@ registerCleanupFunction(function*() {
   while (gBrowser.tabs.length > 1) {
     gBrowser.removeCurrentTab();
   }
 });
 
 const TEST_URL_ROOT = "http://mochi.test:8888/browser/browser/devtools/markupview/test/";
 const CHROME_BASE = "chrome://mochitests/content/browser/browser/devtools/markupview/test/";
 const COMMON_FRAME_SCRIPT_URL = "chrome://browser/content/devtools/frame-script-utils.js";
+const MARKUPVIEW_FRAME_SCRIPT_URL = CHROME_BASE + "frame-script-utils.js";
 
 /**
  * Add a new test tab in the browser and load the given url.
  * @param {String} url The url to be loaded in the new tab
  * @return a promise that resolves to the tab object when the url is loaded
  */
 function addTab(url) {
   info("Adding a new tab with URL: '" + url + "'");
@@ -66,16 +67,17 @@ function addTab(url) {
   // For now, we just make sure the window is focused.
   window.focus();
 
   let tab = window.gBrowser.selectedTab = window.gBrowser.addTab(url);
   let linkedBrowser = tab.linkedBrowser;
 
   info("Loading the helper frame script " + COMMON_FRAME_SCRIPT_URL);
   linkedBrowser.messageManager.loadFrameScript(COMMON_FRAME_SCRIPT_URL, false);
+  linkedBrowser.messageManager.loadFrameScript(MARKUPVIEW_FRAME_SCRIPT_URL, false);
 
   linkedBrowser.addEventListener("load", function onload() {
     linkedBrowser.removeEventListener("load", onload, true);
     info("URL '" + url + "' loading complete");
     def.resolve(tab);
   }, true);
 
   return def.promise;
--- a/browser/devtools/performance/modules/logic/frame-utils.js
+++ b/browser/devtools/performance/modules/logic/frame-utils.js
@@ -549,13 +549,37 @@ function getFrameInfo (node, options) {
     data.totalSizePercentage = node.byteSize / totalBytes * 100;
     data.ALLOCATION_DATA_CALCULATED = true;
   }
 
   return data;
 }
 
 exports.getFrameInfo = getFrameInfo;
+
+/**
+ * Takes an inverted ThreadNode and searches its youngest frames for
+ * a FrameNode with matching location.
+ *
+ * @param {ThreadNode} threadNode
+ * @param {string} location
+ * @return {?FrameNode}
+ */
+function findFrameByLocation (threadNode, location) {
+  if (!threadNode.inverted) {
+    throw new Error("FrameUtils.findFrameByLocation only supports leaf nodes in an inverted tree.");
+  }
+
+  let calls = threadNode.calls;
+  for (let i = 0; i < calls.length; i++) {
+    if (calls[i].location === location) {
+      return calls[i];
+    }
+  }
+  return null;
+}
+
+exports.findFrameByLocation = findFrameByLocation;
 exports.computeIsContentAndCategory = computeIsContentAndCategory;
 exports.parseLocation = parseLocation;
 exports.getInflatedFrameCache = getInflatedFrameCache;
 exports.getOrAddInflatedFrame = getOrAddInflatedFrame;
 exports.InflatedFrame = InflatedFrame;
--- a/browser/devtools/performance/modules/logic/jit.js
+++ b/browser/devtools/performance/modules/logic/jit.js
@@ -264,70 +264,72 @@ const IMPLEMENTATION_NAMES = Object.keys
  * Takes data from a FrameNode and computes rendering positions for
  * a stacked mountain graph, to visualize JIT optimization tiers over time.
  *
  * @param {FrameNode} frameNode
  *                    The FrameNode who's optimizations we're iterating.
  * @param {Array<number>} sampleTimes
  *                        An array of every sample time within the range we're counting.
  *                        From a ThreadNode's `sampleTimes` property.
- * @param {number} op.startTime
- *                 The start time of the first sample.
- * @param {number} op.endTime
- *                 The end time of the last sample.
- * @param {number} op.resolution
- *                 The maximum amount of possible data points returned.
- *                 Also determines the size in milliseconds of each bucket
- *                 via `(endTime - startTime) / resolution`
+ * @param {number} bucketSize
+ *                 Size of each bucket in milliseconds.
+ *                 `duration / resolution = bucketSize` in OptimizationsGraph.
  * @return {?Array<object>}
  */
-function createTierGraphDataFromFrameNode (frameNode, sampleTimes, { startTime, endTime, resolution }) {
-  if (!frameNode.hasOptimizations()) {
-    return;
-  }
-
-  let tierData = frameNode.getOptimizationTierData();
-  let duration = endTime - startTime;
+function createTierGraphDataFromFrameNode (frameNode, sampleTimes, bucketSize) {
+  let tierData = frameNode.getTierData();
   let stringTable = frameNode._stringTable;
   let output = [];
   let implEnum;
 
   let tierDataIndex = 0;
   let nextOptSample = tierData[tierDataIndex];
 
   // Bucket data
   let samplesInCurrentBucket = 0;
   let currentBucketStartTime = sampleTimes[0];
   let bucket = [];
-  // Size of each bucket in milliseconds
-  let bucketSize = Math.ceil(duration / resolution);
+
+  // Store previous data point so we can have straight vertical lines
+  let previousValues;
 
   // Iterate one after the samples, so we can finalize the last bucket
   for (let i = 0; i <= sampleTimes.length; i++) {
     let sampleTime = sampleTimes[i];
 
     // If this sample is in the next bucket, or we're done
     // checking sampleTimes and on the last iteration, finalize previous bucket
     if (sampleTime >= (currentBucketStartTime + bucketSize) ||
         i >= sampleTimes.length) {
 
       let dataPoint = {};
-      dataPoint.ys = [];
-      dataPoint.x = currentBucketStartTime;
+      dataPoint.values = [];
+      dataPoint.delta = currentBucketStartTime;
 
       // Map the opt site counts as a normalized percentage (0-1)
       // of its count in context of total samples this bucket
       for (let j = 0; j < IMPLEMENTATION_NAMES.length; j++) {
-        dataPoint.ys[j] = (bucket[j] || 0) / (samplesInCurrentBucket || 1);
+        dataPoint.values[j] = (bucket[j] || 0) / (samplesInCurrentBucket || 1);
       }
+
+      // Push the values from the previous bucket to the same time
+      // as the current bucket so we get a straight vertical line.
+      if (previousValues) {
+        let data = Object.create(null);
+        data.values = previousValues;
+        data.delta = currentBucketStartTime;
+        output.push(data);
+      }
+
       output.push(dataPoint);
 
       // Set the new start time of this bucket and reset its count
       currentBucketStartTime += bucketSize;
       samplesInCurrentBucket = 0;
+      previousValues = dataPoint.values;
       bucket = [];
     }
 
     // If this sample observed an optimization in this frame, record it
     if (nextOptSample && nextOptSample.time === sampleTime) {
       // If no implementation defined, it was the "interpreter".
       implEnum = IMPLEMENTATION_MAP[stringTable[nextOptSample.implementation] || "interpreter"];
       bucket[implEnum] = (bucket[implEnum] || 0) + 1;
--- a/browser/devtools/performance/modules/logic/tree-model.js
+++ b/browser/devtools/performance/modules/logic/tree-model.js
@@ -31,16 +31,18 @@ function ThreadNode(thread, options = {}
     throw new Error("ThreadNode requires both `startTime` and `endTime`.");
   }
   this.samples = 0;
   this.sampleTimes = [];
   this.youngestFrameSamples = 0;
   this.calls = [];
   this.duration = options.endTime - options.startTime;
   this.nodeType = "Thread";
+  this.inverted = options.invertTree;
+
   // Total bytesize of all allocations if enabled
   this.byteSize = 0;
   this.youngestFrameByteSize = 0;
 
   let { samples, stackTable, frameTable, stringTable } = thread;
 
   // Nothing to do if there are no samples.
   if (samples.data.length === 0) {
@@ -227,20 +229,18 @@ ThreadNode.prototype = {
           calls = prevCalls;
         }
 
         let frameNode = getOrAddFrameNode(calls, isLeaf, frameKey, inflatedFrame,
                                           mutableFrameKeyOptions.isMetaCategoryOut,
                                           leafTable);
         if (isLeaf) {
           frameNode.youngestFrameSamples++;
-          if (inflatedFrame.optimizations) {
-            frameNode._addOptimizations(inflatedFrame.optimizations, inflatedFrame.implementation,
-                                        sampleTime, stringTable);
-          }
+          frameNode._addOptimizations(inflatedFrame.optimizations, inflatedFrame.implementation,
+                                      sampleTime, stringTable);
 
           if (byteSize) {
             frameNode.youngestFrameByteSize += byteSize;
           }
         }
 
         // Don't overcount flattened recursive frames.
         if (!shouldFlatten) {
@@ -405,57 +405,57 @@ function FrameNode(frameKey, { location,
   this.key = frameKey;
   this.location = location;
   this.line = line;
   this.youngestFrameSamples = 0;
   this.samples = 0;
   this.calls = [];
   this.isContent = !!isContent;
   this._optimizations = null;
-  this._tierData = null;
+  this._tierData = [];
   this._stringTable = null;
   this.isMetaCategory = !!isMetaCategory;
   this.category = category;
   this.nodeType = "Frame";
   this.byteSize = 0;
   this.youngestFrameByteSize = 0;
 }
 
 FrameNode.prototype = {
   /**
    * Take optimization data observed for this frame.
    *
    * @param object optimizationSite
    *               Any JIT optimization information attached to the current
    *               sample. Lazily inflated via stringTable.
    * @param number implementation
-   *               JIT implementation used for this observed frame (interpreter,
-   *               baseline, ion);
+   *               JIT implementation used for this observed frame (baseline, ion);
+   *               can be null indicating "interpreter"
    * @param number time
    *               The time this optimization occurred.
    * @param object stringTable
    *               The string table used to inflate the optimizationSite.
    */
   _addOptimizations: function (site, implementation, time, stringTable) {
     // Simply accumulate optimization sites for now. Processing is done lazily
     // by JITOptimizations, if optimization information is actually displayed.
     if (site) {
       let opts = this._optimizations;
       if (opts === null) {
         opts = this._optimizations = [];
-        this._stringTable = stringTable;
       }
       opts.push(site);
+    }
 
-      if (this._tierData === null) {
-        this._tierData = [];
-      }
-      // Record type of implementation used and the sample time
-      this._tierData.push({ implementation, time });
+    if (!this._stringTable) {
+      this._stringTable = stringTable;
     }
+
+    // Record type of implementation used and the sample time
+    this._tierData.push({ implementation, time });
   },
 
   _clone: function (samples, size) {
     let newNode = new FrameNode(this.key, this, this.isMetaCategory);
     newNode._merge(this, samples, size);
     return newNode;
   },
 
@@ -469,27 +469,39 @@ FrameNode.prototype = {
     if (otherNode.youngestFrameSamples > 0) {
       this.youngestFrameSamples += samples;
     }
 
     if (otherNode.youngestFrameByteSize > 0) {
       this.youngestFrameByteSize += otherNode.youngestFrameByteSize;
     }
 
+    if (this._stringTable === null) {
+      this._stringTable = otherNode._stringTable;
+    }
+
     if (otherNode._optimizations) {
+      if (!this._optimizations) {
+        this._optimizations = [];
+      }
       let opts = this._optimizations;
-      if (opts === null) {
-        opts = this._optimizations = [];
-        this._stringTable = otherNode._stringTable;
-      }
       let otherOpts = otherNode._optimizations;
       for (let i = 0; i < otherOpts.length; i++) {
-        opts.push(otherOpts[i]);
+       opts.push(otherOpts[i]);
       }
     }
+
+    if (otherNode._tierData.length) {
+      let tierData = this._tierData;
+      let otherTierData = otherNode._tierData;
+      for (let i = 0; i < otherTierData.length; i++) {
+        tierData.push(otherTierData[i]);
+      }
+      tierData.sort((a, b) => a.time - b.time);
+    }
   },
 
   /**
    * Returns the parsed location and additional data describing
    * this frame. Uses cached data if possible. Takes the following
    * options:
    *
    * @param {ThreadNode} options.root
@@ -524,22 +536,19 @@ FrameNode.prototype = {
   getOptimizations: function () {
     if (!this._optimizations) {
       return null;
     }
     return new JITOptimizations(this._optimizations, this._stringTable);
   },
 
   /**
-   * Returns the optimization tiers used overtime.
+   * Returns the tiers used overtime.
    *
-   * @return {?Array<object>}
+   * @return {Array<object>}
    */
-  getOptimizationTierData: function () {
-    if (!this._tierData) {
-      return null;
-    }
+  getTierData: function () {
     return this._tierData;
   }
 };
 
 exports.ThreadNode = ThreadNode;
 exports.FrameNode = FrameNode;
--- a/browser/devtools/performance/modules/widgets/graphs.js
+++ b/browser/devtools/performance/modules/widgets/graphs.js
@@ -7,53 +7,61 @@
  * This file contains the base line graph that all Performance line graphs use.
  */
 
 const { Cc, Ci, Cu, Cr } = require("chrome");
 const { Task } = require("resource://gre/modules/Task.jsm");
 const { Heritage } = require("resource:///modules/devtools/ViewHelpers.jsm");
 const LineGraphWidget = require("devtools/shared/widgets/LineGraphWidget");
 const BarGraphWidget = require("devtools/shared/widgets/BarGraphWidget");
+const MountainGraphWidget = require("devtools/shared/widgets/MountainGraphWidget");
 const { CanvasGraphUtils } = require("devtools/shared/widgets/Graphs");
 
 loader.lazyRequireGetter(this, "promise");
 loader.lazyRequireGetter(this, "EventEmitter",
   "devtools/toolkit/event-emitter");
 
 loader.lazyRequireGetter(this, "colorUtils",
   "devtools/css-color", true);
 loader.lazyRequireGetter(this, "getColor",
   "devtools/shared/theme", true);
 loader.lazyRequireGetter(this, "ProfilerGlobal",
   "devtools/performance/global");
 loader.lazyRequireGetter(this, "L10N",
   "devtools/performance/global", true);
 loader.lazyRequireGetter(this, "MarkersOverview",
   "devtools/performance/markers-overview", true);
+loader.lazyRequireGetter(this, "createTierGraphDataFromFrameNode",
+  "devtools/performance/jit", true);
 
 /**
  * For line graphs
  */
 const HEIGHT = 35; // px
 const STROKE_WIDTH = 1; // px
 const DAMPEN_VALUES = 0.95;
 const CLIPHEAD_LINE_COLOR = "#666";
 const SELECTION_LINE_COLOR = "#555";
-const SELECTION_BACKGROUND_COLOR_NAME = "highlight-blue";
-const FRAMERATE_GRAPH_COLOR_NAME = "highlight-green";
-const MEMORY_GRAPH_COLOR_NAME = "highlight-blue";
+const SELECTION_BACKGROUND_COLOR_NAME = "graphs-blue";
+const FRAMERATE_GRAPH_COLOR_NAME = "graphs-green";
+const MEMORY_GRAPH_COLOR_NAME = "graphs-blue";
 
 /**
  * For timeline overview
  */
 const MARKERS_GRAPH_HEADER_HEIGHT = 14; // px
 const MARKERS_GRAPH_ROW_HEIGHT = 10; // px
 const MARKERS_GROUP_VERTICAL_PADDING = 4; // px
 
 /**
+ * For optimization graph
+ */
+const OPTIMIZATIONS_GRAPH_RESOLUTION = 100;
+
+/**
  * A base class for performance graphs to inherit from.
  *
  * @param nsIDOMNode parent
  *        The parent node holding the overview.
  * @param string metric
  *        The unit of measurement for this graph.
  */
 function PerformanceGraph(parent, metric) {
@@ -81,17 +89,17 @@ PerformanceGraph.prototype = Heritage.ex
 
   /**
    * Sets the theme via `theme` to either "light" or "dark",
    * and updates the internal styling to match. Requires a redraw
    * to see the effects.
    */
   setTheme: function (theme) {
     theme = theme || "light";
-    let mainColor = getColor(this.mainColor || "highlight-blue", theme);
+    let mainColor = getColor(this.mainColor || "graphs-blue", theme);
     this.backgroundColor = getColor("body-background", theme);
     this.strokeColor = mainColor;
     this.backgroundGradientStart = colorUtils.setAlpha(mainColor, 0.2);
     this.backgroundGradientEnd = colorUtils.setAlpha(mainColor, 0.2);
     this.selectionBackgroundColor = colorUtils.setAlpha(getColor(SELECTION_BACKGROUND_COLOR_NAME, theme), 0.25);
     this.selectionStripesColor = "rgba(255, 255, 255, 0.1)";
     this.maximumLineColor = colorUtils.setAlpha(mainColor, 0.4);
     this.averageLineColor = colorUtils.setAlpha(mainColor, 0.7);
@@ -420,12 +428,88 @@ GraphsController.prototype = {
       if (graph = yield this.isAvailable(graphName)) {
         enabled.push(graph);
       }
     }
     return this._enabledGraphs = enabled;
   }),
 };
 
+/**
+ * A base class for performance graphs to inherit from.
+ *
+ * @param nsIDOMNode parent
+ *        The parent node holding the overview.
+ * @param string metric
+ *        The unit of measurement for this graph.
+ */
+function OptimizationsGraph(parent) {
+  MountainGraphWidget.call(this, parent);
+  this.setTheme();
+}
+
+OptimizationsGraph.prototype = Heritage.extend(MountainGraphWidget.prototype, {
+
+  render: Task.async(function *(threadNode, frameNode) {
+    // Regardless if we draw or clear the graph, wait
+    // until it's ready.
+    yield this.ready();
+
+    if (!threadNode || !frameNode) {
+      this.setData([]);
+      return;
+    }
+
+    let { sampleTimes } = threadNode;
+
+    if (!sampleTimes.length) {
+      this.setData([]);
+      return;
+    }
+
+    // Take startTime/endTime from samples recorded, rather than
+    // using duration directly from threadNode, as the first sample that
+    // equals the startTime does not get recorded.
+    let startTime = sampleTimes[0];
+    let endTime = sampleTimes[sampleTimes.length - 1];
+
+    let bucketSize = (endTime - startTime) / OPTIMIZATIONS_GRAPH_RESOLUTION;
+    let data = createTierGraphDataFromFrameNode(frameNode, sampleTimes, bucketSize);
+
+    // If for some reason we don't have data (like the frameNode doesn't
+    // have optimizations, but it shouldn't be at this point if it doesn't),
+    // log an error.
+    if (!data) {
+      Cu.reportError(`FrameNode#${frameNode.location} does not have optimizations data to render.`);
+      return;
+    }
+
+    this.dataOffsetX = startTime;
+    yield this.setData(data);
+  }),
+
+  /**
+   * Sets the theme via `theme` to either "light" or "dark",
+   * and updates the internal styling to match. Requires a redraw
+   * to see the effects.
+   */
+  setTheme: function (theme) {
+    theme = theme || "light";
+
+    let interpreterColor = getColor("graphs-red", theme);
+    let baselineColor = getColor("graphs-blue", theme);
+    let ionColor = getColor("graphs-green", theme);
+
+    this.format = [
+      { color: interpreterColor },
+      { color: baselineColor },
+      { color: ionColor },
+    ];
+
+    this.backgroundColor = getColor("sidebar-background", theme);
+  }
+});
+
+exports.OptimizationsGraph = OptimizationsGraph;
 exports.FramerateGraph = FramerateGraph;
 exports.MemoryGraph = MemoryGraph;
 exports.TimelineGraph = TimelineGraph;
 exports.GraphsController = GraphsController;
--- a/browser/devtools/performance/performance-controller.js
+++ b/browser/devtools/performance/performance-controller.js
@@ -28,26 +28,30 @@ loader.lazyRequireGetter(this, "L10N",
 loader.lazyRequireGetter(this, "PerformanceTelemetry",
   "devtools/performance/telemetry", true);
 loader.lazyRequireGetter(this, "TIMELINE_BLUEPRINT",
   "devtools/performance/markers", true);
 loader.lazyRequireGetter(this, "RecordingUtils",
   "devtools/toolkit/performance/utils");
 loader.lazyRequireGetter(this, "GraphsController",
   "devtools/performance/graphs", true);
+loader.lazyRequireGetter(this, "OptimizationsGraph",
+  "devtools/performance/graphs", true);
 loader.lazyRequireGetter(this, "WaterfallHeader",
   "devtools/performance/waterfall-ticks", true);
 loader.lazyRequireGetter(this, "MarkerView",
   "devtools/performance/marker-view", true);
 loader.lazyRequireGetter(this, "MarkerDetails",
   "devtools/performance/marker-details", true);
 loader.lazyRequireGetter(this, "MarkerUtils",
   "devtools/performance/marker-utils");
 loader.lazyRequireGetter(this, "WaterfallUtils",
   "devtools/performance/waterfall-utils");
+loader.lazyRequireGetter(this, "FrameUtils",
+  "devtools/performance/frame-utils");
 loader.lazyRequireGetter(this, "CallView",
   "devtools/performance/tree-view", true);
 loader.lazyRequireGetter(this, "ThreadNode",
   "devtools/performance/tree-model", true);
 loader.lazyRequireGetter(this, "FrameNode",
   "devtools/performance/tree-model", true);
 loader.lazyRequireGetter(this, "JITOptimizations",
   "devtools/performance/jit", true);
--- a/browser/devtools/performance/performance.xul
+++ b/browser/devtools/performance/performance.xul
@@ -72,17 +72,17 @@
                 class="experimental-option"
                 type="checkbox"
                 data-pref="enable-jit-optimizations"
                 label="&performanceUI.enableJITOptimizations;"
                 tooltiptext="&performanceUI.enableJITOptimizations.tooltiptext;"/>
     </menupopup>
   </popupset>
 
-  <hbox class="theme-body" flex="1">
+  <hbox id="body" class="theme-body" flex="1">
 
     <!-- Sidebar: controls and recording list -->
     <vbox id="recordings-pane">
       <toolbar id="recordings-toolbar"
                class="devtools-toolbar">
         <hbox id="recordings-controls"
               class="devtools-toolbarbutton-group">
           <toolbarbutton id="main-record-button"
@@ -299,16 +299,17 @@
                   <toolbar id="jit-optimizations-toolbar" class="devtools-toolbar">
                     <hbox id="jit-optimizations-header">
                       <span class="jit-optimizations-title">&performanceUI.JITOptimizationsTitle;</span>
                       <span class="header-function-name" />
                       <span class="header-file opt-url debugger-link" />
                       <span class="header-line opt-line" />
                     </hbox>
                   </toolbar>
+                  <hbox id="optimizations-graph"></hbox>
                   <vbox id="jit-optimizations-raw-view"></vbox>
                 </vbox>
               </hbox>
 
               <!-- JS FlameChart -->
               <hbox id="js-flamegraph-view" flex="1">
               </hbox>
 
@@ -359,17 +360,16 @@
                          type="function"
                          crop="end"
                          value="&performanceUI.table.function;"/>
                 </hbox>
                 <vbox class="call-tree-cells-container" flex="1"/>
               </vbox>
 
               <!-- Memory FlameChart -->
-              <hbox id="memory-flamegraph-view" flex="1">
-              </hbox>
+              <hbox id="memory-flamegraph-view" flex="1"></hbox>
             </deck>
           </deck>
         </vbox>
       </deck>
     </vbox>
   </hbox>
 </window>
--- a/browser/devtools/performance/test/unit/test_jit-graph-data.js
+++ b/browser/devtools/performance/test/unit/test_jit-graph-data.js
@@ -31,75 +31,88 @@ add_task(function test() {
 
   equal(root.samples, SAMPLE_COUNT / 2, "root has correct amount of samples");
   equal(root.sampleTimes.length, SAMPLE_COUNT / 2, "root has correct amount of sample times");
   // Add time offset since the first sample begins TIME_OFFSET after startTime
   equal(root.sampleTimes[0], startTime + TIME_OFFSET, "root recorded first sample time in scope");
   equal(root.sampleTimes[root.sampleTimes.length - 1], endTime, "root recorded last sample time in scope");
 
   let frame = getFrameNodePath(root, "X");
-  let data = createTierGraphDataFromFrameNode(frame, root.sampleTimes, { startTime, endTime, resolution: RESOLUTION });
+  let data = createTierGraphDataFromFrameNode(frame, root.sampleTimes, (endTime-startTime)/RESOLUTION);
 
   let TIME_PER_WINDOW = SAMPLE_COUNT / 2 / RESOLUTION * TIME_PER_SAMPLE;
 
-  for (let i = 0; i < 10; i++) {
-    equal(data[i].x, startTime + TIME_OFFSET + (TIME_PER_WINDOW * i), "first window has correct x");
-    equal(data[i].ys[0], 0.2, "first window has 2 frames in interpreter");
-    equal(data[i].ys[1], 0.2, "first window has 2 frames in baseline");
-    equal(data[i].ys[2], 0.2, "first window has 2 frames in ion");
+  // Filter out the dupes created with the same delta so the graph
+  // can render correctly.
+  let filteredData = [];
+  for (let i = 0; i < data.length; i++) {
+    if (!i || data[i].delta !== data[i-1].delta) {
+      filteredData.push(data[i]);
+    }
+  }
+  data = filteredData;
+
+  for (let i = 0; i < 11; i++) {
+    equal(data[i].delta, startTime + TIME_OFFSET + (TIME_PER_WINDOW * i), "first window has correct x");
+    equal(data[i].values[0], 0.2, "first window has 2 frames in interpreter");
+    equal(data[i].values[1], 0.2, "first window has 2 frames in baseline");
+    equal(data[i].values[2], 0.2, "first window has 2 frames in ion");
   }
-  for (let i = 10; i < 20; i++) {
-    equal(data[i].x, startTime + TIME_OFFSET + (TIME_PER_WINDOW * i), "second window has correct x");
-    equal(data[i].ys[0], 0, "second window observed no optimizations");
-    equal(data[i].ys[1], 0, "second window observed no optimizations");
-    equal(data[i].ys[2], 0, "second window observed no optimizations");
+  // Start on 11, since i===10 is where the values change, and the new value (0,0,0)
+  // is removed in `filteredData`
+  for (let i = 11; i < 20; i++) {
+    equal(data[i].delta, startTime + TIME_OFFSET + (TIME_PER_WINDOW * i), "second window has correct x");
+    equal(data[i].values[0], 0, "second window observed no optimizations");
+    equal(data[i].values[1], 0, "second window observed no optimizations");
+    equal(data[i].values[2], 0, "second window observed no optimizations");
   }
-  for (let i = 20; i < 30; i++) {
-    equal(data[i].x, startTime + TIME_OFFSET + (TIME_PER_WINDOW * i), "third window has correct x");
-    equal(data[i].ys[0], 0.3, "third window has 3 frames in interpreter");
-    equal(data[i].ys[1], 0, "third window has 0 frames in baseline");
-    equal(data[i].ys[2], 0, "third window has 0 frames in ion");
+  // Start on 21, since i===20 is where the values change, and the new value (0.3,0,0)
+  // is removed in `filteredData`
+  for (let i = 21; i < 30; i++) {
+    equal(data[i].delta, startTime + TIME_OFFSET + (TIME_PER_WINDOW * i), "third window has correct x");
+    equal(data[i].values[0], 0.3, "third window has 3 frames in interpreter");
+    equal(data[i].values[1], 0, "third window has 0 frames in baseline");
+    equal(data[i].values[2], 0, "third window has 0 frames in ion");
   }
 });
 
 let gUniqueStacks = new RecordingUtils.UniqueStacks();
 
 function uniqStr(s) {
   return gUniqueStacks.getOrAddStringIndex(s);
 }
 
 const TIER_PATTERNS = [
   // 0-99
-  ["X", "X", "X", "X", "X", "X", "X", "X", "X", "X"],
+  ["X_0", "X_0", "X_0", "X_0", "X_0", "X_0", "X_0", "X_0", "X_0", "X_0"],
   // 100-199
-  ["X", "X", "X", "X", "X", "X", "X", "X", "X", "X"],
+  ["X_0", "X_0", "X_0", "X_0", "X_0", "X_0", "X_0", "X_0", "X_0", "X_0"],
   // 200-299
-  ["X", "X", "X", "X", "X", "X", "X", "X", "X", "X"],
+  ["X_0", "X_0", "X_0", "X_0", "X_0", "X_0", "X_0", "X_0", "X_0", "X_0"],
   // 300-399
-  ["X", "X", "X", "X", "X", "X", "X", "X", "X", "X"],
+  ["X_0", "X_0", "X_0", "X_0", "X_0", "X_0", "X_0", "X_0", "X_0", "X_0"],
   // 400-499
-  ["X", "X", "X", "X", "X", "X", "X", "X", "X", "X"],
+  ["X_0", "X_0", "X_0", "X_0", "X_0", "X_0", "X_0", "X_0", "X_0", "X_0"],
 
   // 500-599
-  // Test current frames in all opts, including that
-  // the same frame with no opts does not get counted
-  ["X", "X", "A", "A", "X_1", "X_2", "X_1", "X_2", "X_0", "X_0"],
+  // Test current frames in all opts
+  ["A", "A", "A", "A", "X_1", "X_2", "X_1", "X_2", "X_0", "X_0"],
 
   // 600-699
   // Nothing for current frame
   ["A", "B", "A", "B", "A", "B", "A", "B", "A", "B"],
 
   // 700-799
   // A few frames where the frame is not the leaf node
   ["X_2 -> Y", "X_2 -> Y", "X_2 -> Y", "X_0", "X_0", "X_0", "A", "A", "A", "A"],
 
   // 800-899
-  ["X", "X", "X", "X", "X", "X", "X", "X", "X", "X"],
+  ["X_0", "X_0", "X_0", "X_0", "X_0", "X_0", "X_0", "X_0", "X_0", "X_0"],
   // 900-999
-  ["X", "X", "X", "X", "X", "X", "X", "X", "X", "X"],
+  ["X_0", "X_0", "X_0", "X_0", "X_0", "X_0", "X_0", "X_0", "X_0", "X_0"],
 ];
 
 function createSample (i, frames) {
   let sample = {};
   sample.time = i * TIME_PER_SAMPLE;
   sample.frames = [{ location: "(root)" }];
   if (i === 0) {
     return sample;
--- a/browser/devtools/performance/views/details-js-call-tree.js
+++ b/browser/devtools/performance/views/details-js-call-tree.js
@@ -31,16 +31,17 @@ let JsCallTreeView = Heritage.extend(Det
   },
 
   /**
    * Unbinds events.
    */
   destroy: function () {
     OptimizationsListView.destroy();
     this.container = null;
+    this.threadNode = null;
     DetailsSubview.destroy.call(this);
   },
 
   /**
    * Method for handling all the set up for rendering a new call tree.
    *
    * @param object interval [optional]
    *        The { startTime, endTime }, in milliseconds.
@@ -51,17 +52,17 @@ let JsCallTreeView = Heritage.extend(Det
     let optimizations = recording.getConfiguration().withJITOptimizations;
 
     let options = {
       contentOnly: !PerformanceController.getOption("show-platform-data"),
       invertTree: PerformanceController.getOption("invert-call-tree"),
       flattenRecursion: PerformanceController.getOption("flatten-tree-recursion"),
       showOptimizationHint: optimizations
     };
-    let threadNode = this._prepareCallTree(profile, interval, options);
+    let threadNode = this.threadNode = this._prepareCallTree(profile, interval, options);
     this._populateCallTree(threadNode, options);
 
     if (optimizations) {
       this.showOptimizations();
     } else {
       this.hideOptimizations();
     }
     OptimizationsListView.reset();
@@ -74,17 +75,17 @@ let JsCallTreeView = Heritage.extend(Det
   },
 
   hideOptimizations: function () {
     $("#jit-optimizations-view").classList.add("hidden");
   },
 
   _onFocus: function (_, treeItem) {
     if (PerformanceController.getCurrentRecording().getConfiguration().withJITOptimizations) {
-      OptimizationsListView.setCurrentFrame(treeItem.frame);
+      OptimizationsListView.setCurrentFrame(this.threadNode, treeItem.frame);
       OptimizationsListView.render();
     }
 
     this.emit("focus", treeItem);
   },
 
   /**
    * Fired on the "link" event for the call tree in this container.
--- a/browser/devtools/performance/views/optimizations-list.js
+++ b/browser/devtools/performance/views/optimizations-list.js
@@ -19,66 +19,84 @@ let OptimizationsListView = {
 
   _currentFrame: null,
 
   /**
    * Initialization function called when the tool starts up.
    */
   initialize: function () {
     this.reset = this.reset.bind(this);
+    this._onThemeChanged = this._onThemeChanged.bind(this);
 
     this.el = $("#jit-optimizations-view");
     this.$headerName = $("#jit-optimizations-header .header-function-name");
     this.$headerFile = $("#jit-optimizations-header .header-file");
     this.$headerLine = $("#jit-optimizations-header .header-line");
 
     this.tree = new TreeWidget($("#jit-optimizations-raw-view"), {
       sorted: false,
       emptyText: JIT_EMPTY_TEXT
     });
+    this.graph = new OptimizationsGraph($("#optimizations-graph"));
+    this.graph.setTheme(PerformanceController.getTheme());
 
     // Start the tree by resetting.
     this.reset();
+
+    PerformanceController.on(EVENTS.THEME_CHANGED, this._onThemeChanged);
   },
 
   /**
    * Destruction function called when the tool cleans up.
    */
   destroy: function () {
+    PerformanceController.off(EVENTS.THEME_CHANGED, this._onThemeChanged);
     this.tree = null;
     this.$headerName = this.$headerFile = this.$headerLine = this.el = null;
   },
 
   /**
    * Takes a FrameNode, with corresponding optimization data to be displayed
    * in the view.
    *
    * @param {FrameNode} frameNode
    */
-  setCurrentFrame: function (frameNode) {
+  setCurrentFrame: function (threadNode, frameNode) {
+    if (threadNode !== this.getCurrentThread()) {
+      this._currentThread = threadNode;
+    }
     if (frameNode !== this.getCurrentFrame()) {
       this._currentFrame = frameNode;
     }
   },
 
   /**
    * Returns the current frame node for this view.
    *
    * @return {?FrameNode}
    */
-  getCurrentFrame: function (frameNode) {
+  getCurrentFrame: function () {
     return this._currentFrame;
   },
 
   /**
+   * Returns the current thread node for this view.
+   *
+   * @return {?ThreadNode}
+   */
+  getCurrentThread: function () {
+    return this._currentThread;
+  },
+
+  /**
    * Clears out data in the tree, sets to an empty state,
    * and removes current frame.
    */
   reset: function () {
-    this.setCurrentFrame(null);
+    this.setCurrentFrame(null, null);
     this.clear();
     this.el.classList.add("empty");
     this.emit(EVENTS.OPTIMIZATIONS_RESET);
     this.emit(EVENTS.OPTIMIZATIONS_RENDERED, this.getCurrentFrame());
   },
 
   /**
    * Clears out data in the tree.
@@ -118,20 +136,29 @@ let OptimizationsListView = {
 
     // An array of sorted OptimizationSites.
     let sites = frameNode.getOptimizations().optimizationSites;
 
     for (let site of sites) {
       this._renderSite(view, site, frameData);
     }
 
+    this._renderTierGraph();
+
     this.emit(EVENTS.OPTIMIZATIONS_RENDERED, this.getCurrentFrame());
   },
 
   /**
+   * Renders the optimization tier graph over time.
+   */
+  _renderTierGraph: function () {
+    this.graph.render(this.getCurrentThread(), this.getCurrentFrame());
+  },
+
+  /**
    * Creates an entry in the tree widget for an optimization site.
    */
   _renderSite: function (view, site, frameData) {
     let { id, samples, data } = site;
     let { types, attempts } = data;
     let siteNode = this._createSiteNode(frameData, site);
 
     // Cast `id` to a string so TreeWidget doesn't think it does not exist
@@ -170,17 +197,16 @@ let OptimizationsListView = {
         view.add([id, `${id}-types`, `${id}-types-${i}`, { node }]);
       }
     }
   },
 
   /**
    * Creates an element for insertion in the raw view for an OptimizationSite.
    */
-
   _createSiteNode: function (frameData, site) {
     let node = document.createElement("span");
     let desc = document.createElement("span");
     let line = document.createElement("span");
     let column = document.createElement("span");
     let urlNode = this._createDebuggerLinkNode(frameData.url, site.data.line);
 
     let attempts = site.getAttempts();
@@ -220,32 +246,30 @@ let OptimizationsListView = {
 
   /**
    * Creates an element for insertion in the raw view for an IonType.
    *
    * @see browser/devtools/performance/modules/logic/jit.js
    * @param {IonType} ionType
    * @return {Element}
    */
-
   _createIonNode: function (ionType) {
     let node = document.createElement("span");
     node.textContent = `${ionType.site} : ${ionType.mirType}`;
     node.className = "opt-ion-type";
     return node;
   },
 
   /**
    * Creates an element for insertion in the raw view for an ObservedType.
    *
    * @see browser/devtools/performance/modules/logic/jit.js
    * @param {ObservedType} type
    * @return {Element}
    */
-
   _createObservedTypeNode: function (type) {
     let node = document.createElement("span");
     let typeNode = document.createElement("span");
 
     typeNode.textContent = `${type.keyedBy}` + (type.name ? ` → ${type.name}` : "");
     typeNode.className = "opt-type";
     node.appendChild(typeNode);
 
@@ -275,17 +299,16 @@ let OptimizationsListView = {
 
   /**
    * Creates an element for insertion in the raw view for an OptimizationAttempt.
    *
    * @see browser/devtools/performance/modules/logic/jit.js
    * @param {OptimizationAttempt} attempt
    * @return {Element}
    */
-
   _createAttemptNode: function (attempt) {
     let node = document.createElement("span");
     let strategyNode = document.createElement("span");
     let outcomeNode = document.createElement("span");
 
     strategyNode.textContent = attempt.strategy;
     strategyNode.className = "opt-strategy";
     outcomeNode.textContent = attempt.outcome;
@@ -304,17 +327,16 @@ let OptimizationsListView = {
    * Can also optionally pass in an element to modify it rather than
    * creating a new one.
    *
    * @param {String} url
    * @param {Number} line
    * @param {?Element} el
    * @return {Element}
    */
-
   _createDebuggerLinkNode: function (url, line, el) {
     let node = el || document.createElement("span");
     node.className = "opt-url";
     let fileName;
 
     if (this._isLinkableURL(url)) {
       fileName = url.slice(url.lastIndexOf("/") + 1);
       node.classList.add("debugger-link");
@@ -324,17 +346,16 @@ let OptimizationsListView = {
     fileName = fileName || url || "";
     node.textContent = fileName ? `@${fileName}` : "";
     return node;
   },
 
   /**
    * Updates the headers with the current frame's data.
    */
-
   _setHeaders: function (frameData) {
     let isMeta = frameData.isMetaCategory;
     let name = isMeta ? frameData.categoryData.label : frameData.functionName;
     let url = isMeta ? "" : frameData.url;
     let line = isMeta ? "" : frameData.line;
 
     this.$headerName.textContent = name;
     this.$headerLine.textContent = line;
@@ -346,20 +367,27 @@ let OptimizationsListView = {
 
   /**
    * Takes a string and returns a boolean indicating whether or not
    * this is a valid url for linking to the debugger.
    *
    * @param {String} url
    * @return {Boolean}
    */
-
   _isLinkableURL: function (url) {
     return url && url.indexOf &&
        (url.indexOf("http") === 0 ||
         url.indexOf("resource://") === 0 ||
         url.indexOf("file://") === 0);
   },
 
+  /**
+   * Called when `devtools.theme` changes.
+   */
+  _onThemeChanged: function (_, theme) {
+    this.graph.setTheme(theme);
+    this.graph.refresh({ force: true });
+  },
+
   toString: () => "[object OptimizationsListView]"
 };
 
 EventEmitter.decorate(OptimizationsListView);
--- a/browser/devtools/responsivedesign/responsivedesign.jsm
+++ b/browser/devtools/responsivedesign/responsivedesign.jsm
@@ -384,16 +384,17 @@ ResponsiveUI.prototype = {
    *    <toolbarbutton class="devtools-responsiveui-home-button" />
    *  </toolbar>
    * </vbox>
    */
   buildUI: function RUI_buildUI() {
     // Toolbar
     this.toolbar = this.chromeDoc.createElement("toolbar");
     this.toolbar.className = "devtools-responsiveui-toolbar";
+    this.toolbar.setAttribute("fullscreentoolbar", "true");
 
     this.menulist = this.chromeDoc.createElement("menulist");
     this.menulist.className = "devtools-responsiveui-menulist";
     this.menulist.setAttribute("editable", "true");
 
     this.menulist.addEventListener("select", this.bound_presetSelected, true);
     this.menulist.addEventListener("change", this.bound_handleManualInput, true);
 
--- a/browser/devtools/shared/widgets/MountainGraphWidget.js
+++ b/browser/devtools/shared/widgets/MountainGraphWidget.js
@@ -7,17 +7,17 @@ const { AbstractCanvasGraph, CanvasGraph
 
 const HTML_NS = "http://www.w3.org/1999/xhtml";
 
 // Bar graph constants.
 
 const GRAPH_DAMPEN_VALUES_FACTOR = 0.9;
 
 const GRAPH_BACKGROUND_COLOR = "#ddd";
-const GRAPH_STROKE_WIDTH = 2; // px
+const GRAPH_STROKE_WIDTH = 1; // px
 const GRAPH_STROKE_COLOR = "rgba(255,255,255,0.9)";
 const GRAPH_HELPER_LINES_DASH = [5]; // px
 const GRAPH_HELPER_LINES_WIDTH = 1; // px
 
 const GRAPH_CLIPHEAD_LINE_COLOR = "#fff";
 const GRAPH_SELECTION_LINE_COLOR = "#fff";
 const GRAPH_SELECTION_BACKGROUND_COLOR = "rgba(44,187,15,0.25)";
 const GRAPH_SELECTION_STRIPES_COLOR = "rgba(255,255,255,0.1)";
@@ -120,18 +120,18 @@ MountainGraphWidget.prototype = Heritage
       throw "The graph format traits are mandatory to style the data source.";
     }
     let { canvas, ctx } = this._getNamedCanvas("mountain-graph-data");
     let width = this._width;
     let height = this._height;
 
     let totalSections = this.format.length;
     let totalTicks = this._data.length;
-    let firstTick = this._data[0].delta;
-    let lastTick = this._data[totalTicks - 1].delta;
+    let firstTick = totalTicks ? this._data[0].delta : 0;
+    let lastTick = totalTicks ? this._data[totalTicks - 1].delta : 0;
 
     let duration = this.dataDuration || lastTick;
     let dataScaleX = this.dataScaleX = width / (duration - this.dataOffsetX);
     let dataScaleY = this.dataScaleY = height * this.dampenValuesFactor;
 
     // Draw the graph.
 
     let prevHeights = Array.from({ length: totalTicks }).fill(0);
--- a/browser/docs/DirectoryLinksProvider.rst
+++ b/browser/docs/DirectoryLinksProvider.rst
@@ -189,18 +189,17 @@ A suggested link has additional values:
   triggering set of sites in Firefox.
 - ``check_inadjacency`` - boolean if true prevents the suggested link from being
   shown if the new tab page is showing a site from an inadjacency list.
 - ``explanation`` - string to override the default explanation that appears
   below a Suggested Tile. %1$S is replaced by the triggering adgroup name and
   %2$S is replaced by the triggering site.
 - ``frecent_sites`` - array of strings of the sites that can trigger showing a
   Suggested Tile if the user has the site in one of the top 100 most-frecent
-  pages. Only preapproved array of strings that are hardcoded into the
-  DirectoryLinksProvider module are allowed.
+  pages.
 - ``frequency_caps`` - an object consisting of daily and total frequency caps
   that limit the number of times a Suggested Tile can be shown in the new tab
   per day and overall.
 - ``time_limits`` - an object consisting of start and end timestamps specifying
   when a Suggested Tile may start and has to stop showing in the newtab.
   The timestamp is expected in ISO_8601 format: '2014-01-10T20:00:00.000Z'
 
 The inadjacency list is packaged with Firefox as base64-encoded 1-way-hashed
--- a/browser/modules/DirectoryLinksProvider.jsm
+++ b/browser/modules/DirectoryLinksProvider.jsm
@@ -59,188 +59,16 @@ const PREF_SELECTED_LOCALE = "general.us
 const PREF_DIRECTORY_SOURCE = "browser.newtabpage.directory.source";
 
 // The preference that tells where to send click/view pings
 const PREF_DIRECTORY_PING = "browser.newtabpage.directory.ping";
 
 // The preference that tells if newtab is enhanced
 const PREF_NEWTAB_ENHANCED = "browser.newtabpage.enhanced";
 
-// Only allow explicitly approved frecent sites with display name
-const ALLOWED_FRECENT_SITES = new Map([
-  [ '1800petmeds.com,800petmeds.com,adopt.dogtime.com,adoptapet.com,akc.org,americanhumane.org,animal.discovery.com,animalconcerns.org,animalshelter.org,arcatapet.com,aspca.org,avma.org,bestfriends.org,blog.petmeds.com,buddydoghs.com,carealotpets.com,dailypuppy.com,dog.com,dogbar.com,dogbreedinfo.com,drsfostersmith.com,entirelypets.com,farmsanctuary.org,farmusa.org,freekibble.com,freekibblekat.com,healthypets.com,hsus.org,humanesociety.org,liveaquaria.com,marinedepot.com,medi-vet.com,nationalpetpharmacy.com,nsalamerica.org,nycacc.org,ohmydogsupplies.com,pet-dog-cat-supply-store.com,petcarerx.com,petco.com,petdiscounters.com,petedge.com,peteducation.com,petfinder.com,petfooddirect.com,petguys.com,petharbor.com,petmountain.com,petplanet.co.uk,pets911.com,petsmart.com,petsuppliesplus.com,puppyfind.com,revivalanimal.com,terrificpets.com,thatpetplace.com,theanimalrescuesite.com,theanimalrescuesite.greatergood.com,thefluffingtonpost.com,therainforestsite.com,vetdepot.com',
-    'pet' ],
-  [ '1aauto.com,autoblog.com,autoguide.com,autosite.com,autoweek.com,bimmerpost.com,bmwblog.com,boldride.com,caranddriver.com,carcomplaints.com,carspoon.com,cherokeeforum.com,classiccars.com,commercialtrucktrader.com,corvetteforum.com,dealerrater.com,ebizautos.com,ford-trucks.com,hemmings.com,jalopnik.com,jeepforum.com,jeepsunlimited.com,jk-forum.com,legendaryspeed.com,motorauthority.com,motortrend.com,motorwings.com,odometer.com,pirate4x4.com,purecars.com,roadandtrack.com,teslamotorsclub.com,topgear.com,topspeed.com,totalmini.com,truckpaper.com,wranglerforum.com',
-    'auto' ],
-  [ 'autobytel.com,autocheck.com,automotive.com,autonation.com,autos.aol.com,autos.msn.com,autos.yahoo.com,autotrader.autos.msn.com,autotrader.com,autotraderclassics.com,autoweb.com,car.com,carbuyingtips.com,carfax.com,cargurus.com,carmax.com,carprices.com,cars.com,cars.oodle.com,carsdirect.com,carsforsale.com,edmunds.com,hertzcarsales.com,imotors.com,intellichoice.com,internetautoguide.com,kbb.com,lemonfree.com,nada.com,nadaguides.com,thecarconnection.com,thetruthaboutcars.com,truecar.com,usedcars.com,usnews.rankingsandreviews.com',
-    'auto' ],
-  [ 'acura.com,audi.ca,audi.com,audiusa.com,automobiles.honda.com,bentleymotors.com,bmw.com,bmwusa.com,buick.com,buyatoyota.com,cadillac.com,cars.mclaren.com,chevrolet.com,choosenissan.com,chrysler.com,daimler.com,dodge.com,ferrari.com/en_us,fiskerautomotive.com,ford.com,gm.com,gmc.com,hummer.com,hyundai.com,hyundaiusa.com,infiniti.com,infinitiusa.com,jaguarusa.com,jeep.com,kia.com,kiamotors.com,lamborghini.com/en/home,landrover.com,landroverusa.com,lexus.com,lincoln.com,maserati.us,mazda.com,mazdausa.com,mbusa.com,mbusi.com,mercedes-amg.com,mercedes-benz.com,mercuryvehicles.com,miniusa.com,nissanusa.com,pontiac.com,porsche.com/usa,ramtrucks.com,rolls-roycemotorcars.com,saturn.com,scion.com,subaru.com,teslamotors.com,toyota.com,volkswagen.co.uk,volkswagen.com,volvocars.com/us,vw.com',
-    'auto' ],
-  [ '1010tires.com,4wheelparts.com,advanceautoparts.com,andysautosport.com,autoanything.com,autogeek.net,autopartsgiant.com,autopartswarehouse.com,autotrucktoys.com,autozone.com,autozoneinc.com,bavauto.com,bigotires.com,bilsteinus.com,brembo.com,car-part.com,carid.com,carparts.com,carquest.com,dinancars.com,discounttire.com,discounttiredirect.com,firestonecompleteautocare.com,goodyear.com,hrewheels,jcwhitney.com,kw-suspensions.com,momousa.com,napaonline.com,onlinetires.com,oreillyauto.com,oriellysautoparts.com,pepboys.com,repairpal.com,rockauto.com,shop.advanceautoparts.com,slickcar.com,stoptech.com,streetbeatcustoms.com,summitracing.com,tirebuyer.com,tirerack.com,tiresplus.com,tsw.com,velocitymotoring.com,wheelmax.com',
-    'auto parts' ],
-  [ 'abebooks.co.uk,abebooks.com,addall.com,alibris.com,allaboutcircuits.com,allbookstores.com,allyoucanbooks.com,answersingenesis.org,artnet.com,audiobooks.com,barnesandnoble.com,barnesandnobleinc.com,bartleby.com,betterworldbooks.com,biblio.com,biggerbooks.com,bncollege.com,bookbyte.com,bookdepository.com,bookfinder.com,bookrenter.com,booksamillion.com,booksite.com,boundless.com,brookstone.com,btol.com,calibre-ebook.com,campusbookrentals.com,casadellibro.com,cbomc.com,cengagebrain.com,chapters.indigo.ca,christianbook.com,ciscopress.com,coursesmart.com,cqpress.com,crafterschoice.com,crossings.com,cshlp.org,deseretbook.com,directtextbook.com,discountmags.com,doubledaybookclub.com,doubledaylargeprint.com,doverpublications.com,ebooks.com,ecampus.com,fellabooks.net,fictionwise.com,flatworldknowledge.com,goodreads.com,grolier.com,harpercollins.com,hayhouse.com,historybookclub.com,hpb.com,hpbmarketplace.com,interweave.com,iseeme.com,katiekazoo.com,knetbooks.com,learnoutloud.com,librarything.com,literaryguild.com,lulu.com,lww.com,macmillan.com,magazines.com,mbsdirect.net,militarybookclub.com,mypearsonstore.com,mysteryguild.com,netplaces.com,noble.com,novelguide.com,onespirit.com,oxfordjournals.org,paperbackswap.com,papy.co.jp,peachpit.com,penguin.com,penguingroup.com,pimsleur.com,powells.com,qpb.com,quepublishing.com,reviews.com,rhapsodybookclub.com,rodalestore.com,royalsocietypublishing.org,sagepub.com,scrubsmag.com,sfbc.com,simonandschuster.com,simonandschuster.net,simpletruths.com,teach12.net,textbooks.com,textbookx.com,thegoodcook.com,thriftbooks.com,tlsbooks.com,toshibabookplace.com,tumblebooks.com,urbookdownload.com,usedbooksearch.co.uk,valorebooks.com,valuemags.com,vialibri.net,wwnorton.com,zoobooks.com',
-    'literature' ],
-  [ '53.com,ally.com,bankofamerica.com,bbt.com,bnymellon.com,capitalone.com/bank/,chase.com,citi.com,citibank.com,citizensbank.com,citizensbankonline.com,creditonebank.com,everbank.com,hsbc.com,key.com,pnc.com,pncbank.com,rbs.co.uk,regions.com,sovereignbank.com,suntrust.com,tdbank.com,usaa.com,usbank.com,wachovia.com,wamu.com,wellsfargo.com,wsecu.org',
-    'banking' ],
-  [ '247wallst.com,bizjournals.com,bloomberg.com,businessweek.com,cnbc.com,cnnmoney.com,dowjones.com,easyhomesite.com,economist.com,entrepreneur.com,fastcompany.com,finance.yahoo.com,forbes.com,fortune.com,foxbusiness.com,ft.com,hbr.org,ibtimes.com,inc.com,manta.com,marketwatch.com,newsweek.com,online.wsj.com,qz.com,reuters.com,smartmoney.com,wsj.com',
-    'business news' ],
-  [ 'achievecard.com,americanexpress.com,barclaycardus.com,card.com,citicards.com,comparecards.com,creditcards.citi.com,discover.com,discovercard.com,experian.com,skylightpaycard.com,squareup.com,visa.com,visabuxx.com,visaextras.com',
-    'finance' ],
-  [ 'alliantcreditunion.org,connexuscu.org,lmcu.org,nasafcu.com,navyfcu.org,navyfederal.org,penfed.org,sccu.com,suncoastcreditunion.com,tinkerfcu.org,veridiancu.org',
-    'finance' ],
-  [ 'allbusiness.com,bankrate.com,buyersellertips.com,cboe.com,cnbcprime.com,coindesk.com,dailyfinance.com,dailyfx.com,dealbreaker.com,easierstreetdaily.com,economywatch.com,etfdailynews.com,etfdb.com,financeformulas.net,finviz.com,fool.com,forexpros.com,forexthreads.com,ftpress.com,fx-exchange.com,insidermonkey.com,investmentu.com,investopedia.com,investorjunkie.com,investors.com,kiplinger.com,minyanville.com,moneymorning.com,moneyning.com,moneysavingexpert.com,morningstar.com,nakedcapitalism.com,ncsoft.net,oilprice.com,realclearmarkets.com,rttnews.com,seekingalpha.com,silverdoctors.com,stockcharts.com,stockpickr.com,thefinancials.com,thestreet.com,wallstreetinsanity.com,wikinvest.com,xe.com,youngmoney.com',
-    'investing' ],
-  [ 'edwardjones.com,fidelity.com,goldmansachs.com,jpmorgan.com,ml.com,morganstanley.com,mymerrill.com,personal.vanguard.com,principal.com,schwab.com,schwabplan.com,scottrade.com,tdameritrade.com,troweprice.com,vanguard.com',
-    'investing' ],
-  [ '247lendinggroup.com,americanoneunsecured.com,avant.com,bestegg.com,chasestudentloans.com,eloan.com,gofundme.com,guidetolenders.com,kiva.org,lendacademy.com,lendingclub.com,lendingtree.com,lightstream.com,loanio.com,manageyourloans.com,meetearnest.com,microplace.com,netcredit.com,peer-lend.com,personalloans.com,prosper.com,salliemae.com,sofi.com,springleaf.com,uk.zopa.com,upstart.com',
-    'finance' ],
-  [ 'betterment.com,blooom.com,futureadvisor.com,kapitall.com,motifinvesting.com,personalcapital.com,wealthfront.com,wisebanyan.com',
-    'investing' ],
-  [ 'bancdebinary.com,cherrytrade.com,empireoption.net,etrade.com,firstrade.com,forex.com,interactivebrokers.com,ishares.com,optionsxpress.com,sharebuilder.com,thinkorswim.com,tradeking.com,trademonster.com,us.etrade.com,zecco.com',
-    'finance' ],
-  [ 'annualcreditreport.com,bluebird.com,credio.com,creditkarma.com,creditreport.com,cybersource.com,equifax.com,freecreditreport.com,freecreditscore.com,freedomdebtrelief.com,freescoreonline.com,mint.com,moneymappress.com,myfico.com,nationaldebtrelief.com,onesmartpenny.com,paypal.com,transunion.com,truecredit.com,upromise.com,vuebill.com,xpressbillpay.com,youneedabudget.com',
-    'personal finance' ],
-  [ 'angieslist.com,bloomberg.com,businessinsider.com,buydomains.com,domain.com,entrepreneur.com,fastcompany.com,forbes.com,fortune.com,godaddy.com,inc.com,manta.com,nytimes.com,openforum.com,register.com,salesforce.com,sba.gov,sbomag.com,shopsmall.americanexpress.com,smallbusiness.yahoo.com,squarespace.com,startupjournal.com,startupnation.com,weebly.com,wordpress.com,youngentrepreneur.com',
-    'business news' ],
-  [ '1040now.net,24hourtax.com,acttax.com,comparetaxsoftware.org,e-file.com,etax.com,free1040taxreturn.com,hrblock.com,intuit.com,irstaxdoctors.com,libertytax.com,octaxcol.com,pay1040.com,priortax.com,quickbooks.com,quickrefunds.com,rapidtax.com,refundschedule.com,taxact.com,taxactonline.com,taxefile.com,taxhead.com,taxhelptoday.me,taxsimple.org,turbotax.com',
-    'tax' ],
-  [ 'adeccousa.com,americasjobexchange.com,aoljobs.com,applicantpro.com,applicantstack.com,apply-4-jobs.com,apply2jobs.com,att.jobs,beyond.com,careerboutique.com,careerbuilder.com,careerflash.net,careerslocal.net,climber.com,coverlettersandresume.com,dice.com,diversityonecareers.com,employmentguide.com,everyjobforme.com,experteer.com,find.ly,findtherightjob.com,freelancer.com,gigats.com,glassdoor.com,governmentjobs.com,hrapply.com,hrdepartment.com,hrsmart.com,ihire.com,indeed.com,internships.com,itsmycareer.com,job-applications.com,job-hunt.org,job-interview-site.com,job.com,jobcentral.com,jobdiagnosis.com,jobhat.com,jobing.com,jobrapido.com,jobs.aol.com,jobs.net,jobsbucket.com,jobsflag.com,jobsgalore.com,jobsonline.com,jobsradar.com,jobster.com,jobtorch.com,jobungo.com,jobvite.com,juju.com,linkedin.com,livecareer.com,localjobster.com,mindtools.com,monster.com,myjobhelper.com,myperfectresume.com,payscale.com,pryor.com,quintcareers.com,randstad.com,recruitingcenter.net,resume-library.com,resume-now.com,roberthalf.com,salary.com,salaryexpert.com,simplyhired.com,smartrecruiters.com,snagajob.com,startwire.com,theladders.com,themuse.com,theresumator.com,thingamajob.com,usajobs.gov,ziprecruiter.com',
-    'career services' ],
-  [ 'americanheart.org,americanredcross.com,americares.org,catholiccharitiesusa.org,charitybuzz.com,charitynavigator.org,charitywater.org,directrelief.org,fao.org,habitat.org,hrw.org,imf.org,mskcc.org,ohchr.org,redcross.org,reliefweb.int,salvationarmyusa.org,savethechildren.org,un.org,undp.org,unep.org,unesco.org,unfpa.org,unhcr.org,unicef.org,unicefusa.org,unops.org,volunteermatch.org,wfp.org,who.int,worldbank.org',
-    'philanthropic' ],
-  [ 'academia.edu,albany.edu,american.edu,amity.edu,annauniv.edu,apus.edu,arizona.edu,ashford.edu,asu.edu,auburn.edu,austincc.edu,baylor.edu,bc.edu,berkeley.edu,brandeis.edu,brookings.edu,brown.edu,bu.edu,buffalo.edu,byu.edu,calpoly.edu,calstate.edu,caltech.edu,cam.ac.uk,cambridge.org,capella.edu,case.edu,clemson.edu,cmu.edu,colorado.edu,colostate-pueblo.edu,colostate.edu,columbia.edu,commnet.edu,cornell.edu,cpp.edu,csulb.edu,csun.edu,csus.edu,cuny.edu,cwru.edu,dartmouth.edu,depaul.edu,devry.edu,drexel.edu,du.edu,duke.edu,emory.edu,fau.edu,fcps.edu,fiu.edu,fordham.edu,fsu.edu,fullerton.edu,fullsail.edu,gatech.edu,gcu.edu,georgetown.edu,gmu.edu,gsu.edu,gwu.edu,harvard.edu,hawaii.edu,hbs.edu,iastate.edu,iit.edu,illinois.edu,indiana.edu,iu.edu,jhu.edu,k-state.edu,kent.edu,ku.edu,lamar.edu,liberty.edu,losrios.edu,lsu.edu,luc.edu,maine.edu,maricopa.edu,mass.edu,miami.edu,miamioh.edu,missouri.edu,mit.edu,mnscu.edu,monash.edu,msu.edu,mtu.edu,nau.edu,ncsu.edu,nd.edu,neu.edu,njit.edu,northeastern.edu,northwestern.edu,nova.edu,nyu.edu,odu.edu,ohio-state.edu,ohio.edu,okstate.edu,oregonstate.edu,osu.edu,ou.edu,ox.ac.uk,pdx.edu,pearson.com,phoenix.edu,pitt.edu,princeton.edu,psu.edu,purdue.edu,regis.edu,rice.edu,rit.edu,rochester.edu,rpi.edu,rutgers.edu,sc.edu,scu.edu,sdsu.edu,seattleu.edu,sfsu.edu,si.edu,sjsu.edu,snhu.edu,stanford.edu,stonybrook.edu,suny.edu,syr.edu,tamu.edu,temple.edu,towson.edu,ttu.edu,tufts.edu,ua.edu,uark.edu,ub.edu,uc.edu,uccs.edu,ucdavis.edu,ucf.edu,uchicago.edu,uci.edu,ucla.edu,uconn.edu,ucr.edu,ucsb.edu,ucsc.edu,ucsd.edu,ucsf.edu,udel.edu,udemy.com,ufl.edu,uga.edu,uh.edu,uic.edu,uillinois.edu,uiowa.edu,uiuc.edu,uky.edu,umass.edu,umb.edu,umbc.edu,umd.edu,umich.edu,umn.edu,umuc.edu,unc.edu,uncc.edu,unf.edu,uniminuto.edu,universityofcalifornia.edu,unl.edu,unlv.edu,unm.edu,unt.edu,uoc.edu,uoregon.edu,upc.edu,upenn.edu,upi.edu,uri.edu,usc.edu,usf.edu,usg.edu,usu.edu,uta.edu,utah.edu,utdallas.edu,utexas.edu,utk.edu,uvm.edu,uw.edu,uwm.edu,vanderbilt.edu,vccs.edu,vcu.edu,virginia.edu,vt.edu,waldenu.edu,washington.edu,wayne.edu,wednet.edu,wgu.edu,wisc.edu,wisconsin.edu,wm.edu,wmich.edu,wsu.edu,wustl.edu,wvu.edu,yale.edu',
-    'college' ],
-  [ 'collegeboard.com,collegeconfidential.com,collegeview.com,ecollege.com,finaid.org,find-colleges-now.com,ratemyprofessors.com,ratemyteachers.com,studentsreview.com',
-    'college' ],
-  [ 'actstudent.org,adaptedmind.com,aesoponline.com,archives.com,bibme.org,blackboard.com,bookrags.com,cengage.com,chegg.com,classdojo.com,classzone.com,cliffsnotes.com,coursecompass.com,educationconnection.com,educationdynamics.com,ets.org,familysearch.org,fastweb.com,genealogy.com,gradesaver.com,instructure.com,khanacademy.org,learn4good.com,mathway.com,mathxl.com,mcgraw-hill.com,merriam-webster.com,mheducation.com,niche.com,openstudy.com,pearsoned.com,pearsonmylabandmastering.com,pearsonsuccessnet.com,poptropica.com,powerschool.com,proprofs.com,purplemath.com,quizlet.com,readwritethink.org,renlearn.com,rhymezone.com,schoolloop.com,schoology.com,smithsonianmag.com,sparknotes.com,study.com,studyisland.com,studymode.com,synonym.com,teacherprobs.com,teacherspayteachers.com,tutorvista.com,vocabulary.com,yourschoolmatch.com',
-    'education' ],
-  [ 'browardschools.com,k12.ca.us,k12.fl.us,k12.ga.us,k12.in.us,k12.mn.us,k12.mo.us,k12.nc.us,k12.nj.us,k12.oh.us,k12.va.us,k12.wi.us',
-    'education' ],
-  [ 'coolmath-games.com,coolmath.com,coolmath4kids.com,coolquiz.com,funbrain.com,funtrivia.com,gamesforthebrain.com,girlsgogames.com,hoodamath.com,lumosity.com,math.com,mathsisfun.com,trivia.com,wizard101.com',
-    'learning games' ],
-  [ 'askmen.com,boredomtherapy.com,buzzfeed.com,complex.com,dailymotion.com,elitedaily.com,gawker.com,howstuffworks.com,instagram.com,madamenoire.com,polygon.com,ranker.com,rollingstone.com,ted.com,theblaze.com,thechive.com,thecrux.com,thedailybeast.com,thoughtcatalog.com,uproxx.com,upworthy.com,zergnet.com',
-    'entertainment' ],
-  [ '11points.com,7gid.com,adultswim.com,break.com,cheezburger.com,collegehumor.com,cracked.com,dailydawdle.com,damnlol.com,dumb.com,dumblaws.com,ebaumsworld.com,explosm.net,failblog.org,fun-gallery.com,funnygig.com,funnyjunk.com,funnymama.com,funnyordie.com,funnytear.com,funplus.com,glassgiant.com,goingviralposts.com,gorillamask.net,i-am-bored.com,icanhascheezburger.com,ifunny.com,imjussayin.co,inherentlyfunny.com,izismile.com,jokes.com,keenspot.com,knowyourmeme.com,laughstub.com,memebase.com,mememaker.net,metacafe.com,mylol.com,picslist.com,punoftheday.com,queendom.com,rajnikantvscidjokes.in,regretfulmorning.com,shareonfb.com,somethingawful.com,stupidvideos.com,superfunnyimages.com,thedailywh.at,theonion.com,tosh.comedycentral.com,uberhumor.com,welltimedphotos.com',
-    'humor' ],
-  [ 'air.tv,amctheatres.com,boxofficemojo.com,cinapalace.com,cinaplay.com,cinemablend.com,cinemark.com,cinematical.com,collider.com,comicbookmovie.com,comingsoon.net,crackle.com,denofgeek.us,dreamworks.com,empireonline.com,enstarz.com,fandango.com,filmschoolrejects.com,flickeringmyth.com,flixster.com,fullmovie2k.com,g2g.fm,galleryhip.com,hollywood.com,hollywoodreporter.com,iglomovies.com,imdb.com,indiewire.com,instantwatcher.com,joblo.com,kickass.to,kissdrama.net,marcustheatres.com,megashare9.com,moviefone.com,movieinsider.com,moviemistakes.com,moviepilot.com,movierulz.com,movies.com,movies.yahoo.com,movieseum.com,movietickets.com,movieweb.com,mrmovietimes.com,mymovieshub.com,netflix.com,onlinemovies.pro,pelis24.com,projectfreetv.ch,redbox.com,regmovies.com,repelis.tv,rogerebert.suntimes.com,ropeofsilicon.com,rottentomatoes.com,sidereel.com,slashfilm.com,solarmovie.is,starwars.com,superherohype.com,tcm.com,twomovies.us,variety.com,vimeo.com,viooz.ac,warnerbros.com,watchfree.to,wbredirect.com,youtubeonfire.com,zmovie.tw,zumvo.com',
-    'movie' ],
-  [ '1079ishot.com,2dopeboyz.com,8tracks.com,acdc.com,allaccess.com,allhiphop.com,allmusic.com,audiofanzine.com,audiomack.com,azlyrics.com,baeblemusic.com,bandsintown.com,billboard.com,brooklynvegan.com,brunomars.com,buzznet.com,cmt.com,coachella.com,consequenceofsound.net,contactmusic.com,countryweekly.com,dangerousminds.net,datpiff.com,ddotomen.com,diffuser.fm,directlyrics.com,djbooth.net,eventful.com,fireflyfestival.com,genius.com,guitartricks.com,harmony-central.com,hiphopdx.com,hiphopearly.com,hypem.com,idolator.com,iheart.com,jambase.com,kanyetothe.com,knue.com,lamusica.com,last.fm,livemixtapes.com,loudwire.com,lyricinterpretations.com,lyrics.net,lyricsbox.com,lyricsmania.com,lyricsmode.com,metal-archives.com,metrolyrics.com,mp3.com,mtv.co.uk,myspace.com,newnownext.com,noisetrade.com,okayplayer.com,pandora.com,phish.com,pigeonsandplanes.com,pitchfork.com,popcrush.com,radio.com,rap-up.com,rdio.com,reverbnation.com,revolvermag.com,rockhall.com,saavn.com,songlyrics.com,soundcloud.com,spin.com,spinrilla.com,spotify.com,stereogum.com,stereotude.com,talkbass.com,tasteofcountry.com,thebacklot.com,theboombox.com,theboot.com,thissongissick.com,tunesbaby.com,ultimate-guitar.com,ultimateclassicrock.com,vevo.com,vibe.com,vladtv.com,whosampled.com,wikibit.me,worldstarhiphop.com,wyrk.com,xxlmag.com',
-    'music' ],
-  [ 'aceshowbiz.com,aintitcoolnews.com,allkpop.com,askkissy.com,atraf.co.il,audioboom.com,beamly.com,beyondhollywood.com,blastr.com,blippitt.com,bollywoodlife.com,bossip.com,buzzlamp.com,buzzsugar.com,cambio.com,celebdirtylaundry.com,celebrity-gossip.net,celebuzz.com,chisms.net,comicsalliance.com,concertboom.com,crushable.com,cultbox.co.uk,dailyentertainmentnews.com,dayscafe.com,deadline.com,deathandtaxesmag.com,diaryofahollywoodstreetking.com,digitalspy.com,dlisted.com,egotastic.com,empirenews.net,enelbrasero.com,eonline.com,etonline.com,ew.com,extratv.com,facade.com,famousfix.com,fanaru.com,fanpop.com,fansshare.com,fhm.com,geektyrant.com,glamourpage.com,gossipcenter.com,gossipcop.com,heatworld.com,hlntv.com,hollyscoop.com,hollywoodlife.com,hollywoodtuna.com,hypable.com,infotransfer.net,insideedition.com,interaksyon.com,jezebel.com,justjared.buzznet.com,justjared.com,justjaredjr.com,komando.com,koreaboo.com,laineygossip.com,maxgo.com,maxim.com,maxviral.com,mediatakeout.com,mosthappy.com,moviestalk.com,my.ology.com,nationalenquirer.com,necolebitchie.com,ngoisao.net,nofilmschool.com,nolocreo.com,octane.tv,okmagazine.com,ouchpress.com,people.com,peopleenespanol.com,perezhilton.com,pinkisthenewblog.com,platotv.tv,playbill.com,playbillvault.com,playgroundmag.net,popsugar.com,purepeople.com,radaronline.com,rantchic.com,realitytea.com,reshareworthy.com,rinkworks.com,ripbird.com,sara-freder.com,screencrush.com,screenjunkies.com,soapcentral.com,soapoperadigest.com,sobadsogood.com,socialitelife.com,sourcefednews.com,splitsider.com,starcasm.net,starmagazine.com,starpulse.com,straightfromthea.com,stupiddope.com,tbn.org,theawesomedaily.com,theawl.com,thefrisky.com,thefw.com,thehollywoodgossip.com,theresacaputo.com,thesuperficial.com,thezooom.com,tmz.com,tvnotas.com.mx,twanatells.com,usmagazine.com,vanityfair.com,vanswarpedtour.com,vietgiaitri.com,viral.buzz,vulture.com,wakavision.com,worthytales.net,wwtdd.com',
-    'entertainment news' ],
-  [ 'abc.go.com,abcfamily.go.com,abclocal.go.com,accesshollywood.com,aetv.com,amctv.com,animalplanet.com,bbcamerica.com,bet.com,biography.com,bravotv.com,cartoonnetwork.com,cbn.com,cbs.com,cc.com,centrictv.com,cinemax.com,comedycentral.com,ctv.ca,cwtv.com,daytondailynews.com,drphil.com,dsc.discovery.com,fox.com,fox23.com,fox4news.com,fxnetworks.com,hbo.com,history.com,hulu.com,ifc.com,iqiyi.com,jeopardy.com,kfor.com,logotv.com,mtv.com,myfoxchicago.com,myfoxdc.com,myfoxmemphis.com,myfoxphilly.com,nbc.com,nbcchicago.com,oxygen.com,pbs.org,pbskids.org,rachaelrayshow.com,rtve.es,scifi.com,sho.com,showtimeanytime.com,spike.com,sundance.tv,syfy.com,tbs.com,teamcoco.com,telemundo.com,thedoctorstv.com,titantv.com,tlc.com,tlc.discovery.com,tnt.tv,tntdrama.com,tv.com,tvguide.com,tvseriesfinale.com,usanetwork.com,uvidi.com,vh1.com,viki.com,watchcartoononline.com,watchseries-online.ch,wetv.com,wheeloffortune.com,whio.com,wnep.com,wral.com,wtvr.com,xfinitytv.com,yidio.com',
-    'TV show' ],
-  [ 'americanhiking.org,appalachiantrail.org,canadiangeographic.ca,defenders.org,discovermagazine.com,discoveroutdoors.com,dsc.discovery.com,earthtouchnews.com,edf.org,epa.gov,ewg.org,fishngame.org,foe.org,fs.fed.us,geography.about.com,landtrustalliance.org,nationalgeographic.com,nature.com,nrdc.org,nwf.org,outdoorchannel.com,outdoors.org,seedmagazine.com,trcp.org,usda.gov,worldwildlife.org',
-    'environment' ],
-  [ 'abbreviations.com,abcmouse.com,abcya.com,achieve3000.com,ancestry.com,animaljam.com,babble.com,babycenter.com,babynamespedia.com,behindthename.com,bestmomstv.com,brainyquote.com,cafemom.com,citationmachine.net,clubpenguin.com,cutemunchkins.com,discoveryeducation.com,disney.com,easybib.com,education.com,enotes.com,everydayfamily.com,familyeducation.com,gamefaqs.com,greatschools.org,hrw.com,imvu.com,infoplease.com,itsybitsysteps.com,justmommies.com,k12.com,kidsactivitiesblog.com,mathwarehouse.com,mom.me,mom365.com,mommyshorts.com,momswhothink.com,momtastic.com,monsterhigh.com,myheritage.com,nameberry.com,nickmom.com,pampers.com,parenthood.com,parenting.com,parenting.ivillage.com,parents.com,parentsociety.com,raz-kids.com,regentsprep.org,scarymommy.com,scholastic.com,shmoop.com,softschools.com,spanishdict.com,starfall.com,thebump.com,thefreedictionary.com,thenest.com,thinkbabynames.com,todaysparent.com,webkinz.com,whattoexpect.com',
-    'family' ],
-  [ 'americangirl.com,barbie.com,barbiecollectibles.com,cartoonnetworkshop.com,chuckecheese.com,coloring.ws,disney.co.uk,disney.com.au,disney.go.com,disney.in,disneychannel-asia.com,disneyinternational.com,disneyjunior.com,disneylatino.com,disneyme.com,dltk-kids.com,dressupone.com,fantage.com,funbrainjr.com,hotwheels.com,icarly.com,kiwicrate.com,marvel.com,marvelkids.com,mattelgames.com,maxsteel.com,monkeyquest.com,nick-asia.com,nick.co.uk,nick.com,nick.tv,nickelodeon.com.au,nickjr.co.uk,nickjr.com,ninjakiwi.com,notdoppler.com,powerrangers.com,sciencekids.co.nz,search.disney.com,seventeen.com,teennick.com,theslap.com,yepi.com',
-    'family' ],
-  [ 'alabama.gov,archives.gov,bls.gov,ca.gov,cancer.gov,cdc.gov,census.gov,cia.gov,cms.gov,commerce.gov,ct.gov,delaware.gov,dhs.gov,doi.gov,dol.gov,dot.gov,ed.gov,eftps.gov,epa.gov,fbi.gov,fda.gov,fema.gov,flhsmv.gov,ftc.gov,ga.gov,georgia.gov,gpo.gov,hhs.gov,house.gov,hud.gov,illinois.gov,in.gov,irs.gov,justice.gov,ky.gov,loc.gov,louisiana.gov,maryland.gov,mass.gov,michigan.gov,mo.gov,nih.gov,nj.gov,nps.gov,ny.gov,nyc.gov,ohio.gov,ok.gov,opm.gov,oregon.gov,pa.gov,recreation.gov,sba.gov,sc.gov,sec.gov,senate.gov,state.fl.us,state.gov,state.il.us,state.ma.us,state.mi.us,state.mn.us,state.nc.us,state.ny.us,state.oh.us,state.pa.us,studentloans.gov,telldc.com,texas.gov,tn.gov,travel.state.gov,tsa.gov,usa.gov,uscis.gov,uscourts.gov,usda.gov,usdoj.gov,usembassy.gov,usgs.gov,utah.gov,va.gov,virginia.gov,wa.gov,whitehouse.gov,wi.gov,wisconsin.gov',
-    'government' ],
-  [ 'beachbody.com,bodybuilding.com,caloriecount.com,extremefitness.com,fitbit.com,fitday.com,fitnessmagazine.com,fitnessonline.com,fitwatch.com,livestrong.com,maxworkouts.com,mensfitness.com,menshealth.com,muscleandfitness.com,muscleandfitnesshers.com,myfitnesspal.com,shape.com,womenshealthmag.com',
-    'health & fitness' ],
-  [ 'activebeat.com,alliancehealth.com,beyonddiet.com,caring.com,complete-health-and-happiness.com,diabeticconnect.com,doctoroz.com,everydayhealth.com,followmyhealth.com,greatist.com,health.com,healthboards.com,healthcaresource.com,healthgrades.com,healthguru.com,healthination.com,healthtap.com,helpguide.org,iherb.com,kidshealth.org,lifescript.com,lovelivehealth.com,medicaldaily.com,mercola.com,perfectorigins.com,prevention.com,qualityhealth.com,questdiagnostics.com,realself.com,sharecare.com,sparkpeople.com,spryliving.com,steadyhealth.com,symptomfind.com,ucomparehealthcare.com,vitals.com,webmd.com,weightwatchers.com,wellness.com,zocdoc.com',
-    'health & wellness' ],
-  [ 'aetna.com,anthem.com,athenahealth.com,bcbs.com,bluecrossca.com,cigna.benefitnation.net,cigna.com,cigna.healthplan.com,ehealthcare.com,ehealthinsurance.com,empireblue.com,goldenrule.com,healthcare.gov,healthnet.com,humana-medicare.com,humana.com,kaiserpermanente.org,metlife.com,my.cigna.com,mybenefits.metlife.com,myuhc.com,uhc.com,unitedhealthcareonline.com,walterrayholt.com',
-    'health insurance' ],
-  [ 'aafp.org,americanheart.org,apa.org,cancer.org,cancercenter.com,caremark.com,clevelandclinic.org,diabetesfree.org,drugs.com,emedicinehealth.com,express-scripts.com,familydoctor.org,goodrx.com,healthcaremagic.com,healthfinder.gov,healthline.com,ieee.org,intelihealth.com,labcorp.com,livecellresearch.com,mayoclinic.com,mayoclinic.org,md.com,medcohealth.com,medhelp.org,medicalnewstoday.com,medicare.gov,medicaresupplement.com,medicinenet.com,medscape.com,memorialhermann.org,merckmanuals.com,patient.co.uk,psychcentral.com,psychology.org,psychologytoday.com,rightdiagnosis.com,rxlist.com,socialpsychology.org,spine-health.com,who.int',
-    'health & wellness' ],
-  [ 'aaa.com,aig.com,allianz-assistance.com,allstate.com,allstateagencies.com,amfam.com,amica.com,autoquotesdirect.com,esurance.com,farmers.com,farmersagent.com,geico.com,general-car-insurance-quotes.net,insurance.com,libertymutual.com,libertymutualgroup.com,mercuryinsurance.com,nationwide.com,progressive.com,progressiveagent.com,progressiveinsurance.com,provide-insurance.com,safeco.com,statefarm.com,thehartford.com,travelers.com,usaa.com',
-    'insurance' ],
-  [ '101cookbooks.com,allrecipes.com,bettycrocker.com,bonappetit.com,chocolateandzucchini.com,chow.com,chowhound.chow.com,cookinglight.com,cooks.com,cooksillustrated.com,cooksrecipes.com,delish.com,eater.com,eatingwell.com,epicurious.com,food.com,foodandwine.com,foodgawker.com,foodnetwork.com,gourmet.com,grouprecipes.com,homemaderecipes.co,iheartnaptime.net,kraftfoods.com,kraftrecipes.com,myrecipes.com,opentable.com,pillsbury.com,recipe.com,recipesource.com,recipezaar.com,saveur.com,seriouseats.com,simplyrecipes.com,smittenkitchen.com,southernliving.com,supercook.com,tasteofhome.com,tastespotting.com,technicpack.net,thekitchn.com,urbanspoon.com,wonderhowto.com,yelp.com,yummly.com,zagat.com',
-    'food & lifestyle' ],
-  [ 'aarp.org,allure.com,bustle.com,cosmopolitan.com,diply.com,eharmony.com,elle.com,glamour.com,grandascent.com,harpersbazaar.com,hellogiggles.com,instructables.com,instyle.com,marieclaire.com,match.com,mindbodygreen.com,nymag.com,okcupid.com,petco.com,photobucket.com,pof.com,rantlifestyle.com,redbookmag.com,reddit.com,sheknows.com,style.com,stylebistro.com,theilovedogssite.com,theknot.com,thescene.com,thrillist.com,vogue.com,womansday.com,youngcons.com,yourdictionary.com',
-    'lifestyle' ],
-  [ 'apartmentratings.com,apartmenttherapy.com,architectmagazine.com,architecturaldigest.com,askthebuilder.com,bhg.com,bobvila.com,countryhome.com,countryliving.com,davesgarden.com,decor8blog.com,decorpad.com,diycozyhome.com,diyideas.com,diynetwork.com,doityourself.com,domainehome.com,dwell.com,elledecor.com,familyhandyman.com,frontdoor.com,gardenguides.com,gardenweb.com,getdecorating.com,goodhousekeeping.com,hgtv.com,hgtvgardens.com,hobbylobby.com,homeadvisor.com,homerepair.about.com,hometalk.com,hometime.com,hometips.com,housebeautiful.com,houzz.com,inhabitat.com,lonny.com,makingitlovely.com,marthastewart.com,michaels.com,myhomeideas.com,realsimple.com,remodelista.com,shanty-2-chic.com,styleathome.com,thehandmadehome.net,thehealthyhomeeconomist.com,thisoldhouse.com,traditionalhome.com,trulia.com,younghouselove.com',
-    'home & lifestyle' ],
-  [ '10best.com,10tv.com,11alive.com,19actionnews.com,9news.com,abcnews.com,abcnews.go.com,adweek.com,ajc.com,anchorfree.us,arcamax.com,austin360.com,azcentral.com,bbc.co.uk,boston.com,bostonglobe.com,capecodonline.com,cbsnews.com,cheatsheet.com,chicagotribune.com,chron.com,citylab.com,cnn.com,csmonitor.com,dailyitem.com,dailymail.co.uk,dallasnews.com,eleconomista.es,examiner.com,fastcolabs.com,fivethirtyeight.com,foursquare.com,foxcarolina.com,foxnews.com,globalnews.ca,greatergood.com,guardian.co.uk,historynet.com,huffingtonpost.co.uk,huffingtonpost.com,ijreview.com,independent.co.uk,journal-news.com,kare11.com,kcra.com,kctv5.com,kgw.com,khou.com,king5.com,kirotv.com,kitv.com,kmbc.com,knoxnews.com,kpho.com,kptv.com,kron4.com,ksdk.com,ksl.com,ktvb.com,kvue.com,kxan.com,latimes.com,lifehack.org,littlethings.com,mailtribune.com,mic.com,mirror.co.uk,msn.com,msnbc.com,msnbc.msn.com,myfoxboston.com,nbcnews.com,nbcnewyork.com,newburyportnews.com,news.bbc.co.uk,news.yahoo.com,news12.com,newschannel10.com,newsday.com,newser.com,newsmax.com,newyorker.com,nj.com,nj1015.com,npr.org,nydailynews.com,nypost.com,nytimes.com,palmbeachpost.com,patch.com,philly.com,phys.org,poconorecord.com,prnewswire.com,rare.us,realclearworld.com,record-eagle.com,richmond.com,rt.com,salemnews.com,salon.com,sfgate.com,slate.com,statesman.com,suntimes.com,takepart.com,telegraph.co.uk,theatlantic.com,thedailystar.com,theguardian.com,theroot.com,theverge.com,time.com,timesonline.co.uk,topix.com,usatoday.com,usatoday30.usatoday.com,usnews.com,vice.com,vox.com,wane.com,washingtonpost.com,washingtontimes.com,wave3.com,wavy.com,wbaltv.com,wbir.com,wcnc.com,wdbj7.com,westernjournalism.com,wfaa.com,wfsb.com,wftv.com,wgal.com,wishtv.com,wisn.com,wistv.com,wivb.com,wkyc.com,wlwt.com,wmur.com,woodtv.com,wpxi.com,wsbtv.com,wsfa.com,wsmv.com,wsoctv.com,wthr.com,wtnh.com,wtsp.com,wwltv.com,wyff4.com,wzzm13.com',
-    'news' ],
-  [ 'aei.org,breitbart.com,conservativetalknow.com,conservativetribune.com,dailykos.com,ddo.com,drudgereport.com,dscc.org,foreignpolicy.com,franklinprosperityreport.com,freedomworks.org,macleans.ca,mediamatters.org,militarytimes.com,nationaljournal.com,nationalreview.com,politicalwire.com,politico.com,pressrepublican.com,qpolitical.com,realclearpolitics.com,talkingpointsmemo.com,thehill.com,thenation.com,thinkprogress.org,tnr.com,worldoftanks.eu',
-    'news' ],
-  [ 'americanscientist.org,discovermagazine.com,iflscience.com,livescience.com,nasa.gov,nationalgeographic.com,nature.com,newscientist.com,popsci.com,sciencedaily.com,sciencemag.org,sciencenews.org,scientificamerican.com,space.com,zmescience.com',
-    'science' ],
-  [ 'accuweather.com,intellicast.com,noaa.gov,ssa.gov,theweathernetwork.com,weather.com,weather.gov,weather.yahoo.com,weatherbug.com,weatherunderground.com,weatherzone.com.au,wunderground.com,www.weather.com',
-    'weather' ],
-  [ 'bhphotovideo.com,bigfolio.com,bigstockphoto.com,cameralabs.com,canonrumors.com,canstockphoto.com,digitalcamerareview.com,dpreview.com,expertphotography.com,gettyimages.com,icp.org,imaging-resource.com,intothedarkroom.com,istockphoto.com,nikonusa.com,photos.com,shutterstock.com,slrgear.com,the-digital-picture.com,thephotoargus.com,usa.canon.com,whatdigitalcamera.com,zenfolio.com',
-    'photography' ],
-  [ 'abercrombie.com,ae.com,aeropostale.com,anthropologie.com,bananarepublic.com,buycostumes.com,chadwicks.com,express.com,forever21.com,freepeople.com,hm.com,hollisterco.com,jcrew.com,jessicalondon.com,kingsizemen.com,lordandtaylor.com,lulus.com,metrostyle.com,nomorerack.com,oldnavy.com,oldnavy.gap.com,polyvore.com,rackroomshoes.com,ralphlauren.com,refinery29.com,roamans.com,sammydress.com,shop.nordstrom.com,shopbop.com,topshop.com,urbanoutfitters.com,victoriassecret.com,wetseal.com,womanwithin.com',
-    'shopping' ],
-  [ 'bizrate.com,compare99.com,coupons.com,dealtime.com,epinions.com,junglee.com,kijiji.ca,pricegrabber.com,pronto.com,redplum.com,retailmenot.com,shopping.com,shopzilla.com,smarter.com,valpak.com',
-    'shopping' ],
-  [ '123greetings.com,1800baskets.com,1800flowers.com,americangreetings.com,birthdayexpress.com,bluemountain.com,e-cards.com,egreetings.com,florists.com,ftd.com,gifts.com,groupcard.com,harryanddavid.com,hipstercards.com,kabloom.com,personalcreations.com,proflowers.com,redenvelope.com,someecards.com',
-    'flowers & gifts' ],
-  [ '6pm.com,alibaba.com,aliexpress.com,amazon.co.uk,amazon.com,asos.com,bathandbodyworks.com,bloomingdales.com,bradsdeals.com,buy.com,cafepress.com,circuitcity.com,clarkhoward.com,consumeraffairs.com,costco.com,cvs.com,dhgate.com,diapers.com,dillards.com,ebates.com,ebay.com,ebaystores.com,etsy.com,fingerhut.com,groupon.com,hsn.com,jcpenney.com,kmart.com,kohls.com,kroger.com,lowes.com,macys.com,menards.com,nextag.com,nordstrom.com,orientaltrading.com,overstock.com,qvc.com,racked.com,rewardsnetwork.com,samsclub.com,sears.com,sephora.com,shopathome.com,shopify.com,shopstyle.com,slickdeals.net,soap.com,staples.com,target.com,toptenreviews.com,vistaprint.com,walgreens.com,walmart.ca,walmart.com,wayfair.com,zappos.com,zazzle.com,zulily.com',
-    'shopping' ],
-  [ 'acehardware.com,ashleyfurniture.com,bedbathandbeyond.com,brylanehome.com,casa.com,cb2.com,crateandbarrel.com,dwr.com,ethanallen.com,furniture.com,harborfreight.com,hayneedle.com,homedecorators.com,homedepot.com,ikea.com,info.ikea-usa.com,landofnod.com,pier1.com,plowhearth.com,potterybarn.com,restorationhardware.com,roomandboard.com,westelm.com,williams-sonoma.com',
-    'home shopping' ],
-  [ 'alexandermcqueen.com,bergdorfgoodman.com,bottegaveneta.com,burberry-bluelabel.com,burberry.com,chanel.com,christianlouboutin.com,coach.com,diesel.com,dior.com,dolcegabbana.com,dolcegabbana.it,fendi.com,ferragamo.com,giorgioarmani.com,givenchy.com,gucci.com,guess.com,hermes.com,jeanpaulgaultier.com,jimmychoo.com,juicycouture.com,katespade.com,louisvuitton.com,manoloblahnik.com,marcjacobs.com,neimanmarcus.com,net-a-porter.com,paulsmith.co.uk,prada.com,robertocavalli.com,saksfifthavenue.com,toryburch.com,valentino.com,versace.com,vuitton.com,ysl.com,yslbeautyus.com',
-    'luxury shopping' ],
-  [ 'bargainseatsonline.com,livenation.com,stubhub.com,ticketfly.com,ticketliquidator.com,ticketmaster.com,tickets.com,ticketsnow.com,ticketweb.com,vividseats.com',
-    'events & tickets' ],
-  [ 'babiesrus.com,brothers-brick.com,etoys.com,fao.com,fisher-price.com,hasbro.com,hasbrotoyshop.com,lego.com,legoland.com,mattel.com,toys.com,toysrus.com,toystogrowon.com,toywiz.com',
-    'toys & games' ],
-  [ 'challengegames.nfl.com,fantasy.nfl.com,fantasyfootballblog.net,fantasyfootballcafe.com,fantasyfootballnerd.com,fantasysmarts.com,fftoday.com,fftoolbox.com,football.fantasysports.yahoo.com,footballsfuture.com,mrfootball.com,officefootballpool.com,thehuddle.com',
-    'fantasy football' ],
-  [ 'dailyjoust.com,draftday.com,draftking.com,draftkings.com,draftstreet.com,fanduel.com,realmoneyfantasyleagues.com,thedailyaudible.com',
-    'fantasy sports' ],
-  [ 'cdmsports.com,fanball.com,fantasyguru.com,fantasynews.cbssports.com,fantasyquestions.com,fantasyrundown.com,fantasysharks.com,fantasysports.yahoo.com,fantazzle.com,fantrax.com,fleaflicker.com,junkyardjake.com,kffl.com,mockdraftcentral.com,myfantasyleague.com,rototimes.com,rotowire.com,rotoworld.com,rtsports.com,whatifsports.com',
-    'fantasy sports' ],
-  [ 'football.about.com,football.com,footballoutsiders.com,nationalfootballpost.com,nflalumni.org,nflpa.com,nfltraderumors.co,profootballhof.com,profootballtalk.com,profootballtalk.nbcsports.com,profootballweekly.com',
-    'football' ],
-  [ '49ers.com,atlantafalcons.com,azcardinals.com,baltimoreravens.com,bengals.com,buccaneers.com,buffalobills.com,chargers.com,chicagobears.com,clevelandbrowns.com,colts.com,dallascowboys.com,denverbroncos.com,detroitlions.com,giants.com,houstontexans.com,jaguars.com,kcchiefs.com,miamidolphins.com,neworleanssaints.com,newyorkjets.com,packers.com,panthers.com,patriots.com,philadelphiaeagles.com,raiders.com,redskins.com,seahawks.com,steelers.com,stlouisrams.com,titansonline.com,vikings.com',
-    'football' ],
-  [ 'baseball-reference.com,baseballamerica.com,europeantour.com,golf.com,golfdigest.com,lpga.com,milb.com,minorleagueball.com,mlb.com,mlb.mlb.com,nascar.com,nba.com,ncaa.com,nhl.com,pga.com,pgatour.com,prowrestling.com,surfermag.com,surfline.com,surfshot.com,thehockeynews.com,tsn.com,ufc.com,worldgolfchampionships.com,wwe.com',
-    'sports' ],
-  [ '247sports.com,active.com,armslist.com,basketball-reference.com,bigten.org,bleacherreport.com,bleedinggreennation.com,bloodyelbow.com,cagesideseats.com,cbssports.com,cinesport.com,collegespun.com,cricbuzz.com,crictime.com,csnphilly.com,csnwashington.com,cstv.com,eastbay.com,espn.com,espn.go.com,espncricinfo.com,espnfc.com,espnfc.us,espnradio.com,eteamz.com,fanatics.com,fansided.com,fbschedules.com,fieldandstream.com,flightclub.com,foxsports.com,givemesport.com,goduke.com,goheels.com,golfchannel.com,golfnow.com,grantland.com,grindtv.com,hoopshype.com,icc-cricket.com,imleagues.com,kentuckysportsradio.com,larrybrownsports.com,leaguelineup.com,maxpreps.com,mlbtraderumors.com,mmafighting.com,mmajunkie.com,mmamania.com,msn.foxsports.com,myscore.com,nbcsports.com,nbcsports.msnbc.com,nesn.com,rantsports.com,realclearsports.com,reserveamerica.com,rivals.com,runnersworld.com,sbnation.com,scout.com,sherdog.com,si.com,speedsociety.com,sportingnews.com,sports.yahoo.com,sportsillustrated.cnn.com,sportsmanias.com,sportsmonster.us,sportsonearth.com,stack.com,teamworkonline.com,thebiglead.com,thescore.com,trails.com,triblive.com,upickem.net,usatodayhss.com,watchcric.net,yardbarker.com',
-    'sports news' ],
-  [ 'adidas.com,backcountry.com,backcountrygear.com,cabelas.com,champssports.com,competitivecyclist.com,dickssportinggoods.com,finishline.com,footlocker.com,ladyfootlocker.com,modells.com,motosport.com,mountaingear.com,newbalance.com,nike.com,patagonia.com,puma.com,reebok.com,sportsmansguide.com,steepandcheap.com,tgw.com,thenorthface.com',
-    'sports & outdoor goods' ],
-  [ 'airdroid.com,android-developers.blogspot.com,android.com,androidandme.com,androidapplications.com,androidapps.com,androidauthority.com,androidcommunity.com,androidfilehost.com,androidforums.com,androidguys.com,androidheadlines.com,androidpit.com,androidspin.com,androidtapp.com,androinica.com,droid-life.com,droidforums.net,droidviews.com,droidxforums.com,forum.xda-developers.com,phandroid.com,play.google.com,shopandroid.com,talkandroid.com,theandroidsoul.com,thedroidguy.com,videodroid.org',
-    'technology' ],
-  [ '9to5mac.com,appadvice.com,apple.com,appleinsider.com,appleturns.com,appsafari.com,cultofmac.com,everymac.com,insanelymac.com,iphoneunlockspot.com,isource.com,itunes.apple.com,lowendmac.com,mac-forums.com,macdailynews.com,macenstein.com,macgasm.net,macintouch.com,maclife.com,macnews.com,macnn.com,macobserver.com,macosx.com,macpaw.com,macrumors.com,macsales.com,macstories.net,macupdate.com,macuser.co.uk,macworld.co.uk,macworld.com,maxiapple.com,spymac.com,theapplelounge.com',
-    'technology' ],
-  [ 'adobe.com,asus.com,avast.com,data.com,formstack.com,gboxapp.com,gotomeeting.com,hp.com,htc.com,ibm.com,intel.com,java.com,logme.in,mcafee.com,mcafeesecure.com,microsoftstore.com,norton.com,office.com,office365.com,opera.com,oracle.com,proboards.com,samsung.com,sourceforge.net,squarespace.com,techtarget.com,ultipro.com,uniblue.com,web.com,winzip.com',
-    'technology' ],
-  [ '3dprint.com,4sysops.com,access-programmers.co.uk,accountingweb.com,afterdawn.com,akihabaranews.com,appsrumors.com,avg.com,belkin.com,besttechinfo.com,betanews.com,botcrawl.com,breakingmuscle.com,cheap-phones.com,chip.de,chip.eu,citeworld.com,cleanpcremove.com,commentcamarche.net,computer.org,computerhope.com,computershopper.com,computerweekly.com,contextures.com,coolest-gadgets.com,csoonline.com,daniweb.com,datacenterknowledge.com,ddj.com,devicemag.com,digitaltrends.com,dottech.org,dslreports.com,edugeek.net,eetimes.com,epic.com,eurekalert.org,eweek.com,experts-exchange.com,fosshub.com,freesoftwaremagazine.com,funkyspacemonkey.com,futuremark.com,gadgetreview.com,gizmodo.co.uk,globalsecurity.org,gunup.com,guru3d.com,head-fi.org,hexus.net,hothardware.com,howtoforge.com,idg.com.au,idownloadblog.com,ihackmyi.com,ilounge.com,infomine.com,intellireview.com,intomobile.com,iphonehacks.com,ismashphone.com,it168.com,itechpost.com,itpro.co.uk,jailbreaknation.com,laptoping.com,lightreading.com,malwaretips.com,mediaroom.com,mobilemag.com,modmyi.com,modmymobile.com,mophie.com,mozillazine.org,neoseeker.com,neowin.net,newsoxy.com,nextadvisor.com,notebookcheck.com,notebookreview.com,nvidia.com,orafaq.com,osdir.com,osxdaily.com,our-hometown.com,pchome.net,pconline.com.cn,pcpop.com,pcpro.co.uk,pcreview.co.uk,pcrisk.com,pcwelt.de,phonerebel.com,phonescoop.com,physorg.com,pocket-lint.com,post-theory.com,prnewswire.co.uk,programming4.us,quickpwn.com,redmondpie.com,redorbit.com,safer-networking.org,scientificblogging.com,sciverse.com,servicerow.com,sinfuliphone.com,singularityhub.com,slashgear.com,softonic.com,softonic.com.br,softonic.fr,sophos.com,sparkfun.com,speedguide.net,stuff.tv,symantec.com,taplikahome.com,techdailynews.net,techeblog.com,techie-buzz.com,techniqueworld.com,technobuffalo.com,technologyreview.com,technologytell.com,techpowerup.com,techpp.com,techradar.com,techshout.com,techworld.com,techworld.com.au,techworldtweets.com,telecomfile.com,tgdaily.com,theinquirer.net,thenextweb.com,theregister.co.uk,thermofisher.com,thewindowsclub.com,tomsitpro.com,trustedreviews.com,tuaw.com,tweaktown.com,unwiredview.com,wccftech.com,webmonkey.com,webpronews.com,windows7codecs.com,windowscentral.com,windowsitpro.com,windowstechies.com,winsupersite.com,wired.co.uk,wp-themes.com,xml.com,zol.com.cn',
-    'technology' ],
-  [ 'addons.mozilla.org,air.mozilla.org,blog.mozilla.org,bugzilla.mozilla.org,developer.mozilla.org,etherpad.mozilla.org,forums.mozillazine.org,hacks.mozilla.org,hg.mozilla.org,mozilla.org,planet.mozilla.org,quality.mozilla.org,support.mozilla.org,treeherder.mozilla.org,wiki.mozilla.org',
-    'Mozilla' ],
-  [ 'addictivetips.com,allthingsd.com,anandtech.com,androidcentral.com,androidpolice.com,arstechnica.com,bgr.com,boygeniusreport.com,cio.com,cnet.com,computerworld.com,crn.com,electronista.com,engadget.com,extremetech.com,fastcocreate.com,fastcodesign.com,fastcoexist.com,frontlinek12.com,gigaom.com,gizmag.com,gizmodo.com,greenbot.com,howtogeek.com,idigitaltimes.com,imore.com,informationweek.com,infoworld.com,itworld.com,kioskea.net,laptopmag.com,leadpages.net,lifehacker.com,mashable.com,networkworld.com,news.cnet.com,nwc.com,pastebin.com,pcadvisor.co.uk,pcmag.com,pcworld.com,phonearena.com,reviewed.com,serverfault.com,siteadvisor.com,slashdot.org,techcrunch.com,techdirt.com,techhive.com,technewsworld.com,techrepublic.com,techweb.com,tomsguide.com,tomshardware.com,ubergizmo.com,venturebeat.com,wired.com,xda-developers.com,zdnet.com',
-    'technology news' ],
-  [ 'bestbuy.ca,bestbuy.com,cdw.com,compusa.com,computerlivehelp.co,cyberguys.com,dell.com,digitalinsight.com,directron.com,ebuyer.com,frontierpc.com,frys-electronics-ads.com,frys.com,geeks.com,gyazo.com,homestead.com,lenovo.com,macmall.com,microcenter.com,miniinthebox.com,mwave.com,newegg.com,officedepot.com,outletpc.com,outpost.com,radioshack.com,rakuten.com,tigerdirect.com',
-    'tech retail' ],
-  [ 'chat.com,fring.com,hello.firefox.com,oovoo.com,viber.com',
-    'video chat' ],
-  [ 'alistapart.com,answers.microsoft.com,backpack.openbadges.org,blog.chromium.org,caniuse.com,codefirefox.com,codepen.io,css-tricks.com,css3generator.com,cssdeck.com,csswizardry.com,devdocs.io,docs.angularjs.org,ghacks.net,github.com,html5demos.com,html5rocks.com,html5test.com,iojs.org,l10n.mozilla.org,marketplace.firefox.com,mozilla-hispano.org,mozillians.org,news.ycombinator.com,npmjs.com,packagecontrol.io,quirksmode.org,readwrite.com,reps.mozilla.org,smashingmagazine.com,speckyboy.com,stackoverflow.com,status.modern.ie,validator.w3.org,w3.org,webreference.com,whatcanidoformozilla.org',
-    'web development' ],
-  [ 'classroom.google.com,codeacademy.org,codecademy.com,codeschool.com,codeyear.com,elearning.ut.ac.id,how-to-build-websites.com,htmlcodetutorial.com,htmldog.com,htmlplayground.com,learn.jquery.com,quackit.com,roseindia.net,teamtreehouse.com,tizag.com,tutorialspoint.com,udacity.com,w3schools.com,webdevelopersnotes.com',
-    'webdev education' ],
-  [ 'att.com,att.net,attonlineoffers.com,bell.ca,bellsouth.com,cableone.net,cablevision.com,centurylink.com,centurylink.net,centurylinkquote.com,charter-business.com,charter.com,charter.net,chartercabledeals.com,chartermedia.com,comcast.com,comcast.net,cox.com,cox.net,coxnewsweb.com,directv.com,dish.com,dishnetwork.com,freeconferencecall.com,frontier.com,hughesnet.com,liveitwithcharter.com,mycenturylink.com,mydish.com,net10.com,officialtvstream.com.es,optimum.com,optimum.net,paygonline.com,paytm.com,qwest.com,rcn.com,rebtel.com,ringcentral.com,straighttalkbyop.com,swappa.com,textem.net,timewarner.com,timewarnercable.com,tracfone.com,verizon.com,verizon.net,voipo.com,vonagebusiness.com,wayport.net,whistleout.com,wildblue.net,windstream.net,windstreambusiness.net,wowway.com,ww2.cox.com,xfinity.com',
-    'telecommunication' ],
-  [ 'alltel.com,assurancewireless.com,attsavings.com,boostmobile.com,boostmobilestore.com,budgetmobile.com,consumercellular.com,credomobile.com,gosmartmobile.com,h2owirelessnow.com,lycamobile.com,lycamobile.us,metropcs.com,motorola.com,mycricket.com,myfamilymobile.com,nextel.com,nokia.com,nokiausa.com,polarmobile.com,qlinkwireless.com,republicwireless.com,sprint.com,sprintpcs.com,straighttalk.com,t-mobile.co.uk,t-mobile.com,tmobile.com,tracfonewireless.com,uscellular.com,verizonwireless.com,virginmobile.com,virginmobile.com.au,virginmobileusa.com,vodafone.co.uk,vodafone.com,vodaphone.co.uk,vonange.com,vzwshop.com,wireless.att.com',
-    'mobile carrier' ],
-  [ 'aa.com,aerlingus.com,airasia.com,aircanada.com,airfrance.com,airindia.com,alaskaair.com,alaskaairlines.com,allegiantair.com,britishairways.com,cathaypacific.com,china-airlines.com,continental.com,delta.com,deltavacations.com,dragonair.com,easyjet.com,elal.co.il,emirates.com,flightaware.com,flyfrontier.com,frontierairlines.com,hawaiianair.com,iberia.com,jetairways.com,jetblue.com,klm.com,koreanair.com,kuwait-airways.com,lan.com,lufthansa.com,malaysiaairlines.com,mihinlanka.com,nwa.com,qantas.com.au,qatarairways.com,ryanair.com,singaporeair.com,smartfares.com,southwest.com,southwestvacations.com,spiritair.com,spiritairlines.com,thaiair.com,united.com,usairways.com,virgin-atlantic.com,virginamerica.com,virginblue.com.au',
-    'travel & airline' ],
-  [ 'carnival.com,celebrity-cruises.com,celebritycruises.com,costacruise.com,cruise.com,cruiseamerica.com,cruisecritic.com,cruisedirect.com,cruisemates.com,cruises.com,cruisesonly.com,crystalcruises.com,cunard.com,disneycruise.disney.go.com,hollandamerica.com,ncl.com,pocruises.com,princess.com,royalcaribbean.com,royalcaribbean.cruiselines.com,rssc.com,seabourn.com,silversea.com,starcruises.com,vikingrivercruises.com,windstarcruises.com',
-    'travel & cruise' ],
-  [ 'agoda.com,airbnb.com,beaches.com,bedandbreakfast.com,bestwestern.com,booking.com,caesars.com,choicehotels.com,comfortinn.com,daysinn.com,dealbase.com,doubletree3.hilton.com,embassysuites.com,fairmont.com,flipkey.com,fourseasons.com,greatwolf.com,hamptoninn.hilton.com,hamptoninn3.hilton.com,hhonors3.hilton.com,hilton.com,hiltongardeninn3.hilton.com,hiltonworldwide.com,holidayinn.com,homeaway.com,hotelclub.com,hotelopia.com,hotels.com,hotelscombined.com,hyatt.com,ihg.com,laterooms.com,lhw.com,lq.com,mandarinoriental.com,marriott.com,motel6.com,omnihotels.com,radisson.com,ramada.com,rci.com,reservationcounter.com,resortvacationstogo.com,ritzcarlton.com,roomkey.com,sheraton.com,starwoodhotels.com,starwoodhotelshawaii.com,super8.com,thetrain.com,vacationhomerentals.com,vacationrentals.com,vrbo.com,wyndhamrewards.com',
-    'hotel & resort' ],
-  [ 'airfarewatchdog.com,airliners.net,atlanta-airport.com,budgettravel.com,cntraveler.com,cntraveller.com,destination360.com,flightstats.com,flyertalk.com,fodors.com,frommers.com,letsgo.com,lonelyplanet.com,matadornetwork.com,perfectvacation.co,ricksteves.com,roughguides.com,timeout.com,travelalberta.us,travelandleisure.com,travelchannel.com,traveler.nationalgeographic.com,travelmath.com,traveltune.com,tripadvisor.com,vegas.com,viator.com,virtualtourist.com,wikitravel.org,worldtravelguide.net',
-    'travel' ],
-  [ 'aavacations.com,applevacations.com,avianca.com,bookingbuddy.com,bookit.com,cheapair.com,cheapcaribbean.com,cheapflights.com,cheapoair.com,cheaptickets.com,chinahighlights.com,costcotravel.com,ctrip.com,despegar.com,edreams.net,expedia.ca,expedia.com,fareboom.com,farebuzz.com,farecast.live.com,farecompare.com,faregeek.com,flightnetwork.com,funjet.com,golastminute.com,hipmunk.com,hotwire.com,ifly.com,justairticket.com,kayak.com,lastminute.com,lastminutetravel.com,lowestfare.com,lowfares.com,momondo.com,onetime.com,onetravel.com,orbitz.com,otel.com,priceline.com,pricelinevisa.com,sidestep.com,skyscanner.com,smartertravel.com,statravel.com,tigerair.com,travelocity.com,travelonbids.com,travelzoo.com,tripsta.com,trivago.com,universalorlando.com,universalstudioshollywood.com,vacationexpress.com,venere.com,webjet.com,yatra.com',
-    'travel' ],
-  [ 'airportrentalcars.com,alamo.com,amtrak.com,anytransitguide.com,avis.com,boltbus.com,budget.com,carrentalexpress.com,carrentals.com,coachusa.com,dollar.com,e-zrentacar.com,enterprise.com,europcar.com,foxrentacar.com,gotobus.com,greyhound.com,hertz.com,hertzondemand.com,indianrail.gov.in,irctc.co.in,megabus.com,mta.info,nationalcar.com,nationalrail.co.uk,njtransit.com,paylesscar.com,paylesscarrental.com,peterpanbus.com,raileurope.com,rentalcars.com,rideuta.com,stagecoachbus.com,thrifty.com,uber.com,wanderu.com,zipcar.com',
-    'travel & transit' ],
-  [ 'bulbagarden.net,cheatcc.com,cheatmasters.com,cheats.ign.com,comicvine.com,computerandvideogames.com,counter-strike.net,escapistmagazine.com,gamedaily.com,gamefront.com,gameinformer.com,gamerankings.com,gamespot.com,gamesradar.com,gamestop.com,gametrailers.com,gamezone.com,giantbomb.com,ign.com,kotaku.com,metacritic.com,minecraft-server-list.com,minecraftforge.net,minecraftforum.net,minecraftservers.org,minecraftskins.com,mmo-champion.com,mojang.com,pcgamer.com,planetminecraft.com,supercheats.com,thesims.com,totaljerkface.com,unity3d.com,vg247.com,wowhead.com',
-    'gaming' ],
-  [ 'a10.com,absolutist.com,addictinggames.com,aeriagames.com,agame.com,alpha-wars.com,arcadeyum.com,armorgames.com,ballerarcade.com,battle.net,battlefield.com,bigfishgames.com,bioware.com,bitrhymes.com,candystand.com,conjurorthegame.com,crazymonkeygames.com,crusharcade.com,curse.com,cuttherope.net,dreammining.com,dressupgames.com,ea.com,easports.com,fps-pb.com,freearcade.com,freeonlinegames.com,friv.com,funplusgame.com,gamefly.com,gameforge.com,gamehouse.com,gamejolt.com,gameloft.com,gameoapp.com,gamepedia.com,gamersfirst.com,games.com,games.yahoo.com,gamesgames.com,gamezhero.com,gamingwonderland.com,ganymede.eu,goodgamestudios.com,gpotato.com,gsn.com,guildwars2.com,hirezstudios.com,igg.com,iwin.com,kahoot.it,king.com,kizi.com,kongregate.com,leagueoflegends.com,lolking.net,maxgames.com,minecraft-mp.com,minecraft.net,miniclip.com,mmo-play.com,mmorpg.com,mobafire.com,moviestarplanet.com,myonlinearcade.com,needforspeed.com,newgrounds.com,nexusmods.com,nintendo.com,noxxic.com,onrpg.com,origin.com,pch.com,peakgames.net,playstation.com,pogo.com,pokemon.com,popcap.com,primarygames.com,r2games.com,railnation.us,riotgames.com,roblox.com,rockstargames.com,runescape.com,shockwave.com,silvergames.com,spore.com,steamcommunity.com,steampowered.com,stickpage.com,swtor.com,tetrisfriends.com,thegamerstop.com,thesims3.com,twitch.tv,warthunder.com,wildtangent.com,worldoftanks.com,worldofwarcraft.com,worldofwarplanes.com,worldofwarships.com,xbox.com,y8.com,zone.msn.com,zynga.com,zyngawithfriends.com',
-    'online gaming' ],
-]);
-
 // Only allow link urls that are http(s)
 const ALLOWED_LINK_SCHEMES = new Set(["http", "https"]);
 
 // Only allow link image urls that are https or data
 const ALLOWED_IMAGE_SCHEMES = new Set(["https", "data"]);
 
 // Only allow urls to Mozilla's CDN or empty (for data URIs)
 const ALLOWED_URL_BASE = new Set(["mozilla.net", ""]);
@@ -764,24 +592,16 @@ let DirectoryLinksProvider = {
    */
   getEnhancedLink: function DirectoryLinksProvider_getEnhancedLink(link) {
     // Use the provided link if it's already enhanced
     return link.enhancedImageURI && link ? link :
            this._enhancedLinks.get(NewTabUtils.extractSite(link.url));
   },
 
   /**
-   * Get the display name of an allowed frecent sites. Returns undefined for a
-   * unallowed frecent sites.
-   */
-  getFrecentSitesName(sites) {
-    return ALLOWED_FRECENT_SITES.get(sites.join(","));
-  },
-
-  /**
    * Check if a url's scheme is in a Set of allowed schemes and if the base
    * domain is allowed.
    * @param url to check
    * @param allowed Set of allowed schemes
    * @param checkBase boolean to check the base domain
    */
   isURLAllowed(url, allowed, checkBase) {
     // Assume no url is an allowed url
@@ -832,28 +652,27 @@ let DirectoryLinksProvider = {
       let validityFilter = function(link) {
         // Make sure the link url is allowed and images too if they exist
         return this.isURLAllowed(link.url, ALLOWED_LINK_SCHEMES, false) &&
                this.isURLAllowed(link.imageURI, ALLOWED_IMAGE_SCHEMES, checkBase) &&
                this.isURLAllowed(link.enhancedImageURI, ALLOWED_IMAGE_SCHEMES, checkBase);
       }.bind(this);
 
       rawLinks.suggested.filter(validityFilter).forEach((link, position) => {
-        // Only allow suggested links with approved frecent sites
-        let name = this.getFrecentSitesName(link.frecent_sites);
-        if (name == undefined) {
+        // Suggested sites must have an adgroup name.
+        if (!link.adgroup_name) {
           return;
         }
 
         let sanitizeFlags = ParserUtils.SanitizerCidEmbedsOnly |
           ParserUtils.SanitizerDropForms |
           ParserUtils.SanitizerDropNonCSSPresentation;
 
         link.explanation = this._escapeChars(link.explanation ? ParserUtils.convertToPlainText(link.explanation, sanitizeFlags, 0) : "");
-        link.targetedName = this._escapeChars(ParserUtils.convertToPlainText(link.adgroup_name, sanitizeFlags, 0) || name);
+        link.targetedName = this._escapeChars(ParserUtils.convertToPlainText(link.adgroup_name, sanitizeFlags, 0));
         link.lastVisitDate = rawLinks.suggested.length - position;
         // check if link wants to avoid inadjacent sites
         if (link.check_inadjacency) {
           this._avoidInadjacentSites = true;
         }
 
         // We cache suggested tiles here but do not push any of them in the links list yet.
         // The decision for which suggested tile to include will be made separately.
--- a/browser/modules/test/xpcshell/test_DirectoryLinksProvider.js
+++ b/browser/modules/test/xpcshell/test_DirectoryLinksProvider.js
@@ -62,49 +62,53 @@ const BinaryInputStream = CC("@mozilla.o
                               "setInputStream");
 
 let gLastRequestPath;
 
 let suggestedTile1 = {
   url: "http://turbotax.com",
   type: "affiliate",
   lastVisitDate: 4,
+  adgroup_name: "Adgroup1",
   frecent_sites: [
     "taxact.com",
     "hrblock.com",
     "1040.com",
     "taxslayer.com"
   ]
 };
 let suggestedTile2 = {
   url: "http://irs.gov",
   type: "affiliate",
   lastVisitDate: 3,
+  adgroup_name: "Adgroup2",
   frecent_sites: [
     "taxact.com",
     "hrblock.com",
     "freetaxusa.com",
     "taxslayer.com"
   ]
 };
 let suggestedTile3 = {
   url: "http://hrblock.com",
   type: "affiliate",
   lastVisitDate: 2,
+  adgroup_name: "Adgroup3",
   frecent_sites: [
     "taxact.com",
     "freetaxusa.com",
     "1040.com",
     "taxslayer.com"
   ]
 };
 let suggestedTile4 = {
   url: "http://sponsoredtile.com",
   type: "sponsored",
   lastVisitDate: 1,
+  adgroup_name: "Adgroup4",
   frecent_sites: [
     "sponsoredtarget.com"
   ]
 }
 let suggestedTile5 = {
   url: "http://eviltile.com",
   type: "affiliate",
   lastVisitDate: 5,
@@ -291,19 +295,16 @@ add_task(function test_updateSuggestedTi
 
   // Initial setup
   let data = {"suggested": [suggestedTile1, suggestedTile2, suggestedTile3], "directory": [someOtherSite]};
   let dataURI = 'data:application/json,' + JSON.stringify(data);
 
   let testObserver = new TestFirstRun();
   DirectoryLinksProvider.addObserver(testObserver);
 
-  let origGetFrecentSitesName = DirectoryLinksProvider.getFrecentSitesName;
-  DirectoryLinksProvider.getFrecentSitesName = () => "";
-
   yield promiseSetupDirectoryLinksProvider({linksURL: dataURI});
   let links = yield fetchData();
 
   let origIsTopPlacesSite = NewTabUtils.isTopPlacesSite;
   NewTabUtils.isTopPlacesSite = function(site) {
     return topSites.indexOf(site) >= 0;
   }
 
@@ -408,26 +409,22 @@ add_task(function test_updateSuggestedTi
   topSites = [];
   testObserver = new TestRemovingSuggestedTile();
   DirectoryLinksProvider.addObserver(testObserver);
   DirectoryLinksProvider.onManyLinksChanged();
   yield testObserver.promise;
 
   // Cleanup
   yield promiseCleanDirectoryLinksProvider();
-  DirectoryLinksProvider.getFrecentSitesName = origGetFrecentSitesName;
   NewTabUtils.isTopPlacesSite = origIsTopPlacesSite;
   NewTabUtils.getProviderLinks = origGetProviderLinks;
   DirectoryLinksProvider._getCurrentTopSiteCount = origCurrentTopSiteCount;
 });
 
 add_task(function test_suggestedLinksMap() {
-  let origGetFrecentSitesName = DirectoryLinksProvider.getFrecentSitesName;
-  DirectoryLinksProvider.getFrecentSitesName = () => "testing map";
-
   let data = {"suggested": [suggestedTile1, suggestedTile2, suggestedTile3, suggestedTile4], "directory": [someOtherSite]};
   let dataURI = 'data:application/json,' + JSON.stringify(data);
 
   yield promiseSetupDirectoryLinksProvider({linksURL: dataURI});
   let links = yield fetchData();
 
   // Ensure the suggested tiles were not considered directory tiles.
   do_check_eq(links.length, 1);
@@ -447,30 +444,26 @@ add_task(function test_suggestedLinksMap
   let suggestedSites = [...DirectoryLinksProvider._suggestedLinks.keys()];
   do_check_eq(suggestedSites.indexOf("sponsoredtarget.com"), 5);
   do_check_eq(suggestedSites.length, Object.keys(expected_data).length);
 
   DirectoryLinksProvider._suggestedLinks.forEach((suggestedLinks, site) => {
     let suggestedLinksItr = suggestedLinks.values();
     for (let link of expected_data[site]) {
       let linkCopy = JSON.parse(JSON.stringify(link));
-      linkCopy.targetedName = "testing map";
+      linkCopy.targetedName = link.adgroup_name;
       linkCopy.explanation = "";
       isIdentical(suggestedLinksItr.next().value, linkCopy);
     }
   })
 
   yield promiseCleanDirectoryLinksProvider();
-  DirectoryLinksProvider.getFrecentSitesName = origGetFrecentSitesName;
 });
 
 add_task(function test_topSitesWithSuggestedLinks() {
-  let origGetFrecentSitesName = DirectoryLinksProvider.getFrecentSitesName;
-  DirectoryLinksProvider.getFrecentSitesName = () => "";
-
   let topSites = ["site0.com", "1040.com", "site2.com", "hrblock.com", "site4.com", "freetaxusa.com", "site6.com"];
   let origIsTopPlacesSite = NewTabUtils.isTopPlacesSite;
   NewTabUtils.isTopPlacesSite = function(site) {
     return topSites.indexOf(site) >= 0;
   }
 
   // Mock out getProviderLinks() so we don't have to populate cache in NewTabUtils
   let origGetProviderLinks = NewTabUtils.getProviderLinks;
@@ -508,40 +501,41 @@ add_task(function test_topSitesWithSugge
 
   // Re-adding freetaxusa.com as a topsite will add it to _topSitesWithSuggestedLinks.
   topSites.push(popped);
   expectedTopSitesWithSuggestedLinks.push(popped);
   DirectoryLinksProvider._handleLinkChanged({url: "http://" + popped});
   isIdentical([...DirectoryLinksProvider._topSitesWithSuggestedLinks], expectedTopSitesWithSuggestedLinks);
 
   // Cleanup.
-  DirectoryLinksProvider.getFrecentSitesName = origGetFrecentSitesName;
   NewTabUtils.isTopPlacesSite = origIsTopPlacesSite;
   NewTabUtils.getProviderLinks = origGetProviderLinks;
 });
 
 add_task(function test_suggestedAttributes() {
   let origIsTopPlacesSite = NewTabUtils.isTopPlacesSite;
   NewTabUtils.isTopPlacesSite = () => true;
 
   let origCurrentTopSiteCount = DirectoryLinksProvider._getCurrentTopSiteCount;
   DirectoryLinksProvider._getCurrentTopSiteCount = () => 8;
 
   let frecent_sites = "addons.mozilla.org,air.mozilla.org,blog.mozilla.org,bugzilla.mozilla.org,developer.mozilla.org,etherpad.mozilla.org,forums.mozillazine.org,hacks.mozilla.org,hg.mozilla.org,mozilla.org,planet.mozilla.org,quality.mozilla.org,support.mozilla.org,treeherder.mozilla.org,wiki.mozilla.org".split(",");
   let imageURI = "https://image/";
   let title = "the title";
   let type = "affiliate";
   let url = "http://test.url/";
+  let adgroup_name = "Mozilla";
   let data = {
     suggested: [{
       frecent_sites,
       imageURI,
       title,
       type,
-      url
+      url,
+      adgroup_name
     }]
   };
   let dataURI = "data:application/json," + escape(JSON.stringify(data));
 
   yield promiseSetupDirectoryLinksProvider({linksURL: dataURI});
 
   // Wait for links to get loaded
   let gLinks = NewTabUtils.links;
@@ -570,32 +564,31 @@ add_task(function test_suggestedAttribut
   NewTabUtils.isTopPlacesSite = origIsTopPlacesSite;
   DirectoryLinksProvider._getCurrentTopSiteCount = origCurrentTopSiteCount;
   gLinks.removeProvider(DirectoryLinksProvider);
   DirectoryLinksProvider.removeObserver(gLinks);
 });
 
 add_task(function test_frequencyCappedSites_views() {
   Services.prefs.setCharPref(kPingUrlPref, "");
-  let origGetFrecentSitesName = DirectoryLinksProvider.getFrecentSitesName;
-  DirectoryLinksProvider.getFrecentSitesName = () => "";
   let origIsTopPlacesSite = NewTabUtils.isTopPlacesSite;
   NewTabUtils.isTopPlacesSite = () => true;
 
   let origCurrentTopSiteCount = DirectoryLinksProvider._getCurrentTopSiteCount;
   DirectoryLinksProvider._getCurrentTopSiteCount = () => 8;
 
   let testUrl = "http://frequency.capped/link";
   let targets = ["top.site.com"];
   let data = {
     suggested: [{
       type: "affiliate",
       frecent_sites: targets,
       url: testUrl,
-      frequency_caps: {daily: 5}
+      frequency_caps: {daily: 5},
+      adgroup_name: "Test"
     }],
     directory: [{
       type: "organic",
       url: "http://directory.site/"
     }]
   };
   let dataURI = "data:application/json," + JSON.stringify(data);
 
@@ -639,41 +632,39 @@ add_task(function test_frequencyCappedSi
   synthesizeAction("view");
   checkFirstTypeAndLength("affiliate", 2);
   synthesizeAction("view");
   checkFirstTypeAndLength("affiliate", 2);
   synthesizeAction("view");
   checkFirstTypeAndLength("organic", 1);
 
   // Cleanup.
-  DirectoryLinksProvider.getFrecentSitesName = origGetFrecentSitesName;
   NewTabUtils.isTopPlacesSite = origIsTopPlacesSite;
   DirectoryLinksProvider._getCurrentTopSiteCount = origCurrentTopSiteCount;
   gLinks.removeProvider(DirectoryLinksProvider);
   DirectoryLinksProvider.removeObserver(gLinks);
   Services.prefs.setCharPref(kPingUrlPref, kPingUrl);
 });
 
 add_task(function test_frequencyCappedSites_click() {
   Services.prefs.setCharPref(kPingUrlPref, "");
-  let origGetFrecentSitesName = DirectoryLinksProvider.getFrecentSitesName;
-  DirectoryLinksProvider.getFrecentSitesName = () => "";
   let origIsTopPlacesSite = NewTabUtils.isTopPlacesSite;
   NewTabUtils.isTopPlacesSite = () => true;
 
   let origCurrentTopSiteCount = DirectoryLinksProvider._getCurrentTopSiteCount;
   DirectoryLinksProvider._getCurrentTopSiteCount = () => 8;
 
   let testUrl = "http://frequency.capped/link";
   let targets = ["top.site.com"];
   let data = {
     suggested: [{
       type: "affiliate",
       frecent_sites: targets,
-      url: testUrl
+      url: testUrl,
+      adgroup_name: "Test"
     }],
     directory: [{
       type: "organic",
       url: "http://directory.site/"
     }]
   };
   let dataURI = "data:application/json," + JSON.stringify(data);
 
@@ -711,17 +702,16 @@ add_task(function test_frequencyCappedSi
   // Make sure the link disappears after the first click
   checkFirstTypeAndLength("affiliate", 2);
   synthesizeAction("view");
   checkFirstTypeAndLength("affiliate", 2);
   synthesizeAction("click");
   checkFirstTypeAndLength("organic", 1);
 
   // Cleanup.
-  DirectoryLinksProvider.getFrecentSitesName = origGetFrecentSitesName;
   NewTabUtils.isTopPlacesSite = origIsTopPlacesSite;
   DirectoryLinksProvider._getCurrentTopSiteCount = origCurrentTopSiteCount;
   gLinks.removeProvider(DirectoryLinksProvider);
   DirectoryLinksProvider.removeObserver(gLinks);
   Services.prefs.setCharPref(kPingUrlPref, kPingUrl);
 });
 
 add_task(function test_reportSitesAction() {
@@ -1212,26 +1202,24 @@ add_task(function test_DirectoryLinksPro
   yield promiseSetupDirectoryLinksProvider({linksURL: dataURI});
   links = yield fetchData();
   do_check_eq(links.length, 0); // There are no directory links.
   checkEnhanced("http://example.net", undefined);
   checkEnhanced("http://example.com", "data:,fresh");
 });
 
 add_task(function test_DirectoryLinksProvider_enhancedURIs() {
-  let origGetFrecentSitesName = DirectoryLinksProvider.getFrecentSitesName;
-  DirectoryLinksProvider.getFrecentSitesName = () => "";
   let origIsTopPlacesSite = NewTabUtils.isTopPlacesSite;
   NewTabUtils.isTopPlacesSite = () => true;
   let origCurrentTopSiteCount = DirectoryLinksProvider._getCurrentTopSiteCount;
   DirectoryLinksProvider._getCurrentTopSiteCount = () => 8;
 
   let data = {
     "suggested": [
-      {url: "http://example.net", enhancedImageURI: "data:,net1", title:"SuggestedTitle", frecent_sites: ["test.com"]}
+      {url: "http://example.net", enhancedImageURI: "data:,net1", title:"SuggestedTitle", adgroup_name: "Test", frecent_sites: ["test.com"]}
     ],
     "directory": [
       {url: "http://example.net", enhancedImageURI: "data:,net2", title:"DirectoryTitle"}
     ]
   };
   let dataURI = 'data:application/json,' + JSON.stringify(data);
   yield promiseSetupDirectoryLinksProvider({linksURL: dataURI});
 
@@ -1257,17 +1245,16 @@ add_task(function test_DirectoryLinksPro
 
   // Check that the suggested tile with the same URL replaces the directory tile.
   links = gLinks.getLinks();
   do_check_eq(links.length, 1);
   do_check_eq(links[0].title, "SuggestedTitle");
   do_check_eq(links[0].enhancedImageURI, "data:,net1");
 
   // Cleanup.
-  DirectoryLinksProvider.getFrecentSitesName = origGetFrecentSitesName;
   NewTabUtils.isTopPlacesSite = origIsTopPlacesSite;
   DirectoryLinksProvider._getCurrentTopSiteCount = origCurrentTopSiteCount;
   gLinks.removeProvider(DirectoryLinksProvider);
 });
 
 add_task(function test_DirectoryLinksProvider_setDefaultEnhanced() {
   function checkDefault(expected) {
     Services.prefs.clearUserPref(kNewtabEnhancedPref);
@@ -1307,19 +1294,16 @@ add_task(function test_timeSensetiveSugg
   // Initial setup
   let topSites = ["site0.com", "1040.com", "site2.com", "hrblock.com", "site4.com", "freetaxusa.com", "site6.com"];
   let data = {"suggested": [suggestedTile], "directory": [someOtherSite]};
   let dataURI = 'data:application/json,' + JSON.stringify(data);
 
   let testObserver = new TestTimingRun();
   DirectoryLinksProvider.addObserver(testObserver);
 
-  let origGetFrecentSitesName = DirectoryLinksProvider.getFrecentSitesName;
-  DirectoryLinksProvider.getFrecentSitesName = () => "";
-
   yield promiseSetupDirectoryLinksProvider({linksURL: dataURI});
   let links = yield fetchData();
 
   let origIsTopPlacesSite = NewTabUtils.isTopPlacesSite;
   NewTabUtils.isTopPlacesSite = function(site) {
     return topSites.indexOf(site) >= 0;
   }
 
@@ -1419,17 +1403,16 @@ add_task(function test_timeSensetiveSugg
     do_check_true(DirectoryLinksProvider._campaignTimeoutID);
     DirectoryLinksProvider._clearCampaignTimeout();
     deferred.resolve();
   });
   yield deferred.promise;
 
   // Cleanup
   yield promiseCleanDirectoryLinksProvider();
-  DirectoryLinksProvider.getFrecentSitesName = origGetFrecentSitesName;
   NewTabUtils.isTopPlacesSite = origIsTopPlacesSite;
   NewTabUtils.getProviderLinks = origGetProviderLinks;
   DirectoryLinksProvider._getCurrentTopSiteCount = origCurrentTopSiteCount;
 });
 
 add_task(function test_setupStartEndTime() {
   let currentTime = Date.now();
   let dt = new Date(currentTime);
@@ -1723,20 +1706,16 @@ add_task(function test_DirectoryLinksPro
 
 add_task(function test_DirectoryLinksProvider_anonymous() {
   do_check_true(DirectoryLinksProvider._newXHR().mozAnon);
 });
 
 add_task(function test_sanitizeExplanation() {
   // Note: this is a basic test to ensure we applied sanitization to the link explanation.
   // Full testing for appropriate sanitization is done in parser/xml/test/unit/test_sanitizer.js.
-
-  let origGetFrecentSitesName = DirectoryLinksProvider.getFrecentSitesName;
-  DirectoryLinksProvider.getFrecentSitesName = () => "testing map";
-
   let data = {"suggested": [suggestedTile5]};
   let dataURI = 'data:application/json,' + encodeURIComponent(JSON.stringify(data));
 
   yield promiseSetupDirectoryLinksProvider({linksURL: dataURI});
   let links = yield fetchData();
 
   let suggestedSites = [...DirectoryLinksProvider._suggestedLinks.keys()];
   do_check_eq(suggestedSites.indexOf("eviltarget.com"), 0);
@@ -1755,19 +1734,16 @@ add_task(function test_inadjecentSites()
   // Initial setup
   let topSites = ["1040.com", "site2.com", "hrblock.com", "site4.com", "freetaxusa.com", "site6.com"];
   let data = {"suggested": [suggestedTile], "directory": [someOtherSite]};
   let dataURI = 'data:application/json,' + JSON.stringify(data);
 
   let testObserver = new TestFirstRun();
   DirectoryLinksProvider.addObserver(testObserver);
 
-  let origGetFrecentSitesName = DirectoryLinksProvider.getFrecentSitesName;
-  DirectoryLinksProvider.getFrecentSitesName = () => "";
-
   yield promiseSetupDirectoryLinksProvider({linksURL: dataURI});
   let links = yield fetchData();
 
   let origIsTopPlacesSite = NewTabUtils.isTopPlacesSite;
   NewTabUtils.isTopPlacesSite = function(site) {
     return topSites.indexOf(site) >= 0;
   }
 
@@ -1913,38 +1889,36 @@ add_task(function test_inadjecentSites()
   do_check_false(DirectoryLinksProvider._isInadjacentLink({}));
 
   // test _checkForInadjacentSites
   do_check_true(DirectoryLinksProvider._checkForInadjacentSites());
 
   // Cleanup
   gLinks.removeProvider(DirectoryLinksProvider);
   DirectoryLinksProvider._inadjacentSitesUrl = origInadjacentSitesUrl;
-  DirectoryLinksProvider.getFrecentSitesName = origGetFrecentSitesName;
   NewTabUtils.isTopPlacesSite = origIsTopPlacesSite;
   NewTabUtils.getProviderLinks = origGetProviderLinks;
   DirectoryLinksProvider._getCurrentTopSiteCount = origCurrentTopSiteCount;
   yield promiseCleanDirectoryLinksProvider();
 });
 
 add_task(function test_reportPastImpressions() {
-  let origGetFrecentSitesName = DirectoryLinksProvider.getFrecentSitesName;
-  DirectoryLinksProvider.getFrecentSitesName = () => "";
   let origIsTopPlacesSite = NewTabUtils.isTopPlacesSite;
   NewTabUtils.isTopPlacesSite = () => true;
   let origCurrentTopSiteCount = DirectoryLinksProvider._getCurrentTopSiteCount;
   DirectoryLinksProvider._getCurrentTopSiteCount = () => 8;
 
   let testUrl = "http://frequency.capped/link";
   let targets = ["top.site.com"];
   let data = {
     suggested: [{
       type: "affiliate",
       frecent_sites: targets,
-      url: testUrl
+      url: testUrl,
+      adgroup_name: "Test"
     }]
   };
   let dataURI = "data:application/json," + JSON.stringify(data);
   yield promiseSetupDirectoryLinksProvider({linksURL: dataURI});
 
   // make DirectoryLinksProvider load json
   let loadPromise = Promise.defer();
   DirectoryLinksProvider.getLinks(_ => {loadPromise.resolve();});
@@ -2021,12 +1995,11 @@ add_task(function test_reportPastImpress
   yield sendPingAndTest("click", "unpin", 2);
   sites.isPinned = _ => false;
   yield sendPingAndTest("click", "click", 2);
   sites.isPinned = _ => false;
   yield sendPingAndTest("click", "block", 2);
 
   // Cleanup.
   done = true;
-  DirectoryLinksProvider.getFrecentSitesName = origGetFrecentSitesName;
   NewTabUtils.isTopPlacesSite = origIsTopPlacesSite;
   DirectoryLinksProvider._getCurrentTopSiteCount = origCurrentTopSiteCount;
 });
--- a/browser/themes/shared/devtools/performance.css
+++ b/browser/themes/shared/devtools/performance.css
@@ -584,16 +584,24 @@ menuitem.marker-color-graphs-grey:before
 
 #jit-optimizations-view {
   width: 350px;
   overflow-x: hidden;
   overflow-y: auto;
   min-width: 200px;
 }
 
+#optimizations-graph {
+  height: 30px;
+}
+
+#jit-optimizations-view.empty #optimizations-graph {
+  display: none !important;
+}
+
 /* override default styles for tree widget */
 #jit-optimizations-view .tree-widget-empty-text {
   font-size: inherit;
   padding: 0px;
   margin: 8px;
 }
 
 #jit-optimizations-view:not(.empty) .tree-widget-empty-text {
--- a/browser/themes/windows/browser.css
+++ b/browser/themes/windows/browser.css
@@ -47,23 +47,23 @@
   --urlbar-dropmarker-active-2x-region: rect(0, 66px, 28px, 44px);
 
   --panel-separator-color: ThreeDLightShadow;
 
   --urlbar-separator-color: hsla(0,0%,16%,.2);
 }
 
 #nav-bar[brighttext] {
-  --toolbarbutton-hover-background: rgba(255,255,255,.1);
-  --toolbarbutton-hover-bordercolor: rgba(255,255,255,.1);
+  --toolbarbutton-hover-background: rgba(255,255,255,.15);
+  --toolbarbutton-hover-bordercolor: rgba(255,255,255,.15);
   --toolbarbutton-hover-boxshadow: none;
 
-  --toolbarbutton-active-background: rgba(255,255,255,.15);
-  --toolbarbutton-active-bordercolor: rgba(255,255,255,.15);
-  --toolbarbutton-active-boxshadow: 0 0 0 1px rgba(255,255,255,.15) inset;
+  --toolbarbutton-active-background: rgba(255,255,255,.3);
+  --toolbarbutton-active-bordercolor: rgba(255,255,255,.3);
+  --toolbarbutton-active-boxshadow: 0 0 0 1px rgba(255,255,255,.3) inset;
 }
 
 #menubar-items {
   -moz-box-orient: vertical; /* for flex hack */
 }
 
 #main-menubar {
   -moz-box-flex: 1; /* make menu items expand to fill toolbar height */
@@ -837,18 +837,18 @@ toolbarbutton[constrain-size="true"][cui
 }
 
 #nav-bar #bookmarks-menu-button[cui-areatype="toolbar"] > .toolbarbutton-menubutton-button > .toolbarbutton-icon {
   /* horizontal padding + border + actual icon width */
   width: 31px;
 }
 
 #nav-bar .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon {
-  padding-top: 8px;
-  padding-bottom: 8px;
+  padding-top: calc(var(--toolbarbutton-vertical-inner-padding) + 6px);
+  padding-bottom: calc(var(--toolbarbutton-vertical-inner-padding) + 6px);
 }
 
 #nav-bar .toolbaritem-combined-buttons {
   margin-left: 2px;
   margin-right: 2px;
 }
 
 #nav-bar .toolbaritem-combined-buttons > .toolbarbutton-1 {
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>
--- a/dom/base/ChromeUtils.h
+++ b/dom/base/ChromeUtils.h
@@ -18,24 +18,24 @@ namespace devtools {
 class HeapSnapshot;
 } // namespace devtools
 
 namespace dom {
 
 class ThreadSafeChromeUtils
 {
 public:
-  // Implemented in toolkit/devtools/server/HeapSnapshot.cpp
+  // Implemented in toolkit/devtools/heapsnapshot/HeapSnapshot.cpp
   static void SaveHeapSnapshot(GlobalObject& global,
                                JSContext* cx,
-                               const nsAString& filePath,
                                const HeapSnapshotBoundaries& boundaries,
+                               nsAString& filePath,
                                ErrorResult& rv);
 
-  // Implemented in toolkit/devtools/server/HeapSnapshot.cpp
+  // Implemented in toolkit/devtools/heapsnapshot/HeapSnapshot.cpp
   static already_AddRefed<devtools::HeapSnapshot> ReadHeapSnapshot(GlobalObject& global,
                                                                    JSContext* cx,
                                                                    const nsAString& filePath,
                                                                    ErrorResult& rv);
 };
 
 class ChromeUtils : public ThreadSafeChromeUtils
 {
--- 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/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/ThreadSafeChromeUtils.webidl
+++ b/dom/webidl/ThreadSafeChromeUtils.webidl
@@ -9,23 +9,25 @@
  * to Chrome. This interface is exposed in workers, while ChromeUtils is not.
  */
 [ChromeOnly, Exposed=(Window,System,Worker)]
 interface ThreadSafeChromeUtils {
   /**
    * Serialize a snapshot of the heap graph, as seen by |JS::ubi::Node| and
    * restricted by |boundaries|, and write it to the provided file path.
    *
-   * @param filePath          The file path to write the heap snapshot to.
+   * @param boundaries        The portion of the heap graph to write.
    *
-   * @param boundaries        The portion of the heap graph to write.
+   * @returns                 The path to the file the heap snapshot was written
+   *                          to. This is guaranteed to be within the temp
+   *                          directory and its file name will match the regexp
+   *                          `\d+(\-\d+)?\.fxsnapshot`.
    */
   [Throws]
-  static void saveHeapSnapshot(DOMString filePath,
-                               optional HeapSnapshotBoundaries boundaries);
+  static DOMString saveHeapSnapshot(optional HeapSnapshotBoundaries boundaries);
 
   /**
    * Deserialize a core dump into a HeapSnapshot.
    *
    * @param filePath          The file path to read the heap snapshot from.
    */
   [Throws, NewObject]
   static HeapSnapshot readHeapSnapshot(DOMString filePath);
--- 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