Merge inbound to m-c a=merge
authorWes Kocher <wkocher@mozilla.com>
Thu, 05 Jun 2014 18:31:10 -0700
changeset 207186 c08a299f21639dfcbc4dd05c72f4e32c56885de4
parent 207110 5e8e9d864a4d3a7da8f7499b4791f6e2323ce170 (current diff)
parent 207185 039b9e7b3616d4f9dcc0fa9d67d932a9053b298b (diff)
child 207188 90b7c043acc3cddc2177c55c4fd6239e3c40ef27
push id494
push userraliiev@mozilla.com
push dateMon, 25 Aug 2014 18:42:16 +0000
treeherdermozilla-release@a3cc3e46b571 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone32.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge inbound to m-c a=merge
configure.in
layout/reftests/text/pre-discard-newlines-1-ref.html
layout/reftests/text/pre-discard-newlines-1.html
netwerk/test/TestAsyncCache.js
netwerk/test/TestCacheCollisions.js
netwerk/test/TestCachePerformance.js
netwerk/test/TestCacheService.cpp
netwerk/test/TestCacheVisitor.js
netwerk/test/TestDiskCache.js
netwerk/test/TestMCTransport.cpp
netwerk/test/TestObjectCache.js
--- a/b2g/app/b2g.js
+++ b/b2g/app/b2g.js
@@ -974,16 +974,19 @@ pref("gfx.canvas.willReadFrequently.enab
 pref("browser.autofocus", false);
 
 // Enable wakelock
 pref("dom.wakelock.enabled", true);
 
 // Disable touch caret by default
 pref("touchcaret.enabled", false);
 
+// Disable selection caret by default
+pref("selectioncaret.enabled", false);
+
 // Enable sync and mozId with Firefox Accounts.
 #ifdef MOZ_SERVICES_FXACCOUNTS
 pref("services.sync.fxaccounts.enabled", true);
 pref("identity.fxaccounts.enabled", true);
 #endif
 
 // Enable mapped array buffer
 pref("dom.mapped_arraybuffer.enabled", true);
--- a/b2g/chrome/content/content.css
+++ b/b2g/chrome/content/content.css
@@ -278,21 +278,19 @@ input[type="checkbox"][disabled]:hover:a
 select[disabled] > button {
   opacity: 0.6;
   padding: 1px 7px 1px 7px;
 }
 
 *:-moz-any-link:active,
 *[role=button]:active,
 button:active,
-input:active,
 option:active,
 select:active,
-label:active,
-textarea:active {
+label:active {
   background-color: rgba(141, 184, 216, 0.5);
 }
 
 input[type=number] > div > div, /* work around bug 946184 */
 input[type=number]::-moz-number-spin-box {
   display: none;
 }
 
--- a/b2g/chrome/content/devtools.js
+++ b/b2g/chrome/content/devtools.js
@@ -267,17 +267,24 @@ Target.prototype = {
    * widgets.
    */
   destroy: function target_destroy() {
     delete this.metrics;
     this._send({});
   },
 
   _send: function target_send(data) {
-    shell.sendEvent(this.frame, 'developer-hud-update', Cu.cloneInto(data, this.frame));
+    let frame = this.frame;
+
+    let systemapp = document.querySelector('#systemapp');
+    if (this.frame === systemapp) {
+      frame = getContentWindow();
+    }
+
+    shell.sendEvent(frame, 'developer-hud-update', Cu.cloneInto(data, target));
   }
 
 };
 
 
 /**
  * The Console Watcher tracks the following metrics in apps: reflows, warnings,
  * and errors, with security errors reported separately.
--- a/b2g/components/ContentPermissionPrompt.js
+++ b/b2g/components/ContentPermissionPrompt.js
@@ -415,17 +415,34 @@ ContentPermissionPrompt.prototype = {
       isApp: isApp,
       remember: remember,
       isGranted: isGranted,
     };
 
     if (isApp) {
       details.manifestURL = DOMApplicationRegistry.getManifestURLByLocalId(principal.appId);
     }
-    SystemAppProxy.dispatchEvent(details);
+
+    // request.element is defined for OOP content, while request.window
+    // is defined for In-Process content.
+    // In both cases the message needs to be dispatched to the top-level
+    // <iframe mozbrowser> container in the system app.
+    // So the above code iterates over window.realFrameElement in order
+    // to crosss mozbrowser iframes boundaries and find the top-level
+    // one in the system app.
+    // window.realFrameElement will be |null| if the code try to cross
+    // content -> chrome boundaries.
+    let targetElement = request.element;
+    let targetWindow = request.window || targetElement.ownerDocument.defaultView;
+    while (targetWindow.realFrameElement) {
+      targetElement = targetWindow.realFrameElement;
+      targetWindow = targetElement.ownerDocument.defaultView;
+    }
+
+    SystemAppProxy.dispatchEvent(details, targetElement);
   },
 
   classID: Components.ID("{8c719f03-afe0-4aac-91ff-6c215895d467}"),
 
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIContentPermissionPrompt])
 };
 
 (function() {
--- a/b2g/components/SystemAppProxy.jsm
+++ b/b2g/components/SystemAppProxy.jsm
@@ -53,17 +53,20 @@ let SystemAppProxy = {
    *     event.details == 'bar'
    *   });
    *
    *   @param type      The custom event type.
    *   @param details   The event details.
    *   @param noPending Set to true to emit this event even before the system
    *                    app is ready.
    */
-  _sendCustomEvent: function systemApp_sendCustomEvent(type, details, noPending) {
+  _sendCustomEvent: function systemApp_sendCustomEvent(type,
+                                                       details,
+                                                       noPending,
+                                                       target) {
     let content = this._frame ? this._frame.contentWindow : null;
 
     // If the system app isn't ready yet,
     // queue events until someone calls setIsReady
     if (!content || (!this._isReady && !noPending)) {
       this._pendingEvents.push([type, details]);
       return null;
     }
@@ -75,24 +78,24 @@ let SystemAppProxy = {
     // we consider the caller already wrapped (correctly) the object.
     if ('__exposedProps__' in details) {
       payload = details;
     } else {
       payload = details ? Cu.cloneInto(details, content) : {};
     }
 
     event.initCustomEvent(type, true, false, payload);
-    content.dispatchEvent(event);
+    (target || content).dispatchEvent(event);
 
     return event;
   },
 
   // Now deprecated, use sendCustomEvent with a custom event name
-  dispatchEvent: function systemApp_sendChromeEvent(details) {
-    return this._sendCustomEvent('mozChromeEvent', details);
+  dispatchEvent: function systemApp_sendChromeEvent(details, target) {
+    return this._sendCustomEvent('mozChromeEvent', details, false, target);
   },
 
   // Listen for dom events on the system app
   addEventListener: function systemApp_addEventListener() {
     let content = this._frame ? this._frame.contentWindow : null;
     if (!content) {
       this._pendingListeners.push(arguments);
       return false;
--- a/b2g/components/test/mochitest/systemapp_helper.js
+++ b/b2g/components/test/mochitest/systemapp_helper.js
@@ -3,16 +3,17 @@ const Cu = Components.utils;
 const { Services } = Cu.import("resource://gre/modules/Services.jsm");
 
 // Load a duplicated copy of the jsm to prevent messing with the currently running one
 let scope = {};
 Services.scriptloader.loadSubScript("resource://gre/modules/SystemAppProxy.jsm", scope);
 const { SystemAppProxy } = scope;
 
 let frame;
+let customEventTarget;
 
 let index = -1;
 function next() {
   index++;
   if (index >= steps.length) {
     assert.ok(false, "Shouldn't get here!");
     return;
   }
@@ -42,16 +43,20 @@ function listener(event) {
 
     next(); // call checkEventDispatching
   } else if (n == 3) {
     assert.equal(event.type, "custom");
     assert.equal(event.detail.name, "third");
   } else if (n == 4) {
     assert.equal(event.type, "mozChromeEvent");
     assert.equal(event.detail.name, "fourth");
+  } else if (n == 5) {
+    assert.equal(event.type, "custom");
+    assert.equal(event.detail.name, "fifth");
+    assert.equal(event.target, customEventTarget);
 
     next(); // call checkEventListening();
   } else {
     assert.ok(false, "Unexpected event of type " + event.type);
   }
 }
 
 
@@ -74,16 +79,18 @@ let steps = [
 
   function createFrame() {
     // Create a fake system app frame
     let win = Services.wm.getMostRecentWindow("navigator:browser");
     let doc = win.document;
     frame = doc.createElement("iframe");
     doc.documentElement.appendChild(frame);
 
+    customEventTarget = frame.contentDocument.body;
+
     // Ensure that events are correctly sent to the frame.
     // `listener` is going to call next()
     frame.contentWindow.addEventListener("mozChromeEvent", listener);
     frame.contentWindow.addEventListener("custom", listener);
 
     // Ensure that listener being registered before the system app is ready
     // are correctly removed from the pending list
     function removedListener() {
@@ -113,17 +120,18 @@ let steps = [
     frame.setAttribute("src", "data:text/html,system app");
   },
 
   function checkEventDispatching() {
     // Send events after the iframe is ready,
     // they should be dispatched right away
     SystemAppProxy._sendCustomEvent("custom", { name: "third" });
     SystemAppProxy.dispatchEvent({ name: "fourth" });
-    // Once this 4th event is received, we will run checkEventListening
+    SystemAppProxy._sendCustomEvent("custom", { name: "fifth" }, false, customEventTarget);
+    // Once this 5th event is received, we will run checkEventListening
   },
 
   function checkEventListening() {
     SystemAppProxy.addEventListener("mozContentEvent", function onContentEvent(event) {
       assert.equal(event.detail.name, "first-content", "received a system app event");
       SystemAppProxy.removeEventListener("mozContentEvent", onContentEvent);
 
       next();
--- a/b2g/installer/package-manifest.in
+++ b/b2g/installer/package-manifest.in
@@ -666,16 +666,28 @@
 @BINPATH@/res/table-add-row-before-hover.gif
 @BINPATH@/res/table-add-row-before.gif
 @BINPATH@/res/table-remove-column-active.gif
 @BINPATH@/res/table-remove-column-hover.gif
 @BINPATH@/res/table-remove-column.gif
 @BINPATH@/res/table-remove-row-active.gif
 @BINPATH@/res/table-remove-row-hover.gif
 @BINPATH@/res/table-remove-row.gif
+@BINPATH@/res/text_caret.png
+@BINPATH@/res/text_caret@1.5x.png
+@BINPATH@/res/text_caret@2.25x.png
+@BINPATH@/res/text_caret@2x.png
+@BINPATH@/res/text_caret_tilt_left.png
+@BINPATH@/res/text_caret_tilt_left@1.5x.png
+@BINPATH@/res/text_caret_tilt_left@2.25x.png
+@BINPATH@/res/text_caret_tilt_left@2x.png
+@BINPATH@/res/text_caret_tilt_right.png
+@BINPATH@/res/text_caret_tilt_right@1.5x.png
+@BINPATH@/res/text_caret_tilt_right@2.25x.png
+@BINPATH@/res/text_caret_tilt_right@2x.png
 @BINPATH@/res/text_selection_handle.png
 @BINPATH@/res/text_selection_handle@1.5.png
 @BINPATH@/res/text_selection_handle@2.png
 @BINPATH@/res/grabber.gif
 #ifdef XP_MACOSX
 @BINPATH@/res/cursors/*
 #endif
 @BINPATH@/res/fonts/*
--- a/browser/base/content/test/general/browser_sanitizeDialog.js
+++ b/browser/base/content/test/general/browser_sanitizeDialog.js
@@ -13,16 +13,17 @@
  * test checks the UI of the dialog and makes sure it's correctly connected to
  * the sanitize timespan code.
  *
  * Some of this code, especially the history creation parts, was taken from
  * browser/base/content/test/general/browser_sanitize-timespans.js.
  */
 
 Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
+let {LoadContextInfo} = Cu.import("resource://gre/modules/LoadContextInfo.jsm", {});
 
 XPCOMUtils.defineLazyModuleGetter(this, "FormHistory",
                                   "resource://gre/modules/FormHistory.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "Downloads",
                                   "resource://gre/modules/Downloads.jsm");
 
 let tempScope = {};
 Cc["@mozilla.org/moz/jssubscript-loader;1"].getService(Ci.mozIJSSubScriptLoader)
@@ -562,68 +563,64 @@ var gAllTests = [
 
     // Give www.example.com privileges to store offline data
     var pm = Cc["@mozilla.org/permissionmanager;1"]
              .getService(Ci.nsIPermissionManager);
     pm.addFromPrincipal(principal, "offline-app", Ci.nsIPermissionManager.ALLOW_ACTION);
     pm.addFromPrincipal(principal, "offline-app", Ci.nsIOfflineCacheUpdateService.ALLOW_NO_WARN);
 
     // Store something to the offline cache
-    const nsICache = Components.interfaces.nsICache;
-    var cs = Components.classes["@mozilla.org/network/cache-service;1"]
-             .getService(Components.interfaces.nsICacheService);
-    var session = cs.createSession(URL + "/manifest", nsICache.STORE_OFFLINE, nsICache.STREAM_BASED);
+    var appcacheserv = Cc["@mozilla.org/network/application-cache-service;1"]
+                       .getService(Ci.nsIApplicationCacheService);
+    var appcachegroupid = appcacheserv.buildGroupID(makeURI(URL + "/manifest"), LoadContextInfo.default);
+    var appcache = appcacheserv.createApplicationCache(appcachegroupid);
+
+    var cacheserv = Cc["@mozilla.org/netwerk/cache-storage-service;1"]
+                    .getService(Ci.nsICacheStorageService);
+    var storage = cacheserv.appCacheStorage(LoadContextInfo.default, appcache);
 
     // Open the dialog
     let wh = new WindowHelper();
     wh.onload = function () {
       this.selectDuration(Sanitizer.TIMESPAN_EVERYTHING);
       // Show details
       this.toggleDetails();
       // Clear only offlineApps
       this.uncheckAllCheckboxes();
       this.checkPrefCheckbox("offlineApps", true);
       this.acceptDialog();
     };
     wh.onunload = function () {
       // Check if the cache has been deleted
       var size = -1;
       var visitor = {
-        visitDevice: function (deviceID, deviceInfo)
+        onCacheStorageInfo: function (aEntryCount, aConsumption, aCapacity, aDiskDirectory)
         {
-          if (deviceID == "offline")
-            size = deviceInfo.totalSize;
-
-          // Do not enumerate entries
-          return false;
-        },
-
-        visitEntry: function (deviceID, entryInfo)
-        {
-          // Do not enumerate entries.
-          return false;
+          size = aConsumption;
         }
       };
-      cs.visitEntries(visitor);
+      storage.asyncVisitStorage(visitor, false);
+      // Offline cache visit happens synchronously, since it's forwarded to the old code
       is(size, 0, "offline application cache entries evicted");
     };
 
     var cacheListener = {
-      onCacheEntryAvailable: function (entry, access, status) {
+      onCacheEntryCheck: function() { return Ci.nsICacheEntryOpenCallback.ENTRY_WANTED; },
+      onCacheEntryAvailable: function (entry, isnew, appcache, status) {
         is(status, Cr.NS_OK);
         var stream = entry.openOutputStream(0);
         var content = "content";
         stream.write(content, content.length);
         stream.close();
         entry.close();
         wh.open();
       }
     };
 
-    session.asyncOpenCacheEntry(URL, nsICache.ACCESS_READ_WRITE, cacheListener);
+    storage.asyncOpenURI(makeURI(URL), "", Ci.nsICacheStorage.OPEN_TRUNCATE, cacheListener);
   },
   function () {
     // Test for offline apps permission deletion
 
     // Prepare stuff, we will work with www.example.com
     var URL = "http://www.example.com";
 
     var ios = Cc["@mozilla.org/network/io-service;1"]
--- a/browser/components/preferences/advanced.js
+++ b/browser/components/preferences/advanced.js
@@ -324,40 +324,31 @@ var gAdvancedPane = {
                 .getService(Components.interfaces.nsICacheStorageService);
     cacheService.asyncGetDiskConsumption(this.observer);
   },
 
   // Retrieves the amount of space currently used by offline cache
   updateActualAppCacheSize: function ()
   {
     var visitor = {
-      visitDevice: function (deviceID, deviceInfo)
+      onCacheStorageInfo: function (aEntryCount, aConsumption, aCapacity, aDiskDirectory)
       {
-        if (deviceID == "offline") {
-          var actualSizeLabel = document.getElementById("actualAppCacheSize");
-          var sizeStrings = DownloadUtils.convertByteUnits(deviceInfo.totalSize);
-          var prefStrBundle = document.getElementById("bundlePreferences");
-          var sizeStr = prefStrBundle.getFormattedString("actualAppCacheSize", sizeStrings);
-          actualSizeLabel.value = sizeStr;
-        }
-        // Do not enumerate entries
-        return false;
-      },
-
-      visitEntry: function (deviceID, entryInfo)
-      {
-        // Do not enumerate entries.
-        return false;
+        var actualSizeLabel = document.getElementById("actualAppCacheSize");
+        var sizeStrings = DownloadUtils.convertByteUnits(aConsumption);
+        var prefStrBundle = document.getElementById("bundlePreferences");
+        var sizeStr = prefStrBundle.getFormattedString("actualAppCacheSize", sizeStrings);
+        actualSizeLabel.value = sizeStr;
       }
     };
 
     var cacheService =
-      Components.classes["@mozilla.org/network/cache-service;1"]
-                .getService(Components.interfaces.nsICacheService);
-    cacheService.visitEntries(visitor);
+      Components.classes["@mozilla.org/netwerk/cache-storage-service;1"]
+                .getService(Components.interfaces.nsICacheStorageService);
+    var storage = cacheService.appCacheStorage(LoadContextInfo.default, null);
+    storage.asyncVisitStorage(visitor, false);
   },
 
   updateCacheSizeUI: function (smartSizeEnabled)
   {
     document.getElementById("useCacheBefore").disabled = smartSizeEnabled;
     document.getElementById("cacheSize").disabled = smartSizeEnabled;
     document.getElementById("useCacheAfter").disabled = smartSizeEnabled;
   },
--- a/browser/components/preferences/in-content/advanced.js
+++ b/browser/components/preferences/in-content/advanced.js
@@ -309,40 +309,31 @@ var gAdvancedPane = {
                 .getService(Components.interfaces.nsICacheStorageService);
     cacheService.asyncGetDiskConsumption(this.observer);
   },
 
   // Retrieves the amount of space currently used by offline cache
   updateActualAppCacheSize: function ()
   {
     var visitor = {
-      visitDevice: function (deviceID, deviceInfo)
+      onCacheStorageInfo: function (aEntryCount, aConsumption, aCapacity, aDiskDirectory)
       {
-        if (deviceID == "offline") {
-          var actualSizeLabel = document.getElementById("actualAppCacheSize");
-          var sizeStrings = DownloadUtils.convertByteUnits(deviceInfo.totalSize);
-          var prefStrBundle = document.getElementById("bundlePreferences");
-          var sizeStr = prefStrBundle.getFormattedString("actualAppCacheSize", sizeStrings);
-          actualSizeLabel.textContent = sizeStr;
-        }
-        // Do not enumerate entries
-        return false;
-      },
-
-      visitEntry: function (deviceID, entryInfo)
-      {
-        // Do not enumerate entries.
-        return false;
+        var actualSizeLabel = document.getElementById("actualAppCacheSize");
+        var sizeStrings = DownloadUtils.convertByteUnits(aConsumption);
+        var prefStrBundle = document.getElementById("bundlePreferences");
+        var sizeStr = prefStrBundle.getFormattedString("actualAppCacheSize", sizeStrings);
+        actualSizeLabel.value = sizeStr;
       }
     };
 
     var cacheService =
-      Components.classes["@mozilla.org/network/cache-service;1"]
-                .getService(Components.interfaces.nsICacheService);
-    cacheService.visitEntries(visitor);
+      Components.classes["@mozilla.org/netwerk/cache-storage-service;1"]
+                .getService(Components.interfaces.nsICacheStorageService);
+    var storage = cacheService.appCacheStorage(LoadContextInfo.default, null);
+    storage.asyncVisitStorage(visitor, false);
   },
 
   updateCacheSizeUI: function (smartSizeEnabled)
   {
     document.getElementById("useCacheBefore").disabled = smartSizeEnabled;
     document.getElementById("cacheSize").disabled = smartSizeEnabled;
     document.getElementById("useCacheAfter").disabled = smartSizeEnabled;
   },
--- a/browser/components/translation/BingTranslator.jsm
+++ b/browser/components/translation/BingTranslator.jsm
@@ -151,19 +151,26 @@ this.BingTranslation.prototype = {
       // of items (from the number of items submitted), we can't use this chunk
       // because all items would be paired incorrectly.
       return false;
     }
 
     let error = false;
     for (let i = 0; i < len; i++) {
       try {
-        bingRequest.translationData[i][0].parseResult(
-          results[i].firstChild.nodeValue
-        );
+        let result = results[i].firstChild.nodeValue;
+        let root = bingRequest.translationData[i][0];
+
+        if (root.isSimpleRoot) {
+          // Workaround for Bing's service problem in which "&" chars in
+          // plain-text TranslationItems are double-escaped.
+          result = result.replace("&amp;", "&", "g");
+        }
+
+        root.parseResult(result);
       } catch (e) { error = true; }
     }
 
     return !error;
   },
 
   /**
    * This function will determine what is the data to be used for
--- a/browser/devtools/shared/AppCacheUtils.jsm
+++ b/browser/devtools/shared/AppCacheUtils.jsm
@@ -24,16 +24,17 @@
  */
 
 "use strict";
 
 const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
 
 let { XPCOMUtils } = Cu.import("resource://gre/modules/XPCOMUtils.jsm", {});
 let { Services }   = Cu.import("resource://gre/modules/Services.jsm", {});
+let { LoadContextInfo } = Cu.import("resource://gre/modules/LoadContextInfo.jsm", {});
 let { Promise: promise } = Cu.import("resource://gre/modules/Promise.jsm", {});
 
 this.EXPORTED_SYMBOLS = ["AppCacheUtils"];
 
 function AppCacheUtils(documentOrUri) {
   this._parseManifest = this._parseManifest.bind(this);
 
   if (documentOrUri) {
@@ -242,80 +243,58 @@ AppCacheUtils.prototype = {
 
   listEntries: function ACU_show(searchTerm) {
     if (!Services.prefs.getBoolPref("browser.cache.disk.enable")) {
       throw new Error(l10n.GetStringFromName("cacheDisabled"));
     }
 
     let entries = [];
 
-    Services.cache.visitEntries({
-      visitDevice: function(deviceID, deviceInfo) {
-        return true;
-      },
+    let appCacheStorage = Services.cache2.appCacheStorage(LoadContextInfo.default, null);
+    appCacheStorage.asyncVisitStorage({
+      onCacheStorageInfo: function() {},
 
-      visitEntry: function(deviceID, entryInfo) {
-        if (entryInfo.deviceID == "offline") {
-          let entry = {};
-          let lowerKey = entryInfo.key.toLowerCase();
+      onCacheEntryInfo: function(aURI, aIdEnhance, aDataSize, aFetchCount, aLastModifiedTime, aExpirationTime) {
+        let lowerKey = aURI.asciiSpec.toLowerCase();
 
-          if (searchTerm && lowerKey.indexOf(searchTerm.toLowerCase()) == -1) {
-            return true;
-          }
+        if (searchTerm && lowerKey.indexOf(searchTerm.toLowerCase()) == -1) {
+          return;
+        }
 
-          for (let [key, value] of Iterator(entryInfo)) {
-            if (key == "QueryInterface") {
-              continue;
-            }
-            if (key == "clientID") {
-              entry.key = entryInfo.key;
-            }
-            if (key == "expirationTime" || key == "lastFetched" || key == "lastModified") {
-              value = new Date(value * 1000);
-            }
-            entry[key] = value;
-          }
-          entries.push(entry);
+        if (aIdEnhance) {
+          aIdEnhance += ":";
         }
+
+        let entry = {
+          "deviceID": "offline",
+          "key": aIdEnhance + aURI.asciiSpec,
+          "fetchCount": aFetchCount,
+          "lastFetched": null,
+          "lastModified": new Date(aLastModifiedTime * 1000),
+          "expirationTime": new Date(aExpirationTime * 1000),
+          "dataSize": aDataSize
+        };
+
+        entries.push(entry);
         return true;
       }
-    });
+    }, true);
 
     if (entries.length === 0) {
       throw new Error(l10n.GetStringFromName("noResults"));
     }
     return entries;
   },
 
   viewEntry: function ACU_viewEntry(key) {
-    let uri;
-
-    Services.cache.visitEntries({
-      visitDevice: function(deviceID, deviceInfo) {
-        return true;
-      },
-
-      visitEntry: function(deviceID, entryInfo) {
-        if (entryInfo.deviceID == "offline" && entryInfo.key == key) {
-          uri = "about:cache-entry?client=" + entryInfo.clientID +
-                "&sb=1&key=" + entryInfo.key;
-          return false;
-        }
-        return true;
-      }
-    });
-
-    if (uri) {
-      let wm = Cc["@mozilla.org/appshell/window-mediator;1"]
-                 .getService(Ci.nsIWindowMediator);
-      let win = wm.getMostRecentWindow("navigator:browser");
-      win.gBrowser.selectedTab = win.gBrowser.addTab(uri);
-    } else {
-      return l10n.GetStringFromName("entryNotFound");
-    }
+    let wm = Cc["@mozilla.org/appshell/window-mediator;1"]
+               .getService(Ci.nsIWindowMediator);
+    let win = wm.getMostRecentWindow("navigator:browser");
+    win.gBrowser.selectedTab = win.gBrowser.addTab(
+      "about:cache-entry?storage=appcache&context=&eid=&uri=" + key);
   },
 
   clearAll: function ACU_clearAll() {
     Services.cache.evictEntries(Ci.nsICache.STORE_OFFLINE);
   },
 
   _getManifestURI: function ACU__getManifestURI() {
     let deferred = promise.defer();
--- a/configure.in
+++ b/configure.in
@@ -6318,27 +6318,23 @@ fi
 if test "$OS_ARCH" = "WINNT" -a -z "$MAKENSISU" -a -n "$CROSS_COMPILE"; then
     MOZ_WEBAPP_RUNTIME=
 fi
 AC_SUBST(MOZ_WEBAPP_RUNTIME)
 if test "$MOZ_WEBAPP_RUNTIME"; then
     AC_DEFINE(MOZ_WEBAPP_RUNTIME)
 fi
 
-AC_MSG_CHECKING([for tar archiver])
 AC_CHECK_PROGS(TAR, gnutar gtar tar, "")
 if test -z "$TAR"; then
     AC_MSG_ERROR([no tar archiver found in \$PATH])
 fi
-AC_MSG_RESULT([$TAR])
 AC_SUBST(TAR)
 
-AC_MSG_CHECKING([for wget])
 AC_CHECK_PROGS(WGET, wget, "")
-AC_MSG_RESULT([$WGET])
 AC_SUBST(WGET)
 
 dnl ========================================================
 dnl Signing
 dnl ========================================================
 
 if test -n "$MOZ_SIGN_CMD"; then
     AC_DEFINE(MOZ_SIGNING)
--- a/content/base/src/nsCCUncollectableMarker.cpp
+++ b/content/base/src/nsCCUncollectableMarker.cpp
@@ -435,16 +435,21 @@ struct TraceClosure
 };
 
 static PLDHashOperator
 TraceActiveWindowGlobal(const uint64_t& aId, nsGlobalWindow*& aWindow, void* aClosure)
 {
   if (aWindow->GetDocShell() && aWindow->IsOuterWindow()) {
     TraceClosure* closure = static_cast<TraceClosure*>(aClosure);
     aWindow->TraceGlobalJSObject(closure->mTrc);
+    EventListenerManager* elm = aWindow->GetExistingListenerManager();
+    if (elm) {
+      elm->TraceListeners(closure->mTrc);
+    }
+
 #ifdef MOZ_XUL
     nsIDocument* doc = aWindow->GetExtantDoc();
     if (doc && doc->IsXUL()) {
       XULDocument* xulDoc = static_cast<XULDocument*>(doc);
       xulDoc->TraceProtos(closure->mTrc, closure->mGCNumber);
     }
 #endif
   }
--- a/content/base/src/nsDocument.cpp
+++ b/content/base/src/nsDocument.cpp
@@ -3946,27 +3946,16 @@ nsDocument::InsertChildAt(nsIContent* aK
   if (aKid->IsElement() && GetRootElement()) {
     NS_ERROR("Inserting element child when we already have one");
     return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR;
   }
 
   return doInsertChildAt(aKid, aIndex, aNotify, mChildren);
 }
 
-nsresult
-nsDocument::AppendChildTo(nsIContent* aKid, bool aNotify)
-{
-  // Make sure to _not_ call the subclass InsertChildAt here.  If
-  // subclasses wanted to hook into this stuff, they would have
-  // overridden AppendChildTo.
-  // XXXbz maybe this should just be a non-virtual method on nsINode?
-  // Feels that way to me...
-  return nsDocument::InsertChildAt(aKid, GetChildCount(), aNotify);
-}
-
 void
 nsDocument::RemoveChildAt(uint32_t aIndex, bool aNotify)
 {
   nsCOMPtr<nsIContent> oldKid = GetChildAt(aIndex);
   if (!oldKid) {
     return;
   }
 
--- a/content/base/src/nsDocument.h
+++ b/content/base/src/nsDocument.h
@@ -884,17 +884,16 @@ public:
   // nsINode
   virtual bool IsNodeOfType(uint32_t aFlags) const MOZ_OVERRIDE;
   virtual nsIContent *GetChildAt(uint32_t aIndex) const MOZ_OVERRIDE;
   virtual nsIContent * const * GetChildArray(uint32_t* aChildCount) const MOZ_OVERRIDE;
   virtual int32_t IndexOf(const nsINode* aPossibleChild) const MOZ_OVERRIDE;
   virtual uint32_t GetChildCount() const MOZ_OVERRIDE;
   virtual nsresult InsertChildAt(nsIContent* aKid, uint32_t aIndex,
                                  bool aNotify) MOZ_OVERRIDE;
-  virtual nsresult AppendChildTo(nsIContent* aKid, bool aNotify);
   virtual void RemoveChildAt(uint32_t aIndex, bool aNotify) MOZ_OVERRIDE;
   virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const MOZ_OVERRIDE
   {
     return NS_ERROR_NOT_IMPLEMENTED;
   }
 
   // nsIRadioGroupContainer
   NS_IMETHOD WalkRadioGroup(const nsAString& aName,
--- a/content/base/src/nsRange.cpp
+++ b/content/base/src/nsRange.cpp
@@ -18,17 +18,16 @@
 #include "nsIDocument.h"
 #include "nsIDOMText.h"
 #include "nsError.h"
 #include "nsIContentIterator.h"
 #include "nsIDOMNodeList.h"
 #include "nsGkAtoms.h"
 #include "nsContentUtils.h"
 #include "nsGenericDOMDataNode.h"
-#include "nsLayoutUtils.h"
 #include "nsTextFrame.h"
 #include "nsFontFaceList.h"
 #include "mozilla/dom/DocumentFragment.h"
 #include "mozilla/dom/DocumentType.h"
 #include "mozilla/dom/RangeBinding.h"
 #include "mozilla/dom/DOMRect.h"
 #include "mozilla/dom/ShadowRoot.h"
 #include "mozilla/Telemetry.h"
@@ -2787,20 +2786,21 @@ static nsresult GetPartialTextRect(nsLay
         ExtractRectFromOffset(f, relativeTo, aEndOffset, &r, !rtl);
       }
       aCallback->AddRect(r);
     }
   }
   return NS_OK;
 }
 
-static void CollectClientRects(nsLayoutUtils::RectCallback* aCollector,
-                               nsRange* aRange,
-                               nsINode* aStartParent, int32_t aStartOffset,
-                               nsINode* aEndParent, int32_t aEndOffset)
+/* static */ void
+nsRange::CollectClientRects(nsLayoutUtils::RectCallback* aCollector,
+                            nsRange* aRange,
+                            nsINode* aStartParent, int32_t aStartOffset,
+                            nsINode* aEndParent, int32_t aEndOffset)
 {
   // Hold strong pointers across the flush
   nsCOMPtr<nsINode> startContainer = aStartParent;
   nsCOMPtr<nsINode> endContainer = aEndParent;
 
   // Flush out layout so our frames are up to date.
   if (!aStartParent->IsInDoc()) {
     return;
@@ -2821,17 +2821,17 @@ static void CollectClientRects(nsLayoutU
   if (iter.IsDone()) {
     // the range is collapsed, only continue if the cursor is in a text node
     nsCOMPtr<nsIContent> content = do_QueryInterface(aStartParent);
     if (content && content->IsNodeOfType(nsINode::eTEXT)) {
       nsTextFrame* textFrame = GetTextFrameForContent(content);
       if (textFrame) {
         int32_t outOffset;
         nsIFrame* outFrame;
-        textFrame->GetChildFrameContainingOffset(aStartOffset, false, 
+        textFrame->GetChildFrameContainingOffset(aStartOffset, false,
           &outOffset, &outFrame);
         if (outFrame) {
            nsIFrame* relativeTo =
              nsLayoutUtils::GetContainingBlockForClientRect(outFrame);
            nsRect r(outFrame->GetOffsetTo(relativeTo), outFrame->GetSize());
            ExtractRectFromOffset(outFrame, relativeTo, aStartOffset, &r, false);
            r.width = 0;
            aCollector->AddRect(r);
--- a/content/base/src/nsRange.h
+++ b/content/base/src/nsRange.h
@@ -10,16 +10,17 @@
 #ifndef nsRange_h___
 #define nsRange_h___
 
 #include "nsIDOMRange.h"
 #include "nsCOMPtr.h"
 #include "nsINode.h"
 #include "nsIDocument.h"
 #include "nsIDOMNode.h"
+#include "nsLayoutUtils.h"
 #include "prmon.h"
 #include "nsStubMutationObserver.h"
 #include "nsWrapperCache.h"
 #include "mozilla/Attributes.h"
 
 namespace mozilla {
 class ErrorResult;
 namespace dom {
@@ -249,16 +250,21 @@ public:
  *****************************************************************************/
   static nsresult CompareNodeToRange(nsINode* aNode, nsRange* aRange,
                                      bool *outNodeBefore,
                                      bool *outNodeAfter);
 
   static bool IsNodeSelected(nsINode* aNode, uint32_t aStartOffset,
                              uint32_t aEndOffset);
 
+  static void CollectClientRects(nsLayoutUtils::RectCallback* aCollector,
+                                 nsRange* aRange,
+                                 nsINode* aStartParent, int32_t aStartOffset,
+                                 nsINode* aEndParent, int32_t aEndOffset);
+
   typedef nsTHashtable<nsPtrHashKey<nsRange> > RangeHashTable;
 protected:
   void RegisterCommonAncestor(nsINode* aNode);
   void UnregisterCommonAncestor(nsINode* aNode);
   nsINode* IsValidBoundary(nsINode* aNode);
 
   // CharacterDataChanged set aNotInsertedYet to true to disable an assertion
   // and suppress re-registering a range common ancestor node since
--- a/content/base/src/nsStyleLinkElement.cpp
+++ b/content/base/src/nsStyleLinkElement.cpp
@@ -10,16 +10,17 @@
  * stylesheets (<style>, <link>, processing instructions, etc).
  */
 
 #include "nsStyleLinkElement.h"
 
 #include "mozilla/css/Loader.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/ShadowRoot.h"
+#include "mozilla/Preferences.h"
 #include "nsCSSStyleSheet.h"
 #include "nsIContent.h"
 #include "nsIDocument.h"
 #include "nsIDOMComment.h"
 #include "nsIDOMNode.h"
 #include "nsIDOMStyleSheet.h"
 #include "nsNetUtil.h"
 #include "nsUnicharUtils.h"
@@ -115,29 +116,44 @@ nsStyleLinkElement::OverrideBaseURI(nsIU
 }
 
 /* virtual */ void
 nsStyleLinkElement::SetLineNumber(uint32_t aLineNumber)
 {
   mLineNumber = aLineNumber;
 }
 
+/* static */ bool
+nsStyleLinkElement::IsImportEnabled()
+{
+  static bool sAdded = false;
+  static bool sImportEnabled;
+  if (!sAdded) {
+    // This part runs only once because of the static flag.
+    Preferences::AddBoolVarCache(&sImportEnabled,
+                                 "dom.webcomponents.enabled",
+                                 false);
+    sAdded = true;
+  }
+  return sImportEnabled;
+}
+
 static uint32_t ToLinkMask(const nsAString& aLink)
 { 
   if (aLink.EqualsLiteral("prefetch"))
     return nsStyleLinkElement::ePREFETCH;
   else if (aLink.EqualsLiteral("dns-prefetch"))
     return nsStyleLinkElement::eDNS_PREFETCH;
   else if (aLink.EqualsLiteral("stylesheet"))
     return nsStyleLinkElement::eSTYLESHEET;
   else if (aLink.EqualsLiteral("next"))
     return nsStyleLinkElement::eNEXT;
   else if (aLink.EqualsLiteral("alternate"))
     return nsStyleLinkElement::eALTERNATE;
-  else if (aLink.EqualsLiteral("import"))
+  else if (aLink.EqualsLiteral("import") && nsStyleLinkElement::IsImportEnabled())
     return nsStyleLinkElement::eHTMLIMPORT;
   else 
     return 0;
 }
 
 uint32_t nsStyleLinkElement::ParseLinkTypes(const nsAString& aTypes)
 {
   uint32_t linkMask = 0;
--- a/content/base/src/nsStyleLinkElement.h
+++ b/content/base/src/nsStyleLinkElement.h
@@ -59,16 +59,18 @@ public:
     eNEXT =         0x00000008,
     eALTERNATE =    0x00000010,
     eHTMLIMPORT =   0x00000020
   };
 
   // The return value is a bitwise or of 0 or more RelValues
   static uint32_t ParseLinkTypes(const nsAString& aTypes);
 
+  static bool IsImportEnabled();
+  
   void UpdateStyleSheetInternal()
   {
     UpdateStyleSheetInternal(nullptr, nullptr);
   }
 protected:
   /**
    * @param aOldDocument should be non-null only if we're updating because we
    *                     removed the node from the document.
--- a/content/canvas/src/WebGLBuffer.cpp
+++ b/content/canvas/src/WebGLBuffer.cpp
@@ -67,16 +67,21 @@ WebGLBuffer::SizeOfIncludingThis(mozilla
 bool
 WebGLBuffer::Validate(GLenum type, uint32_t max_allowed,
                       size_t first, size_t count,
                       uint32_t* out_upperBound)
 {
     return mCache->Validate(type, max_allowed, first, count, out_upperBound);
 }
 
+bool
+WebGLBuffer::IsElementArrayUsedWithMultipleTypes() const
+{
+    return mCache->BeenUsedWithMultipleTypes();
+}
 
 JSObject*
 WebGLBuffer::WrapObject(JSContext *cx) {
     return dom::WebGLBufferBinding::Wrap(cx, this);
 }
 
 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(WebGLBuffer)
 
--- a/content/canvas/src/WebGLBuffer.h
+++ b/content/canvas/src/WebGLBuffer.h
@@ -44,16 +44,18 @@ public:
 
     bool ElementArrayCacheBufferData(const void* ptr, size_t buffer_size_in_bytes);
 
     void ElementArrayCacheBufferSubData(size_t pos, const void* ptr, size_t update_size_in_bytes);
 
     bool Validate(GLenum type, uint32_t max_allowed, size_t first, size_t count,
                   uint32_t* out_upperBound);
 
+    bool IsElementArrayUsedWithMultipleTypes() const;
+
     WebGLContext *GetParentObject() const {
         return Context();
     }
 
     virtual JSObject* WrapObject(JSContext *cx) MOZ_OVERRIDE;
 
     NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLBuffer)
     NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WebGLBuffer)
--- a/content/canvas/src/WebGLContext.h
+++ b/content/canvas/src/WebGLContext.h
@@ -208,16 +208,24 @@ public:
     void ErrorInvalidEnum(const char *fmt = 0, ...);
     void ErrorInvalidOperation(const char *fmt = 0, ...);
     void ErrorInvalidValue(const char *fmt = 0, ...);
     void ErrorInvalidFramebufferOperation(const char *fmt = 0, ...);
     void ErrorInvalidEnumInfo(const char *info, GLenum enumvalue);
     void ErrorOutOfMemory(const char *fmt = 0, ...);
 
     const char *ErrorName(GLenum error);
+
+    /**
+     * Return displayable name for GLenum.
+     * This version is like gl::GLenumToStr but with out the GL_ prefix to
+     * keep consistency with how errors are reported from WebGL.
+     */
+    static const char *EnumName(GLenum glenum);
+
     bool IsTextureFormatCompressed(GLenum format);
 
     void DummyFramebufferOperation(const char *info);
 
     WebGLTexture* activeBoundTextureForTarget(GLenum target) const {
         MOZ_ASSERT(!IsTextureBinding(target));
         return target == LOCAL_GL_TEXTURE_2D ? mBound2DTextures[mActiveTexture]
                                              : mBoundCubeMapTextures[mActiveTexture];
--- a/content/canvas/src/WebGLContextDraw.cpp
+++ b/content/canvas/src/WebGLContextDraw.cpp
@@ -255,16 +255,24 @@ WebGLContext::DrawElements_check(GLsizei
         return false;
     }
 
     if (uint32_t(primcount) > mMaxFetchedInstances) {
         ErrorInvalidOperation("%s: bound instance attribute buffers do not have sufficient size for given primcount", info);
         return false;
     }
 
+    // Bug 1008310 - Check if buffer has been used with a different previous type
+    if (elemArrayBuffer.IsElementArrayUsedWithMultipleTypes()) {
+        GenerateWarning("%s: bound element array buffer previously used with a type other than "
+                        "%s, this will affect performance.",
+                        info,
+                        WebGLContext::EnumName(type));
+    }
+
     MakeContextCurrent();
 
     if (mBoundFramebuffer) {
         if (!mBoundFramebuffer->CheckAndInitializeAttachments()) {
             ErrorInvalidFramebufferOperation("%s: incomplete framebuffer", info);
             return false;
         }
     } else {
--- a/content/canvas/src/WebGLContextUtils.cpp
+++ b/content/canvas/src/WebGLContextUtils.cpp
@@ -357,16 +357,74 @@ WebGLContext::ErrorName(GLenum error)
         case LOCAL_GL_NO_ERROR:
             return "NO_ERROR";
         default:
             MOZ_ASSERT(false);
             return "[unknown WebGL error!]";
     }
 }
 
+const char*
+WebGLContext::EnumName(GLenum glenum)
+{
+    switch (glenum) {
+#define XX(x) case LOCAL_GL_##x: return #x
+        XX(ALPHA);
+        XX(ATC_RGB);
+        XX(ATC_RGBA_EXPLICIT_ALPHA);
+        XX(ATC_RGBA_INTERPOLATED_ALPHA);
+        XX(COMPRESSED_RGBA_PVRTC_2BPPV1);
+        XX(COMPRESSED_RGBA_PVRTC_4BPPV1);
+        XX(COMPRESSED_RGBA_S3TC_DXT1_EXT);
+        XX(COMPRESSED_RGBA_S3TC_DXT3_EXT);
+        XX(COMPRESSED_RGBA_S3TC_DXT5_EXT);
+        XX(COMPRESSED_RGB_PVRTC_2BPPV1);
+        XX(COMPRESSED_RGB_PVRTC_4BPPV1);
+        XX(COMPRESSED_RGB_S3TC_DXT1_EXT);
+        XX(DEPTH_COMPONENT);
+        XX(DEPTH_COMPONENT16);
+        XX(DEPTH_COMPONENT32);
+        XX(DEPTH_STENCIL);
+        XX(DEPTH24_STENCIL8);
+        XX(ETC1_RGB8_OES);
+        XX(FLOAT);
+        XX(HALF_FLOAT);
+        XX(LUMINANCE);
+        XX(LUMINANCE_ALPHA);
+        XX(RGB);
+        XX(RGB16F);
+        XX(RGB32F);
+        XX(RGBA);
+        XX(RGBA16F);
+        XX(RGBA32F);
+        XX(SRGB);
+        XX(SRGB_ALPHA);
+        XX(TEXTURE_2D);
+        XX(TEXTURE_3D);
+        XX(TEXTURE_CUBE_MAP);
+        XX(TEXTURE_CUBE_MAP_NEGATIVE_X);
+        XX(TEXTURE_CUBE_MAP_NEGATIVE_Y);
+        XX(TEXTURE_CUBE_MAP_NEGATIVE_Z);
+        XX(TEXTURE_CUBE_MAP_POSITIVE_X);
+        XX(TEXTURE_CUBE_MAP_POSITIVE_Y);
+        XX(TEXTURE_CUBE_MAP_POSITIVE_Z);
+        XX(UNSIGNED_BYTE);
+        XX(UNSIGNED_INT);
+        XX(UNSIGNED_INT_24_8);
+        XX(UNSIGNED_SHORT);
+        XX(UNSIGNED_SHORT_4_4_4_4);
+        XX(UNSIGNED_SHORT_5_5_5_1);
+        XX(UNSIGNED_SHORT_5_6_5);
+#undef XX
+    }
+
+    return "[Unknown enum name]";
+}
+
+
 bool
 WebGLContext::IsTextureFormatCompressed(GLenum format)
 {
     switch (format) {
         case LOCAL_GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
         case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
         case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
         case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
--- a/content/canvas/src/WebGLContextValidate.cpp
+++ b/content/canvas/src/WebGLContextValidate.cpp
@@ -77,85 +77,23 @@ InfoFrom(WebGLTexImageFunc func)
     case WebGLTexImageFunc::CompTexSubImage: return "compressedTexSubImage2D";
     default:
         MOZ_ASSERT(false, "Missing case for WebGLTexImageSource");
         return "(error)";
     }
 }
 
 /**
- * Return displayable name for GLenum.
- * This version is like gl::GLenumToStr but with out the GL_ prefix to
- * keep consistency with how errors are reported from WebGL.
- */
-static const char*
-NameFrom(GLenum glenum)
-{
-    switch (glenum) {
-#define XX(x) case LOCAL_GL_##x: return #x
-        XX(ALPHA);
-        XX(ATC_RGB);
-        XX(ATC_RGBA_EXPLICIT_ALPHA);
-        XX(ATC_RGBA_INTERPOLATED_ALPHA);
-        XX(COMPRESSED_RGBA_PVRTC_2BPPV1);
-        XX(COMPRESSED_RGBA_PVRTC_4BPPV1);
-        XX(COMPRESSED_RGBA_S3TC_DXT1_EXT);
-        XX(COMPRESSED_RGBA_S3TC_DXT3_EXT);
-        XX(COMPRESSED_RGBA_S3TC_DXT5_EXT);
-        XX(COMPRESSED_RGB_PVRTC_2BPPV1);
-        XX(COMPRESSED_RGB_PVRTC_4BPPV1);
-        XX(COMPRESSED_RGB_S3TC_DXT1_EXT);
-        XX(DEPTH_COMPONENT);
-        XX(DEPTH_COMPONENT16);
-        XX(DEPTH_COMPONENT32);
-        XX(DEPTH_STENCIL);
-        XX(DEPTH24_STENCIL8);
-        XX(ETC1_RGB8_OES);
-        XX(FLOAT);
-        XX(HALF_FLOAT);
-        XX(LUMINANCE);
-        XX(LUMINANCE_ALPHA);
-        XX(RGB);
-        XX(RGB16F);
-        XX(RGB32F);
-        XX(RGBA);
-        XX(RGBA16F);
-        XX(RGBA32F);
-        XX(SRGB);
-        XX(SRGB_ALPHA);
-        XX(TEXTURE_2D);
-        XX(TEXTURE_3D);
-        XX(TEXTURE_CUBE_MAP);
-        XX(TEXTURE_CUBE_MAP_NEGATIVE_X);
-        XX(TEXTURE_CUBE_MAP_NEGATIVE_Y);
-        XX(TEXTURE_CUBE_MAP_NEGATIVE_Z);
-        XX(TEXTURE_CUBE_MAP_POSITIVE_X);
-        XX(TEXTURE_CUBE_MAP_POSITIVE_Y);
-        XX(TEXTURE_CUBE_MAP_POSITIVE_Z);
-        XX(UNSIGNED_BYTE);
-        XX(UNSIGNED_INT);
-        XX(UNSIGNED_INT_24_8);
-        XX(UNSIGNED_SHORT);
-        XX(UNSIGNED_SHORT_4_4_4_4);
-        XX(UNSIGNED_SHORT_5_5_5_1);
-        XX(UNSIGNED_SHORT_5_6_5);
-#undef XX
-    }
-
-    return nullptr;
-}
-
-/**
- * Same as ErrorInvalidEnum but uses NameFrom to print displayable
+ * Same as ErrorInvalidEnum but uses WebGLContext::EnumName to print displayable
  * name for \a glenum.
  */
 static void
 ErrorInvalidEnumWithName(WebGLContext* ctx, const char* msg, GLenum glenum, WebGLTexImageFunc func)
 {
-    const char* name = NameFrom(glenum);
+    const char* name = WebGLContext::EnumName(glenum);
     if (name)
         ctx->ErrorInvalidEnum("%s: %s %s", InfoFrom(func), msg, name);
     else
         ctx->ErrorInvalidEnum("%s: %s 0x%04X", InfoFrom(func), msg, glenum);
 }
 
 /**
  * Return true if the format is valid for source calls.
@@ -599,75 +537,75 @@ WebGLContext::ValidateTexImageFormat(GLe
 
     /* WEBGL_depth_texture added formats */
     if (format == LOCAL_GL_DEPTH_COMPONENT ||
         format == LOCAL_GL_DEPTH_STENCIL)
     {
         bool validFormat = IsExtensionEnabled(WebGLExtensionID::WEBGL_depth_texture);
         if (!validFormat)
             ErrorInvalidEnum("%s: invalid format %s: need WEBGL_depth_texture enabled",
-                             InfoFrom(func), NameFrom(format));
+                             InfoFrom(func), WebGLContext::EnumName(format));
         return validFormat;
     }
 
     /* EXT_sRGB added formats */
     if (format == LOCAL_GL_SRGB ||
         format == LOCAL_GL_SRGB_ALPHA)
     {
         bool validFormat = IsExtensionEnabled(WebGLExtensionID::EXT_sRGB);
         if (!validFormat)
             ErrorInvalidEnum("%s: invalid format %s: need EXT_sRGB enabled",
-                             InfoFrom(func), NameFrom(format));
+                             InfoFrom(func), WebGLContext::EnumName(format));
         return validFormat;
     }
 
     /* WEBGL_compressed_texture_atc added formats */
     if (format == LOCAL_GL_ATC_RGB ||
         format == LOCAL_GL_ATC_RGBA_EXPLICIT_ALPHA ||
         format == LOCAL_GL_ATC_RGBA_INTERPOLATED_ALPHA)
     {
         bool validFormat = IsExtensionEnabled(WebGLExtensionID::WEBGL_compressed_texture_atc);
         if (!validFormat)
             ErrorInvalidEnum("%s: invalid format %s: need WEBGL_compressed_texture_atc enabled",
-                             InfoFrom(func), NameFrom(format));
+                             InfoFrom(func), WebGLContext::EnumName(format));
         return validFormat;
     }
 
     // WEBGL_compressed_texture_etc1
     if (format == LOCAL_GL_ETC1_RGB8_OES) {
         bool validFormat = IsExtensionEnabled(WebGLExtensionID::WEBGL_compressed_texture_etc1);
         if (!validFormat)
             ErrorInvalidEnum("%s: invalid format %s: need WEBGL_compressed_texture_etc1 enabled",
-                             InfoFrom(func), NameFrom(format));
+                             InfoFrom(func), WebGLContext::EnumName(format));
         return validFormat;
     }
 
 
     if (format == LOCAL_GL_COMPRESSED_RGB_PVRTC_2BPPV1 ||
         format == LOCAL_GL_COMPRESSED_RGB_PVRTC_4BPPV1 ||
         format == LOCAL_GL_COMPRESSED_RGBA_PVRTC_2BPPV1 ||
         format == LOCAL_GL_COMPRESSED_RGBA_PVRTC_4BPPV1)
     {
         bool validFormat = IsExtensionEnabled(WebGLExtensionID::WEBGL_compressed_texture_pvrtc);
         if (!validFormat)
             ErrorInvalidEnum("%s: invalid format %s: need WEBGL_compressed_texture_pvrtc enabled",
-                             InfoFrom(func), NameFrom(format));
+                             InfoFrom(func), WebGLContext::EnumName(format));
         return validFormat;
     }
 
 
     if (format == LOCAL_GL_COMPRESSED_RGB_S3TC_DXT1_EXT ||
         format == LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT1_EXT ||
         format == LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT3_EXT ||
         format == LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT5_EXT)
     {
         bool validFormat = IsExtensionEnabled(WebGLExtensionID::WEBGL_compressed_texture_s3tc);
         if (!validFormat)
             ErrorInvalidEnum("%s: invalid format %s: need WEBGL_compressed_texture_s3tc enabled",
-                             InfoFrom(func), NameFrom(format));
+                             InfoFrom(func), WebGLContext::EnumName(format));
         return validFormat;
     }
 
     ErrorInvalidEnumWithName(this, "invalid format", format, func);
 
     return false;
 }
 
@@ -711,38 +649,38 @@ WebGLContext::ValidateTexImageType(GLenu
         return true;
     }
 
     /* OES_texture_float added types */
     if (type == LOCAL_GL_FLOAT) {
         bool validType = IsExtensionEnabled(WebGLExtensionID::OES_texture_float);
         if (!validType)
             ErrorInvalidEnum("%s: invalid type %s: need OES_texture_float enabled",
-                             InfoFrom(func), NameFrom(type));
+                             InfoFrom(func), WebGLContext::EnumName(type));
         return validType;
     }
 
     /* OES_texture_half_float add types */
     if (type == LOCAL_GL_HALF_FLOAT_OES) {
         bool validType = IsExtensionEnabled(WebGLExtensionID::OES_texture_half_float);
         if (!validType)
             ErrorInvalidEnum("%s: invalid type %s: need OES_texture_half_float enabled",
-                             InfoFrom(func), NameFrom(type));
+                             InfoFrom(func), WebGLContext::EnumName(type));
         return validType;
     }
 
     /* WEBGL_depth_texture added types */
     if (type == LOCAL_GL_UNSIGNED_SHORT ||
         type == LOCAL_GL_UNSIGNED_INT ||
         type == LOCAL_GL_UNSIGNED_INT_24_8)
     {
         bool validType = IsExtensionEnabled(WebGLExtensionID::WEBGL_depth_texture);
         if (!validType)
             ErrorInvalidEnum("%s: invalid type %s: need WEBGL_depth_texture enabled",
-                             InfoFrom(func), NameFrom(type));
+                             InfoFrom(func), WebGLContext::EnumName(type));
         return validType;
     }
 
     ErrorInvalidEnumWithName(this, "invalid type", type, func);
     return false;
 }
 
 /**
@@ -1239,17 +1177,17 @@ WebGLContext::ValidateTexImageFormatAndT
         MOZ_ASSERT(false, "Unexpected format and type combo. How'd this happen?");
         validCombo = false;
         // Fall through to return an InvalidOperations. This will alert us to the
         // unexpected case that needs fixing in builds without asserts.
     }
 
     if (!validCombo)
         ErrorInvalidOperation("%s: invalid combination of format %s and type %s",
-                              InfoFrom(func), NameFrom(format), NameFrom(type));
+                              InfoFrom(func), WebGLContext::EnumName(format), WebGLContext::EnumName(type));
 
     return validCombo;
 }
 
 /**
  * Return true if format, type and jsArrayType are a valid combination.
  * Also returns the size for texel of format and type (in bytes) via
  * \a texelSize.
@@ -1361,24 +1299,24 @@ WebGLContext::ValidateTexImage(GLuint di
     /* 5.14.8 Texture objects - WebGL Spec.
      *   "If an attempt is made to call these functions with no
      *    WebGLTexture bound (see above), an INVALID_OPERATION error
      *    is generated."
      */
     WebGLTexture* tex = activeBoundTextureForTarget(target);
     if (!tex) {
         ErrorInvalidOperation("%s: no texture is bound to target %s",
-                              info, NameFrom(target));
+                              info, WebGLContext::EnumName(target));
         return false;
     }
 
     if (IsSubFunc(func)) {
         if (!tex->HasImageInfoAt(target, level)) {
             ErrorInvalidOperation("%s: no texture image previously defined for target %s at level %d",
-                                  info, NameFrom(target), level);
+                                  info, WebGLContext::EnumName(target), level);
             return false;
         }
 
         const WebGLTexture::ImageInfo& imageInfo = tex->ImageInfoAt(target, level);
         if (!ValidateTexSubImageSize(xoffset, yoffset, zoffset,
                                      width, height, depth,
                                      imageInfo.Width(), imageInfo.Height(), 0,
                                      func))
@@ -1399,24 +1337,24 @@ WebGLContext::ValidateTexImage(GLuint di
     }
 
     /* Additional checks for depth textures */
     if (target != LOCAL_GL_TEXTURE_2D &&
         (format == LOCAL_GL_DEPTH_COMPONENT ||
          format == LOCAL_GL_DEPTH_STENCIL))
     {
         ErrorInvalidOperation("%s: with format of %s target must be TEXTURE_2D",
-                              info, NameFrom(format));
+                              info, WebGLContext::EnumName(format));
         return false;
     }
 
     /* Additional checks for compressed textures */
     if (!IsAllowedFromSource(format, func)) {
         ErrorInvalidOperation("%s: Invalid format %s for this operation",
-                              info, NameFrom(format));
+                              info, WebGLContext::EnumName(format));
         return false;
     }
 
     /* Parameters are OK */
     return true;
 }
 
 bool
--- a/content/canvas/src/WebGLElementArrayCache.cpp
+++ b/content/canvas/src/WebGLElementArrayCache.cpp
@@ -599,9 +599,21 @@ WebGLElementArrayCache::SizeOfIncludingT
   size_t uint32TreeSize = mUint32Tree ? mUint32Tree->SizeOfIncludingThis(aMallocSizeOf) : 0;
   return aMallocSizeOf(this) +
           mBytes.SizeOfExcludingThis(aMallocSizeOf) +
           uint8TreeSize +
           uint16TreeSize +
           uint32TreeSize;
 }
 
+bool
+WebGLElementArrayCache::BeenUsedWithMultipleTypes() const
+{
+  // C++ Standard ($4.7)
+  // "If the source type is bool, the value false is converted to zero and
+  //  the value true is converted to one."
+  const int num_types_used = (mUint8Tree  != nullptr) +
+                             (mUint16Tree != nullptr) +
+                             (mUint32Tree != nullptr);
+  return num_types_used > 1;
+}
+
 } // end namespace mozilla
--- a/content/canvas/src/WebGLElementArrayCache.h
+++ b/content/canvas/src/WebGLElementArrayCache.h
@@ -42,16 +42,18 @@ public:
   T Element(size_t i) const { return Elements<T>()[i]; }
 
   WebGLElementArrayCache();
 
   ~WebGLElementArrayCache();
 
   size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
 
+  bool BeenUsedWithMultipleTypes() const;
+
 private:
 
   template<typename T>
   bool Validate(uint32_t maxAllowed, size_t first, size_t count,
                 uint32_t* out_upperBound);
 
   template<typename T>
   const T* Elements() const { return reinterpret_cast<const T*>(mBytes.Elements()); }
--- a/content/html/content/src/HTMLLinkElement.cpp
+++ b/content/html/content/src/HTMLLinkElement.cpp
@@ -284,17 +284,17 @@ HTMLLinkElement::UpdateImport()
   }
 
   nsCOMPtr<nsIURI> uri = GetHrefURI();
   if (!uri) {
     mImportLoader = nullptr;
     return;
   }
 
-  if (!Preferences::GetBool("dom.webcomponents.enabled")) {
+  if (!nsStyleLinkElement::IsImportEnabled()) {
     // For now imports are hidden behind a pref...
     return;
   }
 
   nsRefPtr<ImportManager> manager = doc->ImportManager();
   MOZ_ASSERT(manager, "ImportManager should be created lazily when needed");
 
   {
--- a/content/media/mediasource/test/mochitest.ini
+++ b/content/media/mediasource/test/mochitest.ini
@@ -1,6 +1,6 @@
 [DEFAULT]
 skip-if = e10s
 support-files = seek.webm seek.webm^headers^
 
 [test_MediaSource.html]
-skip-if = buildapp == 'b2g' # b2g( ReferenceError: MediaSource is not defined) b2g-debug( ReferenceError: MediaSource is not defined) b2g-desktop( ReferenceError: MediaSource is not defined)
+skip-if = buildapp == 'b2g' # b2g( ReferenceError: MediaSource is not defined)
--- a/content/media/test/mochitest.ini
+++ b/content/media/test/mochitest.ini
@@ -17,18 +17,17 @@
 # throws an error (and does not cause a crash or hang), just add it to
 # gErrorTests in manifest.js.
 
 # To test for a specific bug in handling a specific resource type, make the
 # test first check canPlayType for the type, and if it's not supported, just
 # do ok(true, "Type not supported") and stop the test.
 
 [DEFAULT]
-#bug 918299
-skip-if = (buildapp == 'b2g' && (toolkit != 'gonk' || debug))
+skip-if = (buildapp == 'b2g' && (toolkit != 'gonk' || debug)) # b2g-debug,b2g-desktop(bug 918299)
 support-files =
   320x240.ogv
   320x240.ogv^headers^
   448636.ogv
   448636.ogv^headers^
   VID_0001.ogg
   VID_0001.ogg^headers^
   allowed.sjs
@@ -293,208 +292,186 @@ support-files =
   wavedata_s16.wav^headers^
   wavedata_u8.wav
   wavedata_u8.wav^headers^
 
 [test_access_control.html]
 [test_aspectratio_mp4.html]
 [test_audio1.html]
 [test_audio2.html]
+[test_audioDocumentTitle.html]
+skip-if = true # bug 475110
 [test_autoplay.html]
+[test_autoplay_contentEditable.html]
+skip-if = buildapp == 'b2g' # bug 899074 - timeouts
+[test_buffered.html]
+skip-if = toolkit == 'android' || os == "win" || (toolkit == 'gonk' && !debug) # See bug 832768 and 864682, b2g(assertion failures)
 [test_bug448534.html]
-skip-if = buildapp == 'b2g' # b2g(Timed out, bug 894922? Bug 902677 is for the timing out of a lot of media tests) b2g-debug(Timed out, bug 894922? Bug 902677 is for the timing out of a lot of media tests) b2g-desktop(Timed out, bug 894922? Bug 902677 is for the timing out of a lot of media tests)
+skip-if = buildapp == 'b2g' # b2g(Timed out, bug 894922? Bug 902677 is for the timing out of a lot of media tests)
 [test_bug463162.xhtml]
+[test_bug465498.html]
+skip-if = os == "win" || (toolkit == 'gonk' && !debug) # See bug 832768 and 864682
+[test_bug493187.html]
+skip-if = os == "win" || (toolkit == 'gonk' && !debug) # See bug 707777
 [test_bug495145.html]
-skip-if = (buildapp == 'b2g' && (toolkit != 'gonk' || debug)) # b2g-debug(timed out) b2g-desktop(timed out)
 [test_bug495300.html]
-skip-if = (buildapp == 'b2g' && (toolkit != 'gonk' || debug))
 [test_bug654550.html]
-skip-if = (buildapp == 'b2g' && (toolkit != 'gonk' || debug)) # b2g-debug(timed out) b2g-desktop(timed out)
 [test_bug686942.html]
-skip-if = (buildapp == 'b2g' && (toolkit != 'gonk' || debug)) # b2g-debug(timed out) b2g-desktop(timed out)
-# [test_bug726904.html] # disabled - See bug 754860
+[test_bug726904.html]
+skip-if = true # bug 754860
 [test_bug874897.html]
 [test_bug883173.html]
+[test_bug895091.html]
 [test_bug895305.html]
-[test_bug895091.html]
 [test_bug919265.html]
 [test_bug957847.html]
+[test_can_play_type.html]
+[test_can_play_type_mpeg.html]
+skip-if = buildapp == 'b2g' # b2g(7 failures out of 27)
+[test_can_play_type_no_ogg.html]
+[test_can_play_type_ogg.html]
+skip-if = buildapp == 'b2g' || e10s
 [test_chaining.html]
-skip-if = buildapp == 'b2g' # b2g(timed out) b2g-debug(timed out) b2g-desktop(timed out)
+skip-if = buildapp == 'b2g' # timeouts
 [test_clone_media_element.html]
+[test_closing_connections.html]
+[test_constants.html]
 [test_contentDuration1.html]
 [test_contentDuration2.html]
 [test_contentDuration3.html]
 [test_contentDuration4.html]
 [test_contentDuration5.html]
 [test_contentDuration6.html]
 [test_contentDuration7.html]
-[test_can_play_type.html]
-skip-if = (buildapp == 'b2g' && (toolkit != 'gonk' || debug)) # b2g-debug(timed out) b2g-desktop(timed out)
-[test_can_play_type_mpeg.html]
-skip-if = buildapp == 'b2g' # b2g(7 failures out of 27) b2g-debug(7 failures out of 27) b2g-desktop(7 failures out of 27)
-[test_can_play_type_ogg.html]
-skip-if = buildapp == 'b2g' || e10s
-[test_can_play_type_no_ogg.html]
-[test_closing_connections.html]
-[test_constants.html]
 [test_controls.html]
 [test_currentTime.html]
 [test_decode_error.html]
+[test_decoder_disable.html]
 [test_defaultMuted.html]
 [test_delay_load.html]
-skip-if = buildapp == 'b2g' # b2g(6 failures) b2g-debug(6 failures) b2g-desktop(6 failures)
+skip-if = buildapp == 'b2g' # b2g(6 failures)
+[test_error_in_video_document.html]
+skip-if = true # bug 608634
 [test_error_on_404.html]
-skip-if = buildapp == 'b2g' && (toolkit != 'gonk' || debug)) # b2g-debug(timed out) b2g-desktop(timed out)
 [test_fastSeek.html]
 [test_info_leak.html]
-skip-if = buildapp == 'b2g' # b2g(2 failures) b2g-debug(2 failures) b2g-desktop(2 failures)
+skip-if = buildapp == 'b2g' # b2g(2 failures)
 [test_invalid_reject.html]
 [test_load.html]
-skip-if = (buildapp == 'b2g' && (toolkit != 'gonk' || debug)) # b2g-debug(Timed out after gizmo.mp4) b2g-desktop(Timed out after gizmo.mp4)
 [test_load_candidates.html]
-skip-if = (buildapp == 'b2g' && (toolkit != 'gonk' || debug)) # b2g-debug(timed out) b2g-desktop(timed out)
 [test_load_same_resource.html]
-skip-if = (buildapp == 'b2g' && (toolkit != 'gonk' || debug))
 [test_load_source.html]
 [test_loop.html]
+[test_media_selection.html]
+skip-if = os == "win" || (toolkit == 'gonk' && !debug) # See bug 897843, b2g(timed out)
+[test_media_sniffer.html]
+[test_mediarecorder_avoid_recursion.html]
+[test_mediarecorder_creation.html]
+[test_mediarecorder_creation_fail.html]
+[test_mediarecorder_getencodeddata.html]
+[test_mediarecorder_record_4ch_audiocontext.html]
+skip-if = (toolkit == 'gonk' && !debug)
+[test_mediarecorder_record_audiocontext.html]
+[test_mediarecorder_record_audiocontext_mlk.html]
+[test_mediarecorder_record_gum_video_timeslice.html]
+skip-if = buildapp == 'b2g' || (toolkit == 'android') # mimetype check, bug 969289
+[test_mediarecorder_record_immediate_stop.html]
+[test_mediarecorder_record_no_timeslice.html]
+[test_mediarecorder_record_nosrc.html]
+[test_mediarecorder_record_session.html]
+[test_mediarecorder_record_startstopstart.html]
+[test_mediarecorder_record_stopms.html]
+[test_mediarecorder_record_timeslice.html]
+[test_mediarecorder_reload_crash.html]
+[test_mediarecorder_unsupported_src.html]
 [test_metadata.html]
-skip-if = (buildapp == 'b2g' && (toolkit != 'gonk' || debug))
-[test_no_load_event.html]
+[test_mixed_principals.html]
+skip-if = true # bug 567954 and 574586
+[test_mozHasAudio.html]
 [test_networkState.html]
 [test_new_audio.html]
+[test_no_load_event.html]
 [test_paused.html]
 [test_paused_after_ended.html]
 [test_play_events.html]
-skip-if = (buildapp == 'b2g' && (toolkit != 'gonk' || debug)) # b2g-debug(Last event should be canplaythrough for gizmo.mp4 - got playing, expected canplaythrough) b2g-desktop(Last event should be canplaythrough for gizmo.mp4 - got playing, expected canplaythrough)
 [test_play_events_2.html]
-skip-if = (buildapp == 'b2g' && (toolkit != 'gonk' || debug)) # b2g-debug(Last event should be canplaythrough for gizmo.mp4 - got playing, expected canplaythrough) b2g-desktop(Last event should be canplaythrough for gizmo.mp4 - got playing, expected canplaythrough)
-[test_playback_errors.html]
-[test_seekable1.html]
-skip-if = (buildapp == 'b2g' && (toolkit != 'gonk' || debug))
-[test_preload_actions.html]
-[test_preload_attribute.html]
-[test_progress.html]
-skip-if = (buildapp == 'b2g' && (toolkit != 'gonk' || debug)) # b2g-debug(bug 901716 - timeouts) b2g-desktop(bug 901716 - timeouts)
-[test_reactivate.html]
-skip-if = (buildapp == 'b2g' && (toolkit != 'gonk' || debug)) # b2g-debug(timed out in small-shot.mp3) b2g-desktop(timed out in small-shot.mp3)
-[test_readyState.html]
-[test_referer.html]
-[test_reset_events_async.html]
-[test_replay_metadata.html]
-skip-if = (buildapp == 'b2g' && (toolkit != 'gonk' || debug))
-[test_seek2.html]
-[test_seek_out_of_range.html]
-skip-if = (buildapp == 'b2g' && (toolkit != 'gonk' || debug))
-[test_seekable2.html]
-[test_seekable3.html]
-skip-if = buildapp == 'b2g' # b2g(timed out) b2g-debug(timed out) b2g-desktop(timed out)
-[test_source.html]
-skip-if = (buildapp == 'b2g' && (toolkit != 'gonk' || debug))
-[test_source_write.html]
-[test_source_null.html]
-[test_standalone.html]
-[test_volume.html]
-[test_video_to_canvas.html]
-[test_mediarecorder_creation.html]
-[test_mediarecorder_creation_fail.html]
-[test_mediarecorder_avoid_recursion.html]
-[test_mediarecorder_record_timeslice.html]
-[test_mediarecorder_record_audiocontext.html]
-[test_mediarecorder_record_audiocontext_mlk.html]
-[test_mediarecorder_record_4ch_audiocontext.html]
-skip-if = (toolkit == 'gonk' && !debug)
-[test_mediarecorder_record_stopms.html]
-[test_mediarecorder_record_nosrc.html]
-[test_mozHasAudio.html]
-skip-if = (buildapp == 'b2g' && (toolkit != 'gonk' || debug))
-[test_source_media.html]
-skip-if = (buildapp == 'b2g' && (toolkit != 'gonk' || debug))
-[test_autoplay_contentEditable.html]
-skip-if = buildapp == 'b2g' # b2g(bug 899074 - timeouts) b2g-debug(bug 899074 - timeouts) b2g-desktop(bug 899074 - timeouts)
-[test_decoder_disable.html]
-[test_mediarecorder_record_no_timeslice.html]
-[test_mediarecorder_reload_crash.html]
-[test_mediarecorder_record_immediate_stop.html]
-[test_mediarecorder_record_session.html]
-[test_mediarecorder_record_startstopstart.html]
-[test_mediarecorder_getencodeddata.html]
-[test_mediarecorder_unsupported_src.html]
-[test_mediarecorder_record_gum_video_timeslice.html]
-skip-if = buildapp == 'b2g' || (toolkit == 'android') # mimetype check, bug 969289
-[test_playback.html]
-skip-if = buildapp == 'b2g' || toolkit == 'android' # Disabled on Android & B2G due to bug 668973
-[test_seekLies.html]
-[test_media_sniffer.html]
-[test_streams_srcObject.html]
-[test_reset_src.html]
-[test_streams_autoplay.html]
-[test_streams_element_capture.html]
-[test_streams_element_capture_reset.html]
-skip-if = buildapp == 'b2g' # b2g(bug 901102) b2g-debug(bug 901102) b2g-desktop(bug 901102)
-[test_streams_element_capture_createObjectURL.html]
-[test_streams_element_capture_playback.html]
-[test_streams_gc.html]
-skip-if = buildapp == 'b2g' # b2g(Value being assigned to HTMLMediaElement.currentTime is not a finite floating-point value) b2g-debug(Value being assigned to HTMLMediaElement.currentTime is not a finite floating-point value) b2g-desktop(Value being assigned to HTMLMediaElement.currentTime is not a finite floating-point value)
-[test_streams_tracks.html]
-[test_trackelementevent.html]
-[test_texttrack.html]
-[test_texttrackcue.html]
-[test_trackevent.html]
-[test_texttrackregion.html]
-[test_texttracklist.html]
-[test_timeupdate_small_files.html]
-[test_unseekable.html]
-skip-if = buildapp == 'b2g'
-[test_VideoPlaybackQuality.html]
-[test_VideoPlaybackQuality_disabled.html]
-[test_webvtt_disabled.html]
-
-# [test_audioDocumentTitle.html] # disabled - See bug 475110
-# [test_error_in_video_document.html] # disabled - See bug 608634
-# [test_mixed_principals.html] # disabled - See bug 567954 and 574586
-# [test_playback_rate_playpause.html] # disabled - See bug 897108
-# [test_played.html] # disabled - See bug 751539
-# [test_preload_suspend.html] # disabled - See bug 493692
-# [test_resume.html] # disabled - No bug :-(
-# [test_videoDocumentTitle.html] # disabled - See bug 492821
-
-# [test_playback_rate.html] # disabled - See bug 921622
-# Disabled since it causes random memory corruption, bug 921622, so
-# the best-case scenario is that it results in random crashes while it
-# runs, like bug 918417, bug 920827, bug 923996, bug 928225, bug 929521
-# bug 930982, bug 932193. Worst-case but quite likely, it causes random
-# crashes and failures in other tests which run after it. Don't even think
-# about reenabling it on any platform unless you *know* that you have fixed
-# that. Then don't think about reenabling it on Windows until you know that
-# you have fixed the timeouts of bug 832768, bug 814533, bug 840742
-
 [test_play_twice.html]
 # Seamonkey: Bug 598252, B2G: Bug 982100, Android: Bug 758476, bug 981086
 skip-if = appname == "seamonkey" || toolkit == 'gonk' || toolkit == 'android'
-
-[test_buffered.html]
-skip-if = toolkit == 'android' || os == "win" || (toolkit == 'gonk' && !debug) # See bug 832768 and 864682, b2g(assertion failures)
-[test_bug465498.html]
-skip-if = os == "win" || (toolkit == 'gonk' && !debug) # See bug 832768 and 864682
-[test_bug493187.html]
-skip-if = os == "win" || (buildapp=='b2g'&&debug) || (toolkit == 'gonk' && !debug) # See bug 707777, #b2g-emulator-debug - process crash
-[test_media_selection.html]
-skip-if = os == "win" || (toolkit == 'gonk' && !debug) # See bug 897843, b2g(timed out)
+[test_playback.html]
+skip-if = buildapp == 'b2g' || toolkit == 'android' # Disabled on Android & B2G due to bug 668973
+[test_playback_errors.html]
+[test_playback_rate.html]
+# Win: Bug 814533, B2G & Android Debug: Bug 1020538
+skip-if = os == 'win' || buildapp == 'b2g' || (toolkit == 'android' && debug)
+[test_playback_rate_playpause.html]
+skip-if = true # bug 897108
+[test_played.html]
+skip-if = true # bug 751539
+[test_preload_actions.html]
+[test_preload_attribute.html]
+[test_preload_suspend.html]
+skip-if = true # bug 493692
+[test_progress.html]
+[test_reactivate.html]
+[test_readyState.html]
+[test_referer.html]
+[test_replay_metadata.html]
+[test_reset_events_async.html]
+[test_reset_src.html]
+[test_resume.html]
+skip-if = true # disabled - No bug :-(
+[test_seek_out_of_range.html]
 [test_seek.html]
 skip-if = toolkit == 'android' || (toolkit == 'gonk' && !debug) # See bug 832678, 795271, and 857424 # android(bug 845162) androidx86(bug 845162)
+[test_seek2.html]
+[test_seekable1.html]
+[test_seekable2.html]
+[test_seekable3.html]
+skip-if = buildapp == 'b2g' # timeouts
+[test_seekLies.html]
+[test_source.html]
+[test_source_media.html]
+[test_source_null.html]
+[test_source_write.html]
+[test_standalone.html]
+[test_streams_autoplay.html]
+[test_streams_element_capture.html]
+[test_streams_element_capture_createObjectURL.html]
+[test_streams_element_capture_playback.html]
+[test_streams_element_capture_reset.html]
+skip-if = buildapp == 'b2g' # bug 901102
+[test_streams_gc.html]
+skip-if = buildapp == 'b2g' # Value being assigned to HTMLMediaElement.currentTime is not a finite floating-point value
+[test_streams_srcObject.html]
+[test_streams_tracks.html]
+[test_texttrack.html]
+[test_texttrackcue.html]
+[test_texttracklist.html]
+[test_texttrackregion.html]
+[test_timeupdate_small_files.html]
+[test_trackelementevent.html]
+[test_trackevent.html]
+[test_unseekable.html]
+skip-if = buildapp == 'b2g'
+[test_video_to_canvas.html]
+[test_videoDocumentTitle.html]
+skip-if = true # bug 492821
+[test_VideoPlaybackQuality.html]
+[test_VideoPlaybackQuality_disabled.html]
+[test_volume.html]
+[test_webvtt_disabled.html]
+
 
 # The tests below contain backend-specific tests. Write backend independent
 # tests rather than adding to this list.
-
 [test_can_play_type_webm.html]
 run-if = webm
 [test_can_play_type_no_webm.html]
 skip-if = webm
-
 [test_can_play_type_wave.html]
 run-if = wave
 [test_can_play_type_no_wave.html]
 skip-if = wave
 [test_fragment_noplay.html]
 run-if = wave
 [test_fragment_play.html]
 run-if = wave
--- a/content/media/test/test_playback_rate.html
+++ b/content/media/test/test_playback_rate.html
@@ -5,22 +5,29 @@
   <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
   <script type="text/javascript" src="manifest.js"></script>
 </head>
 <body>
 <pre id="test">
 <script class="testbody" type='application/javascript;version=1.8'>
 
-SimpleTest.expectAssertions(0, 2);
-
+// In varying quantities:
+// ASSERTION: Should be on state machine or decode thread.:
+//            'OnStateMachineThread() || OnDecodeThread()',
+//            file MediaDecoderStateMachine.cpp, line 559
+// ASSERTION: Clock should go forwards if the playback rate is > 0.:
+//            'mCurrentFrameTime <= clock_time || mPlaybackRate <= 0',
+//            file MediaDecoderStateMachine.cpp, line 2379
+// This test is currently disabled on Android debug for wildly-varying numbers of the above.
+SimpleTest.expectAssertions(5, 9);
 if (navigator.platform.startsWith("Win")) {
-  SimpleTest.expectAssertions(0, 1);
+  SimpleTest.expectAssertions(4, 5);
 } else if (navigator.platform.startsWith("Mac")) {
-  SimpleTest.expectAssertions(0, 2);
+  SimpleTest.expectAssertions(5, 7);
 }
 
 let manager = new MediaTestManager;
 
 function rangeCheck(lhs, rhs, threshold) {
   var diff = Math.abs(lhs - rhs);
   if (diff < threshold) {
     return true;
--- a/content/media/webaudio/test/mochitest.ini
+++ b/content/media/webaudio/test/mochitest.ini
@@ -1,10 +1,10 @@
 [DEFAULT]
-skip-if = (buildapp == 'b2g' && (toolkit != 'gonk' || debug)) #b2g-debug(bug 916135) b2g-desktop(bug 916135)
+skip-if = (buildapp == 'b2g' && (toolkit != 'gonk' || debug)) #b2g-debug,b2g-desktop(bug 916135)
 support-files =
   audio-expected.wav
   audio-mono-expected-2.wav
   audio-mono-expected.wav
   audio-quad.wav
   audio.ogv
   audioBufferSourceNodeNeutered_worker.js
   invalid.txt
@@ -18,40 +18,40 @@ support-files =
   ting-48k-1ch.ogg
   ting-48k-2ch.ogg
   ting-44.1k-1ch.wav
   ting-44.1k-2ch.wav
   ting-48k-1ch.wav
   ting-48k-2ch.wav
   webaudio.js
 
+[test_analyserNode.html]
 [test_AudioBuffer.html]
-[test_AudioContext.html]
-[test_AudioListener.html]
-[test_OfflineAudioContext.html]
-[test_analyserNode.html]
 [test_audioBufferSourceNode.html]
 [test_audioBufferSourceNodeEnded.html]
 [test_audioBufferSourceNodeLazyLoopParam.html]
 [test_audioBufferSourceNodeLoop.html]
 [test_audioBufferSourceNodeLoopStartEnd.html]
 [test_audioBufferSourceNodeLoopStartEndSame.html]
 [test_audioBufferSourceNodeNeutered.html]
 [test_audioBufferSourceNodeNoStart.html]
 [test_audioBufferSourceNodeNullBuffer.html]
 [test_audioBufferSourceNodeOffset.html]
 skip-if = (toolkit == 'gonk' && !debug) #bug 906752
+[test_AudioContext.html]
+[test_audioDestinationNode.html]
+[test_AudioListener.html]
 [test_audioParamExponentialRamp.html]
+[test_audioParamGain.html]
 [test_audioParamLinearRamp.html]
 [test_audioParamSetCurveAtTime.html]
 [test_audioParamSetCurveAtTimeZeroDuration.html]
 [test_audioParamSetTargetAtTime.html]
 [test_audioParamSetValueAtTime.html]
 [test_audioParamTimelineDestinationOffset.html]
-[test_audioParamGain.html]
 [test_badConnect.html]
 [test_biquadFilterNode.html]
 [test_biquadFilterNodeWithGain.html]
 [test_bug808374.html]
 [test_bug827541.html]
 [test_bug839753.html]
 [test_bug845960.html]
 [test_bug856771.html]
@@ -67,19 +67,19 @@ skip-if = (toolkit == 'gonk' && !debug) 
 [test_bug956489.html]
 [test_bug964376.html]
 [test_bug972678.html]
 [test_channelMergerNode.html]
 [test_channelMergerNodeWithVolume.html]
 [test_channelSplitterNode.html]
 [test_channelSplitterNodeWithVolume.html]
 [test_convolverNode.html]
+[test_convolverNode_mono_mono.html]
 [test_convolverNodeChannelCount.html]
 [test_convolverNodeWithGain.html]
-[test_convolverNode_mono_mono.html]
 [test_currentTime.html]
 [test_decodeMultichannel.html]
 [test_delayNode.html]
 [test_delayNodeAtMax.html]
 [test_delayNodeChannelChanges.html]
 [test_delayNodeCycles.html]
 [test_delayNodeSmallMaxDelay.html]
 [test_delayNodeTailIncrease.html]
@@ -93,35 +93,35 @@ skip-if = (toolkit == 'gonk' && !debug) 
 [test_maxChannelCount.html]
 [test_mediaDecoding.html]
 [test_mediaElementAudioSourceNode.html]
 [test_mediaStreamAudioDestinationNode.html]
 [test_mediaStreamAudioSourceNode.html]
 [test_mediaStreamAudioSourceNodeCrossOrigin.html]
 [test_mediaStreamAudioSourceNodeResampling.html]
 [test_mixingRules.html]
+[test_mozaudiochannel.html]
+skip-if = (toolkit == 'gonk' && !debug)
 [test_nodeToParamConnection.html]
+[test_OfflineAudioContext.html]
 [test_offlineDestinationChannelCountLess.html]
 [test_offlineDestinationChannelCountMore.html]
 [test_oscillatorNode.html]
 [test_oscillatorNode2.html]
 [test_oscillatorNodeStart.html]
 [test_oscillatorTypeChange.html]
 [test_pannerNode.html]
+[test_pannerNode_equalPower.html]
 [test_pannerNodeAbove.html]
 [test_pannerNodeChannelCount.html]
 [test_pannerNodeHRTFSymmetry.html]
 [test_pannerNodeTail.html]
-[test_pannerNode_equalPower.html]
 [test_periodicWave.html]
 [test_scriptProcessorNode.html]
 [test_scriptProcessorNodeChannelCount.html]
 [test_scriptProcessorNodeZeroInputOutput.html]
 [test_scriptProcessorNodeNotConnected.html]
+[test_singleSourceDest.html]
 [test_stereoPanningWithGain.html]
-[test_singleSourceDest.html]
+[test_waveDecoder.html]
 [test_waveShaper.html]
 [test_waveShaperNoCurve.html]
 [test_waveShaperZeroLengthCurve.html]
-[test_audioDestinationNode.html]
-[test_mozaudiochannel.html]
-skip-if = (toolkit == 'gonk' && !debug)
-[test_waveDecoder.html]
--- a/content/media/webspeech/recognition/test/mochitest.ini
+++ b/content/media/webspeech/recognition/test/mochitest.ini
@@ -5,15 +5,15 @@ support-files =
   hello.ogg^headers^
   silence.ogg
   silence.ogg^headers^
 
 [test_abort.html]
 [test_audio_capture_error.html]
 [test_call_start_from_end_handler.html]
 [test_nested_eventloop.html]
-skip-if = buildapp == 'b2g' || toolkit == 'android' || e10s # b2g(showmodaldialog) b2g-debug(showmodaldialog) b2g-desktop(showmodaldialog)
+skip-if = buildapp == 'b2g' || toolkit == 'android' || e10s # b2g(showmodaldialog)
 [test_preference_enable.html]
 [test_recognition_service_error.html]
-skip-if = buildapp == 'b2g' # b2g(timed out) b2g-debug(timed out) b2g-desktop(timed out)
+skip-if = buildapp == 'b2g' # b2g(timed out)
 [test_success_without_recognition_service.html]
 [test_timeout.html]
 skip-if = os == "win"
--- a/content/media/webspeech/synth/test/mochitest.ini
+++ b/content/media/webspeech/synth/test/mochitest.ini
@@ -3,11 +3,11 @@ skip-if = e10s
 support-files =
   common.js
   file_setup.html
   file_speech_queue.html
   file_speech_simple.html
 
 [test_setup.html]
 [test_speech_queue.html]
-skip-if = buildapp == 'b2g' # b2g(Test timed out) b2g-debug(Test timed out) b2g-desktop(Test timed out)
+skip-if = buildapp == 'b2g' # b2g(Test timed out)
 [test_speech_simple.html]
-skip-if = buildapp == 'b2g' # b2g(Test timed out) b2g-debug(Test timed out) b2g-desktop(Test timed out)
+skip-if = buildapp == 'b2g' # b2g(Test timed out)
--- a/content/svg/document/src/SVGDocument.cpp
+++ b/content/svg/document/src/SVGDocument.cpp
@@ -61,16 +61,31 @@ SVGDocument::GetRootElement(ErrorResult&
   if (!root->IsSVG()) {
     aRv.Throw(NS_NOINTERFACE);
     return nullptr;
   }
   return static_cast<nsSVGElement*>(root);
 }
 
 nsresult
+SVGDocument::InsertChildAt(nsIContent* aKid, uint32_t aIndex, bool aNotify)
+{
+  nsresult rv = XMLDocument::InsertChildAt(aKid, aIndex, aNotify);
+
+  if (NS_SUCCEEDED(rv) && aKid->IsElement() && !aKid->IsSVG()) {
+    // We can get here when well formed XML with a non-SVG root element is
+    // served with the SVG MIME type, for example. In that case we need to load
+    // the non-SVG UA sheets or else we can get bugs like bug 1016145.
+    EnsureNonSVGUserAgentStyleSheetsLoaded();
+  }
+
+  return rv;
+}
+
+nsresult
 SVGDocument::Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const
 {
   NS_ASSERTION(aNodeInfo->NodeInfoManager() == mNodeInfoManager,
                "Can't import this document into another document!");
 
   nsRefPtr<SVGDocument> clone = new SVGDocument();
   nsresult rv = CloneDocHelper(clone.get());
   NS_ENSURE_SUCCESS(rv, rv);
--- a/content/svg/document/src/SVGDocument.h
+++ b/content/svg/document/src/SVGDocument.h
@@ -23,16 +23,18 @@ class SVGDocument MOZ_FINAL : public XML
 public:
   SVGDocument()
     : XMLDocument("image/svg+xml")
     , mHasLoadedNonSVGUserAgentStyleSheets(false)
   {
     mType = eSVG;
   }
 
+  virtual nsresult InsertChildAt(nsIContent* aKid, uint32_t aIndex,
+                                 bool aNotify) MOZ_OVERRIDE;
   virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const MOZ_OVERRIDE;
 
   // WebIDL API
   void GetDomain(nsAString& aDomain, ErrorResult& aRv);
   nsSVGElement* GetRootElement(ErrorResult& aRv);
 
   virtual SVGDocument* AsSVGDocument() MOZ_OVERRIDE {
     return this;
--- a/docshell/shistory/src/nsSHistory.cpp
+++ b/docshell/shistory/src/nsSHistory.cpp
@@ -14,17 +14,16 @@
 // Interfaces Needed
 #include "nsILayoutHistoryState.h"
 #include "nsIDocShell.h"
 #include "nsIDocShellLoadInfo.h"
 #include "nsISHContainer.h"
 #include "nsIDocShellTreeItem.h"
 #include "nsIURI.h"
 #include "nsIContentViewer.h"
-#include "nsICacheService.h"
 #include "nsIObserverService.h"
 #include "prclist.h"
 #include "mozilla/Services.h"
 #include "nsTArray.h"
 #include "nsCOMArray.h"
 #include "nsDocShell.h"
 #include "mozilla/Attributes.h"
 #include "nsISHEntry.h"
@@ -185,17 +184,17 @@ NS_IMPL_ISUPPORTS(nsSHistoryObserver, ns
 
 NS_IMETHODIMP
 nsSHistoryObserver::Observe(nsISupports *aSubject, const char *aTopic,
                             const char16_t *aData)
 {
   if (!strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID)) {
     nsSHistory::UpdatePrefs();
     nsSHistory::GloballyEvictContentViewers();
-  } else if (!strcmp(aTopic, NS_CACHESERVICE_EMPTYCACHE_TOPIC_ID) ||
+  } else if (!strcmp(aTopic, "cacheservice:empty-cache") ||
              !strcmp(aTopic, "memory-pressure")) {
     nsSHistory::GloballyEvictAllContentViewers();
   }
 
   return NS_OK;
 }
 
 namespace {
@@ -365,17 +364,17 @@ nsSHistory::Startup()
     Preferences::AddStrongObservers(gObserver, kObservedPrefs);
 
     nsCOMPtr<nsIObserverService> obsSvc =
       mozilla::services::GetObserverService();
     if (obsSvc) {
       // Observe empty-cache notifications so tahat clearing the disk/memory
       // cache will also evict all content viewers.
       obsSvc->AddObserver(gObserver,
-                          NS_CACHESERVICE_EMPTYCACHE_TOPIC_ID, false);
+                          "cacheservice:empty-cache", false);
 
       // Same for memory-pressure notifications
       obsSvc->AddObserver(gObserver, "memory-pressure", false);
     }
   }
 
   // Initialize the global list of all SHistory objects
   PR_INIT_CLIST(&gSHistoryList);
@@ -386,17 +385,17 @@ nsSHistory::Startup()
 void
 nsSHistory::Shutdown()
 {
   if (gObserver) {
     Preferences::RemoveObservers(gObserver, kObservedPrefs);
     nsCOMPtr<nsIObserverService> obsSvc =
       mozilla::services::GetObserverService();
     if (obsSvc) {
-      obsSvc->RemoveObserver(gObserver, NS_CACHESERVICE_EMPTYCACHE_TOPIC_ID);
+      obsSvc->RemoveObserver(gObserver, "cacheservice:empty-cache");
       obsSvc->RemoveObserver(gObserver, "memory-pressure");
     }
     NS_RELEASE(gObserver);
   }
 }
 
 /* Add an entry to the History list at mIndex and 
  * increment the index to point to the new entry
--- a/dom/base/MessageChannel.cpp
+++ b/dom/base/MessageChannel.cpp
@@ -1,14 +1,15 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "MessageChannel.h"
+
 #include "mozilla/Preferences.h"
 #include "mozilla/dom/MessageChannelBinding.h"
 #include "mozilla/dom/MessagePort.h"
 #include "nsContentUtils.h"
 #include "nsPIDOMWindow.h"
 
 namespace mozilla {
 namespace dom {
@@ -23,26 +24,48 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(
 NS_INTERFACE_MAP_END
 
 namespace {
   bool gPrefInitialized = false;
   bool gPrefEnabled = false;
 
 }
 
-
 /* static */ bool
-MessageChannel::PrefEnabled()
+MessageChannel::Enabled(JSContext* aCx, JSObject* aObj)
 {
   if (!gPrefInitialized) {
     Preferences::AddBoolVarCache(&gPrefEnabled, "dom.messageChannel.enabled");
     gPrefInitialized = true;
   }
 
-  return gPrefEnabled;
+  // Enabled by pref
+  if (gPrefEnabled) {
+    return true;
+  }
+
+  // Chrome callers are allowed.
+  if (nsContentUtils::ThreadsafeIsCallerChrome()) {
+    return true;
+  }
+
+  nsCOMPtr<nsIPrincipal> principal = nsContentUtils::SubjectPrincipal();
+  MOZ_ASSERT(principal);
+
+  nsCOMPtr<nsIURI> uri;
+  if (NS_FAILED(principal->GetURI(getter_AddRefs(uri))) || !uri) {
+    return false;
+  }
+
+  bool isResource = false;
+  if (NS_FAILED(uri->SchemeIs("resource", &isResource))) {
+    return false;
+  }
+
+  return isResource;
 }
 
 MessageChannel::MessageChannel(nsPIDOMWindow* aWindow)
   : mWindow(aWindow)
 {
   MOZ_COUNT_CTOR(MessageChannel);
   SetIsDOMBinding();
 
--- a/dom/base/MessageChannel.h
+++ b/dom/base/MessageChannel.h
@@ -23,17 +23,17 @@ class MessagePort;
 
 class MessageChannel MOZ_FINAL : public nsISupports
                                , public nsWrapperCache
 {
 public:
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(MessageChannel)
 
-  static bool PrefEnabled();
+  static bool Enabled(JSContext* aCx, JSObject* aGlobal);
 
 public:
   MessageChannel(nsPIDOMWindow* aWindow);
 
   ~MessageChannel();
 
   nsPIDOMWindow*
   GetParentObject() const
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -7900,17 +7900,17 @@ PostMessageReadTransferStructuredClone(J
                                        uint32_t tag, void* aData,
                                        uint64_t aExtraData,
                                        void* aClosure,
                                        JS::MutableHandle<JSObject*> returnObject)
 {
   StructuredCloneInfo* scInfo = static_cast<StructuredCloneInfo*>(aClosure);
   NS_ASSERTION(scInfo, "Must have scInfo!");
 
-  if (MessageChannel::PrefEnabled() && tag == SCTAG_DOM_MAP_MESSAGEPORT) {
+  if (tag == SCTAG_DOM_MAP_MESSAGEPORT) {
     MessagePort* port = static_cast<MessagePort*>(aData);
     port->BindToOwner(scInfo->window);
     scInfo->ports.Put(port, nullptr);
 
     JS::Rooted<JSObject*> obj(aCx, port->WrapObject(aCx));
     if (JS_WrapObject(aCx, &obj)) {
       MOZ_ASSERT(port->GetOwner() == scInfo->window);
       returnObject.set(obj);
@@ -7929,49 +7929,47 @@ PostMessageTransferStructuredClone(JSCon
                                    uint32_t* aTag,
                                    JS::TransferableOwnership* aOwnership,
                                    void** aContent,
                                    uint64_t* aExtraData)
 {
   StructuredCloneInfo* scInfo = static_cast<StructuredCloneInfo*>(aClosure);
   NS_ASSERTION(scInfo, "Must have scInfo!");
 
-  if (MessageChannel::PrefEnabled()) {
-    MessagePortBase* port = nullptr;
-    nsresult rv = UNWRAP_OBJECT(MessagePort, aObj, port);
-    if (NS_SUCCEEDED(rv)) {
-      nsRefPtr<MessagePortBase> newPort;
-      if (scInfo->ports.Get(port, getter_AddRefs(newPort))) {
-        // No duplicate.
-        return false;
-      }
-
-      newPort = port->Clone();
-      scInfo->ports.Put(port, newPort);
-
-      *aTag = SCTAG_DOM_MAP_MESSAGEPORT;
-      *aOwnership = JS::SCTAG_TMO_CUSTOM;
-      *aContent = newPort;
-      *aExtraData = 0;
-
-      return true;
-    }
+  MessagePortBase* port = nullptr;
+  nsresult rv = UNWRAP_OBJECT(MessagePort, aObj, port);
+  if (NS_SUCCEEDED(rv)) {
+    nsRefPtr<MessagePortBase> newPort;
+    if (scInfo->ports.Get(port, getter_AddRefs(newPort))) {
+      // No duplicate.
+      return false;
+    }
+
+    newPort = port->Clone();
+    scInfo->ports.Put(port, newPort);
+
+    *aTag = SCTAG_DOM_MAP_MESSAGEPORT;
+    *aOwnership = JS::SCTAG_TMO_CUSTOM;
+    *aContent = newPort;
+    *aExtraData = 0;
+
+    return true;
   }
 
   return false;
 }
 
 void
 PostMessageFreeTransferStructuredClone(uint32_t aTag, JS::TransferableOwnership aOwnership,
                                        void *aContent, uint64_t aExtraData, void* aClosure)
 {
   StructuredCloneInfo* scInfo = static_cast<StructuredCloneInfo*>(aClosure);
   NS_ASSERTION(scInfo, "Must have scInfo!");
 
-  if (MessageChannel::PrefEnabled() && aTag == SCTAG_DOM_MAP_MESSAGEPORT) {
+  if (aTag == SCTAG_DOM_MAP_MESSAGEPORT) {
     nsRefPtr<MessagePortBase> port(static_cast<MessagePort*>(aContent));
     scInfo->ports.Remove(port);
   }
 }
 
 JSStructuredCloneCallbacks kPostMessageCallbacks = {
   PostMessageReadStructuredClone,
   PostMessageWriteStructuredClone,
--- a/dom/base/nsGlobalWindow.h
+++ b/dom/base/nsGlobalWindow.h
@@ -962,16 +962,17 @@ public:
                                       mozilla::ErrorResult& aError)
   {
     return CancelAnimationFrame(aHandle, aError);
   }
   int64_t GetMozAnimationStartTime(mozilla::ErrorResult& aError);
   void SizeToContent(mozilla::ErrorResult& aError);
   nsIDOMCrypto* GetCrypto(mozilla::ErrorResult& aError);
   nsIControllers* GetControllers(mozilla::ErrorResult& aError);
+  mozilla::dom::Element* GetRealFrameElement(mozilla::ErrorResult& aError);
   float GetMozInnerScreenX(mozilla::ErrorResult& aError);
   float GetMozInnerScreenY(mozilla::ErrorResult& aError);
   float GetDevicePixelRatio(mozilla::ErrorResult& aError);
   int32_t GetScrollMaxX(mozilla::ErrorResult& aError);
   int32_t GetScrollMaxY(mozilla::ErrorResult& aError);
   bool GetFullScreen(mozilla::ErrorResult& aError);
   void SetFullScreen(bool aFullScreen, mozilla::ErrorResult& aError);
   void Back(mozilla::ErrorResult& aError);
@@ -1369,18 +1370,16 @@ protected:
   // Returns device pixels.  Outer windows only.
   nsIntPoint GetScreenXY(mozilla::ErrorResult& aError);
 
   int32_t RequestAnimationFrame(const nsIDocument::FrameRequestCallbackHolder& aCallback,
                                 mozilla::ErrorResult& aError);
 
   nsGlobalWindow* InnerForSetTimeoutOrInterval(mozilla::ErrorResult& aError);
 
-  mozilla::dom::Element* GetRealFrameElement(mozilla::ErrorResult& aError);
-
   void PostMessageMoz(JSContext* aCx, JS::Handle<JS::Value> aMessage,
                       const nsAString& aTargetOrigin,
                       JS::Handle<JS::Value> aTransfer,
                       mozilla::ErrorResult& aError);
 
   already_AddRefed<nsIVariant>
     ShowModalDialog(const nsAString& aUrl, nsIVariant* aArgument,
                     const nsAString& aOptions, mozilla::ErrorResult& aError);
--- a/dom/base/test/chrome.ini
+++ b/dom/base/test/chrome.ini
@@ -3,11 +3,12 @@ support-files =
   file_url.jsm
   file_empty.html
 
 [test_bug715041.xul]
 [test_bug715041_removal.xul]
 [test_domrequesthelper.xul]
 [test_url.xul]
 [test_console.xul]
+[test_messageChannel.xul]
 [test_navigator_resolve_identity_xrays.xul]
 [test_sendQueryContentAndSelectionSetEvent.html]
 [test_bug1016960.html]
new file mode 100644
--- /dev/null
+++ b/dom/base/test/iframe_messageChannel_chrome.html
@@ -0,0 +1,11 @@
+<!DOCTYPE HTML>
+<html>
+<body>
+  <script type="application/javascript">
+
+window.addEventListener('message', receiveMessage, false);
+function receiveMessage(evt) {
+  evt.data.postMessage("Hello world");
+}
+  </script>
+</body>
--- a/dom/base/test/mochitest.ini
+++ b/dom/base/test/mochitest.ini
@@ -1,12 +1,13 @@
 [DEFAULT]
 support-files =
   audio.ogg
   iframe_messageChannel_cloning.html
+  iframe_messageChannel_chrome.html
   iframe_messageChannel_pingpong.html
   iframe_messageChannel_post.html
   file_empty.html
   iframe_postMessage_solidus.html
 
 [test_Image_constructor.html]
 [test_appname_override.html]
 [test_audioWindowUtils.html]
new file mode 100644
--- /dev/null
+++ b/dom/base/test/test_messageChannel.xul
@@ -0,0 +1,38 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/css" href="chrome://global/skin"?>
+<?xml-stylesheet type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"?>
+<window title="Test for MessageChannel API"
+        xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+  <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
+
+  <!-- test results are displayed in the html:body -->
+  <body xmlns="http://www.w3.org/1999/xhtml" id="body">
+  </body>
+
+  <!-- test code goes here -->
+  <script type="application/javascript"><![CDATA[
+
+  ok("MessageChannel" in window, "Should MessageChannel exist?");
+
+  var channel = new MessageChannel();
+  ok(channel, "MessageChannel is created");
+
+  channel.port1.onmessage = function(evt) {
+    ok(true, "message received!");
+    SimpleTest.finish();
+  }
+
+  var ifr = document.createElement('browser');
+  ifr.setAttribute("src", "http://mochi.test:8888/tests/dom/base/test/iframe_messageChannel_chrome.html");
+  ifr.setAttribute("flex", "1");
+  ifr.addEventListener('load', function() {
+    ifr.contentWindow.postMessage(channel.port2, '*', [channel.port2]);
+  });
+
+  var body = document.getElementById("body");
+  body.appendChild(ifr);
+
+  SimpleTest.waitForExplicitFinish();
+
+  ]]></script>
+</window>
--- a/dom/crypto/WebCryptoTask.cpp
+++ b/dom/crypto/WebCryptoTask.cpp
@@ -312,17 +312,18 @@ public:
     if (mEncrypt) {
       if (!mPubKey) {
         mEarlyRv = NS_ERROR_DOM_INVALID_ACCESS_ERR;
         return;
       }
       mStrength = SECKEY_PublicKeyStrength(mPubKey);
 
       // Verify that the data input is not too big
-      // (as required by PKCS#1 / RFC 3447)
+      // (as required by PKCS#1 / RFC 3447, Section 7.2)
+      // http://tools.ietf.org/html/rfc3447#section-7.2
       if (mData.Length() > mStrength - 11) {
         mEarlyRv = NS_ERROR_DOM_DATA_ERR;
         return;
       }
     } else {
       if (!mPrivKey) {
         mEarlyRv = NS_ERROR_DOM_INVALID_ACCESS_ERR;
         return;
@@ -443,20 +444,22 @@ private:
     if (mSign) {
       // Return the computed MAC
       TypedArrayCreator<Uint8Array> ret(mResult);
       mResultPromise->MaybeResolve(ret);
     } else {
       // Compare the MAC to the provided signature
       // No truncation allowed
       bool equal = (mResult.Length() == mSignature.Length());
-      int cmp = NSS_SecureMemcmp(mSignature.Elements(),
-                                 mResult.Elements(),
-                                 mSignature.Length());
-      equal = equal && (cmp == 0);
+      if (equal) {
+        int cmp = NSS_SecureMemcmp(mSignature.Elements(),
+                                   mResult.Elements(),
+                                   mSignature.Length());
+        equal = (cmp == 0);
+      }
       mResultPromise->MaybeResolve(equal);
     }
   }
 };
 
 class RsassaPkcs1Task : public WebCryptoTask
 {
 public:
@@ -530,19 +533,23 @@ private:
       NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_OPERATION_ERR);
 
       rv = MapSECStatus(SGN_Update(ctx, mData.Elements(), mData.Length()));
       NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_OPERATION_ERR);
 
       rv = MapSECStatus(SGN_End(ctx, signature));
       NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_OPERATION_ERR);
 
-      mSignature.Assign(signature);
+      ATTEMPT_BUFFER_ASSIGN(mSignature, signature);
     } else {
       ScopedSECItem signature(mSignature.ToSECItem());
+      if (!signature) {
+        return NS_ERROR_DOM_UNKNOWN_ERR;
+      }
+
       ScopedVFYContext ctx(VFY_CreateContext(mPubKey, signature,
                                              mOidTag, nullptr));
       if (!ctx) {
         int err = PORT_GetError();
         if (err == SEC_ERROR_BAD_SIGNATURE) {
           mVerified = false;
           return NS_OK;
         }
@@ -580,16 +587,17 @@ public:
                    const ObjectOrString& aAlgorithm,
                    const CryptoOperationData& aData)
   {
     ATTEMPT_BUFFER_INIT(mData, aData);
 
     nsString algName;
     mEarlyRv = GetAlgorithmName(aCx, aAlgorithm, algName);
     if (NS_FAILED(mEarlyRv)) {
+      mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR;
       return;
     }
 
     if (algName.EqualsLiteral(WEBCRYPTO_ALG_SHA1))   {
       mOidTag = SEC_OID_SHA1;
     } else if (algName.EqualsLiteral(WEBCRYPTO_ALG_SHA224)) {
       mOidTag = SEC_OID_SHA224;
     } else if (algName.EqualsLiteral(WEBCRYPTO_ALG_SHA256)) {
@@ -932,42 +940,41 @@ private:
   {
     nsNSSShutDownPreventionLock locker;
 
     if (mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_RAW)) {
       mResult = mSymKey;
       if (mResult.Length() == 0) {
         return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
       }
+
+      return NS_OK;
     } else if (mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_PKCS8)) {
       if (!mPrivateKey) {
-        mEarlyRv = NS_ERROR_DOM_NOT_SUPPORTED_ERR;
+        return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
       }
 
       switch (mPrivateKey->keyType) {
         case rsaKey:
           Key::PrivateKeyToPkcs8(mPrivateKey.get(), mResult, locker);
-          mEarlyRv = NS_OK;
-          break;
+          return NS_OK;
         default:
-          mEarlyRv = NS_ERROR_DOM_NOT_SUPPORTED_ERR;
+          return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
       }
     } else if (mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_SPKI)) {
       if (!mPublicKey) {
         return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
       }
 
-      mEarlyRv = Key::PublicKeyToSpki(mPublicKey.get(), mResult, locker);
+      return Key::PublicKeyToSpki(mPublicKey.get(), mResult, locker);
     } else if (mFormat.EqualsLiteral(WEBCRYPTO_KEY_FORMAT_JWK)) {
-      mEarlyRv = NS_ERROR_DOM_NOT_SUPPORTED_ERR;
-    } else {
-      mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR;
+      return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
     }
 
-    return NS_OK;
+    return NS_ERROR_DOM_SYNTAX_ERR;
   }
 };
 
 class GenerateSymmetricKeyTask : public WebCryptoTask
 {
 public:
   GenerateSymmetricKeyTask(JSContext* aCx,
       const ObjectOrString& aAlgorithm, bool aExtractable,
@@ -983,29 +990,31 @@ public:
     mKey = new Key(global);
     mKey->SetExtractable(aExtractable);
     mKey->SetType(Key::SECRET);
 
     // Extract algorithm name
     nsString algName;
     mEarlyRv = GetAlgorithmName(aCx, aAlgorithm, algName);
     if (NS_FAILED(mEarlyRv)) {
+      mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR;
       return;
     }
 
     // Construct an appropriate KeyAlorithm
     nsRefPtr<KeyAlgorithm> algorithm;
     uint32_t allowedUsages = 0;
     if (algName.EqualsLiteral(WEBCRYPTO_ALG_AES_CBC) ||
         algName.EqualsLiteral(WEBCRYPTO_ALG_AES_CTR) ||
         algName.EqualsLiteral(WEBCRYPTO_ALG_AES_GCM)) {
       RootedDictionary<AesKeyGenParams> params(aCx);
       mEarlyRv = Coerce(aCx, params, aAlgorithm);
       if (NS_FAILED(mEarlyRv) || !params.mLength.WasPassed()) {
         mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR;
+        return;
       }
 
       mLength = params.mLength.Value();
       if (mLength != 128 && mLength != 192 && mLength != 256) {
         mEarlyRv = NS_ERROR_DOM_DATA_ERR;
         return;
       }
       algorithm = new AesKeyAlgorithm(global, algName, mLength);
@@ -1021,16 +1030,17 @@ public:
 
       nsString hashName;
       if (params.mHash.Value().IsString()) {
         hashName.Assign(params.mHash.Value().GetAsString());
       } else {
         Algorithm hashAlg;
         mEarlyRv = Coerce(aCx, hashAlg, params.mHash.Value());
         if (NS_FAILED(mEarlyRv) || !hashAlg.mName.WasPassed()) {
+          mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR;
           return;
         }
         hashName.Assign(hashAlg.mName.Value());
       }
 
       mLength = params.mLength.Value();
       algorithm = new HmacKeyAlgorithm(global, algName, mLength, hashName);
       allowedUsages = Key::SIGN | Key::VERIFY;
@@ -1047,18 +1057,16 @@ public:
         return;
       }
     }
 
     mLength = mLength >> 3; // bits to bytes
     mMechanism = algorithm->Mechanism();
     mKey->SetAlgorithm(algorithm);
     // SetSymKey done in Resolve, after we've done the keygen
-
-    return;
   }
 
 private:
   nsRefPtr<Key> mKey;
   size_t mLength;
   CK_MECHANISM_TYPE mMechanism;
   CryptoBuffer mKeyData;
 
@@ -1110,39 +1118,41 @@ public:
 
     // Create an empty key and set easy attributes
     mKeyPair = new KeyPair(global);
 
     // Extract algorithm name
     nsString algName;
     mEarlyRv = GetAlgorithmName(aCx, aAlgorithm, algName);
     if (NS_FAILED(mEarlyRv)) {
+      mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR;
       return;
     }
 
     // Construct an appropriate KeyAlorithm
     KeyAlgorithm* algorithm;
     uint32_t privateAllowedUsages = 0, publicAllowedUsages = 0;
     if (algName.EqualsLiteral(WEBCRYPTO_ALG_RSASSA_PKCS1)) {
       RootedDictionary<RsaHashedKeyGenParams> params(aCx);
       mEarlyRv = Coerce(aCx, params, aAlgorithm);
       if (NS_FAILED(mEarlyRv) || !params.mModulusLength.WasPassed() ||
           !params.mPublicExponent.WasPassed() ||
           !params.mHash.WasPassed()) {
-        // TODO fix error and handle default values
         mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR;
+        return;
       }
 
       // Pull relevant info
       uint32_t modulusLength = params.mModulusLength.Value();
       CryptoBuffer publicExponent;
       ATTEMPT_BUFFER_INIT(publicExponent, params.mPublicExponent.Value());
       nsString hashName;
       mEarlyRv = GetAlgorithmName(aCx, params.mHash.Value(), hashName);
       if (NS_FAILED(mEarlyRv)) {
+        mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR;
         return;
       }
 
       // Create algorithm
       algorithm = new RsaHashedKeyAlgorithm(global, algName, modulusLength,
                                             publicExponent, hashName);
       mKeyPair->PublicKey()->SetAlgorithm(algorithm);
       mKeyPair->PrivateKey()->SetAlgorithm(algorithm);
@@ -1158,18 +1168,18 @@ public:
 
       privateAllowedUsages = Key::SIGN;
       publicAllowedUsages = Key::VERIFY;
     } else if (algName.EqualsLiteral(WEBCRYPTO_ALG_RSAES_PKCS1)) {
       RootedDictionary<RsaKeyGenParams> params(aCx);
       mEarlyRv = Coerce(aCx, params, aAlgorithm);
       if (NS_FAILED(mEarlyRv) || !params.mModulusLength.WasPassed() ||
           !params.mPublicExponent.WasPassed()) {
-        // TODO fix error and handle default values
         mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR;
+        return;
       }
 
       // Pull relevant info
       uint32_t modulusLength = params.mModulusLength.Value();
       CryptoBuffer publicExponent;
       ATTEMPT_BUFFER_INIT(publicExponent, params.mPublicExponent.Value());
 
       // Create algorithm and note the mechanism
@@ -1210,18 +1220,16 @@ public:
       }
 
       mEarlyRv = mKeyPair->PublicKey()->AddUsageIntersecting(aKeyUsages[i],
                                                              publicAllowedUsages);
       if (NS_FAILED(mEarlyRv)) {
         return;
       }
     }
-
-    return;
   }
 
 private:
   nsRefPtr<KeyPair> mKeyPair;
   CK_MECHANISM_TYPE mMechanism;
   PK11RSAGenParams mRsaParams;
   ScopedSECKEYPublicKey mPublicKey;
   ScopedSECKEYPrivateKey mPrivateKey;
--- a/dom/events/EventListenerManager.cpp
+++ b/dom/events/EventListenerManager.cpp
@@ -2,16 +2,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 // Microsoft's API Name hackery sucks
 #undef CreateEvent
 
 #include "mozilla/BasicEvents.h"
+#include "mozilla/CycleCollectedJSRuntime.h"
 #include "mozilla/EventDispatcher.h"
 #include "mozilla/EventListenerManager.h"
 #ifdef MOZ_B2G
 #include "mozilla/Hal.h"
 #endif // #ifdef MOZ_B2G
 #include "mozilla/HalSensor.h"
 #include "mozilla/InternalMutationEvent.h"
 #include "mozilla/JSEventHandler.h"
@@ -1324,16 +1325,37 @@ EventListenerManager::MarkForCC()
       listener.mListener.GetWebIDLCallback()->Callback();
     }
   }
   if (mRefCnt.IsPurple()) {
     mRefCnt.RemovePurple();
   }
 }
 
+void
+EventListenerManager::TraceListeners(JSTracer* aTrc)
+{
+  uint32_t count = mListeners.Length();
+  for (uint32_t i = 0; i < count; ++i) {
+    const Listener& listener = mListeners.ElementAt(i);
+    JSEventHandler* jsEventHandler = listener.GetJSEventHandler();
+    if (jsEventHandler) {
+      const TypedEventHandler& typedHandler =
+        jsEventHandler->GetTypedEventHandler();
+      if (typedHandler.HasEventHandler()) {
+        mozilla::TraceScriptHolder(typedHandler.Ptr(), aTrc);
+      }
+    } else if (listener.mListenerType == Listener::eWebIDLListener) {
+      mozilla::TraceScriptHolder(listener.mListener.GetWebIDLCallback(), aTrc);
+    }
+    // We might have eWrappedJSListener, but that is the legacy type for
+    // JS implemented event listeners, and trickier to handle here.
+  }
+}
+
 already_AddRefed<nsIScriptGlobalObject>
 EventListenerManager::GetScriptGlobalAndDocument(nsIDocument** aDoc)
 {
   nsCOMPtr<nsINode> node(do_QueryInterface(mTarget));
   nsCOMPtr<nsIDocument> doc;
   nsCOMPtr<nsIScriptGlobalObject> global;
   if (node) {
     // Try to get context from doc
--- a/dom/events/EventListenerManager.h
+++ b/dom/events/EventListenerManager.h
@@ -15,16 +15,17 @@
 #include "nsGkAtoms.h"
 #include "nsIDOMEventListener.h"
 #include "nsTObserverArray.h"
 
 class nsIDOMEvent;
 class nsIEventListenerInfo;
 class nsIScriptContext;
 class nsPIDOMWindow;
+class JSTracer;
 
 struct EventTypeData;
 
 template<class T> class nsCOMArray;
 
 namespace mozilla {
 
 class ELMCreationDetector;
@@ -399,16 +400,18 @@ public:
 
   uint32_t ListenerCount() const
   {
     return mListeners.Length();
   }
 
   void MarkForCC();
 
+  void TraceListeners(JSTracer* aTrc);
+
   dom::EventTarget* GetTarget() { return mTarget; }
 
 protected:
   void HandleEventInternal(nsPresContext* aPresContext,
                            WidgetEvent* aEvent,
                            nsIDOMEvent** aDOMEvent,
                            dom::EventTarget* aCurrentTarget,
                            nsEventStatus* aEventStatus);
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -474,17 +474,17 @@ TabChildBase::ProcessUpdateFrame(const F
 }
 
 nsEventStatus
 TabChildBase::DispatchSynthesizedMouseEvent(uint32_t aMsg, uint64_t aTime,
                                             const LayoutDevicePoint& aRefPoint,
                                             nsIWidget* aWidget)
 {
   MOZ_ASSERT(aMsg == NS_MOUSE_MOVE || aMsg == NS_MOUSE_BUTTON_DOWN ||
-             aMsg == NS_MOUSE_BUTTON_UP);
+             aMsg == NS_MOUSE_BUTTON_UP || aMsg == NS_MOUSE_MOZLONGTAP);
 
   WidgetMouseEvent event(true, aMsg, nullptr,
                          WidgetMouseEvent::eReal, WidgetMouseEvent::eNormal);
   event.refPoint = LayoutDeviceIntPoint(aRefPoint.x, aRefPoint.y);
   event.time = aTime;
   event.button = WidgetMouseEvent::eLeftButton;
   event.inputSource = nsIDOMMouseEvent::MOZ_SOURCE_TOUCH;
   if (aMsg != NS_MOUSE_MOVE) {
@@ -686,16 +686,17 @@ TabChild::TabChild(ContentChild* aManage
   , mAppPackageFileDescriptorRecved(false)
   , mLastBackgroundColor(NS_RGB(255, 255, 255))
   , mDidFakeShow(false)
   , mNotified(false)
   , mTriedBrowserInit(false)
   , mOrientation(eScreenOrientation_PortraitPrimary)
   , mUpdateHitRegion(false)
   , mContextMenuHandled(false)
+  , mLongTapEventHandled(false)
   , mWaitingTouchListeners(false)
   , mIgnoreKeyPressEvent(false)
   , mActiveElementManager(new ActiveElementManager())
   , mHasValidInnerSize(false)
 {
   if (!sActiveDurationMsSet) {
     Preferences::AddIntVarCache(&sActiveDurationMs,
                                 "ui.touch_activation.duration_ms",
@@ -1734,29 +1735,44 @@ TabChild::RecvHandleLongTap(const CSSPoi
   }
 
   mContextMenuHandled =
       DispatchMouseEvent(NS_LITERAL_STRING("contextmenu"),
                          APZCCallbackHelper::ApplyCallbackTransform(aPoint, aGuid),
                          2, 1, 0, false,
                          nsIDOMMouseEvent::MOZ_SOURCE_TOUCH);
 
-  SendContentReceivedTouch(aGuid, mContextMenuHandled);
+  // If no one handle context menu, fire MOZLONGTAP event
+  if (!mContextMenuHandled) {
+    LayoutDevicePoint currentPoint =
+      APZCCallbackHelper::ApplyCallbackTransform(aPoint, aGuid) * mWidget->GetDefaultScale();
+    int time = 0;
+    nsEventStatus status =
+      DispatchSynthesizedMouseEvent(NS_MOUSE_MOZLONGTAP, time, currentPoint, mWidget);
+    mLongTapEventHandled = (status == nsEventStatus_eConsumeNoDefault);
+  }
+
+  SendContentReceivedTouch(aGuid, mContextMenuHandled || mLongTapEventHandled);
 
   return true;
 }
 
 bool
 TabChild::RecvHandleLongTapUp(const CSSPoint& aPoint, const ScrollableLayerGuid& aGuid)
 {
   if (mContextMenuHandled) {
     mContextMenuHandled = false;
     return true;
   }
 
+  if (mLongTapEventHandled) {
+    mLongTapEventHandled = false;
+    return true;
+  }
+
   RecvHandleSingleTap(aPoint, aGuid);
   return true;
 }
 
 bool
 TabChild::RecvNotifyAPZStateChange(const ViewID& aViewId,
                                    const APZStateChange& aChange,
                                    const int& aArg)
--- a/dom/ipc/TabChild.h
+++ b/dom/ipc/TabChild.h
@@ -556,16 +556,17 @@ private:
         mCachedFileDescriptorInfos;
     nscolor mLastBackgroundColor;
     bool mDidFakeShow;
     bool mNotified;
     bool mTriedBrowserInit;
     ScreenOrientation mOrientation;
     bool mUpdateHitRegion;
     bool mContextMenuHandled;
+    bool mLongTapEventHandled;
     bool mWaitingTouchListeners;
     void FireSingleTapEvent(LayoutDevicePoint aPoint);
 
     bool mIgnoreKeyPressEvent;
     nsRefPtr<ActiveElementManager> mActiveElementManager;
     bool mHasValidInnerSize;
 
     DISALLOW_EVIL_CONSTRUCTORS(TabChild);
--- a/dom/media/moz.build
+++ b/dom/media/moz.build
@@ -7,16 +7,21 @@
 if CONFIG['MOZ_WEBRTC']:
     DIRS += ['bridge']
 
     LOCAL_INCLUDES += [
         '/media/webrtc/signaling/src/common',
         '/media/webrtc/trunk',
     ]
 
+    if CONFIG['GNU_CXX']:
+        CXXFLAGS += [
+            '-Wno-unused-local-typedefs', # Workaround until we fix bug 1020661
+        ]
+
 TEST_DIRS += ['tests/mochitest', 'tests/ipc', 'tests/identity']
 
 XPIDL_SOURCES += [
     'nsIDOMMediaStream.idl',
     'nsIDOMNavigatorUserMedia.idl',
     'nsIMediaManager.idl',
 ]
 
--- a/dom/media/tests/identity/mochitest.ini
+++ b/dom/media/tests/identity/mochitest.ini
@@ -1,23 +1,19 @@
 [DEFAULT]
-skip-if = e10s
+# All tests are disabled on android&b2g due to lack of https support in
+# mochitests (Bug 907770)
+# Tests are also disabled on b2g due to lack of e10s support in WebRTC identity
+# (Bug 975144)
+skip-if = e10s || os == "android" || appname == "b2g"
 support-files =
   /.well-known/idp-proxy/idp.html
   /.well-known/idp-proxy/idp-proxy.js
   identityevent.js
 
-# All tests are disabled on android&b2g due to lack of https support in
-# mochitests (Bug 907770)
-# All tests are disabled on b2g due to lack of e10s support in WebRTC identity
-# (Bug 975144)
 [test_idpproxy.html]
-skip-if = os == "android" || appname == "b2g"
 [test_getIdentityAssertion.html]
-skip-if = os == "android" || appname == "b2g"
 [test_setIdentityProvider.html]
-skip-if = os == "android" || appname == "b2g"
 [test_setIdentityProviderWithErrors.html]
-skip-if = os == "android" || appname == "b2g"
 [test_peerConnection_peerIdentity.html]
-skip-if = os == "android" || appname == "b2g"
+
+# Bug 950317: Hack for making a cleanup hook after finishing all WebRTC cases
 [../mochitest/test_zmedia_cleanup.html]
-skip-if = os == "android" || appname == "b2g"
--- a/dom/media/tests/mochitest/mochitest.ini
+++ b/dom/media/tests/mochitest/mochitest.ini
@@ -8,25 +8,25 @@ support-files =
   NetworkPreparationChromeScript.js
   blacksilence.js
   turnConfig.js
 
 [test_dataChannel_basicAudio.html]
 skip-if = toolkit == 'gonk' #Bug 962984 for debug, bug 963244 for opt
 [test_dataChannel_basicAudioVideo.html]
 # Disabled on OS X for bug 930481 timeouts
-skip-if = os == 'mac' || toolkit=='gonk' # b2g(Bug 960442, video support for WebRTC is disabled on b2g) b2g-debug(Bug 960442, video support for WebRTC is disabled on b2g)
+skip-if = os == 'mac' || toolkit=='gonk' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
 [test_dataChannel_basicAudioVideoCombined.html]
 # Disabled on OS X for bug 930481 timeouts
-skip-if = os == 'mac' || toolkit=='gonk' # b2g(Bug 960442, video support for WebRTC is disabled on b2g) b2g-debug(Bug 960442, video support for WebRTC is disabled on b2g)
+skip-if = os == 'mac' || toolkit=='gonk' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
 [test_dataChannel_basicDataOnly.html]
 [test_dataChannel_basicVideo.html]
 skip-if = toolkit=='gonk' # b2g emulator seems to bee too slow (Bug 1016498 and 1008080)
 [test_dataChannel_bug1013809.html]
-skip-if = toolkit=='gonk' # b2g(Bug 960442, video support for WebRTC is disabled on b2g) b2g-debug(Bug 960442, video support for WebRTC is disabled on b2g)
+skip-if = toolkit=='gonk' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
 [test_dataChannel_noOffer.html]
 [test_getUserMedia_basicAudio.html]
 skip-if = (toolkit == 'gonk' && debug) #debug-only failure
 [test_getUserMedia_basicVideo.html]
 skip-if = (toolkit == 'gonk' && debug) #debug-only failure
 [test_getUserMedia_basicVideoAudio.html]
 skip-if = (toolkit == 'gonk' && debug) #debug-only failure, turned an intermittent (bug 962579) into a permanant orange
 [test_getUserMedia_constraints.html]
@@ -46,40 +46,41 @@ skip-if = (toolkit == 'gonk' && debug) #
 [test_getUserMedia_stopVideoAudioStreamWithFollowupVideoAudio.html]
 [test_getUserMedia_stopVideoStream.html]
 [test_getUserMedia_stopVideoStreamWithFollowupVideo.html]
 [test_getUserMedia_peerIdentity.html]
 [test_peerConnection_addCandidateInHaveLocalOffer.html]
 [test_peerConnection_basicAudio.html]
 skip-if = (toolkit == 'gonk' && debug) #Bug 962984, test fail on b2g debug build
 [test_peerConnection_basicAudioVideo.html]
-skip-if = toolkit=='gonk' # b2g(Bug 960442, video support for WebRTC is disabled on b2g) b2g-debug(Bug 960442, video support for WebRTC is disabled on b2g)
+skip-if = toolkit=='gonk' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
 [test_peerConnection_basicAudioVideoCombined.html]
-skip-if = toolkit=='gonk' # b2g(Bug 960442, video support for WebRTC is disabled on b2g) b2g-debug(Bug 960442, video support for WebRTC is disabled on b2g)
+skip-if = toolkit=='gonk' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
 [test_peerConnection_basicVideo.html]
-skip-if = toolkit=='gonk' # b2g(Bug 960442, video support for WebRTC is disabled on b2g) b2g-debug(Bug 960442, video support for WebRTC is disabled on b2g)
+skip-if = toolkit=='gonk' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
 [test_peerConnection_bug822674.html]
 [test_peerConnection_bug825703.html]
 [test_peerConnection_bug827843.html]
-skip-if = toolkit=='gonk' # b2g(Bug 960442, video support for WebRTC is disabled on b2g) b2g-debug(Bug 960442, video support for WebRTC is disabled on b2g)
+skip-if = toolkit=='gonk' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
 [test_peerConnection_bug834153.html]
 [test_peerConnection_bug835370.html]
 skip-if = toolkit=='gonk' # b2g emulator seems to bee too slow (Bug 1016498 and 1008080)
 [test_peerConnection_bug1013809.html]
 [test_peerConnection_close.html]
 [test_peerConnection_errorCallbacks.html]
 [test_peerConnection_offerRequiresReceiveAudio.html]
-skip-if = toolkit=='gonk' # b2g(Bug 960442, video support for WebRTC is disabled on b2g) b2g-debug(Bug 960442, video support for WebRTC is disabled on b2g)
+skip-if = toolkit=='gonk' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
 [test_peerConnection_offerRequiresReceiveVideo.html]
-skip-if = toolkit=='gonk' # b2g(Bug 960442, video support for WebRTC is disabled on b2g) b2g-debug(Bug 960442, video support for WebRTC is disabled on b2g)
+skip-if = toolkit=='gonk' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
 [test_peerConnection_offerRequiresReceiveVideoAudio.html]
-skip-if = toolkit=='gonk' # b2g(Bug 960442, video support for WebRTC is disabled on b2g) b2g-debug(Bug 960442, video support for WebRTC is disabled on b2g)
+skip-if = toolkit=='gonk' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
 [test_peerConnection_setLocalAnswerInHaveLocalOffer.html]
 [test_peerConnection_setLocalAnswerInStable.html]
 [test_peerConnection_setLocalOfferInHaveRemoteOffer.html]
 [test_peerConnection_setRemoteAnswerInHaveRemoteOffer.html]
 [test_peerConnection_setRemoteAnswerInStable.html]
 [test_peerConnection_setRemoteOfferInHaveLocalOffer.html]
 [test_peerConnection_throwInCallbacks.html]
-skip-if = toolkit=='gonk' # b2g(Bug 960442, video support for WebRTC is disabled on b2g) b2g-debug(Bug 960442, video support for WebRTC is disabled on b2g)
+skip-if = toolkit=='gonk' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
 [test_peerConnection_toJSON.html]
-# Bug950317: Hack for making a cleanup hook after finishing all WebRTC cases
+
+# Bug 950317: Hack for making a cleanup hook after finishing all WebRTC cases
 [test_zmedia_cleanup.html]
--- a/dom/media/tests/mochitest/templates.js
+++ b/dom/media/tests/mochitest/templates.js
@@ -417,16 +417,72 @@ var commandsDataChannel = [
         function () {
         is(test.pcLocal.signalingState, STABLE,
            "signalingState after local setRemoteDescription is 'stable'");
         test.next();
       });
     }
   ],
   [
+    'PC_LOCAL_WAIT_FOR_ICE_CONNECTED',
+    function (test) {
+      var myTest = test;
+      var myPc = myTest.pcLocal;
+
+      function onIceConnectedSuccess () {
+        ok(true, "pc_local: ICE switched to 'connected' state");
+        myTest.next();
+      };
+      function onIceConnectedFailed () {
+        dumpSdp(myTest);
+        ok(false, "pc_local: ICE failed to switch to 'connected' state: " + myPc.iceConnectionState);
+        myTest.next();
+      };
+
+      if (myPc.isIceConnected()) {
+        ok(true, "pc_local: ICE is in connected state");
+        myTest.next();
+      } else if (myPc.isIceConnectionPending()) {
+        myPc.waitForIceConnected(onIceConnectedSuccess, onIceConnectedFailed);
+      } else {
+        dumpSdp(myTest);
+        ok(false, "pc_local: ICE is already in bad state: " + myPc.iceConnectionState);
+        myTest.next();
+      }
+    }
+  ],
+  [
+    'PC_REMOTE_WAIT_FOR_ICE_CONNECTED',
+    function (test) {
+      var myTest = test;
+      var myPc = myTest.pcRemote;
+
+      function onIceConnectedSuccess () {
+        ok(true, "pc_remote: ICE switched to 'connected' state");
+        myTest.next();
+      };
+      function onIceConnectedFailed () {
+        dumpSdp(myTest);
+        ok(false, "pc_remote: ICE failed to switch to 'connected' state: " + myPc.iceConnectionState);
+        myTest.next();
+      };
+
+      if (myPc.isIceConnected()) {
+        ok(true, "pc_remote: ICE is in connected state");
+        myTest.next();
+      } else if (myPc.isIceConnectionPending()) {
+        myPc.waitForIceConnected(onIceConnectedSuccess, onIceConnectedFailed);
+      } else {
+        dumpSdp(myTest);
+        ok(false, "pc_remote: ICE is already in bad state: " + myPc.iceConnectionState);
+        myTest.next();
+      }
+    }
+  ],
+  [
     'PC_LOCAL_VERIFY_DATA_CHANNEL_STATE',
     function (test) {
       test.waitForInitialDataChannel(test.pcLocal, function() {
         test.next();
       }, function() {
         ok(false, test.pcLocal + " initial dataChannels[0] failed to switch to 'open'");
         unexpectedEventAndFinish(this, 'timeout')
       });
--- a/dom/promise/Promise.cpp
+++ b/dom/promise/Promise.cpp
@@ -1203,19 +1203,21 @@ Promise::RunResolveTask(JS::Handle<JS::V
       !mHadRejectCallback &&
       !NS_IsMainThread()) {
     WorkerPrivate* worker = GetCurrentThreadWorkerPrivate();
     MOZ_ASSERT(worker);
     worker->AssertIsOnWorkerThread();
 
     mFeature = new PromiseReportRejectFeature(this);
     if (NS_WARN_IF(!worker->AddFeature(worker->GetJSContext(), mFeature))) {
+      // To avoid a false RemoveFeature().
+      mFeature = nullptr;
       // Worker is shutting down, report rejection immediately since it is
       // unlikely that reject callbacks will be added after this point.
-      MaybeReportRejected();
+      MaybeReportRejectedOnce();
     }
   }
 
   RunTask();
 }
 
 void
 Promise::RemoveFeature()
--- a/dom/src/offline/nsDOMOfflineResourceList.cpp
+++ b/dom/src/offline/nsDOMOfflineResourceList.cpp
@@ -8,17 +8,16 @@
 #include "nsIScriptSecurityManager.h"
 #include "nsError.h"
 #include "mozilla/dom/DOMStringList.h"
 #include "nsIPrefetchService.h"
 #include "nsCPrefetchService.h"
 #include "nsNetUtil.h"
 #include "nsNetCID.h"
 #include "nsICacheSession.h"
-#include "nsICacheService.h"
 #include "nsIOfflineCacheUpdate.h"
 #include "nsAutoPtr.h"
 #include "nsContentUtils.h"
 #include "nsIObserverService.h"
 #include "nsIScriptGlobalObject.h"
 #include "nsIWebNavigation.h"
 #include "mozilla/dom/OfflineResourceListBinding.h"
 #include "mozilla/EventDispatcher.h"
--- a/dom/tests/mochitest/ajax/offline/offlineTests.js
+++ b/dom/tests/mochitest/ajax/offline/offlineTests.js
@@ -1,13 +1,14 @@
 // Utility functions for offline tests.
 var Cc = SpecialPowers.Cc;
 var Ci = SpecialPowers.Ci;
 var Cu = SpecialPowers.Cu;
 var LoadContextInfo = Cu.import("resource://gre/modules/LoadContextInfo.jsm", {}).LoadContextInfo;
+var CommonUtils = Cu.import("resource://services-common/utils.js", {}).CommonUtils;
 
 const kNetBase = 2152398848; // 0x804B0000
 var NS_ERROR_CACHE_KEY_NOT_FOUND = kNetBase + 61;
 var NS_ERROR_CACHE_KEY_WAIT_FOR_VALIDATION = kNetBase + 64;
 
 // Reading the contents of multiple cache entries asynchronously
 function OfflineCacheContents(urls) {
   this.urls = urls;
@@ -17,23 +18,24 @@ function OfflineCacheContents(urls) {
 OfflineCacheContents.prototype = {
 QueryInterface: function(iid) {
     if (!iid.equals(Ci.nsISupports) &&
         !iid.equals(Ci.nsICacheListener)) {
       throw Cr.NS_ERROR_NO_INTERFACE;
     }
     return this;
   },
-onCacheEntryAvailable: function(desc, accessGranted, status) {
+onCacheEntryCheck: function() { return Ci.nsICacheEntryOpenCallback.ENTRY_WANTED; },
+onCacheEntryAvailable: function(desc, isnew, applicationCache, status) {
     if (!desc) {
       this.fetch(this.callback);
       return;
     }
 
-    var stream = desc.QueryInterface(Ci.nsICacheEntryDescriptor).openInputStream(0);
+    var stream = desc.openInputStream(0);
     var sstream = Cc["@mozilla.org/scriptableinputstream;1"]
                  .createInstance(SpecialPowers.Ci.nsIScriptableInputStream);
     sstream.init(stream);
     this.contents[desc.key] = sstream.read(sstream.available());
     sstream.close();
     desc.close();
     this.fetch(this.callback);
   },
@@ -44,18 +46,18 @@ fetch: function(callback)
   if (this.urls.length == 0) {
     callback(this.contents);
     return;
   }
 
   var url = this.urls.shift();
   var self = this;
 
-  var cacheSession = OfflineTest.getActiveSession();
-  cacheSession.asyncOpenCacheEntry(url, Ci.nsICache.ACCESS_READ, this);
+  var cacheStorage = OfflineTest.getActiveStorage();
+  cacheStorage.asyncOpenURI(CommonUtils.makeURI(url), "", Ci.nsICacheStorage.OPEN_READONLY, this);
 }
 };
 
 var OfflineTest = {
 
 _allowedByDefault: false,
 
 _hasSlave: false,
@@ -250,37 +252,36 @@ failEvent: function(e)
 
 // The offline API as specified has no way to watch the load of a resource
 // added with applicationCache.mozAdd().
 waitForAdd: function(url, onFinished) {
   // Check every half second for ten seconds.
   var numChecks = 20;
 
   var waitForAddListener = {
-    onCacheEntryAvailable: function(entry, access, status) {
+    onCacheEntryCheck: function() { return Ci.nsICacheEntryOpenCallback.ENTRY_WANTED; },
+    onCacheEntryAvailable: function(entry, isnew, applicationCache, status) {
       if (entry) {
         entry.close();
         onFinished();
         return;
       }
 
       if (--numChecks == 0) {
         onFinished();
         return;
       }
 
       setTimeout(OfflineTest.priv(waitFunc), 500);
     }
   };
 
   var waitFunc = function() {
-    var cacheSession = OfflineTest.getActiveSession();
-    cacheSession.asyncOpenCacheEntry(url,
-                                     Ci.nsICache.ACCESS_READ,
-                                     waitForAddListener);
+    var cacheStorage = OfflineTest.getActiveStorage();
+    cacheStorage.asyncOpenURI(CommonUtils.makeURI(url), "", Ci.nsICacheStorage.OPEN_READONLY, waitForAddListener);
   }
 
   setTimeout(this.priv(waitFunc), 500);
 },
 
 manifestURL: function(overload)
 {
   var manifestURLspec;
@@ -322,28 +323,26 @@ getActiveCache: function(overload)
   // Note that this is the current active cache in the cache stack, not the
   // one associated with this window.
   var serv = Cc["@mozilla.org/network/application-cache-service;1"]
              .getService(Ci.nsIApplicationCacheService);
   var groupID = serv.buildGroupID(this.manifestURL(overload), this.loadContextInfo());
   return serv.getActiveCache(groupID);
 },
 
-getActiveSession: function()
+getActiveStorage: function()
 {
   var cache = this.getActiveCache();
   if (!cache) {
     return null;
   }
 
-  var cacheService = Cc["@mozilla.org/network/cache-service;1"]
-                     .getService(Ci.nsICacheService);
-  return cacheService.createSession(cache.clientID,
-                                    Ci.nsICache.STORE_OFFLINE,
-                                    true);
+  var cacheService = Cc["@mozilla.org/netwerk/cache-storage-service;1"]
+                     .getService(Ci.nsICacheStorageService);
+  return cacheService.appCacheStorage(LoadContextInfo.default, cache);
 },
 
 priv: function(func)
 {
   var self = this;
   return function() {
     func(arguments);
   }
@@ -360,34 +359,35 @@ checkCacheEntries: function(entries, cal
     }
   }
 
   checkNextEntry();
 },
 
 checkCache: function(url, expectEntry, callback)
 {
-  var cacheSession = this.getActiveSession();
-  this._checkCache(cacheSession, url, expectEntry, callback);
+  var cacheStorage = this.getActiveStorage();
+  this._checkCache(cacheStorage, url, expectEntry, callback);
 },
 
-_checkCache: function(cacheSession, url, expectEntry, callback)
+_checkCache: function(cacheStorage, url, expectEntry, callback)
 {
-  if (!cacheSession) {
+  if (!cacheStorage) {
     if (expectEntry) {
       this.ok(false, url + " should exist in the offline cache (no session)");
     } else {
       this.ok(true, url + " should not exist in the offline cache (no session)");
     }
     if (callback) setTimeout(this.priv(callback), 0);
     return;
   }
 
   var _checkCacheListener = {
-    onCacheEntryAvailable: function(entry, access, status) {
+    onCacheEntryCheck: function() { return Ci.nsICacheEntryOpenCallback.ENTRY_WANTED; },
+    onCacheEntryAvailable: function(entry, isnew, applicationCache, status) {
       if (entry) {
         if (expectEntry) {
           OfflineTest.ok(true, url + " should exist in the offline cache");
         } else {
           OfflineTest.ok(false, url + " should not exist in the offline cache");
         }
         entry.close();
       } else {
@@ -407,20 +407,17 @@ checkCache: function(url, expectEntry, c
         } else {
           OfflineTest.ok(false, "got invalid error for " + url);
         }
       }
       if (callback) setTimeout(OfflineTest.priv(callback), 0);
     }
   };
 
-  cacheSession.asyncOpenCacheEntry(url,
-                                   Ci.nsICache.ACCESS_READ,
-                                   _checkCacheListener,
-                                   false);
+  cacheStorage.asyncOpenURI(CommonUtils.makeURI(url), "", Ci.nsICacheStorage.OPEN_READONLY, _checkCacheListener);
 },
 
 setSJSState: function(sjsPath, stateQuery)
 {
   var client = new XMLHttpRequest();
   client.open("GET", sjsPath + "?state=" + stateQuery, false);
 
   var appcachechannel = SpecialPowers.wrap(client).channel.QueryInterface(Ci.nsIApplicationCacheChannel);
--- a/dom/tests/mochitest/notification/test_notification_resend.html
+++ b/dom/tests/mochitest/notification/test_notification_resend.html
@@ -150,17 +150,17 @@
         is(notif.text, "Body", "Notification body is valid: " + notif.text);
         is(notif.manifestURL, manifestURL, "Notification manifest URL is valid: " + notif.manifestURL);
         is(notif.imageURL, "icon.jpg", "Notification icon URL is valid: " + notif.imageURL);
         is(notif.lang, "en-US", "Notification lang is valid: " + notif.lang);
         is(notif.id, notif.manifestURL + "#tag:" + notif.tag, "Notification id is valid: " + notif.id);
         ok(notif.dbId.match(uuidRegEx), "Notification dbId is valid: " + notif.dbId);
         is(notif.dir, "ltr", "Notification dir is valid: " + notif.dir);
         is(notif.tag, "fakeTag", "Notification tag is valid: " + notif.tag);
-        ok((notif.timestamp > now), "Notification timestamp is valid: " + notif.timestamp);
+        ok((notif.timestamp >= now), "Notification timestamp is valid: (" + notif.timestamp + " >= " + now + ")");
         notif2.close();
       });
     }
   ];
 
   MockServices.register();
   NotificationTest.run(steps, function () {
     MockServices.unregister();
--- a/dom/webidl/HTMLLinkElement.webidl
+++ b/dom/webidl/HTMLLinkElement.webidl
@@ -39,11 +39,12 @@ partial interface HTMLLinkElement {
   [SetterThrows, Pure]
            attribute DOMString rev;
   [SetterThrows, Pure]
            attribute DOMString target;
 };
 
 // http://w3c.github.io/webcomponents/spec/imports/#interface-import
 partial interface HTMLLinkElement {
+    [Pref="dom.webcomponents.enabled"]
     readonly attribute Document? import;
 };
 
--- a/dom/webidl/MessageChannel.webidl
+++ b/dom/webidl/MessageChannel.webidl
@@ -2,13 +2,13 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
  *
  * For more information on this interface, please see
  * http://www.whatwg.org/specs/web-apps/current-work/#channel-messaging
  */
 
-[Constructor, Pref="dom.messageChannel.enabled"]
+[Constructor, Func="MessageChannel::Enabled"]
 interface MessageChannel {
   readonly attribute MessagePort port1;
   readonly attribute MessagePort port2;
 };
--- a/dom/webidl/Window.webidl
+++ b/dom/webidl/Window.webidl
@@ -280,16 +280,18 @@ partial interface Window {
   /**
    * Method for sizing this window to the content in the window.
    */
   [Throws] void             sizeToContent();
 
   // XXX Shouldn't this be in nsIDOMChromeWindow?
   [ChromeOnly, Replaceable, Throws] readonly attribute MozControllers controllers;
 
+  [ChromeOnly, Throws] readonly attribute Element? realFrameElement;
+
   [Throws] readonly attribute float               mozInnerScreenX;
   [Throws] readonly attribute float               mozInnerScreenY;
   [Throws] readonly attribute float               devicePixelRatio;
 
   /* The maximum offset that the window can be scrolled to
      (i.e., the document width/height minus the scrollport width/height) */
   [Replaceable, Throws] readonly attribute long   scrollMaxX;
   [Replaceable, Throws] readonly attribute long   scrollMaxY;
new file mode 100644
--- /dev/null
+++ b/dom/workers/test/bug1020226_frame.html
@@ -0,0 +1,20 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1020226
+-->
+<head>
+  <meta charset="utf-8">
+  <title>Test for Bug 1020226</title>
+</head>
+<body>
+
+<script type="application/javascript">
+  var worker = new Worker("bug1020226_worker.js");
+  worker.onmessage = function(e) {
+    window.parent.postMessage("loaded", "*");
+  }
+</script>
+</body>
+</html>
+
new file mode 100644
--- /dev/null
+++ b/dom/workers/test/bug1020226_worker.js
@@ -0,0 +1,11 @@
+var p = new Promise(function(resolve, reject) {
+  // This causes a runnable to be queued.
+  reject(new Error());
+  postMessage("loaded");
+
+  // This prevents that runnable from running until the window calls terminate(),
+  // at which point the worker goes into the Canceling state and then an
+  // AddFeature() is attempted, which fails, which used to result in multiple
+  // calls to the error reporter, one after the worker's context had been GCed.
+  while (true);
+});
--- a/dom/workers/test/mochitest.ini
+++ b/dom/workers/test/mochitest.ini
@@ -1,12 +1,14 @@
 [DEFAULT]
 support-files =
   WorkerTest_badworker.js
   atob_worker.js
+  bug1020226_worker.js
+  bug1020226_frame.html
   clearTimeouts_worker.js
   closeOnGC_server.sjs
   closeOnGC_worker.js
   close_worker.js
   content_worker.js
   console_worker.js
   consoleReplaceable_worker.js
   csp_worker.js
@@ -73,16 +75,17 @@ support-files =
   subdir/relativeLoad_sub_import.js
 
 [test_404.html]
 [test_atob.html]
 [test_blobConstructor.html]
 [test_blobWorkers.html]
 [test_bug949946.html]
 [test_bug1010784.html]
+[test_bug1020226.html]
 [test_chromeWorker.html]
 [test_clearTimeouts.html]
 [test_close.html]
 [test_closeOnGC.html]
 skip-if = (buildapp == 'b2g' && (toolkit != 'gonk' || debug)) || toolkit == 'android' #bug 881404 # b2g-debug(times out) b2g-desktop(times out)
 [test_console.html]
 [test_consoleReplaceable.html]
 [test_contentWorker.html]
new file mode 100644
--- /dev/null
+++ b/dom/workers/test/test_bug1020226.html
@@ -0,0 +1,38 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1020226
+-->
+<head>
+  <meta charset="utf-8">
+  <title>Test for Bug 1020226</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.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=1020226">Mozilla Bug 1020226</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+<iframe id="iframe" src="bug1020226_frame.html" onload="finishTest();">
+</iframe>
+</div>
+<pre id="test">
+<script type="application/javascript">
+function finishTest() {
+  document.getElementById("iframe").onload = null;
+  window.onmessage = function(e) {
+    info("Got message");
+    document.getElementById("iframe").src = "about:blank";
+    // We aren't really interested in the test, it shouldn't crash when the
+    // worker is GCed later.
+    ok(true, "Should not crash");
+    SimpleTest.finish();
+  };
+}
+
+SimpleTest.waitForExplicitFinish();
+</script>
+</pre>
+</body>
+</html>
--- a/editor/composer/src/moz.build
+++ b/editor/composer/src/moz.build
@@ -34,12 +34,24 @@ RESOURCE_FILES += [
     'res/table-add-row-before-hover.gif',
     'res/table-add-row-before.gif',
     'res/table-remove-column-active.gif',
     'res/table-remove-column-hover.gif',
     'res/table-remove-column.gif',
     'res/table-remove-row-active.gif',
     'res/table-remove-row-hover.gif',
     'res/table-remove-row.gif',
+    'res/text_caret.png',
+    'res/text_caret@1.5x.png',
+    'res/text_caret@2.25x.png',
+    'res/text_caret@2x.png',
+    'res/text_caret_tilt_left.png',
+    'res/text_caret_tilt_left@1.5x.png',
+    'res/text_caret_tilt_left@2.25x.png',
+    'res/text_caret_tilt_left@2x.png',
+    'res/text_caret_tilt_right.png',
+    'res/text_caret_tilt_right@1.5x.png',
+    'res/text_caret_tilt_right@2.25x.png',
+    'res/text_caret_tilt_right@2x.png',
     'res/text_selection_handle.png',
     'res/text_selection_handle@1.5.png',
     'res/text_selection_handle@2.png',
 ]
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..167cb6526ce7b354b9a395df1c8b2d9e99918f30
GIT binary patch
literal 1652
zc%17D@N?(olHy`uVBq!ia0vp^qChOg!3HEF9L1f1lw^r(L`iUdT1k0gQ7VIDN`6wR
zf@f}GdTLN=VoGJ<$y6H#24<Dakcg59UmvUF{9L_6kQ%*;+yVv=u(7WwNKDR7Em25H
zP0!4;ReHaBzmh^`img((sjq==fpcm`rbks#YH*cbNODznvSo^ry`6$hg%!|%+|-gp
zg^Jvqyke^gTP3i$RzNmLSYJs2tfVB{Rte&$2;Tq&=lr5n1yem^-DCqpLj^N4Jwp>y
zGc!XS1tSAPBYguPGSf9Qu`)HYGBQ_y0wthrMJZ`kK`w4kyMR1frHqo20xNy}^73-M
za$~*xqI7*jOG`_T8Ae9BKoz>hm3bwJ6}oxF$}kgLQj3#|G7CyF^Yauy{KTaE(h^%G
zC72g-3*g4)6+?pw7-0Gpi3R$GdItJP3VnU?E6vS?t1d1HN=?JBx;Uh=AXPsowK%`D
zC>a=WY04nY1y;^Qsfi`|MIrh5Ij~R+$jC3rFV4s>P;d@5Q_%2DOwP;$321_K`1)FT
z<`tJD<|U_ky4WfKMf5T=Q><K!Ok9jD-JD%449pD;U5zcBO$=R44S_r(Q&S^HSD0Rx
z{N&Qy)Vvay-V}sh7o2)Qi2<TJwJ5VJHN~wcKUV?lX{$`!ZgIrz7Kq*y+-`BgsaGH9
z7=5&;h6w@F4~Pj*xIhj(>8Iua(|ZvxVNdLmN?~ANdgkfk7*cU7=}PR+8I1xvWb{ri
z+52MIyUCeH!=G?1|L;2aaKL$&p2n=&-?1}q?9}r(c2$+>=b4r-0wy9H77;&MPCN3X
z<?X9cIO;iZp+dNp>6*gCXQCwx+Rq+b3w(QXvd@XFJ{3GEQ@nDfJqWorpW}(qp(8h!
zPLY1noxZy9N#V;>F@D`cS|9&k=Z_OSf27n$Cg#_PM?F41GHVtY<;h&q%Fdg<vsU%g
zQU&oEtF6vHIu`Zp!s`99VZJ#stNw`HV{dR=-1LTfO<U8UfUV{0IoD789GUPV@*%gm
zTUeQ?Ug>1vSCjj8ES`P1C1-)xZL#Ds&!uyFbk-QTEa6HBFyP+Ud2$`Qnk9eA<_A2E
z?E!Xtmc6MxXLOo)mN2-f@tJY9x*EN_yJ^FMgr;4STy-?;*<YxNvKcX4P&{Pw>zk>A
zn)W8|oe?ZYCP`{A=rApMxTnp}DZyFs<wno$&bh&jLe7oro{E0+VOlDdHo<%5O%;)?
zk}DV*Zc3!^X`cuXO9&EQ(6*50|G$roXP6~V{rLTL^7bnRpU*!pe}C{LW6Hnh-tF%j
zi`163{i`XGPB~{kVPU=9+*|+NeE&UtyXL2#-}Uq3*UqgFJn@IOOjDr#XHD7nC@-GB
zMQ?vRtGC}@%V0T)Gh%MTp1(g|zByHDKmY!Im#~PsioZWzewoDT@XUS2cgF|p0`|36
zrr-PW{O{`JOC)}Lf4%&>f7+BQ%*vc1^X@;e<a!YmkoxW2@x`yj-<h$9|E(x_tYpac
zuj=QEcg=k}CY^u&U6#4%euGSJkjMV0%luro^XvE5{P>gi{ZVmGkI(x^mZPl^6+c)d
zB_st?pZ)*;zkYw^uNQ|OZhb9Rrsl)2={&RRe1}@@ld&g4O}2C~h;l8k(P2HbM(NU|
zJ#2hjXKa}6?7wgG`^VpVOP|}%zgx>Ug*h=Gpz+cV|0gOZJJ#N756h8pIKzB&fz%Yq
zSGE(n9j=}bSNO-r71mSK5Mas3Tb`!zmp|)-ea%c(g#!!+KmK{XUNcS}R1bK%`njxg
HN@xNA6J~-V
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..8b2ec905aae4474fb2507831b0774ba1d6900bca
GIT binary patch
literal 1930
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
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..dae08f27565737d34420b9962cc1031e1e5e6936
GIT binary patch
literal 2468
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
G6Z1DA8zXN3
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..f3151a37a7910a5a2c630ac447c1ce7df03f5d50
GIT binary patch
literal 2524
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
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..9250b816288d13725a21da76d8c99f72d6f0c47a
GIT binary patch
literal 1567
zc%17D@N?(olHy`uVBq!ia0vp^Vn8g#!3HEZm#uLCQj#UE5hcO-X(i=}MX3yqDfvmM
z3ZA)%>8U}fi7AzZCsS=07?@QuLn2Bde0{8v^K<nQL2C3Watjzhz{b9!ATc>RwL~E)
zH9a%WR_Xoj{Yna%DYi=CroINg1<t7%nI2U|slio#A<0$Q$(AWf_I3(36;?n4a#KqZ
z6)JLb@`|l0Y?Z*~S^?Q0VSOb9u#%E&TP292B76fBob!uP6-@Pvb(0MY4HeAH^bAc*
z&CCpS6pRcEjr0wG$V}JJ#LCpn%E(*+3Y37h6{VzE1-ZCE?E>;_l`=|73as??%gf94
z%8m8%i_-NCEiElUW*8ai0#)c1SLT%@R_NvxE5l51Ni9w;$}A|!%+FH*@e`BsOG|8(
zlwe-SEr1)FR}2j%V1VgYBo^o!>KW)GDfIQluQWFouDZA+C^Zeg>f(^ff>iyW)Z+Zo
zqGVvir743n7g#wLr6!i-7lq{K=fFZSAS1sdzc?emK*2fKOhLmpF*!32B%le_;p=PV
znO9trn3tUD>0+w{6w%AfOtEsaFf}x@urPJ8FfcbXbTzhgHZgQHH3agEOihg(U154%
z@{>z*Q}aq-dQ%X3&2Z`kB?gG@)S}F?)D*X({9FaFr>!z^yTur{TOfK<aJ$6>r(S)a
zWAxFY8YToxKOiPN;Q~4Eq@S7xOz%a&gq^bQxc~zL(?m}f$B>F!NmpWj&S(@Wu#6Eq
zmU3lIap0r>>*veorOf=BpyZ_d`2F_tOaIr@rT_W<x%#Yp|GMJlBMwFDuYEDj^s!#L
z%JR3<rf-X)XGd1B$Qu?Glrt`kh$xU;c5S!+w9tr6G3hsJ<=xW6EN93VuUBY(*X4d+
z;@|(@x?(X0P98XMqHWFh(@&kJH;PDei#bPbc^0FU^h_{=CF{|FSG;a+dJ2t-f8Iae
z-tWImbS|S|<OQD8tFy{WrHswvxhx<4{e5<`_W!!NdiIomNls-ek8PPO`b3J0sorki
zKISF+7(d3VMa=M0H9NVPqbodMl2gOFTFxTf4&Guz?fDzC?UaR$#a%P|Cvv8|h)-#@
zY@GP?tb=00vqw)GH_mi8cp&?M#-Sr87kg|xXv1V=aJ-4bO)u2hlP%|E`;`d^sp3pC
z`OSa4K6^P{Vg<v$|3CkV-#q$%e~i_ipa0*-i%9=_{`Yjd!siEU&67^7pU!_iFzdr~
z?{>cCPn<Ur5?-<y{rJ7y*xEek$*ul;xqVUgl23NbKXLNy>+Yv>tLyFdm(RQNpmuxt
zPaTE7eD9K0u$-7C-v7%e>VMteA8jGQ_VE@QUOqjw?ybW!_W-sQX&xRvf#=K{*6jUJ
z;Z<jPA^Lo0@$>)x=bw9b@5ch$ZTu&guS(p1D9Pd}sbOvRyC(1b!P}{MKjr;%?*4dx
zy+41)85Xy1bJIU(N6VL~er4LZ-GQ%pr`Vij6IZKcoMq5zKH3n`H*<Ep-wD-QGrZ46
z$j(^J((v-j_xI-h@ii8^KI#~-#<cJH#A(9uZ$XOK7c2fO3ytp$pY}3{d}cDVzT$d+
z0oz{oNB$0fm~Sq%;C0)~lESEcB_J(h)_-2!ZTA-}=?a<I$0VaFYoK}QNJ0YxGsFK>
VUd7;d6Ieh+wx_F~%Q~loCIGsqS%Lrn
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..9837cbd0feb5350f07f24bc902ef24c879058555
GIT binary patch
literal 2004
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
a0K?kn&*!Yl%3c7fXFXm0T-G@yGywq9?kt%A
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..a76c610008827d78cd01f125f2e8438309f366d7
GIT binary patch
literal 2322
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
Uaf0mC>W_aZ94|js88bZXKa%&mG5`Po
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..5ca79fc8738617127e44d306b42dfb692d19a8b2
GIT binary patch
literal 2411
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
K)ap$;)Bgh#FXoW|
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..965c749d2c36377e448a7729862ea1037228038c
GIT binary patch
literal 1565
zc%17D@N?(olHy`uVBq!ia0vp^Vn8g#!3HEZm#uLCQj#UE5hcO-X(i=}MX3yqDfvmM
z3ZA)%>8U}fi7AzZCsS=07?@QuLn2Bde0{8v^K<nQL2C3Watjzhz{b9!ATc>RwL~E)
zH9a%WR_Xoj{Yna%DYi=CroINg1<t7%nI2U|slio#A<0$Q$(AWf_I3(36;?n4a#KqZ
z6)JLb@`|l0Y?Z*~S^?Q0VSOb9u#%E&TP292B76fBob!uP6-@Pvb(0MY4HeAH^bAc*
z&CCpS6pRcEjr0wG$V}JJ#LCpn%E(*+3Y37h6{VzE1-ZCE?E>;_l`=|73as??%gf94
z%8m8%i_-NCEiElUW*8ai0#)c1SLT%@R_NvxE5l51Ni9w;$}A|!%+FH*@e`BsOG|8(
zlwe-SEr1)FR}2j%V1VgYBo^o!>KW)GDfIQluQWFouDZA+C^Zeg>f(^ff>iyW)Z+Zo
zqGVvir743n7g#wLr6!i-7lq{K=fFZSAS1sdzc?emK*2fKOhLmpF*!32B%le_;p=PV
znO9trn3tUD>0+w{6w%AfOtG>waxyS5a5HzYFt9K*bTzhgHZgQHHMB4=H!?Lfa&(31
zb;(aI%}vcKf$2>_=(WJ97nB$vx>JiX%TiO^it=+6z@E0s#NrlHa~DekOD7ZDZh`1c
z!R;0^oO<<vj?qVpYM2l({eYP8gbU=rlYVL*FufN66L$agy*C*cnEE|k978H@C8Z=J
zBwU$M*3~?*H}*kQ*FWyNQ~UoLPhik%Kb<6+&Xgpk#`jK7Ozxojt?s<sf1h9GetN(C
zd}#dIm+4JeDStk`u=;-g{Cm^?HFfDsQzo-@3T_fu(h$9_z>Q~r>vtZJng9RSGj_gr
zP}Sk->A9m3RR7=R*Z<eYr`>-aS8`XYsD?%8P?~|dvT=9YwLhzW&$zLZ#e<V=!BhKx
zbw2~@bzRr<pZMJ@Ct}~ISMmS%+0CnYmN2=w@ukHb^jljQzO3-Xij4~;czV{<JN&vm
zzkhwc@dVBpJAVd?W=#uic*K44sKSTW_t(qoOKLFa{84%ubaE}%g$J$Df5cDx_w78`
z<8vlv4_jZWgPQiHgFFt2a%^0T-0K&xPk7{HHluT<yF*)0^Gu6Mk;;<X)&p`4mNO<!
zjqPYGI&flbqE>5;!R7z<`~L?WOlZ@;?pNbx_T&Hj@A~pVSug(I-@mVBZ`B*_4o>4A
z-=}-G^95&pSU;Wre4|E6bN#+3`=58__vdRAeO+#BZO*jvy@np!qw@FP^yas&bx>sc
zQ&ac;PxsTg)s1J?e|W-n_L_YBx;MA}{d{!r>=LP8-(Md$@Bd{K)p$l+!8*W*;|h1b
z{Fb9%>TEWq@@{zY%e`mefd|$9DuVJ%H=NnW@uZF+X@i~Hg6xUe%mIo@JV#a?$}7xM
zvdf&9^XQY-4IY+hy7%qo-`@TE=AT<j>+SaJV<{5RsWIenGnymcv9vLw&;7h#@PS+R
zXN0;$HBD@tDjM;x?nl|{H)qSMr_Ez!V_Y$T{b9JnA7;xs1D-Z1J}xCbg=fr3jw@Va
zHhhxquy@|ednjI^RU&IivZ=&LCbx{tqijnh7q&I<{O7&$TRc3~ic28z4={bqlHd_Y
ZVA!6|`A(sA(|k~Y?dj_0vd$@?2>=2lR|)_C
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..9018291b5c543ac9adc1655227d0e5ee7d4e6f67
GIT binary patch
literal 2031
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
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..83f4b931d7ecf1e8a7b8456f1b1031531b668354
GIT binary patch
literal 2345
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
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..ecb4c54e9c69d1abadbfddeb2195cf9837ef803b
GIT binary patch
literal 2443
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
--- a/gfx/layers/client/CanvasClient.cpp
+++ b/gfx/layers/client/CanvasClient.cpp
@@ -171,17 +171,17 @@ CanvasClientSurfaceStream::Update(gfx::I
     }
 
     if (grallocTextureClient->GetIPDLActor()) {
       GetForwarder()->UseTexture(this, grallocTextureClient);
     }
 
     if (mBuffer && CompositorChild::ChildProcessHasCompositor()) {
       // remove old buffer from CompositableHost
-      RefPtr<AsyncTransactionTracker> tracker = new RemoveTextureFromCompositableTracker(this);
+      RefPtr<AsyncTransactionTracker> tracker = new RemoveTextureFromCompositableTracker();
       // Hold TextureClient until transaction complete.
       tracker->SetTextureClient(mBuffer);
       mBuffer->SetRemoveFromCompositableTracker(tracker);
       // RemoveTextureFromCompositableAsync() expects CompositorChild's presence.
       GetForwarder()->RemoveTextureFromCompositableAsync(tracker, this, mBuffer);
     }
     mBuffer = grallocTextureClient;
 #else
--- a/gfx/layers/client/CompositableClient.h
+++ b/gfx/layers/client/CompositableClient.h
@@ -29,55 +29,51 @@ class CompositableChild;
 class SurfaceDescriptor;
 class PCompositableChild;
 
 /**
  * Handle RemoveTextureFromCompositableAsync() transaction.
  */
 class RemoveTextureFromCompositableTracker : public AsyncTransactionTracker {
 public:
-  RemoveTextureFromCompositableTracker(CompositableClient* aCompositableClient)
-    : mCompositableClient(aCompositableClient)
+  RemoveTextureFromCompositableTracker()
   {
     MOZ_COUNT_CTOR(RemoveTextureFromCompositableTracker);
   }
 
   ~RemoveTextureFromCompositableTracker()
   {
     MOZ_COUNT_DTOR(RemoveTextureFromCompositableTracker);
   }
 
   virtual void Complete() MOZ_OVERRIDE
   {
     // The TextureClient's recycling is postponed until the transaction
     // complete.
     mTextureClient = nullptr;
-    mCompositableClient = nullptr;
   }
 
   virtual void Cancel() MOZ_OVERRIDE
   {
     mTextureClient = nullptr;
-    mCompositableClient = nullptr;
   }
 
   virtual void SetTextureClient(TextureClient* aTextureClient) MOZ_OVERRIDE
   {
     mTextureClient = aTextureClient;
   }
 
   virtual void SetReleaseFenceHandle(FenceHandle& aReleaseFenceHandle) MOZ_OVERRIDE
   {
     if (mTextureClient) {
       mTextureClient->SetReleaseFenceHandle(aReleaseFenceHandle);
     }
   }
 
 private:
-  RefPtr<CompositableClient> mCompositableClient;
   RefPtr<TextureClient> mTextureClient;
 };
 
 /**
  * CompositableClient manages the texture-specific logic for composite layers,
  * independently of the layer. It is the content side of a CompositableClient/
  * CompositableHost pair.
  *
--- a/gfx/layers/client/ContentClient.cpp
+++ b/gfx/layers/client/ContentClient.cpp
@@ -363,27 +363,27 @@ ContentClientDoubleBuffered::Updated(con
                                      const nsIntRegion& aVisibleRegion,
                                      bool aDidSelfCopy)
 {
   ContentClientRemoteBuffer::Updated(aRegionToDraw, aVisibleRegion, aDidSelfCopy);
 
 #if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
   if (mFrontClient && CompositorChild::ChildProcessHasCompositor()) {
     // remove old buffer from CompositableHost
-    RefPtr<AsyncTransactionTracker> tracker = new RemoveTextureFromCompositableTracker(this);
+    RefPtr<AsyncTransactionTracker> tracker = new RemoveTextureFromCompositableTracker();
     // Hold TextureClient until transaction complete.
     tracker->SetTextureClient(mFrontClient);
     mFrontClient->SetRemoveFromCompositableTracker(tracker);
     // RemoveTextureFromCompositableAsync() expects CompositorChild's presence.
     GetForwarder()->RemoveTextureFromCompositableAsync(tracker, this, mFrontClient);
   }
 
   if (mFrontClientOnWhite && CompositorChild::ChildProcessHasCompositor()) {
     // remove old buffer from CompositableHost
-    RefPtr<AsyncTransactionTracker> tracker = new RemoveTextureFromCompositableTracker(this);
+    RefPtr<AsyncTransactionTracker> tracker = new RemoveTextureFromCompositableTracker();
     // Hold TextureClient until transaction complete.
     tracker->SetTextureClient(mFrontClientOnWhite);
     mFrontClientOnWhite->SetRemoveFromCompositableTracker(tracker);
     // RemoveTextureFromCompositableAsync() expects CompositorChild's presence.
     GetForwarder()->RemoveTextureFromCompositableAsync(tracker, this, mFrontClientOnWhite);
   }
 #endif
 }
--- a/gfx/layers/client/ImageClient.cpp
+++ b/gfx/layers/client/ImageClient.cpp
@@ -76,27 +76,25 @@ ImageClient::RemoveTexture(TextureClient
   RemoveTextureWithTracker(aTexture, nullptr);
 }
 
 void
 ImageClient::RemoveTextureWithTracker(TextureClient* aTexture,
                                       AsyncTransactionTracker* aAsyncTransactionTracker)
 {
 #ifdef MOZ_WIDGET_GONK
-  // AsyncTransactionTracker is supported only on ImageBridge.
-  // Use AsyncTransactionTracker only when TextureClient is recyeled.
   if (aAsyncTransactionTracker ||
-      (GetForwarder()->IsImageBridgeChild() && aTexture->HasRecycleCallback())) {
+      GetForwarder()->IsImageBridgeChild()) {
     RefPtr<AsyncTransactionTracker> request = aAsyncTransactionTracker;
     if (!request) {
       // Create AsyncTransactionTracker if it is not provided as argument.
-      request = new RemoveTextureFromCompositableTracker(this);
+      request = new RemoveTextureFromCompositableTracker();
     }
     // Hold TextureClient until the transaction complete to postpone
-    // the TextureClient recycle.
+    // the TextureClient recycle/delete.
     request->SetTextureClient(aTexture);
     GetForwarder()->RemoveTextureFromCompositableAsync(request, this, aTexture);
     return;
   }
 #endif
 
   GetForwarder()->RemoveTextureFromCompositable(this, aTexture);
   if (aAsyncTransactionTracker) {
@@ -123,17 +121,17 @@ ImageClientBuffered::ImageClientBuffered
 TextureInfo ImageClientSingle::GetTextureInfo() const
 {
   return TextureInfo(CompositableType::IMAGE);
 }
 
 TemporaryRef<AsyncTransactionTracker>
 ImageClientSingle::PrepareFlushAllImages()
 {
-  RefPtr<AsyncTransactionTracker> status = new RemoveTextureFromCompositableTracker(this);
+  RefPtr<AsyncTransactionTracker> status = new RemoveTextureFromCompositableTracker();
   return status;
 }
 
 void
 ImageClientSingle::FlushAllImages(bool aExceptFront,
                                   AsyncTransactionTracker* aAsyncTransactionTracker)
 {
   if (!aExceptFront && mFrontBuffer) {
--- a/gfx/layers/opengl/CompositorOGL.cpp
+++ b/gfx/layers/opengl/CompositorOGL.cpp
@@ -109,16 +109,25 @@ CompositorOGL::CreateContext()
 
 #ifdef XP_WIN
   if (PR_GetEnv("MOZ_LAYERS_PREFER_EGL")) {
     printf_stderr("Trying GL layers...\n");
     context = gl::GLContextProviderEGL::CreateForWindow(mWidget);
   }
 #endif
 
+  // Allow to create offscreen GL context for main Layer Manager
+  if (!context && PR_GetEnv("MOZ_LAYERS_PREFER_OFFSCREEN")) {
+    SurfaceCaps caps = SurfaceCaps::ForRGB();
+    caps.preserve = false;
+    caps.bpp16 = gfxPlatform::GetPlatform()->GetOffscreenFormat() == gfxImageFormat::RGB16_565;
+    context = GLContextProvider::CreateOffscreen(gfxIntSize(mSurfaceSize.width,
+                                                            mSurfaceSize.height), caps);
+  }
+
   if (!context)
     context = gl::GLContextProvider::CreateForWindow(mWidget);
 
   if (!context) {
     NS_WARNING("Failed to create CompositorOGL context");
   }
 
   return context.forget();
@@ -566,19 +575,25 @@ CompositorOGL::PrepareViewport(const gfx
   // XXX: We keep track of whether the window size changed, so we could skip
   // this update if it hadn't changed since the last call. We will need to
   // track changes to aTransformPolicy and aWorldTransform for this to work
   // though.
 
   // Matrix to transform (0, 0, aWidth, aHeight) to viewport space (-1.0, 1.0,
   // 2, 2) and flip the contents.
   Matrix viewMatrix;
-  viewMatrix.Translate(-1.0, 1.0);
-  viewMatrix.Scale(2.0f / float(aSize.width), 2.0f / float(aSize.height));
-  viewMatrix.Scale(1.0f, -1.0f);
+  if (mGLContext->IsOffscreen()) {
+    // In case of rendering via GL Offscreen context, disable Y-Flipping
+    viewMatrix.Translate(-1.0, -1.0);
+    viewMatrix.Scale(2.0f / float(aSize.width), 2.0f / float(aSize.height));
+  } else {
+    viewMatrix.Translate(-1.0, 1.0);
+    viewMatrix.Scale(2.0f / float(aSize.width), 2.0f / float(aSize.height));
+    viewMatrix.Scale(1.0f, -1.0f);
+  }
 
   viewMatrix = aWorldTransform * viewMatrix;
 
   Matrix4x4 matrix3d = Matrix4x4::From2D(viewMatrix);
   matrix3d._33 = 0.0f;
 
   mProjMatrix = matrix3d;
 }
--- a/gfx/thebes/gfxASurface.cpp
+++ b/gfx/thebes/gfxASurface.cpp
@@ -520,62 +520,16 @@ gfxASurface::BytePerPixelFromFormat(gfxI
         case gfxImageFormat::A8:
             return 1;
         default:
             NS_WARNING("Unknown byte per pixel value for Image format");
     }
     return 0;
 }
 
-void
-gfxASurface::FastMovePixels(const nsIntRect& aSourceRect,
-                            const nsIntPoint& aDestTopLeft)
-{
-    // Used when the backend can internally handle self copies.
-    nsIntRect dest(aDestTopLeft, aSourceRect.Size());
-    
-    nsRefPtr<gfxContext> ctx = new gfxContext(this);
-    ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
-    nsIntPoint srcOrigin = dest.TopLeft() - aSourceRect.TopLeft();
-    ctx->SetSource(this, gfxPoint(srcOrigin.x, srcOrigin.y));
-    ctx->Rectangle(gfxRect(dest.x, dest.y, dest.width, dest.height));
-    ctx->Fill();
-}
-
-void
-gfxASurface::MovePixels(const nsIntRect& aSourceRect,
-                        const nsIntPoint& aDestTopLeft)
-{
-    // Assume the backend can't handle self copying well and allocate
-    // a temporary surface instead.
-    nsRefPtr<gfxASurface> tmp = 
-      CreateSimilarSurface(GetContentType(), 
-                           nsIntSize(aSourceRect.width, aSourceRect.height));
-    // CreateSimilarSurface can return nullptr if the current surface is
-    // in an error state. This isn't good, but its better to carry
-    // on with the error surface instead of crashing.
-    NS_WARN_IF_FALSE(tmp, "Must have temporary surface to move pixels!");
-    if (!tmp) {
-        return;
-    }
-    nsRefPtr<gfxContext> ctx = new gfxContext(tmp);
-    ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
-    ctx->SetSource(this, gfxPoint(-aSourceRect.x, -aSourceRect.y));
-    ctx->Paint();
-
-    ctx = new gfxContext(this);
-    ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
-    ctx->SetSource(tmp, gfxPoint(aDestTopLeft.x, aDestTopLeft.y));
-    ctx->Rectangle(gfxRect(aDestTopLeft.x, 
-                           aDestTopLeft.y, 
-                           aSourceRect.width, 
-                           aSourceRect.height));
-    ctx->Fill();
-}
-
 /** Memory reporting **/
 
 static const char *sDefaultSurfaceDescription =
     "Memory used by gfx surface of the given type.";
 
 struct SurfaceMemoryReporterAttrs {
   const char *path;
   const char *description;
--- a/gfx/thebes/gfxASurface.h
+++ b/gfx/thebes/gfxASurface.h
@@ -205,50 +205,29 @@ public:
 
     const gfxRect& GetOpaqueRect() {
         if (!!mOpaqueRect)
             return *mOpaqueRect;
         return GetEmptyOpaqueRect();
     }
 
     /**
-     * Move the pixels in |aSourceRect| to |aDestTopLeft|.  Like with
-     * memmove(), |aSourceRect| and the rectangle defined by
-     * |aDestTopLeft| are allowed to overlap, and the effect is
-     * equivalent to copying |aSourceRect| to a scratch surface and
-     * then back to |aDestTopLeft|.
-     *
-     * |aSourceRect| and the destination rectangle defined by
-     * |aDestTopLeft| are clipped to this surface's bounds.
-     */
-    virtual void MovePixels(const nsIntRect& aSourceRect,
-                            const nsIntPoint& aDestTopLeft);
-
-    /**
      * Mark the surface as being allowed/not allowed to be used as a source.
      */
     void SetAllowUseAsSource(bool aAllow) { mAllowUseAsSource = aAllow; }
     bool GetAllowUseAsSource() { return mAllowUseAsSource; }
 
     static uint8_t BytesPerPixel(gfxImageFormat aImageFormat);
 
 protected:
     gfxASurface();
 
     static gfxASurface* GetSurfaceWrapper(cairo_surface_t *csurf);
     static void SetSurfaceWrapper(cairo_surface_t *csurf, gfxASurface *asurf);
 
-    /**
-     * An implementation of MovePixels that assumes the backend can
-     * internally handle this operation and doesn't allocate any
-     * temporary surfaces.
-     */
-    void FastMovePixels(const nsIntRect& aSourceRect,
-                        const nsIntPoint& aDestTopLeft);
-
     // NB: Init() *must* be called from within subclass's
     // constructors.  It's unsafe to call it after the ctor finishes;
     // leaks and use-after-frees are possible.
     void Init(cairo_surface_t *surface, bool existingSurface = false);
 
     // out-of-line helper to allow GetOpaqueRect() to be inlined
     // without including gfxRect.h here
     static const gfxRect& GetEmptyOpaqueRect();
--- a/gfx/thebes/gfxD2DSurface.h
+++ b/gfx/thebes/gfxD2DSurface.h
@@ -24,22 +24,16 @@ public:
                   gfxImageFormat imageFormat = gfxImageFormat::RGB24);
 
     gfxD2DSurface(HANDLE handle, gfxContentType aContent);
 
     gfxD2DSurface(ID3D10Texture2D *texture, gfxContentType aContent);
 
     gfxD2DSurface(cairo_surface_t *csurf);
 
-    void MovePixels(const nsIntRect& aSourceRect,
-                    const nsIntPoint& aDestTopLeft)
-    {
-        FastMovePixels(aSourceRect, aDestTopLeft);
-    }
-
     virtual ~gfxD2DSurface();
 
     void Present();
     void Scroll(const nsIntPoint &aDelta, const nsIntRect &aClip);
 
     virtual const gfxIntSize GetSize() const;
 
     ID3D10Texture2D *GetTexture();
--- a/gfx/thebes/gfxFT2FontList.cpp
+++ b/gfx/thebes/gfxFT2FontList.cpp
@@ -1,41 +1,27 @@
 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * 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 "mozilla/ArrayUtils.h"
 #include "mozilla/MemoryReporting.h"
 
-#if (MOZ_WIDGET_GTK == 2)
-#include "gfxPlatformGtk.h"
-#define gfxToolkitPlatform gfxPlatformGtk
-#elif defined(MOZ_WIDGET_QT)
-#include <qfontinfo.h>
-#include "gfxQtPlatform.h"
-#define gfxToolkitPlatform gfxQtPlatform
-#elif defined(XP_WIN)
-#include "gfxWindowsPlatform.h"
-#define gfxToolkitPlatform gfxWindowsPlatform
-#elif defined(ANDROID)
 #include "mozilla/dom/ContentChild.h"
 #include "gfxAndroidPlatform.h"
 #include "mozilla/Omnijar.h"
 #include "nsIInputStream.h"
 #include "nsNetUtil.h"
 #define gfxToolkitPlatform gfxAndroidPlatform
-#endif
 
-#ifdef ANDROID
 #include "nsXULAppAPI.h"
 #include <dirent.h>
 #include <android/log.h>
 #define ALOG(args...)  __android_log_print(ANDROID_LOG_INFO, "Gecko" , ## args)
-#endif
 
 #include "ft2build.h"
 #include FT_FREETYPE_H
 #include FT_TRUETYPE_TAGS_H
 #include FT_TRUETYPE_TABLES_H
 #include "cairo-ft.h"
 
 #include "gfxFT2FontList.h"
@@ -53,21 +39,16 @@
 #include "nsISimpleEnumerator.h"
 #include "nsIMemory.h"
 #include "gfxFontConstants.h"
 
 #include "mozilla/Preferences.h"
 #include "mozilla/scache/StartupCache.h"
 #include <sys/stat.h>
 
-#ifdef XP_WIN
-#include "nsIWindowsRegKey.h"
-#include <windows.h>
-#endif
-
 using namespace mozilla;
 
 #ifdef PR_LOGGING
 static PRLogModuleInfo *
 GetFontInfoLog()
 {
     static PRLogModuleInfo *sLog;
     if (!sLog)
@@ -80,20 +61,16 @@ GetFontInfoLog()
 #define LOG(args) PR_LOG(GetFontInfoLog(), PR_LOG_DEBUG, args)
 #define LOG_ENABLED() PR_LOG_TEST(GetFontInfoLog(), PR_LOG_DEBUG)
 
 static cairo_user_data_key_t sFTUserFontDataKey;
 
 static __inline void
 BuildKeyNameFromFontName(nsAString &aName)
 {
-#ifdef XP_WIN
-    if (aName.Length() >= LF_FACESIZE)
-        aName.Truncate(LF_FACESIZE - 1);
-#endif
     ToLowerCase(aName);
 }
 
 // Helper to access the FT_Face for a given FT2FontEntry,
 // creating a temporary face if the entry does not have one yet.
 // This allows us to read font names, tables, etc if necessary
 // without permanently instantiating a freetype face and consuming
 // memory long-term.
@@ -958,21 +935,17 @@ gfxFT2FontList::AppendFacesFromFontFile(
     if (!faceList.IsEmpty() && 0 == statRetval &&
         s.st_mtime == timestamp && s.st_size == filesize)
     {
         LOG(("using cached font info for %s", aFileName.get()));
         AppendFacesFromCachedFaceList(aFileName, aStdFile, faceList);
         return;
     }
 
-#ifdef XP_WIN
-    FT_Library ftLibrary = gfxWindowsPlatform::GetPlatform()->GetFTLibrary();
-#elif defined(ANDROID)
     FT_Library ftLibrary = gfxAndroidPlatform::GetPlatform()->GetFTLibrary();
-#endif
     FT_Face dummy;
     if (FT_Err_Ok == FT_New_Face(ftLibrary, aFileName.get(), -1, &dummy)) {
         LOG(("reading font info via FreeType for %s", aFileName.get()));
         nsCString faceList;
         timestamp = s.st_mtime;
         filesize = s.st_size;
         for (FT_Long i = 0; i < dummy->num_faces; i++) {
             FT_Face face;
@@ -1165,60 +1138,16 @@ FinalizeFamilyMemberList(nsStringHashKey
     family->CheckForSimpleFamily();
 
     return PL_DHASH_NEXT;
 }
 
 void
 gfxFT2FontList::FindFonts()
 {
-#ifdef XP_WIN
-    nsTArray<nsString> searchPaths(3);
-    nsTArray<nsString> fontPatterns(3);
-    fontPatterns.AppendElement(NS_LITERAL_STRING("\\*.ttf"));
-    fontPatterns.AppendElement(NS_LITERAL_STRING("\\*.ttc"));
-    fontPatterns.AppendElement(NS_LITERAL_STRING("\\*.otf"));
-    wchar_t pathBuf[256];
-    SHGetSpecialFolderPathW(0, pathBuf, CSIDL_WINDOWS, 0);
-    searchPaths.AppendElement(pathBuf);
-    SHGetSpecialFolderPathW(0, pathBuf, CSIDL_FONTS, 0);
-    searchPaths.AppendElement(pathBuf);
-    nsCOMPtr<nsIFile> resDir;
-    NS_GetSpecialDirectory(NS_APP_RES_DIR, getter_AddRefs(resDir));
-    if (resDir) {
-        resDir->Append(NS_LITERAL_STRING("fonts"));
-        nsAutoString resPath;
-        resDir->GetPath(resPath);
-        searchPaths.AppendElement(resPath);
-    }
-    WIN32_FIND_DATAW results;
-    for (uint32_t i = 0;  i < searchPaths.Length(); i++) {
-        const nsString& path(searchPaths[i]);
-        for (uint32_t j = 0; j < fontPatterns.Length(); j++) { 
-            nsAutoString pattern(path);
-            pattern.Append(fontPatterns[j]);
-            HANDLE handle = FindFirstFileExW(pattern.get(),
-                                             FindExInfoStandard,
-                                             &results,
-                                             FindExSearchNameMatch,
-                                             nullptr,
-                                             0);
-            bool moreFiles = handle != INVALID_HANDLE_VALUE;
-            while (moreFiles) {
-                nsAutoString filePath(path);
-                filePath.Append('\\');
-                filePath.Append(results.cFileName);
-                AppendFacesFromFontFile(NS_ConvertUTF16toUTF8(filePath));
-                moreFiles = FindNextFile(handle, &results);
-            }
-            if (handle != INVALID_HANDLE_VALUE)
-                FindClose(handle);
-        }
-    }
-#elif defined(ANDROID)
     gfxFontCache *fc = gfxFontCache::GetCache();
     if (fc)
         fc->AgeAllGenerations();
     mPrefFonts.Clear();
     mCodepointsWithNoFonts.reset();
 
     mCodepointsWithNoFonts.SetRange(0,0x1f);     // C0 controls
     mCodepointsWithNoFonts.SetRange(0x7f,0x9f);  // C1 controls
@@ -1254,17 +1183,16 @@ gfxFT2FontList::FindFonts()
     root.AppendLiteral("/fonts");
 
     FindFontsInDir(root, &fnc);
 
     if (mFontFamilies.Count() == 0) {
         // if we can't find/read the font directory, we are doomed!
         NS_RUNTIMEABORT("Could not read the system fonts directory");
     }
-#endif // XP_WIN && ANDROID
 
     // Look for fonts stored in omnijar, unless we're on a low-memory
     // device where we don't want to spend the RAM to decompress them.
     // (Prefs may disable this, or force-enable it even with low memory.)
     bool lowmem;
     nsCOMPtr<nsIMemory> mem = nsMemory::GetGlobalMemoryService();
     if ((NS_SUCCEEDED(mem->IsLowMemoryPlatform(&lowmem)) && !lowmem &&
          Preferences::GetBool("gfx.bundled_fonts.enabled")) ||
@@ -1286,17 +1214,16 @@ gfxFT2FontList::FindFonts()
     }
 
     // Finalize the families by sorting faces into standard order
     // and marking "simple" families.
     // Passing non-null userData here says that we want faces to be sorted.
     mFontFamilies.Enumerate(FinalizeFamilyMemberList, this);
 }
 
-#ifdef ANDROID
 void
 gfxFT2FontList::FindFontsInDir(const nsCString& aDir, FontNameCache *aFNC)
 {
     static const char* sStandardFonts[] = {
         "DroidSans.ttf",
         "DroidSans-Bold.ttf",
         "DroidSerif-Regular.ttf",
         "DroidSerif-Bold.ttf",
@@ -1343,17 +1270,16 @@ gfxFT2FontList::FindFontsInDir(const nsC
             // and the file is unchanged, we won't actually need to read it.
             // If the file is new/changed, this will update the FontNameCache.
             AppendFacesFromFontFile(s, isStdFont, aFNC);
         }
     }
 
     closedir(d);
 }
-#endif
 
 void
 gfxFT2FontList::AppendFaceFromFontListEntry(const FontListEntry& aFLE,
                                             bool aStdFile)
 {
     FT2FontEntry* fe = FT2FontEntry::CreateFontEntry(aFLE);
     if (fe) {
         fe->mStandardFace = aStdFile;
@@ -1501,26 +1427,17 @@ gfxFT2FontList::LookupLocalFont(const gf
     }
 
     return fe;
 }
 
 gfxFontFamily*
 gfxFT2FontList::GetDefaultFont(const gfxFontStyle* aStyle)
 {
-#ifdef XP_WIN
-    HGDIOBJ hGDI = ::GetStockObject(SYSTEM_FONT);
-    LOGFONTW logFont;
-    if (hGDI && ::GetObjectW(hGDI, sizeof(logFont), &logFont)) {
-        nsAutoString resolvedName;
-        if (ResolveFontName(nsDependentString(logFont.lfFaceName), resolvedName)) {
-            return FindFamily(resolvedName);
-        }
-    }
-#elif defined(MOZ_WIDGET_GONK)
+#ifdef MOZ_WIDGET_GONK
     nsAutoString resolvedName;
     if (ResolveFontName(NS_LITERAL_STRING("Fira Sans OT"), resolvedName)) {
         return FindFamily(resolvedName);
     }
 #elif defined(MOZ_WIDGET_ANDROID)
     nsAutoString resolvedName;
     if (ResolveFontName(NS_LITERAL_STRING("Roboto"), resolvedName) ||
         ResolveFontName(NS_LITERAL_STRING("Droid Sans"), resolvedName)) {
--- a/gfx/thebes/gfxFT2FontList.h
+++ b/gfx/thebes/gfxFT2FontList.h
@@ -2,21 +2,16 @@
  * 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 GFX_FT2FONTLIST_H
 #define GFX_FT2FONTLIST_H
 
 #include "mozilla/MemoryReporting.h"
-
-#ifdef XP_WIN
-#include "gfxWindowsPlatform.h"
-#include <windows.h>
-#endif
 #include "gfxPlatformFontList.h"
 
 namespace mozilla {
     namespace dom {
         class FontListEntry;
     };
 };
 using mozilla::dom::FontListEntry;
@@ -148,16 +143,14 @@ protected:
 
     void AddFaceToList(const nsCString& aEntryName, uint32_t aIndex,
                        bool aStdFile, FT_Face aFace, nsCString& aFaceList);
 
     void FindFonts();
 
     void FindFontsInOmnijar(FontNameCache *aCache);
 
-#ifdef ANDROID
     void FindFontsInDir(const nsCString& aDir, FontNameCache* aFNC);
-#endif
 
     nsTHashtable<nsStringHashKey> mSkipSpaceLookupCheckFamilies;
 };
 
 #endif /* GFX_FT2FONTLIST_H */
--- a/gfx/thebes/gfxImageSurface.cpp
+++ b/gfx/thebes/gfxImageSurface.cpp
@@ -366,75 +366,8 @@ gfxSubimageSurface::gfxSubimageSurface(g
 }
 
 already_AddRefed<gfxImageSurface>
 gfxImageSurface::GetAsImageSurface()
 {
   nsRefPtr<gfxImageSurface> surface = this;
   return surface.forget();
 }
-
-void
-gfxImageSurface::MovePixels(const nsIntRect& aSourceRect,
-                            const nsIntPoint& aDestTopLeft)
-{
-    const nsIntRect bounds(0, 0, mSize.width, mSize.height);
-    nsIntPoint offset = aDestTopLeft - aSourceRect.TopLeft(); 
-    nsIntRect clippedSource = aSourceRect;
-    clippedSource.IntersectRect(clippedSource, bounds);
-    nsIntRect clippedDest = clippedSource + offset;
-    clippedDest.IntersectRect(clippedDest, bounds);
-    const nsIntRect dest = clippedDest;
-    const nsIntRect source = dest - offset;
-    // NB: this relies on IntersectRect() and operator+/- preserving
-    // x/y for empty rectangles
-    NS_ABORT_IF_FALSE(bounds.Contains(dest) && bounds.Contains(source) &&
-                      aSourceRect.Contains(source) &&
-                      nsIntRect(aDestTopLeft, aSourceRect.Size()).Contains(dest) &&
-                      source.Size() == dest.Size() &&
-                      offset == (dest.TopLeft() - source.TopLeft()),
-                      "Messed up clipping, crash or corruption will follow");
-    if (source.IsEmpty() || source.IsEqualInterior(dest)) {
-        return;
-    }
-
-    long naturalStride = ComputeStride(mSize, mFormat);
-    if (mStride == naturalStride && dest.width == bounds.width) {
-        // Fast path: this is a vertical shift of some rows in a
-        // "normal" image surface.  We can directly memmove and
-        // hopefully stay in SIMD land.
-        unsigned char* dst = mData + dest.y * mStride;
-        const unsigned char* src = mData + source.y * mStride;
-        size_t nBytes = dest.height * mStride;
-        memmove(dst, src, nBytes);
-        return;
-    }
-
-    // Slow(er) path: have to move row-by-row.
-    const int32_t bpp = BytePerPixelFromFormat(mFormat);
-    const size_t nRowBytes = dest.width * bpp;
-    // dstRow points at the first pixel within the current destination
-    // row, and similarly for srcRow.  endSrcRow is one row beyond the
-    // last row we need to copy.  stride is either +mStride or
-    // -mStride, depending on which direction we're copying.
-    unsigned char* dstRow;
-    unsigned char* srcRow;
-    unsigned char* endSrcRow;   // NB: this may point outside the image
-    long stride;
-    if (dest.y > source.y) {
-        // We're copying down from source to dest, so walk backwards
-        // starting from the last rows to avoid stomping pixels we
-        // need.
-        stride = -mStride;
-        dstRow = mData + dest.x * bpp + (dest.YMost() - 1) * mStride;
-        srcRow = mData + source.x * bpp + (source.YMost() - 1) * mStride;
-        endSrcRow = mData + source.x * bpp + (source.y - 1) * mStride;
-    } else {
-        stride = mStride;
-        dstRow = mData + dest.x * bpp + dest.y * mStride;
-        srcRow = mData + source.x * bpp + source.y * mStride;
-        endSrcRow = mData + source.x * bpp + source.YMost() * mStride;
-    }
-
-    for (; srcRow != endSrcRow; dstRow += stride, srcRow += stride) {
-        memmove(dstRow, srcRow, nRowBytes);
-    }
-}
--- a/gfx/thebes/gfxImageSurface.h
+++ b/gfx/thebes/gfxImageSurface.h
@@ -119,19 +119,16 @@ public:
     /* return new Subimage with pointing to original image starting from aRect.pos
      * and size of aRect.size. New subimage keeping current image reference
      */
     already_AddRefed<gfxSubimageSurface> GetSubimage(const gfxRect& aRect);
 
     virtual already_AddRefed<gfxImageSurface> GetAsImageSurface();
 
     /** See gfxASurface.h. */
-    virtual void MovePixels(const nsIntRect& aSourceRect,
-                            const nsIntPoint& aDestTopLeft) MOZ_OVERRIDE;
-
     static long ComputeStride(const gfxIntSize&, gfxImageFormat);
 
     virtual size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
         MOZ_OVERRIDE;
     virtual size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
         MOZ_OVERRIDE;
     virtual bool SizeOfIsMeasured() const MOZ_OVERRIDE;
 
--- a/gfx/thebes/gfxPlatform.cpp
+++ b/gfx/thebes/gfxPlatform.cpp
@@ -532,26 +532,16 @@ gfxPlatform::~gfxPlatform()
 
 bool
 gfxPlatform::PreferMemoryOverShmem() const {
   MOZ_ASSERT(!CompositorParent::IsInCompositorThread());
   return mLayersPreferMemoryOverShmem;
 }
 
 already_AddRefed<gfxASurface>
-gfxPlatform::CreateOffscreenImageSurface(const gfxIntSize& aSize,
-                                         gfxContentType aContentType)
-{
-  nsRefPtr<gfxASurface> newSurface;
-  newSurface = new gfxImageSurface(aSize, OptimalFormatForContent(aContentType));
-
-  return newSurface.forget();
-}
-
-already_AddRefed<gfxASurface>
 gfxPlatform::OptimizeImage(gfxImageSurface *aSurface,
                            gfxImageFormat format)
 {
     IntSize surfaceSize = aSurface->GetSize().ToIntSize();
 
 #ifdef XP_WIN
     if (gfxWindowsPlatform::GetPlatform()->GetRenderMode() ==
         gfxWindowsPlatform::RENDER_DIRECT2D) {
@@ -1246,21 +1236,23 @@ bool gfxPlatform::ForEachPrefFont(eFontP
     }
 
     return true;
 }
 
 eFontPrefLang
 gfxPlatform::GetFontPrefLangFor(const char* aLang)
 {
-    if (!aLang || !aLang[0])
+    if (!aLang || !aLang[0]) {
         return eFontPrefLang_Others;
-    for (uint32_t i = 0; i < uint32_t(eFontPrefLang_LangCount); ++i) {
-        if (!PL_strcasecmp(gPrefLangNames[i], aLang))
+    }
+    for (uint32_t i = 0; i < ArrayLength(gPrefLangNames); ++i) {
+        if (!PL_strcasecmp(gPrefLangNames[i], aLang)) {
             return eFontPrefLang(i);
+        }
     }
     return eFontPrefLang_Others;
 }
 
 eFontPrefLang
 gfxPlatform::GetFontPrefLangFor(nsIAtom *aLang)
 {
     if (!aLang)
@@ -1268,18 +1260,19 @@ gfxPlatform::GetFontPrefLangFor(nsIAtom 
     nsAutoCString lang;
     aLang->ToUTF8String(lang);
     return GetFontPrefLangFor(lang.get());
 }
 
 const char*
 gfxPlatform::GetPrefLangName(eFontPrefLang aLang)
 {
-    if (uint32_t(aLang) < uint32_t(eFontPrefLang_AllCount))
+    if (uint32_t(aLang) < ArrayLength(gPrefLangNames)) {
         return gPrefLangNames[uint32_t(aLang)];
+    }
     return nullptr;
 }
 
 eFontPrefLang
 gfxPlatform::GetFontPrefLangFor(uint8_t aUnicodeRange)
 {
     switch (aUnicodeRange) {
         case kRangeSetLatin:   return eFontPrefLang_Western;
--- a/gfx/thebes/gfxPlatform.h
+++ b/gfx/thebes/gfxPlatform.h
@@ -90,22 +90,19 @@ enum eFontPrefLang {
     eFontPrefLang_Khmer       = 23,
     eFontPrefLang_Malayalam   = 24,
     eFontPrefLang_Oriya       = 25,
     eFontPrefLang_Telugu      = 26,
     eFontPrefLang_Kannada     = 27,
     eFontPrefLang_Sinhala     = 28,
     eFontPrefLang_Tibetan     = 29,
 
-    eFontPrefLang_LangCount   = 30, // except Others.
-
     eFontPrefLang_Others      = 30, // x-unicode
 
-    eFontPrefLang_CJKSet      = 31, // special code for CJK set
-    eFontPrefLang_AllCount    = 32
+    eFontPrefLang_CJKSet      = 31  // special code for CJK set
 };
 
 enum eCMSMode {
     eCMSMode_Off          = 0,     // No color management
     eCMSMode_All          = 1,     // Color manage everything
     eCMSMode_TaggedOnly   = 2,     // Color manage tagged Images Only
     eCMSMode_AllCount     = 3
 };
@@ -175,28 +172,16 @@ public:
     /**
      * Create an offscreen surface of the given dimensions
      * and image format.
      */
     virtual already_AddRefed<gfxASurface>
       CreateOffscreenSurface(const IntSize& size,
                              gfxContentType contentType) = 0;
 
-    /**
-     * Create an offscreen surface of the given dimensions and image format which
-     * can be converted to a gfxImageSurface without copying. If we can provide
-     * a platform-hosted surface, then we will return that instead of an actual
-     * gfxImageSurface.
-     * Sub-classes should override this method if CreateOffscreenSurface returns a
-     * surface which implements GetAsImageSurface
-     */
-    virtual already_AddRefed<gfxASurface>
-      CreateOffscreenImageSurface(const gfxIntSize& aSize,
-                                  gfxContentType aContentType);
-
     virtual already_AddRefed<gfxASurface> OptimizeImage(gfxImageSurface *aSurface,
                                                         gfxImageFormat format);
 
     /**
      * Beware that these methods may return DrawTargets which are not fully supported
      * on the current platform and might fail silently in subtle ways. This is a massive
      * potential footgun. You should only use these methods for canvas drawing really.
      * Use extreme caution if you use them for content where you are not 100% sure we
--- a/gfx/thebes/gfxPlatformMac.cpp
+++ b/gfx/thebes/gfxPlatformMac.cpp
@@ -101,30 +101,16 @@ gfxPlatformMac::CreateOffscreenSurface(c
 {
     nsRefPtr<gfxASurface> newSurface =
       new gfxQuartzSurface(ThebesIntSize(size),
                            OptimalFormatForContent(contentType));
     return newSurface.forget();
 }
 
 already_AddRefed<gfxASurface>
-gfxPlatformMac::CreateOffscreenImageSurface(const gfxIntSize& aSize,
-                                            gfxContentType aContentType)
-{
-    nsRefPtr<gfxASurface> surface =
-        CreateOffscreenSurface(aSize.ToIntSize(), aContentType);
-#ifdef DEBUG
-    nsRefPtr<gfxImageSurface> imageSurface = surface->GetAsImageSurface();
-    NS_ASSERTION(imageSurface, "Surface cannot be converted to a gfxImageSurface");
-#endif
-    return surface.forget();
-}
-
-
-already_AddRefed<gfxASurface>
 gfxPlatformMac::OptimizeImage(gfxImageSurface *aSurface,
                               gfxImageFormat format)
 {
     const gfxIntSize& surfaceSize = aSurface->GetSize();
     nsRefPtr<gfxImageSurface> isurf = aSurface;
 
     if (format != aSurface->Format()) {
         isurf = new gfxImageSurface (surfaceSize, format);
--- a/gfx/thebes/gfxPlatformMac.h
+++ b/gfx/thebes/gfxPlatformMac.h
@@ -24,20 +24,16 @@ public:
     static gfxPlatformMac *GetPlatform() {
         return (gfxPlatformMac*) gfxPlatform::GetPlatform();
     }
 
     virtual already_AddRefed<gfxASurface>
       CreateOffscreenSurface(const IntSize& size,
                              gfxContentType contentType) MOZ_OVERRIDE;
 
-    virtual already_AddRefed<gfxASurface>
-      CreateOffscreenImageSurface(const gfxIntSize& aSize,
-                                  gfxContentType aContentType);
-
     already_AddRefed<gfxASurface> OptimizeImage(gfxImageSurface *aSurface,
                                                 gfxImageFormat format);
 
     mozilla::TemporaryRef<mozilla::gfx::ScaledFont>
       GetScaledFontForFont(mozilla::gfx::DrawTarget* aTarget, gfxFont *aFont);
 
     nsresult ResolveFontName(const nsAString& aFontName,
                              FontResolverCallback aCallback,
--- a/gfx/thebes/gfxQuartzSurface.h
+++ b/gfx/thebes/gfxQuartzSurface.h
@@ -34,22 +34,16 @@ public:
     CGContextRef GetCGContext() { return mCGContext; }
 
     CGContextRef GetCGContextWithClip(gfxContext *ctx);
 
     virtual int32_t GetDefaultContextFlags() const;
 
     already_AddRefed<gfxImageSurface> GetAsImageSurface();
 
-    void MovePixels(const nsIntRect& aSourceRect,
-                    const nsIntPoint& aDestTopLeft)
-    {
-        FastMovePixels(aSourceRect, aDestTopLeft);
-    }
-
 protected:
     void MakeInvalid();
 
     CGContextRef mCGContext;
     gfxSize      mSize;
     bool mForPrinting;
 };
 
--- a/gfx/thebes/gfxUserFontSet.cpp
+++ b/gfx/thebes/gfxUserFontSet.cpp
@@ -7,17 +7,16 @@
 #define FORCE_PR_LOG /* Allow logging in the release build */
 #endif /* MOZ_LOGGING */
 #include "prlog.h"
 
 #include "gfxUserFontSet.h"
 #include "gfxPlatform.h"
 #include "nsUnicharUtils.h"
 #include "nsNetUtil.h"
-#include "nsICacheService.h"
 #include "nsIProtocolHandler.h"
 #include "nsIPrincipal.h"
 #include "gfxFontConstants.h"
 #include "mozilla/Services.h"
 #include "mozilla/gfx/2D.h"
 #include "gfxPlatformFontList.h"
 
 #include "opentype-sanitiser.h"
@@ -858,17 +857,17 @@ NS_IMETHODIMP
 gfxUserFontSet::UserFontCache::Flusher::Observe(nsISupports* aSubject,
                                                 const char* aTopic,
                                                 const char16_t* aData)
 {
     if (!sUserFonts) {
         return NS_OK;
     }
 
-    if (!strcmp(aTopic, NS_CACHESERVICE_EMPTYCACHE_TOPIC_ID)) {
+    if (!strcmp(aTopic, "cacheservice:empty-cache")) {
         sUserFonts->Clear();
     } else if (!strcmp(aTopic, "last-pb-context-exited")) {
         sUserFonts->EnumerateEntries(Entry::RemoveIfPrivate, nullptr);
     } else if (!strcmp(aTopic, "xpcom-shutdown")) {
         sUserFonts->EnumerateEntries(Entry::DisconnectSVG, nullptr);
     } else {
         NS_NOTREACHED("unexpected topic");
     }
@@ -912,17 +911,17 @@ gfxUserFontSet::UserFontCache::CacheFont
                  "caching a font associated with no family yet");
     if (!sUserFonts) {
         sUserFonts = new nsTHashtable<Entry>;
 
         nsCOMPtr<nsIObserverService> obs =
             mozilla::services::GetObserverService();
         if (obs) {
             Flusher *flusher = new Flusher;
-            obs->AddObserver(flusher, NS_CACHESERVICE_EMPTYCACHE_TOPIC_ID,
+            obs->AddObserver(flusher, "cacheservice:empty-cache",
                              false);
             obs->AddObserver(flusher, "last-pb-context-exited", false);
             obs->AddObserver(flusher, "xpcom-shutdown", false);
         }
     }
 
     gfxUserFontData *data = aFontEntry->mUserFontData;
     sUserFonts->PutEntry(Key(data->mURI, data->mPrincipal, aFontEntry,
--- a/gfx/thebes/gfxWindowsPlatform.cpp
+++ b/gfx/thebes/gfxWindowsPlatform.cpp
@@ -612,37 +612,16 @@ gfxWindowsPlatform::CreateOffscreenSurfa
     if (!surf || surf->CairoStatus()) {
         surf = new gfxImageSurface(ThebesIntSize(size),
                                    OptimalFormatForContent(contentType));
     }
 
     return surf.forget();
 }
 
-already_AddRefed<gfxASurface>
-gfxWindowsPlatform::CreateOffscreenImageSurface(const gfxIntSize& aSize,
-                                                gfxContentType aContentType)
-{
-#ifdef CAIRO_HAS_D2D_SURFACE
-    if (mRenderMode == RENDER_DIRECT2D) {
-        nsRefPtr<gfxASurface> surface =
-          new gfxImageSurface(aSize, OptimalFormatForContent(aContentType));
-        return surface.forget();
-    }
-#endif
-
-    nsRefPtr<gfxASurface> surface = CreateOffscreenSurface(aSize.ToIntSize(),
-                                                           aContentType);
-#ifdef DEBUG
-    nsRefPtr<gfxImageSurface> imageSurface = surface->GetAsImageSurface();
-    NS_ASSERTION(imageSurface, "Surface cannot be converted to a gfxImageSurface");
-#endif
-    return surface.forget();
-}
-
 TemporaryRef<ScaledFont>
 gfxWindowsPlatform::GetScaledFontForFont(DrawTarget* aTarget, gfxFont *aFont)
 {
     if (aFont->GetType() == gfxFont::FONT_TYPE_DWRITE) {
         gfxDWriteFont *font = static_cast<gfxDWriteFont*>(aFont);
 
         NativeFont nativeFont;
         nativeFont.mType = NativeFontType::DWRITE_FONT_FACE;
--- a/gfx/thebes/gfxWindowsPlatform.h
+++ b/gfx/thebes/gfxWindowsPlatform.h
@@ -123,19 +123,16 @@ public:
         return (gfxWindowsPlatform*) gfxPlatform::GetPlatform();
     }
 
     virtual gfxPlatformFontList* CreatePlatformFontList();
 
     virtual already_AddRefed<gfxASurface>
       CreateOffscreenSurface(const IntSize& size,
                              gfxContentType contentType) MOZ_OVERRIDE;
-    virtual already_AddRefed<gfxASurface>
-      CreateOffscreenImageSurface(const gfxIntSize& aSize,
-                                  gfxContentType aContentType);
 
     virtual mozilla::TemporaryRef<mozilla::gfx::ScaledFont>
       GetScaledFontForFont(mozilla::gfx::DrawTarget* aTarget, gfxFont *aFont);
     virtual already_AddRefed<gfxASurface>
       GetThebesSurfaceForDrawTarget(mozilla::gfx::DrawTarget *aTarget);
 
     enum RenderMode {
         /* Use GDI and windows surfaces */
--- a/gfx/thebes/gfxWindowsSurface.h
+++ b/gfx/thebes/gfxWindowsSurface.h
@@ -62,22 +62,16 @@ public:
     nsresult AbortPrinting();
     nsresult BeginPage();
     nsresult EndPage();
 
     virtual int32_t GetDefaultContextFlags() const;
 
     const gfxIntSize GetSize() const;
 
-    void MovePixels(const nsIntRect& aSourceRect,
-                    const nsIntPoint& aDestTopLeft)
-    {
-        FastMovePixels(aSourceRect, aDestTopLeft);
-    }
-
     // The memory used by this surface lives in this process's address space,
     // but not in the heap.
     virtual gfxMemoryLocation GetMemoryLocation() const;
 
 private:
     void MakeInvalid(gfxIntSize& size);
 
     bool mOwnsDC;
--- a/js/src/NamespaceImports.h
+++ b/js/src/NamespaceImports.h
@@ -27,22 +27,22 @@ class TwoByteChars;
 class AutoFunctionVector;
 class AutoIdVector;
 class AutoObjectVector;
 class AutoScriptVector;
 class AutoValueVector;
 
 class AutoIdArray;
 
-class AutoGCRooter;
+class JS_PUBLIC_API(AutoGCRooter);
 template <typename T> class AutoVectorRooter;
 template<typename K, typename V> class AutoHashMapRooter;
 template<typename T> class AutoHashSetRooter;
 
-class SourceBufferHolder;
+class MOZ_STACK_CLASS SourceBufferHolder;
 
 class HandleValueArray;
 
 class JS_PUBLIC_API(AutoCheckCannotGC);
 
 }
 
 // Do the importing.
--- a/js/src/builtin/TypedObject.cpp
+++ b/js/src/builtin/TypedObject.cpp
@@ -1473,22 +1473,21 @@ TypedObject::createUnattachedWithClass(J
         }
         proto = &protoVal.toObject();
     }
 
     RootedObject obj(cx, NewObjectWithClassProto(cx, clasp, &*proto, nullptr));
     if (!obj)
         return nullptr;
 
-    obj->setPrivate(nullptr);
-    obj->initReservedSlot(JS_TYPEDOBJ_SLOT_BYTEOFFSET, Int32Value(0));
-    obj->initReservedSlot(JS_TYPEDOBJ_SLOT_BYTELENGTH, Int32Value(0));
-    obj->initReservedSlot(JS_TYPEDOBJ_SLOT_OWNER, NullValue());
-    obj->initReservedSlot(JS_TYPEDOBJ_SLOT_NEXT_VIEW, PrivateValue(nullptr));
-    obj->initReservedSlot(JS_TYPEDOBJ_SLOT_LENGTH, Int32Value(length));
+    obj->initPrivate(nullptr);
+    obj->initReservedSlot(JS_BUFVIEW_SLOT_BYTEOFFSET, Int32Value(0));
+    obj->initReservedSlot(JS_BUFVIEW_SLOT_LENGTH, Int32Value(length));
+    obj->initReservedSlot(JS_BUFVIEW_SLOT_OWNER, NullValue());
+    obj->initReservedSlot(JS_BUFVIEW_SLOT_NEXT_VIEW, PrivateValue(nullptr));
     obj->initReservedSlot(JS_TYPEDOBJ_SLOT_TYPE_DESCR, ObjectValue(*type));
 
     // Tag the type object for this instance with the type
     // representation, if that has not been done already.
     if (!type->is<SimpleTypeDescr>()) { // FIXME Bug 929651
         RootedTypeObject typeObj(cx, obj->getType(cx));
         if (typeObj) {
             if (!typeObj->addTypedObjectAddendum(cx, type))
@@ -1502,18 +1501,18 @@ TypedObject::createUnattachedWithClass(J
 void
 TypedObject::attach(ArrayBufferObject &buffer, int32_t offset)
 {
     JS_ASSERT(offset >= 0);
     JS_ASSERT((size_t) (offset + size()) <= buffer.byteLength());
 
     buffer.addView(this);
     InitArrayBufferViewDataPointer(this, &buffer, offset);
-    setReservedSlot(JS_TYPEDOBJ_SLOT_BYTEOFFSET, Int32Value(offset));
-    setReservedSlot(JS_TYPEDOBJ_SLOT_OWNER, ObjectValue(buffer));
+    setReservedSlot(JS_BUFVIEW_SLOT_BYTEOFFSET, Int32Value(offset));
+    setReservedSlot(JS_BUFVIEW_SLOT_OWNER, ObjectValue(buffer));
 }
 
 void
 TypedObject::attach(TypedObject &typedObj, int32_t offset)
 {
     JS_ASSERT(!typedObj.owner().isNeutered());
     JS_ASSERT(typedObj.typedMem() != NULL);
 
@@ -2161,17 +2160,17 @@ TypedObject::obj_enumerate(JSContext *cx
         switch (enum_op) {
           case JSENUMERATE_INIT_ALL:
           case JSENUMERATE_INIT:
             statep.setInt32(0);
             idp.set(INT_TO_JSID(typedObj->length()));
             break;
 
           case JSENUMERATE_NEXT:
-            index = static_cast<int32_t>(statep.toInt32());
+            index = statep.toInt32();
 
             if (index < typedObj->length()) {
                 idp.set(INT_TO_JSID(index));
                 statep.setInt32(index + 1);
             } else {
                 JS_ASSERT(index == typedObj->length());
                 statep.setNull();
             }
@@ -2212,38 +2211,45 @@ TypedObject::obj_enumerate(JSContext *cx
     }
 
     return true;
 }
 
 /* static */ size_t
 TypedObject::offsetOfOwnerSlot()
 {
-    return JSObject::getFixedSlotOffset(JS_TYPEDOBJ_SLOT_OWNER);
+    return JSObject::getFixedSlotOffset(JS_BUFVIEW_SLOT_OWNER);
 }
 
 /* static */ size_t
 TypedObject::offsetOfDataSlot()
 {
-    // the offset of 7 is based on the alloc kind
+#   ifdef DEBUG
+    // Compute offset of private data based on TransparentTypedObject;
+    // both OpaqueTypedObject and TransparentTypedObject have the same
+    // number of slots, so no problem there.
+    gc::AllocKind allocKind = gc::GetGCObjectKind(&TransparentTypedObject::class_);
+    size_t nfixed = gc::GetGCKindSlots(allocKind);
+    JS_ASSERT(JS_TYPEDOBJ_SLOT_DATA == nfixed - 1);
+#   endif
+
     return JSObject::getPrivateDataOffset(JS_TYPEDOBJ_SLOT_DATA);
 }
 
 /* static */ size_t
 TypedObject::offsetOfByteOffsetSlot()
 {
-    return JSObject::getFixedSlotOffset(JS_TYPEDOBJ_SLOT_BYTEOFFSET);
+    return JSObject::getFixedSlotOffset(JS_BUFVIEW_SLOT_BYTEOFFSET);
 }
 
 void
 TypedObject::neuter(void *newData)
 {
-    setSlot(JS_TYPEDOBJ_SLOT_LENGTH, Int32Value(0));
-    setSlot(JS_TYPEDOBJ_SLOT_BYTELENGTH, Int32Value(0));
-    setSlot(JS_TYPEDOBJ_SLOT_BYTEOFFSET, Int32Value(0));
+    setSlot(JS_BUFVIEW_SLOT_LENGTH, Int32Value(0));
+    setSlot(JS_BUFVIEW_SLOT_BYTEOFFSET, Int32Value(0));
     setPrivate(newData);
 }
 
 /******************************************************************************
  * Typed Objects
  */
 
 const Class TransparentTypedObject::class_ = {
@@ -2718,17 +2724,17 @@ js::SetTypedObjectOffset(ThreadSafeConte
 
     TypedObject &typedObj = args[0].toObject().as<TypedObject>();
     int32_t offset = args[1].toInt32();
 
     JS_ASSERT(!typedObj.owner().isNeutered());
     JS_ASSERT(typedObj.typedMem() != nullptr); // must be attached already
 
     typedObj.setPrivate(typedObj.owner().dataPointer() + offset);
-    typedObj.setReservedSlot(JS_TYPEDOBJ_SLOT_BYTEOFFSET, Int32Value(offset));
+    typedObj.setReservedSlot(JS_BUFVIEW_SLOT_BYTEOFFSET, Int32Value(offset));
     args.rval().setUndefined();
     return true;
 }
 
 bool
 js::intrinsic_SetTypedObjectOffset(JSContext *cx, unsigned argc, Value *vp)
 {
     // Do not use JSNativeThreadSafeWrapper<> so that ion can reference
--- a/js/src/builtin/TypedObject.h
+++ b/js/src/builtin/TypedObject.h
@@ -643,37 +643,33 @@ class TypedObject : public ArrayBufferVi
 
     // Otherwise, use this to attach to memory referenced by another typedObj.
     void attach(TypedObject &typedObj, int32_t offset);
 
     // Invoked when array buffer is transferred elsewhere
     void neuter(void *newData);
 
     int32_t offset() const {
-        return getReservedSlot(JS_TYPEDOBJ_SLOT_BYTEOFFSET).toInt32();
+        return getReservedSlot(JS_BUFVIEW_SLOT_BYTEOFFSET).toInt32();
     }
 
     ArrayBufferObject &owner() const {
-        return getReservedSlot(JS_TYPEDOBJ_SLOT_OWNER).toObject().as<ArrayBufferObject>();
+        return getReservedSlot(JS_BUFVIEW_SLOT_OWNER).toObject().as<ArrayBufferObject>();
     }
 
     TypeDescr &typeDescr() const {
         return getReservedSlot(JS_TYPEDOBJ_SLOT_TYPE_DESCR).toObject().as<TypeDescr>();
     }
 
     uint8_t *typedMem() const {
         return (uint8_t*) getPrivate();
     }
 
-    int32_t byteLength() const {
-        return getReservedSlot(JS_TYPEDOBJ_SLOT_BYTELENGTH).toInt32();
-    }
-
     int32_t length() const {
-        return getReservedSlot(JS_TYPEDOBJ_SLOT_LENGTH).toInt32();
+        return getReservedSlot(JS_BUFVIEW_SLOT_LENGTH).toInt32();
     }
 
     int32_t size() const {
         switch (typeDescr().kind()) {
           case TypeDescr::Scalar:
           case TypeDescr::X4:
           case TypeDescr::Reference:
           case TypeDescr::Struct:
--- a/js/src/builtin/TypedObject.js
+++ b/js/src/builtin/TypedObject.js
@@ -26,25 +26,23 @@
 #define DESCR_STRUCT_FIELD_TYPES(obj) \
     UnsafeGetReservedSlot(obj, JS_DESCR_SLOT_STRUCT_FIELD_TYPES)
 #define DESCR_STRUCT_FIELD_OFFSETS(obj) \
     UnsafeGetReservedSlot(obj, JS_DESCR_SLOT_STRUCT_FIELD_OFFSETS)
 
 // Typed object slots
 
 #define TYPEDOBJ_BYTEOFFSET(obj) \
-    TO_INT32(UnsafeGetReservedSlot(obj, JS_TYPEDOBJ_SLOT_BYTEOFFSET))
-#define TYPEDOBJ_BYTELENGTH(obj) \
-    TO_INT32(UnsafeGetReservedSlot(obj, JS_TYPEDOBJ_SLOT_BYTELENGTH))
+    TO_INT32(UnsafeGetReservedSlot(obj, JS_BUFVIEW_SLOT_BYTEOFFSET))
 #define TYPEDOBJ_TYPE_DESCR(obj) \
     UnsafeGetReservedSlot(obj, JS_TYPEDOBJ_SLOT_TYPE_DESCR)
 #define TYPEDOBJ_OWNER(obj) \
-    UnsafeGetReservedSlot(obj, JS_TYPEDOBJ_SLOT_OWNER)
+    UnsafeGetReservedSlot(obj, JS_BUFVIEW_SLOT_OWNER)
 #define TYPEDOBJ_LENGTH(obj) \
-    TO_INT32(UnsafeGetReservedSlot(obj, JS_TYPEDOBJ_SLOT_LENGTH))
+    TO_INT32(UnsafeGetReservedSlot(obj, JS_BUFVIEW_SLOT_LENGTH))
 
 #define HAS_PROPERTY(obj, prop) \
     callFunction(std_Object_hasOwnProperty, obj, prop)
 
 ///////////////////////////////////////////////////////////////////////////
 // Getting values
 //
 // The methods in this section read from the memory pointed at
@@ -566,20 +564,28 @@ function ArrayShorthand(...dims) {
 // typed object, it returns null. Otherwise it throws.
 //
 // Warning: user exposed!
 function StorageOfTypedObject(obj) {
   if (IsObject(obj)) {
     if (ObjectIsOpaqueTypedObject(obj))
       return null;
 
-    if (ObjectIsTransparentTypedObject(obj))
+    if (ObjectIsTransparentTypedObject(obj)) {
+      var descr = TYPEDOBJ_TYPE_DESCR(obj);
+      var byteLength;
+      if (DESCR_KIND(descr) == JS_TYPEREPR_UNSIZED_ARRAY_KIND)
+        byteLength = DESCR_SIZE(descr.elementType) * obj.length;
+      else
+        byteLength = DESCR_SIZE(descr);
+
       return { buffer: TYPEDOBJ_OWNER(obj),
-               byteLength: TYPEDOBJ_BYTELENGTH(obj),
+               byteLength: byteLength,
                byteOffset: TYPEDOBJ_BYTEOFFSET(obj) };
+    }
   }
 
   ThrowError(JSMSG_TYPEDOBJECT_BAD_ARGS);
   return null; // pacify silly "always returns a value" lint
 }
 
 // This is the `objectType()` function defined in the spec.
 // It returns the type of its argument.
--- a/js/src/builtin/TypedObjectConstants.h
+++ b/js/src/builtin/TypedObjectConstants.h
@@ -86,27 +86,42 @@
 // you to write a switch which will receive a warning if you omit a
 // case.
 #define JS_X4TYPEREPR_INT32         0
 #define JS_X4TYPEREPR_FLOAT32       1
 
 ///////////////////////////////////////////////////////////////////////////
 // Slots for typed objects
 
-#define JS_TYPEDOBJ_SLOT_BYTEOFFSET       0
-#define JS_TYPEDOBJ_SLOT_BYTELENGTH       1
-#define JS_TYPEDOBJ_SLOT_OWNER            2
-#define JS_TYPEDOBJ_SLOT_NEXT_VIEW        3
+
+// Common to data view, typed arrays, and typed objects:
+#define JS_BUFVIEW_SLOT_BYTEOFFSET       0
+#define JS_BUFVIEW_SLOT_LENGTH           1 // see (*) below
+#define JS_BUFVIEW_SLOT_OWNER            2
+#define JS_BUFVIEW_SLOT_NEXT_VIEW        3
 
-#define JS_DATAVIEW_SLOTS              4 // Number of slots for data views
+// Specific to data view:
+#define JS_DATAVIEW_SLOT_DATA            7 // see (**) below
+#define JS_DATAVIEW_SLOTS                4 // Number of slots for data views
+
+// Specific to typed arrays:
+#define JS_TYPEDARR_SLOT_TYPE            4 // A ScalarTypeDescr::Type constant
+#define JS_TYPEDARR_SLOT_DATA            7 // see (**) below
+#define JS_TYPEDARR_SLOTS                5 // Number of slots for typed arrays
 
-#define JS_TYPEDOBJ_SLOT_LENGTH           4 // Length of array (see (*) below)
-#define JS_TYPEDOBJ_SLOT_TYPE_DESCR       5 // For typed objects, type descr
+// Specific to typed objects:
+#define JS_TYPEDOBJ_SLOT_TYPE_DESCR      4 // A ScalarTypeDescr::Type constant
+#define JS_TYPEDOBJ_SLOT_DATA            7
+#define JS_TYPEDOBJ_SLOTS                5 // Number of slots for typed objs
 
-#define JS_TYPEDOBJ_SLOT_DATA             7 // private slot, based on alloc kind
-#define JS_TYPEDOBJ_SLOTS                 6 // Number of slots for typed objs
+// (*) The interpretation of the JS_BUFVIEW_SLOT_LENGTH slot depends on
+// the kind of view:
+// - DataView: stores the length in bytes
+// - TypedArray: stores the array length
+// - TypedObject: for arrays, stores the array length, else 0
 
-// (*) The JS_TYPEDOBJ_SLOT_LENGTH slot stores the length for typed objects of
-// sized and unsized array type. The slot contains 0 for non-arrays.
-// The slot also contains 0 for *unattached* typed objects, no matter what
-// type they have.
+// (**) This is the index of the slot that will be used for private data.
+// It is hardcoded here based on the GC Kind that will be assigned. It is
+// a function of the total number of slots, but it is non-trivial to encode
+// that function at compile-time, so we instead use a hardcoded constant
+// coupled with some handy assertions.
 
 #endif
--- a/js/src/irregexp/NativeRegExpMacroAssembler.cpp
+++ b/js/src/irregexp/NativeRegExpMacroAssembler.cpp
@@ -91,19 +91,21 @@ NativeRegExpMacroAssembler::NativeRegExp
 
     // Determine the non-volatile registers which might be modified by jitcode.
     for (GeneralRegisterIterator iter(GeneralRegisterSet::NonVolatile()); iter.more(); iter++) {
         Register reg = *iter;
         if (!regs.has(reg))
             savedNonVolatileRegisters.add(reg);
     }
 
-#ifdef JS_CODEGEN_ARM
+#if defined(JS_CODEGEN_ARM)
     // ARM additionally requires that the link register be saved.
     savedNonVolatileRegisters.add(Register::FromCode(Registers::lr));
+#elif defined(JS_CODEGEN_MIPS)
+    savedNonVolatileRegisters.add(Register::FromCode(Registers::ra));
 #endif
 
     masm.jump(&entry_label_);
     masm.bind(&start_label_);
 }
 
 #define SPEW_PREFIX IonSpew_Codegen, "!!! "
 
@@ -388,18 +390,20 @@ NativeRegExpMacroAssembler::GenerateCode
         masm.bind(&stack_overflow_label_);
 
         Label grow_failed;
 
         masm.movePtr(ImmPtr(runtime), temp1);
 
         // Save registers before calling C function
         RegisterSet volatileRegs = RegisterSet::Volatile();
-#ifdef JS_CODEGEN_ARM
+#if defined(JS_CODEGEN_ARM)
         volatileRegs.add(Register::FromCode(Registers::lr));
+#elif defined(JS_CODEGEN_MIPS)
+        volatileRegs.add(Register::FromCode(Registers::ra));
 #endif
         volatileRegs.takeUnchecked(temp0);
         volatileRegs.takeUnchecked(temp1);
         masm.PushRegsInMask(volatileRegs);
 
         masm.setupUnalignedABICall(1, temp0);
         masm.passABIArg(temp1);
         masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, GrowBacktrackStack));
@@ -810,17 +814,17 @@ NativeRegExpMacroAssembler::CheckBitInTa
 
     JS_ASSERT(mode_ != ASCII); // Ascii case not handled here.
 
     masm.movePtr(ImmPtr(table), temp0);
     masm.move32(Imm32(kTableSize - 1), temp1);
     masm.and32(current_character, temp1);
 
     masm.load8ZeroExtend(BaseIndex(temp0, temp1, TimesOne), temp0);
-    masm.branchTest32(Assembler::NotEqual, temp0, temp0, BranchOrBacktrack(on_bit_set));
+    masm.branchTest32(Assembler::NonZero, temp0, temp0, BranchOrBacktrack(on_bit_set));
 }
 
 void
 NativeRegExpMacroAssembler::Fail()
 {
     IonSpew(SPEW_PREFIX "Fail");
 
     if (!global())
@@ -1223,17 +1227,21 @@ NativeRegExpMacroAssembler::CheckSpecial
       default:
         return false;
     }
 }
 
 bool
 NativeRegExpMacroAssembler::CanReadUnaligned()
 {
+#if defined(JS_CODEGEN_MIPS)
+    return false;
+#else
     return true;
+#endif
 }
 
 const uint8_t
 NativeRegExpMacroAssembler::word_character_map[] =
 {
     0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u,
     0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u,
     0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u,
--- a/js/src/jit-test/jit_test.py
+++ b/js/src/jit-test/jit_test.py
@@ -37,18 +37,20 @@ def main(argv):
     op.add_option('-s', '--show-cmd', dest='show_cmd', action='store_true',
                   help='show js shell command run')
     op.add_option('-f', '--show-failed-cmd', dest='show_failed',
                   action='store_true', help='show command lines of failed tests')
     op.add_option('-o', '--show-output', dest='show_output', action='store_true',
                   help='show output from js shell')
     op.add_option('-x', '--exclude', dest='exclude', action='append',
                   help='exclude given test dir or path')
+    op.add_option('--slow', dest='run_slow', action='store_true',
+                  help='also run tests marked as slow')
     op.add_option('--no-slow', dest='run_slow', action='store_false',
-                  help='do not run tests marked as slow')
+                  help='do not run tests marked as slow (the default)')
     op.add_option('-t', '--timeout', dest='timeout',  type=float, default=150.0,
                   help='set test timeout in seconds')
     op.add_option('--no-progress', dest='hide_progress', action='store_true',
                   help='hide progress bar')
     op.add_option('--tinderbox', dest='tinderbox', action='store_true',
                   help='Tinderbox-parseable output format')
     op.add_option('--args', dest='shell_args', default='',
                   help='extra args to pass to the JS shell')
--- a/js/src/jit-test/tests/gc/bug-948423.js
+++ b/js/src/jit-test/tests/gc/bug-948423.js
@@ -15,9 +15,10 @@ function runTests() {
 	FiveUintsA.equivalent(FiveUintsB)
 	);
   })();
   (function PrototypeHierarchy() {
     schedulegc(3);
     var Uint8s = uint8.array();
   })();
 }
+
 runTests();
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/ion/bug998059.js
@@ -0,0 +1,25 @@
+// Test various ways of changing the behavior of |typedArray.length|.
+
+function addLengthProperty() {
+  var x = new Uint16Array();
+  Object.defineProperty(x, "length", {value:1});
+  for (var i = 0; i < 5; i++)
+    assertEq(x.length, 1);
+}
+addLengthProperty();
+
+function changePrototype() {
+  var x = new Uint16Array();
+  x.__proto__ = [0];
+  for (var i = 0; i < 5; i++)
+    assertEq(x.length, 1);
+}
+changePrototype();
+
+function redefineLengthProperty() {
+  var x = new Uint16Array();
+  Object.defineProperty(Uint16Array.prototype, "length", {value:1});
+  for (var i = 0; i < 5; i++)
+    assertEq(x.length, 1);
+}
+redefineLengthProperty();
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/latin1/search.js
@@ -0,0 +1,60 @@
+function testSearchFlat() {
+    var s1 = toLatin1("fooBar12345");
+    var s2 = toLatin1("Bar1");
+
+    // Latin1 + Latin1
+    assertEq(s1.search(s2), 3);
+    assertEq(s2.search(s1), -1);
+    assertEq(s1.search(s1), 0);
+
+    // Latin1 + TwoByte
+    assertEq(s1.search(s2 + "\u1200"), -1);
+    assertEq(s1.search(("12345\u1200").slice(0, -1)), 6);
+
+    // TwoByte + Latin1
+    assertEq("fooBar12345\u1200".search(s1), 0);
+    assertEq("fooBar12345\u1200".search(s2), 3);
+
+    // TwoByte + TwoByte
+    assertEq("fooBar12345\u1200".search("5\u1200"), 10);
+    assertEq("fooBar12345\u1200".search("5\u1201"), -1);
+}
+testSearchFlat();
+
+function testSearchRope() {
+    // Tests for the RopeMatch algorithm.
+    var s1 = "foobarbaz0123456789".repeat(10);
+    s1.indexOf("333"); // flatten
+    s1 = toLatin1(s1);
+
+    var ropeMixed = s1 + "abcdef\u1200";
+    assertEq(isLatin1(ropeMixed), false);
+
+    var abc = toLatin1("abc");
+    var baz = toLatin1("baz");
+
+    // Mixed + Latin1
+    assertEq(ropeMixed.search(abc), 190);
+    assertEq(ropeMixed.search(baz), 6);
+
+    // Mixed + TwoByte
+    assertEq(ropeMixed.search("def\u1200"), 193);
+
+    // Latin1 + Latin1
+    s1 = "foobarbaz0123456789".repeat(10);
+    var ropeLatin1 = s1 + toLatin1("abcdef\u00AA");
+    assertEq(isLatin1(ropeLatin1), false);
+    assertEq(ropeLatin1.search(abc), 190);
+
+    // Latin1 + TwoByte
+    assertEq(ropeLatin1.search("\u1200bc".substr(1)), 191);
+
+    // TwoByte + Latin1
+    s1 = "foobarbaz0123456789\u11AA".repeat(10);
+    var ropeTwoByte = s1 + "abcdef\u1200";
+    assertEq(ropeTwoByte.search(abc), 200);
+
+    // TwoByte + TwoByte
+    assertEq(ropeTwoByte.search("def\u1200"), 203);
+}
+testSearchRope();
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/latin1/toLowerCase-toUpperCase.js
@@ -0,0 +1,53 @@
+function testToLowerCase() {
+    var s1 = toLatin1("abcdefgABCDEFGH 123456");
+
+    // Latin1
+    var s2 = s1.toLowerCase();
+    assertEq(isLatin1(s2), true);
+    assertEq(s2, "abcdefgabcdefgh 123456");
+
+    s2 = s1.toLocaleLowerCase();
+    assertEq(isLatin1(s2), true);
+    assertEq(s2, "abcdefgabcdefgh 123456");
+
+    // TwoByte
+    s2 = "abcdefg\u1200ABCDEFGH 123456\u04AC".toLowerCase();
+    assertEq(s2, "abcdefg\u1200abcdefgh 123456\u04AD");
+
+    s2 = "abcdefg\u1200ABCDEFGH 123456\u04AC".toLocaleLowerCase();
+    assertEq(s2, "abcdefg\u1200abcdefgh 123456\u04AD");
+
+    // For toLowerCase, every Latin1 character maps to a Latin1 character.
+    for (var i=0; i <= 0xff; i++) {
+	var s = "\u1200\u11AA" + String.fromCharCode(i);
+	assertEq(s.toLowerCase().charCodeAt(2) <= 0xff, true);
+    }
+}
+testToLowerCase();
+
+function testToUpperCase() {
+    var s1 = toLatin1("abcdefgABCDEFGH 12345");
+
+    // Latin1
+    var s2 = s1.toUpperCase();
+    assertEq(s2, "ABCDEFGABCDEFGH 12345");
+
+    s2 = s1.toLocaleUpperCase();
+    assertEq(s2, "ABCDEFGABCDEFGH 12345");
+
+    // TwoByte
+    s2 = "abcdefg\u1200ABCDEFGH 12345\u1E0F".toUpperCase();
+    assertEq(s2, "ABCDEFG\u1200ABCDEFGH 12345\u1E0E");
+
+    s2 = "abcdefg\u1200ABCDEFGH 12345\u1E0F".toLocaleUpperCase();
+    assertEq(s2, "ABCDEFG\u1200ABCDEFGH 12345\u1E0E");
+
+    // Tricky case: Latin1 character \u00FF maps to \u0178, a
+    // non-Latin1 character.
+    s1 = toLatin1("ABC\u00FF");
+    assertEq(isLatin1(s1), true);
+    s2 = s1.toUpperCase();
+    assertEq(isLatin1(s2), false);
+    assertEq(s2, "ABC\u0178");
+}
+testToUpperCase();
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/latin1/trim.js
@@ -0,0 +1,27 @@
+function test() {
+    // Latin1
+    var s = toLatin1("  \r\t\n\u00A0foo 123\t \r\n\u00A0");
+
+    var res = s.trim();
+    assertEq(isLatin1(res), true);
+    assertEq(res, "foo 123");
+
+    res = s.trimLeft();
+    assertEq(isLatin1(res), true);
+    assertEq(res, "foo 123\t \r\n\u00A0");
+
+    res = s.trimRight();
+    assertEq(isLatin1(res), true);
+    assertEq(res, "  \r\t\n\u00A0foo 123");
+
+    res = toLatin1("foo 1234").trim();
+    assertEq(isLatin1(res), true);
+    assertEq(res, "foo 1234");
+
+    // TwoByte
+    s = "  \r\t\n\u00A0\u2000foo\u1200123\t \r\n\u00A0\u2009";
+    assertEq(s.trim(), "foo\u1200123");
+    assertEq(s.trimLeft(), "foo\u1200123\t \r\n\u00A0\u2009");
+    assertEq(s.trimRight(), "  \r\t\n\u00A0\u2000foo\u1200123");
+}
+test();
--- a/js/src/jit/AsmJS.cpp
+++ b/js/src/jit/AsmJS.cpp
@@ -1569,45 +1569,47 @@ class MOZ_STACK_CLASS ModuleCompiler
             CodeLabel src = masm_.codeLabel(i);
             int32_t labelOffset = src.dest()->offset();
             int32_t targetOffset = masm_.actualOffset(src.src()->offset());
             // The patched uses of a label embed a linked list where the
             // to-be-patched immediate is the offset of the next to-be-patched
             // instruction.
             while (labelOffset != LabelBase::INVALID_OFFSET) {
                 size_t patchAtOffset = masm_.labelOffsetToPatchOffset(labelOffset);
-                AsmJSModule::RelativeLink link;
+                AsmJSModule::RelativeLink link(AsmJSModule::RelativeLink::CodeLabel);
                 link.patchAtOffset = patchAtOffset;
                 link.targetOffset = targetOffset;
                 if (!module_->addRelativeLink(link))
                     return false;
-                labelOffset = *(uintptr_t *)(module_->codeBase() + patchAtOffset);
+
+                labelOffset = Assembler::extractCodeLabelOffset(module_->codeBase() +
+                                                                patchAtOffset);
             }
         }
 
         // Function-pointer-table entries
         for (unsigned tableIndex = 0; tableIndex < funcPtrTables_.length(); tableIndex++) {
             FuncPtrTable &table = funcPtrTables_[tableIndex];
             unsigned tableBaseOffset = module_->offsetOfGlobalData() + table.globalDataOffset();
             for (unsigned elemIndex = 0; elemIndex < table.numElems(); elemIndex++) {
-                AsmJSModule::RelativeLink link;
+                AsmJSModule::RelativeLink link(AsmJSModule::RelativeLink::RawPointer);
                 link.patchAtOffset = tableBaseOffset + elemIndex * sizeof(uint8_t*);
                 link.targetOffset = masm_.actualOffset(table.elem(elemIndex).code()->offset());
                 if (!module_->addRelativeLink(link))
                     return false;
             }
         }
 
 #if defined(JS_CODEGEN_X86)
         // Global data accesses in x86 need to be patched with the absolute
         // address of the global. Globals are allocated sequentially after the
         // code section so we can just use an RelativeLink.
         for (unsigned i = 0; i < masm_.numAsmJSGlobalAccesses(); i++) {
             AsmJSGlobalAccess a = masm_.asmJSGlobalAccess(i);
-            AsmJSModule::RelativeLink link;
+            AsmJSModule::RelativeLink link(AsmJSModule::RelativeLink::InstructionImmediate);
             link.patchAtOffset = masm_.labelOffsetToPatchOffset(a.patchAt.offset());
             link.targetOffset = module_->offsetOfGlobalData() + a.globalDataOffset;
             if (!module_->addRelativeLink(link))
                 return false;
         }
 #endif
 
 #if defined(JS_CODEGEN_X64)
@@ -1615,16 +1617,34 @@ class MOZ_STACK_CLASS ModuleCompiler
         // not need patching after deserialization.
         uint8_t *code = module_->codeBase();
         for (unsigned i = 0; i < masm_.numAsmJSGlobalAccesses(); i++) {
             AsmJSGlobalAccess a = masm_.asmJSGlobalAccess(i);
             masm_.patchAsmJSGlobalAccess(a.patchAt, code, module_->globalData(), a.globalDataOffset);
         }
 #endif
 
+#if defined(JS_CODEGEN_MIPS)
+        // On MIPS we need to update all the long jumps because they contain an
+        // absolute adress.
+        for (size_t i = 0; i < masm_.numLongJumps(); i++) {
+            uint32_t patchAtOffset = masm_.longJump(i);
+
+            AsmJSModule::RelativeLink link(AsmJSModule::RelativeLink::InstructionImmediate);
+            link.patchAtOffset = patchAtOffset;
+
+            InstImm *inst = (InstImm *)(module_->codeBase() + patchAtOffset);
+            link.targetOffset = Assembler::extractLuiOriValue(inst, inst->next()) -
+                                (uint32_t)module_->codeBase();
+
+            if (!module_->addRelativeLink(link))
+                return false;
+        }
+#endif
+
         // Absolute links
         for (size_t i = 0; i < masm_.numAsmJSAbsoluteLinks(); i++) {
             AsmJSAbsoluteLink src = masm_.asmJSAbsoluteLink(i);
             AsmJSModule::AbsoluteLink link;
             link.patchAt = CodeOffsetLabel(masm_.actualOffset(src.patchAt.offset()));
             link.target = src.target;
             if (!module_->addAbsoluteLink(link))
                 return false;
@@ -6050,24 +6070,32 @@ StackDecrementForCall(MacroAssembler &ma
 
 template <class VectorT>
 static unsigned
 StackDecrementForCall(MacroAssembler &masm, const VectorT &argTypes, unsigned extraBytes = 0)
 {
     return StackDecrementForCall(masm, StackArgBytes(argTypes) + extraBytes);
 }
 
+#if defined(JS_CODEGEN_MIPS)
+// Mips is using one more double slot due to stack alignment for double values.
+// Look at MacroAssembler::PushRegsInMask(RegisterSet set)
+static const unsigned FramePushedAfterSave = NonVolatileRegs.gprs().size() * sizeof(intptr_t) +
+                                             NonVolatileRegs.fpus().size() * sizeof(double) +
+                                             sizeof(double);
+#else
 static const unsigned FramePushedAfterSave = NonVolatileRegs.gprs().size() * sizeof(intptr_t) +
                                              NonVolatileRegs.fpus().size() * sizeof(double);
-
-// On arm, we need to include an extra word of space at the top of the stack so
-// we can explicitly store the return address before making the call to C++ or
-// Ion. On x86/x64, this isn't necessary since the call instruction pushes the
-// return address.
-#ifdef JS_CODEGEN_ARM
+#endif
+
+// On ARM/MIPS, we need to include an extra word of space at the top of the
+// stack so we can explicitly store the return address before making the call
+// to C++ or Ion. On x86/x64, this isn't necessary since the call instruction
+// pushes the return address.
+#if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS)
 static const unsigned MaybeRetAddr = sizeof(void*);
 #else
 static const unsigned MaybeRetAddr = 0;
 #endif
 
 static bool
 GenerateEntry(ModuleCompiler &m, const AsmJSModule::ExportedFunction &exportedFunc)
 {
@@ -6082,39 +6110,42 @@ GenerateEntry(ModuleCompiler &m, const A
     masm.setFramePushed(0);
 
 #if defined(JS_CODEGEN_ARM)
     // Push lr without incrementing masm.framePushed since this push is
     // accounted for by AlignmentAtAsmJSPrologue. The masm.ret at the end will
     // pop.
     masm.push(lr);
 #endif // JS_CODEGEN_ARM
+#if defined(JS_CODEGEN_MIPS)
+    masm.push(ra);
+#endif
 
     masm.PushRegsInMask(NonVolatileRegs);
     JS_ASSERT(masm.framePushed() == FramePushedAfterSave);
 
     // Remember the stack pointer in the current AsmJSActivation. This will be
     // used by error exit paths to set the stack pointer back to what it was
     // right after the (C++) caller's non-volatile registers were saved so that
     // they can be restored.
     Register activation = ABIArgGenerator::NonArgReturnVolatileReg0;
     LoadAsmJSActivationIntoRegister(masm, activation);
     masm.storePtr(StackPointer, Address(activation, AsmJSActivation::offsetOfErrorRejoinSP()));
 
-    // ARM has a globally-pinned GlobalReg (x64 uses RIP-relative addressing,
-    // x86 uses immediates in effective addresses) and NaN register (used as
-    // part of the out-of-bounds handling in heap loads/stores).
-#if defined(JS_CODEGEN_ARM)
+    // ARM and MIPS have a globally-pinned GlobalReg (x64 uses RIP-relative
+    // addressing, x86 uses immediates in effective addresses) and NaN register
+    // (used as part of the out-of-bounds handling in heap loads/stores).
+#if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS)
     masm.movePtr(IntArgReg1, GlobalReg);
-    masm.ma_vimm(GenericNaN(), NANReg);
+    masm.loadConstantDouble(GenericNaN(), NANReg);
 #endif
 
-    // ARM and x64 have a globally-pinned HeapReg (x86 uses immediates in
+    // ARM, MIPS and x64 have a globally-pinned HeapReg (x86 uses immediates in
     // effective addresses).
-#if defined(JS_CODEGEN_X64) || defined(JS_CODEGEN_ARM)
+#if defined(JS_CODEGEN_X64) || defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS)
     masm.loadPtr(Address(IntArgReg1, m.module().heapOffset()), HeapReg);
 #endif
 
     // Get 'argv' into a non-arg register and save it on the stack.
     Register argv = ABIArgGenerator::NonArgReturnVolatileReg0;
     Register scratch = ABIArgGenerator::NonArgReturnVolatileReg1;
 #if defined(JS_CODEGEN_X86)
     masm.loadPtr(Address(StackPointer, NativeFrameSize + masm.framePushed()), argv);
@@ -6340,33 +6371,38 @@ GenerateFFIInterpreterExit(ModuleCompile
     masm.setFramePushed(0);
 
 #if defined(JS_CODEGEN_ARM)
     // Push lr without incrementing masm.framePushed since this push is
     // accounted for by AlignmentAtAsmJSPrologue. The masm.ret at the end will
     // pop.
     masm.push(lr);
 #endif
+#if defined(JS_CODEGEN_MIPS)
+    masm.push(ra);
+#endif
 
     MIRType typeArray[] = { MIRType_Pointer,   // cx
                             MIRType_Pointer,   // exitDatum
                             MIRType_Int32,     // argc
                             MIRType_Pointer }; // argv
     MIRTypeVector invokeArgTypes(m.cx());
     invokeArgTypes.infallibleAppend(typeArray, ArrayLength(typeArray));
 
-    // The stack layout looks like:
-    // | return address | stack arguments | array of values |
-    unsigned arraySize = Max<size_t>(1, exit.sig().args().length()) * sizeof(Value);
-    unsigned stackDec = StackDecrementForCall(masm, invokeArgTypes, arraySize + MaybeRetAddr);
+    // At the point of the call, the stack layout shall be (sp grows to the left):
+    // | retaddr | stack args | padding | Value argv[] | padding | retaddr | caller stack args |
+    // The first padding ensures double-alignment of argv; the second ensures
+    // sp is aligned.
+    unsigned offsetToArgv = AlignBytes(StackArgBytes(invokeArgTypes) + MaybeRetAddr, StackAlignment);
+    unsigned argvBytes = Max<size_t>(1, exit.sig().args().length()) * sizeof(Value);
+    unsigned stackDec = StackDecrementForCall(masm, offsetToArgv + argvBytes);
     masm.reserveStack(stackDec);
 
     // Fill the argument array.
     unsigned offsetToCallerStackArgs = AlignmentAtAsmJSPrologue + masm.framePushed();
-    unsigned offsetToArgv = StackArgBytes(invokeArgTypes) + MaybeRetAddr;
     Register scratch = ABIArgGenerator::NonArgReturnVolatileReg0;
     FillArgumentArray(m, exit.sig().args(), offsetToArgv, offsetToCallerStackArgs, scratch);
 
     // Prepare the arguments for the call to InvokeFromAsmJS_*.
     ABIArgMIRTypeIter i(invokeArgTypes);
     Register activation = ABIArgGenerator::NonArgReturnVolatileReg1;
     LoadAsmJSActivationIntoRegister(masm, activation);
 
@@ -6518,16 +6554,19 @@ GenerateFFIIonExit(ModuleCompiler &m, co
     // pop.
     masm.push(lr);
 
     // The GlobalReg (r10) and HeapReg (r11) also need to be restored before
     // returning to asm.js code.
     // The NANReg also needs to be restored, but is a constant and is reloaded before
     // returning to asm.js code.
     masm.PushRegsInMask(GeneralRegisterSet((1<<GlobalReg.code()) | (1<<HeapReg.code())));
+#elif defined(JS_CODEGEN_MIPS)
+    masm.push(ra);
+    masm.PushRegsInMask(GeneralRegisterSet((1<<GlobalReg.code()) | (1<<HeapReg.code())));
 #endif
 
     // The stack frame is used for the call into Ion and also for calls into C for OOL
     // conversion of the result.  A frame large enough for both is allocated.
     //
     // Arguments to the Ion function are in the following order on the stack:
     // | return address | descriptor | callee | argc | this | arg1 | arg2 | ...
     unsigned argBytes = 3 * sizeof(size_t) + (1 + exit.sig().args().length()) * sizeof(Value);
@@ -6620,17 +6659,25 @@ GenerateFFIIonExit(ModuleCompiler &m, co
         Register reg0 = AsmJSIonExitRegE0;
         Register reg1 = AsmJSIonExitRegE1;
         Register reg2 = AsmJSIonExitRegE2;
         Register reg3 = AsmJSIonExitRegE3;
 
         LoadAsmJSActivationIntoRegister(masm, reg0);
 
         // Record sp in the AsmJSActivation for stack-walking.
+#if defined(JS_CODEGEN_MIPS)
+        // Add a flag to indicate to AsmJSFrameIterator that we are calling
+        // into Ion, since the offset from SP to the return address is
+        // different when calling Ion vs. the native ABI.
+        masm.ma_or(reg1, StackPointer, Imm32(0x1));
+        masm.storePtr(reg1, Address(reg0, AsmJSActivation::offsetOfExitSP()));
+#else
         masm.storePtr(StackPointer, Address(reg0, AsmJSActivation::offsetOfExitSP()));
+#endif
 
         // The following is inlined:
         //   JSContext *cx = activation->cx();
         //   Activation *act = cx->mainThread().activation();
         //   act.active_ = true;
         //   act.prevJitTop_ = cx->mainThread().jitTop;
         //   act.prevJitJSContext_ = cx->mainThread().jitJSContext;
         //   cx->mainThread().jitJSContext = cx;
@@ -6714,18 +6761,18 @@ GenerateFFIIonExit(ModuleCompiler &m, co
         break;
     }
 
     masm.bind(&done);
     masm.freeStack(stackDec);
 #if defined(JS_CODEGEN_X64)
     masm.Pop(HeapReg);
 #endif
-#if defined(JS_CODEGEN_ARM)
-    masm.ma_vimm(GenericNaN(), NANReg);
+#if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS)
+    masm.loadConstantDouble(GenericNaN(), NANReg);
     masm.PopRegsInMask(GeneralRegisterSet((1<<GlobalReg.code()) | (1<<HeapReg.code())));
 #endif
     masm.ret();
     JS_ASSERT(masm.framePushed() == 0);
 
     // oolConvert
     if (oolConvert.used()) {
         masm.bind(&oolConvert);
@@ -6806,17 +6853,17 @@ GenerateStackOverflowExit(ModuleCompiler
 // stack so that it can be popped directly into PC.
 static bool
 GenerateInterruptExit(ModuleCompiler &m, Label *throwLabel)
 {
     MacroAssembler &masm = m.masm();
     masm.align(CodeAlignment);
     masm.bind(&m.interruptLabel());
 
-#ifndef JS_CODEGEN_ARM
+#if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)
     // Be very careful here not to perturb the machine state before saving it
     // to the stack. In particular, add/sub instructions may set conditions in
     // the flags register.
     masm.push(Imm32(0));            // space for resumePC
     masm.pushFlags();               // after this we are safe to use sub
     masm.setFramePushed(0);         // set to zero so we can use masm.framePushed() below
     masm.PushRegsInMask(AllRegsExceptSP); // save all GP/FP registers (except SP)
 
@@ -6852,17 +6899,57 @@ GenerateInterruptExit(ModuleCompiler &m,
 
     // Restore the StackPointer to it's position before the call.
     masm.mov(ABIArgGenerator::NonVolatileReg, StackPointer);
 
     // Restore the machine state to before the interrupt.
     masm.PopRegsInMask(AllRegsExceptSP); // restore all GP/FP registers (except SP)
     masm.popFlags();              // after this, nothing that sets conditions
     masm.ret();                   // pop resumePC into PC
-#else
+#elif defined(JS_CODEGEN_MIPS)
+    // Reserve space to store resumePC.
+    masm.subPtr(Imm32(sizeof(intptr_t)), StackPointer);
+    // set to zero so we can use masm.framePushed() below.
+    masm.setFramePushed(0);
+    // save all registers,except sp. After this stack is alligned.
+    masm.PushRegsInMask(AllRegsExceptSP);
+
+    // Save the stack pointer in a non-volatile register.
+    masm.movePtr(StackPointer, s0);
+    // Align the stack.
+    masm.ma_and(StackPointer, StackPointer, Imm32(~(StackAlignment - 1)));
+
+    // Store resumePC into the reserved space.
+    LoadAsmJSActivationIntoRegister(masm, IntArgReg0);
+    masm.loadPtr(Address(IntArgReg0, AsmJSActivation::offsetOfResumePC()), IntArgReg1);
+    masm.storePtr(IntArgReg1, Address(s0, masm.framePushed()));
+
+    // argument 0: cx
+    masm.loadPtr(Address(IntArgReg0, AsmJSActivation::offsetOfContext()), IntArgReg0);
+
+    // MIPS ABI requires rewserving stack for registes $a0 to $a3.
+    masm.subPtr(Imm32(4 * sizeof(intptr_t)), StackPointer);
+
+    masm.call(AsmJSImm_HandleExecutionInterrupt);
+
+    masm.addPtr(Imm32(4 * sizeof(intptr_t)), StackPointer);
+
+    masm.branchIfFalseBool(ReturnReg, throwLabel);
+
+    // This will restore stack to the address before the call.
+    masm.movePtr(s0, StackPointer);
+    masm.PopRegsInMask(AllRegsExceptSP);
+
+    // Pop resumePC into PC. Clobber HeapReg to make the jump and restore it
+    // during jump delay slot.
+    JS_ASSERT(Imm16::isInSignedRange(m.module().heapOffset()));
+    masm.pop(HeapReg);
+    masm.as_jr(HeapReg);
+    masm.loadPtr(Address(GlobalReg, m.module().heapOffset()), HeapReg);
+#elif defined(JS_CODEGEN_ARM)
     masm.setFramePushed(0);         // set to zero so we can use masm.framePushed() below
     masm.PushRegsInMask(RegisterSet(GeneralRegisterSet(Registers::AllMask & ~(1<<Registers::sp)), FloatRegisterSet(uint32_t(0))));   // save all GP registers,excep sp
 
     // Save both the APSR and FPSCR in non-volatile registers.
     masm.as_mrs(r4);
     masm.as_vmrs(r5);
     // Save the stack pointer in a non-volatile register.
     masm.mov(sp,r6);
@@ -6900,16 +6987,18 @@ GenerateInterruptExit(ModuleCompiler &m,
     masm.transferReg(r9);
     masm.transferReg(r10);
     masm.transferReg(r11);
     masm.transferReg(r12);
     masm.transferReg(lr);
     masm.finishDataTransfer();
     masm.ret();
 
+#else
+# error "Unknown architecture!"
 #endif
 
     return !masm.oom();
 }
 
 // If an exception is thrown, simply pop all frames (since asm.js does not
 // contain try/catch). To do this:
 //  1. Restore 'sp' to it's value right after the PushRegsInMask in GenerateEntry.
--- a/js/src/jit/AsmJSLink.cpp
+++ b/js/src/jit/AsmJSLink.cpp
@@ -47,23 +47,39 @@ AsmJSFrameIterator::AsmJSFrameIterator(c
     module_ = &activation->module();
     sp_ = activation->exitSP();
 
 #if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)
     // For calls to Ion/C++ on x86/x64, the exitSP is the SP right before the call
     // to C++. Since the call instruction pushes the return address, we know
     // that the return address is 1 word below exitSP.
     returnAddress_ = *(uint8_t**)(sp_ - sizeof(void*));
-#else
+#elif defined(JS_CODEGEN_ARM)
     // For calls to Ion/C++ on ARM, the *caller* pushes the return address on
     // the stack. For Ion, this is just part of the ABI. For C++, the return
     // address is explicitly pushed before the call since we cannot expect the
     // callee to immediately push lr. This means that exitSP points to the
     // return address.
     returnAddress_ = *(uint8_t**)sp_;
+#elif defined(JS_CODEGEN_MIPS)
+    // On MIPS we have two cases. Exit to C++ will store return addres at
+    // sp + 16, While on exits to Ion, the return address will be stored at
+    // sp + 0. We indicate exits to ion by setting the lowest bit of stored sp.
+
+    // Check if this is the exit to Ion.
+    if (uint32_t(sp_) & 0x1) {
+        // Clear the low bit.
+        sp_ -= 0x1;
+        returnAddress_ = *(uint8_t**)sp_;
+    } else {
+        // This is exit to C++
+        returnAddress_ = *(uint8_t**)(sp_ + ShadowStackSpace);
+    }
+#else
+# error "Unknown architecture!"
 #endif
 
     settle();
 }
 
 struct GetCallSite
 {
     const AsmJSModule &module;
--- a/js/src/jit/AsmJSModule.cpp
+++ b/js/src/jit/AsmJSModule.cpp
@@ -308,17 +308,22 @@ void
 AsmJSModule::staticallyLink(ExclusiveContext *cx)
 {
     // Process staticLinkData_
 
     interruptExit_ = code_ + staticLinkData_.interruptExitOffset;
 
     for (size_t i = 0; i < staticLinkData_.relativeLinks.length(); i++) {
         RelativeLink link = staticLinkData_.relativeLinks[i];
-        *(void **)(code_ + link.patchAtOffset) = code_ + link.targetOffset;
+        uint8_t *patchAt = code_ + link.patchAtOffset;
+        uint8_t *target = code_ + link.targetOffset;
+        if (link.isRawPointerPatch())
+            *(uint8_t **)(patchAt) = target;
+        else
+            Assembler::patchInstructionImmediate(patchAt, PatchedImmPtr(target));
     }
 
     for (size_t i = 0; i < staticLinkData_.absoluteLinks.length(); i++) {
         AbsoluteLink link = staticLinkData_.absoluteLinks[i];
         Assembler::patchDataWithValueCheck(CodeLocationLabel(code_ + link.patchAt.offset()),
                                            PatchedImmPtr(AddressOf(link.target, cx)),
                                            PatchedImmPtr((void*)-1));
     }
@@ -1008,31 +1013,36 @@ AsmJSModule::codeIsProtected(JSRuntime *
 
 static bool
 GetCPUID(uint32_t *cpuId)
 {
     enum Arch {
         X86 = 0x1,
         X64 = 0x2,
         ARM = 0x3,
-        ARCH_BITS = 2
+        MIPS = 0x4,
+        ARCH_BITS = 3
     };
 
 #if defined(JS_CODEGEN_X86)
     JS_ASSERT(uint32_t(JSC::MacroAssembler::getSSEState()) <= (UINT32_MAX >> ARCH_BITS));
     *cpuId = X86 | (JSC::MacroAssembler::getSSEState() << ARCH_BITS);
     return true;
 #elif defined(JS_CODEGEN_X64)
     JS_ASSERT(uint32_t(JSC::MacroAssembler::getSSEState()) <= (UINT32_MAX >> ARCH_BITS));
     *cpuId = X64 | (JSC::MacroAssembler::getSSEState() << ARCH_BITS);
     return true;
 #elif defined(JS_CODEGEN_ARM)
     JS_ASSERT(GetARMFlags() <= (UINT32_MAX >> ARCH_BITS));
     *cpuId = ARM | (GetARMFlags() << ARCH_BITS);
     return true;
+#elif defined(JS_CODEGEN_MIPS)
+    JS_ASSERT(GetMIPSFlags() <= (UINT32_MAX >> ARCH_BITS));
+    *cpuId = MIPS | (GetMIPSFlags() << ARCH_BITS);
+    return true;
 #else
     return false;
 #endif
 }
 
 class MachineId
 {
     uint32_t cpuId_;
--- a/js/src/jit/AsmJSModule.h
+++ b/js/src/jit/AsmJSModule.h
@@ -365,16 +365,49 @@ class AsmJSModule
           : ProfiledFunction(copy.name, copy.pod.startCodeOffset, copy.pod.endCodeOffset),
             endInlineCodeOffset(copy.endInlineCodeOffset), blocks(mozilla::Move(copy.blocks))
         { }
     };
 #endif
 
     struct RelativeLink
     {
+        enum Kind
+        {
+            RawPointer,
+            CodeLabel,
+            InstructionImmediate
+        };
+
+        RelativeLink()
+        { }
+
+        RelativeLink(Kind kind)
+        {
+#if defined(JS_CODEGEN_MIPS)
+            kind_ = kind;
+#elif defined(JS_CODEGEN_ARM)
+            // On ARM, CodeLabels are only used to label raw pointers, so in
+            // all cases on ARM, a RelativePatch means patching a raw pointer.
+            JS_ASSERT(kind == CodeLabel || kind == RawPointer);
+#endif
+            // On X64 and X86, all RelativePatch-es are patched as raw pointers.
+        }
+
+        bool isRawPointerPatch() {
+#if defined(JS_CODEGEN_MIPS)
+            return kind_ == RawPointer;
+#else
+            return true;
+#endif
+        }
+
+#ifdef JS_CODEGEN_MIPS
+        Kind kind_;
+#endif
         uint32_t patchAtOffset;
         uint32_t targetOffset;
     };
 
     typedef Vector<RelativeLink, 0, SystemAllocPolicy> RelativeLinkVector;
 
     struct AbsoluteLink
     {
@@ -722,42 +755,43 @@ class AsmJSModule
         HeapPtrFunction fun;
     };
 
     // Global data section
     //
     // The global data section is placed after the executable code (i.e., at
     // offset codeBytes_) in the module's linear allocation. The global data
     // are laid out in this order:
-    //   0. a pointer/descriptor for the heap that was linked to the module
+    //   0. a pointer (padded up to 8 bytes to ensure double-alignment of
+    //      globals) for the heap that was linked to the module.
     //   1. global variable state (elements are sizeof(uint64_t))
     //   2. interleaved function-pointer tables and exits. These are allocated
     //      while type checking function bodies (as exits and uses of
     //      function-pointer tables are encountered).
     size_t offsetOfGlobalData() const {
         JS_ASSERT(code_);
         return pod.codeBytes_;
     }
     uint8_t *globalData() const {
         return code_ + offsetOfGlobalData();
     }
     size_t globalDataBytes() const {
-        return sizeof(void*) +
+        return sizeof(uint64_t) +
                pod.numGlobalVars_ * sizeof(uint64_t) +
                pod.funcPtrTableAndExitBytes_;
     }
     unsigned heapOffset() const {
         return 0;
     }
     uint8_t *&heapDatum() const {
         return *(uint8_t**)(globalData() + heapOffset());
     }
     unsigned globalVarIndexToGlobalDataOffset(unsigned i) const {
         JS_ASSERT(i < pod.numGlobalVars_);
-        return sizeof(void*) +
+        return sizeof(uint64_t) +
                i * sizeof(uint64_t);
     }
     void *globalVarIndexToGlobalDatum(unsigned i) const {
         return (void *)(globalData() + globalVarIndexToGlobalDataOffset(i));
     }
     uint8_t **globalDataOffsetToFuncPtrTable(unsigned globalDataOffset) const {
         JS_ASSERT(globalDataOffset < globalDataBytes());
         return (uint8_t **)(globalData() + globalDataOffset);
--- a/js/src/jit/AsmJSSignalHandlers.cpp
+++ b/js/src/jit/AsmJSSignalHandlers.cpp
@@ -81,16 +81,21 @@ using JS::GenericNaN;
 # define R12_sig(p) ((p)->uc_mcontext.gregs[REG_R12])
 # define R13_sig(p) ((p)->uc_mcontext.gregs[REG_R13])
 # define R14_sig(p) ((p)->uc_mcontext.gregs[REG_R14])
 # if defined(__linux__) && defined(__arm__)
 #  define R15_sig(p) ((p)->uc_mcontext.arm_pc)
 # else
 #  define R15_sig(p) ((p)->uc_mcontext.gregs[REG_R15])
 # endif
+# if defined(__linux__) && defined(__mips__)
+#  define EPC_sig(p) ((p)->uc_mcontext.pc)
+#  define RSP_sig(p) ((p)->uc_mcontext.gregs[29])
+#  define RFP_sig(p) ((p)->uc_mcontext.gregs[30])
+# endif
 #elif defined(__NetBSD__)
 # define XMM_sig(p,i) (((struct fxsave64 *)(p)->uc_mcontext.__fpregs)->fx_xmm[i])
 # define EIP_sig(p) ((p)->uc_mcontext.__gregs[_REG_EIP])
 # define RIP_sig(p) ((p)->uc_mcontext.__gregs[_REG_RIP])
 # define RAX_sig(p) ((p)->uc_mcontext.__gregs[_REG_RAX])
 # define RCX_sig(p) ((p)->uc_mcontext.__gregs[_REG_RCX])
 # define RDX_sig(p) ((p)->uc_mcontext.__gregs[_REG_RDX])
 # define RBX_sig(p) ((p)->uc_mcontext.__gregs[_REG_RBX])
@@ -277,16 +282,47 @@ typedef struct sigcontext mcontext_t;
 typedef struct ucontext {
     uint32_t uc_flags;
     struct ucontext* uc_link;
     stack_t uc_stack;
     mcontext_t uc_mcontext;
     // Other fields are not used so don't define them here.
 } ucontext_t;
 
+#  elif defined(__mips__)
+
+typedef struct {
+    uint32_t regmask;
+    uint32_t status;
+    uint64_t pc;
+    uint64_t gregs[32];
+    uint64_t fpregs[32];
+    uint32_t acx;
+    uint32_t fpc_csr;
+    uint32_t fpc_eir;
+    uint32_t used_math;
+    uint32_t dsp;
+    uint64_t mdhi;
+    uint64_t mdlo;
+    uint32_t hi1;
+    uint32_t lo1;
+    uint32_t hi2;
+    uint32_t lo2;
+    uint32_t hi3;
+    uint32_t lo3;
+} mcontext_t;
+
+typedef struct ucontext {
+    uint32_t uc_flags;
+    struct ucontext* uc_link;
+    stack_t uc_stack;
+    mcontext_t uc_mcontext;
+    // Other fields are not used so don't define them here.
+} ucontext_t;
+
 #  elif defined(__i386__)
 // x86 version for Android.
 typedef struct {
     uint32_t gregs[19];
     void* fpregs;
     uint32_t oldmask;
     uint32_t cr2;
 } mcontext_t;
@@ -321,16 +357,18 @@ static bool IsSignalHandlingBroken() { r
 #endif
 
 #if defined(JS_CPU_X64)
 # define PC_sig(p) RIP_sig(p)
 #elif defined(JS_CPU_X86)
 # define PC_sig(p) EIP_sig(p)
 #elif defined(JS_CPU_ARM)
 # define PC_sig(p) R15_sig(p)
+#elif defined(JS_CPU_MIPS)
+# define PC_sig(p) EPC_sig(p)
 #endif
 
 static bool
 HandleSimulatorInterrupt(JSRuntime *rt, AsmJSActivation *activation, void *faultingAddress)
 {
     // If the ARM simulator is enabled, the pc is in the simulator C++ code and
     // not in the generated code, so we check the simulator's pc manually. Also
     // note that we can't simply use simulator->set_pc() here because the
@@ -350,17 +388,16 @@ HandleSimulatorInterrupt(JSRuntime *rt, 
 #endif
     return false;
 }
 
 #if !defined(XP_MACOSX)
 static uint8_t **
 ContextToPC(CONTEXT *context)
 {
-    JS_STATIC_ASSERT(sizeof(PC_sig(context)) == sizeof(void*));
     return reinterpret_cast<uint8_t**>(&PC_sig(context));
 }
 
 # if defined(JS_CODEGEN_X64)
 static void
 SetRegisterToCoercedUndefined(CONTEXT *context, bool isFloat32, AnyRegister reg)
 {
     if (reg.isFloat()) {
--- a/js/src/jit/BaselineIC.cpp
+++ b/js/src/jit/BaselineIC.cpp
@@ -6060,28 +6060,16 @@ TryAttachLengthStub(JSContext *cx, JSScr
         if (!newStub)
             return false;
 
         *attached = true;
         stub->addNewStub(newStub);
         return true;
     }
 
-    if (obj->is<TypedArrayObject>() && res.isInt32()) {
-        IonSpew(IonSpew_BaselineIC, "  Generating GetProp(TypedArray.length) stub");
-        ICGetProp_TypedArrayLength::Compiler compiler(cx);
-        ICStub *newStub = compiler.getStub(compiler.getStubSpace(script));
-        if (!newStub)
-            return false;
-
-        *attached = true;
-        stub->addNewStub(newStub);
-        return true;
-    }
-
     if (obj->is<ArgumentsObject>() && res.isInt32()) {
         IonSpew(IonSpew_BaselineIC, "  Generating GetProp(ArgsObj.length %s) stub",
                 obj->is<StrictArgumentsObject>() ? "Strict" : "Normal");
         ICGetProp_ArgumentsLength::Which which = ICGetProp_ArgumentsLength::Normal;
         if (obj->is<StrictArgumentsObject>())
             which = ICGetProp_ArgumentsLength::Strict;
         ICGetProp_ArgumentsLength::Compiler compiler(cx, which);
         ICStub *newStub = compiler.getStub(compiler.getStubSpace(script));
@@ -6510,45 +6498,16 @@ ICGetProp_ArrayLength::Compiler::generat
 
     // Failure case - jump to next stub
     masm.bind(&failure);
     EmitStubGuardFailure(masm);
     return true;
 }
 
 bool
-ICGetProp_TypedArrayLength::Compiler::generateStubCode(MacroAssembler &masm)
-{
-    Label failure;
-    masm.branchTestObject(Assembler::NotEqual, R0, &failure);
-
-    Register scratch = R1.scratchReg();
-
-    // Unbox R0.
-    Register obj = masm.extractObject(R0, ExtractTemp0);
-
-    // Implement the negated version of JSObject::isTypedArray predicate.
-    masm.loadObjClass(obj, scratch);
-    masm.branchPtr(Assembler::Below, scratch, ImmPtr(&TypedArrayObject::classes[0]),
-                   &failure);
-    masm.branchPtr(Assembler::AboveOrEqual, scratch,
-                   ImmPtr(&TypedArrayObject::classes[ScalarTypeDescr::TYPE_MAX]),
-                   &failure);
-
-    // Load length from fixed slot.
-    masm.loadValue(Address(obj, TypedArrayObject::lengthOffset()), R0);
-    EmitReturnFromIC(masm);
-
-    // Failure case - jump to next stub
-    masm.bind(&failure);
-    EmitStubGuardFailure(masm);
-    return true;
-}
-
-bool
 ICGetProp_StringLength::Compiler::generateStubCode(MacroAssembler &masm)
 {
     Label failure;
     masm.branchTestString(Assembler::NotEqual, R0, &failure);
 
     // Unbox string and load its length.
     Register string = masm.extractString(R0, ExtractTemp0);
     masm.loadStringLength(string, string);
--- a/js/src/jit/BaselineIC.h
+++ b/js/src/jit/BaselineIC.h
@@ -406,17 +406,16 @@ class ICEntry
                                 \
     _(BindName_Fallback)        \
                                 \
     _(GetIntrinsic_Fallback)    \
     _(GetIntrinsic_Constant)    \
                                 \
     _(GetProp_Fallback)         \
     _(GetProp_ArrayLength)      \
-    _(GetProp_TypedArrayLength) \
     _(GetProp_Primitive)        \
     _(GetProp_StringLength)     \
     _(GetProp_Native)           \
     _(GetProp_NativePrototype)  \
     _(GetProp_CallScripted)     \
     _(GetProp_CallNative)       \
     _(GetProp_CallNativePrototype)\
     _(GetProp_CallDOMProxyNative)\
@@ -4155,46 +4154,16 @@ class ICGetProp_ArrayLength : public ICS
         {}
 
         ICStub *getStub(ICStubSpace *space) {
             return ICGetProp_ArrayLength::New(space, getStubCode());
         }
     };
 };
 
-// Stub for accessing a typed array's length.
-class ICGetProp_TypedArrayLength : public ICStub
-{
-    friend class ICStubSpace;
-
-    explicit ICGetProp_TypedArrayLength(JitCode *stubCode)
-      : ICStub(GetProp_TypedArrayLength, stubCode)
-    {}
-
-  public:
-    static inline ICGetProp_TypedArrayLength *New(ICStubSpace *space, JitCode *code) {
-        if (!code)
-            return nullptr;
-        return space->allocate<ICGetProp_TypedArrayLength>(code);
-    }
-
-    class Compiler : public ICStubCompiler {
-        bool generateStubCode(MacroAssembler &masm);
-
-      public:
-        explicit Compiler(JSContext *cx)
-          : ICStubCompiler(cx, ICStub::GetProp_TypedArrayLength)
-        {}
-
-        ICStub *getStub(ICStubSpace *space) {
-            return ICGetProp_TypedArrayLength::New(space, getStubCode());
-        }
-    };
-};
-
 // Stub for accessing a property on a primitive's prototype.
 class ICGetProp_Primitive : public ICMonitoredStub
 {
     friend class ICStubSpace;
 
   protected: // Protected to silence Clang warning.
     // Shape of String.prototype/Number.prototype to check for.
     HeapPtrShape protoShape_;
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -3480,17 +3480,17 @@ CodeGenerator::generateBody()
 
             if (!callTraceLIR(i, *iter))
                 return false;
 
             if (!iter->accept(this))
                 return false;
 
 #ifdef DEBUG
-            if (!emitDebugResultChecks(*iter))
+            if (!counts && !emitDebugResultChecks(*iter))
                 return false;
 #endif
         }
         if (masm.oom())
             return false;
 
 #if defined(JS_ION_PERF)
         perfSpewer->endBasicBlock(masm);
--- a/js/src/jit/IonBuilder.cpp
+++ b/js/src/jit/IonBuilder.cpp
@@ -6839,17 +6839,17 @@ IonBuilder::checkTypedObjectIndexInBound
     MDefinition *length;
     if (objDescrs.hasKnownArrayLength(&lenOfAll)) {
         length = constantInt(lenOfAll);
 
         // If we are not loading the length from the object itself,
         // then we still need to check if the object was neutered.
         *canBeNeutered = true;
     } else {
-        MInstruction *lengthValue = MLoadFixedSlot::New(alloc(), obj, JS_TYPEDOBJ_SLOT_LENGTH);
+        MInstruction *lengthValue = MLoadFixedSlot::New(alloc(), obj, JS_BUFVIEW_SLOT_LENGTH);
         current->add(lengthValue);
 
         MInstruction *length32 = MTruncateToInt32::New(alloc(), lengthValue);
         current->add(length32);
 
         length = length32;
 
         // If we are loading the length from the object itself,
@@ -8162,23 +8162,16 @@ IonBuilder::jsop_length_fastPath()
             current->add(elements);
 
             // Read length.
             MArrayLength *length = MArrayLength::New(alloc(), elements);
             current->add(length);
             current->push(length);
             return true;
         }
-
-        if (objTypes && objTypes->getTypedArrayType() != ScalarTypeDescr::TYPE_MAX) {
-            current->pop();
-            MInstruction *length = addTypedArrayLength(obj);
-            current->push(length);
-            return true;
-        }
     }
 
     return false;
 }
 
 bool
 IonBuilder::jsop_arguments()
 {
@@ -8886,16 +8879,29 @@ IonBuilder::getPropTryCommonGetter(bool 
     pushConstant(ObjectValue(*commonGetter));
 
     current->push(obj);
 
     CallInfo callInfo(alloc(), false);
     if (!callInfo.init(current, 0))
         return false;
 
+    if (commonGetter->isNative()) {
+        InliningStatus status = inlineNativeGetter(callInfo, commonGetter);
+        switch (status) {
+          case InliningStatus_Error:
+            return false;
+          case InliningStatus_NotInlined:
+            break;
+          case InliningStatus_Inlined:
+            *emitted = true;
+            return true;
+        }
+    }
+
     // Inline if we can, otherwise, forget it and just generate a call.
     bool inlineable = false;
     if (commonGetter->isInterpreted()) {
         InliningDecision decision = makeInliningDecision(commonGetter, callInfo);
         switch (decision) {
           case InliningDecision_Error:
             return false;
           case InliningDecision_DontInline:
--- a/js/src/jit/IonBuilder.h
+++ b/js/src/jit/IonBuilder.h
@@ -748,16 +748,17 @@ class IonBuilder : public MIRGenerator
     InliningStatus inlineBailout(CallInfo &callInfo);
     InliningStatus inlineAssertFloat32(CallInfo &callInfo);
 
     // Bind function.
     InliningStatus inlineBoundFunction(CallInfo &callInfo, JSFunction *target);
 
     // Main inlining functions
     InliningStatus inlineNativeCall(CallInfo &callInfo, JSFunction *target);
+    InliningStatus inlineNativeGetter(CallInfo &callInfo, JSFunction *target);
     bool inlineScriptedCall(CallInfo &callInfo, JSFunction *target);
     InliningStatus inlineSingleCall(CallInfo &callInfo, JSFunction *target);
 
     // Call functions
     InliningStatus inlineCallsite(ObjectVector &targets, ObjectVector &originals,
                                   bool lambda, CallInfo &callInfo);
     bool inlineCalls(CallInfo &callInfo, ObjectVector &targets, ObjectVector &originals,
                      BoolVector &choiceSet, MGetPropertyCache *maybeCache);
--- a/js/src/jit/LIR-Common.h
+++ b/js/src/jit/LIR-Common.h
@@ -3851,17 +3851,18 @@ class LInArray : public LInstructionHelp
         return getOperand(2);
     }
     const LAllocation *object() {
         return getOperand(3);
     }
 };
 
 
-// Load a value from a dense array's elements vector. Bail out if it's the hole value.
+// Load a value from an array's elements vector, loading |undefined| if we hit a hole.
+// Bail out if we get a negative index.
 class LLoadElementHole : public LInstructionHelper<BOX_PIECES, 3, 0>
 {
   public:
     LIR_HEADER(LoadElementHole)
 
     LLoadElementHole(const LAllocation &elements, const LAllocation &index, const LAllocation &initLength) {
         setOperand(0, elements);
         setOperand(1, index);
--- a/js/src/jit/LIR.h
+++ b/js/src/jit/LIR.h
@@ -1387,17 +1387,16 @@ class LSafepoint : public TempObject
         return osiCallPointOffset_;
     }
     void setOsiCallPointOffset(uint32_t osiCallPointOffset) {
         JS_ASSERT(!osiCallPointOffset_);
         osiCallPointOffset_ = osiCallPointOffset;
     }
     void fixupOffset(MacroAssembler *masm) {
         osiCallPointOffset_ = masm->actualOffset(osiCallPointOffset_);
-        safepointOffset_ = masm->actualOffset(safepointOffset_);
     }
 };
 
 class LInstruction::InputIterator
 {
   private:
     LInstruction &ins_;
     size_t idx_;
--- a/js/src/jit/MCallOptimize.cpp
+++ b/js/src/jit/MCallOptimize.cpp
@@ -201,16 +201,45 @@ IonBuilder::inlineNativeCall(CallInfo &c
 
     // Bound function
     if (native == js::CallOrConstructBoundFunction)
         return inlineBoundFunction(callInfo, target);
 
     return InliningStatus_NotInlined;
 }
 
+IonBuilder::InliningStatus
+IonBuilder::inlineNativeGetter(CallInfo &callInfo, JSFunction *target)
+{
+    JS_ASSERT(target->isNative());
+    JSNative native = target->native();
+
+    if (!optimizationInfo().inlineNative())
+        return InliningStatus_NotInlined;
+
+    types::TemporaryTypeSet *thisTypes = callInfo.thisArg()->resultTypeSet();
+    JS_ASSERT(callInfo.argc() == 0);
+
+    // Try to optimize typed array lengths. There is one getter for each
+    // typed array prototype, and make sure we are accessing the right one
+    // for the type of the instance object.
+    if (thisTypes) {
+        ScalarTypeDescr::Type type = (ScalarTypeDescr::Type) thisTypes->getTypedArrayType();
+        if (type != ScalarTypeDescr::TYPE_MAX &&
+            TypedArrayObject::isOriginalLengthGetter(type, native))
+        {
+            MInstruction *length = addTypedArrayLength(callInfo.thisArg());
+            current->push(length);
+            return InliningStatus_Inlined;
+        }
+    }
+
+    return InliningStatus_NotInlined;
+}
+
 types::TemporaryTypeSet *
 IonBuilder::getInlineReturnTypeSet()
 {
     return bytecodeTypes(pc);
 }
 
 MIRType
 IonBuilder::getInlineReturnType()
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -6637,18 +6637,17 @@ class MLoadTypedArrayElement
 
     void printOpcode(FILE *fp) const;
 
     void computeRange(TempAllocator &alloc);
 
     bool canProduceFloat32() const { return arrayType_ == ScalarTypeDescr::TYPE_FLOAT32; }
 };
 
-// Load a value from a typed array. Out-of-bounds accesses are handled using
-// a VM call.
+// Load a value from a typed array. Out-of-bounds accesses are handled in-line.
 class MLoadTypedArrayElementHole
   : public MBinaryInstruction,
     public SingleObjectPolicy
 {
     int arrayType_;
     bool allowDouble_;
 
     MLoadTypedArrayElementHole(MDefinition *object, MDefinition *index, int arrayType, bool allowDouble)
--- a/js/src/jit/arm/Architecture-arm.cpp
+++ b/js/src/jit/arm/Architecture-arm.cpp
@@ -10,20 +10,20 @@
 #include <elf.h>
 #endif
 
 #include <fcntl.h>
 #include <unistd.h>
 
 #include "jit/arm/Assembler-arm.h"
 
-#define HWCAP_USE_HARDFP_ABI (1 << 28)
+#define HWCAP_USE_HARDFP_ABI (1 << 27)
 
 #if !(defined(ANDROID) || defined(MOZ_B2G)) && !defined(JS_ARM_SIMULATOR)
-#define HWCAP_ARMv7 (1 << 29)
+#define HWCAP_ARMv7 (1 << 28)
 #include <asm/hwcap.h>
 #else
 #define HWCAP_VFP      (1<<0)
 #define HWCAP_VFPv3    (1<<1)
 #define HWCAP_VFPv3D16 (1<<2)
 #define HWCAP_VFPv4    (1<<3)
 #define HWCAP_IDIVA    (1<<4)
 #define HWCAP_IDIVT    (1<<5)
--- a/js/src/jit/arm/Assembler-arm.h
+++ b/js/src/jit/arm/Assembler-arm.h
@@ -1793,29 +1793,38 @@ class Assembler : public AssemblerShared
     static uint32_t patchWrite_NearCallSize();
     static uint32_t nopSize() { return 4; }
     static void patchWrite_NearCall(CodeLocationLabel start, CodeLocationLabel toCall);
     static void patchDataWithValueCheck(CodeLocationLabel label, PatchedImmPtr newValue,
                                         PatchedImmPtr expectedValue);
     static void patchDataWithValueCheck(CodeLocationLabel label, ImmPtr newValue,
                                         ImmPtr expectedValue);
     static void patchWrite_Imm32(CodeLocationLabel label, Imm32 imm);
+
+    static void patchInstructionImmediate(uint8_t *code, PatchedImmPtr imm) {
+        MOZ_ASSUME_UNREACHABLE("Unused.");
+    }
+
     static uint32_t alignDoubleArg(uint32_t offset) {
         return (offset+1)&~1;
     }
     static uint8_t *nextInstruction(uint8_t *instruction, uint32_t *count = nullptr);
     // Toggle a jmp or cmp emitted by toggledJump().
 
     static void ToggleToJmp(CodeLocationLabel inst_);
     static void ToggleToCmp(CodeLocationLabel inst_);
 
     static void ToggleCall(CodeLocationLabel inst_, bool enabled);
 
     static void updateBoundsCheck(uint32_t logHeapSize, Instruction *inst);
     void processCodeLabels(uint8_t *rawCode);
+    static int32_t extractCodeLabelOffset(uint8_t *code) {
+        return *(uintptr_t *)code;
+    }
+
     bool bailed() {
         return m_buffer.bail();
     }
 }; // Assembler
 
 // An Instruction is a structure for both encoding and decoding any and all ARM instructions.
 // many classes have not been implemented thusfar.
 class Instruction
--- a/js/src/jit/arm/MacroAssembler-arm.cpp
+++ b/js/src/jit/arm/MacroAssembler-arm.cpp
@@ -3871,17 +3871,17 @@ MacroAssemblerARMCompat::callWithABIPre(
 {
     JS_ASSERT(inCall_);
 
     *stackAdjust = ((usedIntSlots_ > NumIntArgRegs) ? usedIntSlots_ - NumIntArgRegs : 0) * sizeof(intptr_t);
 #if defined(JS_CODEGEN_ARM_HARDFP) || defined(JS_ARM_SIMULATOR)
     if (useHardFpABI())
         *stackAdjust += 2*((usedFloatSlots_ > NumFloatArgRegs) ? usedFloatSlots_ - NumFloatArgRegs : 0) * sizeof(intptr_t);
 #endif
-    uint32_t alignmentAtPrologue = (callFromAsmJS) ? AlignmentAtAsmJSPrologue : 0;
+    uint32_t alignmentAtPrologue = callFromAsmJS ? AlignmentAtAsmJSPrologue : 0;
 
     if (!dynamicAlignment_) {
         *stackAdjust += ComputeByteAlignment(framePushed_ + *stackAdjust + alignmentAtPrologue,
                                              StackAlignment);
     } else {
         // sizeof(intptr_t) account for the saved stack pointer pushed by setupUnalignedABICall
         *stackAdjust += ComputeByteAlignment(*stackAdjust + sizeof(intptr_t), StackAlignment);
     }
--- a/js/src/jit/arm/MacroAssembler-arm.h
+++ b/js/src/jit/arm/MacroAssembler-arm.h
@@ -973,25 +973,27 @@ class MacroAssemblerARMCompat : public M
         Condition c = testDoubleTruthy(truthy, reg);
         ma_b(label, c);
     }
     void branchTestStringTruthy(bool truthy, const ValueOperand &value, Label *label) {
         Condition c = testStringTruthy(truthy, value);
         ma_b(label, c);
     }
     void branchTest32(Condition cond, Register lhs, Register rhs, Label *label) {
+        JS_ASSERT(cond == Zero || cond == NonZero || cond == Signed || cond == NotSigned);
         // x86 likes test foo, foo rather than cmp foo, #0.
         // Convert the former into the latter.
         if (lhs == rhs && (cond == Zero || cond == NonZero))
             ma_cmp(lhs, Imm32(0));
         else
             ma_tst(lhs, rhs);
         ma_b(label, cond);
     }
     void branchTest32(Condition cond, Register lhs, Imm32 imm, Label *label) {
+        JS_ASSERT(cond == Zero || cond == NonZero || cond == Signed || cond == NotSigned);
         ma_tst(lhs, imm);
         ma_b(label, cond);
     }
     void branchTest32(Condition cond, const Address &address, Imm32 imm, Label *label) {
         ma_ldr(Operand(address.base, address.offset), ScratchRegister);
         branchTest32(cond, ScratchRegister, imm, label);
     }
     void branchTest32(Condition cond, AbsoluteAddress address, Imm32 imm, Label *label) {
--- a/js/src/jit/mips/Architecture-mips.h
+++ b/js/src/jit/mips/Architecture-mips.h
@@ -23,17 +23,17 @@
 #else
 #error "Unsupported ABI"
 #endif
 
 namespace js {
 namespace jit {
 
 // Shadow stack space is not required on MIPS.
-static const uint32_t ShadowStackSpace = 0;
+static const uint32_t ShadowStackSpace = 4 * sizeof(uintptr_t);
 
 // These offsets are specific to nunboxing, and capture offsets into the
 // components of a js::Value.
 // Size of MIPS32 general purpose registers is 32 bits.
 static const int32_t NUNBOX32_TYPE_OFFSET = 4;
 static const int32_t NUNBOX32_PAYLOAD_OFFSET = 0;
 
 // Size of each bailout table entry.
@@ -146,25 +146,28 @@ class Registers
         (1 << Registers::t1) |
         (1 << Registers::t2) |
         (1 << Registers::t3) |
         (1 << Registers::t4) |
         (1 << Registers::t5) |
         (1 << Registers::t6) |
         (1 << Registers::t7);
 
+    // We use this constant to save registers when entering functions. This
+    // is why $ra is added here even though it is not "Non Volatile".
     static const uint32_t NonVolatileMask =
         (1 << Registers::s0) |
         (1 << Registers::s1) |
         (1 << Registers::s2) |
         (1 << Registers::s3) |
         (1 << Registers::s4) |
         (1 << Registers::s5) |
         (1 << Registers::s6) |
-        (1 << Registers::s7);
+        (1 << Registers::s7) |
+        (1 << Registers::ra);
 
     static const uint32_t WrapperMask =
         VolatileMask |         // = arguments
         (1 << Registers::t0) | // = outReg
         (1 << Registers::t1);  // = argBase
 
     static const uint32_t NonAllocatableMask =
         (1 << Registers::zero) |
--- a/js/src/jit/mips/Assembler-mips.cpp
+++ b/js/src/jit/mips/Assembler-mips.cpp
@@ -25,18 +25,49 @@ ABIArgGenerator::ABIArgGenerator()
   : usedArgSlots_(0),
     firstArgFloat(false),
     current_()
 {}
 
 ABIArg
 ABIArgGenerator::next(MIRType type)
 {
-    MOZ_ASSUME_UNREACHABLE("NYI");
-    return ABIArg();
+    switch (type) {
+      case MIRType_Int32:
+      case MIRType_Pointer:
+        Register destReg;
+        if (GetIntArgReg(usedArgSlots_, &destReg))
+            current_ = ABIArg(destReg);
+        else
+            current_ = ABIArg(usedArgSlots_ * sizeof(intptr_t));
+        usedArgSlots_++;
+        break;
+      case MIRType_Float32:
+      case MIRType_Double:
+        if (!usedArgSlots_) {
+            current_ = ABIArg(f12);
+            usedArgSlots_ += 2;
+            firstArgFloat = true;
+        } else if (usedArgSlots_ <= 2) {
+            // NOTE: We will use f14 always. This is not compatible with
+            // system ABI. We will have to introduce some infrastructure
+            // changes if we have to use system ABI here.
+            current_ = ABIArg(f14);
+            usedArgSlots_ = 4;
+        } else {
+            usedArgSlots_ += usedArgSlots_ % 2;
+            current_ = ABIArg(usedArgSlots_ * sizeof(intptr_t));
+            usedArgSlots_ += 2;
+        }
+        break;
+      default:
+        MOZ_ASSUME_UNREACHABLE("Unexpected argument type");
+    }
+    return current_;
+
 }
 const Register ABIArgGenerator::NonArgReturnVolatileReg0 = t0;
 const Register ABIArgGenerator::NonArgReturnVolatileReg1 = t1;
 
 // Encode a standard register when it is being used as rd, the rs, and
 // an extra register(rt). These should never be called with an InvalidReg.
 uint32_t
 js::jit::RS(Register r)
@@ -293,16 +324,22 @@ void
 Assembler::processCodeLabels(uint8_t *rawCode)
 {
     for (size_t i = 0; i < codeLabels_.length(); i++) {
         CodeLabel label = codeLabels_[i];
         Bind(rawCode, label.dest(), rawCode + actualOffset(label.src()->offset()));
     }
 }
 
+int32_t
+Assembler::extractCodeLabelOffset(uint8_t *code) {
+    InstImm *inst = (InstImm *)code;
+    return Assembler::extractLuiOriValue(inst, inst->next());
+}
+
 void
 Assembler::Bind(uint8_t *rawCode, AbsoluteLabel *label, const void *address)
 {
     if (label->used()) {
         int32_t src = label->offset();
         do {
             Instruction *inst = (Instruction *) (rawCode + src);
             uint32_t next = Assembler::extractLuiOriValue(inst, inst->next());
@@ -1073,16 +1110,22 @@ Assembler::as_abss(FloatRegister fd, Flo
 
 BufferOffset
 Assembler::as_absd(FloatRegister fd, FloatRegister fs)
 {
     return writeInst(InstReg(op_cop1, rs_d, zero, fs, fd, ff_abs_fmt).encode());
 }
 
 BufferOffset
+Assembler::as_negs(FloatRegister fd, FloatRegister fs)
+{
+    return writeInst(InstReg(op_cop1, rs_s, zero, fs, fd, ff_neg_fmt).encode());
+}
+
+BufferOffset
 Assembler::as_negd(FloatRegister fd, FloatRegister fs)
 {
     return writeInst(InstReg(op_cop1, rs_d, zero, fs, fd, ff_neg_fmt).encode());
 }
 
 BufferOffset
 Assembler::as_muls(FloatRegister fd, FloatRegister fs, FloatRegister ft)
 {
@@ -1210,38 +1253,43 @@ Assembler::bind(InstImm *inst, uint32_t 
 
     // If encoded offset is 4, then the jump must be short
     if (BOffImm16(inst[0]).decode() == 4) {
         MOZ_ASSERT(BOffImm16::isInRange(offset));
         inst[0].setBOffImm16(BOffImm16(offset));
         inst[1].makeNop();
         return;
     }
+
+    // Generate the long jump for calls because return address has to be the
+    // address after the reserved block.
+    if (inst[0].encode() == inst_bgezal.encode()) {
+        addLongJump(BufferOffset(branch));
+        writeLuiOriInstructions(inst, &inst[1], ScratchRegister, target);
+        inst[2] = InstReg(op_special, ScratchRegister, zero, ra, ff_jalr).encode();
+        // There is 1 nop after this.
+        return;
+    }
+
     if (BOffImm16::isInRange(offset)) {
         bool conditional = (inst[0].encode() != inst_bgezal.encode() &&
                             inst[0].encode() != inst_beq.encode());
 
         inst[0].setBOffImm16(BOffImm16(offset));
         inst[1].makeNop();
 
         // Skip the trailing nops in conditional branches.
         if (conditional) {
             inst[2] = InstImm(op_regimm, zero, rt_bgez, BOffImm16(3 * sizeof(void *))).encode();
             // There are 2 nops after this
         }
         return;
     }
 
-    if (inst[0].encode() == inst_bgezal.encode()) {
-        // Handle long call.
-        addLongJump(BufferOffset(branch));
-        writeLuiOriInstructions(inst, &inst[1], ScratchRegister, target);
-        inst[2] = InstReg(op_special, ScratchRegister, zero, ra, ff_jalr).encode();
-        // There is 1 nop after this.
-    } else if (inst[0].encode() == inst_beq.encode()) {
+    if (inst[0].encode() == inst_beq.encode()) {
         // Handle long unconditional jump.
         addLongJump(BufferOffset(branch));
         writeLuiOriInstructions(inst, &inst[1], ScratchRegister, target);
         inst[2] = InstReg(op_special, ScratchRegister, zero, zero, ff_jr).encode();
         // There is 1 nop after this.
     } else {
         // Handle long conditional jump.
         inst[0] = invertBranch(inst[0], BOffImm16(5 * sizeof(void *)));
@@ -1403,16 +1451,23 @@ Assembler::patchWrite_Imm32(CodeLocation
 {
     // Raw is going to be the return address.
     uint32_t *raw = (uint32_t*)label.raw();
     // Overwrite the 4 bytes before the return address, which will
     // end up being the call instruction.
     *(raw - 1) = imm.value;
 }
 
+void
+Assembler::patchInstructionImmediate(uint8_t *code, PatchedImmPtr imm)
+{
+    InstImm *inst = (InstImm *)code;
+    Assembler::updateLuiOriValue(inst, inst->next(), (uint32_t)imm.value);
+}
+
 uint8_t *
 Assembler::nextInstruction(uint8_t *inst_, uint32_t *count)
 {
     Instruction *inst = reinterpret_cast<Instruction*>(inst_);
     if (count != nullptr)
         *count += sizeof(Instruction);
     return reinterpret_cast<uint8_t*>(inst->next());
 }
@@ -1520,10 +1575,14 @@ Assembler::ToggleCall(CodeLocationLabel 
         *i2 = nop;
     }
 
     AutoFlushICache::flush(uintptr_t(i2), 4);
 }
 
 void Assembler::updateBoundsCheck(uint32_t heapSize, Instruction *inst)
 {
-    MOZ_ASSUME_UNREACHABLE("NYI");
+    InstImm *i0 = (InstImm *) inst;
+    InstImm *i1 = (InstImm *) i0->next();
+
+    // Replace with new value
+    Assembler::updateLuiOriValue(i0, i1, heapSize);
 }
--- a/js/src/jit/mips/Assembler-mips.h
+++ b/js/src/jit/mips/Assembler-mips.h
@@ -84,17 +84,17 @@ class ABIArgGenerator
 
   public:
     ABIArgGenerator();
     ABIArg next(MIRType argType);
     ABIArg &current() { return current_; }
 
     uint32_t stackBytesConsumedSoFar() const {
         if (usedArgSlots_ <= 4)
-            return 4 * sizeof(intptr_t);
+            return ShadowStackSpace;
 
         return usedArgSlots_ * sizeof(intptr_t);
     }
 
     static const Register NonArgReturnVolatileReg0;
     static const Register NonArgReturnVolatileReg1;
 };
 
@@ -109,16 +109,31 @@ static MOZ_CONSTEXPR_VAR Register StackP
 static MOZ_CONSTEXPR_VAR Register FramePointer = InvalidReg;
 static MOZ_CONSTEXPR_VAR Register ReturnReg = v0;
 static MOZ_CONSTEXPR_VAR FloatRegister ReturnFloatReg = { FloatRegisters::f0 };
 static MOZ_CONSTEXPR_VAR FloatRegister ScratchFloatReg = { FloatRegisters::f18 };
 static MOZ_CONSTEXPR_VAR FloatRegister SecondScratchFloatReg = { FloatRegisters::f16 };
 
 static MOZ_CONSTEXPR_VAR FloatRegister NANReg = { FloatRegisters::f30 };
 
+// Registers used in the GenerateFFIIonExit Enable Activation block.
+static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegCallee = t0;
+static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegE0 = a0;
+static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegE1 = a1;
+static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegE2 = a2;
+static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegE3 = a3;
+
+// Registers used in the GenerateFFIIonExit Disable Activation block.
+// None of these may be the second scratch register (t8).
+static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegReturnData = JSReturnReg_Data;
+static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegReturnType = JSReturnReg_Type;
+static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegD0 = a0;
+static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegD1 = a1;
+static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegD2 = a2;
+
 static MOZ_CONSTEXPR_VAR FloatRegister f0  = {FloatRegisters::f0};
 static MOZ_CONSTEXPR_VAR FloatRegister f2  = {FloatRegisters::f2};
 static MOZ_CONSTEXPR_VAR FloatRegister f4  = {FloatRegisters::f4};
 static MOZ_CONSTEXPR_VAR FloatRegister f6  = {FloatRegisters::f6};
 static MOZ_CONSTEXPR_VAR FloatRegister f8  = {FloatRegisters::f8};
 static MOZ_CONSTEXPR_VAR FloatRegister f10 = {FloatRegisters::f10};
 static MOZ_CONSTEXPR_VAR FloatRegister f12 = {FloatRegisters::f12};
 static MOZ_CONSTEXPR_VAR FloatRegister f14 = {FloatRegisters::f14};
@@ -133,18 +148,17 @@ static MOZ_CONSTEXPR_VAR FloatRegister f
 
 // MIPS CPUs can only load multibyte data that is "naturally"
 // four-byte-aligned, sp register should be eight-byte-aligned.
 static const uint32_t StackAlignment = 8;
 static const uint32_t CodeAlignment = 4;
 static const bool StackKeptAligned = true;
 // NativeFrameSize is the size of return adress on stack in AsmJS functions.
 static const uint32_t NativeFrameSize = sizeof(void*);
-static const uint32_t AlignmentAtAsmJSPrologue = 0;
-static const uint32_t AlignmentMidPrologue = NativeFrameSize;
+static const uint32_t AlignmentAtAsmJSPrologue = sizeof(void*);
 
 static const Scale ScalePointer = TimesFour;
 
 // MIPS instruction types
 //                +---------------------------------------------------------------+
 //                |    6      |    5    |    5    |    5    |    5    |    6      |
 //                +---------------------------------------------------------------+
 // Register type  |  Opcode   |    Rs   |    Rt   |    Rd   |    Sa   | Function  |
@@ -920,16 +934,17 @@ class Assembler : public AssemblerShared
     // FP arithmetic instructions
     BufferOffset as_adds(FloatRegister fd, FloatRegister fs, FloatRegister ft);
     BufferOffset as_addd(FloatRegister fd, FloatRegister fs, FloatRegister ft);
     BufferOffset as_subs(FloatRegister fd, FloatRegister fs, FloatRegister ft);
     BufferOffset as_subd(FloatRegister fd, FloatRegister fs, FloatRegister ft);
 
     BufferOffset as_abss(FloatRegister fd, FloatRegister fs);
     BufferOffset as_absd(FloatRegister fd, FloatRegister fs);
+    BufferOffset as_negs(FloatRegister fd, FloatRegister fs);
     BufferOffset as_negd(FloatRegister fd, FloatRegister fs);
 
     BufferOffset as_muls(FloatRegister fd, FloatRegister fs, FloatRegister ft);
     BufferOffset as_muld(FloatRegister fd, FloatRegister fs, FloatRegister ft);
     BufferOffset as_divs(FloatRegister fd, FloatRegister fs, FloatRegister ft);
     BufferOffset as_divd(FloatRegister fd, FloatRegister fs, FloatRegister ft);
     BufferOffset as_sqrts(FloatRegister fd, FloatRegister fs);
     BufferOffset as_sqrtd(FloatRegister fd, FloatRegister fs);
@@ -1012,29 +1027,33 @@ class Assembler : public AssemblerShared
                                         Register reg, uint32_t value);
 
     static void patchWrite_NearCall(CodeLocationLabel start, CodeLocationLabel toCall);
     static void patchDataWithValueCheck(CodeLocationLabel label, PatchedImmPtr newValue,
                                         PatchedImmPtr expectedValue);
     static void patchDataWithValueCheck(CodeLocationLabel label, ImmPtr newValue,
                                         ImmPtr expectedValue);
     static void patchWrite_Imm32(CodeLocationLabel label, Imm32 imm);
+
+    static void patchInstructionImmediate(uint8_t *code, PatchedImmPtr imm);
+
     static uint32_t alignDoubleArg(uint32_t offset) {
         return (offset + 1U) &~ 1U;
     }
 
     static uint8_t *nextInstruction(uint8_t *instruction, uint32_t *count = nullptr);
 
     static void ToggleToJmp(CodeLocationLabel inst_);
     static void ToggleToCmp(CodeLocationLabel inst_);
 
     static void ToggleCall(CodeLocationLabel inst_, bool enabled);
 
     static void updateBoundsCheck(uint32_t logHeapSize, Instruction *inst);
     void processCodeLabels(uint8_t *rawCode);
+    static int32_t extractCodeLabelOffset(uint8_t *code);
 
     bool bailed() {
         return m_buffer.bail();
     }
 }; // Assembler
 
 // sll zero, zero, 0
 const uint32_t NopInst = 0x00000000;
--- a/js/src/jit/mips/CodeGenerator-mips.cpp
+++ b/js/src/jit/mips/CodeGenerator-mips.cpp
@@ -35,26 +35,43 @@ using JS::GenericNaN;
 CodeGeneratorMIPS::CodeGeneratorMIPS(MIRGenerator *gen, LIRGraph *graph, MacroAssembler *masm)
   : CodeGeneratorShared(gen, graph, masm)
 {
 }
 
 bool
 CodeGeneratorMIPS::generatePrologue()
 {
-    if (gen->compilingAsmJS()) {
-        masm.Push(ra);
-        // Note that this automatically sets MacroAssembler::framePushed().
-        masm.reserveStack(frameDepth_);
-    } else {
-        // Note that this automatically sets MacroAssembler::framePushed().
-        masm.reserveStack(frameSize());
-        masm.checkStackAlignment();
+    MOZ_ASSERT(!gen->compilingAsmJS());
+    // Note that this automatically sets MacroAssembler::framePushed().
+    masm.reserveStack(frameSize());
+    masm.checkStackAlignment();
+    return true;
+}
+
+bool
+CodeGeneratorMIPS::generateAsmJSPrologue(Label *stackOverflowLabel)
+{
+    JS_ASSERT(gen->compilingAsmJS());
+
+    masm.push(ra);
+
+    // The asm.js over-recursed handler wants to be able to assume that SP
+    // points to the return address, so perform the check after pushing ra but
+    // before pushing frameDepth.
+    if (!omitOverRecursedCheck()) {
+        masm.branchPtr(Assembler::AboveOrEqual,
+                       AsmJSAbsoluteAddress(AsmJSImm_StackLimit),
+                       StackPointer,
+                       stackOverflowLabel);
     }
 
+    // Note that this automatically sets MacroAssembler::framePushed().
+    masm.reserveStack(frameDepth_);
+    masm.checkStackAlignment();
     return true;
 }
 
 bool
 CodeGeneratorMIPS::generateEpilogue()
 {
     masm.bind(&returnLabel_);
 
@@ -62,28 +79,22 @@ CodeGeneratorMIPS::generateEpilogue()
     if (!gen->compilingAsmJS() && gen->info().executionMode() == SequentialExecution) {
         if (!emitTracelogStopEvent(TraceLogger::IonMonkey))
             return false;
         if (!emitTracelogScriptStop())
             return false;
     }
 #endif
 
-    if (gen->compilingAsmJS()) {
-        // Pop the stack we allocated at the start of the function.
+    if (gen->compilingAsmJS())
         masm.freeStack(frameDepth_);
-        masm.Pop(ra);
-        masm.abiret();
-        MOZ_ASSERT(masm.framePushed() == 0);
-    } else {
-        // Pop the stack we allocated at the start of the function.
+    else
         masm.freeStack(frameSize());
-        MOZ_ASSERT(masm.framePushed() == 0);
-        masm.ret();
-    }
+    JS_ASSERT(masm.framePushed() == 0);
+    masm.ret();
     return true;
 }
 
 void
 CodeGeneratorMIPS::branchToBlock(Assembler::FloatFormat fmt, FloatRegister lhs, FloatRegister rhs,
                                  MBasicBlock *mir, Assembler::DoubleCondition cond)
 {
     // Skip past trivial blocks.
@@ -967,24 +978,18 @@ CodeGeneratorMIPS::visitPowHalfD(LPowHal
 MoveOperand
 CodeGeneratorMIPS::toMoveOperand(const LAllocation *a) const
 {
     if (a->isGeneralReg())
         return MoveOperand(ToRegister(a));
     if (a->isFloatReg()) {
         return MoveOperand(ToFloatRegister(a));
     }
-    MOZ_ASSERT((ToStackOffset(a) & 3) == 0);
     int32_t offset = ToStackOffset(a);
-
-    // The way the stack slots work, we assume that everything from
-    // depth == 0 downwards is writable. However, since our frame is included
-    // in this, ensure that the frame gets skipped.
-    if (gen->compilingAsmJS())
-        offset -= AlignmentMidPrologue;
+    MOZ_ASSERT((offset & 3) == 0);
 
     return MoveOperand(StackPointer, offset);
 }
 
 class js::jit::OutOfLineTableSwitch : public OutOfLineCodeBase<CodeGeneratorMIPS>
 {
     MTableSwitch *mir_;
     CodeLabel jumpLabel_;
@@ -1989,17 +1994,17 @@ CodeGeneratorMIPS::visitAsmJSLoadHeap(LA
             masm.convertDoubleToFloat32(NANReg, ToFloatRegister(out));
         else
             masm.moveDouble(NANReg, ToFloatRegister(out));
     } else {
         masm.move32(Imm32(0), ToRegister(out));
     }
     masm.bind(&done);
 
-    return gen->noteHeapAccess(AsmJSHeapAccess(bo.getOffset()));
+    return masm.append(AsmJSHeapAccess(bo.getOffset()));
 }
 
 bool
 CodeGeneratorMIPS::visitAsmJSStoreHeap(LAsmJSStoreHeap *ins)
 {
     const MAsmJSStoreHeap *mir = ins->mir();
     const LAllocation *value = ins->value();
     const LAllocation *ptr = ins->ptr();
@@ -2065,17 +2070,17 @@ CodeGeneratorMIPS::visitAsmJSStoreHeap(L
         } else
             masm.storeDouble(ToFloatRegister(value), BaseIndex(HeapReg, ptrReg, TimesOne));
     } else {
         masm.ma_store(ToRegister(value), BaseIndex(HeapReg, ptrReg, TimesOne),
                       static_cast<LoadStoreSize>(size), isSigned ? SignExtend : ZeroExtend);
     }
     masm.bind(&rejoin);
 
-    return gen->noteHeapAccess(AsmJSHeapAccess(bo.getOffset()));
+    return masm.append(AsmJSHeapAccess(bo.getOffset()));
 }
 
 bool
 CodeGeneratorMIPS::visitAsmJSPassStackArg(LAsmJSPassStackArg *ins)
 {
     const MAsmJSPassStackArg *mir = ins->mir();
     if (ins->arg()->isConstant()) {
         masm.storePtr(ImmWord(ToInt32(ins->arg())), Address(StackPointer, mir->spOffset()));
--- a/js/src/jit/mips/CodeGenerator-mips.h
+++ b/js/src/jit/mips/CodeGenerator-mips.h
@@ -28,44 +28,32 @@ class CodeGeneratorMIPS : public CodeGen
     // Label for the common return path.
     NonAssertingLabel returnLabel_;
     NonAssertingLabel deoptLabel_;
 
     inline Address ToAddress(const LAllocation &a) {
         MOZ_ASSERT(a.isMemory());
         int32_t offset = ToStackOffset(&a);
 
-        // The way the stack slots work, we assume that everything from
-        // depth == 0 downwards is writable however, since our frame is
-        // included in this, ensure that the frame gets skipped.
-        if (gen->compilingAsmJS())
-            offset -= AlignmentMidPrologue;
-
         return Address(StackPointer, offset);
     }
 
     inline Address ToAddress(const LAllocation *a) {
         return ToAddress(*a);
     }
 
     inline Operand ToOperand(const LAllocation &a) {
         if (a.isGeneralReg())
             return Operand(a.toGeneralReg()->reg());
         if (a.isFloatReg())
             return Operand(a.toFloatReg()->reg());
 
         MOZ_ASSERT(a.isMemory());
         int32_t offset = ToStackOffset(&a);
 
-        // The way the stack slots work, we assume that everything from
-        // depth == 0 downwards is writable however, since our frame is
-        // included in this, ensure that the frame gets skipped.
-        if (gen->compilingAsmJS())
-            offset -= AlignmentMidPrologue;
-
         return Operand(StackPointer, offset);
     }
     inline Operand ToOperand(const LAllocation *a) {
         return ToOperand(*a);
     }
     inline Operand ToOperand(const LDefinition *def) {
         return ToOperand(def->output());
     }
@@ -106,16 +94,17 @@ class CodeGeneratorMIPS : public CodeGen
         return bailoutFrom(&bail, snapshot);
     }
 
     bool bailoutFrom(Label *label, LSnapshot *snapshot);
     bool bailout(LSnapshot *snapshot);
 
   protected:
     bool generatePrologue();
+    bool generateAsmJSPrologue(Label *stackOverflowLabel);
     bool generateEpilogue();
     bool generateOutOfLineCode();
 
     template <typename T>
     void branchToBlock(Register lhs, T rhs, MBasicBlock *mir, Assembler::Condition cond)
     {
         mir = skipTrivialBlocks(mir);
 
--- a/js/src/jit/mips/MacroAssembler-mips.cpp
+++ b/js/src/jit/mips/MacroAssembler-mips.cpp
@@ -1769,17 +1769,19 @@ MacroAssemblerMIPSCompat::movePtr(ImmGCP
 void
 MacroAssemblerMIPSCompat::movePtr(ImmPtr imm, Register dest)
 {
     movePtr(ImmWord(uintptr_t(imm.value)), dest);
 }
 void
 MacroAssemblerMIPSCompat::movePtr(AsmJSImmPtr imm, Register dest)
 {
-    MOZ_ASSUME_UNREACHABLE("NYI");
+    enoughMemory_ &= append(AsmJSAbsoluteLink(CodeOffsetLabel(nextOffset().getOffset()),
+                                              imm.kind()));
+    ma_liPatchable(dest, Imm32(-1));
 }
 
 void
 MacroAssemblerMIPSCompat::load8ZeroExtend(const Address &address, Register dest)
 {
     ma_load(dest, address, SizeByte, ZeroExtend);
 }
 
@@ -2902,16 +2904,24 @@ MacroAssemblerMIPSCompat::storeTypeTag(I
 void
 MacroAssemblerMIPSCompat::storeTypeTag(ImmTag tag, Register base, Register index, int32_t shift)
 {
     computeScaledAddress(BaseIndex(base, index, ShiftToScale(shift)), SecondScratchReg);
     ma_li(ScratchRegister, tag);
     as_sw(ScratchRegister, SecondScratchReg, TAG_OFFSET);
 }
 
+void
+MacroAssemblerMIPS::ma_callIonNoPush(const Register r)
+{
+    // This is a MIPS hack to push return address during jalr delay slot.
+    as_jalr(r);
+    as_sw(ra, StackPointer, 0);
+}
+
 // This macrosintruction calls the ion code and pushes the return address to
 // the stack in the case when stack is alligned.
 void
 MacroAssemblerMIPS::ma_callIon(const Register r)
 {
     // This is a MIPS hack to push return address during jalr delay slot.
     as_addiu(StackPointer, StackPointer, -2 * sizeof(intptr_t));
     as_jalr(r);
@@ -2925,16 +2935,31 @@ MacroAssemblerMIPS::ma_callIonHalfPush(c
 {
     // This is a MIPS hack to push return address during jalr delay slot.
     as_addiu(StackPointer, StackPointer, -sizeof(intptr_t));
     as_jalr(r);
     as_sw(ra, StackPointer, 0);
 }
 
 void
+MacroAssemblerMIPS::ma_callAndStoreRet(const Register r, uint32_t stackArgBytes)
+{
+    // Note: this function stores the return address to sp[16]. The caller
+    // must anticipate this by reserving additional space on the stack.
+    // The ABI does not provide space for a return address so this function
+    // stores 'ra' before any ABI arguments.
+    // This function may only be called if there are 4 or less arguments.
+    JS_ASSERT(stackArgBytes == 4 * sizeof(uintptr_t));
+
+    // This is a MIPS hack to push return address during jalr delay slot.
+    as_jalr(r);
+    as_sw(ra, StackPointer, 4 * sizeof(uintptr_t));
+}
+
+void
 MacroAssemblerMIPS::ma_call(ImmPtr dest)
 {
     ma_liPatchable(CallReg, dest);
     as_jalr(CallReg);
     as_nop();
 }
 
 void
@@ -3111,31 +3136,34 @@ void
 MacroAssemblerMIPSCompat::alignPointerUp(Register src, Register dest, uint32_t alignment)
 {
     MOZ_ASSERT(alignment > 1);
     ma_addu(dest, src, Imm32(alignment - 1));
     ma_and(dest, dest, Imm32(~(alignment - 1)));
 }
 
 void
-MacroAssemblerMIPSCompat::callWithABIPre(uint32_t *stackAdjust)
+MacroAssemblerMIPSCompat::callWithABIPre(uint32_t *stackAdjust, bool callFromAsmJS)
 {
     MOZ_ASSERT(inCall_);
 
     // Reserve place for $ra.
     *stackAdjust = sizeof(intptr_t);
 
     *stackAdjust += usedArgSlots_ > NumIntArgRegs ?
                     usedArgSlots_ * sizeof(intptr_t) :
                     NumIntArgRegs * sizeof(intptr_t);
 
+    uint32_t alignmentAtPrologue = callFromAsmJS ? AlignmentAtAsmJSPrologue : 0;
+
     if (dynamicAlignment_) {
         *stackAdjust += ComputeByteAlignment(*stackAdjust, StackAlignment);
     } else {
-        *stackAdjust += ComputeByteAlignment(framePushed_ + *stackAdjust, StackAlignment);
+        *stackAdjust += ComputeByteAlignment(framePushed_ + alignmentAtPrologue + *stackAdjust,
+                                             StackAlignment);
     }
 
     reserveStack(*stackAdjust);
 
     // Save $ra because call is going to clobber it. Restore it in
     // callWithABIPost. NOTE: This is needed for calls from BaselineIC.
     // Maybe we can do this differently.
     ma_sw(ra, Address(StackPointer, *stackAdjust - sizeof(intptr_t)));
@@ -3227,17 +3255,17 @@ MacroAssemblerMIPSCompat::callWithABI(vo
     ma_call(ImmPtr(fun));
     callWithABIPost(stackAdjust, result);
 }
 
 void
 MacroAssemblerMIPSCompat::callWithABI(AsmJSImmPtr imm, MoveOp::Type result)
 {
     uint32_t stackAdjust;
-    callWithABIPre(&stackAdjust);
+    callWithABIPre(&stackAdjust, /* callFromAsmJS = */ true);
     call(imm);
     callWithABIPost(stackAdjust, result);
 }
 
 void
 MacroAssemblerMIPSCompat::callWithABI(const Address &fun, MoveOp::Type result)
 {
     // Load the callee in t9, no instruction between the lw and call
--- a/js/src/jit/mips/MacroAssembler-mips.h
+++ b/js/src/jit/mips/MacroAssembler-mips.h
@@ -296,16 +296,19 @@ class MacroAssemblerMIPS : public Assemb
   public:
     // calls an Ion function, assumes that the stack is untouched (8 byte alinged)
     void ma_callIon(const Register reg);
     // callso an Ion function, assuming that sp has already been decremented
     void ma_callIonNoPush(const Register reg);
     // calls an ion function, assuming that the stack is currently not 8 byte aligned
     void ma_callIonHalfPush(const Register reg);
 
+    // calls reg, storing the return address into sp[stackArgBytes]
+    void ma_callAndStoreRet(const Register reg, uint32_t stackArgBytes);
+
     void ma_call(ImmPtr dest);
 
     void ma_jump(ImmPtr dest);
 
     void ma_cmp_set(Register dst, Register lhs, Register rhs, Condition c);
     void ma_cmp_set(Register dst, Register lhs, Imm32 imm, Condition c);
     void ma_cmp_set(Register dst, Register lhs, ImmPtr imm, Condition c) {
         ma_cmp_set(dst, lhs, Imm32(uint32_t(imm.value)), c);
@@ -391,17 +394,16 @@ class MacroAssemblerMIPSCompat : public 
     }
 
     void call(const Register reg) {
         as_jalr(reg);
         as_nop();
     }
 
     void call(Label *label) {
-        // for now, assume that it'll be nearby?
         ma_bal(label);
     }
 
     void call(ImmWord imm) {
         call(ImmPtr((void*)imm.value));
     }
     void call(ImmPtr imm) {
         BufferOffset bo = m_buffer.nextOffset();
@@ -413,16 +415,50 @@ class MacroAssemblerMIPSCompat : public 
         call(CallReg);
     }
     void call(JitCode *c) {
         BufferOffset bo = m_buffer.nextOffset();
         addPendingJump(bo, ImmPtr(c->raw()), Relocation::JITCODE);
         ma_liPatchable(ScratchRegister, Imm32((uint32_t)c->raw()));
         ma_callIonHalfPush(ScratchRegister);
     }
+
+    void appendCallSite(const CallSiteDesc &desc) {
+        // Add an extra sizeof(void*) to include the return address that was
+        // pushed by the call instruction (see CallSite::stackDepth).
+        enoughMemory_ &= append(CallSite(desc, currentOffset(), framePushed_ + sizeof(void*)));
+    }
+
+    void call(const CallSiteDesc &desc, const Register reg) {
+        call(reg);
+        appendCallSite(desc);
+    }
+    void call(const CallSiteDesc &desc, Label *label) {
+        call(label);
+        appendCallSite(desc);
+    }
+    void call(const CallSiteDesc &desc, AsmJSImmPtr imm) {
+        call(imm);
+        appendCallSite(desc);
+    }
+    void callExit(AsmJSImmPtr imm, uint32_t stackArgBytes) {
+        movePtr(imm, CallReg);
+        ma_callAndStoreRet(CallReg, stackArgBytes);
+        appendCallSite(CallSiteDesc::Exit());
+    }
+    void callIonFromAsmJS(const Register reg) {
+        ma_callIonNoPush(reg);
+        appendCallSite(CallSiteDesc::Exit());
+
+        // The Ion ABI has the callee pop the return address off the stack.
+        // The asm.js caller assumes that the call leaves sp unchanged, so bump
+        // the stack.
+        subPtr(Imm32(sizeof(void*)), StackPointer);
+    }
+
     void branch(JitCode *c) {
         BufferOffset bo = m_buffer.nextOffset();
         addPendingJump(bo, ImmPtr(c->raw()), Relocation::JITCODE);
         ma_liPatchable(ScratchRegister, Imm32((uint32_t)c->raw()));
         as_jr(ScratchRegister);
         as_nop();
     }
     void branch(const Register reg) {
@@ -1196,17 +1232,17 @@ public:
     void passABIArg(Register reg);
     void passABIArg(FloatRegister reg, MoveOp::Type type);
     void passABIArg(const ValueOperand &regs);
 
   protected:
     bool buildOOLFakeExitFrame(void *fakeReturnAddr);
 
   private:
-    void callWithABIPre(uint32_t *stackAdjust);
+    void callWithABIPre(uint32_t *stackAdjust, bool callFromAsmJS = false);
     void callWithABIPost(uint32_t stackAdjust, MoveOp::Type result);
 
   public:
     // Emits a call to a C/C++ function, resolving all argument moves.
     void callWithABI(void *fun, MoveOp::Type result = MoveOp::GENERAL);
     void callWithABI(AsmJSImmPtr imm, MoveOp::Type result = MoveOp::GENERAL);
     void callWithABI(const Address &fun, MoveOp::Type result = MoveOp::GENERAL);
 
--- a/js/src/jit/shared/Assembler-shared.h
+++ b/js/src/jit/shared/Assembler-shared.h
@@ -686,17 +686,17 @@ class AsmJSHeapAccess
       : offset_(offset),
 # if defined(JS_CODEGEN_X86)
         cmpDelta_(cmp == UINT32_MAX ? 0 : offset - cmp),
 # endif
         opLength_(after - offset),
         isFloat32Load_(false),
         loadedReg_(UINT8_MAX)
     {}
-#elif defined(JS_CODEGEN_ARM)
+#elif defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS)
     explicit AsmJSHeapAccess(uint32_t offset)
       : offset_(offset)
     {}
 #endif
 
     uint32_t offset() const { return offset_; }
     void setOffset(uint32_t offset) { offset_ = offset; }
 #if defined(JS_CODEGEN_X86)
--- a/js/src/jit/shared/Assembler-x86-shared.h
+++ b/js/src/jit/shared/Assembler-x86-shared.h
@@ -283,16 +283,19 @@ class AssemblerX86Shared : public Assemb
     }
 
     void setPrinter(Sprinter *sp) {
         masm.setPrinter(sp);
     }
 
     void executableCopy(void *buffer);
     void processCodeLabels(uint8_t *rawCode);
+    static int32_t extractCodeLabelOffset(uint8_t *code) {
+        return *(uintptr_t *)code;
+    }
     void copyJumpRelocationTable(uint8_t *dest);
     void copyDataRelocationTable(uint8_t *dest);
     void copyPreBarrierTable(uint8_t *dest);
 
     bool addCodeLabel(CodeLabel label) {
         return codeLabels_.append(label);
     }
     size_t numCodeLabels() const {
@@ -1672,16 +1675,21 @@ class AssemblerX86Shared : public Assemb
         // The pointer given is a pointer to *after* the data.
         uintptr_t *ptr = ((uintptr_t *) data.raw()) - 1;
         JS_ASSERT(*ptr == (uintptr_t)expectedData.value);
         *ptr = (uintptr_t)newData.value;
     }
     static void patchDataWithValueCheck(CodeLocationLabel data, ImmPtr newData, ImmPtr expectedData) {
         patchDataWithValueCheck(data, PatchedImmPtr(newData.value), PatchedImmPtr(expectedData.value));
     }
+
+    static void patchInstructionImmediate(uint8_t *code, PatchedImmPtr imm) {
+        MOZ_ASSUME_UNREACHABLE("Unused.");
+    }
+
     static uint32_t nopSize() {
         return 1;
     }
     static uint8_t *nextInstruction(uint8_t *cur, uint32_t *count) {
         MOZ_ASSUME_UNREACHABLE("nextInstruction NYI on x86");
     }
 
     // Toggle a jmp or cmp emitted by toggledJump().
--- a/js/src/jit/shared/CodeGenerator-shared.cpp
+++ b/js/src/jit/shared/CodeGenerator-shared.cpp
@@ -63,22 +63,17 @@ CodeGeneratorShared::CodeGeneratorShared
     // argument stack depth separately.
     if (gen->compilingAsmJS()) {
         JS_ASSERT(graph->argumentSlotCount() == 0);
         frameDepth_ += gen->maxAsmJSStackArgBytes();
 
         // An MAsmJSCall does not align the stack pointer at calls sites but instead
         // relies on the a priori stack adjustment (in the prologue) on platforms
         // (like x64) which require the stack to be aligned.
-#if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS)
-        bool forceAlign = true;
-#else
-        bool forceAlign = false;
-#endif
-        if (gen->needsInitialStackAlignment() || forceAlign) {
+        if (StackKeptAligned || gen->needsInitialStackAlignment()) {
             unsigned alignmentAtCall = AlignmentAtAsmJSPrologue + frameDepth_;
             if (unsigned rem = alignmentAtCall % StackAlignment) {
                 frameInitialAdjustment_ = StackAlignment - rem;
                 frameDepth_ += frameInitialAdjustment_;
             }
         }
 
         // FrameSizeClass is only used for bailing, which cannot happen in
--- a/js/src/jit/shared/MacroAssembler-x86-shared.h
+++ b/js/src/jit/shared/MacroAssembler-x86-shared.h
@@ -233,24 +233,27 @@ class MacroAssemblerX86Shared : public A
         cmpl(lhs, rhs);
         j(cond, label);
     }
     void branchTest16(Condition cond, Register lhs, Register rhs, Label *label) {
         testw(lhs, rhs);
         j(cond, label);
     }
     void branchTest32(Condition cond, Register lhs, Register rhs, Label *label) {
+        JS_ASSERT(cond == Zero || cond == NonZero || cond == Signed || cond == NotSigned);
         testl(lhs, rhs);
         j(cond, label);
     }
     void branchTest32(Condition cond, Register lhs, Imm32 imm, Label *label) {
+        JS_ASSERT(cond == Zero || cond == NonZero || cond == Signed || cond == NotSigned);
         testl(lhs, imm);
         j(cond, label);
     }
     void branchTest32(Condition cond, const Address &address, Imm32 imm, Label *label) {
+        JS_ASSERT(cond == Zero || cond == NonZero || cond == Signed || cond == NotSigned);
         testl(Operand(address), imm);
         j(cond, label);
     }
 
     // The following functions are exposed for use in platform-shared code.
     template <typename T>
     void Push(const T &t) {
         push(t);
--- a/js/src/jsfriendapi.h
+++ b/js/src/jsfriendapi.h
@@ -1332,17 +1332,17 @@ extern JS_FRIEND_DATA(const Class* const
 extern JS_FRIEND_DATA(const Class* const) Uint8ClampedArrayClassPtr;
 extern JS_FRIEND_DATA(const Class* const) Int16ArrayClassPtr;
 extern JS_FRIEND_DATA(const Class* const) Uint16ArrayClassPtr;
 extern JS_FRIEND_DATA(const Class* const) Int32ArrayClassPtr;
 extern JS_FRIEND_DATA(const Class* const) Uint32ArrayClassPtr;
 extern JS_FRIEND_DATA(const Class* const) Float32ArrayClassPtr;
 extern JS_FRIEND_DATA(const Class* const) Float64ArrayClassPtr;
 
-const size_t TypedArrayLengthSlot = 4;
+const size_t TypedArrayLengthSlot = 1;
 
 } // namespace detail
 
 /*
  * Test for specific typed array types (ArrayBufferView subtypes) and return
  * the unwrapped object if so, else nullptr.  Never throws.
  */
 
--- a/js/src/jsstr.cpp
+++ b/js/src/jsstr.cpp
@@ -674,46 +674,62 @@ str_substring(JSContext *cx, unsigned ar
         if (!str)
             return false;
     }
 
     args.rval().setString(str);
     return true;
 }
 
-JSString* JS_FASTCALL
-js_toLowerCase(JSContext *cx, JSString *str)
+template <typename CharT>
+static JSString *
+ToLowerCase(JSContext *cx, JSLinearString *str)
 {
-    size_t n = str->length();
-    const jschar *s = str->getChars(cx);
-    if (!s)
+    // Unlike toUpperCase, toLowerCase has the nice invariant that if the input
+    // is a Latin1 string, the output is also a Latin1 string.
+    size_t length = str->length();
+    ScopedJSFreePtr<CharT> newChars(cx->pod_malloc<CharT>(length + 1));
+    if (!newChars)
         return nullptr;
 
-    jschar *news = cx->pod_malloc<jschar>(n + 1);
-    if (!news)
+    {
+        AutoCheckCannotGC nogc;
+        const CharT *chars = str->chars<CharT>(nogc);
+        for (size_t i = 0; i < length; i++) {
+            jschar c = unicode::ToLowerCase(chars[i]);
+            if (IsSame<CharT, Latin1Char>::value)
+                MOZ_ASSERT(c <= 0xff);
+            newChars[i] = c;
+        }
+        newChars[length] = 0;
+    }
+
+    JSString *res = js_NewString<CanGC>(cx, newChars.get(), length);
+    if (!res)
         return nullptr;
-    for (size_t i = 0; i < n; i++)
-        news[i] = unicode::ToLowerCase(s[i]);
-    news[n] = 0;
-    str = js_NewString<CanGC>(cx, news, n);
-    if (!str) {
-        js_free(news);
-        return nullptr;
-    }
-    return str;
+
+    newChars.forget();
+    return res;
 }
 
 static inline bool
 ToLowerCaseHelper(JSContext *cx, CallReceiver call)
 {
     RootedString str(cx, ThisToStringForStringProto(cx, call));
     if (!str)
         return false;
 
-    str = js_toLowerCase(cx, str);
+    JSLinearString *linear = str->ensureLinear(cx);
+    if (!linear)
+        return false;
+
+    if (linear->hasLatin1Chars())
+        str = ToLowerCase<Latin1Char>(cx, linear);
+    else
+        str = ToLowerCase<jschar>(cx, linear);
     if (!str)
         return false;
 
     call.rval().setString(str);
     return true;
 }
 
 static bool
@@ -742,45 +758,58 @@ str_toLocaleLowerCase(JSContext *cx, uns
 
         args.rval().set(result);
         return true;
     }
 
     return ToLowerCaseHelper(cx, args);
 }
 
-JSString* JS_FASTCALL
-js_toUpperCase(JSContext *cx, JSString *str)
+template <typename CharT>
+static JSString *
+ToUpperCase(JSContext *cx, JSLinearString *str)
 {
-    size_t n = str->length();
-    const jschar *s = str->getChars(cx);
-    if (!s)
-        return nullptr;
-    jschar *news = cx->pod_malloc<jschar>(n + 1);
-    if (!news)
+    // toUpperCase on a Latin1 string can yield a non-Latin1 string. For now,
+    // we use a TwoByte string for the result.
+    size_t length = str->length();
+    ScopedJSFreePtr<jschar> newChars(cx->pod_malloc<jschar>(length + 1));
+    if (!newChars)
         return nullptr;
-    for (size_t i = 0; i < n; i++)
-        news[i] = unicode::ToUpperCase(s[i]);
-    news[n] = 0;
-    str = js_NewString<CanGC>(cx, news, n);
-    if (!str) {
-        js_free(news);
+
+    {
+        AutoCheckCannotGC nogc;
+        const CharT *chars = str->chars<CharT>(nogc);
+        for (size_t i = 0; i < length; i++)
+            newChars[i] = unicode::ToUpperCase(chars[i]);
+        newChars[length] = 0;
+    }
+
+    JSString *res = js_NewString<CanGC>(cx, newChars.get(), length);
+    if (!res)
         return nullptr;
-    }
-    return str;
+
+    newChars.forget();
+    return res;
 }
 
 static bool
 ToUpperCaseHelper(JSContext *cx, CallReceiver call)
 {
     RootedString str(cx, ThisToStringForStringProto(cx, call));
     if (!str)
         return false;
 
-    str = js_toUpperCase(cx, str);
+    JSLinearString *linear = str->ensureLinear(cx);
+    if (!linear)
+        return false;
+
+    if (linear->hasLatin1Chars())
+        str = ToUpperCase<Latin1Char>(cx, linear);
+    else
+        str = ToUpperCase<jschar>(cx, linear);
     if (!str)
         return false;
 
     call.rval().setString(str);
     return true;
 }
 
 static bool
@@ -1170,16 +1199,42 @@ StringMatch(const TextChar *text, uint32
 #if !defined(__linux__)
         (patLen > 128 && IsSame<TextChar, PatChar>::value)
             ? UnrolledMatch<MemCmp<TextChar, PatChar>>(text, textLen, pat, patLen)
             :
 #endif
               UnrolledMatch<ManualCmp<TextChar, PatChar>>(text, textLen, pat, patLen);
 }
 
+static int32_t
+StringMatch(JSLinearString *text, JSLinearString *pat, uint32_t start = 0)
+{
+    MOZ_ASSERT(start <= text->length());
+    uint32_t textLen = text->length() - start;
+    uint32_t patLen = pat->length();
+
+    int match;
+    AutoCheckCannotGC nogc;
+    if (text->hasLatin1Chars()) {
+        const Latin1Char *textChars = text->latin1Chars(nogc) + start;
+        if (pat->hasLatin1Chars())
+            match = StringMatch(textChars, textLen, pat->latin1Chars(nogc), patLen);
+        else
+            match = StringMatch(textChars, textLen, pat->twoByteChars(nogc), patLen);
+    } else {
+        const jschar *textChars = text->twoByteChars(nogc) + start;
+        if (pat->hasLatin1Chars())
+            match = StringMatch(textChars, textLen, pat->latin1Chars(nogc), patLen);
+        else
+            match = StringMatch(textChars, textLen, pat->twoByteChars(nogc), patLen);
+    }
+
+    return (match == -1) ? -1 : start + match;
+}
+
 static const size_t sRopeMatchThresholdRatioLog2 = 5;
 
 bool
 js::StringHasPattern(const jschar *text, uint32_t textLen,
                      const jschar *pat, uint32_t patLen)
 {
     return StringMatch(text, textLen, pat, patLen) != -1;
 }
@@ -1236,145 +1291,147 @@ class StringSegmentRange
         if (stack.empty()) {
             cur = nullptr;
             return true;
         }
         return settle(stack.popCopy());
     }
 };
 
+typedef Vector<JSLinearString *, 16, SystemAllocPolicy> LinearStringVector;
+
+template <typename TextChar, typename PatChar>
+static int
+RopeMatchImpl(const AutoCheckCannotGC &nogc, LinearStringVector &strings,
+              const PatChar *pat, size_t patLen)
+{
+    /* Absolute offset from the beginning of the logical text string. */
+    int pos = 0;
+
+    for (JSLinearString **outerp = strings.begin(); outerp != strings.end(); ++outerp) {
+        /* Try to find a match within 'outer'. */
+        JSLinearString *outer = *outerp;
+        const TextChar *chars = outer->chars<TextChar>(nogc);
+        size_t len = outer->length();
+        int matchResult = StringMatch(chars, len, pat, patLen);
+        if (matchResult != -1) {
+            /* Matched! */
+            return pos + matchResult;
+        }
+
+        /* Try to find a match starting in 'outer' and running into other nodes. */
+        const TextChar *const text = chars + (patLen > len ? 0 : len - patLen + 1);
+        const TextChar *const textend = chars + len;
+        const PatChar p0 = *pat;
+        const PatChar *const p1 = pat + 1;
+        const PatChar *const patend = pat + patLen;
+        for (const TextChar *t = text; t != textend; ) {
+            if (*t++ != p0)
+                continue;
+
+            JSLinearString **innerp = outerp;
+            const TextChar *ttend = textend;
+            const TextChar *tt = t;
+            for (const PatChar *pp = p1; pp != patend; ++pp, ++tt) {
+                while (tt == ttend) {
+                    if (++innerp == strings.end())
+                        return -1;
+
+                    JSLinearString *inner = *innerp;
+                    tt = inner->chars<TextChar>(nogc);
+                    ttend = tt + inner->length();
+                }
+                if (*pp != *tt)
+                    goto break_continue;
+            }
+
+            /* Matched! */
+            return pos + (t - chars) - 1;  /* -1 because of *t++ above */
+
+          break_continue:;
+        }
+
+        pos += len;
+    }
+
+    return -1;
+}
+
 /*
  * RopeMatch takes the text to search and the pattern to search for in the text.
  * RopeMatch returns false on OOM and otherwise returns the match index through
  * the 'match' outparam (-1 for not found).
  */
 static bool
-RopeMatch(JSContext *cx, JSString *textstr, const jschar *pat, uint32_t patLen, int *match)
+RopeMatch(JSContext *cx, JSRope *text, JSLinearString *pat, int *match)
 {
-    JS_ASSERT(textstr->isRope());
-
+    uint32_t patLen = pat->length();
     if (patLen == 0) {
         *match = 0;
         return true;
     }
-    if (textstr->length() < patLen) {
+    if (text->length() < patLen) {
         *match = -1;
         return true;
     }
 
     /*
      * List of leaf nodes in the rope. If we run out of memory when trying to
      * append to this list, we can still fall back to StringMatch, so use the
      * system allocator so we don't report OOM in that case.
      */
-    Vector<JSLinearString *, 16, SystemAllocPolicy> strs;
+    LinearStringVector strings;
 
     /*
      * We don't want to do rope matching if there is a poor node-to-char ratio,
      * since this means spending a lot of time in the match loop below. We also
      * need to build the list of leaf nodes. Do both here: iterate over the
      * nodes so long as there are not too many.
+     *
+     * We also don't use rope matching if the rope contains both Latin1 and
+     * TwoByte nodes, to simplify the match algorithm.
      */
     {
-        size_t textstrlen = textstr->length();
-        size_t threshold = textstrlen >> sRopeMatchThresholdRatioLog2;
+        size_t threshold = text->length() >> sRopeMatchThresholdRatioLog2;
         StringSegmentRange r(cx);
-        if (!r.init(textstr))
+        if (!r.init(text))
             return false;
+
+        bool textIsLatin1 = text->hasLatin1Chars();
         while (!r.empty()) {
-            if (threshold-- == 0 || !strs.append(r.front())) {
-                const jschar *chars = textstr->getChars(cx);
-                if (!chars)
+            if (threshold-- == 0 ||
+                r.front()->hasLatin1Chars() != textIsLatin1 ||
+                !strings.append(r.front()))
+            {
+                JSLinearString *linear = text->ensureLinear(cx);
+                if (!linear)
                     return false;
-                *match = StringMatch(chars, textstrlen, pat, patLen);
+
+                *match = StringMatch(linear, pat);
                 return true;
             }
             if (!r.popFront())
                 return false;
         }
     }
 
-    /* Absolute offset from the beginning of the logical string textstr. */
-    int pos = 0;
-
-    for (JSLinearString **outerp = strs.begin(); outerp != strs.end(); ++outerp) {
-        /* Try to find a match within 'outer'. */
-        JSLinearString *outer = *outerp;
-        const jschar *chars = outer->chars();
-        size_t len = outer->length();
-        int matchResult = StringMatch(chars, len, pat, patLen);
-        if (matchResult != -1) {
-            /* Matched! */
-            *match = pos + matchResult;
-            return true;
-        }
-
-        /* Try to find a match starting in 'outer' and running into other nodes. */
-        const jschar *const text = chars + (patLen > len ? 0 : len - patLen + 1);
-        const jschar *const textend = chars + len;
-        const jschar p0 = *pat;
-        const jschar *const p1 = pat + 1;
-        const jschar *const patend = pat + patLen;
-        for (const jschar *t = text; t != textend; ) {
-            if (*t++ != p0)
-                continue;
-            JSLinearString **innerp = outerp;
-            const jschar *ttend = textend;
-            for (const jschar *pp = p1, *tt = t; pp != patend; ++pp, ++tt) {
-                while (tt == ttend) {
-                    if (++innerp == strs.end()) {
-                        *match = -1;
-                        return true;
-                    }
-                    JSLinearString *inner = *innerp;
-                    tt = inner->chars();
-                    ttend = tt + inner->length();
-                }
-                if (*pp != *tt)
-                    goto break_continue;
-            }
-
-            /* Matched! */
-            *match = pos + (t - chars) - 1;  /* -1 because of *t++ above */
-            return true;
-
-          break_continue:;
-        }
-
-        pos += len;
-    }
-
-    *match = -1;
-    return true;
-}
-
-static int32_t
-IndexOfImpl(JSLinearString *text, JSLinearString *pat, uint32_t start)
-{
-    MOZ_ASSERT(start <= text->length());
-    uint32_t textLen = text->length() - start;
-    uint32_t patLen = pat->length();
-
-    int match;
     AutoCheckCannotGC nogc;
     if (text->hasLatin1Chars()) {
-        const Latin1Char *textChars = text->latin1Chars(nogc) + start;
         if (pat->hasLatin1Chars())
-            match = StringMatch(textChars, textLen, pat->latin1Chars(nogc), patLen);
+            *match = RopeMatchImpl<Latin1Char>(nogc, strings, pat->latin1Chars(nogc), patLen);
         else
-            match = StringMatch(textChars, textLen, pat->twoByteChars(nogc), patLen);
+            *match = RopeMatchImpl<Latin1Char>(nogc, strings, pat->twoByteChars(nogc), patLen);
     } else {
-        const jschar *textChars = text->twoByteChars(nogc) + start;
         if (pat->hasLatin1Chars())
-            match = StringMatch(textChars, textLen, pat->latin1Chars(nogc), patLen);
+            *match = RopeMatchImpl<jschar>(nogc, strings, pat->latin1Chars(nogc), patLen);
         else
-            match = StringMatch(textChars, textLen, pat->twoByteChars(nogc), patLen);
+            *match = RopeMatchImpl<jschar>(nogc, strings, pat->twoByteChars(nogc), patLen);
     }
 
-    return (match == -1) ? -1 : start + match;
+    return true;
 }
 
 /* ES6 20121026 draft 15.5.4.24. */
 static bool
 str_contains(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
@@ -1408,17 +1465,17 @@ str_contains(JSContext *cx, unsigned arg
     // Step 9
     uint32_t start = Min(Max(pos, 0U), textLen);
 
     // Steps 10 and 11
     JSLinearString *text = str->ensureLinear(cx);
     if (!text)
         return false;
 
-    args.rval().setBoolean(IndexOfImpl(text, searchStr, start) != -1);
+    args.rval().setBoolean(StringMatch(text, searchStr, start) != -1);
     return true;
 }
 
 /* ES6 20120927 draft 15.5.4.7. */
 static bool
 str_indexOf(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
@@ -1453,17 +1510,17 @@ str_indexOf(JSContext *cx, unsigned argc
     // Step 9
     uint32_t start = Min(Max(pos, 0U), textLen);
 
     // Steps 10 and 11
     JSLinearString *text = str->ensureLinear(cx);
     if (!text)
         return false;
 
-    args.rval().setInt32(IndexOfImpl(text, searchStr, start));
+    args.rval().setInt32(StringMatch(text, searchStr, start));
     return true;
 }
 
 template <typename TextChar, typename PatChar>
 static int32_t
 LastIndexOfImpl(const TextChar *text, size_t textLen, const PatChar *pat, size_t patLen,
                 size_t start)
 {
@@ -1714,87 +1771,103 @@ str_endsWith(JSContext *cx, unsigned arg
     JSLinearString *text = str->ensureLinear(cx);
     if (!text)
         return false;
 
     args.rval().setBoolean(HasSubstringAt(text, searchStr, start));
     return true;
 }
 
-static bool
-js_TrimString(JSContext *cx, Value *vp, bool trimLeft, bool trimRight)
+template <typename CharT>
+static void
+TrimString(const CharT *chars, bool trimLeft, bool trimRight, size_t length,
+           size_t *pBegin, size_t *pEnd)
 {
-    CallReceiver call = CallReceiverFromVp(vp);
-    RootedString str(cx, ThisToStringForStringProto(cx, call));
-    if (!str)
-        return false;
-    size_t length = str->length();
-    const jschar *chars = str->getChars(cx);
-    if (!chars)
-        return false;
-
-    size_t begin = 0;
-    size_t end = length;
+    size_t begin = 0, end = length;
 
     if (trimLeft) {
         while (begin < length && unicode::IsSpace(chars[begin]))
             ++begin;
     }
 
     if (trimRight) {
         while (end > begin && unicode::IsSpace(chars[end - 1]))
             --end;
     }
 
+    *pBegin = begin;
+    *pEnd = end;
+}
+
+static bool
+TrimString(JSContext *cx, Value *vp, bool trimLeft, bool trimRight)
+{
+    CallReceiver call = CallReceiverFromVp(vp);
+    RootedString str(cx, ThisToStringForStringProto(cx, call));
+    if (!str)
+        return false;
+
+    JSLinearString *linear = str->ensureLinear(cx);
+    if (!linear)
+        return false;
+
+    size_t length = linear->length();
+    size_t begin, end;
+    if (linear->hasLatin1Chars()) {
+        AutoCheckCannotGC nogc;
+        TrimString(linear->latin1Chars(nogc), trimLeft, trimRight, length, &begin, &end);
+    } else {
+        AutoCheckCannotGC nogc;
+        TrimString(linear->twoByteChars(nogc), trimLeft, trimRight, length, &begin, &end);
+    }
+
     str = js_NewDependentString(cx, str, begin, end - begin);
     if (!str)
         return false;
 
     call.rval().setString(str);
     return true;
 }
 
 static bool
 str_trim(JSContext *cx, unsigned argc, Value *vp)
 {
-    return js_TrimString(cx, vp, true, true);
+    return TrimString(cx, vp, true, true);
 }
 
 static bool
 str_trimLeft(JSContext *cx, unsigned argc, Value *vp)
 {
-    return js_TrimString(cx, vp, true, false);
+    return TrimString(cx, vp, true, false);
 }
 
 static bool
 str_trimRight(JSContext *cx, unsigned argc, Value *vp)
 {
-    return js_TrimString(cx, vp, false, true);
+    return TrimString(cx, vp, false, true);
 }
 
 /*
  * Perl-inspired string functions.
  */
 
 namespace {
 
 /* Result of a successfully performed flat match. */
 class FlatMatch
 {
-    RootedAtom patstr;
-    const jschar *pat;
-    size_t       patLen;
-    int32_t      match_;
+    RootedAtom pat_;
+    int32_t match_;
 
     friend class StringRegExpGuard;
 
   public:
-    explicit FlatMatch(JSContext *cx) : patstr(cx) {}
-    JSLinearString *pattern() const { return patstr; }
-    size_t patternLength() const { return patLen; }
+    explicit FlatMatch(JSContext *cx) : pat_(cx) {}
+    JSLinearString *pattern() const { return pat_; }
+    size_t patternLength() const { return pat_->length(); }
 
     /*
      * Note: The match is -1 when the match is performed successfully,
      * but no match is found.
      */
     int32_t match() const { return match_; }
 };
 
@@ -1809,26 +1882,37 @@ IsRegExpMetaChar(jschar c)
       case '?': case '(': case ')': case '[': case ']': case '{':
       case '}': case '|':
         return true;
       default:
         return false;
     }
 }
 
+template <typename CharT>
 static inline bool
-HasRegExpMetaChars(const jschar *chars, size_t length)
+HasRegExpMetaChars(const CharT *chars, size_t length)
 {
     for (size_t i = 0; i < length; ++i) {
         if (IsRegExpMetaChar(chars[i]))
             return true;
     }
     return false;
 }
 
+static inline bool
+HasRegExpMetaChars(JSLinearString *str)
+{
+    AutoCheckCannotGC nogc;
+    if (str->hasLatin1Chars())
+        return HasRegExpMetaChars(str->latin1Chars(nogc), str->length());
+
+    return HasRegExpMetaChars(str->twoByteChars(nogc), str->length());
+}
+
 bool
 js::StringHasRegExpMetaChars(const jschar *chars, size_t length)
 {
     return HasRegExpMetaChars(chars, length);
 }
 
 namespace {
 
@@ -1879,89 +1963,84 @@ class MOZ_STACK_CLASS StringRegExpGuard
 
     /* init must succeed in order to call tryFlatMatch or normalizeRegExp. */
     bool init(JSContext *cx, CallArgs args, bool convertVoid = false)
     {
         if (args.length() != 0 && IsObjectWithClass(args[0], ESClass_RegExp, cx))
             return init(cx, &args[0].toObject());
 
         if (convertVoid && !args.hasDefined(0)) {
-            fm.patstr = cx->runtime()->emptyString;
+            fm.pat_ = cx->runtime()->emptyString;
             return true;
         }
 
         JSString *arg = ArgToRootedString(cx, args, 0);
         if (!arg)
             return false;
 
-        fm.patstr = AtomizeString(cx, arg);
-        if (!fm.patstr)
+        fm.pat_ = AtomizeString(cx, arg);
+        if (!fm.pat_)
             return false;
 
         return true;
     }
 
     bool init(JSContext *cx, JSObject *regexp) {
         obj_ = regexp;
 
         JS_ASSERT(ObjectClassIs(obj_, ESClass_RegExp, cx));
 
         if (!RegExpToShared(cx, obj_, &re_))
             return false;
         return true;
     }
 
     bool init(JSContext *cx, HandleString pattern) {
-        fm.patstr = AtomizeString(cx, pattern);
-        if (!fm.patstr)
+        fm.pat_ = AtomizeString(cx, pattern);
+        if (!fm.pat_)
             return false;
         return true;
     }
 
     /*
      * Attempt to match |patstr| to |textstr|. A flags argument, metachars in
      * the pattern string, or a lengthy pattern string can thwart this process.
      *
      * |checkMetaChars| looks for regexp metachars in the pattern string.
      *
      * Return whether flat matching could be used.
      *
      * N.B. tryFlatMatch returns nullptr on OOM, so the caller must check
      * cx->isExceptionPending().
      */
     const FlatMatch *
-    tryFlatMatch(JSContext *cx, JSString *textstr, unsigned optarg, unsigned argc,
+    tryFlatMatch(JSContext *cx, JSString *text, unsigned optarg, unsigned argc,
                  bool checkMetaChars = true)
     {
         if (re_.initialized())
             return nullptr;
 
-        fm.pat = fm.patstr->chars();
-        fm.patLen = fm.patstr->length();
-
         if (optarg < argc)
             return nullptr;
 
-        if (checkMetaChars &&
-            (fm.patLen > MAX_FLAT_PAT_LEN || HasRegExpMetaChars(fm.pat, fm.patLen))) {
+        size_t patLen = fm.pat_->length();
+        if (checkMetaChars && (patLen > MAX_FLAT_PAT_LEN || HasRegExpMetaChars(fm.pat_)))
             return nullptr;
-        }
 
         /*
-         * textstr could be a rope, so we want to avoid flattening it for as
+         * |text| could be a rope, so we want to avoid flattening it for as
          * long as possible.
          */
-        if (textstr->isRope()) {
-            if (!RopeMatch(cx, textstr, fm.pat, fm.patLen, &fm.match_))
+        if (text->isRope()) {
+            if (!RopeMatch(cx, &text->asRope(), fm.pat_, &fm.match_))
                 return nullptr;
         } else {
-            const jschar *text = textstr->asLinear().chars();
-            size_t textLen = textstr->length();
-            fm.match_ = StringMatch(text, textLen, fm.pat, fm.patLen);
+            fm.match_ = StringMatch(&text->asLinear(), fm.pat_, 0);
         }
+
         return &fm;
     }
 
     /* If the pattern is not already a regular expression, make it so. */
     bool normalizeRegExp(JSContext *cx, bool flat, unsigned optarg, CallArgs args)
     {
         if (re_.initialized())
             return true;
@@ -1971,27 +2050,27 @@ class MOZ_STACK_CLASS StringRegExpGuard
         if (optarg < args.length()) {
             opt = ToString<CanGC>(cx, args[optarg]);
             if (!opt)
                 return false;
         } else {
             opt = nullptr;
         }
 
-        Rooted<JSAtom *> patstr(cx);
+        Rooted<JSAtom *> pat(cx);
         if (flat) {
-            patstr = flattenPattern(cx, fm.patstr);
-            if (!patstr)
+            pat = flattenPattern(cx, fm.pat_);
+            if (!pat)
                 return false;
         } else {
-            patstr = fm.patstr;
+            pat = fm.pat_;
         }
-        JS_ASSERT(patstr);
-
-        return cx->compartment()->regExps.get(cx, patstr, opt, &re_);
+        JS_ASSERT(pat);
+
+        return cx->compartment()->regExps.get(cx, pat, opt, &re_);
     }
 
     bool zeroLastIndex(JSContext *cx) {
         if (!regExpIsObject())
             return true;
 
         // Use a fast path for same-global RegExp objects with writable
         // lastIndex.
@@ -3183,17 +3262,17 @@ str_replace_flat_lambda(JSContext *cx, C
         return false;
 
     RootedString leftSide(cx, js_NewDependentString(cx, rdata.str, 0, fm.match()));
     if (!leftSide)
         return false;
 
     size_t matchLimit = fm.match() + fm.patternLength();
     RootedString rightSide(cx, js_NewDependentString(cx, rdata.str, matchLimit,
-                                                        rdata.str->length() - matchLimit));
+                                                     rdata.str->length() - matchLimit));
     if (!rightSide)
         return false;
 
     RopeBuilder builder(cx);
     if (!(builder.append(leftSide) &&
           builder.append(repstr) &&
           builder.append(rightSide))) {
         return false;
@@ -4041,19 +4120,19 @@ js_InitStringClass(JSContext *cx, Handle
      * uneval on the global object.
      */
     if (!JS_DefineFunctions(cx, global, string_functions))
         return nullptr;
 
     return proto;
 }
 
-template <AllowGC allowGC>
+template <AllowGC allowGC, typename CharT>
 JSFlatString *
-js_NewString(ThreadSafeContext *cx, jschar *chars, size_t length)
+js_NewString(ThreadSafeContext *cx, CharT *chars, size_t length)
 {
     if (length == 1) {
         jschar c = chars[0];
         if (StaticStrings::hasUnit(c)) {
             // Free |chars| because we're taking possession of it, but it's no
             // longer needed because we use the static string instead.
             js_free(chars);
             return cx->staticStrings().getUnit(c);
--- a/js/src/jsstr.h
+++ b/js/src/jsstr.h
@@ -56,22 +56,16 @@ CompareChars(const jschar *s1, size_t l1
             return cmp;
     }
 
     return (int32_t)(l1 - l2);
 }
 
 }  /* namespace js */
 
-extern JSString * JS_FASTCALL
-js_toLowerCase(JSContext *cx, JSString *str);
-
-extern JSString * JS_FASTCALL
-js_toUpperCase(JSContext *cx, JSString *str);
-
 struct JSSubString {
     size_t          length;
     const jschar    *chars;
 };
 
 extern const jschar js_empty_ucstr[];
 extern const JSSubString js_EmptySubString;
 
@@ -93,19 +87,19 @@ extern const char js_escape_str[];
 extern const char js_unescape_str[];
 extern const char js_uneval_str[];
 extern const char js_decodeURI_str[];
 extern const char js_encodeURI_str[];
 extern const char js_decodeURIComponent_str[];
 extern const char js_encodeURIComponent_str[];
 
 /* GC-allocate a string descriptor for the given malloc-allocated chars. */
-template <js::AllowGC allowGC>
+template <js::AllowGC allowGC, typename CharT>
 extern JSFlatString *
-js_NewString(js::ThreadSafeContext *cx, jschar *chars, size_t length);
+js_NewString(js::ThreadSafeContext *cx, CharT *chars, size_t length);
 
 extern JSLinearString *
 js_NewDependentString(JSContext *cx, JSString *base, size_t start, size_t length);
 
 /* Copy a counted string and GC-allocate a descriptor for it. */
 template <js::AllowGC allowGC>
 extern JSFlatString *
 js_NewStringCopyN(js::ExclusiveContext *cx, const jschar *s, size_t n);
--- a/js/src/tests/lib/jittests.py
+++ b/js/src/tests/lib/jittests.py
@@ -472,17 +472,18 @@ def run_tests_parallel(tests, prefix, op
                 new_workers.append(worker)
             else:
                 worker.join()
         return new_workers
 
     try:
         testcnt = 0
         # Initially start as many jobs as allowed to run parallel
-        for i in range(min(options.max_jobs,total_tests)):
+        # Always enqueue at least one to avoid a curious deadlock
+        for i in range(max(1, min(options.max_jobs, total_tests))):
             notify_queue.put(True)
 
         # For every item in the notify queue, start one new worker.
         # Every completed worker adds a new item to this queue.
         while notify_queue.get():
             if (testcnt < total_tests):
                 # Start one new worker
                 test = tests[testcnt % len(tests)]
@@ -585,29 +586,35 @@ def print_test_summary(num_tests, failur
         print('Result summary:')
         print('Passed: %d' % (num_tests - num_failures))
         print('Failed: %d' % num_failures)
 
     return not failures
 
 def process_test_results(results, num_tests, options):
     pb = NullProgressBar()
+    failures = []
+    timeouts = 0
+    complete = False
+    doing = 'before starting'
+
+    if num_tests == 0:
+        pb.finish(True)
+        complete = True
+        return print_test_summary(num_tests, failures, complete, doing, options)
+
     if not options.hide_progress and not options.show_cmd and ProgressBar.conservative_isatty():
         fmt = [
             {'value': 'PASS',    'color': 'green'},
             {'value': 'FAIL',    'color': 'red'},
             {'value': 'TIMEOUT', 'color': 'blue'},
             {'value': 'SKIP',    'color': 'brightgray'},
         ]
         pb = ProgressBar(num_tests, fmt)
 
-    failures = []
-    timeouts = 0
-    complete = False
-    doing = 'before starting'
     try:
         for i, res in enumerate(results):
             if options.show_output:
                 sys.stdout.write(res.out)
                 sys.stdout.write(res.err)
                 sys.stdout.write('Exit code: %s\n' % res.rc)
             if res.test.valgrind:
                 sys.stdout.write(res.err)
--- a/js/src/vm/ArrayBufferObject.h
+++ b/js/src/vm/ArrayBufferObject.h
@@ -232,26 +232,26 @@ class ArrayBufferObject : public JSObjec
  *
  * Common definitions shared by all ArrayBufferViews.
  */
 
 class ArrayBufferViewObject : public JSObject
 {
   protected:
     /* Offset of view in underlying ArrayBufferObject */
-    static const size_t BYTEOFFSET_SLOT  = JS_TYPEDOBJ_SLOT_BYTEOFFSET;
+    static const size_t BYTEOFFSET_SLOT  = JS_BUFVIEW_SLOT_BYTEOFFSET;
 
     /* Byte length of view */
-    static const size_t BYTELENGTH_SLOT  = JS_TYPEDOBJ_SLOT_BYTELENGTH;
+    static const size_t LENGTH_SLOT      = JS_BUFVIEW_SLOT_LENGTH;
 
     /* Underlying ArrayBufferObject */
-    static const size_t BUFFER_SLOT      = JS_TYPEDOBJ_SLOT_OWNER;
+    static const size_t BUFFER_SLOT      = JS_BUFVIEW_SLOT_OWNER;
 
     /* ArrayBufferObjects point to a linked list of views, chained through this slot */
-    static const size_t NEXT_VIEW_SLOT   = JS_TYPEDOBJ_SLOT_NEXT_VIEW;
+    static const size_t NEXT_VIEW_SLOT   = JS_BUFVIEW_SLOT_NEXT_VIEW;
 
   public:
     static ArrayBufferObject *bufferObject(JSContext *cx, Handle<ArrayBufferViewObject *> obj);
 
     ArrayBufferViewObject *nextView() const {
         return static_cast<ArrayBufferViewObject*>(getFixedSlot(NEXT_VIEW_SLOT).toPrivate());
     }
 
--- a/js/src/vm/String-inl.h
+++ b/js/src/vm/String-inl.h
@@ -225,27 +225,37 @@ JSString::markBase(JSTracer *trc)
 MOZ_ALWAYS_INLINE void
 JSFlatString::init(const jschar *chars, size_t length)
 {
     d.u1.length = length;
     d.u1.flags = FLAT_BIT;
     d.s.u2.nonInlineCharsTwoByte = chars;
 }
 
-template <js::AllowGC allowGC>
+MOZ_ALWAYS_INLINE void
+JSFlatString::init(const JS::Latin1Char *chars, size_t length)
+{
+    d.u1.length = length;
+    d.u1.flags = FLAT_BIT | LATIN1_CHARS_BIT;
+    d.s.u2.nonInlineCharsLatin1 = chars;
+}
+
+template <js::AllowGC allowGC, typename CharT>
 MOZ_ALWAYS_INLINE JSFlatString *
-JSFlatString::new_(js::ThreadSafeContext *cx, const jschar *chars, size_t length)
+JSFlatString::new_(js::ThreadSafeContext *cx, const CharT *chars, size_t length)
 {
-    JS_ASSERT(chars[length] == jschar(0));
+    JS_ASSERT(chars[length] == CharT(0));
 
     if (!validateLength(cx, length))
         return nullptr;
+
     JSFlatString *str = (JSFlatString *)js_NewGCString<allowGC>(cx);
     if (!str)
         return nullptr;
+
     str->init(chars, length);
     return str;
 }
 
 inline js::PropertyName *
 JSFlatString::toPropertyName(JSContext *cx)
 {
 #ifdef DEBUG
--- a/js/src/vm/String.h
+++ b/js/src/vm/String.h
@@ -698,21 +698,22 @@ class JSFlatString : public JSLinearStri
     /* Vacuous and therefore unimplemented. */
     JSFlatString *ensureFlat(JSContext *cx) MOZ_DELETE;
     bool isFlat() const MOZ_DELETE;
     JSFlatString &asFlat() const MOZ_DELETE;
 
     bool isIndexSlow(uint32_t *indexp) const;
 
     void init(const jschar *chars, size_t length);
+    void init(const JS::Latin1Char *chars, size_t length);
 
   public:
-    template <js::AllowGC allowGC>
+    template <js::AllowGC allowGC, typename CharT>
     static inline JSFlatString *new_(js::ThreadSafeContext *cx,
-                                     const jschar *chars, size_t length);
+                                     const CharT *chars, size_t length);
 
     MOZ_ALWAYS_INLINE
     const jschar *charsZ() const {
         JS_ASSERT(JSString::isFlat());
         return chars();
     }
 
     /*
--- a/js/src/vm/TypedArrayObject.cpp
+++ b/js/src/vm/TypedArrayObject.cpp
@@ -90,17 +90,16 @@ ValueIsLength(const Value &v, uint32_t *
  * This class holds all the member variables that are used by
  * the subclasses.
  */
 
 void
 TypedArrayObject::neuter(void *newData)
 {
     setSlot(LENGTH_SLOT, Int32Value(0));
-    setSlot(BYTELENGTH_SLOT, Int32Value(0));
     setSlot(BYTEOFFSET_SLOT, Int32Value(0));
     setPrivate(newData);
 }
 
 ArrayBufferObject *
 TypedArrayObject::sharedBuffer() const
 {
     return &bufferValue(const_cast<TypedArrayObject*>(this)).toObject().as<SharedArrayBufferObject>();
@@ -167,40 +166,40 @@ js::ClampDoubleToUint8(const double x)
          * want.
          */
         return y & ~1;
     }
 
     return y;
 }
 
-template<typename NativeType> static inline int TypeIDOfType();
-template<> inline int TypeIDOfType<int8_t>() { return ScalarTypeDescr::TYPE_INT8; }
-template<> inline int TypeIDOfType<uint8_t>() { return ScalarTypeDescr::TYPE_UINT8; }
-template<> inline int TypeIDOfType<int16_t>() { return ScalarTypeDescr::TYPE_INT16; }
-template<> inline int TypeIDOfType<uint16_t>() { return ScalarTypeDescr::TYPE_UINT16; }
-template<> inline int TypeIDOfType<int32_t>() { return ScalarTypeDescr::TYPE_INT32; }
-template<> inline int TypeIDOfType<uint32_t>() { return ScalarTypeDescr::TYPE_UINT32; }
-template<> inline int TypeIDOfType<float>() { return ScalarTypeDescr::TYPE_FLOAT32; }
-template<> inline int TypeIDOfType<double>() { return ScalarTypeDescr::TYPE_FLOAT64; }
-template<> inline int TypeIDOfType<uint8_clamped>() { return ScalarTypeDescr::TYPE_UINT8_CLAMPED; }
+template<typename NativeType> static inline ScalarTypeDescr::Type TypeIDOfType();
+template<> inline ScalarTypeDescr::Type TypeIDOfType<int8_t>() { return ScalarTypeDescr::TYPE_INT8; }
+template<> inline ScalarTypeDescr::Type TypeIDOfType<uint8_t>() { return ScalarTypeDescr::TYPE_UINT8; }
+template<> inline ScalarTypeDescr::Type TypeIDOfType<int16_t>() { return ScalarTypeDescr::TYPE_INT16; }
+template<> inline ScalarTypeDescr::Type TypeIDOfType<uint16_t>() { return ScalarTypeDescr::TYPE_UINT16; }
+template<> inline ScalarTypeDescr::Type TypeIDOfType<int32_t>() { return ScalarTypeDescr::TYPE_INT32; }
+template<> inline ScalarTypeDescr::Type TypeIDOfType<uint32_t>() { return ScalarTypeDescr::TYPE_UINT32; }
+template<> inline ScalarTypeDescr::Type TypeIDOfType<float>() { return ScalarTypeDescr::TYPE_FLOAT32; }
+template<> inline ScalarTypeDescr::Type TypeIDOfType<double>() { return ScalarTypeDescr::TYPE_FLOAT64; }
+template<> inline ScalarTypeDescr::Type TypeIDOfType<uint8_clamped>() { return ScalarTypeDescr::TYPE_UINT8_CLAMPED; }
 
 template<typename ElementType>
 static inline JSObject *
 NewArray(JSContext *cx, uint32_t nelements);
 
 namespace {
 
 template<typename NativeType>
 class TypedArrayObjectTemplate : public TypedArrayObject
 {
   public:
     typedef NativeType ThisType;
     typedef TypedArrayObjectTemplate<NativeType> ThisTypedArrayObject;
-    static int ArrayTypeID() { return TypeIDOfType<NativeType>(); }
+    static ScalarTypeDescr::Type ArrayTypeID() { return TypeIDOfType<NativeType>(); }
     static bool ArrayTypeIsUnsigned() { return TypeIsUnsigned<NativeType>(); }
     static bool ArrayTypeIsFloatingPoint() { return TypeIsFloatingPoint<NativeType>(); }
 
     static const size_t BYTES_PER_ELEMENT = sizeof(ThisType);
 
     static inline const Class *protoClass()
     {
         return &TypedArrayObject::protoClasses[ArrayTypeID()];
@@ -315,17 +314,16 @@ class TypedArrayObjectTemplate : public 
         } else {
             void *data = obj->fixedData(FIXED_DATA_START);
             obj->initPrivate(data);
             memset(data, 0, len * sizeof(NativeType));
         }
 
         obj->setSlot(LENGTH_SLOT, Int32Value(len));
         obj->setSlot(BYTEOFFSET_SLOT, Int32Value(byteOffset));
-        obj->setSlot(BYTELENGTH_SLOT, Int32Value(len * sizeof(NativeType)));
         obj->setSlot(NEXT_VIEW_SLOT, PrivateValue(nullptr));
 
 #ifdef DEBUG
         if (buffer) {
             uint32_t arrayByteLength = obj->byteLength();
             uint32_t arrayByteOffset = obj->byteOffset();
             uint32_t bufferByteLength = buffer->byteLength();
             JS_ASSERT_IF(!buffer->isNeutered(), buffer->dataPointer() <= obj->viewData());
@@ -472,17 +470,17 @@ class TypedArrayObjectTemplate : public 
                                     ThisTypedArrayObject::BufferGetterImpl>(cx, args);
     }
 
     // Define an accessor for a read-only property that invokes a native getter
     static bool
     DefineGetter(JSContext *cx, HandleObject proto, PropertyName *name, Native native)
     {
         RootedId id(cx, NameToId(name));
-        unsigned attrs = JSPROP_SHARED | JSPROP_GETTER | JSPROP_PERMANENT;
+        unsigned attrs = JSPROP_SHARED | JSPROP_GETTER;
 
         Rooted<GlobalObject*> global(cx, cx->compartment()->maybeGlobal());
         JSObject *getter = NewFunction(cx, NullPtr(), native, 0,
                                        JSFunction::NATIVE_FUN, global, NullPtr());
         if (!getter)
             return false;
 
         return DefineNativeProperty(cx, proto, id, UndefinedHandleValue,
@@ -1344,17 +1342,17 @@ DataViewObject::create(JSContext *cx, ui
         if (script) {
             if (!types::SetInitializerObjectType(cx, script, pc, obj, newKind))
                 return nullptr;
         }
     }
 
     DataViewObject &dvobj = obj->as<DataViewObject>();
     dvobj.setFixedSlot(BYTEOFFSET_SLOT, Int32Value(byteOffset));
-    dvobj.setFixedSlot(BYTELENGTH_SLOT, Int32Value(byteLength));
+    dvobj.setFixedSlot(LENGTH_SLOT, Int32Value(byteLength));
     dvobj.setFixedSlot(BUFFER_SLOT, ObjectValue(*arrayBuffer));
     dvobj.setFixedSlot(NEXT_VIEW_SLOT, PrivateValue(nullptr));
     InitArrayBufferViewDataPointer(&dvobj, arrayBuffer, byteOffset);
     JS_ASSERT(byteOffset + byteLength <= arrayBuffer->byteLength());
 
     // Verify that the private slot is at the expected place
     JS_ASSERT(dvobj.numFixedSlots() == DATA_SLOT);
 
@@ -2069,20 +2067,20 @@ bool _typedArray##_lengthGetter(JSContex
 }                                                                                  \
 bool _typedArray##_byteLengthGetter(JSContext *cx, unsigned argc, Value *vp) {     \
     return _typedArray##Object::Getter<_typedArray##Object::byteLengthValue>(cx, argc, vp); \
 }                                                                                  \
 bool _typedArray##_byteOffsetGetter(JSContext *cx, unsigned argc, Value *vp) {     \
     return _typedArray##Object::Getter<_typedArray##Object::byteOffsetValue>(cx, argc, vp); \
 }                                                                                  \
 const JSPropertySpec _typedArray##Object::jsprops[] = {                            \
-    JS_PSG("length", _typedArray##_lengthGetter, JSPROP_PERMANENT),                \
-    JS_PSG("buffer", _typedArray##Object::BufferGetter, JSPROP_PERMANENT),         \
-    JS_PSG("byteLength", _typedArray##_byteLengthGetter, JSPROP_PERMANENT),        \
-    JS_PSG("byteOffset", _typedArray##_byteOffsetGetter, JSPROP_PERMANENT),        \
+    JS_PSG("length", _typedArray##_lengthGetter, 0),                               \
+    JS_PSG("buffer", _typedArray##Object::BufferGetter, 0),                        \
+    JS_PSG("byteLength", _typedArray##_byteLengthGetter, 0),                       \
+    JS_PSG("byteOffset", _typedArray##_byteOffsetGetter, 0),                       \
     JS_PS_END                                                                      \
 };
 
 #define IMPL_TYPED_ARRAY_JSAPI_CONSTRUCTORS(Name,NativeType)                                    \
   JS_FRIEND_API(JSObject *) JS_New ## Name ## Array(JSContext *cx, uint32_t nelements)          \
   {                                                                                             \
       return TypedArrayObjectTemplate<NativeType>::fromLength(cx, nelements);                   \
   }                                                                                             \
@@ -2108,17 +2106,17 @@ const JSPropertySpec _typedArray##Object
       obj = CheckedUnwrap(obj);                                                                 \
       if (!obj)                                                                                 \
           return nullptr;                                                                       \
       const Class *clasp = obj->getClass();                                                     \
       if (clasp == &TypedArrayObject::classes[TypedArrayObjectTemplate<NativeType>::ArrayTypeID()]) \
           return obj;                                                                           \
       return nullptr;                                                                           \
   } \
-  JS_FRIEND_DATA(const js::Class* const) js::detail::Name ## ArrayClassPtr =                    \
+  const js::Class* const js::detail::Name ## ArrayClassPtr =                                    \
       &js::TypedArrayObject::classes[TypedArrayObjectTemplate<NativeType>::ArrayTypeID()];
 
 IMPL_TYPED_ARRAY_JSAPI_CONSTRUCTORS(Int8, int8_t)
 IMPL_TYPED_ARRAY_JSAPI_CONSTRUCTORS(Uint8, uint8_t)
 IMPL_TYPED_ARRAY_JSAPI_CONSTRUCTORS(Uint8Clamped, uint8_clamped)
 IMPL_TYPED_ARRAY_JSAPI_CONSTRUCTORS(Int16, int16_t)
 IMPL_TYPED_ARRAY_JSAPI_CONSTRUCTORS(Uint16, uint16_t)
 IMPL_TYPED_ARRAY_JSAPI_CONSTRUCTORS(Int32, int32_t)
@@ -2304,17 +2302,17 @@ js_InitArrayBufferClass(JSContext *cx, H
     {
         return nullptr;
     }
 
     if (!LinkConstructorAndPrototype(cx, ctor, arrayBufferProto))
         return nullptr;
 
     RootedId byteLengthId(cx, NameToId(cx->names().byteLength));
-    unsigned attrs = JSPROP_SHARED | JSPROP_GETTER | JSPROP_PERMANENT;
+    unsigned attrs = JSPROP_SHARED | JSPROP_GETTER;
     JSObject *getter = NewFunction(cx, NullPtr(), ArrayBufferObject::byteLengthGetter, 0,
                                    JSFunction::NATIVE_FUN, global, NullPtr());
     if (!getter)
         return nullptr;
 
     if (!DefineNativeProperty(cx, arrayBufferProto, byteLengthId, UndefinedHandleValue,
                               JS_DATA_TO_FUNC_PTR(PropertyOp, getter), nullptr, attrs))
         return nullptr;
@@ -2323,16 +2321,44 @@ js_InitArrayBufferClass(JSContext *cx, H
         return nullptr;
 
     if (!JS_DefineFunctions(cx, arrayBufferProto, ArrayBufferObject::jsfuncs))
         return nullptr;
 
     return arrayBufferProto;
 }
 
+/* static */ bool
+TypedArrayObject::isOriginalLengthGetter(ScalarTypeDescr::Type type, Native native)
+{
+    switch (type) {
+      case ScalarTypeDescr::TYPE_INT8:
+        return native == Int8Array_lengthGetter;
+      case ScalarTypeDescr::TYPE_UINT8:
+        return native == Uint8Array_lengthGetter;
+      case ScalarTypeDescr::TYPE_UINT8_CLAMPED:
+        return native == Uint8ClampedArray_lengthGetter;
+      case ScalarTypeDescr::TYPE_INT16:
+        return native == Int16Array_lengthGetter;
+      case ScalarTypeDescr::TYPE_UINT16:
+        return native == Uint16Array_lengthGetter;
+      case ScalarTypeDescr::TYPE_INT32:
+        return native == Int32Array_lengthGetter;
+      case ScalarTypeDescr::TYPE_UINT32:
+        return native == Uint32Array_lengthGetter;
+      case ScalarTypeDescr::TYPE_FLOAT32:
+        return native == Float32Array_lengthGetter;
+      case ScalarTypeDescr::TYPE_FLOAT64:
+        return native == Float64Array_lengthGetter;
+      default:
+        MOZ_ASSUME_UNREACHABLE("Unknown TypedArray type");
+        return false;
+    }
+}
+
 const Class DataViewObject::protoClass = {
     "DataViewPrototype",
     JSCLASS_HAS_PRIVATE |
     JSCLASS_HAS_RESERVED_SLOTS(DataViewObject::RESERVED_SLOTS) |
     JSCLASS_HAS_CACHED_PROTO(JSProto_DataView),
     JS_PropertyStub,         /* addProperty */
     JS_DeletePropertyStub,   /* delProperty */
     JS_PropertyStub,         /* getProperty */
@@ -2398,17 +2424,17 @@ DataViewObject::getter(JSContext *cx, un
     return CallNonGenericMethod<is, getterImpl<ValueGetter> >(cx, args);
 }
 
 template<Value ValueGetter(DataViewObject *view)>
 bool
 DataViewObject::defineGetter(JSContext *cx, PropertyName *name, HandleObject proto)
 {
     RootedId id(cx, NameToId(name));
-    unsigned attrs = JSPROP_SHARED | JSPROP_GETTER | JSPROP_PERMANENT;
+    unsigned attrs = JSPROP_SHARED | JSPROP_GETTER;
 
     Rooted<GlobalObject*> global(cx, cx->compartment()->maybeGlobal());
     JSObject *getter = NewFunction(cx, NullPtr(), DataViewObject::getter<ValueGetter>, 0,
                                    JSFunction::NATIVE_FUN, global, NullPtr());
     if (!getter)
         return false;
 
     return DefineNativeProperty(cx, proto, id, UndefinedHandleValue,
@@ -2462,17 +2488,17 @@ DataViewObject::initClass(JSContext *cx)
     global->setCreateDataViewForThis(fun);
 
     return true;
 }
 
 void
 DataViewObject::neuter(void *newData)
 {
-    setSlot(BYTELENGTH_SLOT, Int32Value(0));
+    setSlot(LENGTH_SLOT, Int32Value(0));
     setSlot(BYTEOFFSET_SLOT, Int32Value(0));
     setPrivate(newData);
 }
 
 JSObject *
 js_InitDataViewClass(JSContext *cx, HandleObject obj)
 {
     if (!DataViewObject::initClass(cx))
@@ -2623,105 +2649,105 @@ JS_GetArrayBufferViewType(JSObject *obj)
 
 JS_FRIEND_API(int8_t *)
 JS_GetInt8ArrayData(JSObject *obj)
 {
     obj = CheckedUnwrap(obj);
     if (!obj)
         return nullptr;
     TypedArrayObject *tarr = &obj->as<TypedArrayObject>();
-    JS_ASSERT(tarr->type() == ArrayBufferView::TYPE_INT8);
+    JS_ASSERT((int32_t) tarr->type() == ArrayBufferView::TYPE_INT8);
     return static_cast<int8_t *>(tarr->viewData());
 }
 
 JS_FRIEND_API(uint8_t *)
 JS_GetUint8ArrayData(JSObject *obj)
 {
     obj = CheckedUnwrap(obj);
     if (!obj)
         return nullptr;
     TypedArrayObject *tarr = &obj->as<TypedArrayObject>();
-    JS_ASSERT(tarr->type() == ArrayBufferView::TYPE_UINT8);
+    JS_ASSERT((int32_t) tarr->type() == ArrayBufferView::TYPE_UINT8);
     return static_cast<uint8_t *>(tarr->viewData());
 }
 
 JS_FRIEND_API(uint8_t *)
 JS_GetUint8ClampedArrayData(JSObject *obj)
 {
     obj = CheckedUnwrap(obj);
     if (!obj)
         return nullptr;
     TypedArrayObject *tarr = &obj->as<TypedArrayObject>();
-    JS_ASSERT(tarr->type() == ArrayBufferView::TYPE_UINT8_CLAMPED);
+    JS_ASSERT((int32_t) tarr->type() == ArrayBufferView::TYPE_UINT8_CLAMPED);
     return static_cast<uint8_t *>(tarr->viewData());
 }
 
 JS_FRIEND_API(int16_t *)
 JS_GetInt16ArrayData(JSObject *obj)
 {
     obj = CheckedUnwrap(obj);
     if (!obj)
         return nullptr;
     TypedArrayObject *tarr = &obj->as<TypedArrayObject>();
-    JS_ASSERT(tarr->type() == ArrayBufferView::TYPE_INT16);
+    JS_ASSERT((int32_t) tarr->type() == ArrayBufferView::TYPE_INT16);
     return static_cast<int16_t *>(tarr->viewData());
 }
 
 JS_FRIEND_API(uint16_t *)
 JS_GetUint16ArrayData(JSObject *obj)
 {
     obj = CheckedUnwrap(obj);
     if (!obj)
         return nullptr;
     TypedArrayObject *tarr = &obj->as<TypedArrayObject>();
-    JS_ASSERT(tarr->type() == ArrayBufferView::TYPE_UINT16);
+    JS_ASSERT((int32_t) tarr->type() == ArrayBufferView::TYPE_UINT16);
     return static_cast<uint16_t *>(tarr->viewData());
 }
 
 JS_FRIEND_API(int32_t *)
 JS_GetInt32ArrayData(JSObject *obj)
 {
     obj = CheckedUnwrap(obj);
     if (!obj)
         return nullptr;
     TypedArrayObject *tarr = &obj->as<TypedArrayObject>();
-    JS_ASSERT(tarr->type() == ArrayBufferView::TYPE_INT32);
+    JS_ASSERT((int32_t) tarr->type() == ArrayBufferView::TYPE_INT32);
     return static_cast<int32_t *>(tarr->viewData());
 }
 
 JS_FRIEND_API(uint32_t *)
 JS_GetUint32ArrayData(JSObject *obj)
 {
     obj = CheckedUnwrap(obj);
     if (!obj)
         return nullptr;
     TypedArrayObject *tarr = &obj->as<TypedArrayObject>();
-    JS_ASSERT(tarr->type() == ArrayBufferView::TYPE_UINT32);
+    JS_ASSERT((int32_t) tarr->type() == ArrayBufferView::TYPE_UINT32);
     return static_cast<uint32_t *>(tarr->viewData());
 }
 
 JS_FRIEND_API(float *)
 JS_GetFloat32ArrayData(JSObject *obj)
 {
     obj = CheckedUnwrap(obj);
     if (!obj)
         return nullptr;
     TypedArrayObject *tarr = &obj->as<TypedArrayObject>();
-    JS_ASSERT(tarr->type() == ArrayBufferView::TYPE_FLOAT32);
+    JS_ASSERT((int32_t) tarr->type() == ArrayBufferView::TYPE_FLOAT32);
     return static_cast<float *>(tarr->viewData());
 }
 
 JS_FRIEND_API(double *)
 JS_GetFloat64ArrayData(JSObject *obj)
 {
     obj = CheckedUnwrap(obj);
     if (!obj)
         return nullptr;
     TypedArrayObject *tarr = &obj->as<TypedArrayObject>();
-    JS_ASSERT(tarr->type() == ArrayBufferView::TYPE_FLOAT64);
+    JS_ASSERT((int32_t) tarr->type() == ArrayBufferView::TYPE_FLOAT64);
     return static_cast<double *>(tarr->viewData());
 }
 
 JS_FRIEND_API(bool)
 JS_IsDataViewObject(JSObject *obj)
 {
     obj = CheckedUnwrap(obj);
     return obj ? obj->is<DataViewObject>() : false;
--- a/js/src/vm/TypedArrayObject.h
+++ b/js/src/vm/TypedArrayObject.h
@@ -26,20 +26,19 @@ namespace js {
  * the subclasses.
  */
 
 class TypedArrayObject : public ArrayBufferViewObject
 {
   protected:
     // Typed array properties stored in slots, beyond those shared by all
     // ArrayBufferViews.
-    static const size_t LENGTH_SLOT    = JS_TYPEDOBJ_SLOT_LENGTH;
-    static const size_t TYPE_SLOT      = JS_TYPEDOBJ_SLOT_TYPE_DESCR;
-    static const size_t RESERVED_SLOTS = JS_TYPEDOBJ_SLOTS;
-    static const size_t DATA_SLOT      = JS_TYPEDOBJ_SLOT_DATA;
+    static const size_t TYPE_SLOT      = JS_TYPEDARR_SLOT_TYPE;
+    static const size_t RESERVED_SLOTS = JS_TYPEDARR_SLOTS;
+    static const size_t DATA_SLOT      = JS_TYPEDARR_SLOT_DATA;
 
     static_assert(js::detail::TypedArrayLengthSlot == LENGTH_SLOT,
                   "bad inlined constant in jsfriendapi.h");
 
   public:
     static const Class classes[ScalarTypeDescr::TYPE_MAX];
     static const Class protoClasses[ScalarTypeDescr::TYPE_MAX];
 
@@ -55,24 +54,29 @@ class TypedArrayObject : public ArrayBuf
     {
         JS_ASSERT(nbytes <= INLINE_BUFFER_LIMIT);
         /* For GGC we need at least one slot in which to store a forwarding pointer. */
         size_t dataSlots = Max(size_t(1), AlignBytes(nbytes, sizeof(Value)) / sizeof(Value));
         JS_ASSERT(nbytes <= dataSlots * sizeof(Value));
         return gc::GetGCObjectKind(FIXED_DATA_START + dataSlots);
     }
 
+    ScalarTypeDescr::Type type() const {
+        return (ScalarTypeDescr::Type) getFixedSlot(TYPE_SLOT).toInt32();
+    }
+
     static Value bufferValue(TypedArrayObject *tarr) {
         return tarr->getFixedSlot(BUFFER_SLOT);
     }
     static Value byteOffsetValue(TypedArrayObject *tarr) {
         return tarr->getFixedSlot(BYTEOFFSET_SLOT);
     }
     static Value byteLengthValue(TypedArrayObject *tarr) {
-        return tarr->getFixedSlot(BYTELENGTH_SLOT);
+        int32_t size = ScalarTypeDescr::size(tarr->type());
+        return Int32Value(tarr->getFixedSlot(LENGTH_SLOT).toInt32() * size);
     }
     static Value lengthValue(TypedArrayObject *tarr) {
         return tarr->getFixedSlot(LENGTH_SLOT);
     }
 
     static bool
     ensureHasBuffer(JSContext *cx, Handle<TypedArrayObject *> tarray);
 
@@ -90,19 +94,16 @@ class TypedArrayObject : public ArrayBuf
     }
     uint32_t byteLength() const {
         return byteLengthValue(const_cast<TypedArrayObject*>(this)).toInt32();
     }
     uint32_t length() const {
         return lengthValue(const_cast<TypedArrayObject*>(this)).toInt32();
     }
 
-    uint32_t type() const {
-        return getFixedSlot(TYPE_SLOT).toInt32();
-    }
     void *viewData() const {
         // Keep synced with js::Get<Type>ArrayLengthAndData in jsfriendapi.h!
         return static_cast<void*>(getPrivate(DATA_SLOT));
     }
 
     Value getElement(uint32_t index);
     static void setElement(TypedArrayObject &obj, uint32_t index, double d);
 
@@ -135,16 +136,18 @@ class TypedArrayObject : public ArrayBuf
     /*
      * Byte length above which created typed arrays and data views will have
      * singleton types regardless of the context in which they are created.
      */
     static const uint32_t SINGLETON_TYPE_BYTE_LENGTH = 1024 * 1024 * 10;
 
     static int lengthOffset();
     static int dataOffset();
+
+    static bool isOriginalLengthGetter(ScalarTypeDescr::Type type, Native native);
 };
 
 inline bool
 IsTypedArrayClass(const Class *clasp)
 {
     return &TypedArrayObject::classes[0] <= clasp &&
            clasp < &TypedArrayObject::classes[ScalarTypeDescr::TYPE_MAX];
 }
@@ -213,17 +216,17 @@ TypedArrayShift(ArrayBufferView::ViewTyp
       default:;
     }
     MOZ_ASSUME_UNREACHABLE("Unexpected array type");
 }
 
 class DataViewObject : public ArrayBufferViewObject
 {
     static const size_t RESERVED_SLOTS = JS_DATAVIEW_SLOTS;
-    static const size_t DATA_SLOT      = JS_TYPEDOBJ_SLOT_DATA;
+    static const size_t DATA_SLOT      = JS_DATAVIEW_SLOT_DATA;
 
   private:
     static const Class protoClass;
 
     static bool is(HandleValue v) {
         return v.isObject() && v.toObject().hasClass(&class_);
     }
 
@@ -248,17 +251,17 @@ class DataViewObject : public ArrayBuffe
 
     static Value byteOffsetValue(DataViewObject *view) {
         Value v = view->getReservedSlot(BYTEOFFSET_SLOT);
         JS_ASSERT(v.toInt32() >= 0);
         return v;
     }
 
     static Value byteLengthValue(DataViewObject *view) {
-        Value v = view->getReservedSlot(BYTELENGTH_SLOT);
+        Value v = view->getReservedSlot(LENGTH_SLOT);
         JS_ASSERT(v.toInt32() >= 0);
         return v;
     }
 
     static Value bufferValue(DataViewObject *view) {
         return view->getReservedSlot(BUFFER_SLOT);
     }
 
--- a/js/xpconnect/src/XPCJSRuntime.cpp
+++ b/js/xpconnect/src/XPCJSRuntime.cpp
@@ -76,16 +76,17 @@ const char* const XPCJSRuntime::mStrings
     "prototype",            // IDX_PROTOTYPE
     "createInstance",       // IDX_CREATE_INSTANCE
     "item",                 // IDX_ITEM
     "__proto__",            // IDX_PROTO
     "__iterator__",         // IDX_ITERATOR
     "__exposedProps__",     // IDX_EXPOSEDPROPS
     "eval",                 // IDX_EVAL
     "controllers",           // IDX_CONTROLLERS
+    "realFrameElement",     // IDX_REALFRAMEELEMENT
 };
 
 /***************************************************************************/
 
 static mozilla::Atomic<bool> sDiscardSystemSource(false);
 
 bool
 xpc::ShouldDiscardSystemSource() { return sDiscardSystemSource; }
@@ -1380,16 +1381,21 @@ XPCJSRuntime::InterruptCallback(JSContex
 
     // If this is the first time the interrupt callback has fired since we last
     // returned to the event loop, mark the checkpoint.
     if (self->mSlowScriptCheckpoint.IsNull()) {
         self->mSlowScriptCheckpoint = TimeStamp::NowLoRes();
         return true;
     }
 
+    // Sometimes we get called back during XPConnect initialization, before Gecko
+    // has finished bootstrapping. Avoid crashing in nsContentUtils below.
+    if (!nsContentUtils::IsInitialized())
+        return true;
+
     // This is at least the second interrupt callback we've received since
     // returning to the event loop. See how long it's been, and what the limit
     // is.
     TimeDuration duration = TimeStamp::NowLoRes() - self->mSlowScriptCheckpoint;
     bool chrome = nsContentUtils::IsCallerChrome();
     const char *prefName = chrome ? "dom.max_chrome_script_run_time"
                                   : "dom.max_script_run_time";
     int32_t limit = Preferences::GetInt(prefName, chrome ? 20 : 10);
--- a/js/xpconnect/src/xpcprivate.h
+++ b/js/xpconnect/src/xpcprivate.h
@@ -474,16 +474,17 @@ public:
         IDX_PROTOTYPE               ,
         IDX_CREATE_INSTANCE         ,
         IDX_ITEM                    ,
         IDX_PROTO                   ,
         IDX_ITERATOR                ,
         IDX_EXPOSEDPROPS            ,
         IDX_EVAL                    ,
         IDX_CONTROLLERS             ,
+        IDX_REALFRAMEELEMENT        ,
         IDX_TOTAL_COUNT // just a count of the above
     };
 
     JS::HandleId GetStringID(unsigned index) const
     {
         MOZ_ASSERT(index < IDX_TOTAL_COUNT, "index out of range");
         // fromMarkedLocation() is safe because the string is interned.
         return JS::HandleId::fromMarkedLocation(&mStrIDs[index]);
--- a/js/xpconnect/wrappers/XrayWrapper.cpp
+++ b/js/xpconnect/wrappers/XrayWrapper.cpp
@@ -5,16 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "XrayWrapper.h"
 #include "AccessCheck.h"
 #include "WrapperFactory.h"
 
 #include "nsIContent.h"
 #include "nsIControllers.h"
+#include "mozilla/dom/Element.h"
 #include "nsContentUtils.h"
 
 #include "XPCWrapper.h"
 #include "xpcprivate.h"
 
 #include "jsapi.h"
 #include "jsprf.h"
 #include "nsJSUtils.h"
@@ -1085,16 +1086,38 @@ XPCWrappedNativeXrayTraits::resolveNativ
             JS_ReportError(cx, "Failed to invoke GetControllers via Xrays");
             return false;
         }
 
         desc.object().set(wrapper);
         return true;
     }
 
+    // The |realFrameElement| property is accessible as a [ChromeOnly] property
+    // on Window.WebIDL, and [noscript] in XPIDL. Chrome needs to see this over
+    // Xray, so we need to special-case it until we move |Window| to WebIDL.
+    if (id == GetRTIdByIndex(cx, XPCJSRuntime::IDX_REALFRAMEELEMENT) &&
+        AccessCheck::isChrome(wrapper) &&
+        (win = AsWindow(cx, wrapper)))
+    {
+        ErrorResult rv;
+        Element* f = win->GetRealFrameElement(rv);
+        if (!f) {
+          desc.object().set(nullptr);
+          return true;
+        }
+
+        if (!WrapNewBindingObject(cx, f, desc.value())) {
+          return false;
+        }
+
+        desc.object().set(wrapper);
+        return true;
+    }
+
     XPCNativeInterface *iface;
     XPCNativeMember *member;
     XPCWrappedNative *wn = getWN(wrapper);
 
     if (ccx.GetWrapper() != wn || !wn->IsValid()) {
         // Something is wrong. If the wrapper is not even valid let's not risk
         // calling resolveDOMCollectionProperty.
         return true;
new file mode 100644
--- /dev/null
+++ b/layout/base/SelectionCarets.cpp
@@ -0,0 +1,883 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 sw=2 et tw=78: */
+/* 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 "SelectionCarets.h"
+
+#include "gfxPrefs.h"
+#include "nsBidiPresUtils.h"
+#include "nsCanvasFrame.h"
+#include "nsCaret.h"
+#include "nsContentUtils.h"
+#include "nsDebug.h"
+#include "nsDOMTokenList.h"
+#include "nsFrame.h"
+#include "nsIDocument.h"
+#include "nsIDocShell.h"
+#include "nsIDOMDocument.h"
+#include "nsIDOMNodeFilter.h"
+#include "nsIPresShell.h"
+#include "nsPresContext.h"
+#include "nsRect.h"
+#include "nsView.h"
+#include "mozilla/dom/DOMRect.h"
+#include "mozilla/dom/Element.h"
+#include "mozilla/dom/Selection.h"
+#include "mozilla/dom/TreeWalker.h"
+#include "mozilla/Preferences.h"
+#include "mozilla/TouchEvents.h"
+#include "TouchCaret.h"
+
+using namespace mozilla;
+
+// We treat mouse/touch move as "REAL" move event once its move distance
+// exceed this value, in CSS pixel.
+static const int32_t kMoveStartTolerancePx = 5;
+// Time for trigger scroll end event, in miliseconds.
+static const int32_t kScrollEndTimerDelay = 300;
+
+NS_IMPL_ISUPPORTS(SelectionCarets,
+                  nsISelectionListener,
+                  nsIScrollObserver,
+                  nsISupportsWeakReference)
+
+/*static*/ int32_t SelectionCarets::sSelectionCaretsInflateSize = 0;
+
+SelectionCarets::SelectionCarets(nsIPresShell *aPresShell)
+  : mActiveTouchId(-1)
+  , mCaretCenterToDownPointOffsetY(0)
+  , mDragMode(NONE)
+  , mVisible(false)
+  , mStartCaretVisible(false)
+  , mEndCaretVisible(false)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  static bool addedPref = false;
+  if (!addedPref) {
+    Preferences::AddIntVarCache(&sSelectionCaretsInflateSize,
+                                "selectioncaret.inflatesize.threshold");
+    addedPref = true;
+  }
+
+  mPresShell = aPresShell;
+}
+
+SelectionCarets::~SelectionCarets()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  if (mLongTapDetectorTimer) {
+    mLongTapDetectorTimer->Cancel();
+    mLongTapDetectorTimer = nullptr;
+  }
+
+  if (mScrollEndDetectorTimer) {
+    mScrollEndDetectorTimer->Cancel();
+    mScrollEndDetectorTimer = nullptr;
+  }
+
+  mPresShell = nullptr;
+}
+
+static bool
+IsOnRect(const nsRect& aRect,
+         const nsPoint& aPoint,
+         int32_t aInflateSize)
+{
+  // Check if the click was in the bounding box of the selection caret
+  nsRect rect = aRect;
+  rect.Inflate(aInflateSize);
+  return rect.Contains(aPoint);
+}
+
+nsEventStatus
+SelectionCarets::HandleEvent(WidgetEvent* aEvent)
+{
+  WidgetMouseEvent *mouseEvent = aEvent->AsMouseEvent();
+  if (mouseEvent && mouseEvent->reason == WidgetMouseEvent::eSynthesized) {
+    return nsEventStatus_eIgnore;
+  }
+
+  WidgetTouchEvent *touchEvent = aEvent->AsTouchEvent();
+  nsIntPoint movePoint;
+  int32_t nowTouchId = -1;
+  if (touchEvent && !touchEvent->touches.IsEmpty()) {
+    // If touch happened, just grab event with same identifier
+    if (mActiveTouchId >= 0) {
+      for (uint32_t i = 0; i < touchEvent->touches.Length(); ++i) {
+        if (touchEvent->touches[i]->Identifier() == mActiveTouchId) {
+          movePoint = touchEvent->touches[i]->mRefPoint;
+          nowTouchId = touchEvent->touches[i]->Identifier();
+          break;
+        }
+      }
+
+      // not found, consume it
+      if (nowTouchId == -1) {
+        return nsEventStatus_eConsumeNoDefault;
+      }
+    } else {
+      movePoint = touchEvent->touches[0]->mRefPoint;
+      nowTouchId = touchEvent->touches[0]->Identifier();
+    }
+  } else if (mouseEvent) {
+    movePoint = LayoutDeviceIntPoint::ToUntyped(mouseEvent->AsGUIEvent()->refPoint);
+  }
+
+  // Get event coordinate relative to canvas frame
+  nsIFrame* canvasFrame = mPresShell->GetCanvasFrame();
+  if (!canvasFrame) {
+    return nsEventStatus_eIgnore;
+  }
+  nsPoint ptInCanvas =
+    nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, movePoint, canvasFrame);
+
+  if (aEvent->message == NS_TOUCH_START ||
+      (aEvent->message == NS_MOUSE_BUTTON_DOWN &&
+       mouseEvent->button == WidgetMouseEvent::eLeftButton)) {
+    // If having a active touch, ignore other touch down event
+    if (aEvent->message == NS_TOUCH_START && mActiveTouchId >= 0) {
+      return nsEventStatus_eConsumeNoDefault;
+    }
+
+    mActiveTouchId = nowTouchId;
+    mDownPoint = ptInCanvas;
+    int32_t inflateSize = SelectionCaretsInflateSize();
+    if (mVisible && IsOnRect(GetStartFrameRect(), ptInCanvas, inflateSize)) {
+      mDragMode = START_FRAME;
+      mCaretCenterToDownPointOffsetY = GetCaretYCenterPosition() - ptInCanvas.y;
+      SetSelectionDirection(false);
+      SetMouseDownState(true);
+      return nsEventStatus_eConsumeNoDefault;
+    } else if (mVisible && IsOnRect(GetEndFrameRect(), ptInCanvas, inflateSize)) {
+      mDragMode = END_FRAME;
+      mCaretCenterToDownPointOffsetY = GetCaretYCenterPosition() - ptInCanvas.y;
+      SetSelectionDirection(true);
+      SetMouseDownState(true);
+      return nsEventStatus_eConsumeNoDefault;
+    } else {
+      mDragMode = NONE;
+      mActiveTouchId = -1;
+      SetVisibility(false);
+      LaunchLongTapDetector();
+    }
+  } else if (aEvent->message == NS_TOUCH_END ||
+             aEvent->message == NS_TOUCH_CANCEL ||
+             aEvent->message == NS_MOUSE_BUTTON_UP) {
+    CancelLongTapDetector();
+    if (mDragMode != NONE) {
+      // Only care about same id
+      if (mActiveTouchId == nowTouchId) {
+        SetMouseDownState(false);
+        mDragMode = NONE;
+        mActiveTouchId = -1;
+      }
+      return nsEventStatus_eConsumeNoDefault;
+    }
+  } else if (aEvent->message == NS_TOUCH_MOVE ||
+             aEvent->message == NS_MOUSE_MOVE) {
+    if (mDragMode == START_FRAME || mDragMode == END_FRAME) {
+      if (mActiveTouchId == nowTouchId) {
+        ptInCanvas.y += mCaretCenterToDownPointOffsetY;
+        return DragSelection(ptInCanvas);
+      }
+
+      return nsEventStatus_eConsumeNoDefault;
+    }
+
+    nsPoint delta = mDownPoint - ptInCanvas;
+    if (NS_hypot(delta.x, delta.y) >
+          nsPresContext::AppUnitsPerCSSPixel() * kMoveStartTolerancePx) {
+      CancelLongTapDetector();
+    }
+  } else if (aEvent->message == NS_MOUSE_MOZLONGTAP) {
+    if (!mVisible) {
+      SelectWord();
+      return nsEventStatus_eConsumeNoDefault;
+    }
+  }
+  return nsEventStatus_eIgnore;
+}
+
+static void
+SetElementVisibility(dom::Element* aElement, bool aVisible)
+{
+  NS_ENSURE_TRUE_VOID(aElement);
+  ErrorResult err;
+  aElement->ClassList()->Toggle(NS_LITERAL_STRING("hidden"),
+                                   dom::Optional<bool>(!aVisible), err);
+}
+
+void
+SelectionCarets::SetVisibility(bool aVisible)
+{
+  if (!mPresShell) {
+    return;
+  }
+
+  if (mVisible == aVisible) {
+    return;
+  }
+  mVisible = aVisible;
+
+  dom::Element* startElement = mPresShell->GetSelectionCaretsStartElement();
+  SetElementVisibility(startElement, mVisible && mStartCaretVisible);
+
+  dom::Element* endElement = mPresShell->GetSelectionCaretsEndElement();
+  SetElementVisibility(endElement, mVisible && mEndCaretVisible);
+
+  // We must call SetHasTouchCaret() in order to get APZC to wait until the
+  // event has been round-tripped and check whether it has been handled,
+  // otherwise B2G will end up panning the document when the user tries to drag
+  // selection caret.
+  mPresShell->SetMayHaveTouchCaret(mVisible);
+}
+
+void
+SelectionCarets::SetStartFrameVisibility(bool aVisible)
+{
+  mStartCaretVisible = aVisible;
+  dom::Element* element = mPresShell->GetSelectionCaretsStartElement();
+  SetElementVisibility(element, mVisible && mStartCaretVisible);
+}
+
+void
+SelectionCarets::SetEndFrameVisibility(bool aVisible)
+{
+  mEndCaretVisible = aVisible;
+  dom::Element* element = mPresShell->GetSelectionCaretsEndElement();
+  SetElementVisibility(element, mVisible && mEndCaretVisible);
+}
+
+void
+SelectionCarets::SetTilted(bool aIsTilt)
+{
+  dom::Element* startElement = mPresShell->GetSelectionCaretsStartElement();
+  dom::Element* endElement = mPresShell->GetSelectionCaretsEndElement();
+  NS_ENSURE_TRUE_VOID(startElement && endElement);
+
+  ErrorResult err;
+  startElement->ClassList()->Toggle(NS_LITERAL_STRING("tilt"),
+                                       dom::Optional<bool>(aIsTilt), err);
+
+  endElement->ClassList()->Toggle(NS_LITERAL_STRING("tilt"),
+                                     dom::Optional<bool>(aIsTilt), err);
+}
+
+static void
+SetCaretDirection(dom::Element* aElement, bool aIsRight)
+{
+  MOZ_ASSERT(aElement);
+
+  ErrorResult err;
+  if (aIsRight) {
+    aElement->ClassList()->Add(NS_LITERAL_STRING("moz-selectioncaret-right"), err);
+    aElement->ClassList()->Remove(NS_LITERAL_STRING("moz-selectioncaret-left"), err);
+  } else {
+    aElement->ClassList()->Add(NS_LITERAL_STRING("moz-selectioncaret-left"), err);
+    aElement->ClassList()->Remove(NS_LITERAL_STRING("moz-selectioncaret-right"), err);
+  }
+}
+
+static bool
+IsRightToLeft(nsIFrame* aFrame)
+{
+  MOZ_ASSERT(aFrame);
+
+  return aFrame->IsFrameOfType(nsIFrame::eLineParticipant) ?
+    (nsBidiPresUtils::GetFrameEmbeddingLevel(aFrame) & 1) :
+    aFrame->StyleVisibility()->mDirection == NS_STYLE_DIRECTION_RTL;
+}
+
+/*
+ * Reduce rect to 1 app unit width along either left or right edge base on
+ * aToRightEdge parameter.
+ */
+static void
+ReduceRectToVerticalEdge(nsRect& aRect, bool aToRightEdge)
+{
+  if (aToRightEdge) {
+    aRect.x = aRect.XMost() - 1;
+  }
+  aRect.width = 1;
+}
+
+static nsIFrame*
+FindFirstNodeWithFrame(nsIDocument* aDocument,
+                       nsRange* aRange,
+                       nsFrameSelection* aFrameSelection,
+                       bool aBackward,
+                       int& aOutOffset)
+{
+  NS_ENSURE_TRUE(aDocument && aRange && aFrameSelection, nullptr);
+
+  nsCOMPtr<nsINode> startNode =
+    do_QueryInterface(aBackward ? aRange->GetEndParent() : aRange->GetStartParent());
+  nsCOMPtr<nsINode> endNode =
+    do_QueryInterface(aBackward ? aRange->GetStartParent() : aRange->GetEndParent());
+  int32_t offset = aBackward ? aRange->EndOffset() : aRange->StartOffset();
+
+  nsCOMPtr<nsIContent> startContent = do_QueryInterface(startNode);
+  nsCOMPtr<nsIContent> endContent = do_QueryInterface(endNode);
+  nsFrameSelection::HINT hintStart =
+    nsFrameSelection::GetHintForPosition(startContent, offset);
+  nsIFrame* startFrame = aFrameSelection->GetFrameForNodeOffset(startContent,
+                                                                offset,
+                                                                hintStart,
+                                                                &aOutOffset);
+
+  if (startFrame) {
+    return startFrame;
+  }
+
+  ErrorResult err;
+  nsRefPtr<dom::TreeWalker> walker =
+    aDocument->CreateTreeWalker(*startNode,
+                                nsIDOMNodeFilter::SHOW_ALL,
+                                nullptr,
+                                err);
+
+  NS_ENSURE_TRUE(walker, nullptr);
+  startFrame = startContent ? startContent->GetPrimaryFrame() : nullptr;
+  while (!startFrame && startNode != endNode) {
+    if (aBackward) {
+      startNode = walker->PreviousNode(err);
+    } else {
+      startNode = walker->NextNode(err);
+    }
+    startContent = do_QueryInterface(startNode);
+    startFrame = startContent ? startContent->GetPrimaryFrame() : nullptr;
+  }
+  return startFrame;
+}
+
+void
+SelectionCarets::UpdateSelectionCarets()
+{
+  if (!mPresShell) {
+    return;
+  }
+
+  nsISelection* caretSelection = GetSelection();
+  if (!caretSelection) {
+    SetVisibility(false);
+    return;
+  }
+
+  nsRefPtr<dom::Selection> selection = static_cast<dom::Selection*>(caretSelection);
+  if (selection->GetRangeCount() <= 0) {
+    SetVisibility(false);
+    return;
+  }
+
+  nsRefPtr<nsRange> range = selection->GetRangeAt(0);
+  if (range->Collapsed()) {
+    SetVisibility(false);
+    return;
+  }
+
+  nsLayoutUtils::FirstAndLastRectCollector collector;
+  nsRange::CollectClientRects(&collector, range,
+                              range->GetStartParent(), range->StartOffset(),
+                              range->GetEndParent(), range->EndOffset());
+
+  nsIFrame* canvasFrame = mPresShell->GetCanvasFrame();
+  nsIFrame* rootFrame = mPresShell->GetRootFrame();
+
+  if (!canvasFrame || !rootFrame) {
+    SetVisibility(false);
+    return;
+  }
+
+  // Check if caret inside the scroll frame's boundary
+  nsIFrame* caretFocusFrame = GetCaretFocusFrame();
+  if (!caretFocusFrame) {
+    SetVisibility(false);
+    return;
+  }
+  nsIContent *editableAncestor = caretFocusFrame->GetContent()->GetEditingHost();
+
+  if (!editableAncestor) {
+    SetVisibility(false);
+    return;
+  }
+
+  nsRect resultRect;
+  for (nsIFrame* frame = editableAncestor->GetPrimaryFrame();
+      frame != nullptr;
+      frame = frame->GetNextContinuation()) {
+    nsRect rect = frame->GetRectRelativeToSelf();
+    nsLayoutUtils::TransformRect(frame, rootFrame, rect);
+    resultRect = resultRect.Union(rect);
+  }
+
+  // Check start and end frame is rtl or ltr text
+  nsRefPtr<nsFrameSelection> fs = caretFocusFrame->GetFrameSelection();
+  int32_t startOffset;
+  nsIFrame* startFrame = FindFirstNodeWithFrame(mPresShell->GetDocument(),
+                                                range, fs, false, startOffset);
+
+  int32_t endOffset;
+  nsIFrame* endFrame = FindFirstNodeWithFrame(mPresShell->GetDocument(),
+                                              range, fs, true, endOffset);
+
+  if (!startFrame || !endFrame) {
+    SetVisibility(false);
+    return;
+  }
+
+  // Check if startFrame is after endFrame.
+  if (nsLayoutUtils::CompareTreePosition(startFrame, endFrame) > 0) {
+    SetVisibility(false);
+    return;
+  }
+
+  bool startFrameIsRTL = IsRightToLeft(startFrame);
+  bool endFrameIsRTL = IsRightToLeft(endFrame);
+
+  // If start frame is LTR, then place start caret in first rect's leftmost
+  // otherwise put it to first rect's rightmost.
+  ReduceRectToVerticalEdge(collector.mFirstRect, startFrameIsRTL);
+
+  // Contrary to start frame, if end frame is LTR, put end caret to last
+  // rect's rightmost position, otherwise, put it to last rect's leftmost.
+  ReduceRectToVerticalEdge(collector.mLastRect, !endFrameIsRTL);
+
+  SetStartFrameVisibility(resultRect.Intersects(collector.mFirstRect));
+  SetEndFrameVisibility(resultRect.Intersects(collector.mLastRect));
+
+  nsLayoutUtils::TransformRect(rootFrame, canvasFrame, collector.mFirstRect);
+  nsLayoutUtils::TransformRect(rootFrame, canvasFrame, collector.mLastRect);
+
+  SetStartFramePos(collector.mFirstRect.BottomLeft());
+  SetEndFramePos(collector.mLastRect.BottomRight());
+  SetVisibility(true);
+
+  // If range select only one character, append tilt class name to it.
+  bool isTilt = false;
+  if (startFrame) {
+    nsPeekOffsetStruct pos(eSelectCluster,
+                           eDirNext,
+                           startOffset,
+                           0,
+                           false,
+                           true,  //limit on scrolled views
+                           false,
+                           false);
+    startFrame->PeekOffset(&pos);
+    nsCOMPtr<nsIContent> endContent = do_QueryInterface(range->GetEndParent());
+    if (nsLayoutUtils::CompareTreePosition(pos.mResultContent, endContent) > 0 ||
+        (pos.mResultContent == endContent &&
+         pos.mContentOffset >= range->EndOffset())) {
+      isTilt = true;
+    }
+  }
+
+  SetCaretDirection(mPresShell->GetSelectionCaretsStartElement(), startFrameIsRTL);
+  SetCaretDirection(mPresShell->GetSelectionCaretsEndElement(), !endFrameIsRTL);
+  SetTilted(isTilt);
+}
+
+nsresult
+SelectionCarets::SelectWord()
+{
+  // If caret isn't visible, the word is not selectable
+  if (!GetCaretVisible()) {
+    return NS_OK;
+  }
+
+  NS_ENSURE_TRUE(mPresShell, NS_OK);
+
+  nsIFrame* canvasFrame = mPresShell->GetCanvasFrame();
+  NS_ENSURE_TRUE(canvasFrame, NS_OK);
+
+  // Find content offsets for mouse down point
+  nsIFrame *ptFrame = nsLayoutUtils::GetFrameForPoint(canvasFrame, mDownPoint,
+    nsLayoutUtils::IGNORE_PAINT_SUPPRESSION | nsLayoutUtils::IGNORE_CROSS_DOC);
+  NS_ENSURE_TRUE(ptFrame, NS_OK);
+  nsPoint ptInFrame = mDownPoint;
+  nsLayoutUtils::TransformPoint(canvasFrame, ptFrame, ptInFrame);
+
+  nsIFrame* caretFocusFrame = GetCaretFocusFrame();
+  nsRefPtr<nsFrameSelection> fs = caretFocusFrame->GetFrameSelection();
+  fs->SetMouseDownState(true);
+  nsFrame* frame = static_cast<nsFrame*>(ptFrame);
+  nsresult rs = frame->SelectByTypeAtPoint(mPresShell->GetPresContext(), ptInFrame,
+                                           eSelectWord, eSelectWord, 0);
+  fs->SetMouseDownState(false);
+
+  // Clear maintain selection otherwise we cannot select less than a word
+  fs->MaintainSelection();
+  return rs;
+}
+
+/*
+ * If we're dragging start caret, we do not want to drag over previous
+ * character of end caret. Same as end caret. So we check if content offset
+ * exceed previous/next character of end/start caret base on aDragMode.
+ */
+static bool
+CompareRangeWithContentOffset(nsRange* aRange,
+                              nsFrameSelection* aSelection,
+                              nsIFrame::ContentOffsets& aOffsets,
+                              SelectionCarets::DragMode aDragMode)
+{
+  MOZ_ASSERT(aDragMode != SelectionCarets::NONE);
+  nsINode* node = nullptr;
+  int32_t nodeOffset = 0;
+  nsFrameSelection::HINT hint = nsFrameSelection::HINTLEFT;
+  nsDirection dir;
+
+  if (aDragMode == SelectionCarets::START_FRAME) {
+    // Check previous character of end node offset
+    node = aRange->GetEndParent();
+    nodeOffset = aRange->EndOffset();
+    hint = nsFrameSelection::HINTLEFT;
+    dir = eDirPrevious;
+  } else {
+    // Check next character of start node offset
+    node = aRange->GetStartParent();
+    nodeOffset = aRange->StartOffset();
+    hint = nsFrameSelection::HINTRIGHT;
+    dir = eDirNext;
+  }
+  nsCOMPtr<nsIContent> content = do_QueryInterface(node);
+
+  int32_t offset = 0;
+  nsIFrame* theFrame =
+    aSelection->GetFrameForNodeOffset(content, nodeOffset, hint, &offset);
+
+  NS_ENSURE_TRUE(theFrame, false);
+
+  // Move one character forward/backward from point and get offset
+  nsPeekOffsetStruct pos(eSelectCluster,
+                         dir,
+                         offset,
+                         0,
+                         true,
+                         true,  //limit on scrolled views
+                         false,
+                         false);
+  nsresult rv = theFrame->PeekOffset(&pos);
+  if (NS_FAILED(rv)) {
+    pos.mResultContent = content;
+    pos.mContentOffset = nodeOffset;
+  }
+
+  // Compare with current point
+  int32_t result = nsContentUtils::ComparePoints(aOffsets.content,
+                                                 aOffsets.StartOffset(),
+                                                 pos.mResultContent,
+                                                 pos.mContentOffset);
+  if ((aDragMode == SelectionCarets::START_FRAME && result == 1) ||
+      (aDragMode == SelectionCarets::END_FRAME && result == -1)) {
+    aOffsets.content = pos.mResultContent;
+    aOffsets.offset = pos.mContentOffset;
+    aOffsets.secondaryOffset = pos.mContentOffset;
+  }
+
+  return true;
+}
+
+nsEventStatus
+SelectionCarets::DragSelection(const nsPoint &movePoint)
+{
+  nsIFrame* canvasFrame = mPresShell->GetCanvasFrame();
+  NS_ENSURE_TRUE(canvasFrame, nsEventStatus_eConsumeNoDefault);
+
+  // Find out which content we point to
+  nsIFrame *ptFrame = nsLayoutUtils::GetFrameForPoint(canvasFrame, movePoint,
+    nsLayoutUtils::IGNORE_PAINT_SUPPRESSION | nsLayoutUtils::IGNORE_CROSS_DOC);
+  NS_ENSURE_TRUE(ptFrame, nsEventStatus_eConsumeNoDefault);
+  nsPoint ptInFrame = movePoint;
+  nsLayoutUtils::TransformPoint(canvasFrame, ptFrame, ptInFrame);
+  nsFrame::ContentOffsets offsets =
+    ptFrame->GetContentOffsetsFromPoint(ptInFrame);
+  NS_ENSURE_TRUE(offsets.content, nsEventStatus_eConsumeNoDefault);
+
+  nsISelection* caretSelection = GetSelection();
+  nsRefPtr<dom::Selection> selection = static_cast<dom::Selection*>(caretSelection);
+  if (selection->GetRangeCount() <= 0) {
+    return nsEventStatus_eConsumeNoDefault;
+  }
+
+  nsRefPtr<nsRange> range = selection->GetRangeAt(0);
+  nsIFrame* caretFocusFrame = GetCaretFocusFrame();
+  nsRefPtr<nsFrameSelection> fs = caretFocusFrame->GetFrameSelection();
+  if (!CompareRangeWithContentOffset(range, fs, offsets, mDragMode)) {
+    return nsEventStatus_eConsumeNoDefault;
+  }
+
+  // Move caret postion.
+  nsIFrame *scrollable =
+    nsLayoutUtils::GetClosestFrameOfType(caretFocusFrame, nsGkAtoms::scrollFrame);
+  nsWeakFrame weakScrollable = scrollable;
+  fs->HandleClick(offsets.content, offsets.StartOffset(),
+                  offsets.EndOffset(),
+                  true,
+                  false,
+                  offsets.associateWithNext);
+  if (!weakScrollable.IsAlive()) {
+    return nsEventStatus_eConsumeNoDefault;
+  }
+
+  // Scroll scrolled frame.
+  nsIScrollableFrame *saf = do_QueryFrame(scrollable);
+  nsIFrame *capturingFrame = saf->GetScrolledFrame();
+  nsPoint ptInScrolled = movePoint;
+  nsLayoutUtils::TransformPoint(canvasFrame, capturingFrame, ptInScrolled);
+  fs->StartAutoScrollTimer(capturingFrame, ptInScrolled, TouchCaret::sAutoScrollTimerDelay);
+  UpdateSelectionCarets();
+  return nsEventStatus_eConsumeNoDefault;
+}
+
+nscoord
+SelectionCarets::GetCaretYCenterPosition()
+{
+  nsIFrame* canvasFrame = mPresShell->GetCanvasFrame();
+  nsIFrame* caretFocusFrame = GetCaretFocusFrame();
+
+  if (!canvasFrame || !caretFocusFrame) {
+    return 0;
+  }
+  nsISelection* caretSelection = GetSelection();
+  nsRefPtr<dom::Selection> selection = static_cast<dom::Selection*>(caretSelection);
+  if (selection->GetRangeCount() <= 0) {
+    return 0;
+  }
+  nsRefPtr<nsRange> range = selection->GetRangeAt(0);
+  nsRefPtr<nsFrameSelection> fs = caretFocusFrame->GetFrameSelection();
+
+  MOZ_ASSERT(mDragMode != NONE);
+  nsCOMPtr<nsIContent> node;
+  uint32_t nodeOffset;
+  if (mDragMode == START_FRAME) {
+    node = do_QueryInterface(range->GetStartParent());
+    nodeOffset = range->StartOffset();
+  } else {
+    node = do_QueryInterface(range->GetEndParent());
+    nodeOffset = range->EndOffset();
+  }
+
+  int32_t offset;
+  nsFrameSelection::HINT hint =
+    nsFrameSelection::GetHintForPosition(node, nodeOffset);
+  nsIFrame* theFrame =
+    fs->GetFrameForNodeOffset(node, nodeOffset, hint, &offset);
+
+  if (!theFrame) {
+    return 0;
+  }
+  nsRect frameRect = theFrame->GetRectRelativeToSelf();
+  nsLayoutUtils::TransformRect(theFrame, canvasFrame, frameRect);
+  return frameRect.Center().y;
+}
+
+void
+SelectionCarets::SetMouseDownState(bool aState)
+{
+  nsIFrame* caretFocusFrame = GetCaretFocusFrame();
+  nsRefPtr<nsFrameSelection> fs = caretFocusFrame->GetFrameSelection();
+  if (fs->GetMouseDownState() == aState) {
+    return;
+  }
+  fs->SetMouseDownState(aState);
+
+  if (aState) {
+    fs->StartBatchChanges();
+  } else {
+    fs->EndBatchChanges();
+  }
+}
+
+void
+SelectionCarets::SetSelectionDirection(bool aForward)
+{
+  nsISelection* caretSelection = GetSelection();
+  nsRefPtr<dom::Selection> selection = static_cast<dom::Selection*>(caretSelection);
+  selection->SetDirection(aForward ? eDirNext : eDirPrevious);
+}
+
+static void
+SetFramePos(dom::Element* aElement, const nsPoint& aPosition)
+{
+  NS_ENSURE_TRUE_VOID(aElement);
+
+  nsAutoString styleStr;
+  styleStr.AppendLiteral("left:");
+  styleStr.AppendFloat(nsPresContext::AppUnitsToFloatCSSPixels(aPosition.x));
+  styleStr.AppendLiteral("px;top:");
+  styleStr.AppendFloat(nsPresContext::AppUnitsToFloatCSSPixels(aPosition.y));
+  styleStr.AppendLiteral("px;");
+
+  aElement->SetAttr(kNameSpaceID_None, nsGkAtoms::style, styleStr, true);
+}
+
+void
+SelectionCarets::SetStartFramePos(const nsPoint& aPosition)
+{
+  SetFramePos(mPresShell->GetSelectionCaretsStartElement(), aPosition);
+}
+
+void
+SelectionCarets::SetEndFramePos(const nsPoint& aPosition)
+{
+  SetFramePos(mPresShell->GetSelectionCaretsEndElement(), aPosition);
+}
+
+nsRect
+SelectionCarets::GetStartFrameRect()
+{
+  nsIFrame* canvasFrame = mPresShell->GetCanvasFrame();
+  dom::Element* element = mPresShell->GetSelectionCaretsStartElement();
+  NS_ENSURE_TRUE(element, nsRect());
+
+  nsIFrame* frame = element->GetPrimaryFrame();
+  NS_ENSURE_TRUE(frame, nsRect());
+
+  nsRect frameRect = frame->GetRectRelativeToSelf();
+  nsLayoutUtils::TransformRect(frame, canvasFrame, frameRect);
+  return frameRect;
+}
+
+nsRect
+SelectionCarets::GetEndFrameRect()
+{
+  nsIFrame* canvasFrame = mPresShell->GetCanvasFrame();
+  dom::Element* element = mPresShell->GetSelectionCaretsEndElement();
+  NS_ENSURE_TRUE(element, nsRect());
+
+  nsIFrame* frame = element->GetPrimaryFrame();
+  NS_ENSURE_TRUE(frame, nsRect());
+
+  nsRect frameRect = frame->GetRectRelativeToSelf();
+  nsLayoutUtils::TransformRect(frame, canvasFrame, frameRect);
+  return frameRect;
+}
+
+nsIFrame*
+SelectionCarets::GetCaretFocusFrame()
+{
+  nsRefPtr<nsCaret> caret = mPresShell->GetCaret();
+  NS_ENSURE_TRUE(caret, nullptr);
+
+  nsISelection* caretSelection = caret->GetCaretDOMSelection();
+  nsRect focusRect;
+  return caret->GetGeometry(caretSelection, &focusRect);
+}
+
+bool
+SelectionCarets::GetCaretVisible()
+{
+  NS_ENSURE_TRUE(mPresShell, false);
+  nsRefPtr<nsCaret> caret = mPresShell->GetCaret();
+  NS_ENSURE_TRUE(caret, false);
+
+  bool caretVisible = false;
+  caret->GetCaretVisible(&caretVisible);
+  return caretVisible;
+}
+
+nsISelection*
+SelectionCarets::GetSelection()
+{
+  nsRefPtr<nsCaret> caret = mPresShell->GetCaret();
+  return caret->GetCaretDOMSelection();
+}
+
+nsresult
+SelectionCarets::NotifySelectionChanged(nsIDOMDocument* aDoc,
+                                       nsISelection* aSel,
+                                       int16_t aReason)
+{
+  bool isCollapsed;
+  aSel->GetIsCollapsed(&isCollapsed);
+  if (isCollapsed) {
+    SetVisibility(false);
+    return NS_OK;
+  }
+  if (aReason & nsISelectionListener::KEYPRESS_REASON) {
+    SetVisibility(false);
+  } else {
+    UpdateSelectionCarets();
+  }
+  return NS_OK;
+}
+
+void
+SelectionCarets::ScrollPositionChanged()
+{
+  SetVisibility(false);
+  LaunchScrollEndDetector();
+}
+
+void
+SelectionCarets::LaunchLongTapDetector()
+{
+  if (XRE_GetProcessType() != GeckoProcessType_Default) {
+    return;
+  }
+
+  if (!mLongTapDetectorTimer) {
+    mLongTapDetectorTimer = do_CreateInstance("@mozilla.org/timer;1");
+  }
+
+  MOZ_ASSERT(mLongTapDetectorTimer);
+  CancelLongTapDetector();
+  int32_t longTapDelay = gfxPrefs::UiClickHoldContextMenusDelay();
+  mLongTapDetectorTimer->InitWithFuncCallback(FireLongTap,
+                                              this,
+                                              longTapDelay,
+                                              nsITimer::TYPE_ONE_SHOT);
+}
+
+void
+SelectionCarets::CancelLongTapDetector()
+{
+  if (XRE_GetProcessType() != GeckoProcessType_Default) {
+    return;
+  }
+
+  if (!mLongTapDetectorTimer) {
+    return;
+  }
+
+  mLongTapDetectorTimer->Cancel();
+}
+
+/* static */void
+SelectionCarets::FireLongTap(nsITimer* aTimer, void* aSelectionCarets)
+{
+  nsRefPtr<SelectionCarets> self = static_cast<SelectionCarets*>(aSelectionCarets);
+  NS_PRECONDITION(aTimer == self->mLongTapDetectorTimer,
+                  "Unexpected timer");
+
+  self->SelectWord();
+}
+
+void
+SelectionCarets::LaunchScrollEndDetector()
+{
+  if (!mScrollEndDetectorTimer) {
+    mScrollEndDetectorTimer = do_CreateInstance("@mozilla.org/timer;1");
+  }
+
+  MOZ_ASSERT(mScrollEndDetectorTimer);
+  mScrollEndDetectorTimer->InitWithFuncCallback(FireScrollEnd,
+                                                this,
+                                                kScrollEndTimerDelay,
+                                                nsITimer::TYPE_ONE_SHOT);
+}
+
+/* static */void
+SelectionCarets::FireScrollEnd(nsITimer* aTimer, void* aSelectionCarets)
+{
+  nsRefPtr<SelectionCarets> self = static_cast<SelectionCarets*>(aSelectionCarets);
+  NS_PRECONDITION(aTimer == self->mScrollEndDetectorTimer,
+                  "Unexpected timer");
+  self->SetVisibility(true);
+  self->UpdateSelectionCarets();
+}
new file mode 100644
--- /dev/null
+++ b/layout/base/SelectionCarets.h
@@ -0,0 +1,215 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 sw=2 et tw=78: */
+/* 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 SelectionCarets_h__
+#define SelectionCarets_h__
+
+#include "nsIScrollObserver.h"
+#include "nsISelectionListener.h"
+#include "nsWeakPtr.h"
+#include "nsWeakReference.h"
+#include "Units.h"
+#include "mozilla/EventForwards.h"
+
+class nsCanvasFrame;
+class nsIDocument;
+class nsIFrame;
+class nsIPresShell;
+class nsITimer;
+class nsIWidget;
+class nsPresContext;
+
+namespace mozilla {
+
+/**
+ * The SelectionCarets draw a pair of carets when the selection is not
+ * collapsed, one at each end of the selection.
+ * SelectionCarets also handle visibility, dragging caret and selecting word
+ * when long tap event fired.
+ *
+ * The DOM structure is 2 div elements for showing start and end caret.
+ *
+ * Here is an explanation of the html class names:
+ *   .moz-selectioncaret-left: Indicates start DIV.
+ *   .moz-selectioncaret-right: Indicates end DIV.
+ *   .hidden: This class name is set by SetVisibility,
+ *            SetStartFrameVisibility and SetEndFrameVisibility. Element
+ *            with this class name become hidden.
+ *   .tilt: This class name is set by SetTilted. According to the
+ *          UX spec, when selection contains only one characters, the image of
+ *          caret becomes tilt.
+ */
+class SelectionCarets MOZ_FINAL : public nsISelectionListener,
+                                  public nsIScrollObserver,
+                                  public nsSupportsWeakReference
+{
+public:
+  /**
+   * Indicate which part of caret we are dragging at.
+   */
+  enum DragMode {
+    NONE,
+    START_FRAME,
+    END_FRAME
+  };
+
+  explicit SelectionCarets(nsIPresShell *aPresShell);
+  virtual ~SelectionCarets();
+
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSISELECTIONLISTENER
+
+  // nsIScrollObserver
+  virtual void ScrollPositionChanged() MOZ_OVERRIDE;
+
+  void Terminate()
+  {
+    mPresShell = nullptr;
+  }
+
+  nsEventStatus HandleEvent(WidgetEvent* aEvent);
+
+  /**
+   * Set visibility for selection caret.
+   */
+  void SetVisibility(bool aVisible);
+
+  bool GetVisibility() const
+  {
+    return mVisible;
+  }
+
+  /**
+   * Get from pref "selectioncaret.inflatesize.threshold". This will inflate size of
+   * caret frame when we checking if user click on caret or not. In app units.
+   */
+  static int32_t SelectionCaretsInflateSize()
+  {
+    return sSelectionCaretsInflateSize;
+  }
+
+private:
+  SelectionCarets() MOZ_DELETE;
+
+  /**
+   * Update selection caret position base on current selection range.
+   */
+  void UpdateSelectionCarets();
+
+  /**
+   * Select word base on current position, only active when element
+   * is focused. Triggered by long tap event.
+   */
+  nsresult SelectWord();
+
+  /**
+   * Move selection base on current touch/mouse point
+   */
+  nsEventStatus DragSelection(const nsPoint &movePoint);
+
+  /**
+   * Get the vertical center position of selection caret relative to canvas
+   * frame.
+   */
+  nscoord GetCaretYCenterPosition();
+
+  /**
+   * Simulate mouse down state when we change the selection range.
+   * Hence, the selection change event will fire normally.
+   */
+  void SetMouseDownState(bool aState);
+
+  void SetSelectionDirection(bool aForward);
+
+  /**
+   * Move start frame of selection caret to given position.
+   * In app units.
+   */
+  void SetStartFramePos(const nsPoint& aPosition);
+
+  /**
+   * Move end frame of selection caret to given position.
+   * In app units.
+   */
+  void SetEndFramePos(const nsPoint& aPosition);
+
+  /**
+   * Get rect of selection caret's start frame relative
+   * to document's canvas frame, in app units.
+   */
+  nsRect GetStartFrameRect();
+
+  /**
+   * Get rect of selection caret's end frame relative
+   * to document's canvas frame, in app units.
+   */
+  nsRect GetEndFrameRect();
+
+  /**
+   * Set visibility for start part of selection caret, this function
+   * only affects css property of start frame. So it doesn't change
+   * mVisible member. When caret overflows element's box we'll hide
+   * it by calling this function.
+   */
+  void SetStartFrameVisibility(bool aVisible);
+
+  /**
+   * Same as above function but for end frame of selection caret.
+   */
+  void SetEndFrameVisibility(bool aVisible);
+
+  /**
+   * Set tilt class name to start and end frame of selection caret.
+   */
+  void SetTilted(bool aIsTilt);
+
+  // Utility function
+  nsIFrame* GetCaretFocusFrame();
+  bool GetCaretVisible();
+  nsISelection* GetSelection();
+
+  /**
+   * Detecting long tap using timer
+   */
+  void LaunchLongTapDetector();
+  void CancelLongTapDetector();
+  static void FireLongTap(nsITimer* aTimer, void* aSelectionCarets);
+
+  void LaunchScrollEndDetector();
+  static void FireScrollEnd(nsITimer* aTimer, void* aSelectionCarets);
+
+  nsIPresShell* mPresShell;
+
+  // This timer is used for detecting long tap fire. If content process
+  // has APZC, we'll use APZC for long tap detecting. Otherwise, we use this
+  // timer to detect long tap.