Merge last PGO-green changeset of mozilla-inbound to mozilla-central
authorEd Morley <emorley@mozilla.com>
Wed, 19 Dec 2012 19:30:22 +0000
changeset 125622 27a1c1839d428dd1e89ad4dae30719744142382e
parent 125540 1b6ab3a080d81bb9519e09304abd0713489eebba (current diff)
parent 125621 d7a482019f541a2aef919ff88945a7d7bb680a80 (diff)
child 125623 21195f52311c61195b9c555279bc734626e7a1c0
child 125646 fc3697b75c74bf99a1bf78d44f8114646a686ea2
push id2151
push userlsblakk@mozilla.com
push dateTue, 19 Feb 2013 18:06:57 +0000
treeherdermozilla-beta@4952e88741ec [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone20.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 last PGO-green changeset of mozilla-inbound to mozilla-central
browser/components/sessionstore/test/browser_248970_b.js
js/src/builtin/array.js
--- a/b2g/app/b2g.js
+++ b/b2g/app/b2g.js
@@ -549,16 +549,18 @@ pref("dom.ipc.processPriorityManager.ena
 pref("dom.ipc.processPriorityManager.gracePeriodMS", 1000);
 
 // Kernel parameters for how processes are killed on low-memory.
 pref("gonk.systemMemoryPressureRecoveryPollMS", 5000);
 pref("hal.processPriorityManager.gonk.masterOomScoreAdjust", 0);
 pref("hal.processPriorityManager.gonk.masterKillUnderMB", 1);
 pref("hal.processPriorityManager.gonk.foregroundOomScoreAdjust", 67);
 pref("hal.processPriorityManager.gonk.foregroundKillUnderMB", 4);
+pref("hal.processPriorityManager.gonk.backgroundHomescreenOomScoreAdjust", 200);
+pref("hal.processPriorityManager.gonk.backgroundHomescreenKillUnderMB", 5);
 pref("hal.processPriorityManager.gonk.backgroundOomScoreAdjust", 400);
 pref("hal.processPriorityManager.gonk.backgroundKillUnderMB", 8);
 pref("hal.processPriorityManager.gonk.notifyLowMemUnderMB", 10);
 
 // Niceness values (i.e., CPU priorities) for B2G processes.
 pref("hal.processPriorityManager.gonk.masterNice", -1);
 pref("hal.processPriorityManager.gonk.foregroundNice", 0);
 pref("hal.processPriorityManager.gonk.backgroundNice", 10);
--- a/b2g/config/tooltool-manifests/macosx64/releng.manifest
+++ b/b2g/config/tooltool-manifests/macosx64/releng.manifest
@@ -1,17 +1,17 @@
 [
 {
-"clang_version": "r169730"
+"clang_version": "r170377"
 },
 {
 "size": 47,
 "digest": "2005a41fe97a5e00997063705f39d42b6a43b1cf7ba306cbc7b1513de34cdcd050fc6326efa2107f19ba0cc67914745dbf13154fa748010a93cf072481ef4aaa",
 "algorithm": "sha512",
 "filename": "setup.sh"
 },
 {
-"size": 56115091,
-"digest": "d7188264f28d6f6a84fab9737520cad22fe3d575917a87fc110d0b9a2033617c35da83530ea20553f5c55a996459f750fa2d0c49288c1fb9671f6252a92cf4c9",
+"size": 56131193,
+"digest": "a1e705d3a72e0e95eeb15722f538a3908277f9f756909ce5e67f0a09b8531c1ba7fcc4816e20795af2e98839e0308b1bc6df95308cda310ae06abf21d429624f",
 "algorithm": "sha512",
 "filename": "clang.tar.bz2"
 }
 ]
--- a/browser/base/content/test/social/Makefile.in
+++ b/browser/base/content/test/social/Makefile.in
@@ -15,17 +15,17 @@ include $(DEPTH)/config/autoconf.mk
                  browser_social.js \
                  browser_social_toolbar.js \
                  browser_social_shareButton.js \
                  browser_social_sidebar.js \
                  browser_social_flyout.js \
                  browser_social_mozSocial_API.js \
                  browser_social_isVisible.js \
                  browser_social_chatwindow.js \
-                 $(filter disabled-temporarily--bug-820489, browser_social_multiprovider.js) \
+                 browser_social_multiprovider.js \
                  social_panel.html \
                  social_share_image.png \
                  social_sidebar.html \
                  social_chat.html \
                  social_flyout.html \
                  social_window.html \
                  social_worker.js \
                  $(NULL)
--- a/browser/base/content/test/social/browser_social_toolbar.js
+++ b/browser/base/content/test/social/browser_social_toolbar.js
@@ -12,16 +12,33 @@ function test() {
     iconURL: "https://example.com/browser/browser/base/content/test/moz.png"
   };
   runSocialTestWithProvider(manifest, function (finishcb) {
     runSocialTests(tests, undefined, undefined, finishcb);
   });
 }
 
 var tests = {
+  testProfileNone: function(next, useNull) {
+    let profile = useNull ? null : {};
+    Social.provider.updateUserProfile(profile);
+    // check dom values
+    let portrait = document.getElementsByClassName("social-statusarea-user-portrait")[0].getAttribute("src");
+    // this is the default image for the profile area when not logged in.
+    is(portrait, "chrome://global/skin/icons/information-32.png", "portrait is empty");
+    let userDetailsBroadcaster = document.getElementById("socialBroadcaster_userDetails");
+    let notLoggedInStatusValue = userDetailsBroadcaster.getAttribute("notLoggedInLabel");
+    let userButton = document.getElementsByClassName("social-statusarea-loggedInStatus")[0];
+    ok(!userButton.hidden, "username is visible");
+    is(userButton.getAttribute("label"), notLoggedInStatusValue, "label reflects not being logged in");
+    next();
+  },
+  testProfileNull: function(next) {
+    this.testProfileNone(next, true);
+  },
   testProfileSet: function(next) {
     let profile = {
       portrait: "https://example.com/portrait.jpg",
       userName: "trickster",
       displayName: "Kuma Lisa",
       profileURL: "http://en.wikipedia.org/wiki/Kuma_Lisa"
     }
     Social.provider.updateUserProfile(profile);
--- a/browser/components/places/content/downloadsView.js
+++ b/browser/components/places/content/downloadsView.js
@@ -113,16 +113,22 @@ DownloadElementShell.prototype = {
   get downloadURI() {
     if (this._dataItem)
      return this._dataItem.uri;
     if (this._placesNode)
       return this._placesNode.uri;
     throw new Error("Unexpected download element state");
   },
 
+  get _downloadURIObj() {
+    if (!("__downloadURIObj" in this))
+      this.__downloadURIObj = NetUtil.newURI(this.downloadURI);
+    return this.__downloadURIObj;
+  },
+
   get _icon() {
     if (this._targetFileURI)
       return "moz-icon://" + this._targetFileURI + "?size=32";
     if (this._placesNode)
       return this.placesNode.icon;
     if (this._dataItem)
       throw new Error("Session-download items should always have a target file uri");
     throw new Error("Unexpected download element state");
@@ -131,17 +137,17 @@ DownloadElementShell.prototype = {
   // Helper for getting a places annotation set for the download.
   _getAnnotation: function DES__getAnnotation(aAnnotation, aDefaultValue) {
     if (this._annotations.has(aAnnotation))
       return this._annotations.get(aAnnotation);
 
     let value;
     try {
       value = PlacesUtils.annotations.getPageAnnotation(
-        NetUtil.newURI(this.downloadURI), aAnnotation);
+        this._downloadURIObj, aAnnotation);
     }
     catch(ex) {
       if (aDefaultValue === undefined) {
         throw new Error("Could not get required annotation '" + aAnnotation +
                         "' for download with url '" + this.downloadURI + "'");
       }
       value = aDefaultValue;
     }
@@ -461,17 +467,17 @@ DownloadElementShell.prototype = {
       case "downloadsCmd_cancel": {
         this._dataItem.cancel();
         break;
       }
       case "cmd_delete": {
         if (this._dataItem)
           this._dataItem.remove();
         if (this._placesNode)
-          PlacesUtils.bhistory.removePage(NetUtil.newURI(this.downloadURI));
+          PlacesUtils.bhistory.removePage(this._downloadURIObj);
         break;
        }
       case "downloadsCmd_retry": {
         if (this._dataItem)
           this._dataItem.retry();
         else
           this._retryAsHistoryDownload();
         break;
@@ -572,28 +578,45 @@ DownloadsPlacesView.prototype = {
     if (this._downloadElementsShellsForURI.has(aURI)) {
       let downloadElementShells = this._downloadElementsShellsForURI.get(aURI);
       for (let des of downloadElementShells) {
         aCallback(des);
       }
     }
   },
 
-  // Given a data item for a session download, or a places node for a past
-  // download, updates the view as necessary.
-  // 1. If the given data is a places node, we check whether there are any
-  //    element for the same download url. If there are, then we just reset
-  //    their places node. Otherwise we add a new download element.
-  // 2. If the given data is a data item, we first check if there's an history
-  //    download in the list that is not associated with a data item. If we found
-  //    one, we use it for the data item as well and reposition it alongside the
-  //    other session downloads. If we don't, then we go ahead and create a new
-  //    element for the download.
+  /**
+   * Given a data item for a session download, or a places node for a past
+   * download, updates the view as necessary.
+   *  1. If the given data is a places node, we check whether there are any
+   *     elements for the same download url. If there are, then we just reset
+   *     their places node. Otherwise we add a new download element.
+   *  2. If the given data is a data item, we first check if there's a history
+   *     download in the list that is not associated with a data item. If we
+   *     found one, we use it for the data item as well and reposition it
+   *     alongside the other session downloads. If we don't, then we go ahead
+   *     and create a new element for the download.
+   *
+   * @param aDataItem
+   *        The data item of a session download. Set to null for history
+   *        downloads data.
+   * @param [optional] aPlacesNode
+   *        The places node for a history download. Required if there's no data
+   *        item.
+   * @param [optional] aNewest
+   *        @see onDataItemAdded. Ignored for history downlods.
+   * @param [optional] aDocumentFragment
+   *        To speed up the appending of multiple elements to the end of the
+   *        list which are coming in a single batch (i.e. invalidateContainer),
+   *        a document fragment may be passed to which the new elements would
+   *        be appended. It's the caller's job to ensure the fragment is merged
+   *        to the richlistbox at the end.
+   */
   _addDownloadData:
-  function DPV_addDownload(aDataItem, aPlacesNode, aNewest) {
+  function DPV_addDownload(aDataItem, aPlacesNode, aNewest = false, aDocumentFragment = null) {
     let downloadURI = aPlacesNode ? aPlacesNode.uri : aDataItem.uri;
     let shellsForURI = this._downloadElementsShellsForURI.get(downloadURI, null);
     if (!shellsForURI) {
       shellsForURI = new Set();
       this._downloadElementsShellsForURI.set(downloadURI, shellsForURI);
     }
 
     let newOrUpdatedShell = null;
@@ -653,22 +676,23 @@ DownloadsPlacesView.prototype = {
         this._richlistbox.insertBefore(newOrUpdatedShell.element,
                                        this._richlistbox.firstChild);
         if (!this._lastSessionDownloadElement) {
           this._lastSessionDownloadElement = newOrUpdatedShell.element;
         }
       }
       else if (aDataItem) {
         let before = this._lastSessionDownloadElement ?
-          this._lastSessionDownloadElement.nextSibling : this._richlistbox.firstChild
-        this._richlistbox.insertBefore(newOrUpdatedShell.element, before)
+          this._lastSessionDownloadElement.nextSibling : this._richlistbox.firstChild;
+        this._richlistbox.insertBefore(newOrUpdatedShell.element, before);
         this._lastSessionDownloadElement = newOrUpdatedShell.element;
       }
       else {
-        this._richlistbox.appendChild(newOrUpdatedShell.element);
+        let appendTo = aDocumentFragment || this._richlistbox;
+        appendTo.appendChild(newOrUpdatedShell.element);
       }
 
       if (this.searchTerm) {
         newOrUpdatedShell.element.hidden =
           !newOrUpdatedShell.element._shell.matchesSearchTerm(this.searchTerm);
       }
     }
   },
@@ -816,28 +840,32 @@ DownloadsPlacesView.prototype = {
 
     // Remove the invalidated history downloads from the list and unset the
     // places node for data downloads.
     for (let element of this._richlistbox.childNodes) {
       if (element._shell.placesNode)
         this._removeHistoryDownloadFromView(element._shell.placesNode);
     }
 
+    let elementsToAppendFragment = document.createDocumentFragment();
     for (let i = 0; i < aContainer.childCount; i++) {
       try {
-        this._addDownloadData(null, aContainer.getChild(i), false)
+        this._addDownloadData(null, aContainer.getChild(i), false,
+                              elementsToAppendFragment);
       }
       catch(ex) {
         Cu.reportError(ex);
       }
     }
+
+    this._richlistbox.appendChild(elementsToAppendFragment);
   },
 
   nodeInserted: function DPV_nodeInserted(aParent, aPlacesNode) {
-    this._addDownloadData(null, aPlacesNode, false);
+    this._addDownloadData(null, aPlacesNode);
   },
 
   nodeRemoved: function DPV_nodeRemoved(aParent, aPlacesNode, aOldIndex) {
     this._removeHistoryDownloadFromView(aPlacesNode);
   },
 
   nodeIconChanged: function DPV_nodeIconChanged(aNode) {
     this._forEachDownloadElementShellForURI(aNode.uri, function(aDownloadElementShell) {
@@ -890,17 +918,17 @@ DownloadsPlacesView.prototype = {
   onDataLoadStarting: function() { },
   onDataLoadCompleted: function() { },
 
   onDataItemAdded: function DPV_onDataItemAdded(aDataItem, aNewest) {
     this._addDownloadData(aDataItem, null, aNewest);
   },
 
   onDataItemRemoved: function DPV_onDataItemRemoved(aDataItem) {
-    this._removeSessionDownloadFromView(aDataItem)
+    this._removeSessionDownloadFromView(aDataItem);
   },
 
   getViewItem: function(aDataItem)
     this._viewItemsForDataItems.get(aDataItem, null),
 
   supportsCommand: function(aCommand)
     DOWNLOAD_VIEW_SUPPORTED_COMMANDS.indexOf(aCommand) != -1,
 
@@ -934,17 +962,17 @@ DownloadsPlacesView.prototype = {
                 createInstance(Ci.nsITransferable);
     trans.init(null);
 
     let flavors = ["text/x-moz-url", "text/unicode"];
     flavors.forEach(trans.addDataFlavor);
 
     Services.clipboard.getData(trans, Services.clipboard.kGlobalClipboard);
 
-    // Getting the data or creating the nsIURI might fail
+    // Getting the data or creating the nsIURI might fail.
     try {
       let data = {};
       trans.getAnyTransferData({}, data, {});
       let [url, name] = data.value.QueryInterface(Ci.nsISupportsString)
                             .data.split("\n");
       if (url)
         return [NetUtil.newURI(url, null, null).spec, name];
     }
--- a/browser/components/sessionstore/src/SessionStore.jsm
+++ b/browser/components/sessionstore/src/SessionStore.jsm
@@ -1268,18 +1268,18 @@ let SessionStoreInternal = {
     delete browser.__SS_data;
     delete browser.__SS_tabStillLoading;
     delete browser.__SS_formDataSaved;
     delete browser.__SS_hostSchemeData;
 
     // If this tab was in the middle of restoring or still needs to be restored,
     // we need to reset that state. If the tab was restoring, we will attempt to
     // restore the next tab.
-    let previousState;
-    if (previousState = browser.__SS_restoreState) {
+    let previousState = browser.__SS_restoreState;
+    if (previousState) {
       this._resetTabRestoringState(aTab);
       if (previousState == TAB_STATE_RESTORING)
         this.restoreNextTab();
     }
 
     if (!aNoNotification) {
       this.saveStateDelayed(aWindow);
     }
--- a/browser/components/sessionstore/test/Makefile.in
+++ b/browser/components/sessionstore/test/Makefile.in
@@ -137,16 +137,17 @@ ifdef MOZ_PER_WINDOW_PRIVATE_BROWSING
 MOCHITEST_BROWSER_FILES += \
 	browser_354894_perwindowpb.js \
 	browser_394759_perwindowpb.js \
 	$(NULL)
 else
 MOCHITEST_BROWSER_FILES += \
 	browser_248970_a.js \
 	browser_248970_b.js \
++	browser_248970_b_perwindowpb.js \
 	browser_354894.js \
 	browser_394759_privatebrowsing.js \
 	$(NULL)
 endif
 
 # Disabled on Windows for frequent intermittent failures
 ifneq ($(OS_ARCH), WINNT)
 MOCHITEST_FILES += \
copy from browser/components/sessionstore/test/browser_248970_b.js
copy to browser/components/sessionstore/test/browser_248970_b_perwindowpb.js
--- a/browser/components/sessionstore/test/browser_248970_b.js
+++ b/browser/components/sessionstore/test/browser_248970_b_perwindowpb.js
@@ -1,27 +1,19 @@
 /* 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/. */
 
 function test() {
   /** Test (B) for Bug 248970 **/
+  waitForExplicitFinish();
 
-  function test(aLambda) {
-    try {
-      return aLambda() || true;
-    } catch(ex) { }
-    return false;
-  }
-
-  var file = Components.classes["@mozilla.org/file/directory_service;1"]
-             .getService(Components.interfaces.nsIProperties)
-             .get("TmpD", Components.interfaces.nsIFile);
-  var filePath = file.path;
-
+  let windowsToClose = [];
+  let file = Services.dirsvc.get("TmpD", Ci.nsIFile);
+  let filePath = file.path;
   let fieldList = {
     "//input[@name='input']":     Date.now().toString(),
     "//input[@name='spaced 1']":  Math.random().toString(),
     "//input[3]":                 "three",
     "//input[@type='checkbox']":  true,
     "//input[@name='uncheck']":   false,
     "//input[@type='radio'][1]":  false,
     "//input[@type='radio'][2]":  true,
@@ -29,16 +21,29 @@ function test() {
     "//select":                   2,
     "//select[@multiple]":        [1, 3],
     "//textarea[1]":              "",
     "//textarea[2]":              "Some text... " + Math.random(),
     "//textarea[3]":              "Some more text\n" + new Date(),
     "//input[@type='file']":      filePath
   };
 
+  registerCleanupFunction(function() {
+    windowsToClose.forEach(function(win) {
+      win.close();
+    });
+  });
+
+  function test(aLambda) {
+    try {
+      return aLambda() || true;
+    } catch(ex) { }
+    return false;
+  }
+
   function getElementByXPath(aTab, aQuery) {
     let doc = aTab.linkedBrowser.contentDocument;
     let xptype = Ci.nsIDOMXPathResult.FIRST_ORDERED_NODE_TYPE;
     return doc.evaluate(aQuery, doc, null, xptype, null).singleNodeValue;
   }
 
   function setFormValue(aTab, aQuery, aValue) {
     let node = getElementByXPath(aTab, aQuery);
@@ -63,113 +68,100 @@ function test() {
     if (node instanceof Ci.nsIDOMHTMLTextAreaElement)
       return aValue == node.value;
     if (!node.multiple)
       return aValue == node.selectedIndex;
     return Array.every(node.options, function(aOpt, aIx)
             (aValue.indexOf(aIx) > -1) == aOpt.selected);
   }
 
-  // test setup
-  waitForExplicitFinish();
-
-  // private browsing service
-  let pb = Cc["@mozilla.org/privatebrowsing;1"].
-           getService(Ci.nsIPrivateBrowsingService);
-  gPrefService.setBoolPref("browser.privatebrowsing.keep_current_session", true);
-
   //////////////////////////////////////////////////////////////////
-  // Test (B) : Session data restoration between modes            //
+  // Test (B) : Session data restoration between windows          //
   //////////////////////////////////////////////////////////////////
 
   let rootDir = getRootDirectory(gTestPath);
   const testURL = rootDir + "browser_248970_b_sample.html";
   const testURL2 = "http://mochi.test:8888/browser/" +
-  "browser/components/sessionstore/test/browser_248970_b_sample.html";
+    "browser/components/sessionstore/test/browser_248970_b_sample.html";
 
-  // get closed tab count
-  let count = ss.getClosedTabCount(window);
-  let max_tabs_undo = gPrefService.getIntPref("browser.sessionstore.max_tabs_undo");
-  ok(0 <= count && count <= max_tabs_undo,
-    "getClosedTabCount should return zero or at most max_tabs_undo");
+  whenNewWindowLoaded(false, function(aWin) {
+    windowsToClose.push(aWin);
 
-  // setup a state for tab (A) so we can check later that is restored
-  let key = "key";
-  let value = "Value " + Math.random();
-  let state = { entries: [{ url: testURL }], extData: { key: value } };
+    // get closed tab count
+    let count = ss.getClosedTabCount(aWin);
+    let max_tabs_undo =
+      Services.prefs.getIntPref("browser.sessionstore.max_tabs_undo");
+    ok(0 <= count && count <= max_tabs_undo,
+      "getClosedTabCount should return zero or at most max_tabs_undo");
 
-  // public session, add new tab: (A)
-  let tab_A = gBrowser.addTab(testURL);
-  ss.setTabState(tab_A, JSON.stringify(state));
-  tab_A.linkedBrowser.addEventListener("load", function(aEvent) {
-    this.removeEventListener("load", arguments.callee, true);
-
-    // make sure that the next closed tab will increase getClosedTabCount
-    gPrefService.setIntPref("browser.sessionstore.max_tabs_undo", max_tabs_undo + 1)
+    // setup a state for tab (A) so we can check later that is restored
+    let key = "key";
+    let value = "Value " + Math.random();
+    let state = { entries: [{ url: testURL }], extData: { key: value } };
 
-    // populate tab_A with form data
-    for (let i in fieldList)
-      setFormValue(tab_A, i, fieldList[i]);
-
-    // public session, close tab: (A)
-    gBrowser.removeTab(tab_A);
-
-    // verify that closedTabCount increased
-    ok(ss.getClosedTabCount(window) > count, "getClosedTabCount has increased after closing a tab");
+    // public session, add new tab: (A)
+    let tab_A = aWin.gBrowser.addTab(testURL);
+    ss.setTabState(tab_A, JSON.stringify(state));
+    whenBrowserLoaded(tab_A.linkedBrowser, function() {
+      // make sure that the next closed tab will increase getClosedTabCount
+      Services.prefs.setIntPref(
+        "browser.sessionstore.max_tabs_undo", max_tabs_undo + 1)
 
-    // verify tab: (A), in undo list
-    let tab_A_restored = test(function() ss.undoCloseTab(window, 0));
-    ok(tab_A_restored, "a tab is in undo list");
-    tab_A_restored.linkedBrowser.addEventListener("load", function(aEvent) {
-      this.removeEventListener("load", arguments.callee, true);
+      // populate tab_A with form data
+      for (let i in fieldList)
+        setFormValue(tab_A, i, fieldList[i]);
 
-      is(testURL, this.currentURI.spec, "it's the same tab that we expect");
-      gBrowser.removeTab(tab_A_restored);
+      // public session, close tab: (A)
+      aWin.gBrowser.removeTab(tab_A);
 
-      // enter private browsing mode
-      pb.privateBrowsingEnabled = true;
-      ok(pb.privateBrowsingEnabled, "private browsing enabled");
+      // verify that closedTabCount increased
+      ok(ss.getClosedTabCount(aWin) > count,
+         "getClosedTabCount has increased after closing a tab");
 
-      // setup a state for tab (B) so we can check that its duplicated properly
-      let key1 = "key1";
-      let value1 = "Value " + Math.random();
-      let state1 = { entries: [{ url: testURL2 }], extData: { key1: value1 } };
+      // verify tab: (A), in undo list
+      let tab_A_restored = test(function() ss.undoCloseTab(aWin, 0));
+      ok(tab_A_restored, "a tab is in undo list");
+      whenBrowserLoaded(tab_A_restored.linkedBrowser, function() {
+        is(testURL, tab_A_restored.linkedBrowser.currentURI.spec,
+           "it's the same tab that we expect");
+        aWin.gBrowser.removeTab(tab_A_restored);
 
-      // private browsing session, new tab: (B)
-      let tab_B = gBrowser.addTab(testURL2);
-      ss.setTabState(tab_B, JSON.stringify(state1));
-      tab_B.linkedBrowser.addEventListener("load", function(aEvent) {
-        this.removeEventListener("load", arguments.callee, true);
+        whenNewWindowLoaded(true, function(aWin) {
+          windowsToClose.push(aWin);
 
-        // populate tab: (B) with different form data
-        for (let item in fieldList)
-          setFormValue(tab_B, item, fieldList[item]);
-
-        // duplicate tab: (B)
-        let tab_C = gBrowser.duplicateTab(tab_B);
-        tab_C.linkedBrowser.addEventListener("load", function(aEvent) {
-          this.removeEventListener("load", arguments.callee, true);
+          // setup a state for tab (B) so we can check that its duplicated
+          // properly
+          let key1 = "key1";
+          let value1 = "Value " + Math.random();
+          let state1 = {
+            entries: [{ url: testURL2 }], extData: { key1: value1 }
+          };
 
-          // verify the correctness of the duplicated tab
-          is(ss.getTabValue(tab_C, key1), value1,
-            "tab successfully duplicated - correct state");
+          let tab_B = aWin.gBrowser.addTab(testURL2);
+          ss.setTabState(tab_B, JSON.stringify(state1));
+          whenBrowserLoaded(tab_B.linkedBrowser, function() {
+            // populate tab: (B) with different form data
+            for (let item in fieldList)
+              setFormValue(tab_B, item, fieldList[item]);
 
-          for (let item in fieldList)
-            ok(compareFormValue(tab_C, item, fieldList[item]),
-              "The value for \"" + item + "\" was correctly duplicated");
-
-          // private browsing session, close tab: (C) and (B)
-          gBrowser.removeTab(tab_C);
-          gBrowser.removeTab(tab_B);
+            // duplicate tab: (B)
+            let tab_C = aWin.gBrowser.duplicateTab(tab_B);
+            whenBrowserLoaded(tab_C.linkedBrowser, function() {
+              // verify the correctness of the duplicated tab
+              is(ss.getTabValue(tab_C, key1), value1,
+                "tab successfully duplicated - correct state");
 
-          // exit private browsing mode
-          pb.privateBrowsingEnabled = false;
-          ok(!pb.privateBrowsingEnabled, "private browsing disabled");
+              for (let item in fieldList)
+                ok(compareFormValue(tab_C, item, fieldList[item]),
+                  "The value for \"" + item + "\" was correctly duplicated");
+
+              // private browsing session, close tab: (C) and (B)
+              aWin.gBrowser.removeTab(tab_C);
+              aWin.gBrowser.removeTab(tab_B);
 
-          // cleanup
-          if (gPrefService.prefHasUserValue("browser.privatebrowsing.keep_current_session"))
-            gPrefService.clearUserPref("browser.privatebrowsing.keep_current_session");
-          finish();
-        }, true);
-      }, true);
-    }, true);
-  }, true);
+              finish();
+            });
+          });
+        });
+      });
+    });
+  });
 }
--- a/browser/components/sessionstore/test/head.js
+++ b/browser/components/sessionstore/test/head.js
@@ -272,8 +272,16 @@ registerCleanupFunction(function () {
 // because apparently it's buggy. See bug 599253.
 function closeAllButPrimaryWindow() {
   for (let win in BrowserWindowIterator()) {
     if (win != window) {
       win.close();
     }
   }
 }
+
+function whenNewWindowLoaded(aIsPrivate, aCallback) {
+  let win = OpenBrowserWindow({private: aIsPrivate});
+  win.addEventListener("load", function onLoad() {
+    win.removeEventListener("load", onLoad, false);
+    aCallback(win);
+  }, false);
+}
--- a/browser/components/tabview/ui.js
+++ b/browser/components/tabview/ui.js
@@ -59,25 +59,27 @@ let UI = {
   _cleanupFunctions: [],
   
   // Constant: _maxInteractiveWait
   // If the UI is in the middle of an operation, this is the max amount of
   // milliseconds to wait between input events before we no longer consider
   // the operation interactive.
   _maxInteractiveWait: 250,
 
+#ifndef MOZ_PER_WINDOW_PRIVATE_BROWSING
   // Variable: _privateBrowsing
   // Keeps track of info related to private browsing, including: 
   //   transitionMode - whether we're entering or exiting PB
   //   wasInTabView - whether TabView was visible before we went into PB
   _privateBrowsing: {
     transitionMode: "",
     wasInTabView: false 
   },
-  
+#endif
+
   // Variable: _storageBusy
   // Tells whether the storage is currently busy or not.
   _storageBusy: false,
 
   // Variable: isDOMWindowClosing
   // Tells wether the parent window is about to close
   isDOMWindowClosing: false,
 
@@ -590,18 +592,23 @@ let UI = {
       mainWindow.removeAttribute("activetitlebarcolor");
       mainWindow.removeAttribute("inactivetitlebarcolor");
     }
   },
 #endif
 
   // ----------
   // Function: storageBusy
+#ifdef MOZ_PER_WINDOW_PRIVATE_BROWSING
+  // Pauses the storage activity that conflicts with sessionstore updates.
+  // Calls can be nested.
+#else
   // Pauses the storage activity that conflicts with sessionstore updates and 
   // private browsing mode switches. Calls can be nested. 
+#endif
   storageBusy: function UI_storageBusy() {
     if (this._storageBusy)
       return;
 
     this._storageBusy = true;
 
     TabItems.pauseReconnecting();
     GroupItems.pauseAutoclose();
@@ -644,16 +651,17 @@ let UI = {
     gWindow.addEventListener("SSWindowStateBusy", handleSSWindowStateBusy, false);
     gWindow.addEventListener("SSWindowStateReady", handleSSWindowStateReady, false);
 
     this._cleanupFunctions.push(function() {
       gWindow.removeEventListener("SSWindowStateBusy", handleSSWindowStateBusy, false);
       gWindow.removeEventListener("SSWindowStateReady", handleSSWindowStateReady, false);
     });
 
+#ifndef MOZ_PER_WINDOW_PRIVATE_BROWSING
     // Private Browsing:
     // When transitioning to PB, we exit Panorama if necessary (making note of the
     // fact that we were there so we can return after PB) and make sure we
     // don't reenter Panorama due to all of the session restore tab
     // manipulation (which otherwise we might). When transitioning away from
     // PB, we reenter Panorama if we had been there directly before PB.
     function pbObserver(subject, topic, data) {
       if (topic == "private-browsing") {
@@ -684,16 +692,17 @@ let UI = {
     Services.obs.addObserver(pbObserver, "private-browsing-change-granted", false);
     Services.obs.addObserver(pbObserver, "private-browsing-transition-complete", false);
 
     this._cleanupFunctions.push(function() {
       Services.obs.removeObserver(pbObserver, "private-browsing");
       Services.obs.removeObserver(pbObserver, "private-browsing-change-granted");
       Services.obs.removeObserver(pbObserver, "private-browsing-transition-complete");
     });
+#endif
 
     // TabOpen
     this._eventListeners.open = function (event) {
       let tab = event.target;
 
       // if it's an app tab, add it to all the group items
       if (tab.pinned)
         GroupItems.addAppTab(tab);
@@ -709,17 +718,21 @@ let UI = {
       if (tab.pinned)
         GroupItems.removeAppTab(tab);
         
       if (self.isTabViewVisible()) {
         // just closed the selected tab in the TabView interface.
         if (self._currentTab == tab)
           self._closedSelectedTabInTabView = true;
       } else {
+#ifdef MOZ_PER_WINDOW_PRIVATE_BROWSING
+        // If we're currently in the process of session store update,
+#else
         // If we're currently in the process of entering private browsing,
+#endif
         // we don't want to go to the Tab View UI. 
         if (self._storageBusy)
           return;
 
         // if not closing the last tab
         if (gBrowser.tabs.length > 1) {
           // Don't return to TabView if there are any app tabs
           for (let a = 0; a < gBrowser._numPinnedTabs; a++) {
@@ -820,19 +833,24 @@ let UI = {
   // Function: onTabSelect
   // Called when the user switches from one tab to another outside of the TabView UI.
   onTabSelect: function UI_onTabSelect(tab) {
     this._currentTab = tab;
 
     if (this.isTabViewVisible()) {
       // We want to zoom in if:
       // 1) we didn't just restore a tab via Ctrl+Shift+T
+#ifdef MOZ_PER_WINDOW_PRIVATE_BROWSING
+      // 2) the currently selected tab is the last created tab and has a tabItem
+      if (!this.restoredClosedTab &&
+#else
       // 2) we're not in the middle of switching from/to private browsing
       // 3) the currently selected tab is the last created tab and has a tabItem
       if (!this.restoredClosedTab && !this._privateBrowsing.transitionMode &&
+#endif
           this._lastOpenedTab == tab && tab._tabViewTabItem) {
         tab._tabViewTabItem.zoomIn(true);
         this._lastOpenedTab = null;
         return;
       }
       if (this._closedLastVisibleTab ||
           (this._closedSelectedTabInTabView && !this.closedLastTabInTabView) ||
           this.restoredClosedTab) {
@@ -1007,18 +1025,20 @@ let UI = {
     // to handle both upper and lower cases here.
     [
 #ifdef XP_UNIX
       "redo",
 #endif
 #ifdef XP_MACOSX
       "fullScreen",
 #endif
-      "closeWindow", "tabview", "undoCloseTab", "undoCloseWindow",
-      "privatebrowsing"
+      "closeWindow", "tabview", "undoCloseTab", "undoCloseWindow"
+#ifndef MOZ_PER_WINDOW_PRIVATE_BROWSING
+      , "privatebrowsing"
+#endif
     ].forEach(function(key) {
       let element = gWindow.document.getElementById("key_" + key);
       let code = element.getAttribute("key").toLocaleLowerCase().charCodeAt(0);
       keys[code] = key;
     });
     this._browserKeysWithShift = keys;
   },
 
--- a/browser/config/tooltool-manifests/linux32/clang.manifest
+++ b/browser/config/tooltool-manifests/linux32/clang.manifest
@@ -1,17 +1,17 @@
 [
 {
-"clang_version": "r169730"
+"clang_version": "r170377"
 },
 {
 "size": 47,
 "digest": "2005a41fe97a5e00997063705f39d42b6a43b1cf7ba306cbc7b1513de34cdcd050fc6326efa2107f19ba0cc67914745dbf13154fa748010a93cf072481ef4aaa",
 "algorithm": "sha512",
 "filename": "setup.sh"
 },
 {
-"size": 61875575,
-"digest": "7098e1cc85a8ae45672333320c7673c284023366fbe6d4fab3e9276960b7f92fd74ee63d0ad6c43a86fd96a1b886408993479260ac897fa6fe101c4a9fb807b1",
+"size": 61878564,
+"digest": "bc344ad6cb8f4d7b25447a8f06ae3a22c6b90283fcc70f28f12578bdaf01ec960a774cdc215bdda4960cef04b6a991e462daeeda4f7e802bf65e6c9a3967f66c",
 "algorithm": "sha512",
 "filename": "clang.tar.bz2"
 }
 ]
--- a/browser/config/tooltool-manifests/linux64/clang.manifest
+++ b/browser/config/tooltool-manifests/linux64/clang.manifest
@@ -1,17 +1,17 @@
 [
 {
-"clang_version": "r169730"
+"clang_version": "r170377"
 },
 {
 "size": 47,
 "digest": "2005a41fe97a5e00997063705f39d42b6a43b1cf7ba306cbc7b1513de34cdcd050fc6326efa2107f19ba0cc67914745dbf13154fa748010a93cf072481ef4aaa",
 "algorithm": "sha512",
 "filename": "setup.sh"
 },
 {
-"size": 62279267,
-"digest": "0c9f87e3d7675feaa79b6d5d0997c8f370785901b8668f51da3339ae674291b3946e9d76629adb1c4ccd15aa851d84e4cd39ddd9032c916cc75233fe73c68f2e",
+"size": 62277867,
+"digest": "b9c6ab4069e336fcbe705f07fd2beda37aecfd4078863898826c9591305b92f3f3f762e7f5c1b0eeb7e0fb1c0dacbca60f24868e0b3181bd34dcd9c5d44d20ee",
 "algorithm": "sha512",
 "filename": "clang.tar.bz2"
 }
 ]
--- a/browser/config/tooltool-manifests/macosx32/releng.manifest
+++ b/browser/config/tooltool-manifests/macosx32/releng.manifest
@@ -1,17 +1,17 @@
 [
 {
-"clang_version": "r169730"
+"clang_version": "r170377"
 },
 {
 "size": 47,
 "digest": "2005a41fe97a5e00997063705f39d42b6a43b1cf7ba306cbc7b1513de34cdcd050fc6326efa2107f19ba0cc67914745dbf13154fa748010a93cf072481ef4aaa",
 "algorithm": "sha512",
 "filename": "setup.sh"
 },
 {
-"size": 56115091,
-"digest": "d7188264f28d6f6a84fab9737520cad22fe3d575917a87fc110d0b9a2033617c35da83530ea20553f5c55a996459f750fa2d0c49288c1fb9671f6252a92cf4c9",
+"size": 56131193,
+"digest": "a1e705d3a72e0e95eeb15722f538a3908277f9f756909ce5e67f0a09b8531c1ba7fcc4816e20795af2e98839e0308b1bc6df95308cda310ae06abf21d429624f",
 "algorithm": "sha512",
 "filename": "clang.tar.bz2"
 }
 ]
--- a/browser/config/tooltool-manifests/macosx64/releng.manifest
+++ b/browser/config/tooltool-manifests/macosx64/releng.manifest
@@ -1,17 +1,17 @@
 [
 {
-"clang_version": "r169730"
+"clang_version": "r170377"
 },
 {
 "size": 47,
 "digest": "2005a41fe97a5e00997063705f39d42b6a43b1cf7ba306cbc7b1513de34cdcd050fc6326efa2107f19ba0cc67914745dbf13154fa748010a93cf072481ef4aaa",
 "algorithm": "sha512",
 "filename": "setup.sh"
 },
 {
-"size": 56115091,
-"digest": "d7188264f28d6f6a84fab9737520cad22fe3d575917a87fc110d0b9a2033617c35da83530ea20553f5c55a996459f750fa2d0c49288c1fb9671f6252a92cf4c9",
+"size": 56131193,
+"digest": "a1e705d3a72e0e95eeb15722f538a3908277f9f756909ce5e67f0a09b8531c1ba7fcc4816e20795af2e98839e0308b1bc6df95308cda310ae06abf21d429624f",
 "algorithm": "sha512",
 "filename": "clang.tar.bz2"
 }
 ]
--- a/browser/confvars.sh
+++ b/browser/confvars.sh
@@ -18,59 +18,41 @@ if test "$OS_ARCH" = "WINNT"; then
             "$MOZ_UPDATE_CHANNEL" = "release"; then
       if ! test "$MOZ_DEBUG"; then
         MOZ_STUB_INSTALLER=1
       fi
     fi
   fi
 fi
 
-# The value of ACCEPTED_MAR_CHANNEL_IDS should usually be the same as the value
-# MAR_CHANNEL_ID. If more than one ID is needed, then you should use a comma
-# separated list of values.
-# The MAR_CHANNEL_ID must not contain the following 3 characters: ",\t "
-case "$MOZ_UPDATE_CHANNEL" in
-release|aurora|esr)
-  ACCEPTED_MAR_CHANNEL_IDS=firefox-mozilla-$MOZ_UPDATE_CHANNEL
-  MAR_CHANNEL_ID=firefox-mozilla-$MOZ_UPDATE_CHANNEL
-  ;;
-beta)
-  ACCEPTED_MAR_CHANNEL_IDS=firefox-mozilla-beta,firefox-mozilla-release
-  MAR_CHANNEL_ID=firefox-mozilla-beta
-  ;;
-*)
-  ACCEPTED_MAR_CHANNEL_IDS=firefox-mozilla-central
-  MAR_CHANNEL_ID=firefox-mozilla-central
-  ;;
-esac
-
-# MOZ_APP_DISPLAYNAME will be set by branding/configure.sh
-# Changing MOZ_*BRANDING_DIRECTORY requires a clobber to ensure correct results,
-# because branding dependencies are broken.
-# MOZ_BRANDING_DIRECTORY is the default branding directory used when none is
-# specified. It should never point to the "official" branding directory.
-# For mozilla-beta, mozilla-release, or mozilla-central repositories, use
-# "nightly" branding (until bug 659568 is fixed).
-# For the mozilla-aurora repository, use "aurora".
-MOZ_OFFICIAL_BRANDING_DIRECTORY=browser/branding/official
-if test "$MOZ_UPDATE_CHANNEL" = "aurora"; then
-  MOZ_BRANDING_DIRECTORY=browser/branding/aurora
-else
-  MOZ_BRANDING_DIRECTORY=browser/branding/nightly
-fi
-
 MOZ_CHROME_FILE_FORMAT=omni
 MOZ_SAFE_BROWSING=1
 MOZ_SERVICES_AITC=1
 MOZ_SERVICES_COMMON=1
 MOZ_SERVICES_CRYPTO=1
 MOZ_SERVICES_METRICS=1
 MOZ_SERVICES_NOTIFICATIONS=1
 MOZ_SERVICES_SYNC=1
 MOZ_APP_VERSION=$FIREFOX_VERSION
 MOZ_EXTENSIONS_DEFAULT=" gio"
+# MOZ_APP_DISPLAYNAME will be set by branding/configure.sh
+# Changing MOZ_*BRANDING_DIRECTORY requires a clobber to ensure correct results,
+# because branding dependencies are broken.
+# MOZ_BRANDING_DIRECTORY is the default branding directory used when none is
+# specified. It should never point to the "official" branding directory.
+# For mozilla-beta, mozilla-release, or mozilla-central repositories, use
+# "nightly" branding (until bug 659568 is fixed).
+# For the mozilla-aurora repository, use "aurora".
+MOZ_BRANDING_DIRECTORY=browser/branding/nightly
+MOZ_OFFICIAL_BRANDING_DIRECTORY=browser/branding/official
 MOZ_APP_ID={ec8030f7-c20a-464f-9b0e-13a3a9e97384}
+# This should usually be the same as the value MAR_CHANNEL_ID.
+# If more than one ID is needed, then you should use a comma separated list
+# of values.
+ACCEPTED_MAR_CHANNEL_IDS=firefox-mozilla-central
+# The MAR_CHANNEL_ID must not contain the following 3 characters: ",\t "
+MAR_CHANNEL_ID=firefox-mozilla-central
 MOZ_PROFILE_MIGRATOR=1
 MOZ_EXTENSION_MANAGER=1
 MOZ_APP_STATIC_INI=1
 MOZ_WEBAPP_RUNTIME=1
 MOZ_MEDIA_NAVIGATOR=1
 MOZ_PER_WINDOW_PRIVATE_BROWSING=1
--- a/browser/modules/NewTabUtils.jsm
+++ b/browser/modules/NewTabUtils.jsm
@@ -534,17 +534,17 @@ let PlacesProvider = {
     options.sortingMode = Ci.nsINavHistoryQueryOptions.SORT_BY_FRECENCY_DESCENDING
 
     let links = [];
 
     let callback = {
       handleResult: function (aResultSet) {
         let row;
 
-        while (row = aResultSet.getNextRow()) {
+        while ((row = aResultSet.getNextRow())) {
           let url = row.getResultByIndex(1);
           if (LinkChecker.checkLoadURI(url)) {
             let title = row.getResultByIndex(2);
             links.push({url: url, title: title});
           }
         }
       },
 
--- a/build/Makefile.in
+++ b/build/Makefile.in
@@ -52,16 +52,22 @@ GRE_MILESTONE = $(shell tail -n 1 $(tops
 APP_INI_DEPS = $(topsrcdir)/config/milestone.txt
 endif
 
 APP_BUILDID := $(shell cat $(DEPTH)/config/buildid)
 APP_INI_DEPS += $(DEPTH)/config/buildid
 
 DEFINES += -DGRE_MILESTONE=$(GRE_MILESTONE) -DAPP_BUILDID=$(APP_BUILDID)
 
+# Set a flag that can be used in pref files to disable features if
+# we are not building for Aurora or Nightly.
+ifeq (,$(findstring a,$(GRE_MILESTONE)))
+PREF_PPFLAGS += -DRELEASE_BUILD
+endif
+
 DEFINES += -DMOZ_APP_VERSION="$(MOZ_APP_VERSION)"
 APP_INI_DEPS += $(DEPTH)/config/autoconf.mk
 
 MOZ_SOURCE_STAMP := $(firstword $(shell cd $(topsrcdir)/$(MOZ_BUILD_APP)/.. && hg parent --template="{node|short}\n" 2>/dev/null))
 ifdef MOZ_SOURCE_STAMP
 DEFINES += -DMOZ_SOURCE_STAMP="$(MOZ_SOURCE_STAMP)"
 endif
 
--- a/build/autoconf/android.m4
+++ b/build/autoconf/android.m4
@@ -49,17 +49,17 @@ MOZ_ARG_WITH_STRING(android-platform,
                            location of platform dir],
     android_platform=$withval)
 
 case "$target" in
 arm-linux*-android*|*-linuxandroid*)
     android_tool_prefix="arm-linux-androideabi"
     ;;
 i?86-*android*)
-    android_tool_prefix="i686-android-linux"
+    android_tool_prefix="i686-linux-android"
     ;;
 mipsel-*android*)
     android_tool_prefix="mipsel-linux-android"
     ;;
 *)
     android_tool_prefix="$target_os"
     ;;
 esac
@@ -114,16 +114,27 @@ case "$target" in
 
         if test -d "$android_platform" ; then
             AC_MSG_RESULT([$android_platform])
         else
             AC_MSG_ERROR([not found. You have to specify --with-android-platform=/path/to/ndk/platform.])
         fi
     fi
 
+    dnl Old NDK support. If minimum requirement is changed to NDK r8b,
+    dnl please remove this.
+    case "$target_cpu" in
+    i?86)
+        if ! test -e "$android_toolchain"/bin/"$android_tool_prefix"-gcc; then
+            dnl Old NDK toolchain name
+            android_tool_prefix="i686-android-linux"
+        fi
+        ;;
+    esac
+
     dnl set up compilers
     TOOLCHAIN_PREFIX="$android_toolchain/bin/$android_tool_prefix-"
     AS="$android_toolchain"/bin/"$android_tool_prefix"-as
     CC="$android_toolchain"/bin/"$android_tool_prefix"-gcc
     CXX="$android_toolchain"/bin/"$android_tool_prefix"-g++
     CPP="$android_toolchain"/bin/"$android_tool_prefix"-cpp
     LD="$android_toolchain"/bin/"$android_tool_prefix"-ld
     AR="$android_toolchain"/bin/"$android_tool_prefix"-ar
--- a/build/unix/build-clang/build-clang.py
+++ b/build/unix/build-clang/build-clang.py
@@ -1,14 +1,14 @@
 #!/usr/bin/python
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
-llvm_revision = "169730"
+llvm_revision = "170377"
 moz_version = "moz0"
 
 ##############################################
 
 import os
 import os.path
 import shutil
 import tarfile
--- a/content/base/src/nsAttrValue.h
+++ b/content/base/src/nsAttrValue.h
@@ -14,22 +14,21 @@
 #include "nscore.h"
 #include "nsStringGlue.h"
 #include "nsStringBuffer.h"
 #include "nsColor.h"
 #include "nsCaseTreatment.h"
 #include "nsMargin.h"
 #include "nsCOMPtr.h"
 #include "SVGAttrValueWrapper.h"
+#include "nsTArrayForwardDeclare.h"
 
 class nsAString;
 class nsIAtom;
 class nsIDocument;
-template<class E, class A> class nsTArray;
-struct nsTArrayDefaultAllocator;
 class nsStyledElementNotElementCSSInlineStyle;
 struct MiscContainer;
 
 namespace mozilla {
 namespace css {
 class StyleRule;
 struct URLValue;
 struct ImageValue;
@@ -421,17 +420,17 @@ private:
                           nsresult* aErrorCode,
                           bool aCanBePercent = false,
                           bool* aIsPercent = nullptr) const;
   // Given an enum table and a particular entry in that table, return
   // the actual integer value we should store.
   int32_t EnumTableEntryToValue(const EnumTable* aEnumTable,
                                 const EnumTable* aTableEntry);  
 
-  static nsTArray<const EnumTable*, nsTArrayDefaultAllocator>* sEnumTableArray;
+  static nsTArray<const EnumTable*>* sEnumTableArray;
 
   uintptr_t mBits;
 };
 
 inline const nsAttrValue&
 nsAttrValue::operator=(const nsAttrValue& aOther)
 {
   SetTo(aOther);
--- a/content/base/src/nsFrameLoader.cpp
+++ b/content/base/src/nsFrameLoader.cpp
@@ -2059,16 +2059,24 @@ nsFrameLoader::TryRemoteBrowser()
     context.SetTabContextForBrowserFrame(containingApp, scrollingBehavior);
   }
 
   mRemoteBrowser = ContentParent::CreateBrowserOrApp(context);
   if (mRemoteBrowser) {
     nsCOMPtr<nsIDOMElement> element = do_QueryInterface(mOwnerContent);
     mRemoteBrowser->SetOwnerElement(element);
 
+    // If we're an app, send the frame element's mozapptype down to the child
+    // process.  This ends up in TabChild::GetAppType().
+    if (ownApp) {
+      nsAutoString appType;
+      mOwnerContent->GetAttr(kNameSpaceID_None, nsGkAtoms::mozapptype, appType);
+      mRemoteBrowser->SendSetAppType(appType);
+    }
+
     nsCOMPtr<nsIDocShellTreeItem> rootItem;
     parentAsItem->GetRootTreeItem(getter_AddRefs(rootItem));
     nsCOMPtr<nsIDOMWindow> rootWin = do_GetInterface(rootItem);
     nsCOMPtr<nsIDOMChromeWindow> rootChromeWin = do_QueryInterface(rootWin);
     NS_ABORT_IF_FALSE(rootChromeWin, "How did we not get a chrome window here?");
 
     nsCOMPtr<nsIBrowserDOMWindow> browserDOMWin;
     rootChromeWin->GetBrowserDOMWindow(getter_AddRefs(browserDOMWin));
--- a/content/base/src/nsGkAtomList.h
+++ b/content/base/src/nsGkAtomList.h
@@ -84,16 +84,17 @@ GK_ATOM(always, "always")
 GK_ATOM(ancestor, "ancestor")
 GK_ATOM(ancestorOrSelf, "ancestor-or-self")
 GK_ATOM(_and, "and")
 GK_ATOM(any, "any")
 GK_ATOM(mozapp, "mozapp")
 GK_ATOM(applet, "applet")
 GK_ATOM(applyImports, "apply-imports")
 GK_ATOM(applyTemplates, "apply-templates")
+GK_ATOM(mozapptype, "mozapptype")
 GK_ATOM(archive, "archive")
 GK_ATOM(area, "area")
 GK_ATOM(article, "article")
 GK_ATOM(ascending, "ascending")
 GK_ATOM(aside, "aside")
 GK_ATOM(aspectRatio, "aspect-ratio")
 GK_ATOM(assign, "assign")
 GK_ATOM(async, "async")
--- a/content/canvas/src/WebGLContextGL.cpp
+++ b/content/canvas/src/WebGLContextGL.cpp
@@ -1059,25 +1059,26 @@ WebGLContext::DeleteTexture(WebGLTexture
         return;
 
     if (!tex || tex->IsDeleted())
         return;
 
     if (mBoundFramebuffer)
         mBoundFramebuffer->DetachTexture(tex);
 
+    WebGLuint activeTexture = mActiveTexture;
     for (int32_t i = 0; i < mGLMaxTextureUnits; i++) {
         if ((tex->Target() == LOCAL_GL_TEXTURE_2D && mBound2DTextures[i] == tex) ||
             (tex->Target() == LOCAL_GL_TEXTURE_CUBE_MAP && mBoundCubeMapTextures[i] == tex))
         {
             ActiveTexture(LOCAL_GL_TEXTURE0 + i);
             BindTexture(tex->Target(), static_cast<WebGLTexture*>(nullptr));
         }
     }
-    ActiveTexture(LOCAL_GL_TEXTURE0 + mActiveTexture);
+    ActiveTexture(LOCAL_GL_TEXTURE0 + activeTexture);
 
     tex->RequestDelete();
 }
 
 void
 WebGLContext::DeleteProgram(WebGLProgram *prog)
 {
     if (!IsContextStable())
--- a/content/media/nsDOMMediaStream.cpp
+++ b/content/media/nsDOMMediaStream.cpp
@@ -90,28 +90,30 @@ nsDOMLocalMediaStream::CreateSourceStrea
   nsRefPtr<nsDOMLocalMediaStream> stream = new nsDOMLocalMediaStream();
   stream->SetHintContents(aHintContents);
   MediaStreamGraph* gm = MediaStreamGraph::GetInstance();
   stream->mStream = gm->CreateSourceStream(stream);
   return stream.forget();
 }
 
 already_AddRefed<nsDOMMediaStream>
-nsDOMMediaStream::CreateTrackUnionStream()
+nsDOMMediaStream::CreateTrackUnionStream(uint32_t aHintContents)
 {
   nsRefPtr<nsDOMMediaStream> stream = new nsDOMMediaStream();
+  stream->SetHintContents(aHintContents);
   MediaStreamGraph* gm = MediaStreamGraph::GetInstance();
   stream->mStream = gm->CreateTrackUnionStream(stream);
   return stream.forget();
 }
 
 already_AddRefed<nsDOMLocalMediaStream>
-nsDOMLocalMediaStream::CreateTrackUnionStream()
+nsDOMLocalMediaStream::CreateTrackUnionStream(uint32_t aHintContents)
 {
   nsRefPtr<nsDOMLocalMediaStream> stream = new nsDOMLocalMediaStream();
+  stream->SetHintContents(aHintContents);
   MediaStreamGraph* gm = MediaStreamGraph::GetInstance();
   stream->mStream = gm->CreateTrackUnionStream(stream);
   return stream.forget();
 }
 
 bool
 nsDOMMediaStream::CombineWithPrincipal(nsIPrincipal* aPrincipal)
 {
--- a/content/media/nsDOMMediaStream.h
+++ b/content/media/nsDOMMediaStream.h
@@ -65,17 +65,17 @@ public:
     HINT_CONTENTS_VIDEO = 0x00000002U
   };
   uint32_t GetHintContents() const { return mHintContents; }
   void SetHintContents(uint32_t aHintContents) { mHintContents = aHintContents; }
 
   /**
    * Create an nsDOMMediaStream whose underlying stream is a TrackUnionStream.
    */
-  static already_AddRefed<nsDOMMediaStream> CreateTrackUnionStream();
+  static already_AddRefed<nsDOMMediaStream> CreateTrackUnionStream(uint32_t aHintContents = 0);
 
 protected:
   // MediaStream is owned by the graph, but we tell it when to die, and it won't
   // die until we let it.
   MediaStream* mStream;
   // Principal identifying who may access the contents of this stream.
   // If null, this stream can be used by anyone because it has no content yet.
   nsCOMPtr<nsIPrincipal> mPrincipal;
@@ -101,12 +101,12 @@ public:
   /**
    * Create an nsDOMLocalMediaStream whose underlying stream is a SourceMediaStream.
    */
   static already_AddRefed<nsDOMLocalMediaStream> CreateSourceStream(uint32_t aHintContents);
 
   /**
    * Create an nsDOMLocalMediaStream whose underlying stream is a TrackUnionStream.
    */
-  static already_AddRefed<nsDOMLocalMediaStream> CreateTrackUnionStream();
+  static already_AddRefed<nsDOMLocalMediaStream> CreateTrackUnionStream(uint32_t aHintContents = 0);
 };
 
 #endif /* NSDOMMEDIASTREAM_H_ */
--- a/content/media/ogg/OggReader.cpp
+++ b/content/media/ogg/OggReader.cpp
@@ -416,24 +416,27 @@ nsresult OggReader::DecodeVorbis(ogg_pac
     }
   }
   return NS_OK;
 }
 #ifdef MOZ_OPUS
 nsresult OggReader::DecodeOpus(ogg_packet* aPacket) {
   NS_ASSERTION(aPacket->granulepos != -1, "Must know opus granulepos!");
 
-  // Maximum value is 63*2880.
+  // Maximum value is 63*2880, so there's no chance of overflow.
   int32_t frames_number = opus_packet_get_nb_frames(aPacket->packet,
                                                     aPacket->bytes);
+  if (frames_number <= 0)
+    return NS_ERROR_FAILURE; // Invalid packet header.
   int32_t samples = opus_packet_get_samples_per_frame(aPacket->packet,
                                                       (opus_int32) mOpusState->mRate);
   int32_t frames = frames_number*samples;
 
-  if (frames <= 0)
+  // A valid Opus packet must be between 2.5 and 120 ms long.
+  if (frames < 120 || frames > 5760)
     return NS_ERROR_FAILURE;
   uint32_t channels = mOpusState->mChannels;
   nsAutoArrayPtr<AudioDataValue> buffer(new AudioDataValue[frames * channels]);
 
   // Decode to the appropriate sample type.
 #ifdef MOZ_SAMPLE_TYPE_FLOAT32
   int ret = opus_multistream_decode_float(mOpusState->mDecoder,
                                           aPacket->packet, aPacket->bytes,
--- a/docshell/shistory/public/nsISHistoryInternal.idl
+++ b/docshell/shistory/public/nsISHistoryInternal.idl
@@ -13,21 +13,20 @@ interface nsIDocShell;
 
 %{C++
 #define NS_SHISTORY_INTERNAL_CID \
 { 0x9c47c121, 0x1c6e, 0x4d8f, \
   { 0xb9, 0x04, 0x3a, 0xc9, 0x68, 0x11, 0x6e, 0x88 } }
 
 #define NS_SHISTORY_INTERNAL_CONTRACTID "@mozilla.org/browser/shistory-internal;1"
 
-template<class E, class A> class nsTArray;
-struct nsTArrayDefaultAllocator;
+#include "nsTArrayForwardDeclare.h"
 %}
 
-[ref] native nsDocshellIDArray(nsTArray<uint64_t, nsTArrayDefaultAllocator>);
+[ref] native nsDocshellIDArray(nsTArray<uint64_t>);
 
 [scriptable, uuid(f9348014-0239-11e2-b029-3d38e719eb2d)]
 interface nsISHistoryInternal: nsISupports
 {
   /**
    * Add a new Entry to the History List
    * @param aEntry - The entry to add
    * @param aPersist - If true this specifies that the entry should persist
--- a/dom/apps/src/Webapps.jsm
+++ b/dom/apps/src/Webapps.jsm
@@ -863,25 +863,36 @@ this.DOMApplicationRegistry = {
       aMm.sendAsyncMessage("Webapps:Launch:Return:KO", aData);
       return;
     }
 
     Services.obs.notifyObservers(aMm, "webapps-launch", JSON.stringify(aData));
   },
 
   cancelDownload: function cancelDownload(aManifestURL) {
-    // We can't cancel appcache downloads for now.
-    if (!this.downloads[aManifestURL]) {
+    debug("cancelDownload " + aManifestURL);
+    let download = this.downloads[aManifestURL];
+    if (!download) {
+      debug("Could not find a download for " + aManifestURL);
       return;
     }
-    // This is a HTTP channel.
-    let download = this.downloads[aManifestURL]
-    download.channel.cancel(Cr.NS_BINDING_ABORTED);
+
+    if (download.cacheUpdate) {
+      // Cancel hosted app download.
+      try {
+        download.cacheUpdate.cancel();
+      } catch (e) { debug (e); }
+    } else if (download.channel) {
+      // Cancel packaged app download.
+      download.channel.cancel(Cr.NS_BINDING_ABORTED);
+    } else {
+      return;
+    }
+
     let app = this.webapps[download.appId];
-
     app.progress = 0;
     app.installState = download.previousState;
     app.downloading = false;
     app.downloadAvailable = false;
     app.downloadSize = 0;
     this._saveApps((function() {
       this.broadcastMessage("Webapps:PackageEvent",
                              { type: "canceled",
@@ -1033,36 +1044,52 @@ this.DOMApplicationRegistry = {
       });
     }).bind(this));
   },
 
   startOfflineCacheDownload: function startOfflineCacheDownload(aManifest, aApp,
                                                                 aProfileDir,
                                                                 aOfflineCacheObserver,
                                                                 aIsUpdate) {
-    // if the manifest has an appcache_path property, use it to populate the appcache
-    if (aManifest.appcache_path) {
-      let appcacheURI = Services.io.newURI(aManifest.fullAppcachePath(), null, null);
-      let docURI = Services.io.newURI(aManifest.fullLaunchPath(), null, null);
-      // We determine the app's 'installState' according to its previous
-      // state. Cancelled download should remain as 'pending'. Successfully
-      // installed apps should morph to 'updating'.
-      if (aIsUpdate) {
-        aApp.installState = "updating";
-      }
-      // We set the 'downloading' flag right before starting the app
-      // download/update.
-      aApp.downloading = true;
-      let cacheUpdate = aProfileDir
-        ? updateSvc.scheduleCustomProfileUpdate(appcacheURI, docURI, aProfileDir)
-        : updateSvc.scheduleAppUpdate(appcacheURI, docURI, aApp.localId, false);
-      cacheUpdate.addObserver(new AppcacheObserver(aApp), false);
-      if (aOfflineCacheObserver) {
-        cacheUpdate.addObserver(aOfflineCacheObserver, false);
-      }
+    if (!aManifest.appcache_path) {
+      return;
+    }
+
+    // If the manifest has an appcache_path property, use it to populate the
+    // appcache.
+    let appcacheURI = Services.io.newURI(aManifest.fullAppcachePath(),
+                                         null, null);
+    let docURI = Services.io.newURI(aManifest.fullLaunchPath(), null, null);
+
+    // We determine the app's 'installState' according to its previous
+    // state. Cancelled downloads should remain as 'pending'. Successfully
+    // installed apps should morph to 'updating'.
+    if (aIsUpdate) {
+      aApp.installState = "updating";
+    }
+
+    // We set the 'downloading' flag right before starting the app
+    // download/update.
+    aApp.downloading = true;
+    let cacheUpdate = aProfileDir
+      ? updateSvc.scheduleCustomProfileUpdate(appcacheURI, docURI, aProfileDir)
+      : updateSvc.scheduleAppUpdate(appcacheURI, docURI, aApp.localId, false);
+
+    // We save the download details for potential further usage like cancelling
+    // it.
+    let download = {
+      cacheUpdate: cacheUpdate,
+      appId: this._appIdForManifestURL(aApp.manifestURL),
+      previousState: aIsUpdate ? "installed" : "pending"
+    };
+    this.downloads[aApp.manifestURL] = download;
+
+    cacheUpdate.addObserver(new AppcacheObserver(aApp), false);
+    if (aOfflineCacheObserver) {
+      cacheUpdate.addObserver(aOfflineCacheObserver, false);
     }
   },
 
   checkForUpdate: function(aData, aMm) {
     debug("checkForUpdate for " + aData.manifestURL);
     let id = this._appIdForManifestURL(aData.manifestURL);
     let app = this.webapps[id];
 
@@ -1709,21 +1736,21 @@ this.DOMApplicationRegistry = {
                               app: app });
     }
 
     function download() {
       debug("About to download " + aManifest.fullPackagePath());
 
       let requestChannel = NetUtil.newChannel(aManifest.fullPackagePath())
                                   .QueryInterface(Ci.nsIHttpChannel);
-      self.downloads[aApp.manifestURL] =
-        { channel:requestChannel,
-          appId: id,
-          previousState: aIsUpdate ? "installed" : "pending"
-        };
+      self.downloads[aApp.manifestURL] = {
+        channel: requestChannel,
+        appId: id,
+        previousState: aIsUpdate ? "installed" : "pending"
+      };
 
       let lastProgressTime = 0;
       requestChannel.notificationCallbacks = {
         QueryInterface: function notifQI(aIID) {
           if (aIID.equals(Ci.nsISupports)          ||
               aIID.equals(Ci.nsIProgressEventSink) ||
               aIID.equals(Ci.nsILoadContext))
             return this;
--- a/dom/bindings/BindingUtils.h
+++ b/dom/bindings/BindingUtils.h
@@ -1365,16 +1365,20 @@ public:
   const T& Value() const {
     return mImpl.ref();
   }
 
   T& Value() {
     return mImpl.ref();
   }
 
+  // If we ever decide to add conversion operators for optional arrays
+  // like the ones Nullable has, we'll need to ensure that Maybe<> has
+  // the boolean before the actual data.
+
 private:
   // Forbid copy-construction and assignment
   Optional(const Optional& other) MOZ_DELETE;
   const Optional &operator=(const Optional &other) MOZ_DELETE;
   
   Maybe<T> mImpl;
 };
 
--- a/dom/bindings/Nullable.h
+++ b/dom/bindings/Nullable.h
@@ -3,36 +3,39 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_Nullable_h
 #define mozilla_dom_Nullable_h
 
 #include "mozilla/Assertions.h"
+#include "nsTArrayForwardDeclare.h"
 
 namespace mozilla {
 namespace dom {
 
 // Support for nullable types
 template <typename T>
 struct Nullable
 {
 private:
+  // mIsNull MUST COME FIRST because otherwise the casting in our array
+  // conversion operators would shift where it is found in the struct.
+  bool mIsNull;
   T mValue;
-  bool mIsNull;
 
 public:
   Nullable()
     : mIsNull(true)
   {}
 
-  Nullable(T aValue)
-    : mValue(aValue)
-    , mIsNull(false)
+  explicit Nullable(T aValue)
+    : mIsNull(false)
+    , mValue(aValue)
   {}
 
   void SetValue(T aValue) {
     mValue = aValue;
     mIsNull = false;
   }
 
   // For cases when |T| is some type with nontrivial copy behavior, we may want
@@ -55,14 +58,31 @@ public:
   T& Value() {
     MOZ_ASSERT(!mIsNull);
     return mValue;
   }
 
   bool IsNull() const {
     return mIsNull;
   }
+
+  // Make it possible to use a const Nullable of an array type with other
+  // array types.
+  template<typename U>
+  operator const Nullable< nsTArray<U> >&() const {
+    // Make sure that T is ok to reinterpret to nsTArray<U>
+    const nsTArray<U>& arr = mValue;
+    (void)arr;
+    return *reinterpret_cast<const Nullable< nsTArray<U> >*>(this);
+  }
+  template<typename U>
+  operator const Nullable< FallibleTArray<U> >&() const {
+    // Make sure that T is ok to reinterpret to FallibleTArray<U>
+    const FallibleTArray<U>& arr = mValue;
+    (void)arr;
+    return *reinterpret_cast<const Nullable< FallibleTArray<U> >*>(this);
+  }
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif /* mozilla_dom_Nullable_h */
--- a/dom/bluetooth/BluetoothDevice.cpp
+++ b/dom/bluetooth/BluetoothDevice.cpp
@@ -176,17 +176,17 @@ BluetoothDevice::Create(nsPIDOMWindow* a
 }
 
 void
 BluetoothDevice::Notify(const BluetoothSignal& aData)
 {
   if (aData.name().EqualsLiteral("PropertyChanged")) {
     NS_ASSERTION(aData.value().type() == BluetoothValue::TArrayOfBluetoothNamedValue,
                  "PropertyChanged: Invalid value type");
-    InfallibleTArray<BluetoothNamedValue> arr = aData.value().get_ArrayOfBluetoothNamedValue();
+    InfallibleTArray<BluetoothNamedValue> arr(aData.value().get_ArrayOfBluetoothNamedValue());
 
     NS_ASSERTION(arr.Length() == 1, "Got more than one property in a change message!");
     BluetoothNamedValue v = arr[0];
     nsString name = v.name();
 
     SetPropertyByValue(v);
     if (name.EqualsLiteral("Connected")) {
       DispatchTrustedEvent(mConnected ? NS_LITERAL_STRING("connected")
--- a/dom/bluetooth/BluetoothService.cpp
+++ b/dom/bluetooth/BluetoothService.cpp
@@ -698,17 +698,17 @@ BluetoothService::Observe(nsISupports* a
 
   MOZ_ASSERT(false, "BluetoothService got unexpected topic!");
   return NS_ERROR_UNEXPECTED;
 }
 
 void
 BluetoothService::Notify(const BluetoothSignal& aData)
 {
-  InfallibleTArray<BluetoothNamedValue> arr = aData.value().get_ArrayOfBluetoothNamedValue();
+  InfallibleTArray<BluetoothNamedValue> arr(aData.value().get_ArrayOfBluetoothNamedValue());
   nsString type;
 
   JSContext* cx = nsContentUtils::GetSafeJSContext();
   NS_ASSERTION(!::JS_IsExceptionPending(cx),
                "Shouldn't get here when an exception is pending!");
 
   JSAutoRequest jsar(cx);
   JSObject* obj = JS_NewObject(cx, NULL, NULL, NULL);
--- a/dom/bluetooth/ipc/BluetoothParent.cpp
+++ b/dom/bluetooth/ipc/BluetoothParent.cpp
@@ -388,19 +388,18 @@ BluetoothRequestParent::DoRequest(const 
 }
 
 bool
 BluetoothRequestParent::DoRequest(const DevicePropertiesRequest& aRequest)
 {
   MOZ_ASSERT(mService);
   MOZ_ASSERT(mRequestType == Request::TDevicePropertiesRequest);
 
-  // Have to copy because our array types don't match up
   nsresult rv =
-    mService->GetPairedDevicePropertiesInternal(nsTArray<nsString>(aRequest.addresses()),
+    mService->GetPairedDevicePropertiesInternal(aRequest.addresses(),
                                                 mReplyRunnable.get());
   NS_ENSURE_SUCCESS(rv, false);
 
   return true;
 }
 
 bool
 BluetoothRequestParent::DoRequest(const SetPinCodeRequest& aRequest)
--- a/dom/bluetooth/linux/BluetoothDBusService.cpp
+++ b/dom/bluetooth/linux/BluetoothDBusService.cpp
@@ -1715,38 +1715,38 @@ public:
   NS_IMETHOD Run()
   {
     MOZ_ASSERT(!NS_IsMainThread());
 
     nsString devicePath;
     BluetoothValue v = mSignal.value();
     if (v.type() == BluetoothValue::TArrayOfBluetoothNamedValue &&
         v.get_ArrayOfBluetoothNamedValue().Length() ) {
-      InfallibleTArray<BluetoothNamedValue> arr = v.get_ArrayOfBluetoothNamedValue();
+      const InfallibleTArray<BluetoothNamedValue>& arr = v.get_ArrayOfBluetoothNamedValue();
       NS_ASSERTION(arr[0].value().type() == BluetoothValue::TnsString, "failed to get_nsString");
       devicePath = arr[0].value().get_nsString();
     }
     else if (v.type() == BluetoothValue::TnsString) {
       devicePath = v.get_nsString();
     }
     else {
       NS_WARNING("Invalid value type for GetDeviceProperties() method");
       return NS_ERROR_FAILURE;
     }
 
     BluetoothValue prop;
     if (!GetPropertiesInternal(devicePath, DBUS_DEVICE_IFACE, prop)) {
       NS_WARNING("Getting properties failed!");
       return NS_ERROR_FAILURE;
     }
-    InfallibleTArray<BluetoothNamedValue> properties = prop.get_ArrayOfBluetoothNamedValue();
+    InfallibleTArray<BluetoothNamedValue> properties(prop.get_ArrayOfBluetoothNamedValue());
     if (v.type() == BluetoothValue::TArrayOfBluetoothNamedValue) {
       // Return original dbus message parameters and also device name
       // for agent events "RequestConfirmation", "RequestPinCode", and "RequestPasskey"
-      InfallibleTArray<BluetoothNamedValue> parameters = v.get_ArrayOfBluetoothNamedValue();
+      InfallibleTArray<BluetoothNamedValue> parameters(v.get_ArrayOfBluetoothNamedValue());
 
       // For consistency, append path
       nsString path = parameters[0].value();
       BluetoothNamedValue pathprop;
       pathprop.name().AssignLiteral("Path");
       pathprop.value() = path;
       parameters.AppendElement(pathprop);
 
@@ -1799,17 +1799,17 @@ public:
   Run()
   {
     MOZ_ASSERT(!NS_IsMainThread());
     DBusError err;
     dbus_error_init(&err);
 
     BluetoothValue values = InfallibleTArray<BluetoothNamedValue>();
 
-    for (int i = 0; i < mDeviceAddresses.Length(); i++) {
+    for (uint32_t i = 0; i < mDeviceAddresses.Length(); i++) {
       BluetoothValue v;
       if (!GetPropertiesInternal(mDeviceAddresses[i], DBUS_DEVICE_IFACE, v)) {
         nsAutoString errorStr;
         errorStr.AssignLiteral("Getting properties failed!");
         NS_WARNING(NS_ConvertUTF16toUTF8(errorStr).get());
         mRunnable->SetReply(new BluetoothReply(BluetoothReplyError(errorStr)));
         if (NS_FAILED(NS_DispatchToMainThread(mRunnable))) {
           NS_WARNING("Failed to dispatch to main thread!");
--- a/dom/browser-element/BrowserElementScrolling.js
+++ b/dom/browser-element/BrowserElementScrolling.js
@@ -1,207 +1,117 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 const ContentPanning = {
   init: function cp_init() {
-    ['mousedown', 'mouseup', 'mousemove', 'touchstart', 'touchend', 'touchmove'].forEach(function(type) {
+    ['mousedown', 'mouseup', 'mousemove'].forEach(function(type) {
       addEventListener(type, ContentPanning, false);
     });
 
     addMessageListener("Viewport:Change", this._recvViewportChange.bind(this));
     addMessageListener("Gesture:DoubleTap", this._recvDoubleTap.bind(this));
   },
 
-  evtFilter: '',
-  _filterEvent: function cp_filterEvent(evt) {
-    switch (this.evtFilter) {
-      case 'mouse':
-        if (evt.type == 'touchstart' || evt.type == 'touchend' || evt.type == 'touchmove') {
-          return false;
-        }
-        break;
-      case 'touch':
-        if (evt.type == 'mousedown' || evt.type == 'mouseup' || evt.type == 'mousemove') {
-          return false;
-        }
-        break;
-    }
-    return true;
-  },
   handleEvent: function cp_handleEvent(evt) {
-    // determine scrolling detection is based on touch or mouse event at runtime
-    if (!this.evtFilter) {
-      if (evt.type == 'touchstart') this.evtFilter = 'touch';
-      else if (evt.type == 'mousedown') this.evtFilter = 'mouse';
-    }
-    if (evt.defaultPrevented || !this._filterEvent(evt)) return;
-
     switch (evt.type) {
       case 'mousedown':
-      case 'touchstart':
         this.onTouchStart(evt);
         break;
       case 'mousemove':
-      case 'touchmove':
         this.onTouchMove(evt);
         break;
       case 'mouseup':
-      case 'touchend':
         this.onTouchEnd(evt);
         break;
       case 'click':
         evt.stopPropagation();
         evt.preventDefault();
 
         let target = evt.target;
         let view = target.ownerDocument ? target.ownerDocument.defaultView
                                         : target;
         view.removeEventListener('click', this, true, true);
         break;
     }
   },
 
   position: new Point(0 , 0),
 
-  findFirstTouch: function cp_findFirstTouch(touches) {
-    if (!('trackingId' in this)) return undefined;
-
-    for (let i = 0; i < touches.length; i++) {
-      if (touches[i].identifier === this.trackingId)
-        return touches[i];
-    }
-    return undefined;
-  },
-
   onTouchStart: function cp_onTouchStart(evt) {
-    let target, screenX, screenY;
-    if (this.evtFilter == 'touch') {
-      if ('trackingId' in this) {
-        return;
-      }
-
-      let firstTouch = evt.changedTouches[0];
-      this.trackingId = firstTouch.identifier;
-      target = firstTouch.target;
-      screenX = firstTouch.screenX;
-      screenY = firstTouch.screenY;
-    } else {
-      target = evt.target;
-      screenX = evt.screenX;
-      screenY = evt.screenY;
-    }
-
     this.dragging = true;
     this.panning = false;
 
     let oldTarget = this.target;
-    [this.target, this.scrollCallback] = this.getPannable(target);
+    [this.target, this.scrollCallback] = this.getPannable(evt.target);
 
     // If we found a target, that means we have found a scrollable subframe. In
     // this case, and if we are using async panning and zooming on the parent
     // frame, inform the pan/zoom controller that it should not attempt to
     // handle any touch events it gets until the next batch (meaning the next
     // time we get a touch end).
     if (this.target != null && ContentPanning._asyncPanZoomForViewportFrame) {
       var os = Cc["@mozilla.org/observer-service;1"].getService(Ci.nsIObserverService);
-      os.notifyObservers(docShell, 'detect-scrollable-subframe', null);
+      os.notifyObservers(docShell, 'cancel-default-pan-zoom', null);
     }
 
     // If there is a pan animation running (from a previous pan gesture) and
     // the user touch back the screen, stop this animation immediatly and
     // prevent the possible click action if the touch happens on the same
     // target.
     this.preventNextClick = false;
     if (KineticPanning.active) {
       KineticPanning.stop();
 
       if (oldTarget && oldTarget == this.target)
         this.preventNextClick = true;
     }
 
 
-    this.position.set(screenX, screenY);
+    this.position.set(evt.screenX, evt.screenY);
     KineticPanning.record(new Point(0, 0), evt.timeStamp);
   },
 
   onTouchEnd: function cp_onTouchEnd(evt) {
-    if (this.evtFilter == 'touch' && !this.findFirstTouch(evt.changedTouches))
-      return;
-
     if (!this.dragging)
       return;
     this.dragging = false;
-    this.isScrolling = false;
 
     this.onTouchMove(evt);
 
-    delete this.trackingId;
-
-    let click = (this.evtFilter == 'touch') ? true : evt.detail;
+    let click = evt.detail;
     if (this.target && click && (this.panning || this.preventNextClick)) {
       let target = this.target;
       let view = target.ownerDocument ? target.ownerDocument.defaultView
                                       : target;
       view.addEventListener('click', this, true, true);
     }
 
     if (this.panning)
       KineticPanning.start(this);
   },
 
-  isScrolling: false, // Scrolling gesture is executed in BrowserElementScrolling
   onTouchMove: function cp_onTouchMove(evt) {
     if (!this.dragging || !this.scrollCallback)
       return;
 
-    let screenX, screenY;
-    if (this.evtFilter == 'touch') {
-      let firstTouch = this.findFirstTouch(evt.changedTouches);
-      if (evt.touches.length > 1 || !firstTouch)
-        return;
-      screenX = firstTouch.screenX;
-      screenY = firstTouch.screenY;
-    } else {
-      screenX = evt.screenX;
-      screenY = evt.screenY;
-    }
-
     let current = this.position;
-    let delta = new Point(screenX - current.x, screenY - current.y);
-    current.set(screenX, screenY);
+    let delta = new Point(evt.screenX - current.x, evt.screenY - current.y);
+    current.set(evt.screenX, evt.screenY);
 
     KineticPanning.record(delta, evt.timeStamp);
-    let success = this.scrollCallback(delta.scale(-1));
+    this.scrollCallback(delta.scale(-1));
 
-    // Stop async-pan-zooming if the subframe is really scrolled.
-    if (!this.isScrolling && ContentPanning._asyncPanZoomForViewportFrame) {
-      if (success) {
-        var os = Cc["@mozilla.org/observer-service;1"].getService(Ci.nsIObserverService);
-        os.notifyObservers(docShell, 'cancel-default-pan-zoom', null);
-      } else {
-        // Let AsyncPanZoomController handle the scrolling gesture.
-        delete this.trackingId;
-        return;
-      }
-    }
-
-    // Successfully scroll the inner scrollable region.
-    if (success && !this.isScrolling) {
-      this.isScrolling = true;
-    }
-      
     // If a pan action happens, cancel the active state of the
     // current target.
     if (!this.panning && KineticPanning.isPan()) {
       this.panning = true;
       this._resetActive();
     }
-
     evt.stopPropagation();
     evt.preventDefault();
   },
 
 
   onKineticBegin: function cp_onKineticBegin(evt) {
   },
 
--- a/dom/camera/GonkCameraControl.cpp
+++ b/dom/camera/GonkCameraControl.cpp
@@ -42,16 +42,26 @@
 #include "GonkCameraControl.h"
 #include "CameraCommon.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 using namespace mozilla::layers;
 using namespace android;
 
+/**
+ * See bug 783682.  Most camera implementations, despite claiming they
+ * support 'yuv420p' as a preview format, actually ignore this setting
+ * and return 'yuv420sp' data anyway.  We have come across a new implementation
+ * that, while reporting that 'yuv420p' is supported *and* has been accepted,
+ * still returns the frame data in 'yuv420sp' anyway.  So for now, since
+ * everyone seems to return this format, we just force it.
+ */
+#define FORCE_PREVIEW_FORMAT_YUV420SP   1
+
 static const char* getKeyText(uint32_t aKey)
 {
   switch (aKey) {
     case CAMERA_PARAM_EFFECT:
       return CameraParameters::KEY_EFFECT;
     case CAMERA_PARAM_WHITEBALANCE:
       return CameraParameters::KEY_WHITE_BALANCE;
     case CAMERA_PARAM_SCENEMODE:
@@ -184,17 +194,21 @@ nsGonkCameraControl::nsGonkCameraControl
   , mHwHandle(0)
   , mExposureCompensationMin(0.0)
   , mExposureCompensationStep(0.0)
   , mDeferConfigUpdate(false)
   , mWidth(0)
   , mHeight(0)
   , mLastPictureWidth(0)
   , mLastPictureHeight(0)
+#if !FORCE_PREVIEW_FORMAT_YUV420SP
   , mFormat(PREVIEW_FORMAT_UNKNOWN)
+#else
+  , mFormat(PREVIEW_FORMAT_YUV420SP)
+#endif
   , mFps(30)
   , mDiscardedFrameCount(0)
   , mMediaProfiles(nullptr)
   , mRecorder(nullptr)
   , mProfileManager(nullptr)
   , mRecorderProfile(nullptr)
   , mVideoFile(nullptr)
 {
@@ -212,35 +226,42 @@ nsGonkCameraControl::Init()
 {
   mHwHandle = GonkCameraHardware::GetHandle(this, mCameraId);
   DOM_CAMERA_LOGI("Initializing camera %d (this=%p, mHwHandle=%d)\n", mCameraId, this, mHwHandle);
 
   // Initialize our camera configuration database.
   PullParametersImpl();
 
   // Try to set preferred image format and frame rate
+#if !FORCE_PREVIEW_FORMAT_YUV420SP
   DOM_CAMERA_LOGI("Camera preview formats: %s\n", mParams.get(mParams.KEY_SUPPORTED_PREVIEW_FORMATS));
   const char* const PREVIEW_FORMAT = "yuv420p";
   const char* const BAD_PREVIEW_FORMAT = "yuv420sp";
   mParams.setPreviewFormat(PREVIEW_FORMAT);
   mParams.setPreviewFrameRate(mFps);
+#else
+  mParams.setPreviewFormat("yuv420sp");
+  mParams.setPreviewFrameRate(mFps);
+#endif
   PushParametersImpl();
 
   // Check that our settings stuck
   PullParametersImpl();
+#if !FORCE_PREVIEW_FORMAT_YUV420SP
   const char* format = mParams.getPreviewFormat();
   if (strcmp(format, PREVIEW_FORMAT) == 0) {
     mFormat = PREVIEW_FORMAT_YUV420P;  /* \o/ */
   } else if (strcmp(format, BAD_PREVIEW_FORMAT) == 0) {
     mFormat = PREVIEW_FORMAT_YUV420SP;
     DOM_CAMERA_LOGA("Camera ignored our request for '%s' preview, will have to convert (from %d)\n", PREVIEW_FORMAT, mFormat);
   } else {
     mFormat = PREVIEW_FORMAT_UNKNOWN;
     DOM_CAMERA_LOGE("Camera ignored our request for '%s' preview, returned UNSUPPORTED format '%s'\n", PREVIEW_FORMAT, format);
   }
+#endif
 
   // Check the frame rate and log if the camera ignored our setting
   uint32_t fps = mParams.getPreviewFrameRate();
   if (fps != mFps) {
     DOM_CAMERA_LOGA("We asked for %d fps but camera returned %d fps, using that", mFps, fps);
     mFps = fps;
   }
 
--- a/dom/identity/nsDOMIdentity.js
+++ b/dom/identity/nsDOMIdentity.js
@@ -4,16 +4,21 @@
 
 "use strict";
 
 const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
 
 const PREF_DEBUG = "toolkit.identity.debug";
 const PREF_ENABLED = "dom.identity.enabled";
 
+// Bug 822450: Workaround for Bug 821740.  When testing with marionette,
+// relax navigator.id.request's requirement that it be handling native
+// events.  Synthetic marionette events are ok.
+const PREF_SYNTHETIC_EVENTS_OK = "dom.identity.syntheticEventsOk";
+
 // Maximum length of a string that will go through IPC
 const MAX_STRING_LENGTH = 2048;
 // Maximum number of times navigator.id.request can be called for a document
 const MAX_RP_CALLS = 100;
 
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/identity/IdentityUtils.jsm");
@@ -42,17 +47,24 @@ nsDOMIdentity.prototype = {
     raiseProvisioningFailure: 'r',
 
     // Authentication
     beginAuthentication: 'r',
     completeAuthentication: 'r',
     raiseAuthenticationFailure: 'r',
   },
 
-  // nsIDOMIdentity
+  // require native events unless syntheticEventsOk is set
+  get nativeEventsRequired() {
+    if (Services.prefs.prefHasUserValue(PREF_SYNTHETIC_EVENTS_OK)) {
+      return !Services.prefs.getBoolPref(PREF_SYNTHETIC_EVENTS_OK);
+    }
+    return true;
+  },
+
   /**
    * Relying Party (RP) APIs
    */
 
   watch: function nsDOMIdentity_watch(aOptions) {
     if (this._rpWatcher) {
       throw new Error("navigator.id.watch was already called");
     }
@@ -110,17 +122,18 @@ nsDOMIdentity.prototype = {
   request: function nsDOMIdentity_request(aOptions) {
     let util = this._window.QueryInterface(Ci.nsIInterfaceRequestor)
                            .getInterface(Ci.nsIDOMWindowUtils);
 
     // The only time we permit calling of request() outside of a user
     // input handler is when we are handling the (deprecated) get() or
     // getVerifiedEmail() calls, which make use of an RP context
     // marked as _internal.
-    if (!util.isHandlingUserInput && !aOptions._internal) {
+    if (this.nativeEventsRequired && !util.isHandlingUserInput && !aOptions._internal) {
+      this._log("request: rejecting non-native event");
       return;
     }
 
     // Has the caller called watch() before this?
     if (!this._rpWatcher) {
       throw new Error("navigator.id.request called before navigator.id.watch");
     }
     if (this._rpCalls > MAX_RP_CALLS) {
--- a/dom/indexedDB/IDBIndex.cpp
+++ b/dom/indexedDB/IDBIndex.cpp
@@ -1663,17 +1663,17 @@ GetAllHelper::UnpackResponseFromParentPr
   const InfallibleTArray<SerializedStructuredCloneReadInfo>& cloneInfos =
     getAllResponse.cloneInfos();
   const InfallibleTArray<BlobArray>& blobArrays = getAllResponse.blobs();
 
   mCloneReadInfos.SetCapacity(cloneInfos.Length());
 
   for (uint32_t index = 0; index < cloneInfos.Length(); index++) {
     const SerializedStructuredCloneReadInfo srcInfo = cloneInfos[index];
-    const InfallibleTArray<PBlobChild*> blobs = blobArrays[index].blobsChild();
+    const InfallibleTArray<PBlobChild*>& blobs = blobArrays[index].blobsChild();
 
     StructuredCloneReadInfo* destInfo = mCloneReadInfos.AppendElement();
     if (!destInfo->SetFromSerialized(srcInfo)) {
       NS_WARNING("Failed to copy clone buffer!");
       return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
     }
 
     IDBObjectStore::ConvertActorsToBlobs(blobs, destInfo->mFiles);
--- a/dom/indexedDB/IDBObjectStore.cpp
+++ b/dom/indexedDB/IDBObjectStore.cpp
@@ -3902,17 +3902,17 @@ GetAllHelper::UnpackResponseFromParentPr
   const InfallibleTArray<SerializedStructuredCloneReadInfo>& cloneInfos =
     getAllResponse.cloneInfos();
   const InfallibleTArray<BlobArray>& blobArrays = getAllResponse.blobs();
 
   mCloneReadInfos.SetCapacity(cloneInfos.Length());
 
   for (uint32_t index = 0; index < cloneInfos.Length(); index++) {
     const SerializedStructuredCloneReadInfo srcInfo = cloneInfos[index];
-    const InfallibleTArray<PBlobChild*> blobs = blobArrays[index].blobsChild();
+    const InfallibleTArray<PBlobChild*>& blobs = blobArrays[index].blobsChild();
 
     StructuredCloneReadInfo* destInfo = mCloneReadInfos.AppendElement();
     if (!destInfo->SetFromSerialized(srcInfo)) {
       NS_WARNING("Failed to copy clone buffer!");
       return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
     }
 
     IDBObjectStore::ConvertActorsToBlobs(blobs, destInfo->mFiles);
--- a/dom/ipc/PBrowser.ipdl
+++ b/dom/ipc/PBrowser.ipdl
@@ -378,16 +378,30 @@ child:
      * the document.  The rendered image will be of size |renderSize|.
      */
     PDocumentRenderer(nsRect documentRect, gfxMatrix transform,
                       nsString bgcolor,
                       uint32_t renderFlags, bool flushLayout,
                       nsIntSize renderSize);
 
     /**
+     * Send the child its app type.  The app type identifies the kind of app
+     * shown in this PBrowser.  Currently, the only recognized app type is
+     * "homescreen".
+     *
+     * The value here corresponds to the "mozapptype" attribute on iframes.  For
+     * example, <iframe mozbrowser mozapp="..." mozapptype="homescreen">.
+     *
+     * Only app frames (i.e., frames with an app-id) should have a non-empty app
+     * type.  If you try to SetAppType() with a non-empty app type on a non-app
+     * PBrowserChild, we may assert.
+     */
+    SetAppType(nsString appType);
+
+    /**
      * Sent by the chrome process when it no longer wants this remote
      * <browser>.  The child side cleans up in response, then
      * finalizing its death by sending back __delete__() to the
      * parent.
      */
     Destroy();
 
 /*
--- a/dom/ipc/ProcessPriorityManager.cpp
+++ b/dom/ipc/ProcessPriorityManager.cpp
@@ -1,15 +1,17 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set sw=2 ts=8 et ft=cpp : */
 /* 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/dom/ipc/ProcessPriorityManager.h"
+#include "mozilla/dom/ContentChild.h"
+#include "mozilla/dom/TabChild.h"
 #include "mozilla/Hal.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/Services.h"
 #include "mozilla/HalTypes.h"
 #include "mozilla/TimeStamp.h"
 #include "prlog.h"
 #include "nsWeakPtr.h"
 #include "nsXULAppAPI.h"
@@ -64,16 +66,43 @@ GetPPMLog()
 #define LOG(fmt, ...) \
   PR_LOG(GetPPMLog(), PR_LOG_DEBUG,                                     \
          ("[%d] ProcessPriorityManager - " fmt, getpid(), ##__VA_ARGS__))
 #else
 #define LOG(fmt, ...)
 #endif
 
 /**
+ * Get the appropriate backround priority for this process.
+ */
+ProcessPriority
+GetBackgroundPriority()
+{
+  bool isHomescreen = false;
+
+  ContentChild* contentChild = ContentChild::GetSingleton();
+  if (contentChild) {
+    const InfallibleTArray<PBrowserChild*>& browsers =
+      contentChild->ManagedPBrowserChild();
+    for (uint32_t i = 0; i < browsers.Length(); i++) {
+      nsAutoString appType;
+      static_cast<TabChild*>(browsers[i])->GetAppType(appType);
+      if (appType.EqualsLiteral("homescreen")) {
+        isHomescreen = true;
+        break;
+      }
+    }
+  }
+
+  return isHomescreen ?
+         PROCESS_PRIORITY_BACKGROUND_HOMESCREEN :
+         PROCESS_PRIORITY_BACKGROUND;
+}
+
+/**
  * This class listens to window creation and visibilitychange events and
  * informs the hal back-end when this process transitions between having no
  * visible top-level windows, and when it has at least one visible top-level
  * window.
  *
  *
  * An important heuristic here is that we don't mark a process as background
  * until it's had no visible top-level windows for some amount of time.
@@ -101,18 +130,18 @@ public:
 private:
   void SetPriority(ProcessPriority aPriority);
   void OnContentDocumentGlobalCreated(nsISupports* aOuterWindow);
   void OnInnerWindowDestroyed();
   void OnGracePeriodTimerFired();
   void RecomputeNumVisibleWindows();
 
   // mProcessPriority tracks the priority we've given this process in hal,
-  // except that, when the grace period timer is active,
-  // mProcessPriority == BACKGROUND even though hal still thinks we're a
+  // except that, when the grace period timer is active, mProcessPriority ==
+  // BACKGROUND or HOMESCREEN_BACKGROUND even though hal still thinks we're a
   // foreground process.
   ProcessPriority mProcessPriority;
 
   nsTArray<nsWeakPtr> mWindows;
   nsCOMPtr<nsITimer> mGracePeriodTimer;
   nsWeakPtr mMemoryMinimizerRunnable;
   TimeStamp mStartupTime;
 };
@@ -246,28 +275,29 @@ ProcessPriorityManager::RecomputeNumVisi
     allHidden = allHidden && hidden;
 
     // We could break out early from this loop if
     //   !hidden && mProcessPriority == BACKGROUND,
     // but then we might not clean up all the weak refs.
   }
 
   SetPriority(allHidden ?
-              PROCESS_PRIORITY_BACKGROUND :
+              GetBackgroundPriority() :
               PROCESS_PRIORITY_FOREGROUND);
 }
 
 void
 ProcessPriorityManager::SetPriority(ProcessPriority aPriority)
 {
   if (aPriority == mProcessPriority) {
     return;
   }
 
-  if (aPriority == PROCESS_PRIORITY_BACKGROUND) {
+  if (aPriority == PROCESS_PRIORITY_BACKGROUND ||
+      aPriority == PROCESS_PRIORITY_BACKGROUND_HOMESCREEN) {
     // If this is a foreground --> background transition, give ourselves a
     // grace period before informing hal.
     uint32_t gracePeriodMS = Preferences::GetUint("dom.ipc.processPriorityManager.gracePeriodMS", 1000);
     if (mGracePeriodTimer) {
       LOG("Grace period timer already active.");
       return;
     }
 
@@ -299,25 +329,26 @@ ProcessPriorityManager::SetPriority(Proc
     MOZ_ASSERT(false);
   }
 }
 
 void
 ProcessPriorityManager::OnGracePeriodTimerFired()
 {
   LOG("Grace period timer fired; setting priority to %d.",
-      PROCESS_PRIORITY_BACKGROUND);
+      mProcessPriority);
 
-  // mProcessPriority should already be BACKGROUND: We set it in
-  // SetPriority(BACKGROUND), and we canceled this timer if there was an
+  // mProcessPriority should already be one of the BACKGROUND values: We set it
+  // in SetPriority(BACKGROUND), and we canceled this timer if there was an
   // intervening SetPriority(FOREGROUND) call.
-  MOZ_ASSERT(mProcessPriority == PROCESS_PRIORITY_BACKGROUND);
+  MOZ_ASSERT(mProcessPriority == PROCESS_PRIORITY_BACKGROUND ||
+             mProcessPriority == PROCESS_PRIORITY_BACKGROUND_HOMESCREEN);
 
   mGracePeriodTimer = nullptr;
-  hal::SetProcessPriority(getpid(), PROCESS_PRIORITY_BACKGROUND);
+  hal::SetProcessPriority(getpid(), mProcessPriority);
 
   // We're in the background; dump as much memory as we can.
   nsCOMPtr<nsIMemoryReporterManager> mgr =
     do_GetService("@mozilla.org/memory-reporter-manager;1");
   if (mgr) {
     nsCOMPtr<nsICancelableRunnable> runnable =
       do_QueryReferent(mMemoryMinimizerRunnable);
 
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -92,17 +92,16 @@ using namespace mozilla::widget;
 
 NS_IMPL_ISUPPORTS1(ContentListener, nsIDOMEventListener)
 
 static const nsIntSize kDefaultViewportSize(980, 480);
 
 static const char CANCEL_DEFAULT_PAN_ZOOM[] = "cancel-default-pan-zoom";
 static const char BROWSER_ZOOM_TO_RECT[] = "browser-zoom-to-rect";
 static const char BEFORE_FIRST_PAINT[] = "before-first-paint";
-static const char DETECT_SCROLLABLE_SUBFRAME[] = "detect-scrollable-subframe";
 
 NS_IMETHODIMP
 ContentListener::HandleEvent(nsIDOMEvent* aEvent)
 {
   RemoteDOMEvent remoteEvent;
   remoteEvent.mEvent = do_QueryInterface(aEvent);
   NS_ENSURE_STATE(remoteEvent.mEvent);
   mTabChild->SendEvent(remoteEvent);
@@ -238,22 +237,16 @@ TabChild::Observe(nsISupports *aSubject,
           AsyncPanZoomController::CalculateResolution(mLastMetrics);
         mLastMetrics.mScrollOffset = gfx::Point(0, 0);
         utils->SetResolution(mLastMetrics.mResolution.width,
                              mLastMetrics.mResolution.height);
 
         HandlePossibleViewportChange();
       }
     }
-  } else if (!strcmp(aTopic, DETECT_SCROLLABLE_SUBFRAME)) {
-    nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(aSubject));
-    nsCOMPtr<nsITabChild> tabChild(GetTabChildFrom(docShell));
-    if (tabChild == this) {
-      mRemoteFrame->DetectScrollableSubframe();
-    }
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 TabChild::OnStateChange(nsIWebProgress* aWebProgress,
                         nsIRequest* aRequest,
@@ -1682,30 +1675,37 @@ TabChild::RecvDestroy()
   }
 
   nsCOMPtr<nsIObserverService> observerService =
     do_GetService(NS_OBSERVERSERVICE_CONTRACTID);
 
   observerService->RemoveObserver(this, CANCEL_DEFAULT_PAN_ZOOM);
   observerService->RemoveObserver(this, BROWSER_ZOOM_TO_RECT);
   observerService->RemoveObserver(this, BEFORE_FIRST_PAINT);
-  observerService->RemoveObserver(this, DETECT_SCROLLABLE_SUBFRAME);
 
   const InfallibleTArray<PIndexedDBChild*>& idbActors =
     ManagedPIndexedDBChild();
   for (uint32_t i = 0; i < idbActors.Length(); ++i) {
     static_cast<IndexedDBChild*>(idbActors[i])->Disconnect();
   }
 
   // XXX what other code in ~TabChild() should we be running here?
   DestroyWindow();
 
   return Send__delete__(this);
 }
 
+/* virtual */ bool
+TabChild::RecvSetAppType(const nsString& aAppType)
+{
+  MOZ_ASSERT_IF(!aAppType.IsEmpty(), HasOwnApp());
+  mAppType = aAppType;
+  return true;
+}
+
 PRenderFrameChild*
 TabChild::AllocPRenderFrame(ScrollingBehavior* aScrolling,
                             LayersBackend* aBackend,
                             int32_t* aMaxTextureSize,
                             uint64_t* aLayersId)
 {
     return new RenderFrameChild();
 }
@@ -1810,19 +1810,16 @@ TabChild::InitRenderingState()
                                      CANCEL_DEFAULT_PAN_ZOOM,
                                      false);
         observerService->AddObserver(this,
                                      BROWSER_ZOOM_TO_RECT,
                                      false);
         observerService->AddObserver(this,
                                      BEFORE_FIRST_PAINT,
                                      false);
-        observerService->AddObserver(this,
-                                     DETECT_SCROLLABLE_SUBFRAME,
-                                     false);
     }
 
     return true;
 }
 
 void
 TabChild::SetBackgroundColor(const nscolor& aColor)
 {
--- a/dom/ipc/TabChild.h
+++ b/dom/ipc/TabChild.h
@@ -302,16 +302,26 @@ public:
     /**
      * Signal to this TabChild that it should be made visible:
      * activated widget, retained layer tree, etc.  (Respectively,
      * made not visible.)
      */
     void MakeVisible();
     void MakeHidden();
 
+    virtual bool RecvSetAppType(const nsString& aAppType);
+
+    /**
+     * Get this object's app type.
+     *
+     * A TabChild's app type corresponds to the value of its frame element's
+     * "mozapptype" attribute.
+     */
+    void GetAppType(nsAString& aAppType) const { aAppType = mAppType; }
+
 protected:
     virtual PRenderFrameChild* AllocPRenderFrame(ScrollingBehavior* aScrolling,
                                                  LayersBackend* aBackend,
                                                  int32_t* aMaxTextureSize,
                                                  uint64_t* aLayersId) MOZ_OVERRIDE;
     virtual bool DeallocPRenderFrame(PRenderFrameChild* aFrame) MOZ_OVERRIDE;
     virtual bool RecvDestroy() MOZ_OVERRIDE;
 
@@ -403,16 +413,17 @@ private:
     nsIntSize mInnerSize;
     float mOldViewportWidth;
     nscolor mLastBackgroundColor;
     ScrollingBehavior mScrolling;
     bool mDidFakeShow;
     bool mNotified;
     bool mContentDocumentIsDisplayed;
     bool mTriedBrowserInit;
+    nsString mAppType;
 
     DISALLOW_EVIL_CONSTRUCTORS(TabChild);
 };
 
 inline TabChild*
 GetTabChildFrom(nsIDocShell* aDocShell)
 {
     nsCOMPtr<nsITabChild> tc = do_GetInterface(aDocShell);
--- a/dom/media/MediaManager.cpp
+++ b/dom/media/MediaManager.cpp
@@ -257,41 +257,50 @@ public:
     StreamListeners* listeners = MediaManager::Get()->GetWindowListeners(mWindowID);
     if (!listeners) {
       // This window is no longer live.
       return NS_OK;
     }
 
     // Create a media stream.
     nsRefPtr<nsDOMLocalMediaStream> stream;
+    nsRefPtr<nsDOMLocalMediaStream> trackunion;
     uint32_t hints = (mAudioSource ? nsDOMMediaStream::HINT_CONTENTS_AUDIO : 0);
     hints |= (mVideoSource ? nsDOMMediaStream::HINT_CONTENTS_VIDEO : 0);
 
-    stream = nsDOMLocalMediaStream::CreateSourceStream(hints);
-    if (!stream) {
+    stream     = nsDOMLocalMediaStream::CreateSourceStream(hints);
+    trackunion = nsDOMLocalMediaStream::CreateTrackUnionStream(hints);
+    if (!stream || !trackunion) {
       nsCOMPtr<nsIDOMGetUserMediaErrorCallback> error(mError);
       LOG(("Returning error for getUserMedia() - no stream"));
       error->OnError(NS_LITERAL_STRING("NO_STREAM"));
       return NS_OK;
     }
+    // connect the source stream to the track union stream to avoid us blocking
+    trackunion->GetStream()->AsProcessedStream()->SetAutofinish(true);
+    nsRefPtr<MediaInputPort> port = trackunion->GetStream()->AsProcessedStream()->
+      AllocateInputPort(stream->GetStream()->AsSourceStream(),
+                        MediaInputPort::FLAG_BLOCK_OUTPUT);
 
     nsPIDOMWindow *window = static_cast<nsPIDOMWindow*>
       (nsGlobalWindow::GetInnerWindowWithId(mWindowID));
     if (window && window->GetExtantDoc()) {
       stream->CombineWithPrincipal(window->GetExtantDoc()->NodePrincipal());
+      trackunion->CombineWithPrincipal(window->GetExtantDoc()->NodePrincipal());
     }
 
     // Ensure there's a thread for gum to proxy to off main thread
     nsIThread *mediaThread = MediaManager::GetThread();
 
     // Add our listener. We'll call Start() on the source when get a callback
     // that the MediaStream has started consuming. The listener is freed
     // when the page is invalidated (on navigation or close).
     GetUserMediaCallbackMediaStreamListener* listener =
       new GetUserMediaCallbackMediaStreamListener(mediaThread, stream,
+                                                  port.forget(),
                                                   mAudioSource,
                                                   mVideoSource);
     stream->GetStream()->AddListener(listener);
 
     // No need for locking because we always do this in the main thread.
     listeners->AppendElement(listener);
 
     // Dispatch to the media thread to ask it to start the sources,
@@ -306,17 +315,17 @@ public:
     nsCOMPtr<nsIDOMGetUserMediaErrorCallback> error(mError);
 
     if (!(MediaManager::Get()->IsWindowStillActive(mWindowID))) {
       return NS_OK;
     }
     // This is safe since we're on main-thread, and the windowlist can only
     // be invalidated from the main-thread (see OnNavigation)
     LOG(("Returning success for getUserMedia()"));
-    success->OnSuccess(static_cast<nsIDOMLocalMediaStream*>(stream));
+    success->OnSuccess(static_cast<nsIDOMLocalMediaStream*>(trackunion));
 
     return NS_OK;
   }
 
 private:
   already_AddRefed<nsIDOMGetUserMediaSuccessCallback> mSuccess;
   already_AddRefed<nsIDOMGetUserMediaErrorCallback> mError;
   nsRefPtr<MediaEngineSource> mAudioSource;
--- a/dom/media/MediaManager.h
+++ b/dom/media/MediaManager.h
@@ -84,16 +84,17 @@ public:
     MediaEngineSource* aAudioSource,
     MediaEngineSource* aVideoSource)
     : mType(aType)
     , mAudioSource(aAudioSource)
     , mVideoSource(aVideoSource)
     , mStream(aStream)
     {}
 
+  // so we can send Stop without AddRef()ing from the MSG thread
   MediaOperationRunnable(MediaOperation aType,
     SourceMediaStream* aStream,
     MediaEngineSource* aAudioSource,
     MediaEngineSource* aVideoSource)
     : mType(aType)
     , mAudioSource(aAudioSource)
     , mVideoSource(aVideoSource)
     , mStream(nullptr)
@@ -156,16 +157,17 @@ public:
             mAudioSource->Deallocate();
           }
           if (mVideoSource) {
             mVideoSource->Stop();
             mVideoSource->Deallocate();
           }
           // Do this after stopping all tracks with EndTrack()
           mSourceStream->Finish();
+          // the TrackUnion destination of the port will autofinish
 
           nsRefPtr<GetUserMediaNotificationEvent> event =
             new GetUserMediaNotificationEvent(GetUserMediaNotificationEvent::STOPPING);
 
           NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL);
         }
         break;
     }
@@ -185,33 +187,35 @@ private:
  * to Start() and Stop() the underlying MediaEngineSource when MediaStreams
  * are assigned and deassigned in content.
  */
 class GetUserMediaCallbackMediaStreamListener : public MediaStreamListener
 {
 public:
   GetUserMediaCallbackMediaStreamListener(nsIThread *aThread,
     nsDOMMediaStream* aStream,
+    already_AddRefed<MediaInputPort> aPort,
     MediaEngineSource* aAudioSource,
     MediaEngineSource* aVideoSource)
     : mMediaThread(aThread)
     , mAudioSource(aAudioSource)
     , mVideoSource(aVideoSource)
-    , mStream(aStream) {}
+    , mStream(aStream)
+    , mPort(aPort) {}
 
   void
   Invalidate()
   {
     nsRefPtr<MediaOperationRunnable> runnable;
 
     // We can't take a chance on blocking here, so proxy this to another
     // thread.
     // XXX FIX! I'm cheating and passing a raw pointer to the sourcestream
     // which is valid as long as the mStream pointer here is.  Need a better solution.
-    runnable = new MediaOperationRunnable(MEDIA_STOP, 
+    runnable = new MediaOperationRunnable(MEDIA_STOP,
                                           mStream->GetStream()->AsSourceStream(),
                                           mAudioSource, mVideoSource);
     mMediaThread->Dispatch(runnable, NS_DISPATCH_NORMAL);
 
     return;
   }
 
   // Proxy NotifyPull() to sources
@@ -234,16 +238,17 @@ public:
     Invalidate();
   }
 
 private:
   nsCOMPtr<nsIThread> mMediaThread;
   nsRefPtr<MediaEngineSource> mAudioSource;
   nsRefPtr<MediaEngineSource> mVideoSource;
   nsRefPtr<nsDOMMediaStream> mStream;
+  nsRefPtr<MediaInputPort> mPort;
 };
 
 typedef nsTArray<nsRefPtr<GetUserMediaCallbackMediaStreamListener> > StreamListeners;
 typedef nsClassHashtable<nsUint64HashKey, StreamListeners> WindowTable;
 
 class MediaDevice : public nsIMediaDevice
 {
 public:
--- a/dom/tests/mochitest/ajax/offline/Makefile.in
+++ b/dom/tests/mochitest/ajax/offline/Makefile.in
@@ -93,13 +93,14 @@ MOCHITEST_FILES	= \
 	changing1Sec.sjs \
 	changing1Hour.sjs \
 	changingManifest.sjs \
 	offlineChild.html \
 	test_xhtmlManifest.xhtml \
 	test_missingManifest.html \
 	missing.html \
 	jupiter.jpg \
+	test_cancelOfflineCache.html \
 	$(NULL)
 
 # test_offlineMode.html disabled due to bug 656943
 
 include $(topsrcdir)/config/rules.mk
new file mode 100644
--- /dev/null
+++ b/dom/tests/mochitest/ajax/offline/test_cancelOfflineCache.html
@@ -0,0 +1,59 @@
+<html xmlns="http://www.w3.org/1999/xhtml" manifest="http://mochi.test:8888/tests/dom/tests/mochitest/ajax/offline/simpleManifest.cacheManifest">
+<head>
+<title>Cancel offline cache</title>
+
+<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+<script type="text/javascript" src="/tests/dom/tests/mochitest/ajax/offline/offlineTests.js"></script>
+<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+
+<script type="text/javascript">
+
+var manifest = "http://mochi.test:8888/tests/dom/tests/mochitest/ajax/offline/simpleManifest.cacheManifest";
+var manifestURI = Cc["@mozilla.org/network/io-service;1"]
+                  .getService(Ci.nsIIOService)
+                  .newURI(manifest, null, null);
+var updateService = Cc['@mozilla.org/offlinecacheupdate-service;1']
+                    .getService(Ci.nsIOfflineCacheUpdateService);
+
+function manifestCached () {
+  OfflineTest.ok(false, "The update was supposed to be canceled");
+
+  OfflineTest.teardown();
+  OfflineTest.finish();
+}
+
+function onError () {
+  OfflineTest.ok(true, "Expected error: Update canceled");
+
+  OfflineTest.teardown();
+  OfflineTest.finish();
+}
+
+function onProgress () {
+  var i = 0;
+  while (i < updateService.numUpdates) {
+    var update = updateService.getUpdate(i);
+    if (update.manifestURI.spec == manifestURI.spec) {
+      update.cancel();
+      return;
+    }
+    i++;
+  }
+}
+
+if (OfflineTest.setup()) {
+  applicationCache.onerror = OfflineTest.priv(onError);
+  applicationCache.onprogress = OfflineTest.priv(onProgress);
+  applicationCache.oncached = OfflineTest.priv(manifestCached);
+}
+
+SimpleTest.waitForExplicitFinish();
+
+</script>
+
+</head>
+
+<body>
+
+</body>
+</html>
--- a/gfx/2d/image_operations.cpp
+++ b/gfx/2d/image_operations.cpp
@@ -265,42 +265,35 @@ void ResizeFilter::ComputeFilters(int sr
     fixed_filter_values->clear();
 
     // This is the pixel in the source directly under the pixel in the dest.
     // Note that we base computations on the "center" of the pixels. To see
     // why, observe that the destination pixel at coordinates (0, 0) in a 5.0x
     // downscale should "cover" the pixels around the pixel with *its center*
     // at coordinates (2.5, 2.5) in the source, not those around (0, 0).
     // Hence we need to scale coordinates (0.5, 0.5), not (0, 0).
-    // TODO(evannier): this code is therefore incorrect and should read:
-    // float src_pixel = (static_cast<float>(dest_subset_i) + 0.5f) * inv_scale;
-    // I leave it incorrect, because changing it would require modifying
-    // the results for the webkit test, which I will do in a subsequent checkin.
-    float src_pixel = dest_subset_i * inv_scale;
+    float src_pixel = (static_cast<float>(dest_subset_i) + 0.5f) * inv_scale;
 
     // Compute the (inclusive) range of source pixels the filter covers.
     int src_begin = NS_MAX(0, FloorInt(src_pixel - src_support));
     int src_end = NS_MIN(src_size - 1, CeilInt(src_pixel + src_support));
 
     // Compute the unnormalized filter value at each location of the source
     // it covers.
     float filter_sum = 0.0f;  // Sub of the filter values for normalizing.
     for (int cur_filter_pixel = src_begin; cur_filter_pixel <= src_end;
          cur_filter_pixel++) {
       // Distance from the center of the filter, this is the filter coordinate
       // in source space. We also need to consider the center of the pixel
       // when comparing distance against 'src_pixel'. In the 5x downscale
       // example used above the distance from the center of the filter to
       // the pixel with coordinates (2, 2) should be 0, because its center
       // is at (2.5, 2.5).
-      // TODO(evannier): as above (in regards to the 0.5 pixel error),
-      // this code is incorrect, but is left it for the same reasons.
-      // float src_filter_dist =
-      //     ((static_cast<float>(cur_filter_pixel) + 0.5f) - src_pixel);
-      float src_filter_dist = cur_filter_pixel - src_pixel;
+      float src_filter_dist =
+           ((static_cast<float>(cur_filter_pixel) + 0.5f) - src_pixel);
 
       // Since the filter really exists in dest space, map it there.
       float dest_filter_dist = src_filter_dist * clamped_scale;
 
       // Compute the filter value at that location.
       float filter_value = ComputeFilter(dest_filter_dist);
       filter_values->push_back(filter_value);
 
--- a/gfx/gl/GLContext.cpp
+++ b/gfx/gl/GLContext.cpp
@@ -520,17 +520,18 @@ GLContext::InitWithPrefix(const char *pr
         }
        
         // Load developer symbols, don't fail if we can't find them.
         SymLoadStruct auxSymbols[] = {
                 { (PRFuncPtr*) &mSymbols.fGetTexImage, { "GetTexImage", nullptr } },
                 { (PRFuncPtr*) &mSymbols.fGetTexLevelParameteriv, { "GetTexLevelParameteriv", nullptr } },
                 { nullptr, { nullptr } },
         };
-        LoadSymbols(&auxSymbols[0], trygl, prefix);
+        bool warnOnFailures = DebugMode();
+        LoadSymbols(&auxSymbols[0], trygl, prefix, warnOnFailures);
     }
 
     if (mInitialized) {
         GLint v[4];
 
         fGetIntegerv(LOCAL_GL_SCISSOR_BOX, v);
         mScissorStack.AppendElement(nsIntRect(v[0], v[1], v[2], v[3]));
 
@@ -589,16 +590,26 @@ GLContext::InitExtensions()
     static bool firstRun = true;
 #else
     // Non-DEBUG, so never spew.
     const bool firstRun = false;
 #endif
 
     mAvailableExtensions.Load(extensions, sExtensionNames, firstRun && DebugMode());
 
+#ifdef XP_MACOSX
+    // The Mac Nvidia driver, for versions up to and including 10.8, don't seem
+    // to properly support this.  See 814839
+    if (WorkAroundDriverBugs() &&
+        Vendor() == gl::GLContext::VendorNVIDIA)
+    {
+        MarkExtensionUnsupported(gl::GLContext::EXT_packed_depth_stencil);
+    }
+#endif
+
 #ifdef DEBUG
     firstRun = false;
 #endif
 }
 
 
 // Take texture data in a given buffer and copy it into a larger buffer,
 // padding out the edge pixels for filtering if necessary
--- a/gfx/gl/GLContext.h
+++ b/gfx/gl/GLContext.h
@@ -990,29 +990,44 @@ public:
     void fDrawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices) {
         BeforeGLDrawCall();
         raw_fDrawElements(mode, count, type, indices);
         AfterGLDrawCall();
     }
 
     // Read call hooks:
     void fReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels) {
+        y = FixYValue(y, height);
+
         BeforeGLReadCall();
         raw_fReadPixels(x, y, width, height, format, type, pixels);
         AfterGLReadCall();
     }
 
     void fCopyTexImage2D(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border) {
+        y = FixYValue(y, height);
+
+        if (!IsTextureSizeSafeToPassToDriver(target, width, height)) {
+            // pass wrong values to cause the GL to generate GL_INVALID_VALUE.
+            // See bug 737182 and the comment in IsTextureSizeSafeToPassToDriver.
+            level = -1;
+            width = -1;
+            height = -1;
+            border = -1;
+        }
+
         BeforeGLReadCall();
         raw_fCopyTexImage2D(target, level, internalformat,
                             x, y, width, height, border);
         AfterGLReadCall();
     }
 
     void fCopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height) {
+        y = FixYValue(y, height);
+
         BeforeGLReadCall();
         raw_fCopyTexSubImage2D(target, level, xoffset, yoffset,
                                x, y, width, height);
         AfterGLReadCall();
     }
 
     void ForceDirtyFBOs() {
         GLuint draw = SwapUserDrawFBO(0);
@@ -1708,16 +1723,25 @@ public:
 
 #else
 
 #define BEFORE_GL_CALL do { } while (0)
 #define AFTER_GL_CALL do { } while (0)
 
 #endif
 
+#define ASSERT_SYMBOL_PRESENT(func) \
+    do {\
+        MOZ_ASSERT(strstr(MOZ_FUNCTION_NAME, #func) != nullptr, "Mismatched symbol check.");\
+        if (MOZ_UNLIKELY(!mSymbols.func)) {\
+            printf_stderr("RUNTIME ASSERT: Uninitialized GL function: %s\n", #func);\
+            MOZ_CRASH();\
+        }\
+    } while (0)
+
     /*** In GL debug mode, we completely override glGetError ***/
 
     GLenum fGetError() {
 #ifdef DEBUG
         // debug mode ends up eating the error in AFTER_GL_CALL
         if (DebugMode()) {
             GLenum err = mGLError;
             mGLError = LOCAL_GL_NO_ERROR;
@@ -1727,39 +1751,29 @@ public:
 
         return mSymbols.fGetError();
     }
 
 
     /*** Scissor functions ***/
 
 protected:
-
     GLint FixYValue(GLint y, GLint height)
     {
+        MOZ_ASSERT( !(mIsOffscreen && mFlipped) );
         return mFlipped ? ViewportRect().height - (height + y) : y;
     }
 
-    // only does the glScissor call, no ScissorRect business
-    void raw_fScissor(GLint x, GLint y, GLsizei width, GLsizei height) {
-        BEFORE_GL_CALL;
-        // GL's coordinate system is flipped compared to ours (in the Y axis),
-        // so we may need to flip our rectangle.
-        mSymbols.fScissor(x, 
-                          FixYValue(y, height),
-                          width, 
-                          height);
-        AFTER_GL_CALL;
-    }
-
 public:
-
-    // but let GL-using code use that instead, updating the ScissorRect
     void fScissor(GLint x, GLint y, GLsizei width, GLsizei height) {
         ScissorRect().SetRect(x, y, width, height);
+
+        // GL's coordinate system is flipped compared to the one we use in
+        // OGL Layers (in the Y axis), so we may need to flip our rectangle.
+        y = FixYValue(y, height);
         raw_fScissor(x, y, width, height);
     }
 
     nsIntRect& ScissorRect() {
         return mScissorStack[mScissorStack.Length()-1];
     }
 
     void PushScissorRect() {
@@ -1783,32 +1797,30 @@ public:
         if (!thisRect.IsEqualInterior(ScissorRect())) {
             raw_fScissor(ScissorRect().x, ScissorRect().y,
                               ScissorRect().width, ScissorRect().height);
         }
     }
 
     /*** Viewport functions ***/
 
-protected:
-
+private:
     // only does the glViewport call, no ViewportRect business
     void raw_fViewport(GLint x, GLint y, GLsizei width, GLsizei height) {
         BEFORE_GL_CALL;
         // XXX: Flipping should really happen using the destination height, but
         // we use viewport instead and assume viewport size matches the
         // destination. If we ever try use partial viewports for layers we need
         // to fix this, and remove the assertion.
         NS_ASSERTION(!mFlipped || (x == 0 && y == 0), "TODO: Need to flip the viewport rect"); 
         mSymbols.fViewport(x, y, width, height);
         AFTER_GL_CALL;
     }
 
 public:
-
     void fViewport(GLint x, GLint y, GLsizei width, GLsizei height) {
         ViewportRect().SetRect(x, y, width, height);
         raw_fViewport(x, y, width, height);
     }
 
     nsIntRect& ViewportRect() {
         return mViewportStack[mViewportStack.Length()-1];
     }
@@ -1894,44 +1906,51 @@ public:
     }
 
     void fBlendFuncSeparate(GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha) {
         BEFORE_GL_CALL;
         mSymbols.fBlendFuncSeparate(sfactorRGB, dfactorRGB, sfactorAlpha, dfactorAlpha);
         AFTER_GL_CALL;
     }
 
-    void fBufferData(GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usage) {
+private:
+    void raw_fBufferData(GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usage) {
         BEFORE_GL_CALL;
         mSymbols.fBufferData(target, size, data, usage);
+        AFTER_GL_CALL;
+    }
+
+public:
+    void fBufferData(GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usage) {
+        raw_fBufferData(target, size, data, usage);
 
         // bug 744888
         if (WorkAroundDriverBugs() &&
             !data &&
             Vendor() == VendorNVIDIA)
         {
             char c = 0;
-            mSymbols.fBufferSubData(target, size-1, 1, &c);
+            fBufferSubData(target, size-1, 1, &c);
         }
-
-        AFTER_GL_CALL;
     }
 
     void fBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid* data) {
         BEFORE_GL_CALL;
         mSymbols.fBufferSubData(target, offset, size, data);
         AFTER_GL_CALL;
     }
 
+private:
     void raw_fClear(GLbitfield mask) {
         BEFORE_GL_CALL;
         mSymbols.fClear(mask);
         AFTER_GL_CALL;
     }
 
+public:
     void fClearColor(GLclampf r, GLclampf g, GLclampf b, GLclampf a) {
         BEFORE_GL_CALL;
         mSymbols.fClearColor(r, g, b, a);
         AFTER_GL_CALL;
     }
 
     void fClearStencil(GLint s) {
         BEFORE_GL_CALL;
@@ -1988,28 +2007,30 @@ public:
     }
 
     void fDisableVertexAttribArray(GLuint index) {
         BEFORE_GL_CALL;
         mSymbols.fDisableVertexAttribArray(index);
         AFTER_GL_CALL;
     }
 
+private:
     void raw_fDrawArrays(GLenum mode, GLint first, GLsizei count) {
         BEFORE_GL_CALL;
         mSymbols.fDrawArrays(mode, first, count);
         AFTER_GL_CALL;
     }
 
     void raw_fDrawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices) {
         BEFORE_GL_CALL;
         mSymbols.fDrawElements(mode, count, type, indices);
         AFTER_GL_CALL;
     }
 
+public:
     void fEnable(GLenum capability) {
         BEFORE_GL_CALL;
         mSymbols.fEnable(capability);
         AFTER_GL_CALL;
     }
 
     void fEnableVertexAttribArray(GLuint index) {
         BEFORE_GL_CALL;
@@ -2123,31 +2144,26 @@ public:
     const GLubyte* fGetString(GLenum name) {
         BEFORE_GL_CALL;
         const GLubyte *result = mSymbols.fGetString(name);
         AFTER_GL_CALL;
         return result;
     }
 
     void fGetTexImage(GLenum target, GLint level, GLenum format, GLenum type, GLvoid *img) {
-        if (!mSymbols.fGetTexImage) {
-          return;
-        }
         BEFORE_GL_CALL;
+        ASSERT_SYMBOL_PRESENT(fGetTexImage);
         mSymbols.fGetTexImage(target, level, format, type, img);
         AFTER_GL_CALL;
     }
 
     void fGetTexLevelParameteriv(GLenum target, GLint level, GLenum pname, GLint *params)
     {  
-        if (!mSymbols.fGetTexLevelParameteriv) {
-          *params = 0;
-          return;
-        }
         BEFORE_GL_CALL;
+        ASSERT_SYMBOL_PRESENT(fGetTexLevelParameteriv);
         mSymbols.fGetTexLevelParameteriv(target, level, pname, params);
         AFTER_GL_CALL;
     }
 
     void fGetTexParameterfv(GLenum target, GLenum pname, const GLfloat *params) {
         BEFORE_GL_CALL;
         mSymbols.fGetTexParameterfv(target, pname, params);
         AFTER_GL_CALL;
@@ -2204,38 +2220,38 @@ public:
 
     realGLboolean fIsBuffer(GLuint buffer) {
         BEFORE_GL_CALL;
         realGLboolean retval = mSymbols.fIsBuffer(buffer);
         AFTER_GL_CALL;
         return retval;
     }
 
-    realGLboolean fIsEnabled (GLenum capability) {
+    realGLboolean fIsEnabled(GLenum capability) {
         BEFORE_GL_CALL;
         realGLboolean retval = mSymbols.fIsEnabled(capability);
         AFTER_GL_CALL;
         return retval;
     }
 
-    realGLboolean fIsProgram (GLuint program) {
+    realGLboolean fIsProgram(GLuint program) {
         BEFORE_GL_CALL;
         realGLboolean retval = mSymbols.fIsProgram(program);
         AFTER_GL_CALL;
         return retval;
     }
 
-    realGLboolean fIsShader (GLuint shader) {
+    realGLboolean fIsShader(GLuint shader) {
         BEFORE_GL_CALL;
         realGLboolean retval = mSymbols.fIsShader(shader);
         AFTER_GL_CALL;
         return retval;
     }
 
-    realGLboolean fIsTexture (GLuint texture) {
+    realGLboolean fIsTexture(GLuint texture) {
         BEFORE_GL_CALL;
         realGLboolean retval = mSymbols.fIsTexture(texture);
         AFTER_GL_CALL;
         return retval;
     }
 
     void fLineWidth(GLfloat width) {
         BEFORE_GL_CALL;
@@ -2268,28 +2284,38 @@ public:
     }
 
     void fReadBuffer(GLenum mode) {
         BEFORE_GL_CALL;
         mSymbols.fReadBuffer(mode);
         AFTER_GL_CALL;
     }
 
+private:
     void raw_fReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels) {
         BEFORE_GL_CALL;
         mSymbols.fReadPixels(x, FixYValue(y, height), width, height, format, type, pixels);
         AFTER_GL_CALL;
     }
 
+public:
     void fSampleCoverage(GLclampf value, realGLboolean invert) {
         BEFORE_GL_CALL;
         mSymbols.fSampleCoverage(value, invert);
         AFTER_GL_CALL;
     }
 
+private:
+    void raw_fScissor(GLint x, GLint y, GLsizei width, GLsizei height) {
+        BEFORE_GL_CALL;
+        mSymbols.fScissor(x, y, width, height);
+        AFTER_GL_CALL;
+    }
+
+public:
     void fStencilFunc(GLenum func, GLint ref, GLuint mask) {
         BEFORE_GL_CALL;
         mSymbols.fStencilFunc(func, ref, mask);
         AFTER_GL_CALL;
     }
 
     void fStencilFuncSeparate(GLenum frontfunc, GLenum backfunc, GLint ref, GLuint mask) {
         BEFORE_GL_CALL;
@@ -2316,26 +2342,35 @@ public:
     }
 
     void fStencilOpSeparate(GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass) {
         BEFORE_GL_CALL;
         mSymbols.fStencilOpSeparate(face, sfail, dpfail, dppass);
         AFTER_GL_CALL;
     }
 
-    void fTexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels) {
+private:
+    void raw_fTexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels) {
         BEFORE_GL_CALL;
-        if (IsTextureSizeSafeToPassToDriver(target, width, height)) {
-          mSymbols.fTexImage2D(target, level, internalformat, width, height, border, format, type, pixels);
-        } else {
-          // pass wrong values to cause the GL to generate GL_INVALID_VALUE.
-          // See bug 737182 and the comment in IsTextureSizeSafeToPassToDriver.
-          mSymbols.fTexImage2D(target, -1, internalformat, -1, -1, -1, format, type, nullptr);
+        mSymbols.fTexImage2D(target, level, internalformat, width, height, border, format, type, pixels);
+        AFTER_GL_CALL;
+    }
+
+public:
+    void fTexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels) {
+        if (!IsTextureSizeSafeToPassToDriver(target, width, height)) {
+            // pass wrong values to cause the GL to generate GL_INVALID_VALUE.
+            // See bug 737182 and the comment in IsTextureSizeSafeToPassToDriver.
+            level = -1;
+            width = -1;
+            height = -1;
+            border = -1;
         }
-        AFTER_GL_CALL;
+
+        raw_fTexImage2D(target, level, internalformat, width, height, border, format, type, pixels);
     }
 
     void fTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid* pixels) {
         BEFORE_GL_CALL;
         mSymbols.fTexSubImage2D(target, level, xoffset, yoffset, width, height, format, type, pixels);
         AFTER_GL_CALL;
     }
 
@@ -2520,63 +2555,60 @@ public:
     }
 
     void fCompileShader(GLuint shader) {
         BEFORE_GL_CALL;
         mSymbols.fCompileShader(shader);
         AFTER_GL_CALL;
     }
 
+private:
     void raw_fCopyTexImage2D(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border) {
         BEFORE_GL_CALL;
-        if (IsTextureSizeSafeToPassToDriver(target, width, height)) {
-          mSymbols.fCopyTexImage2D(target, level, internalformat, 
-                                   x, FixYValue(y, height),
-                                   width, height, border);
-
-        } else {
-          // pass wrong values to cause the GL to generate GL_INVALID_VALUE.
-          // See bug 737182 and the comment in IsTextureSizeSafeToPassToDriver.
-          mSymbols.fCopyTexImage2D(target, -1, internalformat, 
-                                   x, FixYValue(y, height),
-                                   -1, -1, -1);
-
-        }
+        mSymbols.fCopyTexImage2D(target, level, internalformat, x, y, width, height, border);
         AFTER_GL_CALL;
     }
 
     void raw_fCopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height) {
         BEFORE_GL_CALL;
-        mSymbols.fCopyTexSubImage2D(target, level, xoffset, yoffset, 
-                                    x, FixYValue(y, height),
-                                    width, height);
+        mSymbols.fCopyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height);
         AFTER_GL_CALL;
     }
 
+public:
     void fGetShaderiv(GLuint shader, GLenum pname, GLint* param) {
         BEFORE_GL_CALL;
         mSymbols.fGetShaderiv(shader, pname, param);
         AFTER_GL_CALL;
     }
 
     void fGetShaderInfoLog(GLuint shader, GLsizei bufSize, GLsizei* length, GLchar* infoLog) {
         BEFORE_GL_CALL;
         mSymbols.fGetShaderInfoLog(shader, bufSize, length, infoLog);
         AFTER_GL_CALL;
     }
 
-    void fGetShaderPrecisionFormat(GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision) {
+private:
+    void raw_fGetShaderPrecisionFormat(GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision) {
+        MOZ_ASSERT(mIsGLES2);
+
         BEFORE_GL_CALL;
-        if (mIsGLES2) {
-            mSymbols.fGetShaderPrecisionFormat(shadertype, precisiontype, range, precision);
+        ASSERT_SYMBOL_PRESENT(fGetShaderPrecisionFormat);
+        mSymbols.fGetShaderPrecisionFormat(shadertype, precisiontype, range, precision);
+        AFTER_GL_CALL;
+    }
+
+public:
+    void fGetShaderPrecisionFormat(GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision) {
+       if (mIsGLES2) {
+            raw_fGetShaderPrecisionFormat(shadertype, precisiontype, range, precision);
         } else {
             // Fall back to automatic values because almost all desktop hardware supports the OpenGL standard precisions.
             GetShaderPrecisionFormatNonES2(shadertype, precisiontype, range, precision);
         }
-        AFTER_GL_CALL;
     }
 
     void fGetShaderSource(GLint obj, GLsizei maxLength, GLsizei* length, GLchar* source) {
         BEFORE_GL_CALL;
         mSymbols.fGetShaderSource(obj, maxLength, length, source);
         AFTER_GL_CALL;
     }
 
@@ -2633,240 +2665,346 @@ public:
 
     realGLboolean fIsFramebuffer (GLuint framebuffer) {
         BEFORE_GL_CALL;
         realGLboolean retval = mSymbols.fIsFramebuffer(framebuffer);
         AFTER_GL_CALL;
         return retval;
     }
 
+private:
     void raw_fBlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter) {
         BEFORE_GL_CALL;
+        ASSERT_SYMBOL_PRESENT(fBlitFramebuffer);
         mSymbols.fBlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter);
         AFTER_GL_CALL;
     }
 
+public:
     realGLboolean fIsRenderbuffer (GLuint renderbuffer) {
         BEFORE_GL_CALL;
         realGLboolean retval = mSymbols.fIsRenderbuffer(renderbuffer);
         AFTER_GL_CALL;
         return retval;
     }
 
     void fRenderbufferStorage(GLenum target, GLenum internalFormat, GLsizei width, GLsizei height) {
         BEFORE_GL_CALL;
         mSymbols.fRenderbufferStorage(target, internalFormat, width, height);
         AFTER_GL_CALL;
     }
 
     void fRenderbufferStorageMultisample(GLenum target, GLsizei samples, GLenum internalFormat, GLsizei width, GLsizei height) {
         BEFORE_GL_CALL;
+        ASSERT_SYMBOL_PRESENT(fRenderbufferStorageMultisample);
         mSymbols.fRenderbufferStorageMultisample(target, samples, internalFormat, width, height);
         AFTER_GL_CALL;
     }
 
+private:
+    void raw_fDepthRange(GLclampf a, GLclampf b) {
+        MOZ_ASSERT(!mIsGLES2);
+
+        BEFORE_GL_CALL;
+        ASSERT_SYMBOL_PRESENT(fDepthRange);
+        mSymbols.fDepthRange(a, b);
+        AFTER_GL_CALL;
+    }
+
+    void raw_fDepthRangef(GLclampf a, GLclampf b) {
+        MOZ_ASSERT(mIsGLES2);
+
+        BEFORE_GL_CALL;
+        ASSERT_SYMBOL_PRESENT(fDepthRangef);
+        mSymbols.fDepthRangef(a, b);
+        AFTER_GL_CALL;
+    }
+
+    void raw_fClearDepth(GLclampf v) {
+        MOZ_ASSERT(!mIsGLES2);
+
+        BEFORE_GL_CALL;
+        ASSERT_SYMBOL_PRESENT(fClearDepth);
+        mSymbols.fClearDepth(v);
+        AFTER_GL_CALL;
+    }
+
+    void raw_fClearDepthf(GLclampf v) {
+        MOZ_ASSERT(mIsGLES2);
+
+        BEFORE_GL_CALL;
+        ASSERT_SYMBOL_PRESENT(fClearDepthf);
+        mSymbols.fClearDepthf(v);
+        AFTER_GL_CALL;
+    }
+
+public:
     void fDepthRange(GLclampf a, GLclampf b) {
-        BEFORE_GL_CALL;
         if (mIsGLES2) {
-            mSymbols.fDepthRangef(a, b);
+            raw_fDepthRangef(a, b);
         } else {
-            mSymbols.fDepthRange(a, b);
+            raw_fDepthRange(a, b);
         }
-        AFTER_GL_CALL;
     }
 
     void fClearDepth(GLclampf v) {
-        BEFORE_GL_CALL;
         if (mIsGLES2) {
-            mSymbols.fClearDepthf(v);
+            raw_fClearDepthf(v);
         } else {
-            mSymbols.fClearDepth(v);
+            raw_fClearDepth(v);
         }
-        AFTER_GL_CALL;
     }
 
     void* fMapBuffer(GLenum target, GLenum access) {
         BEFORE_GL_CALL;
+        ASSERT_SYMBOL_PRESENT(fMapBuffer);
         void *ret = mSymbols.fMapBuffer(target, access);
         AFTER_GL_CALL;
         return ret;
     }
 
     realGLboolean fUnmapBuffer(GLenum target) {
         BEFORE_GL_CALL;
+        ASSERT_SYMBOL_PRESENT(fUnmapBuffer);
         realGLboolean ret = mSymbols.fUnmapBuffer(target);
         AFTER_GL_CALL;
         return ret;
     }
 
 
+private:
 #ifdef DEBUG
     GLContext *TrackingContext() {
         GLContext *tip = this;
         while (tip->mSharedContext)
             tip = tip->mSharedContext;
         return tip;
     }
 
 #define TRACKING_CONTEXT(a) do { TrackingContext()->a; } while (0)
 #else
 #define TRACKING_CONTEXT(a) do {} while (0)
 #endif
 
-    GLuint GLAPIENTRY fCreateProgram() {
+    GLuint GLAPIENTRY raw_fCreateProgram() {
         BEFORE_GL_CALL;
         GLuint ret = mSymbols.fCreateProgram();
         AFTER_GL_CALL;
-        TRACKING_CONTEXT(CreatedProgram(this, ret));
         return ret;
     }
 
-    GLuint GLAPIENTRY fCreateShader(GLenum t) {
+    GLuint GLAPIENTRY raw_fCreateShader(GLenum t) {
         BEFORE_GL_CALL;
         GLuint ret = mSymbols.fCreateShader(t);
         AFTER_GL_CALL;
-        TRACKING_CONTEXT(CreatedShader(this, ret));
         return ret;
     }
 
-    void GLAPIENTRY fGenBuffers(GLsizei n, GLuint* names) {
+    void GLAPIENTRY raw_fGenBuffers(GLsizei n, GLuint* names) {
         BEFORE_GL_CALL;
         mSymbols.fGenBuffers(n, names);
         AFTER_GL_CALL;
-        TRACKING_CONTEXT(CreatedBuffers(this, n, names));
     }
 
-    void GLAPIENTRY fGenTextures(GLsizei n, GLuint* names) {
-        BEFORE_GL_CALL;
-        mSymbols.fGenTextures(n, names);
-        AFTER_GL_CALL;
-        TRACKING_CONTEXT(CreatedTextures(this, n, names));
-    }
-
-    void GLAPIENTRY fGenFramebuffers(GLsizei n, GLuint* names) {
+    void GLAPIENTRY raw_fGenFramebuffers(GLsizei n, GLuint* names) {
         BEFORE_GL_CALL;
         mSymbols.fGenFramebuffers(n, names);
         AFTER_GL_CALL;
-        TRACKING_CONTEXT(CreatedFramebuffers(this, n, names));
     }
 
-    void GLAPIENTRY fGenRenderbuffers(GLsizei n, GLuint* names) {
+    void GLAPIENTRY raw_fGenRenderbuffers(GLsizei n, GLuint* names) {
         BEFORE_GL_CALL;
         mSymbols.fGenRenderbuffers(n, names);
         AFTER_GL_CALL;
+    }
+
+    void GLAPIENTRY raw_fGenTextures(GLsizei n, GLuint* names) {
+        BEFORE_GL_CALL;
+        mSymbols.fGenTextures(n, names);
+        AFTER_GL_CALL;
+    }
+
+public:
+    GLuint fCreateProgram() {
+        GLuint ret = raw_fCreateProgram();
+        TRACKING_CONTEXT(CreatedProgram(this, ret));
+        return ret;
+    }
+
+    GLuint fCreateShader(GLenum t) {
+        GLuint ret = raw_fCreateShader(t);
+        TRACKING_CONTEXT(CreatedShader(this, ret));
+        return ret;
+    }
+
+    void fGenBuffers(GLsizei n, GLuint* names) {
+        raw_fGenBuffers(n, names);
+        TRACKING_CONTEXT(CreatedBuffers(this, n, names));
+    }
+
+    void fGenFramebuffers(GLsizei n, GLuint* names) {
+        raw_fGenFramebuffers(n, names);
+        TRACKING_CONTEXT(CreatedFramebuffers(this, n, names));
+    }
+
+    void fGenRenderbuffers(GLsizei n, GLuint* names) {
+        raw_fGenRenderbuffers(n, names);
         TRACKING_CONTEXT(CreatedRenderbuffers(this, n, names));
     }
 
-    void GLAPIENTRY fDeleteProgram(GLuint program) {
+    void fGenTextures(GLsizei n, GLuint* names) {
+        raw_fGenTextures(n, names);
+        TRACKING_CONTEXT(CreatedTextures(this, n, names));
+    }
+
+private:
+    void GLAPIENTRY raw_fDeleteProgram(GLuint program) {
         BEFORE_GL_CALL;
         mSymbols.fDeleteProgram(program);
         AFTER_GL_CALL;
-        TRACKING_CONTEXT(DeletedProgram(this, program));
     }
 
-    void GLAPIENTRY fDeleteShader(GLuint shader) {
+    void GLAPIENTRY raw_fDeleteShader(GLuint shader) {
         BEFORE_GL_CALL;
         mSymbols.fDeleteShader(shader);
         AFTER_GL_CALL;
-        TRACKING_CONTEXT(DeletedShader(this, shader));
     }
 
-    void GLAPIENTRY fDeleteBuffers(GLsizei n, GLuint *names) {
+    void GLAPIENTRY raw_fDeleteBuffers(GLsizei n, GLuint *names) {
         BEFORE_GL_CALL;
         mSymbols.fDeleteBuffers(n, names);
         AFTER_GL_CALL;
-        TRACKING_CONTEXT(DeletedBuffers(this, n, names));
+    }
+
+    void GLAPIENTRY raw_fDeleteFramebuffers(GLsizei n, GLuint *names) {
+        BEFORE_GL_CALL;
+        mSymbols.fDeleteFramebuffers(n, names);
+        AFTER_GL_CALL;
     }
 
-    void GLAPIENTRY fDeleteTextures(GLsizei n, GLuint *names) {
+    void GLAPIENTRY raw_fDeleteRenderbuffers(GLsizei n, GLuint *names) {
+        BEFORE_GL_CALL;
+        mSymbols.fDeleteRenderbuffers(n, names);
+        AFTER_GL_CALL;
+    }
+
+    void GLAPIENTRY raw_fDeleteTextures(GLsizei n, GLuint *names) {
         BEFORE_GL_CALL;
         mSymbols.fDeleteTextures(n, names);
         AFTER_GL_CALL;
-        TRACKING_CONTEXT(DeletedTextures(this, n, names));
+    }
+
+public:
+    void fDeleteProgram(GLuint program) {
+        raw_fDeleteProgram(program);
+        TRACKING_CONTEXT(DeletedProgram(this, program));
     }
 
-    void GLAPIENTRY fDeleteFramebuffers(GLsizei n, GLuint *names) {
-        BEFORE_GL_CALL;
+    void fDeleteShader(GLuint shader) {
+        raw_fDeleteShader(shader);
+        TRACKING_CONTEXT(DeletedShader(this, shader));
+    }
+
+    void fDeleteBuffers(GLsizei n, GLuint *names) {
+        raw_fDeleteBuffers(n, names);
+        TRACKING_CONTEXT(DeletedBuffers(this, n, names));
+    }
+
+    void fDeleteFramebuffers(GLsizei n, GLuint *names) {
         if (n == 1 && *names == 0) {
-           /* Deleting framebuffer 0 causes hangs on the DROID. See bug 623228 */
+            // Deleting framebuffer 0 causes hangs on the DROID. See bug 623228.
         } else {
-           mSymbols.fDeleteFramebuffers(n, names);
+            raw_fDeleteFramebuffers(n, names);
         }
-        AFTER_GL_CALL;
         TRACKING_CONTEXT(DeletedFramebuffers(this, n, names));
     }
 
-    void GLAPIENTRY fDeleteRenderbuffers(GLsizei n, GLuint *names) {
-        BEFORE_GL_CALL;
-        mSymbols.fDeleteRenderbuffers(n, names);
-        AFTER_GL_CALL;
+    void fDeleteRenderbuffers(GLsizei n, GLuint *names) {
+        raw_fDeleteRenderbuffers(n, names);
         TRACKING_CONTEXT(DeletedRenderbuffers(this, n, names));
     }
 
+    void fDeleteTextures(GLsizei n, GLuint *names) {
+        raw_fDeleteTextures(n, names);
+        TRACKING_CONTEXT(DeletedTextures(this, n, names));
+    }
+
 
     GLenum GLAPIENTRY fGetGraphicsResetStatus() {
+        MOZ_ASSERT(mHasRobustness);
+
         BEFORE_GL_CALL;
-        GLenum ret = mHasRobustness ? mSymbols.fGetGraphicsResetStatus() : 0;
+        ASSERT_SYMBOL_PRESENT(fGetGraphicsResetStatus);
+        GLenum ret = mSymbols.fGetGraphicsResetStatus();
         AFTER_GL_CALL;
         return ret;
     }
 
     GLsync GLAPIENTRY fFenceSync(GLenum condition, GLbitfield flags) {
         BEFORE_GL_CALL;
+        ASSERT_SYMBOL_PRESENT(fFenceSync);
         GLsync ret = mSymbols.fFenceSync(condition, flags);
         AFTER_GL_CALL;
         return ret;
     }
 
     realGLboolean GLAPIENTRY fIsSync(GLsync sync) {
         BEFORE_GL_CALL;
+        ASSERT_SYMBOL_PRESENT(fIsSync);
         realGLboolean ret = mSymbols.fIsSync(sync);
         AFTER_GL_CALL;
         return ret;
     }
 
     void GLAPIENTRY fDeleteSync(GLsync sync) {
         BEFORE_GL_CALL;
+        ASSERT_SYMBOL_PRESENT(fDeleteSync);
         mSymbols.fDeleteSync(sync);
         AFTER_GL_CALL;
     }
 
     GLenum GLAPIENTRY fClientWaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout) {
         BEFORE_GL_CALL;
+        ASSERT_SYMBOL_PRESENT(fClientWaitSync);
         GLenum ret = mSymbols.fClientWaitSync(sync, flags, timeout);
         AFTER_GL_CALL;
         return ret;
     }
 
     void GLAPIENTRY fWaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout) {
         BEFORE_GL_CALL;
+        ASSERT_SYMBOL_PRESENT(fWaitSync);
         mSymbols.fWaitSync(sync, flags, timeout);
         AFTER_GL_CALL;
     }
 
     void GLAPIENTRY fGetInteger64v(GLenum pname, GLint64 *params) {
         BEFORE_GL_CALL;
+        ASSERT_SYMBOL_PRESENT(fGetInteger64v);
         mSymbols.fGetInteger64v(pname, params);
         AFTER_GL_CALL;
     }
 
     void GLAPIENTRY fGetSynciv(GLsync sync, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *values) {
         BEFORE_GL_CALL;
+        ASSERT_SYMBOL_PRESENT(fGetSynciv);
         mSymbols.fGetSynciv(sync, pname, bufSize, length, values);
         AFTER_GL_CALL;
     }
 
     // OES_EGL_image (GLES)
-    void fEGLImageTargetTexture2D(GLenum target, GLeglImage image)
-    {
+    void fEGLImageTargetTexture2D(GLenum target, GLeglImage image) {
         BEFORE_GL_CALL;
+        ASSERT_SYMBOL_PRESENT(fEGLImageTargetTexture2D);
         mSymbols.fEGLImageTargetTexture2D(target, image);
         AFTER_GL_CALL;
     }
 
+#undef ASSERT_SYMBOL_PRESENT
+
 #ifdef DEBUG
     void THEBES_API CreatedProgram(GLContext *aOrigin, GLuint aName);
     void THEBES_API CreatedShader(GLContext *aOrigin, GLuint aName);
     void THEBES_API CreatedBuffers(GLContext *aOrigin, GLsizei aCount, GLuint *aNames);
     void THEBES_API CreatedTextures(GLContext *aOrigin, GLsizei aCount, GLuint *aNames);
     void THEBES_API CreatedFramebuffers(GLContext *aOrigin, GLsizei aCount, GLuint *aNames);
     void THEBES_API CreatedRenderbuffers(GLContext *aOrigin, GLsizei aCount, GLuint *aNames);
     void THEBES_API DeletedProgram(GLContext *aOrigin, GLuint aName);
--- a/gfx/gl/GLLibraryLoader.cpp
+++ b/gfx/gl/GLLibraryLoader.cpp
@@ -1,14 +1,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/. */
 
 #include "GLLibraryLoader.h"
 
+#include "nsDebug.h"
+
 namespace mozilla {
 namespace gl {
 
 bool
 GLLibraryLoader::OpenLibrary(const char *library)
 {
     PRLibSpec lspec;
     lspec.type = PR_LibSpec_Pathname;
@@ -17,25 +19,32 @@ GLLibraryLoader::OpenLibrary(const char 
     mLibrary = PR_LoadLibraryWithFlags(lspec, PR_LD_LAZY | PR_LD_LOCAL);
     if (!mLibrary)
         return false;
 
     return true;
 }
 
 bool
-GLLibraryLoader::LoadSymbols(SymLoadStruct *firstStruct, bool tryplatform, const char *prefix)
+GLLibraryLoader::LoadSymbols(SymLoadStruct *firstStruct,
+                             bool tryplatform,
+                             const char *prefix,
+                             bool warnOnFailure)
 {
-    return LoadSymbols(mLibrary, firstStruct, tryplatform ? mLookupFunc : nullptr, prefix);
+    return LoadSymbols(mLibrary,
+                       firstStruct,
+                       tryplatform ? mLookupFunc : nullptr,
+                       prefix,
+                       warnOnFailure);
 }
 
 PRFuncPtr
 GLLibraryLoader::LookupSymbol(PRLibrary *lib,
-                                  const char *sym,
-                                  PlatformLookupFunction lookupFunction)
+                              const char *sym,
+                              PlatformLookupFunction lookupFunction)
 {
     PRFuncPtr res = 0;
 
     // try finding it in the library directly, if we have one
     if (lib) {
         res = PR_FindFunctionSymbol(lib, sym);
     }
 
@@ -50,19 +59,20 @@ GLLibraryLoader::LookupSymbol(PRLibrary 
         res = PR_FindFunctionSymbolAndLibrary(sym, &leakedLibRef);
     }
 
     return res;
 }
 
 bool
 GLLibraryLoader::LoadSymbols(PRLibrary *lib,
-                                 SymLoadStruct *firstStruct,
-                                 PlatformLookupFunction lookupFunction,
-                                 const char *prefix)
+                             SymLoadStruct *firstStruct,
+                             PlatformLookupFunction lookupFunction,
+                             const char *prefix,
+                             bool warnOnFailure)
 {
     char sbuf[MAX_SYMBOL_LENGTH * 2];
     int failCount = 0;
 
     SymLoadStruct *ss = firstStruct;
     while (ss->symPointer) {
         *ss->symPointer = 0;
 
@@ -80,17 +90,19 @@ GLLibraryLoader::LoadSymbols(PRLibrary *
             PRFuncPtr p = LookupSymbol(lib, s, lookupFunction);
             if (p) {
                 *ss->symPointer = p;
                 break;
             }
         }
 
         if (*ss->symPointer == 0) {
-            fprintf (stderr, "Can't find symbol '%s'\n", ss->symNames[0]);
+            if (warnOnFailure)
+                printf_stderr("Can't find symbol '%s'.\n", ss->symNames[0]);
+
             failCount++;
         }
 
         ss++;
     }
 
     return failCount == 0 ? true : false;
 }
--- a/gfx/gl/GLLibraryLoader.h
+++ b/gfx/gl/GLLibraryLoader.h
@@ -32,29 +32,31 @@ public:
     };
 
     typedef struct {
         PRFuncPtr *symPointer;
         const char *symNames[MAX_SYMBOL_NAMES];
     } SymLoadStruct;
 
     bool LoadSymbols(SymLoadStruct *firstStruct,
-                       bool tryplatform = false,
-                       const char *prefix = nullptr);
+                     bool tryplatform = false,
+                     const char *prefix = nullptr,
+                     bool warnOnFailure = true);
 
     /*
      * Static version of the functions in this class
      */
     static PRFuncPtr LookupSymbol(PRLibrary *lib,
                                   const char *symname,
                                   PlatformLookupFunction lookupFunction = nullptr);
     static bool LoadSymbols(PRLibrary *lib,
-                              SymLoadStruct *firstStruct,
-                              PlatformLookupFunction lookupFunction = nullptr,
-                              const char *prefix = nullptr);
+                            SymLoadStruct *firstStruct,
+                            PlatformLookupFunction lookupFunction = nullptr,
+                            const char *prefix = nullptr,
+                            bool warnOnFailure = true);
 protected:
     GLLibraryLoader() {
         mLibrary = nullptr;
         mLookupFunc = nullptr;
     }
 
     PRLibrary *mLibrary;
     PlatformLookupFunction mLookupFunc;
--- a/gfx/layers/basic/BasicLayerManager.cpp
+++ b/gfx/layers/basic/BasicLayerManager.cpp
@@ -624,26 +624,17 @@ BasicLayerManager::EndTransactionInterna
   // out target is the default target.
 
   return !mTransactionIncomplete;
 }
 
 void
 BasicLayerManager::FlashWidgetUpdateArea(gfxContext *aContext)
 {
-  static bool sWidgetFlashingEnabled;
-  static bool sWidgetFlashingPrefCached = false;
-
-  if (!sWidgetFlashingPrefCached) {
-    sWidgetFlashingPrefCached = true;
-    mozilla::Preferences::AddBoolVarCache(&sWidgetFlashingEnabled,
-                                          "nglayout.debug.widget_update_flashing");
-  }
-
-  if (sWidgetFlashingEnabled) {
+  if (gfxPlatform::GetPlatform()->WidgetUpdateFlashing()) {
     float r = float(rand()) / RAND_MAX;
     float g = float(rand()) / RAND_MAX;
     float b = float(rand()) / RAND_MAX;
     aContext->SetColor(gfxRGBA(r, g, b, 0.2));
     aContext->Paint();
   }
 }
 
--- a/gfx/layers/ipc/AsyncPanZoomController.cpp
+++ b/gfx/layers/ipc/AsyncPanZoomController.cpp
@@ -232,36 +232,16 @@ nsEventStatus AsyncPanZoomController::Ha
   nsEventStatus rv = nsEventStatus_eIgnore;
 
   if (mGestureEventListener && !mDisableNextTouchBatch) {
     rv = mGestureEventListener->HandleInputEvent(aEvent);
     if (rv == nsEventStatus_eConsumeNoDefault)
       return rv;
   }
 
-  if (mDelayPanning && aEvent.mInputType == MULTITOUCH_INPUT) {
-    const MultiTouchInput& multiTouchInput = aEvent.AsMultiTouchInput();
-    if (multiTouchInput.mType == MultiTouchInput::MULTITOUCH_MOVE) {
-      // Let BrowserElementScrolling perform panning gesture first.
-      SetState(WAITING_LISTENERS);
-      mTouchQueue.AppendElement(multiTouchInput);
-
-      if (!mTouchListenerTimeoutTask) {
-        mTouchListenerTimeoutTask =
-          NewRunnableMethod(this, &AsyncPanZoomController::TimeoutTouchListeners);
-
-        MessageLoop::current()->PostDelayedTask(
-          FROM_HERE,
-          mTouchListenerTimeoutTask,
-          TOUCH_LISTENER_TIMEOUT);
-      }
-      return nsEventStatus_eConsumeNoDefault;
-    }
-  }
-
   switch (aEvent.mInputType) {
   case MULTITOUCH_INPUT: {
     const MultiTouchInput& multiTouchInput = aEvent.AsMultiTouchInput();
     switch (multiTouchInput.mType) {
       case MultiTouchInput::MULTITOUCH_START: rv = OnTouchStart(multiTouchInput); break;
       case MultiTouchInput::MULTITOUCH_MOVE: rv = OnTouchMove(multiTouchInput); break;
       case MultiTouchInput::MULTITOUCH_END: rv = OnTouchEnd(multiTouchInput); break;
       case MultiTouchInput::MULTITOUCH_CANCEL: rv = OnTouchCancel(multiTouchInput); break;
@@ -1104,17 +1084,16 @@ bool AsyncPanZoomController::SampleConte
 
 void AsyncPanZoomController::NotifyLayersUpdated(const FrameMetrics& aViewportFrame, bool aIsFirstPaint) {
   MonitorAutoLock monitor(mMonitor);
 
   mPaintThrottler.TaskComplete();
 
   mLastContentPaintMetrics = aViewportFrame;
 
-  mFrameMetrics.mMayHaveTouchListeners = aViewportFrame.mMayHaveTouchListeners;
   if (mWaitingForContentToPaint) {
     // Remove the oldest sample we have if adding a new sample takes us over our
     // desired number of samples.
     if (mPreviousPaintDurations.Length() >= NUM_PAINT_DURATION_SAMPLES) {
       mPreviousPaintDurations.RemoveElementAt(0);
     }
 
     mPreviousPaintDurations.AppendElement(
@@ -1198,20 +1177,16 @@ void AsyncPanZoomController::UpdateCompo
 
 void AsyncPanZoomController::CancelDefaultPanZoom() {
   mDisableNextTouchBatch = true;
   if (mGestureEventListener) {
     mGestureEventListener->CancelGesture();
   }
 }
 
-void AsyncPanZoomController::DetectScrollableSubframe() {
-  mDelayPanning = true;
-}
-
 void AsyncPanZoomController::ZoomToRect(const gfxRect& aRect) {
   gfx::Rect zoomToRect(gfx::Rect(aRect.x, aRect.y, aRect.width, aRect.height));
 
   SetState(ANIMATING_ZOOM);
 
   {
     MonitorAutoLock mon(mMonitor);
 
@@ -1288,43 +1263,34 @@ void AsyncPanZoomController::ZoomToRect(
 
     mAnimationStartTime = TimeStamp::Now();
 
     ScheduleComposite();
   }
 }
 
 void AsyncPanZoomController::ContentReceivedTouch(bool aPreventDefault) {
-  if (!mFrameMetrics.mMayHaveTouchListeners && !mDelayPanning) {
+  if (!mFrameMetrics.mMayHaveTouchListeners) {
     mTouchQueue.Clear();
     return;
   }
 
   if (mTouchListenerTimeoutTask) {
     mTouchListenerTimeoutTask->Cancel();
     mTouchListenerTimeoutTask = nullptr;
   }
 
   if (mState == WAITING_LISTENERS) {
     if (!aPreventDefault) {
-      // Delayed scrolling gesture is pending at TOUCHING state.
-      if (mDelayPanning) {
-        SetState(TOUCHING);
-      } else {
-        SetState(NOTHING);
-      }
+      SetState(NOTHING);
     }
 
     mHandlingTouchQueue = true;
 
     while (!mTouchQueue.IsEmpty()) {
-      // we need to reset mDelayPanning before handling scrolling gesture.
-      if (mTouchQueue[0].mType == MultiTouchInput::MULTITOUCH_MOVE) {
-        mDelayPanning = false;
-      }
       if (!aPreventDefault) {
         HandleInputEvent(mTouchQueue[0]);
       }
 
       if (mTouchQueue[0].mType == MultiTouchInput::MULTITOUCH_END ||
           mTouchQueue[0].mType == MultiTouchInput::MULTITOUCH_CANCEL) {
         mTouchQueue.RemoveElementAt(0);
         break;
--- a/gfx/layers/ipc/AsyncPanZoomController.h
+++ b/gfx/layers/ipc/AsyncPanZoomController.h
@@ -103,32 +103,26 @@ public:
    * the frame this is tied to during composition onto, in device pixels. In
    * general, this will just be:
    * { x = 0, y = 0, width = surface.width, height = surface.height }, however
    * there is no hard requirement for this.
    */
   void UpdateCompositionBounds(const nsIntRect& aCompositionBounds);
 
   /**
-   * We are scrolling a subframe, so disable our machinery until we hit
+   * We have found a scrollable subframe, so disable our machinery until we hit
    * a touch end or a new touch start. This prevents us from accidentally
    * panning both the subframe and the parent frame.
    *
    * XXX/bug 775452: We should eventually be supporting async scrollable
    * subframes.
    */
   void CancelDefaultPanZoom();
 
   /**
-   * We have found a scrollable subframe, so we need to delay the scrolling
-   * gesture executed and let subframe do the scrolling first.
-   */
-  void DetectScrollableSubframe();
-
-  /**
    * Kicks an animation to zoom to a rect. This may be either a zoom out or zoom
    * in. The actual animation is done on the compositor thread after being set
    * up. |aRect| must be given in CSS pixels, relative to the document.
    */
   void ZoomToRect(const gfxRect& aRect);
 
   /**
    * If we have touch listeners, this should always be called when we know
@@ -550,21 +544,15 @@ private:
   bool mDisableNextTouchBatch;
 
   // Flag used to determine whether or not we should try to enter the
   // WAITING_LISTENERS state. This is used in the case that we are processing a
   // queued up event block. If set, this means that we are handling this queue
   // and we don't want to queue the events back up again.
   bool mHandlingTouchQueue;
 
-  // Flag used to determine whether or not we should try scrolling by
-  // BrowserElementScrolling first. If set, this means we should pend touch move
-  // event, which not be cosumed by GestureListener. This flag will be reset
-  // after touch move event has been handled by content process.
-  bool mDelayPanning;
-
   friend class Axis;
 };
 
 }
 }
 
 #endif // mozilla_layers_PanZoomController_h
--- a/gfx/thebes/gfxPlatform.cpp
+++ b/gfx/thebes/gfxPlatform.cpp
@@ -335,16 +335,19 @@ gfxPlatform::Init()
     gPlatform->mSRGBOverrideObserver = new SRGBOverrideObserver();
     Preferences::AddWeakObserver(gPlatform->mSRGBOverrideObserver, "gfx.color_management.force_srgb");
 
     gPlatform->mFontPrefsObserver = new FontPrefsObserver();
     Preferences::AddStrongObservers(gPlatform->mFontPrefsObserver, kObservedPrefs);
 
     gPlatform->mWorkAroundDriverBugs = Preferences::GetBool("gfx.work-around-driver-bugs", true);
 
+    mozilla::Preferences::AddBoolVarCache(&gPlatform->mWidgetUpdateFlashing,
+                                          "nglayout.debug.widget_update_flashing");
+
     mozilla::gl::GLContext::PlatformStartup();
 
 #ifdef MOZ_WIDGET_ANDROID
     // Texture pool init
     mozilla::gl::TexturePoolOGL::Init();
 #endif
 
     // Force registration of the gfx component, thus arranging for
--- a/gfx/thebes/gfxPlatform.h
+++ b/gfx/thebes/gfxPlatform.h
@@ -488,16 +488,18 @@ public:
      * Returns a logger if one is available and logging is enabled
      */
     static PRLogModuleInfo* GetLog(eGfxLog aWhichLog);
 
     bool WorkAroundDriverBugs() const { return mWorkAroundDriverBugs; }
 
     virtual int GetScreenDepth() const;
 
+    bool WidgetUpdateFlashing() const { return mWidgetUpdateFlashing; }
+
 protected:
     gfxPlatform();
     virtual ~gfxPlatform();
 
     void AppendCJKPrefLangs(eFontPrefLang aPrefLangs[], uint32_t &aLen, 
                             eFontPrefLang aCharLang, eFontPrefLang aPageLang);
 
     /**
@@ -581,11 +583,12 @@ private:
     mozilla::gfx::BackendType mFallbackCanvasBackend;
     // The backend to use for content
     mozilla::gfx::BackendType mContentBackend;
 
     mozilla::widget::GfxInfoCollector<gfxPlatform> mAzureCanvasBackendCollector;
     bool mWorkAroundDriverBugs;
 
     mozilla::RefPtr<mozilla::gfx::DrawEventRecorder> mRecorder;
+    bool mWidgetUpdateFlashing;
 };
 
 #endif /* GFX_PLATFORM_H */
--- a/hal/HalTypes.h
+++ b/hal/HalTypes.h
@@ -64,16 +64,17 @@ enum SwitchState {
   SWITCH_STATE_HEADPHONE,        // without microphone
   NUM_SWITCH_STATE
 };
 
 typedef Observer<SwitchEvent> SwitchObserver;
 
 enum ProcessPriority {
   PROCESS_PRIORITY_BACKGROUND,
+  PROCESS_PRIORITY_BACKGROUND_HOMESCREEN,
   PROCESS_PRIORITY_FOREGROUND,
   PROCESS_PRIORITY_MASTER,
   NUM_PROCESS_PRIORITY
 };
 
 /**
  * Used by ModifyWakeLock
  */
--- a/hal/gonk/GonkHal.cpp
+++ b/hal/gonk/GonkHal.cpp
@@ -1041,17 +1041,18 @@ EnsureKernelLowMemKillerParamsSet()
   // notify_trigger is a single integer.   If we set notify_trigger=Z, then
   // we'll get notified when there are fewer than Z pages of memory free.  (See
   // GonkMemoryPressureMonitoring.cpp.)
 
   // Build the adj and minfree strings.
   nsAutoCString adjParams;
   nsAutoCString minfreeParams;
 
-  const char* priorityClasses[] = {"master", "foreground", "background"};
+  const char* priorityClasses[] =
+    {"master", "foreground", "background", "backgroundHomescreen"};
   for (size_t i = 0; i < NS_ARRAY_LENGTH(priorityClasses); i++) {
     int32_t oomScoreAdj;
     if (!NS_SUCCEEDED(Preferences::GetInt(nsPrintfCString(
           "hal.processPriorityManager.gonk.%sOomScoreAdjust",
           priorityClasses[i]).get(), &oomScoreAdj))) {
       continue;
     }
 
@@ -1103,16 +1104,19 @@ SetProcessPriority(int aPid, ProcessPrio
   // SetProcessPriority being called early in startup.
   EnsureKernelLowMemKillerParamsSet();
 
   const char* priorityStr = NULL;
   switch (aPriority) {
   case PROCESS_PRIORITY_BACKGROUND:
     priorityStr = "background";
     break;
+  case PROCESS_PRIORITY_BACKGROUND_HOMESCREEN:
+    priorityStr = "backgroundHomescreen";
+    break;
   case PROCESS_PRIORITY_FOREGROUND:
     priorityStr = "foreground";
     break;
   case PROCESS_PRIORITY_MASTER:
     priorityStr = "master";
     break;
   default:
     MOZ_NOT_REACHED();
--- a/hal/sandbox/SandboxHal.cpp
+++ b/hal/sandbox/SandboxHal.cpp
@@ -432,18 +432,17 @@ public:
               const InfallibleTArray<uint64_t> &id,
               PBrowserParent *browserParent) MOZ_OVERRIDE
   {
     // We give all content vibration permission.
     TabParent *tabParent = static_cast<TabParent*>(browserParent);
     nsCOMPtr<nsIDOMWindow> window =
       do_QueryInterface(tabParent->GetBrowserDOMWindow());
     WindowIdentifier newID(id, window);
-    // Have to copy, because Vibrate doesn't take a compatible array type
-    hal::Vibrate(nsTArray<uint32_t>(pattern), newID);
+    hal::Vibrate(pattern, newID);
     return true;
   }
 
   virtual bool
   RecvCancelVibrate(const InfallibleTArray<uint64_t> &id,
                     PBrowserParent *browserParent) MOZ_OVERRIDE
   {
     TabParent *tabParent = static_cast<TabParent*>(browserParent);
--- a/ipc/glue/IPCMessageUtils.h
+++ b/ipc/glue/IPCMessageUtils.h
@@ -331,20 +331,20 @@ struct ParamTraits<nsAutoCString> : Para
 #endif  // MOZILLA_INTERNAL_API
 
 template <>
 struct ParamTraits<nsString> : ParamTraits<nsAString>
 {
   typedef nsString paramType;
 };
 
-template <typename E, class A>
-struct ParamTraits<nsTArray<E, A> >
+template <typename E>
+struct ParamTraits<FallibleTArray<E> >
 {
-  typedef nsTArray<E, A> paramType;
+  typedef FallibleTArray<E> paramType;
 
   static void Write(Message* aMsg, const paramType& aParam)
   {
     uint32_t length = aParam.Length();
     WriteParam(aMsg, length);
     for (uint32_t index = 0; index < length; index++) {
       WriteParam(aMsg, aParam[index]);
     }
@@ -375,35 +375,40 @@ struct ParamTraits<nsTArray<E, A> >
         aLog->append(L" ");
       }
       LogParam(aParam[index], aLog);
     }
   }
 };
 
 template<typename E>
-struct ParamTraits<InfallibleTArray<E> > :
-  ParamTraits<nsTArray<E, nsTArrayInfallibleAllocator> >
+struct ParamTraits<InfallibleTArray<E> >
 {
   typedef InfallibleTArray<E> paramType;
 
-  // use nsTArray Write() method
+  static void Write(Message* aMsg, const paramType& aParam)
+  {
+    WriteParam(aMsg, static_cast<const FallibleTArray<E>&>(aParam));
+  }
 
   // deserialize the array fallibly, but return an InfallibleTArray
   static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
   {
-    nsTArray<E> temp;
+    FallibleTArray<E> temp;
     if (!ReadParam(aMsg, aIter, &temp))
       return false;
 
     aResult->SwapElements(temp);
     return true;
   }
 
-  // use nsTArray Log() method
+  static void Log(const paramType& aParam, std::wstring* aLog)
+  {
+    LogParam(static_cast<const FallibleTArray<E>&>(aParam), aLog);
+  }
 };
 
 template<>
 struct ParamTraits<float>
 {
   typedef float paramType;
 
   static void Write(Message* aMsg, const paramType& aParam)
--- a/ipc/ipdl/ipdl/lower.py
+++ b/ipc/ipdl/ipdl/lower.py
@@ -3287,17 +3287,17 @@ class _GenerateProtocolActorCode(ipdl.as
 
             block = StmtBlock()
             block.addstmts([
                 Whitespace(
                     '// Recursively shutting down %s kids\n'% (managed.name()),
                     indent=1),
                 StmtDecl(
                     Decl(p.managedVarType(managed, self.side), kidsvar.name),
-                    init=p.managedVar(managed, self.side)),
+                    initargs=[ p.managedVar(managed, self.side) ]),
                 foreachdestroy,
             ])
             destroysubtree.addstmt(block)
 
         if len(ptype.manages):
             destroysubtree.addstmt(Whitespace.NL)
         destroysubtree.addstmts([ Whitespace('// Finally, destroy "us".\n',
                                              indent=1),
@@ -4396,17 +4396,17 @@ class _GenerateProtocolActorCode(ipdl.as
                 # XXX: better error message
                 readcase.addstmt(StmtReturn.FALSE)
             else:
                 if c.special:
                     c = c.other       # see above
                 tmpvar = ExprVar('tmp')
                 ct = c.bareType()
                 readcase.addstmts([
-                    StmtDecl(Decl(ct, tmpvar.name), init=c.defaultValue()),
+                    StmtDecl(Decl(ct, tmpvar.name)),
                     StmtExpr(ExprAssn(ExprDeref(var), tmpvar)),
                     StmtReturn(self.read(
                         c.ipdltype,
                         ExprAddrOf(ExprCall(ExprSelect(var, '->',
                                                        c.getTypeName()))),
                         msgvar, itervar))
                 ])
 
--- a/js/src/Makefile.in
+++ b/js/src/Makefile.in
@@ -899,17 +899,18 @@ ifdef HAVE_LINUX_PERF_EVENT_H
 pm_linux.$(OBJ_SUFFIX): CXXFLAGS += $(LINUX_HEADERS_INCLUDES)
 endif
 
 # Prepare self-hosted JS code for embedding
 export:: selfhosting
 selfhosting:: selfhosted.out.h
 
 selfhosting_srcs := \
-  $(srcdir)/builtin/array.js \
+  $(srcdir)/builtin/Utilities.js \
+  $(srcdir)/builtin/Array.js \
   $(NULL)
 
 selfhosted_out_h_deps := \
   $(selfhosting_srcs) \
   $(srcdir)/js.msg \
   $(srcdir)/builtin/macros.py \
   $(srcdir)/builtin/js2c.py \
   $(srcdir)/builtin/embedjs.py
--- a/js/src/build/autoconf/android.m4
+++ b/js/src/build/autoconf/android.m4
@@ -49,17 +49,17 @@ MOZ_ARG_WITH_STRING(android-platform,
                            location of platform dir],
     android_platform=$withval)
 
 case "$target" in
 arm-linux*-android*|*-linuxandroid*)
     android_tool_prefix="arm-linux-androideabi"
     ;;
 i?86-*android*)
-    android_tool_prefix="i686-android-linux"
+    android_tool_prefix="i686-linux-android"
     ;;
 mipsel-*android*)
     android_tool_prefix="mipsel-linux-android"
     ;;
 *)
     android_tool_prefix="$target_os"
     ;;
 esac
@@ -114,16 +114,27 @@ case "$target" in
 
         if test -d "$android_platform" ; then
             AC_MSG_RESULT([$android_platform])
         else
             AC_MSG_ERROR([not found. You have to specify --with-android-platform=/path/to/ndk/platform.])
         fi
     fi
 
+    dnl Old NDK support. If minimum requirement is changed to NDK r8b,
+    dnl please remove this.
+    case "$target_cpu" in
+    i?86)
+        if ! test -e "$android_toolchain"/bin/"$android_tool_prefix"-gcc; then
+            dnl Old NDK toolchain name
+            android_tool_prefix="i686-android-linux"
+        fi
+        ;;
+    esac
+
     dnl set up compilers
     TOOLCHAIN_PREFIX="$android_toolchain/bin/$android_tool_prefix-"
     AS="$android_toolchain"/bin/"$android_tool_prefix"-as
     CC="$android_toolchain"/bin/"$android_tool_prefix"-gcc
     CXX="$android_toolchain"/bin/"$android_tool_prefix"-g++
     CPP="$android_toolchain"/bin/"$android_tool_prefix"-cpp
     LD="$android_toolchain"/bin/"$android_tool_prefix"-ld
     AR="$android_toolchain"/bin/"$android_tool_prefix"-ar
rename from js/src/builtin/array.js
rename to js/src/builtin/Array.js
new file mode 100644
--- /dev/null
+++ b/js/src/builtin/Utilities.js
@@ -0,0 +1,93 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*jshint bitwise: true, camelcase: false, curly: false, eqeqeq: true, forin: true,
+         immed: true, indent: 4, latedef: false, newcap: false, noarg: true,
+         noempty: true, nonew: true, plusplus: false, quotmark: false, regexp: true,
+         undef: true, unused: false, strict: false, trailing: true,
+*/
+
+/*global ToObject: false, ToInteger: false, IsCallable: false, ThrowError: false,
+         AssertionFailed: false, MakeConstructible: false, DecompileArg: false,
+         callFunction: false,
+         IS_UNDEFINED: false, TO_UINT32: false,
+         JSMSG_NOT_FUNCTION: false, JSMSG_MISSING_FUN_ARG: false,
+         JSMSG_EMPTY_ARRAY_REDUCE: false,
+*/
+
+
+/* cache built-in functions before applications can change them */
+var std_ArrayIndexOf = ArrayIndexOf;
+var std_ArrayJoin = Array.prototype.join;
+var std_ArrayPush = Array.prototype.push;
+var std_ArraySlice = Array.prototype.slice;
+var std_ArraySort = Array.prototype.sort;
+var std_ObjectCreate = Object.create;
+var std_String = String;
+
+
+/********** List specification type **********/
+
+
+/* Spec: ECMAScript Language Specification, 5.1 edition, 8.8 */
+function List() {
+    if (IS_UNDEFINED(List.prototype)) {
+        var proto = std_ObjectCreate(null);
+        proto.indexOf = std_ArrayIndexOf;
+        proto.join = std_ArrayJoin;
+        proto.push = std_ArrayPush;
+        proto.slice = std_ArraySlice;
+        proto.sort = std_ArraySort;
+        List.prototype = proto;
+    }
+}
+MakeConstructible(List);
+
+
+/********** Record specification type **********/
+
+
+/* Spec: ECMAScript Internationalization API Specification, draft, 5 */
+function Record() {
+    return std_ObjectCreate(null);
+}
+MakeConstructible(Record);
+
+
+/********** Abstract operations defined in ECMAScript Language Specification **********/
+
+
+/* Spec: ECMAScript Language Specification, 5.1 edition, 8.12.6 and 11.8.7 */
+function HasProperty(o, p) {
+    return p in o;
+}
+
+
+/* Spec: ECMAScript Language Specification, 5.1 edition, 9.2 and 11.4.9 */
+function ToBoolean(v) {
+    return !!v;
+}
+
+
+/* Spec: ECMAScript Language Specification, 5.1 edition, 9.3 and 11.4.6 */
+function ToNumber(v) {
+    return +v;
+}
+
+
+/* Spec: ECMAScript Language Specification, 5.1 edition, 9.8 and 15.2.1.1 */
+function ToString(v) {
+    assert(arguments.length > 0, "__toString");
+    return std_String(v);
+}
+
+
+/********** Assertions **********/
+
+
+function assert(b, info) {
+    if (!b)
+        AssertionFailed(info);
+}
+
--- a/js/src/ion/Ion.cpp
+++ b/js/src/ion/Ion.cpp
@@ -1204,20 +1204,23 @@ SequentialCompileContext::compile(IonBui
     if (!builder->build()) {
         IonSpew(IonSpew_Abort, "Builder failed to build.");
         return false;
     }
     builder->clearForBackEnd();
 
     // Try to compile the script off thread, if possible. Compilation cannot be
     // performed off thread during an incremental GC, as doing so may trip
-    // incremental read barriers.
+    // incremental read barriers. Also skip off thread compilation if script
+    // execution is being profiled, as CodeGenerator::maybeCreateScriptCounts
+    // will not attach script profiles when running off thread.
     if (js_IonOptions.parallelCompilation &&
         OffThreadCompilationAvailable(cx) &&
-        cx->runtime->gcIncrementalState == gc::NO_INCREMENTAL)
+        cx->runtime->gcIncrementalState == gc::NO_INCREMENTAL &&
+        !cx->runtime->profilingScripts)
     {
         builder->script()->ion = ION_COMPILING_SCRIPT;
 
         if (!StartOffThreadIonCompile(cx, builder)) {
             IonSpew(IonSpew_Abort, "Unable to start off-thread ion compilation.");
             return false;
         }
 
--- a/js/src/ion/IonCaches.cpp
+++ b/js/src/ion/IonCaches.cpp
@@ -1383,19 +1383,20 @@ js::ion::SetPropertyCache(JSContext *cx,
 
     uint32_t oldSlots = obj->numDynamicSlots();
     RootedShape oldShape(cx, obj->lastProperty());
 
     // Set/Add the property on the object, the inlined cache are setup for the next execution.
     if (!SetProperty(cx, obj, name, value, cache.strict(), isSetName))
         return false;
 
-    // The property did not exists before, now we can try again to inline the
-    // procedure which is adding the property.
-    if (inlinable && !addedSetterStub && IsPropertyAddInlineable(cx, obj, id, oldSlots, &shape)) {
+    // The property did not exist before, now we can try to inline the propery add.
+    if (inlinable && !addedSetterStub && obj->lastProperty() != oldShape &&
+        IsPropertyAddInlineable(cx, obj, id, oldSlots, &shape))
+    {
         RootedShape newShape(cx, obj->lastProperty());
         cache.incrementStubCount();
         if (!cache.attachNativeAdding(cx, ion, obj, oldShape, newShape, shape))
             return false;
     }
 
     return true;
 }
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/basic/bug821340.js
@@ -0,0 +1,10 @@
+var g = newGlobal('new-compartment');
+var dbg = Debugger(g);
+function test(code, expected) {
+    var actual = '';
+    g.h = function () { actual += dbg.getNewestFrame().environment.type; }
+    g.eval(code);
+}
+test("h();", 'object');
+gczeal(4);
+var count2 = countHeap();
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/truthiness/if-strict-equal-null.js
@@ -0,0 +1,46 @@
+var counterF = 0;
+
+function f(v, value)
+{
+  if (v === null)
+    counterF++;
+  assertEq(counterF, value,
+           "failed: " + v + " " + value);
+}
+
+f({}, 0);
+f({}, 0);
+f(null, 1);
+f(null, 2);
+f(undefined, 2);
+f(undefined, 2);
+f(objectEmulatingUndefined(), 2);
+f(objectEmulatingUndefined(), 2);
+f(Object.prototype, 2);
+f(Object.prototype, 2);
+
+var counterG = 0;
+
+function g(v, value)
+{
+  if (v === null)
+    counterG++;
+  assertEq(counterG, value,
+           "failed: " + v + " " + value);
+}
+
+g({}, 0);
+g({}, 0);
+
+var counterH = 0;
+
+function h(v, value)
+{
+  if (v === null)
+    counterH++;
+  assertEq(counterH, value,
+           "failed: " + v + " " + value);
+}
+
+h(objectEmulatingUndefined(), 0);
+h(objectEmulatingUndefined(), 0);
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/truthiness/if-strict-equal-undefined.js
@@ -0,0 +1,46 @@
+var counterF = 0;
+
+function f(v, value)
+{
+  if (v === undefined)
+    counterF++;
+  assertEq(counterF, value,
+           "failed: " + v + " " + value);
+}
+
+f({}, 0);
+f({}, 0);
+f(null, 0);
+f(null, 0);
+f(undefined, 1);
+f(undefined, 2);
+f(objectEmulatingUndefined(), 2);
+f(objectEmulatingUndefined(), 2);
+f(Object.prototype, 2);
+f(Object.prototype, 2);
+
+var counterG = 0;
+
+function g(v, value)
+{
+  if (v === undefined)
+    counterG++;
+  assertEq(counterG, value,
+           "failed: " + v + " " + value);
+}
+
+g({}, 0);
+g({}, 0);
+
+var counterH = 0;
+
+function h(v, value)
+{
+  if (v === undefined)
+    counterH++;
+  assertEq(counterH, value,
+           "failed: " + v + " " + value);
+}
+
+h(objectEmulatingUndefined(), 0);
+h(objectEmulatingUndefined(), 0);
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/truthiness/if-strict-not-equal-null.js
@@ -0,0 +1,46 @@
+var counterF = 0;
+
+function f(v, value)
+{
+  if (v !== null)
+    counterF++;
+  assertEq(counterF, value,
+           "failed: " + v + " " + value);
+}
+
+f({}, 1);
+f({}, 2);
+f(null, 2);
+f(null, 2);
+f(undefined, 3);
+f(undefined, 4);
+f(objectEmulatingUndefined(), 5);
+f(objectEmulatingUndefined(), 6);
+f(Object.prototype, 7);
+f(Object.prototype, 8);
+
+var counterG = 0;
+
+function g(v, value)
+{
+  if (v !== null)
+    counterG++;
+  assertEq(counterG, value,
+           "failed: " + v + " " + value);
+}
+
+g({}, 1);
+g({}, 2);
+
+var counterH = 0;
+
+function h(v, value)
+{
+  if (v !== null)
+    counterH++;
+  assertEq(counterH, value,
+           "failed: " + v + " " + value);
+}
+
+h(objectEmulatingUndefined(), 1);
+h(objectEmulatingUndefined(), 2);
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/truthiness/if-strict-not-equal-undefined.js
@@ -0,0 +1,46 @@
+var counterF = 0;
+
+function f(v, value)
+{
+  if (v !== undefined)
+    counterF++;
+  assertEq(counterF, value,
+           "failed: " + v + " " + value);
+}
+
+f({}, 1);
+f({}, 2);
+f(null, 3);
+f(null, 4);
+f(undefined, 4);
+f(undefined, 4);
+f(objectEmulatingUndefined(), 5);
+f(objectEmulatingUndefined(), 6);
+f(Object.prototype, 7);
+f(Object.prototype, 8);
+
+var counterG = 0;
+
+function g(v, value)
+{
+  if (v !== undefined)
+    counterG++;
+  assertEq(counterG, value,
+           "failed: " + v + " " + value);
+}
+
+g({}, 1);
+g({}, 2);
+
+var counterH = 0;
+
+function h(v, value)
+{
+  if (v !== undefined)
+    counterH++;
+  assertEq(counterH, value,
+           "failed: " + v + " " + value);
+}
+
+h(objectEmulatingUndefined(), 1);
+h(objectEmulatingUndefined(), 2);
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/truthiness/obj-obj-equal.js
@@ -0,0 +1,23 @@
+function f(v1, v2, value)
+{
+  var b = v1 == v2;
+  assertEq(b, value,
+           "failed: " + v1 + ", " + v2 + ": " + value);
+}
+
+var obj = {};
+var emul = objectEmulatingUndefined();
+
+f(obj, obj, true);
+f(obj, obj, true);
+f(emul, obj, false);
+f(emul, obj, false);
+f(obj, emul, false);
+f(obj, emul, false);
+f(Object.prototype, obj, false);
+f(Object.prototype, obj, false);
+f(emul, emul, true);
+f(objectEmulatingUndefined(), emul, false);
+f(objectEmulatingUndefined(), emul, false);
+f(emul, objectEmulatingUndefined(), false);
+f(emul, objectEmulatingUndefined(), false);
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/truthiness/obj-obj-not-equal.js
@@ -0,0 +1,23 @@
+function f(v1, v2, value)
+{
+  var b = v1 != v2;
+  assertEq(b, value,
+           "failed: " + v1 + ", " + v2 + ": " + value);
+}
+
+var obj = {};
+var emul = objectEmulatingUndefined();
+
+f(obj, obj, false);
+f(obj, obj, false);
+f(emul, obj, true);
+f(emul, obj, true);
+f(obj, emul, true);
+f(obj, emul, true);
+f(Object.prototype, obj, true);
+f(Object.prototype, obj, true);
+f(emul, emul, false);
+f(objectEmulatingUndefined(), emul, true);
+f(objectEmulatingUndefined(), emul, true);
+f(emul, objectEmulatingUndefined(), true);
+f(emul, objectEmulatingUndefined(), true);
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/truthiness/strict-equal-null.js
@@ -0,0 +1,37 @@
+function f(v, value)
+{
+  var b = v === null;
+  assertEq(b, value,
+           "failed: " + v + " " + value);
+}
+
+f({}, false);
+f({}, false);
+f(null, true);
+f(null, true);
+f(undefined, false);
+f(undefined, false);
+f(objectEmulatingUndefined(), false);
+f(objectEmulatingUndefined(), false);
+f(Object.prototype, false);
+f(Object.prototype, false);
+
+function g(v, value)
+{
+  var b = v === null;
+  assertEq(b, value,
+           "failed: " + v + " " + value);
+}
+
+g({}, false);
+g({}, false);
+
+function h(v, value)
+{
+  var b = v === null;
+  assertEq(b, value,
+           "failed: " + v + " " + value);
+}
+
+h(objectEmulatingUndefined(), false);
+h(objectEmulatingUndefined(), false);
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/truthiness/strict-equal-undefined.js
@@ -0,0 +1,37 @@
+function f(v, value)
+{
+  var b = v === undefined;
+  assertEq(b, value,
+           "failed: " + v + " " + value);
+}
+
+f({}, false);
+f({}, false);
+f(null, false);
+f(null, false);
+f(undefined, true);
+f(undefined, true);
+f(objectEmulatingUndefined(), false);
+f(objectEmulatingUndefined(), false);
+f(Object.prototype, false);
+f(Object.prototype, false);
+
+function g(v, value)
+{
+  var b = v === undefined;
+  assertEq(b, value,
+           "failed: " + v + " " + value);
+}
+
+g({}, false);
+g({}, false);
+
+function h(v, value)
+{
+  var b = v === undefined;
+  assertEq(b, value,
+           "failed: " + v + " " + value);
+}
+
+h(objectEmulatingUndefined(), false);
+h(objectEmulatingUndefined(), false);
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/truthiness/strict-not-equal-null.js
@@ -0,0 +1,37 @@
+function f(v, value)
+{
+  var b = v !== null;
+  assertEq(b, value,
+           "failed: " + v + " " + value);
+}
+
+f({}, true);
+f({}, true);
+f(null, false);
+f(null, false);
+f(undefined, true);
+f(undefined, true);
+f(objectEmulatingUndefined(), true);
+f(objectEmulatingUndefined(), true);
+f(Object.prototype, true);
+f(Object.prototype, true);
+
+function g(v, value)
+{
+  var b = v !== null;
+  assertEq(b, value,
+           "failed: " + v + " " + value);
+}
+
+g({}, true);
+g({}, true);
+
+function h(v, value)
+{
+  var b = v !== null;
+  assertEq(b, value,
+           "failed: " + v + " " + value);
+}
+
+h(objectEmulatingUndefined(), true);
+h(objectEmulatingUndefined(), true);
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/truthiness/strict-not-equal-undefined.js
@@ -0,0 +1,37 @@
+function f(v, value)
+{
+  var b = v !== undefined;
+  assertEq(b, value,
+           "failed: " + v + " " + value);
+}
+
+f({}, true);
+f({}, true);
+f(null, true);
+f(null, true);
+f(undefined, false);
+f(undefined, false);
+f(objectEmulatingUndefined(), true);
+f(objectEmulatingUndefined(), true);
+f(Object.prototype, true);
+f(Object.prototype, true);
+
+function g(v, value)
+{
+  var b = v !== undefined;
+  assertEq(b, value,
+           "failed: " + v + " " + value);
+}
+
+g({}, true);
+g({}, true);
+
+function h(v, value)
+{
+  var b = v !== undefined;
+  assertEq(b, value,
+           "failed: " + v + " " + value);
+}
+
+h(objectEmulatingUndefined(), true);
+h(objectEmulatingUndefined(), true);
--- a/js/src/jsmath.cpp
+++ b/js/src/jsmath.cpp
@@ -373,71 +373,47 @@ js::math_log(JSContext *cx, unsigned arg
     z = math_log_impl(mathCache, x);
     vp->setNumber(z);
     return JS_TRUE;
 }
 
 JSBool
 js_math_max(JSContext *cx, unsigned argc, Value *vp)
 {
-    double x, z = js_NegativeInfinity;
-    Value *argv;
-    unsigned i;
+    CallArgs args = CallArgsFromVp(argc, vp);
 
-    if (argc == 0) {
-        vp->setDouble(js_NegativeInfinity);
-        return JS_TRUE;
+    double x;
+    double maxval = MOZ_DOUBLE_NEGATIVE_INFINITY();
+    for (unsigned i = 0; i < args.length(); i++) {
+        if (!ToNumber(cx, args[i], &x))
+            return false;
+        // Math.max(num, NaN) => NaN, Math.max(-0, +0) => +0
+        if (x > maxval || MOZ_DOUBLE_IS_NaN(x) || (x == maxval && MOZ_DOUBLE_IS_NEGATIVE(maxval)))
+            maxval = x;
     }
-    argv = vp + 2;
-    for (i = 0; i < argc; i++) {
-        if (!ToNumber(cx, argv[i], &x))
-            return JS_FALSE;
-        if (MOZ_DOUBLE_IS_NaN(x)) {
-            vp->setDouble(js_NaN);
-            return JS_TRUE;
-        }
-        if (x == 0 && x == z) {
-            if (js_copysign(1.0, z) == -1)
-                z = x;
-        } else {
-            z = (x > z) ? x : z;
-        }
-    }
-    vp->setNumber(z);
-    return JS_TRUE;
+    args.rval().setNumber(maxval);
+    return true;
 }
 
 JSBool
 js_math_min(JSContext *cx, unsigned argc, Value *vp)
 {
-    double x, z = js_PositiveInfinity;
-    Value *argv;
-    unsigned i;
+    CallArgs args = CallArgsFromVp(argc, vp);
 
-    if (argc == 0) {
-        vp->setDouble(js_PositiveInfinity);
-        return JS_TRUE;
+    double x;
+    double minval = MOZ_DOUBLE_POSITIVE_INFINITY();
+    for (unsigned i = 0; i < args.length(); i++) {
+        if (!ToNumber(cx, args[i], &x))
+            return false;
+        // Math.min(num, NaN) => NaN, Math.min(-0, +0) => -0
+        if (x < minval || MOZ_DOUBLE_IS_NaN(x) || (x == minval && MOZ_DOUBLE_IS_NEGATIVE_ZERO(x)))
+            minval = x;
     }
-    argv = vp + 2;
-    for (i = 0; i < argc; i++) {
-        if (!ToNumber(cx, argv[i], &x))
-            return JS_FALSE;
-        if (MOZ_DOUBLE_IS_NaN(x)) {
-            vp->setDouble(js_NaN);
-            return JS_TRUE;
-        }
-        if (x == 0 && x == z) {
-            if (js_copysign(1.0, x) == -1)
-                z = x;
-        } else {
-            z = (x < z) ? x : z;
-        }
-    }
-    vp->setNumber(z);
-    return JS_TRUE;
+    args.rval().setNumber(minval);
+    return true;
 }
 
 // Disable PGO for Math.pow() and related functions (see bug 791214).
 #if defined(_MSC_VER)
 # pragma optimize("g", off)
 #endif
 double
 js::powi(double x, int y)
--- a/js/src/vm/SelfHosting.cpp
+++ b/js/src/vm/SelfHosting.cpp
@@ -98,16 +98,42 @@ intrinsic_ThrowError(JSContext *cx, unsi
 
     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, errorNumber,
                          errorArgs[0], errorArgs[1], errorArgs[2]);
     for (unsigned i = 0; i < 3; i++)
         js_free(errorArgs[i]);
     return false;
 }
 
+/**
+ * Handles an assertion failure in self-hosted code just like an assertion
+ * failure in C++ code. Information about the failure can be provided in args[0].
+ */
+static JSBool
+intrinsic_AssertionFailed(JSContext *cx, unsigned argc, Value *vp)
+{
+    CallArgs args = CallArgsFromVp(argc, vp);
+#ifdef DEBUG
+    if (argc > 0) {
+        // try to dump the informative string
+        JSString *str = ToString(cx, args[0]);
+        if (str) {
+            const jschar *chars = str->getChars(cx);
+            if (chars) {
+                fprintf(stderr, "Self-hosted JavaScript assertion info: ");
+                JSString::dumpChars(chars, str->length());
+                fputc('\n', stderr);
+            }
+        }
+    }
+#endif
+    JS_ASSERT(false);
+    return false;
+}
+
 /*
  * Used to decompile values in the nearest non-builtin stack frame, falling
  * back to decompiling in the current frame. Helpful for printing higher-order
  * function arguments.
  *
  * The user must supply the argument number of the value in question; it
  * _cannot_ be automatically determined.
  */
@@ -139,20 +165,22 @@ intrinsic_MakeConstructible(JSContext *c
     return true;
 }
 
 JSFunctionSpec intrinsic_functions[] = {
     JS_FN("ToObject",           intrinsic_ToObject,             1,0),
     JS_FN("ToInteger",          intrinsic_ToInteger,            1,0),
     JS_FN("IsCallable",         intrinsic_IsCallable,           1,0),
     JS_FN("ThrowError",         intrinsic_ThrowError,           4,0),
+    JS_FN("AssertionFailed",    intrinsic_AssertionFailed,      1,0),
     JS_FN("MakeConstructible",  intrinsic_MakeConstructible,    1,0),
     JS_FN("DecompileArg",       intrinsic_DecompileArg,         2,0),
     JS_FS_END
 };
+
 bool
 JSRuntime::initSelfHosting(JSContext *cx)
 {
     JS_ASSERT(!selfHostingGlobal_);
     RootedObject savedGlobal(cx, JS_GetGlobalObject(cx));
     if (!(selfHostingGlobal_ = JS_NewGlobalObject(cx, &self_hosting_global_class, NULL)))
         return false;
     JS_SetGlobalObject(cx, selfHostingGlobal_);
--- a/layout/base/FrameLayerBuilder.cpp
+++ b/layout/base/FrameLayerBuilder.cpp
@@ -110,17 +110,17 @@ FrameLayerBuilder::DisplayItemData::Upda
   mClip.mHaveClipRect = false;
   mClip.mRoundedClipRects.Clear();
   mUsed = true;
 
   if (!aItem) {
     return;
   }
 
-  nsAutoTArray<nsIFrame*, 4> copy = mFrameList;
+  nsAutoTArray<nsIFrame*, 4> copy(mFrameList);
   if (!copy.RemoveElement(aItem->GetUnderlyingFrame())) {
     AddFrame(aItem->GetUnderlyingFrame());
   }
 
   nsAutoTArray<nsIFrame*,4> mergedFrames;
   aItem->GetMergedFrames(&mergedFrames);
   for (uint32_t i = 0; i < mergedFrames.Length(); ++i) {
     if (!copy.RemoveElement(mergedFrames[i])) {
--- a/layout/generic/nsIAnonymousContentCreator.h
+++ b/layout/generic/nsIAnonymousContentCreator.h
@@ -9,20 +9,20 @@
  */
 
 #ifndef nsIAnonymousContentCreator_h___
 #define nsIAnonymousContentCreator_h___
 
 #include "nsQueryFrame.h"
 #include "nsIContent.h"
 #include "nsStyleContext.h"
+#include "nsTArrayForwardDeclare.h"
 
 class nsBaseContentList;
 class nsIFrame;
-template <class T, class A> class nsTArray;
 
 /**
  * Any source for anonymous content can implement this interface to provide it.
  * HTML frames like nsFileControlFrame currently use this.
  *
  * @see nsCSSFrameConstructor
  */
 class nsIAnonymousContentCreator
--- a/layout/ipc/PRenderFrame.ipdl
+++ b/layout/ipc/PRenderFrame.ipdl
@@ -37,17 +37,16 @@ parent:
      * |id| is set to 0 in the "direct" case, and to a whole number
      * in the "indirect" case.
      */
     async PLayers();
 
     async NotifyCompositorTransaction();
 
     async CancelDefaultPanZoom();
-    async DetectScrollableSubframe();
 
     async __delete__();
 
 state EMPTY_OR_DIRECT_COMPOSITOR:
     recv PLayers goto HAVE_CONTENT;
     recv NotifyCompositorTransaction goto EMPTY_OR_DIRECT_COMPOSITOR;
     recv __delete__;
 
--- a/layout/ipc/RenderFrameChild.cpp
+++ b/layout/ipc/RenderFrameChild.cpp
@@ -33,22 +33,16 @@ RenderFrameChild::Destroy()
 }
 
 void
 RenderFrameChild::CancelDefaultPanZoom()
 {
   SendCancelDefaultPanZoom();
 }
 
-void
-RenderFrameChild::DetectScrollableSubframe()
-{
-  SendDetectScrollableSubframe();
-}
-
 PLayersChild*
 RenderFrameChild::AllocPLayers()
 {
   return new ShadowLayersChild();
 }
 
 bool
 RenderFrameChild::DeallocPLayers(PLayersChild* aLayers)
--- a/layout/ipc/RenderFrameChild.h
+++ b/layout/ipc/RenderFrameChild.h
@@ -15,17 +15,16 @@ namespace layout {
 
 class RenderFrameChild : public PRenderFrameChild
 {
 public:
   RenderFrameChild() {}
   virtual ~RenderFrameChild() {}
 
   void CancelDefaultPanZoom();
-  void DetectScrollableSubframe();
 
   void Destroy();
 
 protected:
   virtual PLayersChild* AllocPLayers() MOZ_OVERRIDE;
   virtual bool DeallocPLayers(PLayersChild* aLayers) MOZ_OVERRIDE;
 };
 
--- a/layout/ipc/RenderFrameParent.cpp
+++ b/layout/ipc/RenderFrameParent.cpp
@@ -805,25 +805,16 @@ bool
 RenderFrameParent::RecvCancelDefaultPanZoom()
 {
   if (mPanZoomController) {
     mPanZoomController->CancelDefaultPanZoom();
   }
   return true;
 }
 
-bool
-RenderFrameParent::RecvDetectScrollableSubframe()
-{
-  if (mPanZoomController) {
-    mPanZoomController->DetectScrollableSubframe();
-  }
-  return true;
-}
-
 PLayersParent*
 RenderFrameParent::AllocPLayers()
 {
   if (!mFrameLoader || mFrameLoaderDestroyed) {
     return nullptr;
   }
   nsRefPtr<LayerManager> lm = GetFrom(mFrameLoader);
   return new ShadowLayersParent(lm->AsShadowManager(), this, 0);
--- a/layout/ipc/RenderFrameParent.h
+++ b/layout/ipc/RenderFrameParent.h
@@ -104,17 +104,16 @@ public:
   void UpdateZoomConstraints(bool aAllowZoom, float aMinZoom, float aMaxZoom);
 
 protected:
   void ActorDestroy(ActorDestroyReason why) MOZ_OVERRIDE;
 
   virtual bool RecvNotifyCompositorTransaction() MOZ_OVERRIDE;
 
   virtual bool RecvCancelDefaultPanZoom() MOZ_OVERRIDE;
-  virtual bool RecvDetectScrollableSubframe() MOZ_OVERRIDE;
 
   virtual PLayersParent* AllocPLayers() MOZ_OVERRIDE;
   virtual bool DeallocPLayers(PLayersParent* aLayers) MOZ_OVERRIDE;
 
 private:
   void BuildViewMap();
   void TriggerRepaint();
   void DispatchEventForPanZoomController(const InputEvent& aEvent);
--- a/layout/style/nsCSSStyleSheet.h
+++ b/layout/style/nsCSSStyleSheet.h
@@ -26,17 +26,16 @@
 class nsXMLNameSpaceMap;
 class nsCSSRuleProcessor;
 class nsIPrincipal;
 class nsIURI;
 class nsMediaList;
 class nsMediaQueryResultCacheKey;
 class nsCSSStyleSheet;
 class nsPresContext;
-template<class E, class A> class nsTArray;
 
 namespace mozilla {
 namespace css {
 class Rule;
 class GroupRule;
 class ImportRule;
 }
 }
--- a/media/webrtc/signaling/signaling.gyp
+++ b/media/webrtc/signaling/signaling.gyp
@@ -577,16 +577,19 @@
 
       ],
 
       #
       # DEFINES
       #
       
       'defines' : [
+      # CPR timers are needed by SIP, but are disabled for now
+      # to avoid the extra timer thread and stale cleanup code
+      #    'CPR_TIMERS_ENABLED',
       ],
 
       'cflags_mozilla': [
         '$(NSPR_CFLAGS)',
       ],
 
       #
       # OS SPECIFIC
--- a/media/webrtc/signaling/src/common/browser_logging/CSFLog.cpp
+++ b/media/webrtc/signaling/src/common/browser_logging/CSFLog.cpp
@@ -4,34 +4,52 @@
 
 #include <stdio.h>
 #include <string.h>
 #include <stdarg.h>
 
 #include "CSFLog.h"
 #include "base/basictypes.h"
 #include "prtypes.h"
-#include "prlog.h"
 
 static PRLogModuleInfo *gLogModuleInfo = NULL;
 
+PRLogModuleInfo *GetSignalingLogInfo()
+{
+  if (gLogModuleInfo == NULL)
+    gLogModuleInfo = PR_NewLogModule("signaling");
+
+  return gLogModuleInfo;
+}
+
+static PRLogModuleInfo *gWebRTCLogModuleInfo = NULL;
+int gWebrtcTraceLoggingOn = 0;
+
+PRLogModuleInfo *GetWebRTCLogInfo()
+{
+  if (gWebRTCLogModuleInfo == NULL)
+    gWebRTCLogModuleInfo = PR_NewLogModule("webrtc_trace");
+
+  return gWebRTCLogModuleInfo;
+}
+
+
 void CSFLogV(CSFLogLevel priority, const char* sourceFile, int sourceLine, const char* tag , const char* format, va_list args)
 {
 #ifdef STDOUT_LOGGING
   printf("%s\n:",tag);
   vprintf(format, args);
 #else
 
 #define MAX_MESSAGE_LENGTH 1024
   char message[MAX_MESSAGE_LENGTH];
 
   vsnprintf(message, MAX_MESSAGE_LENGTH, format, args);
 
-  if (gLogModuleInfo == NULL)
-    gLogModuleInfo = PR_NewLogModule("ikran");
+  GetSignalingLogInfo();
 
   switch(priority)
   {
     case CSF_LOG_CRITICAL:
     case CSF_LOG_ERROR:
       PR_LOG(gLogModuleInfo, PR_LOG_ERROR, ("%s %s", tag, message));
       break;
     case CSF_LOG_WARNING:
--- a/media/webrtc/signaling/src/common/browser_logging/CSFLog.h
+++ b/media/webrtc/signaling/src/common/browser_logging/CSFLog.h
@@ -1,16 +1,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/. */
 
 #ifndef CSFLOG_H
 #define CSFLOG_H
 
 #include <stdarg.h>
+#include "prlog.h"
 
 typedef enum{
 	CSF_LOG_CRITICAL =1,
 	CSF_LOG_ERROR,
 	CSF_LOG_WARNING,
 	CSF_LOG_NOTICE,
 	CSF_LOG_INFO,
 	CSF_LOG_DEBUG
@@ -28,14 +29,19 @@ typedef enum{
 #define CSFLogDebugV(tag , format, va_list_arg) CSFLogV(CSF_LOG_DEBUG, __FILE__ , __LINE__ , tag , format , va_list_arg )
 
 #ifdef __cplusplus
 extern "C"
 {
 #endif
 void CSFLog( CSFLogLevel priority, const char* sourceFile, int sourceLine, const char* tag , const char* format, ...);
 void CSFLogV( CSFLogLevel priority, const char* sourceFile, int sourceLine, const char* tag , const char* format, va_list args);
+
+PRLogModuleInfo *GetSignalingLogInfo();
+PRLogModuleInfo *GetWebRTCLogInfo();
+extern int gWebrtcTraceLoggingOn;
+
 #ifdef __cplusplus
 }
 #endif
 
 #endif
 
--- a/media/webrtc/signaling/src/media-conduit/AudioConduit.cpp
+++ b/media/webrtc/signaling/src/media-conduit/AudioConduit.cpp
@@ -88,16 +88,31 @@ MediaConduitErrorCode WebrtcAudioConduit
 
   //Per WebRTC APIs below function calls return NULL on failure
   if(!(mVoiceEngine = webrtc::VoiceEngine::Create()))
   {
     CSFLogError(logTag, "%s Unable to create voice engine", __FUNCTION__);
     return kMediaConduitSessionNotInited;
   }
 
+  PRLogModuleInfo *logs = GetWebRTCLogInfo();
+  if (!gWebrtcTraceLoggingOn && logs && logs->level > 0) {
+    // no need to a critical section or lock here
+    gWebrtcTraceLoggingOn = 1;
+
+    const char *file = PR_GetEnv("WEBRTC_TRACE_FILE");
+    if (!file) {
+      file = "WebRTC.log";
+    }
+    CSFLogDebug(logTag,  "%s Logging webrtc to %s level %d", __FUNCTION__,
+                file, logs->level);
+    mVoiceEngine->SetTraceFilter(logs->level);
+    mVoiceEngine->SetTraceFile(file);
+  }
+
   if(!(mPtrVoEBase = VoEBase::GetInterface(mVoiceEngine)))
   {
     CSFLogError(logTag, "%s Unable to initialize VoEBase", __FUNCTION__);
     return kMediaConduitSessionNotInited;
   }
 
   if(!(mPtrVoENetwork = VoENetwork::GetInterface(mVoiceEngine)))
   {
--- a/media/webrtc/signaling/src/media-conduit/VideoConduit.cpp
+++ b/media/webrtc/signaling/src/media-conduit/VideoConduit.cpp
@@ -75,17 +75,16 @@ WebrtcVideoConduit::~WebrtcVideoConduit(
     mPtrViEBase->DeleteChannel(mChannel);
     mPtrViEBase->Release();
   }
 
   if (mPtrRTP)
   {
     mPtrRTP->Release();
   }
-
   if(mVideoEngine)
   {
     webrtc::VideoEngine::Delete(mVideoEngine);
   }
 }
 
 /**
  * Peforms intialization of the MANDATORY components of the Video Engine
@@ -96,21 +95,30 @@ MediaConduitErrorCode WebrtcVideoConduit
   CSFLogDebug(logTag,  "%s ", __FUNCTION__);
 
   if( !(mVideoEngine = webrtc::VideoEngine::Create()) )
   {
     CSFLogError(logTag, "%s Unable to create video engine ", __FUNCTION__);
      return kMediaConduitSessionNotInited;
   }
 
-#if 0
-  // TRACING
-  mVideoEngine->SetTraceFilter(webrtc::kTraceAll);
-  mVideoEngine->SetTraceFile( "Vievideotrace.out" );
-#endif
+  PRLogModuleInfo *logs = GetWebRTCLogInfo();
+  if (!gWebrtcTraceLoggingOn && logs && logs->level > 0) {
+    // no need to a critical section or lock here
+    gWebrtcTraceLoggingOn = 1;
+
+    const char *file = PR_GetEnv("WEBRTC_TRACE_FILE");
+    if (!file) {
+      file = "WebRTC.log";
+    }
+    CSFLogDebug(logTag,  "%s Logging webrtc to %s level %d", __FUNCTION__,
+                file, logs->level);
+    mVideoEngine->SetTraceFilter(logs->level);
+    mVideoEngine->SetTraceFile(file);
+  }
 
   if( !(mPtrViEBase = ViEBase::GetInterface(mVideoEngine)))
   {
     CSFLogError(logTag, "%s Unable to get video base interface ", __FUNCTION__);
     return kMediaConduitSessionNotInited;
   }
 
   if( !(mPtrViECapture = ViECapture::GetInterface(mVideoEngine)))
--- a/media/webrtc/signaling/src/sipcc/core/common/init.c
+++ b/media/webrtc/signaling/src/sipcc/core/common/init.c
@@ -211,17 +211,17 @@ ccInit ()
 
     platInit();
 
     strlib_init();
 
     /*
      * below should move to cprPreInit. keep it here until then
      */
-#ifdef _WIN32
+#if defined(_WIN32) && defined(CPR_TIMERS_ENABLED)
     cprTimerSystemInit();
 #endif
 
     /* Initialize threads, queues etc. */
     (void) thread_init();
 
     platform_initialized = TRUE;
 
--- a/media/webrtc/signaling/src/sipcc/core/sipstack/sip_platform_task.c
+++ b/media/webrtc/signaling/src/sipcc/core/sipstack/sip_platform_task.c
@@ -32,27 +32,26 @@
 /* The maximum number of messages parsed from the message queue at one time */
 #define MAX_SIP_MESSAGES 8
 
 /* The maximum number of connections allowed */
 #define MAX_SIP_CONNECTIONS (64 - 2)
 
 /* SIP Message queue waiting thread and the main thread IPC names */
 #ifdef __ANDROID__
-#define SIP_MSG_IPC_PATH  "/data/data/com.cisco.telephony.provider/"
+#define SIP_IPC_TEMP_PATH "/data/data/com.cisco.telephony.provider/SIP-%d"
 #else
-#define SIP_MSG_IPC_PATH  "/tmp/"
+#define SIP_IPC_TEMP_PATH "/tmp/SIP-%d"
 #endif
-#define SIP_MSG_SERV_NAME "SIP-Main-%d"
-#define SIP_MSG_CLNT_NAME "SIP-MsgQ-%d"
+#define SIP_MSG_SERV_NAME "Main"
+#define SIP_MSG_CLNT_NAME "MsgQ"
 
 #define SIP_PAUSE_WAIT_IPC_LISTEN_READY_TIME   50  /* 50ms. */
 #define SIP_MAX_WAIT_FOR_IPC_LISTEN_READY    1200  /* 50 * 1200 = 1 minutes */
 
-
 /*---------------------------------------------------------
  *
  * Local Variables
  *
  */
 fd_set read_fds;
 fd_set write_fds;
 static cpr_socket_t listen_socket = INVALID_SOCKET;
@@ -69,19 +68,16 @@ sip_connection_t sip_conn;
 typedef struct sip_int_msg_t_ {
     void            *msg;
     phn_syshdr_t    *syshdr;
 } sip_int_msg_t;
 
 /* Internal message queue (array) */
 static sip_int_msg_t sip_int_msgq_buf[MAX_SIP_MESSAGES] = {{0,0},{0,0}};
 
-/* Main thread and message queue waiting thread IPC names */
-static const char *sip_IPC_serv_name = SIP_MSG_IPC_PATH SIP_MSG_SERV_NAME;
-static const char *sip_IPC_clnt_name = SIP_MSG_IPC_PATH SIP_MSG_CLNT_NAME;
 static cpr_sockaddr_un_t sip_serv_sock_addr;
 static cpr_sockaddr_un_t sip_clnt_sock_addr;
 
 
 /*---------------------------------------------------------
  *
  * Global Variables
  *
@@ -158,17 +154,17 @@ static cpr_socket_t sip_create_IPC_sock 
                           " errno=%d\n", fname, cpr_errno);
         return (INVALID_SOCKET);
     }
 
     /* Bind to the local socket */
     cpr_set_sockun_addr(&addr, name, getpid());
 
     /* make sure file doesn't already exist */
-    unlink( (char *)addr.sun_path);
+    unlink(addr.sun_path);
 
     /* do the bind */
     if (cprBind(sock, (cpr_sockaddr_t *)&addr,
                 cpr_sun_len(addr)) == CPR_FAILURE) {
         (void) sipSocketClose(sock, FALSE);
         CCSIP_DEBUG_ERROR(SIP_F_PREFIX"cprBind() failed"
                           " errno=%d\n", fname, cpr_errno);
         return (INVALID_SOCKET);
@@ -235,30 +231,26 @@ void sip_platform_task_msgqwait (void *a
                               " socket ready, exiting\n", fname);
             return;
         }
     }
 
     /*
      * Adjust relative priority of SIP thread.
      */
-#ifndef WIN32
     (void) cprAdjustRelativeThreadPriority(SIP_THREAD_RELATIVE_PRIORITY);
-#else
-    /* Use default priority */
-    (void) cprAdjustRelativeThreadPriority(0);
-#endif
 
     /*
      * The main thread is ready. set global client socket address
      * so that the server can send back response.
      */
-    cpr_set_sockun_addr(&sip_clnt_sock_addr, sip_IPC_clnt_name, getpid());
+    cpr_set_sockun_addr(&sip_clnt_sock_addr,
+                        SIP_IPC_TEMP_PATH "/" SIP_MSG_CLNT_NAME, getpid());
 
-    sip_ipc_clnt_socket = sip_create_IPC_sock(sip_IPC_clnt_name);
+    sip_ipc_clnt_socket = sip_create_IPC_sock(sip_clnt_sock_addr.sun_path);
 
     if (sip_ipc_clnt_socket == INVALID_SOCKET) {
         CCSIP_DEBUG_ERROR(SIP_F_PREFIX"sip_create_IPC_sock() failed,"
                           "  exiting\n", fname);
         return;
     }
 
     while (quit_thread == FALSE) {
@@ -318,16 +310,18 @@ void sip_platform_task_msgqwait (void *a
             			sizeof(response), 0, NULL, NULL) < 0) {
             		CCSIP_DEBUG_ERROR(SIP_F_PREFIX"read IPC failed:"
             				" errno=%d\n", fname, cpr_errno);
             	}
             	num_messages = 0;
             }
         }
     }
+    cprCloseSocket(sip_ipc_clnt_socket);
+    unlink(sip_clnt_sock_addr.sun_path); // removes tmp file
 }
 
 /**
  *  sip_process_int_msg - process internal IPC message from the
  *  the message queue waiting thread.
  *
  *  @param - none.
  *
@@ -365,16 +359,31 @@ static void sip_process_int_msg (void)
     }
 
     /* process messages */
     int_msg = &sip_int_msgq_buf[0];
     while (num_messages) {
         msg    = int_msg->msg;
         syshdr = int_msg->syshdr;
         if (msg != NULL && syshdr != NULL) {
+            if (syshdr->Cmd == THREAD_UNLOAD) {
+                /*
+                 * Cleanup here, as SIPTaskProcessListEvent wont return.
+                 * - Remove last tmp file and tmp dir.
+                 */
+                cprCloseSocket(sip_ipc_serv_socket);
+                unlink(sip_serv_sock_addr.sun_path);
+
+                char stmpdir[sizeof(sip_serv_sock_addr.sun_path)];
+                PR_snprintf(stmpdir, sizeof(stmpdir), SIP_IPC_TEMP_PATH, getpid());
+                if (rmdir(stmpdir) != 0) {
+                    CCSIP_DEBUG_ERROR(SIP_F_PREFIX"failed to remove temp dir\n",
+                                      fname);
+                }
+            }
             SIPTaskProcessListEvent(syshdr->Cmd, msg, syshdr->Usr.UsrPtr,
                 syshdr->Len);
             cprReleaseSysHeader(syshdr);
 
             int_msg->msg    = NULL;
             int_msg->syshdr = NULL;
         }
 
@@ -430,33 +439,38 @@ sip_platform_task_loop (void *arg)
     if (platThreadInit("SIPStack Task") != 0) {
         CCSIP_DEBUG_ERROR(SIP_F_PREFIX"failed to attach thread to JVM\n", fname);
         return;
     }
 
     /*
      * Adjust relative priority of SIP thread.
      */
-#ifndef WIN32
     (void) cprAdjustRelativeThreadPriority(SIP_THREAD_RELATIVE_PRIORITY);
-#else
-    /* Use default priority */
-    (void) cprAdjustRelativeThreadPriority(0);
-#endif
 
     /*
      * Setup IPC socket addresses for main thread (server)
      */
-    cpr_set_sockun_addr(&sip_serv_sock_addr, sip_IPC_serv_name, getpid());
+    {
+      char stmpdir[sizeof(sip_serv_sock_addr.sun_path)];
+      PR_snprintf(stmpdir, sizeof(stmpdir), SIP_IPC_TEMP_PATH, getpid());
+
+      if (mkdir(stmpdir, 0700) != 0) {
+          CCSIP_DEBUG_ERROR(SIP_F_PREFIX"failed to create temp dir\n", fname);
+          return;
+      }
+    }
+    cpr_set_sockun_addr(&sip_serv_sock_addr,
+                        SIP_IPC_TEMP_PATH "/" SIP_MSG_SERV_NAME, getpid());
 
     /*
      * Create IPC between the message queue thread and this main
      * thread.
      */
-    sip_ipc_serv_socket = sip_create_IPC_sock(sip_IPC_serv_name);
+    sip_ipc_serv_socket = sip_create_IPC_sock(sip_serv_sock_addr.sun_path);
 
     if (sip_ipc_serv_socket == INVALID_SOCKET) {
         CCSIP_DEBUG_ERROR(SIP_F_PREFIX"sip_create_IPC_sock() failed:"
                           " errno=%d\n", fname, cpr_errno);
         return;
     }
 
     /*
@@ -475,16 +489,17 @@ sip_platform_task_loop (void *arg)
     /*
      * Let the message queue waiting thread know that the main
      * thread is ready.
      */
     main_thread_ready = TRUE;
 
     /*
      * Main Event Loop
+     * - Forever-loop exits in sip_process_int_msg()::THREAD_UNLOAD
      */
     while (TRUE) {
         /*
          * Wait on events or timeout
          */
         sip_read_fds = read_fds;
 
         // start off by init to zero
--- a/media/webrtc/signaling/src/sipcc/cpr/darwin/cpr_darwin_init.c
+++ b/media/webrtc/signaling/src/sipcc/cpr/darwin/cpr_darwin_init.c
@@ -166,24 +166,23 @@ cprPreInit (void)
     /*
      * Create message queue list mutex
      */
     returnCode = pthread_mutex_init(&msgQueueListMutex, NULL);
     if (returnCode != 0) {
         CPR_ERROR("%s: MsgQueue Mutex init failure %d\n", fname, returnCode);
         return CPR_FAILURE;
     }
-
+#ifdef CPR_TIMERS_ENABLED
     returnCode = cpr_timer_pre_init();
     if (returnCode != 0) {
         CPR_ERROR("%s: timer pre init failed %d\n", fname, returnCode);
         return CPR_FAILURE;
     }
-
-
+#endif
     return CPR_SUCCESS;
 }
 
 
 /**
  * cprPostInit
  *
  * @brief The cprPostInit function IS called from pSIPCC @b after all the components are initialized.
--- a/media/webrtc/signaling/src/sipcc/cpr/darwin/cpr_darwin_socket.c
+++ b/media/webrtc/signaling/src/sipcc/cpr/darwin/cpr_darwin_socket.c
@@ -760,26 +760,26 @@ cpr_inet_pton (int af, const char *src, 
 }
 
 
 /**
  *  Utility function that sets up the socket address
  *
  *  @param[in] addr - socket fd to bind with the IPC address.
  *  @param[in] name - pointer to the name of socket to bind to.
- *
+ *  @param[in] pid  - process id (only used if name contains %d)
  *
  *  @pre  (name != NULL)
  */
 void cpr_set_sockun_addr (cpr_sockaddr_un_t *addr, const char *name, pid_t pid)
 {
     /* Bind to the local socket */
     memset(addr, 0, sizeof(cpr_sockaddr_un_t));
     addr->sun_family = AF_UNIX;
-    snprintf((char *) addr->sun_path, sizeof(addr->sun_path), "%s_%d", name, pid);
+    snprintf(addr->sun_path, sizeof(addr->sun_path), name, pid);
 }
 
 /* int
  * inet_pton4(src, dst, pton)
  *	when last arg is 0: inet_aton(). with hexadecimal, octal and shorthand.
  *	when last arg is 1: inet_pton(). decimal dotted-quad only.
  * return:
  *	1 if `src' is a valid input, else 0.
--- a/media/webrtc/signaling/src/sipcc/cpr/darwin/cpr_darwin_timers_using_select.c
+++ b/media/webrtc/signaling/src/sipcc/cpr/darwin/cpr_darwin_timers_using_select.c
@@ -47,16 +47,17 @@
  * @brief The module related to Timer abstraction for the pSIPCC
  * @addtogroup TimerAPIs The Timer APIs
  * @ingroup Timers
  * @brief APIs expected by pSIPCC for using Timers
  *
  */
 
 #include "cpr.h"
+#include "cpr_assert.h"
 #include "cpr_socket.h"
 #include "cpr_stdlib.h"
 #include "cpr_stdio.h"
 #include "cpr_threads.h"
 #include "cpr_timers.h"
 #include "cpr_string.h"
 #include "phntask.h"
 #include <errno.h>
@@ -221,24 +222,20 @@ cprSleep (uint32_t duration)
  * @param[in] cprTimerPtr  - timer pointer
  * @param[in] duration     - timer duration in msec.
  * @param[in] data         - opaque data
  * @return  - CPR_SUCCESS or CPR_FAILURE
  */
 static cprRC_t addTimerToList (cpr_timer_t *cprTimerPtr, uint32_t duration, void *data)
 {
     // TODO(ekr@rtfm.com): Put this back in when you figure out why it causes crashes
-    return CPR_SUCCESS;
-
-#if 0
-    static const char fname[] = "addTimerToList";
+#ifdef CPR_TIMERS_ENABLED
     timer_ipc_t tmr_cmd = {0};
     timer_ipc_t tmr_rsp={0};
 
-
     API_ENTER();
 
     CPR_INFO("%s: cprTimerptr=0x%x dur=%d user_data=%p\n",
              fname, cprTimerPtr, duration, data);
     tmr_cmd.msg_type = TMR_CMD_ADD;
     tmr_cmd.u.cmd.timer_ptr = cprTimerPtr;
     tmr_cmd.u.cmd.user_data_ptr = data;
     tmr_cmd.u.cmd.duration = duration;
@@ -249,33 +246,37 @@ static cprRC_t addTimerToList (cpr_timer
         if (sendto(client_sock, &tmr_cmd, sizeof(timer_ipc_t), 0,
                    (struct sockaddr *)&tmr_serv_addr, sizeof(tmr_serv_addr)) < 0) {
             CPR_ERROR("Failed to tx IPC msg to timer service, errno = %s %s\n",
                    strerror(errno), fname);
             API_RETURN(CPR_FAILURE);
         }
 
     } else {
-        CPR_ERROR("can not make IPC connection, client_sock is invalid %s\n", fname);
+        CPR_ERROR("can not make IPC connection, client_sock is invalid %s\n", __FUNCTION__);
         API_RETURN(CPR_FAILURE);
     }
 
     /*
      * wait for the timer service to excute the request
      * so that we get result of operation
      */
 
     if (recvfrom(client_sock, &tmr_rsp, sizeof(timer_ipc_t),0, NULL, NULL) < 0) {
         //CPR_INFO("error in recving the result error=%s\n", strerror(errno));
         API_RETURN(CPR_FAILURE);
     } else {
         //CPR_INFO("received response from the timer result=%d\n", tmr_rsp.u.result);
         API_RETURN(tmr_rsp.u.result);
     }
+#else
+    cprAssert(FALSE, CPR_FAILURE);
+    CPR_ERROR("CPR Timers are disabled! %s\n", __FUNCTION__);
 #endif
+    return CPR_SUCCESS;
 }
 
 
 /**
  * addTimer
  *
  * Add a timer to the timer linked list.
  * This function is only called by CPR functions and is not visible to external
--- a/media/webrtc/signaling/src/sipcc/cpr/linux/cpr_linux_init.c
+++ b/media/webrtc/signaling/src/sipcc/cpr/linux/cpr_linux_init.c
@@ -170,24 +170,23 @@ cprPreInit (void)
     /*
      * Create message queue list mutex
      */
     returnCode = pthread_mutex_init(&msgQueueListMutex, NULL);
     if (returnCode != 0) {
         CPR_ERROR("%s: MsgQueue Mutex init failure %d\n", fname, returnCode);
         return CPR_FAILURE;
     }
-
+#if CPR_TIMERS_ENABLED
     returnCode = cpr_timer_pre_init();
     if (returnCode != 0) {
         CPR_ERROR("%s: timer pre init failed %d\n", fname, returnCode);
         return CPR_FAILURE;
     }
-
-
+#endif
     return CPR_SUCCESS;
 }
 
 
 /**
  * cprPostInit
  *
  * @brief The cprPostInit function IS called from pSIPCC @b after all the components are initialized.
--- a/media/webrtc/signaling/src/sipcc/cpr/linux/cpr_linux_socket.c
+++ b/media/webrtc/signaling/src/sipcc/cpr/linux/cpr_linux_socket.c
@@ -735,26 +735,26 @@ cpr_inet_pton (int af, const char *src, 
 
 
 /**
  *  Utility function that sets up the socket address, using
  *  the name and the pid to guarantee uniqueness
  *
  *  @param[in] addr - socket fd to bind with the IPC address.
  *  @param[in] name - pointer to the name of socket to bind to.
- *
+ *  @param[in] pid  - process id (only used if name contains %d)
  *
  *  @pre  (name != NULL)
  */
 void cpr_set_sockun_addr (cpr_sockaddr_un_t *addr, const char *name, pid_t pid)
 {
     /* Bind to the local socket */
     memset(addr, 0, sizeof(cpr_sockaddr_un_t));
     addr->sun_family = AF_LOCAL;
-    snprintf((char *) addr->sun_path, sizeof(addr->sun_path), "%s_%d", name, pid);
+    snprintf(addr->sun_path, sizeof(addr->sun_path), name, pid);
 }
 
 /* int
  * inet_pton4(src, dst, pton)
  *	when last arg is 0: inet_aton(). with hexadecimal, octal and shorthand.
  *	when last arg is 1: inet_pton(). decimal dotted-quad only.
  * return:
  *	1 if `src' is a valid input, else 0.
--- a/media/webrtc/signaling/src/sipcc/cpr/win32/cpr_win_socket.c
+++ b/media/webrtc/signaling/src/sipcc/cpr/win32/cpr_win_socket.c
@@ -1079,10 +1079,10 @@ cpr_inet_pton (int af, const char *src, 
 }
 
 void cpr_set_sockun_addr(cpr_sockaddr_un_t *addr, const char *name, pid_t pid)
 {
   /* COPIED FROM OTHER PLATFORM AS A PLACE HOLDER */
   /* Bind to the local socket */
   memset(addr, 0, sizeof(cpr_sockaddr_un_t));
   addr->sun_family = AF_INET;
-  snprintf((char *) addr->sun_path, sizeof(addr->sun_path), "%s_%d", name, pid);
+  snprintf(addr->sun_path, sizeof(addr->sun_path), name, pid);
 }
--- a/mobile/android/base/GeckoApp.java
+++ b/mobile/android/base/GeckoApp.java
@@ -1715,17 +1715,18 @@ abstract public class GeckoApp
           SmsManager.getInstance().start();
         }
 
         mPromptService = new PromptService();
 
         mTextSelection = new TextSelection((TextSelectionHandle) findViewById(R.id.start_handle),
                                            (TextSelectionHandle) findViewById(R.id.middle_handle),
                                            (TextSelectionHandle) findViewById(R.id.end_handle),
-                                           GeckoAppShell.getEventDispatcher());
+                                           GeckoAppShell.getEventDispatcher(),
+                                           this);
 
         PrefsHelper.getPref("app.update.autodownload", new PrefsHelper.PrefHandlerBase() {
             @Override public void prefValue(String pref, String value) {
                 UpdateServiceHelper.registerForUpdates(GeckoApp.this, value);
             }
         });
 
         final GeckoApp self = this;
--- a/mobile/android/base/GeckoViewsFactory.java
+++ b/mobile/android/base/GeckoViewsFactory.java
@@ -63,16 +63,18 @@ public final class GeckoViewsFactory imp
             else if (TextUtils.equals(viewName, "BackButton"))
                 return new BackButton(context, attrs);
             else if (TextUtils.equals(viewName, "BrowserToolbarBackground"))
                 return new BrowserToolbarBackground(context, attrs);
             else if (TextUtils.equals(viewName, "BrowserToolbar$RightEdge"))
                 return new BrowserToolbar.RightEdge(context, attrs);
             else if (TextUtils.equals(viewName, "FormAssistPopup"))
                 return new FormAssistPopup(context, attrs);
+            else if (TextUtils.equals(viewName, "ForwardButton"))
+                return new ForwardButton(context, attrs);
             else if (TextUtils.equals(viewName, "GeckoApp$MainLayout"))
                 return new GeckoApp.MainLayout(context, attrs);
             else if (TextUtils.equals(viewName, "LinkTextView"))
                 return new LinkTextView(context, attrs);
             else if (TextUtils.equals(viewName, "FindInPageBar"))
                 return new FindInPageBar(context, attrs);
             else if (TextUtils.equals(viewName, "MenuButton"))
                 return new MenuButton(context, attrs);
--- a/mobile/android/base/TabsTray.java
+++ b/mobile/android/base/TabsTray.java
@@ -253,16 +253,17 @@ public class TabsTray extends LinearLayo
                 convertView = mInflater.inflate(R.layout.tabs_row, null);
 
                 row = new TabRow(convertView);
                 row.close.setOnClickListener(mOnCloseClickListener);
 
                 convertView.setTag(row);
             } else {
                 row = (TabRow) convertView.getTag();
+                row.close.setVisibility(View.VISIBLE);
             }
 
             Tab tab = mTabs.get(position);
             assignValues(row, tab);
 
             return convertView;
         }
     }
--- a/mobile/android/base/TextSelection.java
+++ b/mobile/android/base/TextSelection.java
@@ -7,16 +7,17 @@ package org.mozilla.gecko;
 import org.mozilla.gecko.gfx.Layer;
 import org.mozilla.gecko.gfx.Layer.RenderContext;
 import org.mozilla.gecko.gfx.LayerView;
 import org.mozilla.gecko.util.EventDispatcher;
 import org.mozilla.gecko.util.FloatUtils;
 import org.mozilla.gecko.util.GeckoEventListener;
 
 import org.json.JSONArray;
+import org.json.JSONException;
 import org.json.JSONObject;
 
 import android.util.Log;
 import android.view.View;
 
 class TextSelection extends Layer implements GeckoEventListener {
     private static final String LOGTAG = "GeckoTextSelection";
 
@@ -24,24 +25,28 @@ class TextSelection extends Layer implem
     private final TextSelectionHandle mMiddleHandle;
     private final TextSelectionHandle mEndHandle;
     private final EventDispatcher mEventDispatcher;
 
     private float mViewLeft;
     private float mViewTop;
     private float mViewZoom;
 
+    private GeckoApp mActivity;
+
     TextSelection(TextSelectionHandle startHandle,
                   TextSelectionHandle middleHandle,
                   TextSelectionHandle endHandle,
-                  EventDispatcher eventDispatcher) {
+                  EventDispatcher eventDispatcher,
+                  GeckoApp activity) {
         mStartHandle = startHandle;
         mMiddleHandle = middleHandle;
         mEndHandle = endHandle;
         mEventDispatcher = eventDispatcher;
+        mActivity = activity;
 
         // Only register listeners if we have valid start/middle/end handles
         if (mStartHandle == null || mMiddleHandle == null || mEndHandle == null) {
             Log.e(LOGTAG, "Failed to initialize text selection because at least one handle is null");
         } else {
             registerEventListener("TextSelection:ShowHandles");
             registerEventListener("TextSelection:HideHandles");
             registerEventListener("TextSelection:PositionHandles");
@@ -59,95 +64,80 @@ class TextSelection extends Layer implem
             return mStartHandle;
         } else if (name.equals("MIDDLE")) {
             return mMiddleHandle;
         } else {
             return mEndHandle;
         }
     }
 
-    public void handleMessage(String event, JSONObject message) {
-        try {
-            if (event.equals("TextSelection:ShowHandles")) {
-                final JSONArray handles = message.getJSONArray("handles");
-                GeckoApp.mAppContext.mMainHandler.post(new Runnable() {
-                    public void run() {
-                        try {
-                            for (int i=0; i < handles.length(); i++) {
-                                String handle = handles.getString(i);
-                                getHandle(handle).setVisibility(View.VISIBLE);
-                            }
+    public void handleMessage(final String event, final JSONObject message) {
+        mActivity.runOnUiThread(new Runnable() {
+            public void run() {
+                try {
+                    if (event.equals("TextSelection:ShowHandles")) {
+                        final JSONArray handles = message.getJSONArray("handles");
+                        for (int i=0; i < handles.length(); i++) {
+                            String handle = handles.getString(i);
+                            getHandle(handle).setVisibility(View.VISIBLE);
+                        }
 
-                            mViewLeft = 0.0f;
-                            mViewTop = 0.0f;
-                            mViewZoom = 0.0f;
-                            LayerView layerView = GeckoApp.mAppContext.getLayerView();
-                            if (layerView != null) {
-                                layerView.addLayer(TextSelection.this);
-                            }
-                        } catch(Exception e) {}
+                        mViewLeft = 0.0f;
+                        mViewTop = 0.0f;
+                        mViewZoom = 0.0f;
+                        LayerView layerView = mActivity.getLayerView();
+                        if (layerView != null) {
+                            layerView.addLayer(TextSelection.this);
+                        }
+                    } else if (event.equals("TextSelection:HideHandles")) {
+                        final JSONArray handles = message.getJSONArray("handles");
+                        LayerView layerView = mActivity.getLayerView();
+                        if (layerView != null) {
+                            layerView.removeLayer(TextSelection.this);
+                        }
+
+                        for (int i=0; i < handles.length(); i++) {
+                            String handle = handles.getString(i);
+                            getHandle(handle).setVisibility(View.GONE);
+                        }
+                    } else if (event.equals("TextSelection:PositionHandles")) {
+                        final boolean rtl = message.getBoolean("rtl");
+                        final JSONArray positions = message.getJSONArray("positions");
+                        for (int i=0; i < positions.length(); i++) {
+                            JSONObject position = positions.getJSONObject(i);
+                            int left = position.getInt("left");
+                            int top = position.getInt("top");
+
+                            TextSelectionHandle handle = getHandle(position.getString("handle"));
+                            handle.setVisibility(position.getBoolean("hidden") ? View.GONE : View.VISIBLE);
+                            handle.positionFromGecko(left, top, rtl);
+                        }
                     }
-                });
-            } else if (event.equals("TextSelection:HideHandles")) {
-                final JSONArray handles = message.getJSONArray("handles");
-                GeckoApp.mAppContext.mMainHandler.post(new Runnable() {
-                    public void run() {
-                        try {
-                            LayerView layerView = GeckoApp.mAppContext.getLayerView();
-                            if (layerView != null) {
-                                layerView.removeLayer(TextSelection.this);
-                            }
-
-                            for (int i=0; i < handles.length(); i++) {
-                                String handle = handles.getString(i);
-                                getHandle(handle).setVisibility(View.GONE);
-                            }
-
-                        } catch(Exception e) {}
-                    }
-                });
-            } else if (event.equals("TextSelection:PositionHandles")) {
-                final boolean rtl = message.getBoolean("rtl");
-                final JSONArray positions = message.getJSONArray("positions");
-                GeckoApp.mAppContext.mMainHandler.post(new Runnable() {
-                    public void run() {
-                        try {
-                            for (int i=0; i < positions.length(); i++) {
-                                JSONObject position = positions.getJSONObject(i);
-                                int left = position.getInt("left");
-                                int top = position.getInt("top");
-
-                                TextSelectionHandle handle = getHandle(position.getString("handle"));
-                                handle.setVisibility(position.getBoolean("hidden") ? View.GONE : View.VISIBLE);
-                                handle.positionFromGecko(left, top, rtl);
-                            }
-                        } catch (Exception e) { }
-                    }
-                });
+                } catch (JSONException e) {
+                    Log.e(LOGTAG, "JSON exception", e);
+                }
             }
-        } catch (Exception e) {
-            Log.e(LOGTAG, "Exception handling message \"" + event + "\":", e);
-        }
+        });
     }
 
     @Override
     public void draw(final RenderContext context) {
         // cache the relevant values from the context and bail out if they are the same. we do this
         // because this draw function gets called a lot (once per compositor frame) and we want to
         // avoid doing a lot of extra work in cases where it's not needed.
         if (FloatUtils.fuzzyEquals(mViewLeft, context.viewport.left)
                 && FloatUtils.fuzzyEquals(mViewTop, context.viewport.top)
                 && FloatUtils.fuzzyEquals(mViewZoom, context.zoomFactor)) {
             return;
         }
         mViewLeft = context.viewport.left;
         mViewTop = context.viewport.top;
         mViewZoom = context.zoomFactor;
 
-        GeckoApp.mAppContext.mMainHandler.post(new Runnable() {
+        mActivity.runOnUiThread(new Runnable() {
             public void run() {
                 mStartHandle.repositionWithViewport(context.viewport.left, context.viewport.top, context.zoomFactor);
                 mMiddleHandle.repositionWithViewport(context.viewport.left, context.viewport.top, context.zoomFactor);
                 mEndHandle.repositionWithViewport(context.viewport.left, context.viewport.top, context.zoomFactor);
             }
         });
     }
 
--- a/mobile/android/base/TextSelectionHandle.java
+++ b/mobile/android/base/TextSelectionHandle.java
@@ -7,16 +7,17 @@ package org.mozilla.gecko;
 import org.mozilla.gecko.gfx.ImmutableViewportMetrics;
 import org.mozilla.gecko.gfx.LayerView;
 
 import org.json.JSONObject;
 
 import android.content.Context;
 import android.content.res.TypedArray;
 import android.graphics.PointF;
+import android.graphics.Rect;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.view.MotionEvent;
 import android.view.View;
 import android.widget.ImageView;
 import android.widget.RelativeLayout;
 
 class TextSelectionHandle extends ImageView implements View.OnTouchListener {
@@ -24,31 +25,36 @@ class TextSelectionHandle extends ImageV
 
     private enum HandleType { START, MIDDLE, END }; 
 
     private final HandleType mHandleType;
     private final int mWidth;
     private final int mHeight;
     private final int mShadow;
 
-    private int mLeft;
-    private int mTop;
+    private float mLeft;
+    private float mTop;
     private boolean mIsRTL; 
     private PointF mGeckoPoint;
-    private int mTouchStartX;
-    private int mTouchStartY;
+    private float mTouchStartX;
+    private float mTouchStartY;
+    private int mLayerViewX;
+    private int mLayerViewY;
 
     private RelativeLayout.LayoutParams mLayoutParams;
 
     private static final int IMAGE_LEVEL_LTR = 0;
     private static final int IMAGE_LEVEL_RTL = 1;
 
+    private GeckoApp mActivity;
+
     TextSelectionHandle(Context context, AttributeSet attrs) {
         super(context, attrs);
         setOnTouchListener(this);
+        mActivity = (GeckoApp) context;
 
         TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.TextSelectionHandle);
         int handleType = a.getInt(R.styleable.TextSelectionHandle_handleType, 0x01);
 
         if (handleType == 0x01)
             mHandleType = HandleType.START;
         else if (handleType == 0x02)
             mHandleType = HandleType.MIDDLE;
@@ -61,18 +67,23 @@ class TextSelectionHandle extends ImageV
         mWidth = getResources().getDimensionPixelSize(R.dimen.text_selection_handle_width);
         mHeight = getResources().getDimensionPixelSize(R.dimen.text_selection_handle_height);
         mShadow = getResources().getDimensionPixelSize(R.dimen.text_selection_handle_shadow);
     }
 
     public boolean onTouch(View v, MotionEvent event) {
         switch (event.getActionMasked()) {
             case MotionEvent.ACTION_DOWN: {
-                mTouchStartX = Math.round(event.getX());
-                mTouchStartY = Math.round(event.getY());
+                mTouchStartX = event.getX();
+                mTouchStartY = event.getY();
+
+                int[] rect = new int[2];
+                mActivity.getLayerView().getLocationOnScreen(rect);
+                mLayerViewX = rect[0];
+                mLayerViewY = rect[1];
                 break;
             }
             case MotionEvent.ACTION_UP: {
                 mTouchStartX = 0;
                 mTouchStartY = 0;
 
                 // Reposition handles to line up with ends of selection
                 JSONObject args = new JSONObject();
@@ -80,94 +91,104 @@ class TextSelectionHandle extends ImageV
                     args.put("handleType", mHandleType.toString());
                 } catch (Exception e) {
                     Log.e(LOGTAG, "Error building JSON arguments for TextSelection:Position");
                 }
                 GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("TextSelection:Position", args.toString()));
                 break;
             }
             case MotionEvent.ACTION_MOVE: {
-                move(Math.round(event.getX()), Math.round(event.getY()));
+                move(event.getRawX(), event.getRawY());
                 break;
             }
         }
         return true;
     }
 
-    private void move(int newX, int newY) {
-        mLeft = mLeft + newX - mTouchStartX;
-        mTop = mTop + newY - mTouchStartY;
+    private void move(float newX, float newY) {
+        // newX and newY are absolute coordinates, so we need to adjust them to
+        // account for other views on the screen (such as the URL bar). We also
+        // need to include the offset amount of the touch location relative to
+        // the top left of the handle (mTouchStartX and mTouchStartY).
+        mLeft = newX - mLayerViewX - mTouchStartX;
+        mTop = newY - mLayerViewY - mTouchStartY;
 
-        LayerView layerView = GeckoApp.mAppContext.getLayerView();
+        LayerView layerView = mActivity.getLayerView();
         if (layerView == null) {
             Log.e(LOGTAG, "Can't move selection because layerView is null");
             return;
         }
         // Send x coordinate on the right side of the start handle, left side of the end handle.
-        float left = (float) mLeft + adjustLeftForHandle();
+        float left = mLeft + adjustLeftForHandle();
 
-        PointF geckoPoint = new PointF(left, (float) mTop);
+        PointF geckoPoint = new PointF(left, mTop);
         geckoPoint = layerView.convertViewPointToLayerPoint(geckoPoint);
 
         JSONObject args = new JSONObject();
         try {
             args.put("handleType", mHandleType.toString());
-            args.put("x", Math.round(geckoPoint.x));
-            args.put("y", Math.round(geckoPoint.y));
+            args.put("x", (int) geckoPoint.x);
+            args.put("y", (int) geckoPoint.y);
         } catch (Exception e) {
             Log.e(LOGTAG, "Error building JSON arguments for TextSelection:Move");
         }
         GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("TextSelection:Move", args.toString()));
 
-        setLayoutPosition();
+        // If we're positioning a cursor, don't move the handle here. Gecko
+        // will tell us the position of the caret, so we set the handle
+        // position then. This allows us to lock the handle to wherever the
+        // caret appears.
+        if (!mHandleType.equals(HandleType.MIDDLE)) {
+            setLayoutPosition();
+        }
     }
 
     void positionFromGecko(int left, int top, boolean rtl) {
-        LayerView layerView = GeckoApp.mAppContext.getLayerView();
+        LayerView layerView = mActivity.getLayerView();
         if (layerView == null) {
             Log.e(LOGTAG, "Can't position handle because layerView is null");
             return;
         }
 
-        mGeckoPoint = new PointF((float) left, (float) top);
+        mGeckoPoint = new PointF(left, top);
         if (mIsRTL != rtl) {
             mIsRTL = rtl;
             setImageLevel(mIsRTL ? IMAGE_LEVEL_RTL : IMAGE_LEVEL_LTR);
         }
 
         ImmutableViewportMetrics metrics = layerView.getViewportMetrics();
         repositionWithViewport(metrics.viewportRectLeft, metrics.viewportRectTop, metrics.zoomFactor);
     }
 
     void repositionWithViewport(float x, float y, float zoom) {
         PointF viewPoint = new PointF((mGeckoPoint.x * zoom) - x,
                                       (mGeckoPoint.y * zoom) - y);
 
-        mLeft = Math.round(viewPoint.x) - (int) adjustLeftForHandle();
-        mTop = Math.round(viewPoint.y);
+        mLeft = viewPoint.x - adjustLeftForHandle();
+        mTop = viewPoint.y;
 
         setLayoutPosition();
     }
 
     private float adjustLeftForHandle() {
         if (mHandleType.equals(HandleType.START))
             return mIsRTL ? mShadow : mWidth - mShadow;
         else if (mHandleType.equals(HandleType.MIDDLE))
-            return (float) ((mWidth - mShadow) / 2);
+            return (mWidth - mShadow) / 2;
         else
             return mIsRTL ? mWidth - mShadow : mShadow;
     }
 
     private void setLayoutPosition() {
         if (mLayoutParams == null) {
             mLayoutParams = (RelativeLayout.LayoutParams) getLayoutParams();
             // Set negative right/bottom margins so that the handles can be dragged outside of
             // the content area (if they are dragged to the left/top, the dyanmic margins set
             // below will take care of that).
             mLayoutParams.rightMargin = 0 - mWidth;
             mLayoutParams.bottomMargin = 0 - mHeight;
         }
 
-        mLayoutParams.leftMargin = mLeft;
-        mLayoutParams.topMargin = mTop;
+        mLayoutParams.leftMargin = (int) mLeft;
+        mLayoutParams.topMargin = (int) mTop;
         setLayoutParams(mLayoutParams);
     }
 }
--- a/mobile/android/base/resources/layout/remote_tabs.xml
+++ b/mobile/android/base/resources/layout/remote_tabs.xml
@@ -2,11 +2,12 @@
 <!-- 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/. -->
 
 <ExpandableListView xmlns:android="http://schemas.android.com/apk/res/android"
                     android:id="@+id/list"
                     style="@style/TabsList"
                     android:background="@android:color/transparent"
+                    android:cacheColorHint="@android:color/transparent"
                     android:childDivider="@drawable/tabs_tray_list_divider"
                     android:dividerHeight="2dip"
                     android:groupIndicator="@android:color/transparent"/>
--- a/mobile/android/chrome/content/browser.js
+++ b/mobile/android/chrome/content/browser.js
@@ -1699,35 +1699,37 @@ var SelectionHandler = {
         break;
       }
       case "Tab:Selected":
       case "Window:Resize": {
         if (this._activeType == this.TYPE_SELECTION) {
           // Knowing when the page is done drawing is hard, so let's just cancel
           // the selection when the window changes. We should fix this later.
           this.endSelection();
-        } else if (this._activeType == this.TYPE_CURSOR) {
-          //  Hide the cursor if the window changes
-          this.hideThumb();
         }
         break;
       }
       case "after-viewport-change": {
         if (this._activeType == this.TYPE_SELECTION) {
           // Update the cache after the viewport changes (e.g. panning, zooming).
           this.updateCacheForSelection();
         }
         break;
       }
       case "TextSelection:Move": {
         let data = JSON.parse(aData);
         if (this._activeType == this.TYPE_SELECTION)
           this.moveSelection(data.handleType == this.HANDLE_TYPE_START, data.x, data.y);
-        else if (this._activeType == this.TYPE_CURSOR)
+        else if (this._activeType == this.TYPE_CURSOR) {
+          // Send a click event to the text box, which positions the caret
           this._sendMouseEvents(data.x, data.y);
+
+          // Move the handle directly under the caret
+          this.positionHandles();
+        }
         break;
       }
       case "TextSelection:Position": {
         if (this._activeType == this.TYPE_SELECTION) {
           let data = JSON.parse(aData);
 
           // Reverse the handles if necessary.
           let selectionReversed = this.updateCacheForSelection(data.handleType == this.HANDLE_TYPE_START);
@@ -1931,19 +1933,59 @@ var SelectionHandler = {
         this._sendMouseEvents(this.cache.start.x, this.cache.start.y, false);
 
       // Selects text between the carat and the end handle using a fake shift+click
       this._sendMouseEvents( this.cache.end.x, this.cache.end.y, true);
     }
   },
 
   _sendMouseEvents: function sh_sendMouseEvents(aX, aY, useShift) {
-    // Send mouse event 1px too high to prevent selection from entering the line below where it should be
-    this._cwu.sendMouseEventToWindow("mousedown", aX, aY - 1, 0, 0, useShift ? Ci.nsIDOMNSEvent.SHIFT_MASK : 0, true);
-    this._cwu.sendMouseEventToWindow("mouseup", aX, aY - 1, 0, 0, useShift ? Ci.nsIDOMNSEvent.SHIFT_MASK : 0, true);
+    // If we're positioning a cursor in an input field, make sure the handle
+    // stays within the bounds of the field
+    if (this._activeType == this.TYPE_CURSOR) {
+      // Get rect of text inside element
+      let range = document.createRange();
+      range.selectNodeContents(this._target.QueryInterface(Ci.nsIDOMNSEditableElement).editor.rootElement);
+      let textBounds = range.getBoundingClientRect();
+
+      // Get rect of editor
+      let editorBounds = this._cwu.sendQueryContentEvent(this._cwu.QUERY_EDITOR_RECT, 0, 0, 0, 0);
+      let editorRect = new Rect(editorBounds.left, editorBounds.top, editorBounds.width, editorBounds.height);
+
+      // Use intersection of the text rect and the editor rect
+      let rect = new Rect(textBounds.left, textBounds.top, textBounds.width, textBounds.height);
+      rect.restrictTo(editorRect);
+
+      // Clamp vertically and scroll if handle is at bounds. The top and bottom
+      // must be restricted by an additional pixel since clicking on the top
+      // edge of an input field moves the cursor to the beginning of that
+      // field's text (and clicking the bottom moves the cursor to the end).
+      if (aY < rect.y + 1) {
+        aY = rect.y + 1;
+        this.getSelectionController().scrollLine(false);
+      } else if (aY > rect.y + rect.height - 1) {
+        aY = rect.y + rect.height - 1;
+        this.getSelectionController().scrollLine(true);
+      }
+
+      // Clamp horizontally and scroll if handle is at bounds
+      if (aX < rect.x) {
+        aX = rect.x;
+        this.getSelectionController().scrollCharacter(false);
+      } else if (aX > rect.x + rect.width) {
+        aX = rect.x + rect.width;
+        this.getSelectionController().scrollCharacter(true);
+      }
+    } else if (this._activeType == this.TYPE_SELECTION) {
+      // Send mouse event 1px too high to prevent selection from entering the line below where it should be
+      aY -= 1;
+    }
+
+    this._cwu.sendMouseEventToWindow("mousedown", aX, aY, 0, 0, useShift ? Ci.nsIDOMNSEvent.SHIFT_MASK : 0, true);
+    this._cwu.sendMouseEventToWindow("mouseup", aX, aY, 0, 0, useShift ? Ci.nsIDOMNSEvent.SHIFT_MASK : 0, true);
   },
 
   // aX/aY are in top-level window browser coordinates
   endSelection: function sh_endSelection(aX, aY) {
     if (this._activeType != this.TYPE_SELECTION)
       return "";
  
     this._activeType = this.TYPE_NONE;
--- a/modules/libpref/public/nsIPrefService.idl
+++ b/modules/libpref/public/nsIPrefService.idl
@@ -3,21 +3,20 @@
  * 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 "nsISupports.idl"
 #include "nsIPrefBranch.idl"
 
 %{C++
 struct PrefTuple;
-template<class E, class A> class nsTArray;
-struct nsTArrayInfallibleAllocator;
+#include "nsTArrayForwardDeclare.h"
 %}
 
-[ptr] native nsPreferencesArrayPtr(nsTArray<PrefTuple, nsTArrayInfallibleAllocator>);
+[ptr] native nsPreferencesArrayPtr(nsTArray<PrefTuple>);
 [ptr] native nsPreferencePtr(PrefTuple);
 [ptr] native nsPreferencePtrConst(const PrefTuple);
 
 interface nsIFile;
 
 /**
  * The nsIPrefService interface is the main entry point into the back end
  * preferences management library. The preference service is directly
--- a/netwerk/protocol/http/SpdySession2.cpp
+++ b/netwerk/protocol/http/SpdySession2.cpp
@@ -379,16 +379,26 @@ SpdySession2::NetworkRead(nsAHttpSegment
 void
 SpdySession2::SetWriteCallbacks()
 {
   if (mConnection && (GetWriteQueueSize() || mOutputQueueUsed))
       mConnection->ResumeSend();
 }
 
 void
+SpdySession2::RealignOutputQueue()
+{
+  mOutputQueueUsed -= mOutputQueueSent;
+  memmove(mOutputQueueBuffer.get(),
+          mOutputQueueBuffer.get() + mOutputQueueSent,
+          mOutputQueueUsed);
+  mOutputQueueSent = 0;
+}
+
+void
 SpdySession2::FlushOutputQueue()
 {
   if (!mSegmentReader || !mOutputQueueUsed)
     return;
   
   nsresult rv;
   uint32_t countRead;
   uint32_t avail = mOutputQueueUsed - mOutputQueueSent;
@@ -411,21 +421,17 @@ SpdySession2::FlushOutputQueue()
 
   mOutputQueueSent += countRead;
 
   // If the output queue is close to filling up and we have sent out a good
   // chunk of data from the beginning then realign it.
   
   if ((mOutputQueueSent >= kQueueMinimumCleanup) &&
       ((mOutputQueueSize - mOutputQueueUsed) < kQueueTailRoom)) {
-    mOutputQueueUsed -= mOutputQueueSent;
-    memmove(mOutputQueueBuffer.get(),
-            mOutputQueueBuffer.get() + mOutputQueueSent,
-            mOutputQueueUsed);
-    mOutputQueueSent = 0;
+    RealignOutputQueue();
   }
 }
 
 void
 SpdySession2::DontReuse()
 {
   mShouldGoAway = true;
   if (!mStreamTransactionHash.Count())
@@ -1913,37 +1919,43 @@ SpdySession2::OnReadSegment(const char *
   *countRead = count;
 
   FlushOutputQueue();
 
   return NS_OK;
 }
 
 nsresult
-SpdySession2::CommitToSegmentSize(uint32_t count)
+SpdySession2::CommitToSegmentSize(uint32_t count, bool forceCommitment)
 {
   if (mOutputQueueUsed)
     FlushOutputQueue();
 
   // would there be enough room to buffer this if needed?
   if ((mOutputQueueUsed + count) <= (mOutputQueueSize - kQueueReserved))
     return NS_OK;
-  
-  // if we are using part of our buffers already, try again later
-  if (mOutputQueueUsed)
+
+  // if we are using part of our buffers already, try again later unless
+  // forceCommitment is set.
+  if (mOutputQueueUsed && !forceCommitment)
     return NS_BASE_STREAM_WOULD_BLOCK;
 
-  // not enough room to buffer even with completely empty buffers.
-  // normal frames are max 4kb, so the only case this can really happen
-  // is a SYN_STREAM with technically unbounded headers. That is highly
-  // unlikely, but possible. Create enough room for it because the buffers
-  // will be necessary - SSL does not absorb writes of very large sizes
-  // in single sends.
+  if (mOutputQueueUsed) {
+    // normally we avoid the memmove of RealignOutputQueue, but we'll try
+    // it if forceCommitment is set before growing the buffer.
+    RealignOutputQueue();
 
-  EnsureBuffer(mOutputQueueBuffer, count + kQueueReserved, 0, mOutputQueueSize);
+    // is there enough room now?
+    if ((mOutputQueueUsed + count) <= (mOutputQueueSize - kQueueReserved))
+      return NS_OK;
+  }
+
+  // resize the buffers as needed
+  EnsureBuffer(mOutputQueueBuffer, mOutputQueueUsed + count + kQueueReserved,
+               mOutputQueueUsed, mOutputQueueSize);
 
   NS_ABORT_IF_FALSE((mOutputQueueUsed + count) <=
                     (mOutputQueueSize - kQueueReserved),
                     "buffer not as large as expected");
 
   return NS_OK;
 }
 
--- a/netwerk/protocol/http/SpdySession2.h
+++ b/netwerk/protocol/http/SpdySession2.h
@@ -107,23 +107,23 @@ public:
     SETTINGS_TYPE_MAX_CONCURRENT = 4, // streams
     SETTINGS_TYPE_CWND = 5, // packets
     SETTINGS_TYPE_DOWNLOAD_RETRANS_RATE = 6, // percentage
     SETTINGS_TYPE_INITIAL_WINDOW = 7  // bytes. Not used in v2.
   };
 
   // This should be big enough to hold all of your control packets,
   // but if it needs to grow for huge headers it can do so dynamically.
-  // About 1% of requests to SPDY google services seem to be > 1000
-  // with all less than 2000.
+  // About 1% of responses from SPDY google services seem to be > 1000
+  // with all less than 2000 when compression is enabled.
   const static uint32_t kDefaultBufferSize = 2048;
 
   // kDefaultQueueSize must be >= other queue size constants
-  const static uint32_t kDefaultQueueSize =  16384;
-  const static uint32_t kQueueMinimumCleanup = 8192;
+  const static uint32_t kDefaultQueueSize =  32768;
+  const static uint32_t kQueueMinimumCleanup = 24576;
   const static uint32_t kQueueTailRoom    =  4096;
   const static uint32_t kQueueReserved    =  1024;
 
   const static uint32_t kDefaultMaxConcurrent = 100;
   const static uint32_t kMaxStreamID = 0x7800000;
   
   // This is a sentinel for a deleted stream. It is not a valid
   // 31 bit stream ID.
@@ -148,17 +148,17 @@ public:
 
   // an overload of nsAHttpConnection
   void TransactionHasDataToWrite(nsAHttpTransaction *);
 
   // a similar version for SpdyStream2
   void TransactionHasDataToWrite(SpdyStream2 *);
 
   // an overload of nsAHttpSegementReader
-  virtual nsresult CommitToSegmentSize(uint32_t size);
+  virtual nsresult CommitToSegmentSize(uint32_t size, bool forceCommitment);
   
   void     PrintDiagnostics (nsCString &log);
 
 private:
 
   enum stateType {
     BUFFERING_FRAME_HEADER,
     BUFFERING_CONTROL_FRAME,
@@ -180,16 +180,17 @@ private:
   void        GeneratePing(uint32_t);
   void        GenerateRstStream(uint32_t, uint32_t);
   void        GenerateGoAway();
   void        CleanupStream(SpdyStream2 *, nsresult, rstReason);
   void        CloseStream(SpdyStream2 *, nsresult);
 
   void        SetWriteCallbacks();
   void        FlushOutputQueue();
+  void        RealignOutputQueue();
 
   bool        RoomForMoreConcurrent();
   void        ActivateStream(SpdyStream2 *);
   void        ProcessPending();
   nsresult    SetInputFrameDataStream(uint32_t);
   bool        VerifyStream(SpdyStream2 *, uint32_t);
   void        SetNeedsCleanup();
 
--- a/netwerk/protocol/http/SpdySession3.cpp
+++ b/netwerk/protocol/http/SpdySession3.cpp
@@ -380,16 +380,26 @@ SpdySession3::NetworkRead(nsAHttpSegment
 void
 SpdySession3::SetWriteCallbacks()
 {
   if (mConnection && (GetWriteQueueSize() || mOutputQueueUsed))
       mConnection->ResumeSend();
 }
 
 void
+SpdySession3::RealignOutputQueue()
+{
+  mOutputQueueUsed -= mOutputQueueSent;
+  memmove(mOutputQueueBuffer.get(),
+          mOutputQueueBuffer.get() + mOutputQueueSent,
+          mOutputQueueUsed);
+  mOutputQueueSent = 0;
+}
+
+void
 SpdySession3::FlushOutputQueue()
 {
   if (!mSegmentReader || !mOutputQueueUsed)
     return;
   
   nsresult rv;
   uint32_t countRead;
   uint32_t avail = mOutputQueueUsed - mOutputQueueSent;
@@ -412,21 +422,17 @@ SpdySession3::FlushOutputQueue()
 
   mOutputQueueSent += countRead;
 
   // If the output queue is close to filling up and we have sent out a good
   // chunk of data from the beginning then realign it.
   
   if ((mOutputQueueSent >= kQueueMinimumCleanup) &&
       ((mOutputQueueSize - mOutputQueueUsed) < kQueueTailRoom)) {
-    mOutputQueueUsed -= mOutputQueueSent;
-    memmove(mOutputQueueBuffer.get(),
-            mOutputQueueBuffer.get() + mOutputQueueSent,
-            mOutputQueueUsed);
-    mOutputQueueSent = 0;
+    RealignOutputQueue();
   }
 }
 
 void
 SpdySession3::DontReuse()
 {
   mShouldGoAway = true;
   if (!mStreamTransactionHash.Count())
@@ -1958,37 +1964,43 @@ SpdySession3::OnReadSegment(const char *
   *countRead = count;
 
   FlushOutputQueue();
 
   return NS_OK;
 }
 
 nsresult
-SpdySession3::CommitToSegmentSize(uint32_t count)
+SpdySession3::CommitToSegmentSize(uint32_t count, bool forceCommitment)
 {
   if (mOutputQueueUsed)
     FlushOutputQueue();
 
   // would there be enough room to buffer this if needed?
   if ((mOutputQueueUsed + count) <= (mOutputQueueSize - kQueueReserved))
     return NS_OK;
-  
-  // if we are using part of our buffers already, try again later
-  if (mOutputQueueUsed)
+
+  // if we are using part of our buffers already, try again later unless
+  // forceCommitment is set.
+  if (mOutputQueueUsed && !forceCommitment)
     return NS_BASE_STREAM_WOULD_BLOCK;
 
-  // not enough room to buffer even with completely empty buffers.
-  // normal frames are max 4kb, so the only case this can really happen
-  // is a SYN_STREAM with technically unbounded headers. That is highly
-  // unlikely, but possible. Create enough room for it because the buffers
-  // will be necessary - SSL does not absorb writes of very large sizes
-  // in single sends.
+  if (mOutputQueueUsed) {
+    // normally we avoid the memmove of RealignOutputQueue, but we'll try
+    // it if forceCommitment is set before growing the buffer.
+    RealignOutputQueue();
 
-  EnsureBuffer(mOutputQueueBuffer, count + kQueueReserved, 0, mOutputQueueSize);
+    // is there enough room now?
+    if ((mOutputQueueUsed + count) <= (mOutputQueueSize - kQueueReserved))
+      return NS_OK;
+  }
+
+  // resize the buffers as needed
+  EnsureBuffer(mOutputQueueBuffer, mOutputQueueUsed + count + kQueueReserved,
+               mOutputQueueUsed, mOutputQueueSize);
 
   NS_ABORT_IF_FALSE((mOutputQueueUsed + count) <=
                     (mOutputQueueSize - kQueueReserved),
                     "buffer not as large as expected");
 
   return NS_OK;
 }
 
--- a/netwerk/protocol/http/SpdySession3.h
+++ b/netwerk/protocol/http/SpdySession3.h
@@ -106,23 +106,23 @@ public:
     SETTINGS_TYPE_CWND = 5, // packets
     SETTINGS_TYPE_DOWNLOAD_RETRANS_RATE = 6, // percentage
     SETTINGS_TYPE_INITIAL_WINDOW = 7,  // bytes
     SETTINGS_CLIENT_CERTIFICATE_VECTOR_SIZE = 8
   };
 
   // This should be big enough to hold all of your control packets,
   // but if it needs to grow for huge headers it can do so dynamically.
-  // About 1% of requests to SPDY google services seem to be > 1000
-  // with all less than 2000.
+  // About 1% of responses from SPDY google services seem to be > 1000
+  // with all less than 2000 when compression is enabled.
   const static uint32_t kDefaultBufferSize = 2048;
 
   // kDefaultQueueSize must be >= other queue size constants
-  const static uint32_t kDefaultQueueSize =  16384;
-  const static uint32_t kQueueMinimumCleanup = 8192;
+  const static uint32_t kDefaultQueueSize =  32768;
+  const static uint32_t kQueueMinimumCleanup = 24576;
   const static uint32_t kQueueTailRoom    =  4096;
   const static uint32_t kQueueReserved    =  1024;
 
   const static uint32_t kDefaultMaxConcurrent = 100;
   const static uint32_t kMaxStreamID = 0x7800000;
 
   // This is a sentinel for a deleted stream. It is not a valid
   // 31 bit stream ID.
@@ -157,17 +157,17 @@ public:
 
   // an overload of nsAHttpConnection
   void TransactionHasDataToWrite(nsAHttpTransaction *);
 
   // a similar version for SpdyStream3
   void TransactionHasDataToWrite(SpdyStream3 *);
 
   // an overload of nsAHttpSegementReader
-  virtual nsresult CommitToSegmentSize(uint32_t size);
+  virtual nsresult CommitToSegmentSize(uint32_t size, bool forceCommitment);
   
   uint32_t GetServerInitialWindow() { return mServerInitialWindow; }
 
   void     PrintDiagnostics (nsCString &log);
 
 private:
 
   enum stateType {
@@ -189,16 +189,17 @@ private:
   void        GenerateRstStream(uint32_t, uint32_t);
   void        GenerateGoAway(uint32_t);
   void        CleanupStream(SpdyStream3 *, nsresult, rstReason);
   void        CloseStream(SpdyStream3 *, nsresult);
   void        GenerateSettings();
 
   void        SetWriteCallbacks();
   void        FlushOutputQueue();
+  void        RealignOutputQueue();
 
   bool        RoomForMoreConcurrent();
   void        ActivateStream(SpdyStream3 *);
   void        ProcessPending();
   nsresult    SetInputFrameDataStream(uint32_t);
   bool        VerifyStream(SpdyStream3 *, uint32_t);
   void        SetNeedsCleanup();
 
--- a/netwerk/protocol/http/SpdyStream2.cpp
+++ b/netwerk/protocol/http/SpdyStream2.cpp
@@ -123,45 +123,22 @@ SpdyStream2::ReadSegments(nsAHttpSegment
         ChangeState(SENDING_FIN_STREAM);
         mSession->TransactionHasDataToWrite(this);
         rv = NS_BASE_STREAM_WOULD_BLOCK;
       }
     }
 
     break;
 
-  case SENDING_SYN_STREAM:
-    // We were trying to send the SYN-STREAM but were blocked from trying
-    // to transmit it the first time(s).
-    mSegmentReader = reader;
-    rv = TransmitFrame(nullptr, nullptr);
-    mSegmentReader = nullptr;
-    *countRead = 0;
-    if (NS_SUCCEEDED(rv)) {
-      NS_ABORT_IF_FALSE(!mTxInlineFrameUsed,
-                        "Transmit Frame should be all or nothing");
-    
-      if (mSentFinOnData) {
-        ChangeState(UPSTREAM_COMPLETE);
-        rv = NS_OK;
-      }
-      else {
-        rv = NS_BASE_STREAM_WOULD_BLOCK;
-        ChangeState(GENERATING_REQUEST_BODY);
-        mSession->TransactionHasDataToWrite(this);
-      }
-    }
-    break;
-
   case SENDING_FIN_STREAM:
     // We were trying to send the FIN-STREAM but were blocked from
     // sending it out - try again.
     if (!mSentFinOnData) {
       mSegmentReader = reader;
-      rv = TransmitFrame(nullptr, nullptr);
+      rv = TransmitFrame(nullptr, nullptr, false);
       mSegmentReader = nullptr;
       NS_ABORT_IF_FALSE(NS_FAILED(rv) || !mTxInlineFrameUsed,
                         "Transmit Frame should be all or nothing");
       if (NS_SUCCEEDED(rv))
         ChangeState(UPSTREAM_COMPLETE);
     }
     else {
       rv = NS_OK;
@@ -498,17 +475,18 @@ SpdyStream2::UpdateTransportSendEvents(u
     mTransaction->OnTransportStatus(mSocketTransport,
                                     NS_NET_STATUS_WAITING_FOR,
                                     0);
   }
 }
 
 nsresult
 SpdyStream2::TransmitFrame(const char *buf,
-                          uint32_t *countUsed)
+                           uint32_t *countUsed,
+                           bool forceCommitment)
 {
   // If TransmitFrame returns SUCCESS than all the data is sent (or at least
   // buffered at the session level), if it returns WOULD_BLOCK then none of
   // the data is sent.
 
   // You can call this function with no data and no out parameter in order to
   // flush internal buffers that were previously blocked on writing. You can
   // of course feed new data to it as well.
@@ -537,20 +515,24 @@ SpdyStream2::TransmitFrame(const char *b
     memcpy (mTxInlineFrame + mTxInlineFrameUsed,
             buf, mTxStreamFrameSize);
     if (countUsed)
       *countUsed += mTxStreamFrameSize;
     mTxInlineFrameUsed += mTxStreamFrameSize;
     mTxStreamFrameSize = 0;
   }
 
-  rv = mSegmentReader->CommitToSegmentSize(mTxStreamFrameSize +
-                                           mTxInlineFrameUsed);
-  if (rv == NS_BASE_STREAM_WOULD_BLOCK)
+  rv =
+    mSegmentReader->CommitToSegmentSize(mTxStreamFrameSize + mTxInlineFrameUsed,
+                                        forceCommitment);
+
+  if (rv == NS_BASE_STREAM_WOULD_BLOCK) {
+    NS_ABORT_IF_FALSE(!forceCommitment, "forceCommitment with WOULD_BLOCK");
     mSession->TransactionHasDataToWrite(this);
+  }
   if (NS_FAILED(rv))     // this will include WOULD_BLOCK
     return rv;
 
   // This function calls mSegmentReader->OnReadSegment to report the actual SPDY
   // bytes through to the SpdySession2 and then the HttpConnection which calls
   // the socket write function. It will accept all of the inline and stream
   // data because of the above 'commitment' even if it has to buffer
   
@@ -805,38 +787,25 @@ SpdyStream2::OnReadSegment(const char *b
     rv = ParseHttpRequestHeaders(buf, count, countRead);
     if (NS_FAILED(rv))
       return rv;
     LOG3(("ParseHttpRequestHeaders %p used %d of %d. complete = %d",
           this, *countRead, count, mSynFrameComplete));
     if (mSynFrameComplete) {
       NS_ABORT_IF_FALSE(mTxInlineFrameUsed,
                         "OnReadSegment SynFrameComplete 0b");
-      rv = TransmitFrame(nullptr, nullptr);
-      NS_ABORT_IF_FALSE(NS_FAILED(rv) || !mTxInlineFrameUsed,
-                        "Transmit Frame should be all or nothing");
-
-      // normalize a blocked write into an ok one if we have consumed the data
-      // while parsing headers as some code will take WOULD_BLOCK to mean an
-      // error with nothing processed.
-      // (e.g. nsHttpTransaction::ReadRequestSegment())
-      if (rv == NS_BASE_STREAM_WOULD_BLOCK && *countRead)
-        rv = NS_OK;
+      rv = TransmitFrame(nullptr, nullptr, true);
+      if (rv == NS_BASE_STREAM_WOULD_BLOCK) {
+        // this can't happen
+        NS_ABORT_IF_FALSE(false,
+                          "Transmit Frame SYN_FRAME must at least buffer data");
+        rv = NS_ERROR_UNEXPECTED;
+      }
 
-      // mTxInlineFrameUsed > 0 means the current frame is in progress
-      // of sending.  mTxInlineFrameUsed is dropped to 0 after both the frame
-      // and its payload (if any) are completely sent out.  Here during
-      // GENERATING_SYN_STREAM state we are sending just the http headers.
-      // Only when the frame is completely sent out do we proceed to
-      // GENERATING_REQUEST_BODY state.
-
-      if (mTxInlineFrameUsed)
-        ChangeState(SENDING_SYN_STREAM);
-      else
-        ChangeState(GENERATING_REQUEST_BODY);
+      ChangeState(GENERATING_REQUEST_BODY);
       break;
     }
     NS_ABORT_IF_FALSE(*countRead == count,
                       "Header parsing not complete but unused data");
     break;
 
   case GENERATING_REQUEST_BODY:
     dataLength = NS_MIN(count, mChunkSize);
@@ -847,17 +816,17 @@ SpdyStream2::OnReadSegment(const char *b
       return NS_ERROR_UNEXPECTED;
     mRequestBodyLenRemaining -= dataLength;
     GenerateDataFrameHeader(dataLength, !mRequestBodyLenRemaining);
     ChangeState(SENDING_REQUEST_BODY);
     // NO BREAK
 
   case SENDING_REQUEST_BODY:
     NS_ABORT_IF_FALSE(mTxInlineFrameUsed, "OnReadSegment Send Data Header 0b");
-    rv = TransmitFrame(buf, countRead);
+    rv = TransmitFrame(buf, countRead, false);
     NS_ABORT_IF_FALSE(NS_FAILED(rv) || !mTxInlineFrameUsed,
                       "Transmit Frame should be all or nothing");
 
     LOG3(("TransmitFrame() rv=%x returning %d data bytes. "
           "Header is %d Body is %d.",
           rv, *countRead, mTxInlineFrameUsed, mTxStreamFrameSize));
 
     // normalize a partial write with a WOULD_BLOCK into just a partial write
@@ -866,20 +835,16 @@ SpdyStream2::OnReadSegment(const char *b
     if (rv == NS_BASE_STREAM_WOULD_BLOCK && *countRead)
       rv = NS_OK;
 
     // If that frame was all sent, look for another one
     if (!mTxInlineFrameUsed)
         ChangeState(GENERATING_REQUEST_BODY);
     break;
 
-  case SENDING_SYN_STREAM:
-    rv = NS_BASE_STREAM_WOULD_BLOCK;
-    break;
-
   case SENDING_FIN_STREAM:
     NS_ABORT_IF_FALSE(false,
                       "resuming partial fin stream out of OnReadSegment");
     break;
     
   default:
     NS_ABORT_IF_FALSE(false, "SpdyStream2::OnReadSegment non-write state");
     break;
--- a/netwerk/protocol/http/SpdyStream2.h
+++ b/netwerk/protocol/http/SpdyStream2.h
@@ -65,30 +65,29 @@ private:
   // a SpdyStream2 object is only destroyed by being removed from the
   // SpdySession2 mStreamTransactionHash - make the dtor private to
   // just the AutoPtr implementation needed for that hash.
   friend class nsAutoPtr<SpdyStream2>;
   ~SpdyStream2();
 
   enum stateType {
     GENERATING_SYN_STREAM,
-    SENDING_SYN_STREAM,
     GENERATING_REQUEST_BODY,
     SENDING_REQUEST_BODY,
     SENDING_FIN_STREAM,
     UPSTREAM_COMPLETE
   };
 
   static PLDHashOperator hdrHashEnumerate(const nsACString &,
                                           nsAutoPtr<nsCString> &,
                                           void *);
 
   void     ChangeState(enum stateType);
   nsresult ParseHttpRequestHeaders(const char *, uint32_t, uint32_t *);
-  nsresult TransmitFrame(const char *, uint32_t *);
+  nsresult TransmitFrame(const char *, uint32_t *, bool forceCommitment);
   void     GenerateDataFrameHeader(uint32_t, bool);
 
   void     CompressToFrame(const nsACString &);
   void     CompressToFrame(const nsACString *);
   void     CompressToFrame(const char *, uint32_t);
   void     CompressToFrame(uint16_t);
   void     CompressFlushFrame();
   void     ExecuteCompress(uint32_t);
--- a/netwerk/protocol/http/SpdyStream3.cpp
+++ b/netwerk/protocol/http/SpdyStream3.cpp
@@ -134,45 +134,22 @@ SpdyStream3::ReadSegments(nsAHttpSegment
         GenerateDataFrameHeader(0, true);
         ChangeState(SENDING_FIN_STREAM);
         mSession->TransactionHasDataToWrite(this);
         rv = NS_BASE_STREAM_WOULD_BLOCK;
       }
     }
     break;
 
-  case SENDING_SYN_STREAM:
-    // We were trying to send the SYN-STREAM but were blocked from trying
-    // to transmit it the first time(s).
-    mSegmentReader = reader;
-    rv = TransmitFrame(nullptr, nullptr);
-    mSegmentReader = nullptr;
-    *countRead = 0;
-    if (NS_SUCCEEDED(rv)) {
-      NS_ABORT_IF_FALSE(!mTxInlineFrameUsed,
-                        "Transmit Frame should be all or nothing");
-    
-      if (mSentFinOnData) {
-        ChangeState(UPSTREAM_COMPLETE);
-        rv = NS_OK;
-      }
-      else {
-        rv = NS_BASE_STREAM_WOULD_BLOCK;
-        ChangeState(GENERATING_REQUEST_BODY);
-        mSession->TransactionHasDataToWrite(this);
-      }
-    }
-    break;
-
   case SENDING_FIN_STREAM:
     // We were trying to send the FIN-STREAM but were blocked from
     // sending it out - try again.
     if (!mSentFinOnData) {
       mSegmentReader = reader;
-      rv = TransmitFrame(nullptr, nullptr);
+      rv = TransmitFrame(nullptr, nullptr, false);
       mSegmentReader = nullptr;
       NS_ABORT_IF_FALSE(NS_FAILED(rv) || !mTxInlineFrameUsed,
                         "Transmit Frame should be all or nothing");
       if (NS_SUCCEEDED(rv))
         ChangeState(UPSTREAM_COMPLETE);
     }
     else {
       rv = NS_OK;
@@ -518,17 +495,18 @@ SpdyStream3::UpdateTransportSendEvents(u
     mTransaction->OnTransportStatus(mSocketTransport,
                                     NS_NET_STATUS_WAITING_FOR,
                                     0);
   }
 }
 
 nsresult
 SpdyStream3::TransmitFrame(const char *buf,
-                          uint32_t *countUsed)
+                           uint32_t *countUsed,
+                           bool forceCommitment)
 {
   // If TransmitFrame returns SUCCESS than all the data is sent (or at least
   // buffered at the session level), if it returns WOULD_BLOCK then none of
   // the data is sent.
 
   // You can call this function with no data and no out parameter in order to
   // flush internal buffers that were previously blocked on writing. You can
   // of course feed new data to it as well.
@@ -557,20 +535,24 @@ SpdyStream3::TransmitFrame(const char *b
     memcpy (mTxInlineFrame + mTxInlineFrameUsed,
             buf, mTxStreamFrameSize);
     if (countUsed)
       *countUsed += mTxStreamFrameSize;
     mTxInlineFrameUsed += mTxStreamFrameSize;
     mTxStreamFrameSize = 0;
   }
 
-  rv = mSegmentReader->CommitToSegmentSize(mTxStreamFrameSize +
-                                           mTxInlineFrameUsed);
-  if (rv == NS_BASE_STREAM_WOULD_BLOCK)
+  rv =
+    mSegmentReader->CommitToSegmentSize(mTxStreamFrameSize + mTxInlineFrameUsed,
+                                        forceCommitment);
+
+  if (rv == NS_BASE_STREAM_WOULD_BLOCK) {
+    NS_ABORT_IF_FALSE(!forceCommitment, "forceCommitment with WOULD_BLOCK");
     mSession->TransactionHasDataToWrite(this);
+  }
   if (NS_FAILED(rv))     // this will include WOULD_BLOCK
     return rv;
 
   // This function calls mSegmentReader->OnReadSegment to report the actual SPDY
   // bytes through to the SpdySession3 and then the HttpConnection which calls
   // the socket write function. It will accept all of the inline and stream
   // data because of the above 'commitment' even if it has to buffer
   
@@ -1222,38 +1204,25 @@ SpdyStream3::OnReadSegment(const char *b
     rv = ParseHttpRequestHeaders(buf, count, countRead);
     if (NS_FAILED(rv))
       return rv;
     LOG3(("ParseHttpRequestHeaders %p used %d of %d. complete = %d",
           this, *countRead, count, mSynFrameComplete));
     if (mSynFrameComplete) {
       NS_ABORT_IF_FALSE(mTxInlineFrameUsed,
                         "OnReadSegment SynFrameComplete 0b");
-      rv = TransmitFrame(nullptr, nullptr);
-      NS_ABORT_IF_FALSE(NS_FAILED(rv) || !mTxInlineFrameUsed,
-                        "Transmit Frame should be all or nothing");
-
-      // normalize a blocked write into an ok one if we have consumed the data
-      // while parsing headers as some code will take WOULD_BLOCK to mean an
-      // error with nothing processed.
-      // (e.g. nsHttpTransaction::ReadRequestSegment())
-      if (rv == NS_BASE_STREAM_WOULD_BLOCK && *countRead)
-        rv = NS_OK;
+      rv = TransmitFrame(nullptr, nullptr, true);
+      if (rv == NS_BASE_STREAM_WOULD_BLOCK) {
+        // this can't happen
+        NS_ABORT_IF_FALSE(false,
+                          "Transmit Frame SYN_FRAME must at least buffer data");
+        rv = NS_ERROR_UNEXPECTED;
+      }
 
-      // mTxInlineFrameUsed > 0 means the current frame is in progress
-      // of sending.  mTxInlineFrameUsed is dropped to 0 after both the frame
-      // and its payload (if any) are completely sent out.  Here during
-      // GENERATING_SYN_STREAM state we are sending just the http headers.
-      // Only when the frame is completely sent out do we proceed to
-      // GENERATING_REQUEST_BODY state.
-
-      if (mTxInlineFrameUsed)
-        ChangeState(SENDING_SYN_STREAM);
-      else
-        ChangeState(GENERATING_REQUEST_BODY);
+      ChangeState(GENERATING_REQUEST_BODY);
       break;
     }
     NS_ABORT_IF_FALSE(*countRead == count,
                       "Header parsing not complete but unused data");
     break;
 
   case GENERATING_REQUEST_BODY:
     if (mRemoteWindow <= 0) {
@@ -1281,17 +1250,17 @@ SpdyStream3::OnReadSegment(const char *b
       return NS_ERROR_UNEXPECTED;
     mRequestBodyLenRemaining -= dataLength;
     GenerateDataFrameHeader(dataLength, !mRequestBodyLenRemaining);
     ChangeState(SENDING_REQUEST_BODY);
     // NO BREAK
 
   case SENDING_REQUEST_BODY:
     NS_ABORT_IF_FALSE(mTxInlineFrameUsed, "OnReadSegment Send Data Header 0b");
-    rv = TransmitFrame(buf, countRead);
+    rv = TransmitFrame(buf, countRead, false);
     NS_ABORT_IF_FALSE(NS_FAILED(rv) || !mTxInlineFrameUsed,
                       "Transmit Frame should be all or nothing");
 
     LOG3(("TransmitFrame() rv=%x returning %d data bytes. "
           "Header is %d Body is %d.",
           rv, *countRead, mTxInlineFrameUsed, mTxStreamFrameSize));
 
     // normalize a partial write with a WOULD_BLOCK into just a partial write
@@ -1300,20 +1269,16 @@ SpdyStream3::OnReadSegment(const char *b
     if (rv == NS_BASE_STREAM_WOULD_BLOCK && *countRead)
       rv = NS_OK;
 
     // If that frame was all sent, look for another one
     if (!mTxInlineFrameUsed)
         ChangeState(GENERATING_REQUEST_BODY);
     break;
 
-  case SENDING_SYN_STREAM:
-    rv = NS_BASE_STREAM_WOULD_BLOCK;
-    break;
-
   case SENDING_FIN_STREAM:
     NS_ABORT_IF_FALSE(false,
                       "resuming partial fin stream out of OnReadSegment");
     break;
     
   default:
     NS_ABORT_IF_FALSE(false, "SpdyStream3::OnReadSegment non-write state");
     break;
--- a/netwerk/protocol/http/SpdyStream3.h
+++ b/netwerk/protocol/http/SpdyStream3.h
@@ -86,30 +86,29 @@ private:
   // a SpdyStream3 object is only destroyed by being removed from the
   // SpdySession3 mStreamTransactionHash - make the dtor private to
   // just the AutoPtr implementation needed for that hash.
   friend class nsAutoPtr<SpdyStream3>;
   ~SpdyStream3();
 
   enum stateType {
     GENERATING_SYN_STREAM,
-    SENDING_SYN_STREAM,
     GENERATING_REQUEST_BODY,
     SENDING_REQUEST_BODY,
     SENDING_FIN_STREAM,
     UPSTREAM_COMPLETE
   };
 
   static PLDHashOperator hdrHashEnumerate(const nsACString &,
                                           nsAutoPtr<nsCString> &,
                                           void *);
 
   void     ChangeState(enum stateType);
   nsresult ParseHttpRequestHeaders(const char *, uint32_t, uint32_t *);
-  nsresult TransmitFrame(const char *, uint32_t *);
+  nsresult TransmitFrame(const char *, uint32_t *, bool forceCommitment);
   void     GenerateDataFrameHeader(uint32_t, bool);
 
   void     CompressToFrame(const nsACString &);
   void     CompressToFrame(const nsACString *);
   void     CompressToFrame(const char *, uint32_t);
   void     CompressToFrame(uint32_t);
   void     CompressFlushFrame();
   void     ExecuteCompress(uint32_t);
--- a/netwerk/protocol/http/nsAHttpTransaction.h
+++ b/netwerk/protocol/http/nsAHttpTransaction.h
@@ -167,22 +167,23 @@ public:
     virtual nsresult OnReadSegment(const char *segment,
                                    uint32_t count,
                                    uint32_t *countRead) = 0;
 
     // Ask the segment reader to commit to accepting size bytes of
     // data from subsequent OnReadSegment() calls or throw hard
     // (i.e. not wouldblock) exceptions. Implementations
     // can return NS_ERROR_FAILURE if they never make commitments of that size
-    // (the default), NS_BASE_STREAM_WOULD_BLOCK if they cannot make
-    // the commitment now but might in the future, or NS_OK
-    // if they make the commitment.
+    // (the default), NS_OK if they make the commitment, or
+    // NS_BASE_STREAM_WOULD_BLOCK if they cannot make the
+    // commitment now but might in the future and forceCommitment is not true .
+    // (forceCommitment requires a hard failure or OK at this moment.)
     //
     // Spdy uses this to make sure frames are atomic.
-    virtual nsresult CommitToSegmentSize(uint32_t size)
+    virtual nsresult CommitToSegmentSize(uint32_t size, bool forceCommitment)
     {
         return NS_ERROR_FAILURE;
     }
 };
 
 #define NS_DECL_NSAHTTPSEGMENTREADER \
     nsresult OnReadSegment(const char *, uint32_t, uint32_t *);
 
--- a/storage/src/Variant.h
+++ b/storage/src/Variant.h
@@ -54,49 +54,52 @@ struct variant_traits
   static inline uint16_t type() { return nsIDataType::VTYPE_EMPTY; }
 };
 
 template <typename DataType>
 struct variant_storage_traits
 {
   typedef DataType ConstructorType;
   typedef DataType StorageType;
-  static inline StorageType storage_conversion(ConstructorType aData) { return aData; }
+  static inline void storage_conversion(const ConstructorType aData, StorageType* _storage)
+  {
+    *_storage = aData;
+  }
 };
 
 #define NO_CONVERSION return NS_ERROR_CANNOT_CONVERT_DATA;
 
 template <typename DataType>
 struct variant_integer_traits
 {
   typedef typename variant_storage_traits<DataType>::StorageType StorageType;
-  static inline nsresult asInt32(StorageType, int32_t *) { NO_CONVERSION }
-  static inline nsresult asInt64(StorageType, int64_t *) { NO_CONVERSION }
+  static inline nsresult asInt32(const StorageType &, int32_t *) { NO_CONVERSION }
+  static inline nsresult asInt64(const StorageType &, int64_t *) { NO_CONVERSION }
 };
 
 template <typename DataType>
 struct variant_float_traits
 {
   typedef typename variant_storage_traits<DataType>::StorageType StorageType;
-  static inline nsresult asDouble(StorageType, double *) { NO_CONVERSION }
+  static inline nsresult asDouble(const StorageType &, double *) { NO_CONVERSION }
 };
 
 template <typename DataType>
 struct variant_text_traits
 {
   typedef typename variant_storage_traits<DataType>::StorageType StorageType;
-  static inline nsresult asUTF8String(StorageType, nsACString &) { NO_CONVERSION }
-  static inline nsresult asString(StorageType, nsAString &) { NO_CONVERSION }
+  static inline nsresult asUTF8String(const StorageType &, nsACString &) { NO_CONVERSION }
+  static inline nsresult asString(const StorageType &, nsAString &) { NO_CONVERSION }
 };
 
 template <typename DataType>
 struct variant_blob_traits
 {
   typedef typename variant_storage_traits<DataType>::StorageType StorageType;
-  static inline nsresult asArray(StorageType, uint16_t *, uint32_t *, void **)
+  static inline nsresult asArray(const StorageType &, uint16_t *, uint32_t *, void **)
   { NO_CONVERSION }
 };
 
 #undef NO_CONVERSION
 
 /**
  * INTEGER types
  */
@@ -166,19 +169,19 @@ struct variant_traits<nsString>
 {
   static inline uint16_t type() { return nsIDataType::VTYPE_ASTRING; }
 };
 template < >
 struct variant_storage_traits<nsString>
 {
   typedef const nsAString & ConstructorType;
   typedef nsString StorageType;
-  static inline StorageType storage_conversion(ConstructorType aText)
+  static inline void storage_conversion(ConstructorType aText, StorageType* _outData)
   {
-    return StorageType(aText);
+    *_outData = aText;
   }
 };
 template < >
 struct variant_text_traits<nsString>
 {
   static inline nsresult asUTF8String(const nsString &aValue,
                                       nsACString &_result)
   {
@@ -198,19 +201,19 @@ struct variant_traits<nsCString>
 {
   static inline uint16_t type() { return nsIDataType::VTYPE_UTF8STRING; }
 };
 template < >
 struct variant_storage_traits<nsCString>
 {
   typedef const nsACString & ConstructorType;
   typedef nsCString StorageType;
-  static inline StorageType storage_conversion(ConstructorType aText)
+  static inline void storage_conversion(ConstructorType aText, StorageType* _outData)
   {
-    return StorageType(aText);
+    *_outData = aText;
   }
 };
 template < >
 struct variant_text_traits<nsCString>
 {
   static inline nsresult asUTF8String(const nsCString &aValue,
                                       nsACString &_result)
   {
@@ -234,22 +237,22 @@ struct variant_traits<uint8_t[]>
 {
   static inline uint16_t type() { return nsIDataType::VTYPE_ARRAY; }
 };
 template < >
 struct variant_storage_traits<uint8_t[]>
 {
   typedef std::pair<const void *, int> ConstructorType;
   typedef FallibleTArray<uint8_t> StorageType;
-  static inline StorageType storage_conversion(ConstructorType aBlob)
+  static inline void storage_conversion(ConstructorType aBlob, StorageType* _outData)
   {
-    StorageType data(aBlob.second);
-    (void)data.AppendElements(static_cast<const uint8_t *>(aBlob.first),
-                              aBlob.second);
-    return data;
+    _outData->Clear();
+    _outData->SetCapacity(aBlob.second);
+    (void)_outData->AppendElements(static_cast<const uint8_t *>(aBlob.first),
+                                   aBlob.second);
   }
 };
 template < >
 struct variant_blob_traits<uint8_t[]>
 {
   static inline nsresult asArray(FallibleTArray<uint8_t> &aData,
                                  uint16_t *_type,
                                  uint32_t *_size,
@@ -307,19 +310,19 @@ public:
 
 ////////////////////////////////////////////////////////////////////////////////
 //// Template Implementation
 
 template <typename DataType>
 class Variant : public Variant_base
 {
 public:
-  Variant(typename variant_storage_traits<DataType>::ConstructorType aData)
-    : mData(variant_storage_traits<DataType>::storage_conversion(aData))
+  Variant(const typename variant_storage_traits<DataType>::ConstructorType& aData)
   {
+    variant_storage_traits<DataType>::storage_conversion(aData, &mData);
   }
 
   NS_IMETHOD GetDataType(uint16_t *_type)
   {
     *_type = variant_traits<DataType>::type();
     return NS_OK;
   }
   NS_IMETHOD GetAsInt32(int32_t *_integer)
--- a/testing/mochitest/b2g.json
+++ b/testing/mochitest/b2g.json
@@ -1,12 +1,108 @@
 {
 "runtests": {
     "dom/base": "",
     "dom/tests/mochitest/dom-level0": "",
     "dom/tests/mochitest/dom-level1-core": "",
     "dom/tests/mochitest/dom-level2-core": "",
-    "dom/tests/mochitest/dom-level2-html": ""
+    "dom/tests/mochitest/dom-level2-html": "",
+    "layout": ""
   },
 "excludetests": {
-    "dom/tests/mochitest/dom-level0/test_innerWidthHeight_script.html": "bug 807137"
+    "dom/tests/mochitest/dom-level0/test_innerWidthHeight_script.html": "bug 807137",
+    "layout/base/tests/test_bug450930.xhtml" : "times out",
+    "layout/base/tests/test_bug465448.xul" : "uncaught expception, window.onerror",
+    "layout/base/tests/test_bug465448.xul": "times out",
+    "layout/base/tests/test_bug394057.html" : "window.onerror not available",
+    "layout/base/tests/test_bug423523.html" : "Caret should be at offset 1",
+    "layout/base/tests/test_bug458898.html" : "window.onerror not available",
+    "layout/base/tests/test_bug603550.html" : "Components.classes['@mozilla.org/widget/dragservice;1'] undefined",
+    "layout/base/tests/test_bug607529.html" : "timed out",
+    "layout/base/tests/test_bug629838.html" : "TypeError: document.getElementById(...).setColor is not a function",
+    "layout/base/tests/test_bug696020.html" : "test timed out",
+    "layout/base/tests/test_bug696020.html" : "[SimpleTest.finish()] waitForFocus() was called a different number of times from the number of callbacks run",
+    "layout/base/tests/test_event_target_radius.html" : "checking 't' offset 141.43328857421875,10 [basic functionality] - got body, expected t and more",
+    "layout/base/tests/test_mozPaintCount.html" : "TypeError: document.getElementById(...).setColor is not a function",
+    "layout/base/tests/test_scroll_selection_into_view.html" : "Scrolling target1 into view with vPercent 0, starting at 0 - got 399, expected 400 and more",
+    "layout/base/tests/test_bug761572.html" : "timed out",
+    "layout/base/tests/test_reftests_with_caret.html": "iframe load timed out",
+    "layout/base/tests/test_scroll_event_ordering.html": "timed out",
+    "layout/forms/test/test_bug287446.html" : "Typing should work - got Test, expected FooTest and more",
+    "layout/forms/test/test_bug348236.html" : " Select's value should be 3 after hovering over option 3 and pressing ALT-Down. - got 1, expected 3 and more",
+    "layout/forms/test/test_bug36619.html" : "an unexpected uncaught JS exception reported through window.onerror - NS_ERROR_FACTORY_NOT_REGISTERED: Component returned failure code: 0x80040154 (NS_ERROR_FACTORY_NOT_REGISTERED) [nsIComponentRegistrar.contractIDToCID] at resource://specialpowers/MockFilePicker.jsm:52",
+    "layout/forms/test/test_bug411236.html" : "NS_ERROR_NOT_AVAILABLE: Component returned failure code: 0x80040111 (NS_ERROR_NOT_AVAILABLE) [nsIPrefBranch.setIntPref] at chrome://specialpowers/content/specialpowersAPI.js:119",
+    "layout/forms/test/test_bug446663.html and more" : "How come no input? - got false, expected true",
+    "layout/forms/test/test_bug478219.xhtml" : "win is null at http://mochi.test:8888/tests/layout/forms/test/test_bug478219.xhtml:20",
+    "layout/forms/test/test_bug564115.html" : "timed out",
+    "layout/forms/test/test_bug571352.html" : "first two options are selected and more",
+    "layout/forms/test/test_textarea_resize.html" : "both width has increased with box sizing content-box using synthesizeMouse - got 156, expected 206 and more",
+    "layout/forms/test/test_bug365410.html" : "timed out",
+    "layout/forms/test/test_bug446663.html" : "bug446663_a cut - got 123, expected",
+    "layout/forms/test/test_bug477700.html" : "Typing should work - got , expected Test",
+    "layout/forms/test/test_bug534785.html" : "timed out",
+    "layout/forms/test/test_bug563642.html" : "timed out",
+    "layout/forms/test/test_bug572649.html" : "timed out",
+    "layout/forms/test/test_bug644542.html" : "timed out",
+    "layout/forms/test/test_bug672810.html" : "timed out",
+    "layout/forms/test/test_bug704049.html" : "timed out",
+    "layout/generic/test/test_bug240933.html" : "timed out",
+    "layout/generic/test/test_bug263683.html" : "timed out",
+    "layout/generic/test/test_bug290397.html" : "timed out",
+    "layout/generic/test/test_bug392746.html" : "First selection range should be ddd text text ",
+    "layout/generic/test/test_bug424627.html" : "timed out",
+    "layout/generic/test/test_bug438840.html" : "timed out",
+    "layout/generic/test/test_bug468167.html" : "timed out",
+    "layout/generic/test/test_bug470212.html" : "rangeCount should be 0 - got 1, expected 0",
+    "layout/generic/test/test_bug496275.html" : "test 0b: Wrong anchor node. Expected [object Text] or https://bugzilla.mozilla.org/show_bug.cgi?id=496275 to be [object HTMLParagraphElement].",
+    "layout/generic/test/test_bug514732.html" : "timed out",
+    "layout/generic/test/test_bug597333.html" : "timed out",
+    "layout/generic/test/test_bug633762.html" : "timed out",
+    "layout/generic/test/test_bug666225.html" : "timed out",
+    "layout/generic/test/test_bug735641.html" : "TypeError: w is null at http://mochi.test:8888/tests/layout/generic/test/test_bug735641.html:41",
+    "layout/generic/test/test_bug784410.html" : "timed out",
+    "layout/generic/test/test_bug791616.html" : "timed out",
+    "layout/generic/test/test_image_selection_2.html" : "timed out",
+    "layout/generic/test/test_invalidate_during_plugin_paint.html" : "TypeError: p1.getPaintCount is not a function at http://mochi.test:8888/tests/layout/generic/test/test_invalidate_during_plugin_paint.html:33",
+    "layout/generic/test/test_movement_by_characters.html" : "Right movement broken in H K - got 0, expected 1",
+    "layout/generic/test/test_movement_by_words.html" : "NS_ERROR_NOT_AVAILABLE: Component returned failure code: 0x80040111 (NS_ERROR_NOT_AVAILABLE) [nsIPrefBranch.setBoolPref]",
+    "layout/generic/test/test_page_scroll_with_fixed_pos.html" : "timed out",
+    "layout/generic/test/test_plugin_clipping.xhtml" : "timed out",
+    "layout/generic/test/test_plugin_clipping2.xhtml" : "timed out",
+    "layout/generic/test/test_plugin_clipping_table.xhtml" : "timed out",
+    "layout/generic/test/test_plugin_clipping_transformed.xhtml" : "timed out",
+    "layout/generic/test/test_plugin_focus.html" : "timed out",
+    "layout/generic/test/test_plugin_mouse_coords.html" : "TypeError: p1.getLastMouseX is not a function at http://mochi.test:8888/tests/layout/generic/test/test_plugin_mouse_coords.html:32",
+    "layout/generic/test/test_plugin_position.xhtml" : "No checks actually run. (You need to call ok(), is(), or similar functions at least once.  Make sure you use SimpleTest.waitForExplicitFinish() if you need it.)",
+    "layout/generic/test/test_selection_expanding.html" : "The contents of div1 aren't selected (div1-div2, all boxes are overflow: visible;): Selected String:",
+    "layout/inspector/tests/test_bug522601.xhtml" : "an unexpected uncaught JS exception reported through window.onerror - TypeError: document.getAnonymousNodes(...) is null at http://mochi.test:8888/tests/layout/inspector/tests/test_bug522601.xhtml:110",
+    "layout/inspector/tests/test_bug609549.xhtml" : "bad withAnons.length - got 2, expected 4",
+    "layout/mathml/tests/test_bug706406.html" : "timed out",
+    "layout/style/test/test_compute_data_with_start_struct.html" : "initial and other values of height are different - didn't expect 26px, but got it",
+    "layout/style/test/test_dont_use_document_colors.html" : "color is blocked - got rgb(255, 255, 0), expected rgb(0, 0, 0)",
+    "layout/style/test/test_inherit_computation.html" : "should be testing with values that compute to different things for 'width' - didn't expect 15px, but got it",
+    "layout/style/test/test_media_queries.html" : "timed out",
+    "layout/style/test/test_media_queries_dynamic_xbl.html" : "should be purple when portait - got rgb(0, 0, 0), expected rgb(128, 0, 128)",
+    "layout/style/test/test_rule_insertion.html": "<0,0,0,0,3> inserting @font-face { font-family: UnlikelyFontName; src: local('Courier'), local('Courier New'), local('Monaco'), local('DejaVu Sans Mono'), local('Droid Sans Mono'); } into style sheet",
+    "layout/style/test/test_pixel_lengths.html" : "Checking width in mozmm at 192 DPI - got 96, expected 192",
+    "layout/style/test/test_selectors.html" : "element in <a id='a' href='data:text/plain,this_better_be_unvisited'></a><a id='b'></a> did not match *|a:not(:link) - got 518, expected auto",
+    "layout/style/test/test_compute_data_with_start_struct.html" : "initial and other values of height are different - didn't expect 26px, but got it",
+    "layout/style/test/test_selectors_on_anonymous_content.html" : "TypeError: document.getAnonymousNodes(...) is null at http://mochi.test:8888/tests/layout/style/test/test_selectors_on_anonymous_content.html:45",
+    "layout/style/test/test_transitions_per_property.html" : "timed out",
+    "layout/style/test/test_units_angle.html" : "test_unclosed_parentheses.html finished in a non-clean fashion, probably because it didn't call SimpleTest.finish()",
+    "layout/style/test/test_transitions_step_functions.html" : "[SimpleTest.finish()] this test already called finish!",
+    "layout/style/test/test_units_frequency.html" : "finished in a non-clean fashion, probably because it didn't call SimpleTest.finish()",
+    "layout/style/test/test_units_length.html" : "finished in a non-clean fashion, probably because it didn't call SimpleTest.finish()",
+    "layout/style/test/test_units_time.html" : "finished in a non-clean fashion, probably because it didn't call SimpleTest.finish()",
+    "layout/style/test/test_value_cloning.html" : "finished in a non-clean fashion, probably because it didn't call SimpleTest.finish()",
+    "layout/style/test/test_value_computation.html" : "timed out",
+    "layout/style/test/test_value_storage.html" : "should be testing with values that compute to different things for 'border-left-width' - didn't expect 3px, but got it",
+    "layout/style/test/test_viewport_units.html" : "NS_ERROR_NOT_AVAILABLE: Component is not available at http://mochi.test:8888/tests/layout/style/test/test_value_storage.html:116",
+    "layout/style/test/test_viewport_units.html" : "[SimpleTest.finish()] this test already called finish!",
+    "layout/style/test/test_visited_image_loading.html" : "finished in a non-clean fashion, probably because it didn't call SimpleTest.finish()", 
+    "layout/style/test/test_visited_image_loading_empty.html" : "timed out", 
+    "layout/style/test/test_visited_lying.html" : "timed out", 
+    "layout/style/test/test_visited_pref.html" : "timed out", 
+    "layout/style/test/test_visited_reftests.html" : "timed out",
+    "layout/tables/test/test_bug541668_table_event_delivery.html" : "timed out",
+    "layout/xul" : "xul doesn't work in b2g"
   }
 }
--- a/testing/xpcshell/remotexpcshelltests.py
+++ b/testing/xpcshell/remotexpcshelltests.py
@@ -20,22 +20,26 @@ class XPCShellRemote(xpcshell.XPCShellTe
     def __init__(self, devmgr, options, args):
         xpcshell.XPCShellTests.__init__(self)
         self.localLib = options.localLib
         self.localBin = options.localBin
         self.options = options
         self.device = devmgr
         self.pathMapping = []
         self.remoteTestRoot = self.device.getTestRoot("xpcshell")
-        # Terse directory names are used here ("b" for a binaries directory)
+        # remoteBinDir contains xpcshell and its wrapper script, both of which must
+        # be executable. Since +x permissions cannot usually be set on /mnt/sdcard,
+        # and the test root may be on /mnt/sdcard, remoteBinDir is set to be on 
+        # /data/local, always.
+        self.remoteBinDir = "/data/local/xpcb"
+        # Terse directory names are used here ("c" for the components directory)
         # to minimize the length of the command line used to execute
         # xpcshell on the remote device. adb has a limit to the number
         # of characters used in a shell command, and the xpcshell command
         # line can be quite complex.
-        self.remoteBinDir = self.remoteJoin(self.remoteTestRoot, "b")
         self.remoteTmpDir = self.remoteJoin(self.remoteTestRoot, "tmp")
         self.remoteScriptsDir = self.remoteTestRoot
         self.remoteComponentsDir = self.remoteJoin(self.remoteTestRoot, "c")
         self.remoteModulesDir = self.remoteJoin(self.remoteTestRoot, "m")
         self.profileDir = self.remoteJoin(self.remoteTestRoot, "p")
         self.remoteDebugger = options.debugger
         self.remoteDebuggerArgs = options.debuggerArgs
         self.testingModulesDir = options.testingModulesDir
@@ -78,16 +82,20 @@ class XPCShellRemote(xpcshell.XPCShellTe
 
     def remoteForLocal(self, local):
         for mapping in self.pathMapping:
           if (os.path.abspath(mapping.local) == os.path.abspath(local)):
             return mapping.remote
         return local
 
     def setupUtilities(self):
+        if (not self.device.dirExists(self.remoteBinDir)):
+          # device.mkDir may fail here where shellCheckOutput may succeed -- see bug 817235
+          self.device.shellCheckOutput(["mkdir", self.remoteBinDir]);
+
         remotePrefDir = self.remoteJoin(self.remoteBinDir, "defaults/pref")
         if (self.device.dirExists(self.remoteTmpDir)):
           self.device.removeDir(self.remoteTmpDir)
         self.device.mkDir(self.remoteTmpDir)
         if (not self.device.dirExists(remotePrefDir)):
           self.device.mkDirs(self.remoteJoin(remotePrefDir, "extra"))
         if (not self.device.dirExists(self.remoteScriptsDir)):
           self.device.mkDir(self.remoteScriptsDir)
@@ -430,19 +438,19 @@ def main():
 
     if len(args) < 1 and options.manifest is None:
       print >>sys.stderr, """Usage: %s <test dirs>
            or: %s --manifest=test.manifest """ % (sys.argv[0], sys.argv[0])
       sys.exit(1)
 
     if (options.dm_trans == "adb"):
       if (options.deviceIP):
-        dm = devicemanagerADB.DeviceManagerADB(options.deviceIP, options.devicePort)
+        dm = devicemanagerADB.DeviceManagerADB(options.deviceIP, options.devicePort, packageName=None)
       else:
-        dm = devicemanagerADB.DeviceManagerADB()
+        dm = devicemanagerADB.DeviceManagerADB(packageName=None)
     else:
       dm = devicemanagerSUT.DeviceManagerSUT(options.deviceIP, options.devicePort)
       if (options.deviceIP == None):
         print "Error: you must provide a device IP to connect to via the --device option"
         sys.exit(1)
 
     if options.interactive and not options.testPath:
       print >>sys.stderr, "Error: You must specify a test filename in interactive mode!"
--- a/toolkit/components/nsDefaultCLH.js
+++ b/toolkit/components/nsDefaultCLH.js
@@ -39,32 +39,32 @@ nsDefaultCLH.prototype = {
   /* nsISupports */
 
   QueryInterface : XPCOMUtils.generateQI([nsICommandLineHandler]),
 
   /* nsICommandLineHandler */
 
   handle : function clh_handle(cmdLine) {
     var printDir;
-    while (printDir = cmdLine.handleFlagWithParam("print-xpcom-dir", false)) {
+    while ((printDir = cmdLine.handleFlagWithParam("print-xpcom-dir", false))) {
       var out = "print-xpcom-dir(\"" + printDir + "\"): ";
       try {
         out += getDirectoryService().get(printDir, nsIFile).path;
       }
       catch (e) {
         out += "<Not Provided>";
       }
 
       dump(out + "\n");
       Components.utils.reportError(out);
     }
 
     var printDirList;
-    while (printDirList = cmdLine.handleFlagWithParam("print-xpcom-dirlist",
-                                                      false)) {
+    while ((printDirList = cmdLine.handleFlagWithParam("print-xpcom-dirlist",
+                                                       false))) {
       out = "print-xpcom-dirlist(\"" + printDirList + "\"): ";
       try {
         var list = getDirectoryService().get(printDirList,
                                              nsISimpleEnumerator);
         while (list.hasMoreElements())
           out += list.getNext().QueryInterface(nsIFile).path + ";";
       }
       catch (e) {
--- a/toolkit/components/social/SocialService.jsm
+++ b/toolkit/components/social/SocialService.jsm
@@ -363,16 +363,18 @@ SocialProvider.prototype = {
   // Map of objects describing the provider's notification icons, whose
   // properties include:
   //   name, iconURL, counter, contentPanel
   // See https://developer.mozilla.org/en-US/docs/Social_API
   ambientNotificationIcons: null,
 
   // Called by the workerAPI to update our profile information.
   updateUserProfile: function(profile) {
+    if (!profile)
+      profile = {};
     this.profile = profile;
 
     // Sanitize the portrait from any potential script-injection.
     if (profile.portrait) {
       try {
         let portraitUri = Services.io.newURI(profile.portrait, null, null);
 
         let scheme = portraitUri ? portraitUri.scheme : "";
--- a/toolkit/components/telemetry/TelemetryPing.js
+++ b/toolkit/components/telemetry/TelemetryPing.js
@@ -70,18 +70,16 @@ const MEM_HISTOGRAMS = {
   "ghost-windows": "GHOST_WINDOWS"
 };
 
 // Seconds of idle time before pinging.
 // On idle-daily a gather-telemetry notification is fired, during it probes can
 // start asynchronous tasks to gather data.  On the next idle the data is sent.
 const IDLE_TIMEOUT_SECONDS = 5 * 60;
 
-const SHUTDOWN_TIME_READ_DELAY_MS = 5413;
-
 var gLastMemoryPoll = null;
 
 let gWasDebuggerAttached = false;
 
 function getLocale() {
   return Cc["@mozilla.org/chrome/chrome-registry;1"].
          getService(Ci.nsIXULChromeRegistry).
          getSelectedLocale('global');
@@ -722,32 +720,37 @@ TelemetryPing.prototype = {
       // Prerequesite prefs aren't set
     }
     if (!enabled) {
       // Turn off local telemetry if telemetry is disabled.
       // This may change once about:telemetry is added.
       Telemetry.canRecord = false;
       return;
     }
+#ifndef MOZ_PER_WINDOW_PRIVATE_BROWSING
     Services.obs.addObserver(this, "private-browsing", false);
+#endif
     Services.obs.addObserver(this, "profile-before-change", false);
     Services.obs.addObserver(this, "sessionstore-windows-restored", false);
     Services.obs.addObserver(this, "quit-application-granted", false);
     Services.obs.addObserver(this, "xul-window-visible", false);
     this._hasWindowRestoredObserver = true;
     this._hasXulWindowVisibleObserver = true;
 
     // Delay full telemetry initialization to give the browser time to
     // run various late initializers. Otherwise our gathered memory
     // footprint and other numbers would be too optimistic.
     this._timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
     function timerCallback() {
       this._initialized = true;
       this.attachObservers();
       this.gatherMemory();
+
+      Telemetry.asyncReadShutdownTime(function () {
+      });
       delete this._timer;
     }
     this._timer.initWithCallback(timerCallback.bind(this), TELEMETRY_DELAY,
                                  Ci.nsITimer.TYPE_ONE_SHOT);
     this.loadSavedPings(false);
   },
 
   verifyPingChecksum: function verifyPingChecksum(ping) {
@@ -944,17 +947,19 @@ TelemetryPing.prototype = {
       Services.obs.removeObserver(this, "sessionstore-windows-restored");
       this._hasWindowRestoredObserver = false;
     }
     if (this._hasXulWindowVisibleObserver) {
       Services.obs.removeObserver(this, "xul-window-visible");
       this._hasXulWindowVisibleObserver = false;
     }
     Services.obs.removeObserver(this, "profile-before-change");
+#ifndef MOZ_PER_WINDOW_PRIVATE_BROWSING
     Services.obs.removeObserver(this, "private-browsing");
+#endif
     Services.obs.removeObserver(this, "quit-application-granted");
   },
 
   getPayload: function getPayload() {
     // This function returns the current Telemetry payload to the caller.
     // We only gather startup info once.
     if (Object.keys(this._slowSQLStartup).length == 0) {
       this.gatherStartupHistograms();
@@ -1012,32 +1017,28 @@ TelemetryPing.prototype = {
     case "cycle-collector-begin":
       let now = new Date();
       if (!gLastMemoryPoll
           || (TELEMETRY_INTERVAL <= now - gLastMemoryPoll)) {
         gLastMemoryPoll = now;
         this.gatherMemory();
       }
       break;
+#ifndef MOZ_PER_WINDOW_PRIVATE_BROWSING
     case "private-browsing":
       Telemetry.canRecord = aData == "exit";
       if (aData == "enter") {
         this.detachObservers()
       } else {
         this.attachObservers()
       }
       break;
+#endif
     case "xul-window-visible":
       Services.obs.removeObserver(this, "xul-window-visible");
-
-      let timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
-      timer.initWithCallback(function() {
-        Telemetry.asyncReadShutdownTime(function () {
-        });
-      }, SHUTDOWN_TIME_READ_DELAY_MS, Ci.nsITimer.TYPE_ONE_SHOT);
       this._hasXulWindowVisibleObserver = false;   
       var counters = processInfo.getCounters();
       if (counters) {
         [this._startupIO.startupWindowVisibleReadBytes, 
           this._startupIO.startupWindowVisibleWriteBytes] = counters;
       }
       break;
     case "sessionstore-windows-restored":
--- a/toolkit/components/url-classifier/content/moz/debug.js
+++ b/toolkit/components/url-classifier/content/moz/debug.js
@@ -601,20 +601,20 @@ G_DebugService.prototype.observe = funct
   }
 }
 
 /**
  * Private helper to report an nsIScriptError instance to the log/console.
  */
 G_DebugService.prototype.reportScriptError_ = function(message, sourceName, 
                                                        lineNumber, label) {
-  var message = "\n------------------------------------------------------------\n" +
-                label + ": " + message +
-                "\nlocation: " + sourceName + ", " + "line: " + lineNumber +
-                "\n------------------------------------------------------------\n\n";
+  message = "\n------------------------------------------------------------\n" +
+            label + ": " + message +
+            "\nlocation: " + sourceName + ", " + "line: " + lineNumber +
+            "\n------------------------------------------------------------\n\n";
 
   dump(message);
   this.maybeDumpToFile(message);
 }
 
 
 
 /**
--- a/toolkit/content/license.html
+++ b/toolkit/content/license.html
@@ -57,26 +57,26 @@
     <ul>
       <li><a href="about:license#ACE">ACE License</a></li>
       <li><a href="about:license#android">Android Open Source License</a></li>
       <li><a href="about:license#angle">ANGLE License</a></li>
       <li><a href="about:license#apache">Apache License 2.0</a></li>
       <li><a href="about:license#apple">Apple License</a></li>
       <li><a href="about:license#apple-mozilla">Apple/Mozilla NPRuntime License</a></li>
       <li><a href="about:license#apple-torch">Apple/Torch Mobile License</a></li>
-      <li><a href="about:license#breakpad">Breakpad License</a></li>
       <li><a href="about:license#bspatch">bspatch License</a></li>
       <li><a href="about:license#cairo">Cairo Component Licenses</a></li>
       <li><a href="about:license#chromium">Chromium License</a></li>
       <li><a href="about:license#dtoa">dtoa License</a></li>
       <li><a href="about:license#hunspell-nl">Dutch Spellchecking Dictionary License</a></li>
       <li><a href="about:license#edl">Eclipse Distribution License</a></li>
       <li><a href="about:license#expat">Expat License</a></li>
       <li><a href="about:license#firebug">Firebug License</a></li>
       <li><a href="about:license#gfx-font-list">gfxFontList License</a></li>
+      <li><a href="about:license#google-bsd">Google BSD License</a></li>
       <li><a href="about:license#gears">Google Gears License</a></li>
       <li><a href="about:license#gears-istumbler">Google Gears/iStumbler License</a></li>
       <li><a href="about:license#vp8">Google VP8 License</a></li>
       <li><a href="about:license#gyp">gyp License</a></li>
       <li><a href="about:license#halloc">halloc License</a></li>
       <li><a href="about:license#harfbuzz">HarfBuzz License</a></li>
       <li><a href="about:license#icu">ICU License</a></li>
       <li><a href="about:license#jpnic">Japan Network Information Center License</a></li>
@@ -596,16 +596,17 @@ executables of your software products.
 
 
     <hr>
 
     <h1><a id="android"></a>Android Open Source License</h1>
 
     <p>This license applies to various files in the Mozilla codebase,
     including those in the directory <span class="path">gfx/skia/</span>.</p>
+<!-- This is the wrong directory, what was intended? -->
 
 <pre>
  Copyright 2009, The Android Open Source Project
 
  Redistribution and use in source and binary forms, with or without
  modification, are permitted provided that the following conditions
  are met:
   * Redistributions of source code must retain the above copyright
@@ -964,56 +965,16 @@ PROFITS; OR BUSINESS INTERRUPTION) HOWEV
 OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 </pre>
 
 
     <hr>
 
-    <h1><a id="breakpad"></a>Breakpad License</h1>
-
-    <p>This license applies to files in the directory
-    <span class="path">toolkit/crashreporter/google-breakpad/</span> and
-    <span class="path">camino/google-breakpad/</span>.</p>
-
-<pre>
-Copyright (c) 2006, Google Inc.
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are
-met:
-
-    * Redistributions of source code must retain the above copyright
-notice, this list of conditions and the following disclaimer.
-    * Redistributions in binary form must reproduce the above
-copyright notice, this list of conditions and the following disclaimer
-in the documentation and/or other materials provided with the
-distribution.
-    * Neither the name of Google Inc. nor the names of its
-contributors may be used to endorse or promote products derived from
-this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-</pre>
-
-
-    <hr>
-
     <h1><a id="bspatch"></a>bspatch License</h1>
 
     <p>This license applies to the files
     <span class="path">toolkit/mozapps/update/updater/bspatch.cpp</span> and
     <span class="path">toolkit/mozapps/update/updater/bspatch.h</span>.
     </p>
 
 <pre>
@@ -1362,16 +1323,57 @@ ON ANY THEORY OF LIABILITY, WHETHER IN C
 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 </pre>
 
 
 
     <hr>
 
+    <h1><a id="google-bsd"></a>Google BSD License</h1>
+
+    <p>This license applies to files in the directories
+    <span class="path">toolkit/crashreporter/google-breakpad/</span>,
+    <span class="path">camino/google-breakpad/</span> and
+    <span class="path">toolkit/components/protobuf/</span>.</p>
+
+<pre>
+Copyright (c) 2006, Google Inc.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+    * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+    * Neither the name of Google Inc. nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+</pre>
+
+
+    <hr>
+
     <h1><a id="gears"></a>Google Gears License</h1>
 
     <p>This license applies to the file
     <span class="path">netwerk/wifi/wlanapi.h</span>.</p>
 
 <pre>
 Copyright 2008, Google Inc.
 
@@ -2644,17 +2646,17 @@ SUBSTITUTE GOODS OR SERVICES; LOSS OF US
 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 POSSIBILITY OF SUCH DAMAGE.
 </pre>
 
     <hr>
 
-    <h1><a id="skia"></a>SCTP Licenses</h1>
+    <h1><a id="sctp"></a>SCTP Licenses</h1>
 
     <p>These licenses apply to certain files in the directory
     <span class="path">netwerk/sctp/src/</span>.</p>
 
 <pre>
 Copyright (c) 2009-2010 Brad Penoff
 Copyright (c) 2009-2010 Humaira Kamal
 Copyright (c) 2011-2012 Irene Ruengeler
--- a/toolkit/mozapps/downloads/content/downloads.js
+++ b/toolkit/mozapps/downloads/content/downloads.js
@@ -431,18 +431,20 @@ function Startup()
   // downloads can finish before Startup() does, so check if the window should
   // close and act accordingly
   if (!autoRemoveAndClose())
     gDownloadsView.focus();
 
   let obs = Cc["@mozilla.org/observer-service;1"].
             getService(Ci.nsIObserverService);
   obs.addObserver(gDownloadObserver, "download-manager-remove-download", false);
+#ifndef MOZ_PER_WINDOW_PRIVATE_BROWSING
   obs.addObserver(gDownloadObserver, "private-browsing", false);
   obs.addObserver(gDownloadObserver, "private-browsing-change-granted", false);
+#endif
   obs.addObserver(gDownloadObserver, "browser-lastwindow-close-granted", false);
 
   // Clear the search box and move focus to the list on escape from the box
   gSearchBox.addEventListener("keypress", function(e) {
     if (e.keyCode == e.DOM_VK_ESCAPE) {
       // Move focus to the list instead of closing the window
       gDownloadsView.focus();
       e.preventDefault();
@@ -457,18 +459,20 @@ function Startup()
 }
 
 function Shutdown()
 {
   gDownloadManager.removeListener(gDownloadListener);
 
   let obs = Cc["@mozilla.org/observer-service;1"].
             getService(Ci.nsIObserverService);
+#ifndef MOZ_PER_WINDOW_PRIVATE_BROWSING
   obs.removeObserver(gDownloadObserver, "private-browsing");
   obs.removeObserver(gDownloadObserver, "private-browsing-change-granted");
+#endif
   obs.removeObserver(gDownloadObserver, "download-manager-remove-download");
   obs.removeObserver(gDownloadObserver, "browser-lastwindow-close-granted");
 
   clearTimeout(gBuilder);
   gStmt.reset();
   gStmt.finalize();
 }
 
@@ -483,16 +487,17 @@ let gDownloadObserver = {
           break;
         }
 
         // Otherwise, remove a single download
         let id = aSubject.QueryInterface(Ci.nsISupportsPRUint32);
         let dl = getDownload(id.data);
         removeFromView(dl);
         break;
+#ifndef MOZ_PER_WINDOW_PRIVATE_BROWSING
       case "private-browsing-change-granted":
         // Finalize our statements cause the connection will be closed by the
         // service during the private browsing transition.
         gStmt.finalize();
         gStmt = null;
         break;
       case "private-browsing":
         if (aData == "enter" || aData == "exit") {
@@ -510,16 +515,17 @@ let gDownloadObserver = {
           // yet.  Defer this until all private-browsing notifications
           // have been processed.
           setTimeout(function() {
             initStatement();
             buildDownloadList(true);
           }, 0);
         }
         break;
+#endif
       case "browser-lastwindow-close-granted":
 #ifndef XP_MACOSX
         if (gDownloadManager.activeDownloadCount == 0) {
           setTimeout(gCloseDownloadManager, 0);
         }
 #endif
         break;
     }
@@ -1341,20 +1347,22 @@ function updateClearListButton()
 
 function getDownload(aID)
 {
   return document.getElementById("dl" + aID);
 }
 
 /**
  * Initialize the statement which is used to retrieve the list of downloads.
+#ifndef MOZ_PER_WINDOW_PRIVATE_BROWSING
  *
  * This function gets called both at startup, and when entering the private
  * browsing mode (because the database connection is changed when entering
  * the private browsing mode, and a new statement should be initialized.
+#endif
  */
 function initStatement()
 {
   if (gStmt)
     gStmt.finalize();
 
   gStmt = gDownloadManager.DBConnection.createStatement(
     "SELECT id, target, name, source, state, startTime, endTime, referrer, " +
--- a/toolkit/mozapps/downloads/content/downloads.xul
+++ b/toolkit/mozapps/downloads/content/downloads.xul
@@ -20,17 +20,20 @@
 %downloadManagerDTD;
 <!ENTITY % editMenuOverlayDTD SYSTEM "chrome://global/locale/editMenuOverlay.dtd">
 %editMenuOverlayDTD;
 ]>
 
 <window xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
         xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
         id="downloadManager" windowtype="Download:Manager"
-        orient="vertical" title="&downloads.title;" statictitle="&downloads.title;"
+        orient="vertical" title="&downloads.title;"
+#ifndef MOZ_PER_WINDOW_PRIVATE_BROWSING
+        statictitle="&downloads.title;"
+#endif
         width="&window.width2;" height="&window.height;" screenX="10" screenY="10"
         persist="width height screenX screenY sizemode"
         onload="Startup();" onunload="Shutdown();"
         onclose="return closeWindow(false);">
 
   <script type="application/javascript" src="chrome://mozapps/content/downloads/downloads.js"/>
   <script type="application/javascript" src="chrome://mozapps/content/downloads/DownloadProgressListener.js"/>
   <script type="application/javascript" src="chrome://global/content/contentAreaUtils.js"/>
--- a/toolkit/mozapps/downloads/tests/chrome/Makefile.in
+++ b/toolkit/mozapps/downloads/tests/chrome/Makefile.in
@@ -25,17 +25,16 @@ MOCHITEST_CHROME_FILES = \
   test_multi_select.xul \
   test_multiword_search.xul \
   test_pause_button_state.xul \
   test_removeDownload_updates_ui.xul \
   test_search_clearlist.xul \
   test_search_keys.xul \
   test_select_all.xul \
   test_space_key_pauses_resumes.xul \
-  test_privatebrowsing_title.xul \
   test_ui_stays_open_on_alert_clickback.xul \
   test_unknownContentType_dialog_layout.xul \
   test_bug_412360.xul \
   test_bug_429247.xul \
   test_bug_462172.xul \
   test_close_on_last_window.xul \
   unknownContentType_dialog_layout_data.txt \
   unknownContentType_dialog_layout_data.txt^headers^ \
@@ -51,9 +50,15 @@ endif
 
 ifeq ($(OS_ARCH),WINNT)
 MOCHITEST_CHROME_FILES += \
   test_taskbarprogress_downloadstates.xul \
   $(filter disabled-for-very-frequent-orange--bug-630567, test_taskbarprogress_service.xul) \
   $(NULL)
 endif
 
+ifndef MOZ_PER_WINDOW_PRIVATE_BROWSING
+MOCHITEST_CHROME_FILES += \
+  test_privatebrowsing_title.xul \
+  $(NULL)
+endif
+
 include $(topsrcdir)/config/rules.mk
--- a/toolkit/mozapps/update/nsUpdateService.js
+++ b/toolkit/mozapps/update/nsUpdateService.js
@@ -3617,19 +3617,19 @@ Downloader.prototype = {
 
     if (state == STATE_DOWNLOAD_FAILED) {
       var allFailed = true;
       // Check if there is a complete update patch that can be downloaded.
       if (!this._update.isCompleteUpdate && this._update.patchCount == 2) {
         LOG("Downloader:onStopRequest - verification of patch failed, " +
             "downloading complete update patch");
         this._update.isCompleteUpdate = true;
-        var status = this.downloadUpdate(this._update);
-
-        if (status == STATE_NONE) {
+        let updateStatus = this.downloadUpdate(this._update);
+
+        if (updateStatus == STATE_NONE) {
           cleanupActiveUpdate();
         } else {
           allFailed = false;
         }
       }
 
       if (allFailed) {
         LOG("Downloader:onStopRequest - all update patch downloads failed");
--- a/toolkit/mozapps/update/test/unit/xpcshell.ini
+++ b/toolkit/mozapps/update/test/unit/xpcshell.ini
@@ -16,23 +16,23 @@ reason = bug 820380
 [test_0064_manager.js]
 [test_0070_update_dir_cleanup.js]
 [test_0071_update_dir_cleanup.js]
 [test_0072_update_dir_cleanup.js]
 [test_0073_update_dir_cleanup.js]
 [test_0080_prompt_silent.js]
 [test_0081_prompt_uiAlreadyOpen.js]
 skip-if = toolkit == "gonk"
-reason = bug 820380
+reason = custom nsIUpdatePrompt
 ; Tests that require the updater binary
 [include:xpcshell_updater.ini]
 skip-if = os == 'android'
 ; Platform-specific updater tests
 [include:xpcshell_updater_windows.ini]
 run-if = os == 'win'
 [include:xpcshell_updater_xp_unix.ini]
 run-if = os == 'linux' || os == 'mac' || os == 'sunos'
 [test_bug497578.js]
 skip-if = perwindowprivatebrowsing
 [test_bug595059.js]
 skip-if = toolkit == "gonk"
-reason = bug 820380
+reason = custom nsIUpdatePrompt
 [test_bug794211.js]
--- a/tools/rb/fix_macosx_stack.py
+++ b/tools/rb/fix_macosx_stack.py
@@ -85,29 +85,28 @@ def addressToSymbol(file, address):
         atoses[file] = converter
     else:
         converter = atoses[file]
     return converter.convert("0x%X" % address)
 
 cxxfilt_proc = None
 def cxxfilt(sym):
     if cxxfilt_proc is None:
+        # --no-strip-underscores because atos already stripped the underscore
         globals()["cxxfilt_proc"] = subprocess.Popen(['c++filt',
                                                       '--no-strip-underscores',
                                                       '--format', 'gnu-v3'],
                                                      stdin=subprocess.PIPE,
                                                      stdout=subprocess.PIPE)
-    # strip underscores ourselves (works better than c++filt's
-    # --strip-underscores)
-    cxxfilt_proc.stdin.write(sym[1:] + "\n")
+    cxxfilt_proc.stdin.write(sym + "\n")
     return cxxfilt_proc.stdout.readline().rstrip("\n")
 
 line_re = re.compile("^(.*) ?\[([^ ]*) \+(0x[0-9A-F]{1,8})\](.*)$")
 balance_tree_re = re.compile("^([ \|0-9-]*)")
-atos_sym_re = re.compile("^(\S+) \(in ([^)]+)\) \((.+)\)$")
+atos_name_re = re.compile("^(.+) \(in ([^)]+)\) \((.+)\)$")
 
 def fixSymbols(line):
     result = line_re.match(line)
     if result is not None:
         # before allows preservation of balance trees
         # after allows preservation of counts
         (before, file, address, after) = result.groups()
         address = int(address, 16)
@@ -115,24 +114,27 @@ def fixSymbols(line):
         if os.path.exists(file) and os.path.isfile(file):
             address += address_adjustment(file)
             info = addressToSymbol(file, address)
 
             # atos output seems to have three forms:
             #   address
             #   address (in foo.dylib)
             #   symbol (in foo.dylib) (file:line)
-            symresult = atos_sym_re.match(info)
-            if symresult is not None:
+            name_result = atos_name_re.match(info)
+            if name_result is not None:
                 # Print the first two forms as-is, and transform the third
-                (symbol, library, fileline) = symresult.groups()
-                symbol = cxxfilt(symbol)
-                info = "%s (%s, in %s)" % (symbol, fileline, library)
+                (name, library, fileline) = name_result.groups()
+                # atos demangles, but occasionally it fails.  cxxfilt can mop
+                # up the remaining cases(!), which will begin with '_Z'.
+                if (name.startswith("_Z")):
+                    name = cxxfilt(name)
+                info = "%s (%s, in %s)" % (name, fileline, library)
 
-             # throw away the bad symbol, but keep balance tree structure
+            # throw away the bad symbol, but keep balance tree structure
             before = balance_tree_re.match(before).groups()[0]
 
             return before + info + after + "\n"
         else:
             sys.stderr.write("Warning: File \"" + file + "\" does not exist.\n")
             return line
     else:
         return line
--- a/uriloader/prefetch/OfflineCacheUpdateChild.cpp
+++ b/uriloader/prefetch/OfflineCacheUpdateChild.cpp
@@ -320,16 +320,22 @@ OfflineCacheUpdateChild::GetIsUpgrade(bo
 
 NS_IMETHODIMP
 OfflineCacheUpdateChild::AddDynamicURI(nsIURI *aURI)
 {
     return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 NS_IMETHODIMP
+OfflineCacheUpdateChild::Cancel()
+{
+    return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
 OfflineCacheUpdateChild::AddObserver(nsIOfflineCacheUpdateObserver *aObserver,
                                   bool aHoldWeak)
 {
     LOG(("OfflineCacheUpdateChild::AddObserver [%p]", this));
 
     NS_ENSURE_TRUE(mState >= STATE_INITIALIZED, NS_ERROR_NOT_INITIALIZED);
 
     if (aHoldWeak) {
--- a/uriloader/prefetch/OfflineCacheUpdateGlue.h
+++ b/uriloader/prefetch/OfflineCacheUpdateGlue.h
@@ -29,17 +29,18 @@ namespace docshell {
   NS_IMETHOD GetUpdateDomain(nsACString & aUpdateDomain) { return !_to ? NS_ERROR_NULL_POINTER : _to->GetUpdateDomain(aUpdateDomain); } \
   NS_IMETHOD GetManifestURI(nsIURI **aManifestURI) { return !_to ? NS_ERROR_NULL_POINTER : _to->GetManifestURI(aManifestURI); } \
   NS_IMETHOD GetSucceeded(bool *aSucceeded) { return !_to ? NS_ERROR_NULL_POINTER : _to->GetSucceeded(aSucceeded); } \
   NS_IMETHOD InitPartial(nsIURI *aManifestURI, const nsACString & aClientID, nsIURI *aDocumentURI) { return !_to ? NS_ERROR_NULL_POINTER : _to->InitPartial(aManifestURI, aClientID, aDocumentURI); } \
   NS_IMETHOD InitForUpdateCheck(nsIURI *aManifestURI, uint32_t aAppID, bool aInBrowser, nsIObserver *aObserver) { return !_to ? NS_ERROR_NULL_POINTER : _to->InitForUpdateCheck(aManifestURI, aAppID, aInBrowser, aObserver); } \
   NS_IMETHOD AddDynamicURI(nsIURI *aURI) { return !_to ? NS_ERROR_NULL_POINTER : _to->AddDynamicURI(aURI); } \
   NS_IMETHOD AddObserver(nsIOfflineCacheUpdateObserver *aObserver, bool aHoldWeak) { return !_to ? NS_ERROR_NULL_POINTER : _to->AddObserver(aObserver, aHoldWeak); } \
   NS_IMETHOD RemoveObserver(nsIOfflineCacheUpdateObserver *aObserver) { return !_to ? NS_ERROR_NULL_POINTER : _to->RemoveObserver(aObserver); } \
-  NS_IMETHOD GetByteProgress(uint64_t * _result) { return !_to ? NS_ERROR_NULL_POINTER : _to->GetByteProgress(_result); }
+  NS_IMETHOD GetByteProgress(uint64_t * _result) { return !_to ? NS_ERROR_NULL_POINTER : _to->GetByteProgress(_result); } \
+  NS_IMETHOD Cancel() { return !_to ? NS_ERROR_NULL_POINTER : _to->Cancel(); }
 
 class OfflineCacheUpdateGlue MOZ_FINAL : public nsSupportsWeakReference
                                        , public nsIOfflineCacheUpdate
                                        , public nsIOfflineCacheUpdateObserver
 {
 public:
     NS_DECL_ISUPPORTS
 
--- a/uriloader/prefetch/nsIOfflineCacheUpdate.idl
+++ b/uriloader/prefetch/nsIOfflineCacheUpdate.idl
@@ -58,17 +58,17 @@ interface nsIOfflineCacheUpdateObserver 
  * Each update object maintains a list of nsIDOMLoadStatus items for the
  * resources it is updating.  The list of these items will be available
  * after the object is scheduled.
  *
  * One update object will be updating at a time.  The active object will
  * load its items one by one, sending itemCompleted() to any registered
  * observers.
  */
-[scriptable, uuid(91b94446-5d91-4089-bed7-edfab25824a7)]
+[scriptable, uuid(a4503a53-6ab8-4b50-b01e-1c4f393fc980)]
 interface nsIOfflineCacheUpdate : nsISupports {
   /**
    * Fetch the status of the running update.  This will return a value
    * defined in nsIDOMOfflineResourceList.
    */
   readonly attribute unsigned short status;
 
   /**
@@ -180,16 +180,23 @@ interface nsIOfflineCacheUpdate : nsISup
    * Remove an observer from the update.
    *
    * @param aObserver
    *        the observer to remove.
    */
   void removeObserver(in nsIOfflineCacheUpdateObserver aObserver);
 
   /**
+   * Cancel the update when still in progress. This stops all running resource
+   * downloads and discards the downloaded cache version. Throws when update
+   * has already finished and made the new cache version active.
+   */
+  void cancel();
+
+  /**
    * Return the number of bytes downloaded so far
    */
   readonly attribute uint64_t byteProgress;
 };
 
 [scriptable, uuid(cf362a31-4166-4994-8443-b68704ecdcc0)]
 interface nsIOfflineCacheUpdateService : nsISupports {
     /**
--- a/uriloader/prefetch/nsOfflineCacheUpdate.cpp
+++ b/uriloader/prefetch/nsOfflineCacheUpdate.cpp
@@ -1545,16 +1545,17 @@ nsOfflineCacheUpdate::LoadCompleted(nsOf
         LOG(("  after completion, ignoring"));
         return;
     }
 
     // Keep the object alive through a Finish() call.
     nsCOMPtr<nsIOfflineCacheUpdate> kungFuDeathGrip(this);
 
     if (mState == STATE_CANCELLED) {
+        NotifyState(nsIOfflineCacheUpdateObserver::STATE_ERROR);
         Finish();
         return;
     }
 
     if (mState == STATE_CHECKING) {
         // Manifest load finished.
 
         if (mOnlyCheckUpdate) {
@@ -1802,35 +1803,16 @@ nsOfflineCacheUpdate::Begin()
     nsresult rv = mManifestItem->OpenChannel(this);
     if (NS_FAILED(rv)) {
         LoadCompleted(mManifestItem);
     }
 
     return NS_OK;
 }
 
-nsresult
-nsOfflineCacheUpdate::Cancel()
-{
-    LOG(("nsOfflineCacheUpdate::Cancel [%p]", this));
-
-    mState = STATE_CANCELLED;
-    mSucceeded = false;
-
-    // Cancel all running downloads
-    for (uint32_t i = 0; i < mItems.Length(); ++i) {
-        nsOfflineCacheUpdateItem * item = mItems[i];
-
-        if (item->IsInProgress())
-            item->Cancel();
-    }
-
-    return NS_OK;
-}
-
 //-----------------------------------------------------------------------------
 // nsOfflineCacheUpdate <private>
 //-----------------------------------------------------------------------------
 
 nsresult
 nsOfflineCacheUpdate::AddExistingItems(uint32_t aType,
                                        nsTArray<nsCString>* namespaceFilter)
 {
@@ -1878,19 +1860,16 @@ nsresult
 nsOfflineCacheUpdate::ProcessNextURI()
 {
     // Keep the object alive through a Finish() call.
     nsCOMPtr<nsIOfflineCacheUpdate> kungFuDeathGrip(this);
 
     LOG(("nsOfflineCacheUpdate::ProcessNextURI [%p, inprogress=%d, numItems=%d]",
          this, mItemsInProgress, mItems.Length()));
 
-    NS_ASSERTION(mState == STATE_DOWNLOADING,
-                 "ProcessNextURI should only be called from the DOWNLOADING state");
-
     if (mState != STATE_DOWNLOADING) {
         LOG(("  should only be called from the DOWNLOADING state, ignoring"));
         return NS_ERROR_UNEXPECTED;
     }
 
     nsOfflineCacheUpdateItem * runItem = nullptr;
     uint32_t completedItems = 0;
     for (uint32_t i = 0; i < mItems.Length(); ++i) {
@@ -2357,16 +2336,39 @@ nsOfflineCacheUpdate::AddDynamicURI(nsIU
             return NS_OK;
         }
     }
 
     return AddURI(aURI, nsIApplicationCache::ITEM_DYNAMIC);
 }
 
 NS_IMETHODIMP
+nsOfflineCacheUpdate::Cancel()
+{
+    LOG(("nsOfflineCacheUpdate::Cancel [%p]", this));
+
+    if ((mState == STATE_FINISHED) || (mState == STATE_CANCELLED)) {
+      return NS_ERROR_NOT_AVAILABLE;
+    }
+
+    mState = STATE_CANCELLED;
+    mSucceeded = false;
+
+    // Cancel all running downloads
+    for (uint32_t i = 0; i < mItems.Length(); ++i) {
+        nsOfflineCacheUpdateItem * item = mItems[i];
+
+        if (item->IsInProgress())
+            item->Cancel();
+    }
+
+    return NS_OK;
+}
+
+NS_IMETHODIMP
 nsOfflineCacheUpdate::AddObserver(nsIOfflineCacheUpdateObserver *aObserver,
                                   bool aHoldWeak)
 {
     LOG(("nsOfflineCacheUpdate::AddObserver [%p] to update [%p]", aObserver, this));
 
     NS_ENSURE_TRUE(mState >= STATE_INITIALIZED, NS_ERROR_NOT_INITIALIZED);
 
     if (aHoldWeak) {
--- a/uriloader/prefetch/nsOfflineCacheUpdate.h
+++ b/uriloader/prefetch/nsOfflineCacheUpdate.h
@@ -196,17 +196,16 @@ public:
     nsOfflineCacheUpdate();
     ~nsOfflineCacheUpdate();
 
     static nsresult GetCacheKey(nsIURI *aURI, nsACString &aKey);
 
     nsresult Init();
 
     nsresult Begin();
-    nsresult Cancel();
 
     void LoadCompleted(nsOfflineCacheUpdateItem *aItem);
     void ManifestCheckCompleted(nsresult aStatus,
                                 const nsCString &aManifestHash);
     void StickDocument(nsIURI *aDocumentURI);
 
     void SetOwner(nsOfflineCacheUpdateOwner *aOwner);
 
--- a/widget/gonk/OrientationObserver.cpp
+++ b/widget/gonk/OrientationObserver.cpp
@@ -195,17 +195,17 @@ OrientationObserver::ShutDown()
 
 void
 OrientationObserver::Notify(const hal::SensorData& aSensorData)
 {
   // Sensor will call us on the main thread.
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aSensorData.sensor() == hal::SensorType::SENSOR_ORIENTATION);
 
-  InfallibleTArray<float> values = aSensorData.values();
+  const InfallibleTArray<float>& values = aSensorData.values();
   // Azimuth (values[0]): the device's horizontal orientation
   // (0 degree is north). It's unused for screen rotation.
   float pitch = values[1];
   float roll = values[2];
 
   uint32_t rotation;
   if (roll > 45) {
     rotation = nsIScreen::ROTATION_90_DEG;
--- a/xpcom/glue/Makefile.in
+++ b/xpcom/glue/Makefile.in
@@ -64,16 +64,17 @@ SDK_HEADERS = \
 		nsMemory.h \
 		nsQuickSort.h \
 		nsRefPtrHashtable.h \
 		nsServiceManagerUtils.h \
 		nsStringAPI.h \
 		nsStringGlue.h \
 		nsTArray.h \
 		nsTArray-inl.h \
+		nsTArrayForwardDeclare.h \
 		nsTHashtable.h \
 		nsTObserverArray.h \
 		nsTWeakRef.h \
 		nsTextFormatter.h \
 		nsTraceRefcnt.h \
 		nsVersionComparator.h \
 		nsVoidArray.h \
 		nsWeakReference.h \
--- a/xpcom/glue/nsTArray-inl.h
+++ b/xpcom/glue/nsTArray-inl.h
@@ -365,17 +365,17 @@ nsTArray_base<Alloc>::SwapArrayElements(
     largerElements = Hdr() + 1;
   }
 
   // Allocate temporary storage for the smaller of the two arrays.  We want to
   // allocate this space on the stack, if it's not too large.  Sounds like a
   // job for AutoTArray!  (One of the two arrays we're swapping is using an
   // auto buffer, so we're likely not allocating a lot of space here.  But one
   // could, in theory, allocate a huge AutoTArray on the heap.)
-  nsAutoTArray<uint8_t, 64, Alloc> temp;
+  nsAutoArrayBase<nsTArray_Impl<uint8_t, Alloc>, 64> temp;
   if (!temp.SetCapacity(smallerLength * elemSize)) {
     return false;
   }
 
   memcpy(temp.Elements(), smallerElements, smallerLength * elemSize);
   memcpy(smallerElements, largerElements, largerLength * elemSize);
   memcpy(largerElements, temp.Elements(), smallerLength * elemSize);
 
--- a/xpcom/glue/nsTArray.h
+++ b/xpcom/glue/nsTArray.h
@@ -2,41 +2,85 @@
 /* vim:set ts=2 sw=2 sts=2 et cindent: */
 /* 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 nsTArray_h__
 #define nsTArray_h__
 
+#include "nsTArrayForwardDeclare.h"
 #include "mozilla/Assertions.h"
 #include "mozilla/Util.h"
 
 #include <string.h>
 
 #include "nsCycleCollectionNoteChild.h"
 #include "nsAlgorithm.h"
 #include "nscore.h"
 #include "nsQuickSort.h"
 #include "nsDebug.h"
 #include "nsTraceRefcnt.h"
 #include NEW_H
 
 //
-// NB: nsTArray assumes that your "T" can be memmove()d.  This is in
-// contrast to STL containers, which follow C++
-// construction/destruction rules.
+// nsTArray is a resizable array class, like std::vector.
+//
+// Unlike std::vector, which follows C++'s construction/destruction rules,
+// nsTArray assumes that your "T" can be memmoved()'ed safely.
+//
+// The public classes defined in this header are
+//
+//   nsTArray<T>,
+//   FallibleTArray<T>,
+//   nsAutoTArray<T, N>, and
+//   AutoFallibleTArray<T, N>.
+//
+// nsTArray and nsAutoTArray are infallible; if one tries to make an allocation
+// which fails, it crashes the program.  In contrast, FallibleTArray and
+// AutoFallibleTArray are fallible; if you use one of these classes, you must
+// check the return values of methods such as Append() which may allocate.  If
+// in doubt, choose an infallible type.
+//
+// InfallibleTArray and AutoInfallibleTArray are aliases for nsTArray and
+// nsAutoTArray.
 //
-// Don't use nsTArray if your "T" can't be memmove()d correctly.
+// If you just want to declare the nsTArray types (e.g., if you're in a header
+// file and don't need the full nsTArray definitions) consider including
+// nsTArrayForwardDeclare.h instead of nsTArray.h.
+//
+// The template parameter (i.e., T in nsTArray<T>) specifies the type of the
+// elements and has the following requirements:
+//
+//   T MUST be safely memmove()'able.
+//   T MUST define a copy-constructor.
+//   T MAY define operator< for sorting.
+//   T MAY define operator== for searching.
+//
+// For methods taking a Comparator instance, the Comparator must be a class
+// defining the following methods:
+//
+//   class Comparator {
+//     public:
+//       /** @return True if the elements are equals; false otherwise. */
+//       bool Equals(const elem_type& a, const Item& b) const;
+//
+//       /** @return True if (a < b); false otherwise. */
+//       bool LessThan(const elem_type& a, const Item& b) const;
+//   };
+//
+// The Equals method is used for searching, and the LessThan method is used for
+// searching and sorting.  The |Item| type above can be arbitrary, but must
+// match the Item type passed to the sort or search function.
 //
 
+
 //
-// nsTArray*Allocators must all use the same |free()|, to allow
-// swapping between fallible and infallible variants.  (NS_Free() and
-// moz_free() end up calling the same underlying free()).
+// nsTArray*Allocators must all use the same |free()|, to allow swap()'ing
+// between fallible and infallible variants.
 //
 
 #if defined(MOZALLOC_HAVE_XMALLOC)
 #include "mozilla/mozalloc_abort.h"
 
 struct nsTArrayFallibleAllocator
 {
   static void* Malloc(size_t size) {
@@ -70,18 +114,18 @@ struct nsTArrayInfallibleAllocator
   }
 
   static void SizeTooBig() {
     mozalloc_abort("Trying to allocate an infallible array that's too big");
   }
 };
 
 #else
+#include <stdlib.h>
 
-#include <stdlib.h>
 struct nsTArrayFallibleAllocator
 {
   static void* Malloc(size_t size) {
     return malloc(size);
   }
 
   static void* Realloc(void* ptr, size_t size) {
     return realloc(ptr, size);
@@ -90,22 +134,50 @@ struct nsTArrayFallibleAllocator
   static void Free(void* ptr) {
     free(ptr);
   }
 
   static void SizeTooBig() {
   }
 };
 
-#endif
+struct nsTArrayInfallibleAllocator
+{
+  static void* Malloc(size_t size) {
+    void* ptr = malloc(size);
+    if (MOZ_UNLIKELY(!ptr)) {
+      HandleOOM();
+    }
+    return ptr;
+  }
 
-#if defined(MOZALLOC_HAVE_XMALLOC)
-struct nsTArrayDefaultAllocator : public nsTArrayInfallibleAllocator { };
-#else
-struct nsTArrayDefaultAllocator : public nsTArrayFallibleAllocator { };
+  static void* Realloc(void* ptr, size_t size) {
+    void* newptr = realloc(ptr, size);
+    if (MOZ_UNLIKELY(!ptr && size)) {
+      HandleOOM();
+    }
+    return newptr;
+  }
+
+  static void Free(void* ptr) {
+    free(ptr);
+  }
+
+  static void SizeTooBig() {
+    HandleOOM();
+  }
+
+private:
+  static void HandleOOM() {
+    fputs("Out of memory allocating nsTArray buffer.\n", stderr);
+    MOZ_CRASH();
+    MOZ_NOT_REACHED();
+  }
+};
+
 #endif
 
 // nsTArray_base stores elements into the space allocated beyond
 // sizeof(*this).  This is done to minimize the size of the nsTArray
 // object when it is empty.
 struct NS_COM_GLUE nsTArrayHeader
 {
   static nsTArrayHeader sEmptyHdr;
@@ -369,63 +441,41 @@ public:
   bool Equals(const A& a, const B& b) const {
     return a == b;
   }
   bool LessThan(const A& a, const B& b) const {
     return a < b;
   }
 };
 
-//
-// The templatized array class that dynamically resizes its storage as
-// elements are added.  This class is designed to behave a bit like
-// std::vector, though note that unlike std::vector, nsTArray doesn't
-// follow C++ construction/destruction rules.
+template <class E> class InfallibleTArray;
+template <class E> class FallibleTArray;
+
 //
-// The template parameter specifies the type of the elements (elem_type), and
-// has the following requirements:
-//
-//   elem_type MUST define a copy-constructor.
-//   elem_type MAY define operator< for sorting.
-//   elem_type MAY define operator== for searching.
-//
-// For methods taking a Comparator instance, the Comparator must be a class
-// defining the following methods:
+// nsTArray_Impl contains most of the guts supporting nsTArray, FallibleTArray,
+// nsAutoTArray, and AutoFallibleTArray.
 //
-//   class Comparator {
-//     public:
-//       /** @return True if the elements are equals; false otherwise. */
-//       bool Equals(const elem_type& a, const Item& b) const;
-//
-//       /** @return True if (a < b); false otherwise. */
-//       bool LessThan(const elem_type& a, const Item& b) const;
-//   };
+// The only situation in which you might need to use nsTArray_Impl in your code
+// is if you're writing code which mutates a TArray which may or may not be
+// infallible.
 //
-// The Equals method is used for searching, and the LessThan method is used
-// for sorting.  The |Item| type above can be arbitrary, but must match the
-// Item type passed to the sort or search function.
+// Code which merely reads from a TArray which may or may not be infallible can
+// simply cast the TArray to |const nsTArray&|; both fallible and infallible
+// TArrays can be cast to |const nsTArray&|.
 //
-// The Alloc template parameter can be used to choose between
-// "fallible" and "infallible" nsTArray (if available), defaulting to
-// fallible.  If the *fallible* allocator is used, the return value of
-// methods that might allocate needs to be checked; Append() is
-// one such method.  These return values don't need to be checked if
-// the *in*fallible allocator is chosen.  When in doubt, choose the
-// infallible allocator.
-//
-template<class E, class Alloc=nsTArrayDefaultAllocator>
-class nsTArray : public nsTArray_base<Alloc>,
-                 public nsTArray_SafeElementAtHelper<E, nsTArray<E, Alloc> >
+template<class E, class Alloc>
+class nsTArray_Impl : public nsTArray_base<Alloc>,
+                      public nsTArray_SafeElementAtHelper<E, nsTArray_Impl<E, Alloc> >
 {
 public:
   typedef nsTArray_base<Alloc>           base_type;
   typedef typename base_type::size_type  size_type;
   typedef typename base_type::index_type index_type;
   typedef E                              elem_type;
-  typedef nsTArray<E, Alloc>             self_type;
+  typedef nsTArray_Impl<E, Alloc>        self_type;
   typedef nsTArrayElementTraits<E>       elem_traits;
   typedef nsTArray_SafeElementAtHelper<E, self_type> safeelementat_helper_type;
 
   using safeelementat_helper_type::SafeElementAt;
   using base_type::EmptyHdr;
 
   // A special value that is used to indicate an invalid or unknown index
   // into the array.
@@ -434,52 +484,74 @@ public:
   };
 
   using base_type::Length;
 
   //
   // Finalization method
   //
 
-  ~nsTArray() { Clear(); }
+  ~nsTArray_Impl() { Clear(); }
 
   //
   // Initialization methods
   //
 
-  nsTArray() {}
+  nsTArray_Impl() {}
 
   // Initialize this array and pre-allocate some number of elements.
-  explicit nsTArray(size_type capacity) {
+  explicit nsTArray_Impl(size_type capacity) {
     SetCapacity(capacity);
   }
 
   // The array's copy-constructor performs a 'deep' copy of the given array.
   // @param other  The array object to copy.
-  explicit nsTArray(const self_type& other) {
+  //
+  // It's very important that we declare this method as taking |const
+  // self_type&| as opposed to taking |const nsTArray_Impl<E, OtherAlloc>| for
+  // an arbitrary OtherAlloc.
+  //
+  // If we don't declare a constructor taking |const self_type&|, C++ generates
+  // a copy-constructor for this class which merely copies the object's
+  // members, which is obviously wrong.
+  //
+  // You can pass an nsTArray_Impl<E, OtherAlloc> to this method because
+  // nsTArray_Impl<E, X> can be cast to const nsTArray_Impl<E, Y>&.  So the
+  // effect on the API is the same as if we'd declared this method as taking
+  // |const nsTArray_Impl<E, OtherAlloc>&|.
+  explicit nsTArray_Impl(const self_type& other) {
     AppendElements(other);
   }
 
+  // Allow converting to a const array with a different kind of allocator,
+  // Since the allocator doesn't matter for const arrays
   template<typename Allocator>
-  explicit nsTArray(const nsTArray<E, Allocator>& other) {
-    AppendElements(other);
+  operator const nsTArray_Impl<E, Allocator>&() const {
+    return *reinterpret_cast<const nsTArray_Impl<E, Allocator>*>(this);
+  }
+  // And we have to do this for our subclasses too
+  operator const nsTArray<E>&() const {
+    return *reinterpret_cast<const InfallibleTArray<E>*>(this);
+  }
+  operator const FallibleTArray<E>&() const {
+    return *reinterpret_cast<const FallibleTArray<E>*>(this);
   }
 
   // The array's assignment operator performs a 'deep' copy of the given
   // array.  It is optimized to reuse existing storage if possible.
   // @param other  The array object to copy.
-  nsTArray& operator=(const self_type& other) {
+  self_type& operator=(const self_type& other) {
     ReplaceElementsAt(0, Length(), other.Elements(), other.Length());
     return *this;
   }
 
   // Return true if this array has the same length and the same
   // elements as |other|.
   template<typename Allocator>
-  bool operator==(const nsTArray<E, Allocator>& other) const {
+  bool operator==(const nsTArray_Impl<E, Allocator>& other) const {
     size_type len = Length();
     if (len != other.Length())
       return false;
 
     // XXX std::equal would be as fast or faster here
     for (index_type i = 0; i < len; ++i)
       if (!(operator[](i) == other[i]))
         return false;
@@ -489,30 +561,30 @@ public:
 
   // Return true if this array does not have the same length and the same
   // elements as |other|.
   bool operator!=(const self_type& other) const {
     return !operator==(other);
   }
 
   template<typename Allocator>
-  nsTArray& operator=(const nsTArray<E, Allocator>& other) {
+  self_type& operator=(const nsTArray_Impl<E, Allocator>& other) {
     ReplaceElementsAt(0, Length(), other.Elements(), other.Length());
     return *this;
   }
 
-  // @return The amount of memory used by this nsTArray, excluding
+  // @return The amount of memory used by this nsTArray_Impl, excluding
   // sizeof(*this).
   size_t SizeOfExcludingThis(nsMallocSizeOfFun mallocSizeOf) const {
     if (this->UsesAutoArrayBuffer() || Hdr() == EmptyHdr())
       return 0;
     return mallocSizeOf(this->Hdr());
   }
 
-  // @return The amount of memory used by this nsTArray, including
+  // @return The amount of memory used by this nsTArray_Impl, including
   // sizeof(*this).
   size_t SizeOfIncludingThis(nsMallocSizeOfFun mallocSizeOf) const {
     return mallocSizeOf(this) + SizeOfExcludingThis(mallocSizeOf);
   }
 
   //
   // Accessor methods
   //
@@ -760,18 +832,18 @@ public:
   // A variation on the ReplaceElementsAt method defined above.
   template<class Item>
   elem_type *InsertElementsAt(index_type index, const Item* array,
                               size_type arrayLen) {
     return ReplaceElementsAt(index, 0, array, arrayLen);
   }
 
   // A variation on the ReplaceElementsAt method defined above.
-  template<class Item>
-  elem_type *InsertElementsAt(index_type index, const nsTArray<Item>& array) {
+  template<class Item, class Allocator>
+  elem_type *InsertElementsAt(index_type index, const nsTArray_Impl<Item, Allocator>& array) {
     return ReplaceElementsAt(index, 0, array.Elements(), array.Length());
   }
 
   // A variation on the ReplaceElementsAt method defined above.
   template<class Item>
   elem_type *InsertElementAt(index_type index, const Item& item) {
     return ReplaceElementsAt(index, 0, &item, 1);
   }
@@ -881,17 +953,17 @@ public:
     index_type len = Length();
     AssignRange(len, arrayLen, array);
     this->IncrementLength(arrayLen);
     return Elements() + len;
   }
 
   // A variation on the AppendElements method defined above.
   template<class Item, class Allocator>
-  elem_type *AppendElements(const nsTArray<Item, Allocator>& array) {
+  elem_type *AppendElements(const nsTArray_Impl<Item, Allocator>& array) {
     return AppendElements(array.Elements(), array.Length());
   }
 
   // A variation on the AppendElements method defined above.
   template<class Item>
   elem_type *AppendElement(const Item& item) {
     return AppendElements(&item, 1);
   }
@@ -917,17 +989,17 @@ public:
   elem_type *AppendElement() {
     return AppendElements(1);
   }
 
   // Move all elements from another array to the end of this array without 
   // calling copy constructors or destructors.
   // @return A pointer to the newly appended elements, or null on OOM.
   template<class Item, class Allocator>
-  elem_type *MoveElementsFrom(nsTArray<Item, Allocator>& array) {
+  elem_type *MoveElementsFrom(nsTArray_Impl<Item, Allocator>& array) {
     MOZ_ASSERT(&array != this, "argument must be different array");
     index_type len = Length();
     index_type otherLen = array.Length();
     if (!this->EnsureCapacity(len + otherLen, sizeof(elem_type)))
       return nullptr;
     memcpy(Elements() + len, array.Elements(), otherLen * sizeof(elem_type));
     this->IncrementLength(otherLen);      
     array.ShiftData(0, otherLen, 0, sizeof(elem_type), MOZ_ALIGNOF(elem_type));
@@ -997,17 +1069,17 @@ public:
   template<class Item>
   bool RemoveElementSorted(const Item& item) {
     return RemoveElementSorted(item, nsDefaultComparator<elem_type, Item>());
   }
 
   // This method causes the elements contained in this array and the given
   // array to be swapped.
   template<class Allocator>
-  bool SwapElements(nsTArray<E, Allocator>& other) {
+  bool SwapElements(nsTArray_Impl<E, Allocator>& other) {
     return this->SwapArrayElements(other, sizeof(elem_type), MOZ_ALIGNOF(elem_type));
   }
 
   //
   // Allocation
   //
 
   // This method may increase the capacity of this array object by the
@@ -1113,17 +1185,17 @@ public:
   }
 
   //
   // Sorting
   //
  
   // This function is meant to be used with the NS_QuickSort function.  It
   // maps the callback API expected by NS_QuickSort to the Comparator API
-  // used by nsTArray.  See nsTArray::Sort.
+  // used by nsTArray_Impl.  See nsTArray_Impl::Sort.
   template<class Comparator>
   static int Compare(const void* e1, const void* e2, void *data) {
     const Comparator* c = reinterpret_cast<const Comparator*>(data);
     const elem_type* a = static_cast<const elem_type*>(e1);
     const elem_type* b = static_cast<const elem_type*>(e2);
     return c->LessThan(*a, *b) ? -1 : (c->Equals(*a, *b) ? 0 : 1);
   }
 
@@ -1267,115 +1339,93 @@ protected:
       elem[parent_index] = elem[index];
     }
     elem[index] = item;
   }
 };
 
 template <typename E, typename Alloc>
 inline void
-ImplCycleCollectionUnlink(nsTArray<E, Alloc>& aField)
+ImplCycleCollectionUnlink(nsTArray_Impl<E, Alloc>& aField)
 {
   aField.Clear();
 }
 
 template <typename E, typename Alloc>
 inline void
 ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback,
-                            nsTArray<E, Alloc>& aField,
+                            nsTArray_Impl<E, Alloc>& aField,
                             const char* aName,
                             uint32_t aFlags = 0)
 {
   aFlags |= CycleCollectionEdgeNameArrayFlag;
   size_t length = aField.Length();
   for (size_t i = 0; i < length; ++i) {
     ImplCycleCollectionTraverse(aCallback, aField[i], aName, aFlags);
   }
 }
 
 //
-// Convenience subtypes of nsTArray.
+// nsTArray is an infallible vector class.  See the comment at the top of this
+// file for more details.
 //
 template <class E>
-class FallibleTArray : public nsTArray<E, nsTArrayFallibleAllocator>
+class nsTArray : public nsTArray_Impl<E, nsTArrayInfallibleAllocator>
 {
 public:
-  typedef nsTArray<E, nsTArrayFallibleAllocator>   base_type;
-  typedef typename base_type::size_type            size_type;
+  typedef nsTArray_Impl<E, nsTArrayInfallibleAllocator> base_type;
+  typedef nsTArray<E>                                   self_type;
+  typedef typename base_type::size_type                 size_type;
+
+  nsTArray() {}
+  explicit nsTArray(size_type capacity) : base_type(capacity) {}
+  explicit nsTArray(const nsTArray& other) : base_type(other) {}
+
+  template<class Allocator>
+  explicit nsTArray(const nsTArray_Impl<E, Allocator>& other) : base_type(other) {}
+};
+
+//
+// FallibleTArray is a fallible vector class.
+//
+template <class E>
+class FallibleTArray : public nsTArray_Impl<E, nsTArrayFallibleAllocator>
+{
+public:
+  typedef nsTArray_Impl<E, nsTArrayFallibleAllocator>   base_type;
+  typedef FallibleTArray<E>                             self_type;
+  typedef typename base_type::size_type                 size_type;
 
   FallibleTArray() {}
   explicit FallibleTArray(size_type capacity) : base_type(capacity) {}
-  FallibleTArray(const FallibleTArray& other) : base_type(other) {}
+  explicit FallibleTArray(const FallibleTArray<E>& other) : base_type(other) {}
+
+  template<class Allocator>
+  explicit FallibleTArray(const nsTArray_Impl<E, Allocator>& other) : base_type(other) {}
 };
 
-template <typename E>
-inline void
-ImplCycleCollectionUnlink(FallibleTArray<E>& aField)
-{
-  aField.Clear();
-}
-
-template <typename E>
-inline void
-ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback,
-                            FallibleTArray<E>& aField,
-                            const char* aName,
-                            uint32_t aFlags = 0)
-{
-  aFlags |= CycleCollectionEdgeNameArrayFlag;
-  size_t length = aField.Length();
-  for (size_t i = 0; i < length; ++i) {
-    ImplCycleCollectionTraverse(aCallback, aField[i], aName, aFlags);
-  }
-}
-
-
-#ifdef MOZALLOC_HAVE_XMALLOC
-template <class E>
-class InfallibleTArray : public nsTArray<E, nsTArrayInfallibleAllocator>
-{
-public:
-  typedef nsTArray<E, nsTArrayInfallibleAllocator> base_type;
-  typedef typename base_type::size_type            size_type;
- 
-  InfallibleTArray() {}
-  explicit InfallibleTArray(size_type capacity) : base_type(capacity) {}
-  InfallibleTArray(const InfallibleTArray& other) : base_type(other) {}
-};
-
-template <typename E>
-inline void ImplCycleCollectionUnlink(InfallibleTArray<E>& aField)
-{
-  aField.Clear();
-}
-
-template <typename E>
-inline void
-ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback,
-                            InfallibleTArray<E>& aField,
-                            const char* aName,
-                            uint32_t aFlags = 0)
-{
-  aFlags |= CycleCollectionEdgeNameArrayFlag;
-  size_t length = aField.Length();
-  for (size_t i = 0; i < length; ++i) {
-    ImplCycleCollectionTraverse(aCallback, aField[i], aName, aFlags);
-  }
-}
-
-#endif
-
+//
+// nsAutoArrayBase is a base class for AutoFallibleTArray and nsAutoTArray.
+// You shouldn't use this class directly.
+//
 template <class TArrayBase, uint32_t N>
 class nsAutoArrayBase : public TArrayBase
 {
 public:
+  typedef nsAutoArrayBase<TArrayBase, N> self_type;
   typedef TArrayBase base_type;
   typedef typename base_type::Header Header;
   typedef typename base_type::elem_type elem_type;
 
+  template<typename Allocator>
+  self_type& operator=(const nsTArray_Impl<elem_type, Allocator>& other) {
+    base_type::operator=(other);
+    return *this;
+  }
+
 protected:
   nsAutoArrayBase() {
     Init();
   }
 
   // We need this constructor because nsAutoTArray and friends all have
   // implicit copy-constructors.  If we don't have this method, those
   // copy-constructors will call nsAutoArrayBase's implicit copy-constructor,
@@ -1414,28 +1464,64 @@ private:
   union {
     char mAutoBuf[sizeof(nsTArrayHeader) + N * sizeof(elem_type)];
     // Do the max operation inline to ensure that it is a compile-time constant.
     mozilla::AlignedElem<(MOZ_ALIGNOF(Header) > MOZ_ALIGNOF(elem_type))
                          ? MOZ_ALIGNOF(Header) : MOZ_ALIGNOF(elem_type)> mAlign;
   };
 };
 
-template<class E, uint32_t N, class Alloc=nsTArrayDefaultAllocator>
-class nsAutoTArray : public nsAutoArrayBase<nsTArray<E, Alloc>, N>
+//
+// nsAutoTArray<E, N> is an infallible vector class with N elements of inline
+// storage.  If you try to store more than N elements inside an
+// nsAutoTArray<E, N>, we'll call malloc() and store them all on the heap.
+//
+// Note that you can cast an nsAutoTArray<E, N> to
+// |const AutoFallibleTArray<E, N>&|.
+//
+template<class E, uint32_t N>
+class nsAutoTArray : public nsAutoArrayBase<nsTArray<E>, N>
 {
-  typedef nsAutoArrayBase<nsTArray<E, Alloc>, N> Base;
+  typedef nsAutoTArray<E, N> self_type;
+  typedef nsAutoArrayBase<nsTArray<E>, N> Base;
 
 public:
   nsAutoTArray() {}
 
   template<typename Allocator>
-  nsAutoTArray(const nsTArray<E, Allocator>& other) {
+  explicit nsAutoTArray(const nsTArray_Impl<E, Allocator>& other) {
     Base::AppendElements(other);
   }
+
+  operator const AutoFallibleTArray<E, N>&() const {
+    return *reinterpret_cast<const AutoFallibleTArray<E, N>*>(this);
+  }
+};
+
+//
+// AutoFallibleTArray<E, N> is a fallible vector class with N elements of
+// inline storage.
+//
+template<class E, uint32_t N>
+class AutoFallibleTArray : public nsAutoArrayBase<FallibleTArray<E>, N>
+{
+  typedef AutoFallibleTArray<E, N> self_type;
+  typedef nsAutoArrayBase<FallibleTArray<E>, N> Base;
+
+public:
+  AutoFallibleTArray() {}
+
+  template<typename Allocator>
+  explicit AutoFallibleTArray(const nsTArray_Impl<E, Allocator>& other) {
+    Base::AppendElements(other);
+  }
+
+  operator const nsAutoTArray<E, N>&() const {
+    return *reinterpret_cast<const nsAutoTArray<E, N>*>(this);
+  }
 };
 
 // Assert that nsAutoTArray doesn't have any extra padding inside.
 //
 // It's important that the data stored in this auto array takes up a multiple of
 // 8 bytes; e.g. nsAutoTArray<uint32_t, 1> wouldn't work.  Since nsAutoTArray
 // contains a pointer, its size must be a multiple of alignof(void*).  (This is
 // because any type may be placed into an array, and there's no padding between
@@ -1446,70 +1532,12 @@ public:
 // 64-bit system, where the compiler inserts 4 bytes of padding at the end of
 // the auto array to make its size a multiple of alignof(void*) == 8 bytes.
 
 MOZ_STATIC_ASSERT(sizeof(nsAutoTArray<uint32_t, 2>) ==
                   sizeof(void*) + sizeof(nsTArrayHeader) + sizeof(uint32_t) * 2,
                   "nsAutoTArray shouldn't contain any extra padding, "
                   "see the comment");
 
-template<class E, uint32_t N>
-class AutoFallibleTArray : public nsAutoArrayBase<FallibleTArray<E>, N>
-{
-  typedef nsAutoArrayBase<FallibleTArray<E>, N> Base;
-
-public:
-  AutoFallibleTArray() {}
-
-  template<typename Allocator>
-  AutoFallibleTArray(const nsTArray<E, Allocator>& other) {
-    Base::AppendElements(other);
-  }
-};
-
-#if defined(MOZALLOC_HAVE_XMALLOC)
-template<class E, uint32_t N>
-class AutoInfallibleTArray : public nsAutoArrayBase<InfallibleTArray<E>, N>
-{
-  typedef nsAutoArrayBase<InfallibleTArray<E>, N> Base;
-
-public:
-  AutoInfallibleTArray() {}
-
-  template<typename Allocator>
-  AutoInfallibleTArray(const nsTArray<E, Allocator>& other) {
-    Base::AppendElements(other);
-  }
-};
-#endif
-
-// specializations for N = 0. this makes the inheritance model easier for
-// templated users of nsAutoTArray.
-template<class E>
-class nsAutoTArray<E, 0, nsTArrayDefaultAllocator> :
-  public nsAutoArrayBase< nsTArray<E, nsTArrayDefaultAllocator>, 0>
-{
-public:
-  nsAutoTArray() {}
-};
-
-template<class E>
-class AutoFallibleTArray<E, 0> :
-  public nsAutoArrayBase< FallibleTArray<E>, 0>
-{
-public:
-  AutoFallibleTArray() {}
-};
-
-#if defined(MOZALLOC_HAVE_XMALLOC)
-template<class E>
-class AutoInfallibleTArray<E, 0> :
-  public nsAutoArrayBase< InfallibleTArray<E>, 0>
-{
-public:
-  AutoInfallibleTArray() {}
-};
-#endif
- 
-// Definitions of nsTArray methods
+// Definitions of nsTArray_Impl methods
 #include "nsTArray-inl.h"
 
 #endif  // nsTArray_h__
new file mode 100644
--- /dev/null
+++ b/xpcom/glue/nsTArrayForwardDeclare.h
@@ -0,0 +1,39 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* 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 nsTArrayForwardDeclare_h__
+#define nsTArrayForwardDeclare_h__
+
+//
+// This simple header file contains forward declarations for the TArray family
+// of classes.
+//
+// Including this header is preferable to writing
+//
+//   template<class E> class nsTArray;
+//
+// yourself, since this header gives us flexibility to e.g. change the default
+// template parameters.
+//
+
+#include "mozilla/StandardInteger.h"
+
+template<class E>
+class nsTArray;
+
+template<class E>
+class FallibleTArray;
+
+template<class E, uint32_t N>
+class nsAutoTArray;
+
+template<class E, uint32_t N>
+class AutoFallibleTArray;
+
+#define InfallibleTArray nsTArray
+#define AutoInfallibleTArray nsAutoTArray
+
+#endif
--- a/xpcom/tests/TestTArray.cpp
+++ b/xpcom/tests/TestTArray.cpp
@@ -866,16 +866,69 @@ static bool test_fallible()
   }
 
   // No OOM?  That's...weird.
   printf("test_fallible: Didn't OOM or crash?  nsTArray::SetCapacity "
          "must be lying.\n");
   return false;
 }
 
+static bool test_conversion_operator() {
+  FallibleTArray<int> f;
+  const FallibleTArray<int> fconst;
+  AutoFallibleTArray<int, 8> fauto;
+  const AutoFallibleTArray<int, 8> fautoconst;
+
+  InfallibleTArray<int> i;
+  const InfallibleTArray<int> iconst;
+  AutoInfallibleTArray<int, 8> iauto;
+  const AutoInfallibleTArray<int, 8> iautoconst;
+
+  nsTArray<int> t;
+  const nsTArray<int> tconst;
+  nsAutoTArray<int, 8> tauto;
+  const nsAutoTArray<int, 8> tautoconst;
+
+#define CHECK_ARRAY_CAST(type)                                 \
+  do {                                                         \
+    const type<int>& z1 = f;                                   \
+    if ((void*)&z1 != (void*)&f) return false;                 \
+    const type<int>& z2 = fconst;                              \
+    if ((void*)&z2 != (void*)&fconst) return false;            \
+    const type<int>& z3 = fauto;                               \
+    if ((void*)&z3 != (void*)&fauto) return false;             \
+    const type<int>& z4 = fautoconst;                          \
+    if ((void*)&z4 != (void*)&fautoconst) return false;        \
+    const type<int>& z5 = i;                                   \
+    if ((void*)&z5 != (void*)&i) return false;                 \
+    const type<int>& z6 = iconst;                              \
+    if ((void*)&z6 != (void*)&iconst) return false;            \
+    const type<int>& z7 = iauto;                               \
+    if ((void*)&z7 != (void*)&iauto) return false;             \
+    const type<int>& z8 = iautoconst;                          \
+    if ((void*)&z8 != (void*)&iautoconst) return false;        \
+    const type<int>& z9 = t;                                   \
+    if ((void*)&z9 != (void*)&t) return false;                 \
+    const type<int>& z10 = tconst;                             \
+    if ((void*)&z10 != (void*)&tconst) return false;           \
+    const type<int>& z11 = tauto;                              \
+    if ((void*)&z11 != (void*)&tauto) return false;            \
+    const type<int>& z12 = tautoconst;                         \
+    if ((void*)&z12 != (void*)&tautoconst) return false;       \
+  } while (0)
+
+  CHECK_ARRAY_CAST(FallibleTArray);
+  CHECK_ARRAY_CAST(InfallibleTArray);
+  CHECK_ARRAY_CAST(nsTArray);
+
+#undef CHECK_ARRAY_CAST
+
+  return true;
+}
+
 //----
 
 typedef bool (*TestFunc)();
 #define DECL_TEST(name) { #name, name }
 
 static const struct Test {
   const char* name;
   TestFunc    func;
@@ -891,16 +944,17 @@ static const struct Test {
   DECL_TEST(test_ptrarray),
 #ifdef DEBUG
   DECL_TEST(test_autoarray),
 #endif
   DECL_TEST(test_indexof),
   DECL_TEST(test_heap),
   DECL_TEST(test_swap),
   DECL_TEST(test_fallible),
+  DECL_TEST(test_conversion_operator),
   { nullptr, nullptr }
 };
 
 }
 
 using namespace TestTArray;
 
 int main(int argc, char **argv) {