Merge mozilla-central to services-central.
authorRichard Newman <rnewman@mozilla.com>
Mon, 08 Aug 2011 08:16:57 -0700
changeset 74077 3d020dccebbeb3dda8b51a0dc25e9e1df8217d1b
parent 74076 bc57027802ab05974762dfa8a1e030e18bf36fd2 (current diff)
parent 73952 eef25ec2d58e3f7d845438209ba2d95c44f0e441 (diff)
child 74078 a0e3c589c8fad05ab6e67efe7cd4911469561dbf
push id2
push userbsmedberg@mozilla.com
push dateFri, 19 Aug 2011 14:38:13 +0000
milestone8.0a1
Merge mozilla-central to services-central.
browser/branding/aurora/splash.bmp
browser/branding/nightly/splash.bmp
browser/branding/official/splash.bmp
browser/branding/unofficial/splash.bmp
js/src/make_unicode.py
mobile/app/splash.bmp
toolkit/components/places/History.cpp
toolkit/content/tests/widgets/test_arrowpanel.xul
toolkit/xre/nsSplashScreen.h
toolkit/xre/nsSplashScreenDummy.cpp
--- a/accessible/src/base/nsARIAGridAccessible.cpp
+++ b/accessible/src/base/nsARIAGridAccessible.cpp
@@ -101,17 +101,19 @@ nsARIAGridAccessible::GetColumnCount(PRI
 {
   NS_ENSURE_ARG_POINTER(acolumnCount);
   *acolumnCount = 0;
 
   if (IsDefunct())
     return NS_ERROR_FAILURE;
 
   AccIterator rowIter(this, filters::GetRow);
-  nsAccessible *row = rowIter.GetNext();
+  nsAccessible* row = rowIter.GetNext();
+  if (!row)
+    return NS_OK;
 
   AccIterator cellIter(row, filters::GetCell);
   nsAccessible *cell = nsnull;
 
   while ((cell = cellIter.GetNext()))
     (*acolumnCount)++;
 
   return NS_OK;
--- a/accessible/src/base/nsAccessibilityAtomList.h
+++ b/accessible/src/base/nsAccessibilityAtomList.h
@@ -38,17 +38,17 @@
 
 /******
 
   This file contains the list of all accessibility nsIAtoms and their values
 
   It is designed to be used as inline input to nsAccessibilityAtoms.cpp *only*
   through the magic of C preprocessing.
 
-  All entires must be enclosed in the macro ACCESSIBILITY_ATOM which will have cruel
+  All entries must be enclosed in the macro ACCESSIBILITY_ATOM which will have cruel
   and unusual things done to it
 
   It is recommended (but not strictly necessary) to keep all entries
   in alphabetical order
 
   The first argument to ACCESSIBILITY_ATOM is the C++ identifier of the atom
   The second argument is the string value of the atom
 
--- a/accessible/src/base/nsAccessible.cpp
+++ b/accessible/src/base/nsAccessible.cpp
@@ -658,16 +658,21 @@ nsAccessible::IsVisible(PRBool* aIsOffsc
   }
   return isVisible;
 }
 
 PRUint64
 nsAccessible::NativeState()
 {
   PRUint64 state = 0;
+
+  nsDocAccessible* document = GetDocAccessible();
+  if (!document || !document->IsInDocument(this))
+    state |= states::STALE;
+
   PRBool disabled = PR_FALSE;
   if (mContent->IsElement()) {
     nsEventStates elementState = mContent->AsElement()->State();
 
     if (elementState.HasState(NS_EVENT_STATE_INVALID))
       state |= states::INVALID;
 
     if (elementState.HasState(NS_EVENT_STATE_REQUIRED))
--- a/accessible/src/base/nsDocAccessible.h
+++ b/accessible/src/base/nsDocAccessible.h
@@ -230,19 +230,29 @@ public:
    *
    * @return the accessible object
    */
   nsAccessible* GetAccessible(nsINode* aNode) const;
 
   /**
    * Return whether the given DOM node has an accessible or not.
    */
-  inline bool HasAccessible(nsINode* aNode)
+  inline bool HasAccessible(nsINode* aNode) const
+    { return GetAccessible(aNode); }
+
+  /**
+   * Return true if the given accessible is in document.
+   */
+  inline bool IsInDocument(nsAccessible* aAccessible) const
   {
-    return GetAccessible(aNode);
+    nsAccessible* acc = aAccessible;
+    while (acc && !acc->IsPrimaryForNode())
+      acc = acc->Parent();
+
+    return acc ? mNodeToAccessibleMap.Get(acc->GetNode()) : false;
   }
 
   /**
    * Return the cached accessible by the given unique ID within this document.
    *
    * @note   the unique ID matches with the uniqueID() of nsAccessNode
    *
    * @param  aUniqueID  [in] the unique ID used to cache the node.
--- a/accessible/tests/mochitest/relations/test_tabbrowser.xul
+++ b/accessible/tests/mochitest/relations/test_tabbrowser.xul
@@ -19,16 +19,18 @@
           src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" />
 
   <script type="application/javascript"
           src="../common.js" />
   <script type="application/javascript"
           src="../role.js" />
   <script type="application/javascript"
           src="../relations.js" />
+  <script type="application/javascript"
+          src="../events.js" />
 
   <script type="application/javascript" src="chrome://global/content/globalOverlay.js"/>
   <script type="application/javascript">
   <![CDATA[
     ////////////////////////////////////////////////////////////////////////////
     // Test
 
     const Ci = Components.interfaces;
@@ -44,29 +46,38 @@
     var gFindBar = {
       hidden: true
     };
 
     function doTest()
     {
       var tabBrowser = document.getElementById("tabbrowser");
 
-      var progressListener =
-      {
-        onStateChange: function onStateChange(aWebProgress,
-                                              aRequest,
-                                              aStateFlags,
-                                              aStatus)
-       {
-        if (aStateFlags & Ci.nsIWebProgressListener.STATE_STOP)
-          testRelations();
-       }
+      // Load documents into tabs and wait for reorder events caused by these
+      // documents load before we start the test.
+      var docURIs = ["about:", "about:mozilla"];
+
+      var handler = {
+        handleEvent: function handleEvent(aEvent) {
+          var target = aEvent.accessible;
+          if (target.role == ROLE_INTERNAL_FRAME &&
+              target.parent.parent == getAccessible(this.tabBrowser.mTabBox.tabpanels)) {
+            this.reorderCnt++;
+          }
+
+          if (this.reorderCnt == docURIs.length) {
+            unregisterA11yEventListener(EVENT_REORDER, this);
+            testAccTree();
+          }
+        },
+
+        tabBrowser: tabBrowser,
+        reorderCnt: 0
       };
-
-      tabBrowser.addProgressListener(progressListener);
+      registerA11yEventListener(EVENT_REORDER, handler);
 
       tabBrowser.loadTabs(["about:", "about:mozilla"], false, true);
     }
 
     function testRelations()
     {
       //////////////////////////////////////////////////////////////////////////
       // 'labelled by'/'label for' relations for xul:tab and xul:tabpanel
--- a/accessible/tests/mochitest/states/Makefile.in
+++ b/accessible/tests/mochitest/states/Makefile.in
@@ -53,16 +53,17 @@ include $(topsrcdir)/config/rules.mk
 		test_doc.html \
 		test_docarticle.html \
 		test_editablebody.html \
 		test_frames.html \
 		test_inputs.html \
 		test_inputs.xul \
 		test_link.html \
 		test_popup.xul \
+		test_stale.html \
 		test_textbox.xul \
 		test_tree.xul \
 		z_frames.html \
 		z_frames_article.html \
 		z_frames_checkbox.html \
 		z_frames_textbox.html \
 		z_frames_update.html \
 		$(NULL)
new file mode 100644
--- /dev/null
+++ b/accessible/tests/mochitest/states/test_stale.html
@@ -0,0 +1,115 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <title>Stale state testing</title>
+  <link rel="stylesheet" type="text/css"
+        href="chrome://mochikit/content/tests/SimpleTest/test.css" />
+
+  <script type="application/javascript"
+          src="chrome://mochikit/content/MochiKit/packed.js"></script>
+  <script type="application/javascript"
+          src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+
+  <script type="application/javascript"
+          src="../common.js"></script>
+  <script type="application/javascript"
+          src="../states.js"></script>
+  <script type="application/javascript"
+          src="../events.js"></script>
+
+  <script type="application/javascript">
+    function addChild(aContainerID)
+    {
+      this.containerNode = getNode(aContainerID);
+      this.childNode = null;
+
+      this.eventSeq = [
+        new invokerChecker(EVENT_REORDER, this.containerNode)
+      ];
+
+      this.invoke = function addChild_invoke()
+      {
+        this.childNode = document.createElement("div");
+        this.containerNode.appendChild(this.childNode);
+      }
+
+      this.finalCheck = function addChild_finalCheck()
+      {
+        // no stale state should be set
+        testStates(this.childNode, 0, 0, 0, EXT_STATE_STALE);
+      }
+
+      this.getID = function addChild_getID()
+      {
+        return "add child for " + prettyName(aContainerID);
+      }
+    }
+
+    function removeChildChecker(aInvoker)
+    {
+      this.type = EVENT_HIDE;
+      this.__defineGetter__("target", function() { return aInvoker.child; });
+
+      this.check = function removeChildChecker_check()
+      {
+        // stale state should be set
+        testStates(aInvoker.child, 0, EXT_STATE_STALE);
+      }
+    }
+
+    function removeChild(aContainerID)
+    {
+      this.containerNode = getNode(aContainerID);
+      this.child = null;
+
+      this.eventSeq = [
+        new removeChildChecker(this)
+      ];
+
+      this.invoke = function removeChild_invoke()
+      {
+        var childNode = this.containerNode.firstChild;
+        this.child = getAccessible(childNode);
+
+        this.containerNode.removeChild(childNode);
+      }
+
+      this.getID = function removeChild_getID()
+      {
+        return "remove child from " + prettyName(aContainerID);
+      }
+    }
+
+    //gA11yEventDumpToConsole = true; //debugging
+
+    var gQueue = null;
+    function doTest()
+    {
+      gQueue = new eventQueue();
+
+      gQueue.push(new addChild("container"));
+      gQueue.push(new removeChild("container"));
+
+      gQueue.invoke(); // will call SimpleTest.finish()
+    }
+
+    SimpleTest.waitForExplicitFinish();
+    addA11yLoadEvent(doTest);
+  </script>
+</head>
+
+<body role="">
+
+  <a target="_blank"
+     title="Expose stale state on accessibles unattached from tree"
+     href="https://bugzilla.mozilla.org/show_bug.cgi?id=676267">Mozilla Bug 676267</a>
+
+  <p id="display"></p>
+  <div id="content" style="display: none"></div>
+  <pre id="test">
+  </pre>
+
+  <div id="container"></div>
+
+</body>
+</html>
--- a/accessible/tests/mochitest/table.js
+++ b/accessible/tests/mochitest/table.js
@@ -43,17 +43,17 @@ function testTableStruct(aIdentifier, aC
                          aCaption, aSummary, aIsTreeTable)
 {
   var tableNode = getNode(aIdentifier);
   var isGrid = tableNode.getAttribute("role") == "grid" ||
     tableNode.getAttribute("role") == "treegrid" ||
     tableNode.localName == "tree";
 
   var rowCount = aCellsArray.length;
-  var colsCount = aCellsArray[0].length;
+  var colsCount = aCellsArray[0] ? aCellsArray[0].length : 0;
 
   // Test table accessible tree.
   var tableObj = {
     role: aIsTreeTable ? ROLE_TREE_TABLE : ROLE_TABLE,
     children: []
   };
 
   // caption accessible handling
--- a/accessible/tests/mochitest/table/test_struct_ariagrid.html
+++ b/accessible/tests/mochitest/table/test_struct_ariagrid.html
@@ -45,16 +45,24 @@
       // ARIA grid with HTML table elements
       cellsArray = [
         [kColHeaderCell, kColHeaderCell],
         [kDataCell,      kDataCell]
       ];
 
       testTableStruct("grid2", cellsArray);
 
+      //////////////////////////////////////////////////////////////////////////
+      // ARIA grid of wrong markup
+      cellsArray = [ ];
+      testTableStruct("grid3", cellsArray);
+
+      cellsArray = [ [] ];
+      testTableStruct("grid4", cellsArray);
+
       SimpleTest.finish();
     }
 
     SimpleTest.waitForExplicitFinish();
     addA11yLoadEvent(doTest);
   </script>
 </head>
 
@@ -63,16 +71,19 @@
      title="ARIA grid based on HTML table"
      href="https://bugzilla.mozilla.org/show_bug.cgi?id=491683">Mozilla Bug 491683</a>
   <a target="_blank"
      title="implement IAccessibleTable2"
      href="https://bugzilla.mozilla.org/show_bug.cgi?id=512424">Mozilla Bug 512424</a>
   <a target="_blank"
      title="nsHTMLTableCellAccessible is used in dojo's crazy ARIA grid"
      href="https://bugzilla.mozilla.org/show_bug.cgi?id=513848">Mozilla Bug 513848</a>
+  <a target="_blank"
+     title="Crash [@ AccIterator::GetNext()]"
+     href="https://bugzilla.mozilla.org/show_bug.cgi?id=675861">Mozilla Bug 675861</a>
 
   <p id="display"></p>
   <div id="content" style="display: none"></div>
   <pre id="test">
   </pre>
 
   <!-- Not usual markup to avoid text accessible between cell accessibles -->
   <div id="table" role="grid">
@@ -128,10 +139,13 @@
         <tr>
           <td role="gridcell">cell1</td>
           <td role="gridcell" tabindex="-1">cell2</td>
         </tr>
       </table>
     </div>
   </div>
 
+  <!-- Wrong markup ARIA grid -->
+  <div role="grid" id="grid3"></div>
+  <div role="grid" id="grid4"><div role="row"></div></div>
 </body>
 </html>
--- a/accessible/tests/mochitest/tree/test_tabbrowser.xul
+++ b/accessible/tests/mochitest/tree/test_tabbrowser.xul
@@ -18,16 +18,18 @@
           src="chrome://mochikit/content/MochiKit/packed.js" />
   <script type="application/javascript"
           src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" />
 
   <script type="application/javascript"
           src="../common.js" />
   <script type="application/javascript"
           src="../role.js" />
+  <script type="application/javascript"
+          src="../events.js" />
 
   <script type="application/javascript" src="chrome://global/content/globalOverlay.js"/>
   <script type="application/javascript">
   <![CDATA[
     ////////////////////////////////////////////////////////////////////////////
     // Test
 
     const Ci = Components.interfaces;
@@ -42,34 +44,41 @@
     var gFindBar = {
       hidden: true
     };
 
     function doTest()
     {
       var tabBrowser = document.getElementById("tabbrowser");
 
-      var progressListener =
-      {
-        onStateChange: function onStateChange(aWebProgress,
-                                              aRequest,
-                                              aStateFlags,
-                                              aStatus)
-        {
-          if (aStateFlags & Ci.nsIWebProgressListener.STATE_STOP) {
-            tabBrowser.removeProgressListener(progressListener);
+      // Load documents into tabs and wait for reorder events caused by these
+      // documents load before we start the test.
+      var docURIs = ["about:", "about:mozilla"];
 
-            SimpleTest.executeSoon(testAccTree);
+      var handler = {
+        handleEvent: function handleEvent(aEvent) {
+          var target = aEvent.accessible;
+          if (target.role == ROLE_INTERNAL_FRAME &&
+              target.parent.parent == getAccessible(this.tabBrowser.mTabBox.tabpanels)) {
+            this.reorderCnt++;
           }
-        }
+
+          if (this.reorderCnt == docURIs.length) {
+            unregisterA11yEventListener(EVENT_REORDER, this);
+            testAccTree();
+          }
+        },
+
+        tabBrowser: tabBrowser,
+        reorderCnt: 0
       };
-      tabBrowser.addProgressListener(progressListener);
+      registerA11yEventListener(EVENT_REORDER, handler);
 
       // Test XUL and HTML documents.
-      tabBrowser.loadTabs(["about:", "about:mozilla"], false, true);
+      tabBrowser.loadTabs(docURIs, false, true);
     }
 
     function testAccTree()
     {
       var tabBrowser = document.getElementById("tabbrowser");
 
       ////////////////////
       // Tab bar
--- a/browser/app/Makefile.in
+++ b/browser/app/Makefile.in
@@ -200,23 +200,16 @@ endif
 ifeq ($(MOZ_WIDGET_TOOLKIT),gtk2)
 libs::
 	$(INSTALL) $(IFLAGS1) $(DIST)/branding/mozicon128.png $(DIST)/bin/icons
 	$(INSTALL) $(IFLAGS1) $(DIST)/branding/default16.png  $(DIST)/bin/chrome/icons/default
 	$(INSTALL) $(IFLAGS1) $(DIST)/branding/default32.png  $(DIST)/bin/chrome/icons/default
 	$(INSTALL) $(IFLAGS1) $(DIST)/branding/default48.png  $(DIST)/bin/chrome/icons/default
 endif
 
-ifdef MOZ_SPLASHSCREEN
-ifeq ($(MOZ_WIDGET_TOOLKIT),windows)
-libs::
-	$(INSTALL) $(IFLAGS1) $(DIST)/branding/splash.bmp $(DIST)/bin
-endif
-endif
-
 libs:: $(srcdir)/profile/prefs.js
 	$(INSTALL) $(IFLAGS1) $^ $(DIST)/bin/defaults/profile
 
 libs:: $(srcdir)/blocklist.xml
 	$(INSTALL) $(IFLAGS1) $^ $(DIST)/bin
 
 ifeq (cocoa,$(MOZ_WIDGET_TOOLKIT))
 
--- a/browser/app/blocklist.xml
+++ b/browser/app/blocklist.xml
@@ -0,0 +1,213 @@
+<?xml version="1.0"?>
+<blocklist xmlns="http://www.mozilla.org/2006/addons-blocklist" lastupdate="1311096050000">
+  <emItems>
+      <emItem  blockID="i41" id="{99079a25-328f-4bd4-be04-00955acaa0a7}">
+                        <versionRange  minVersion="0.1" maxVersion="4.3.0.00" severity="1">
+                    </versionRange>
+                  </emItem>
+      <emItem  blockID="i8" id="{B13721C7-F507-4982-B2E5-502A71474FED}">
+                        <versionRange  minVersion=" " severity="1">
+                    </versionRange>
+                  </emItem>
+      <emItem  blockID="i38" id="{B7082FAA-CB62-4872-9106-E42DD88EDE45}">
+                        <versionRange  minVersion="0.1" maxVersion="3.3.0.*">
+                      <targetApplication  id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
+                              <versionRange  minVersion="3.7a1" maxVersion="*" />
+                          </targetApplication>
+                    </versionRange>
+                                <versionRange  minVersion="3.3.1" maxVersion="*">
+                      <targetApplication  id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
+                              <versionRange  minVersion="5.0a1" maxVersion="*" />
+                          </targetApplication>
+                    </versionRange>
+                  </emItem>
+      <emItem  blockID="i19" id="{46551EC9-40F0-4e47-8E18-8E5CF550CFB8}">
+                        <versionRange  minVersion="1.1b1" maxVersion="1.1b1">
+                    </versionRange>
+                  </emItem>
+      <emItem  blockID="i16" id="{27182e60-b5f3-411c-b545-b44205977502}">
+                        <versionRange  minVersion="1.0" maxVersion="1.0">
+                    </versionRange>
+                  </emItem>
+      <emItem  blockID="i39" id="{c2d64ff7-0ab8-4263-89c9-ea3b0f8f050c}">
+                        <versionRange  minVersion="0.1" maxVersion="4.3.0.00" severity="1">
+                    </versionRange>
+                  </emItem>
+      <emItem  blockID="i10" id="{8CE11043-9A15-4207-A565-0C94C42D590D}">
+                        </emItem>
+      <emItem  blockID="i1" id="mozilla_cc@internetdownloadmanager.com">
+                        <versionRange  minVersion="2.1" maxVersion="3.3">
+                      <targetApplication  id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
+                              <versionRange  minVersion="3.0a1" maxVersion="*" />
+                          </targetApplication>
+                    </versionRange>
+                                <versionRange  minVersion=" " maxVersion="6.9.8">
+                      <targetApplication  id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
+                              <versionRange  minVersion="3.7a1pre" maxVersion="*" />
+                          </targetApplication>
+                    </versionRange>
+                  </emItem>
+      <emItem  blockID="i18" id="msntoolbar@msn.com">
+                        <versionRange  minVersion=" " maxVersion="6.*">
+                    </versionRange>
+                  </emItem>
+      <emItem  blockID="i13" id="{E8E88AB0-7182-11DF-904E-6045E0D72085}">
+                        </emItem>
+      <emItem  blockID="i4" id="{4B3803EA-5230-4DC3-A7FC-33638F3D3542}">
+                        <versionRange  minVersion="1.2" maxVersion="1.2">
+                      <targetApplication  id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
+                              <versionRange  minVersion="3.0a1" maxVersion="*" />
+                          </targetApplication>
+                    </versionRange>
+                  </emItem>
+      <emItem  blockID="i40" id="{28387537-e3f9-4ed7-860c-11e69af4a8a0}">
+                        <versionRange  minVersion="0.1" maxVersion="4.3.0.00" severity="1">
+                    </versionRange>
+                  </emItem>
+      <emItem  blockID="i23" id="firefox@bandoo.com">
+                        <versionRange  minVersion="5.0" maxVersion="5.0" severity="1">
+                      <targetApplication  id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
+                              <versionRange  minVersion="3.7a1pre" maxVersion="*" />
+                          </targetApplication>
+                    </versionRange>
+                  </emItem>
+      <emItem  blockID="i22" id="ShopperReports@ShopperReports.com">
+                        <versionRange  minVersion="3.1.22.0" maxVersion="3.1.22.0">
+                    </versionRange>
+                  </emItem>
+      <emItem  blockID="i2" id="fdm_ffext@freedownloadmanager.org">
+                        <versionRange  minVersion="1.0" maxVersion="1.3.1">
+                      <targetApplication  id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
+                              <versionRange  minVersion="3.0a1" maxVersion="*" />
+                          </targetApplication>
+                    </versionRange>
+                  </emItem>
+      <emItem  blockID="i5" id="support@daemon-tools.cc">
+                        <versionRange  minVersion=" " maxVersion="1.0.0.5">
+                    </versionRange>
+                  </emItem>
+      <emItem  blockID="i6" id="{3f963a5b-e555-4543-90e2-c3908898db71}">
+                        <versionRange  minVersion=" " maxVersion="8.5">
+                    </versionRange>
+                  </emItem>
+      <emItem  blockID="i12" id="masterfiler@gmail.com">
+                        <versionRange  severity="3">
+                    </versionRange>
+                  </emItem>
+      <emItem  blockID="i20" id="{AB2CE124-6272-4b12-94A9-7303C7397BD1}">
+                        <versionRange  minVersion="0.1" maxVersion="5.2.0.7164" severity="1">
+                    </versionRange>
+                  </emItem>
+      <emItem  blockID="i11" id="yslow@yahoo-inc.com">
+                        <versionRange  minVersion="2.0.5" maxVersion="2.0.5">
+                      <targetApplication  id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
+                              <versionRange  minVersion="3.5.7" maxVersion="*" />
+                          </targetApplication>
+                    </versionRange>
+                  </emItem>
+      <emItem  blockID="i17" id="{3252b9ae-c69a-4eaf-9502-dc9c1f6c009e}">
+                        <versionRange  minVersion="2.2" maxVersion="2.2">
+                    </versionRange>
+                  </emItem>
+      <emItem  blockID="i3" id="langpack-vi-VN@firefox.mozilla.org">
+                        <versionRange  minVersion="2.0" maxVersion="2.0">
+                    </versionRange>
+                  </emItem>
+      <emItem  blockID="i7" id="{2224e955-00e9-4613-a844-ce69fccaae91}">
+                        </emItem>
+      <emItem  blockID="i24" id="{6E19037A-12E3-4295-8915-ED48BC341614}">
+                        <versionRange  minVersion="0.1" maxVersion="1.3.328.4" severity="1">
+                      <targetApplication  id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
+                              <versionRange  minVersion="3.7a1pre" maxVersion="*" />
+                          </targetApplication>
+                    </versionRange>
+                  </emItem>
+      <emItem  blockID="i15" id="personas@christopher.beard">
+                        <versionRange  minVersion="1.6" maxVersion="1.6">
+                      <targetApplication  id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
+                              <versionRange  minVersion="3.6" maxVersion="3.6.*" />
+                          </targetApplication>
+                    </versionRange>
+                  </emItem>
+      <emItem  blockID="i21" id="support@update-firefox.com">
+                        </emItem>
+    </emItems>
+
+  <pluginItems>
+      <pluginItem  blockID="p26">
+      <match name="name" exp="^Yahoo Application State Plugin$" />      <match name="description" exp="^Yahoo Application State Plugin$" />      <match name="filename" exp="npYState.dll" />              <versionRange >
+                      <targetApplication id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
+              <versionRange  minVersion="3.0a1" maxVersion="3.*" />
+            </targetApplication>
+                  </versionRange>
+          </pluginItem>
+      <pluginItem  blockID="p27">
+      <match name="name" exp="QuickTime Plug-in 7[.]1[.]" />            <match name="filename" exp="npqtplugin.?[.]dll" />              <versionRange >
+                      <targetApplication id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
+              <versionRange  minVersion="3.0a1" maxVersion="3.*" />
+            </targetApplication>
+                  </versionRange>
+          </pluginItem>
+      <pluginItem  blockID="p28">
+                  <match name="filename" exp="NPFFAddOn.dll" />              <versionRange >
+                  </versionRange>
+          </pluginItem>
+      <pluginItem  blockID="p31">
+                  <match name="filename" exp="NPMySrch.dll" />              <versionRange >
+                  </versionRange>
+          </pluginItem>
+      <pluginItem  blockID="p32">
+                  <match name="filename" exp="npViewpoint.dll" />              <versionRange >
+                      <targetApplication id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
+              <versionRange  minVersion="3.0" maxVersion="*" />
+            </targetApplication>
+                  </versionRange>
+          </pluginItem>
+      <pluginItem  blockID="p33">
+      <match name="name" exp="[0-6]\.0\.[01]\d{2}\.\d+" />            <match name="filename" exp="npdeploytk.dll" />              <versionRange  severity="1">
+                  </versionRange>
+          </pluginItem>
+      <pluginItem  blockID="p34">
+                  <match name="filename" exp="[Nn][Pp][Jj][Pp][Ii]1[56]0_[0-9]+\.[Dd][Ll][Ll]" />              <versionRange >
+                      <targetApplication id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
+              <versionRange  minVersion="3.6a1pre" maxVersion="*" />
+            </targetApplication>
+                  </versionRange>
+          </pluginItem>
+    </pluginItems>
+
+  <gfxItems>
+    <gfxBlacklistEntry  blockID="g35">
+      <os>WINNT 6.1</os>
+      <vendor>0x10de</vendor>
+              <devices>
+                      <device>0x0a6c</device>
+                  </devices>
+            <feature>DIRECT2D</feature>
+      <featureStatus>BLOCKED_DRIVER_VERSION</featureStatus>
+      <driverVersion>8.17.12.5896</driverVersion>
+      <driverVersionComparator>LESS_THAN_OR_EQUAL</driverVersionComparator>
+    </gfxBlacklistEntry>
+    <gfxBlacklistEntry  blockID="g36">
+      <os>WINNT 6.1</os>
+      <vendor>0x10de</vendor>
+              <devices>
+                      <device>0x0a6c</device>
+                  </devices>
+            <feature>DIRECT3D_9_LAYERS</feature>
+      <featureStatus>BLOCKED_DRIVER_VERSION</featureStatus>
+      <driverVersion>8.17.12.5896</driverVersion>
+      <driverVersionComparator>LESS_THAN_OR_EQUAL</driverVersionComparator>
+    </gfxBlacklistEntry>
+    <gfxBlacklistEntry  blockID="g37">
+      <os>WINNT 5.1</os>
+      <vendor>0x10de</vendor>
+            <feature>DIRECT3D_9_LAYERS</feature>
+      <featureStatus>BLOCKED_DRIVER_VERSION</featureStatus>
+      <driverVersion>7.0.0.0</driverVersion>
+      <driverVersionComparator>GREATER_THAN_OR_EQUAL</driverVersionComparator>
+    </gfxBlacklistEntry>
+    </gfxItems>
+
+
+</blocklist>
\ No newline at end of file
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -959,16 +959,17 @@
                   onclick="return contentAreaClick(event, false);"/>
       <statuspanel id="statusbar-display" label=""/>
     </vbox>
     <vbox id="browser-border-end" hidden="true" layer="true"/>
   </hbox>
 
   <vbox id="browser-bottombox" layer="true">
     <toolbar id="inspector-toolbar"
+             nowindowdrag="true"
              hidden="true">
       <toolbarbutton id="inspector-inspect-toolbutton"
                      label="&inspectButton.label;"
                      accesskey="&inspectButton.accesskey;"
                      class="toolbarbutton-text"
                      command="Inspector:Inspect"/>
       <toolbarseparator />
       <hbox id="inspector-tools">
--- a/browser/base/content/inspector.js
+++ b/browser/base/content/inspector.js
@@ -763,17 +763,17 @@ var InspectorUI = {
 
     if (!this.domplate) {
       Cu.import("resource:///modules/domplate.jsm", this);
       this.domplateUtils.setDOM(window);
     }
 
     this.openTreePanel();
 
-    this.toolbar.hidden = null;
+    this.toolbar.hidden = false;
     this.inspectCmd.setAttribute("checked", true);
   },
 
   /**
    * Initialize highlighter.
    */
   initializeHighlighter: function IUI_initializeHighlighter()
   {
--- a/browser/base/content/tabview/ui.js
+++ b/browser/base/content/tabview/ui.js
@@ -428,17 +428,18 @@ let UI = {
   // Parameters:
   //
   // options
   //  dontSetActiveTabInGroup bool for not setting active tab in group
   setActive: function UI_setActive(item, options) {
     Utils.assert(item, "item must be given");
 
     if (item.isATabItem) {
-      GroupItems.setActiveGroupItem(item.parent);
+      if (item.parent)
+        GroupItems.setActiveGroupItem(item.parent);
       this._setActiveTab(item);
     } else {
       GroupItems.setActiveGroupItem(item);
       if (!options || !options.dontSetActiveTabInGroup) {
         let activeTab = item.getActiveTab()
         if (activeTab)
           this._setActiveTab(activeTab);
       }
--- a/browser/base/content/test/tabview/browser_tabview_privatebrowsing.js
+++ b/browser/base/content/test/tabview/browser_tabview_privatebrowsing.js
@@ -17,17 +17,17 @@ function test() {
   showTabView(onTabViewLoadedAndShown);
 }
 
 // -----------
 function onTabViewLoadedAndShown() {
   ok(TabView.isVisible(), "Tab View is visible");
 
   // Establish initial state
-  contentWindow = document.getElementById("tab-view").contentWindow;
+  contentWindow = TabView.getContentWindow();
   verifyCleanState("start");
 
   // register a clean up for private browsing just in case
   registerCleanupFunction(function() {
     pb.privateBrowsingEnabled = false;
   });
 
   // create a group
@@ -45,50 +45,47 @@ function onTabViewLoadedAndShown() {
   // collect the group titles
   let count = contentWindow.GroupItems.groupItems.length;
   for (let a = 0; a < count; a++) {
     let gi = contentWindow.GroupItems.groupItems[a];
     groupTitles[a] = gi.getTitle();
   }
 
   // Create a second tab
-  gBrowser.loadOneTab("about:robots", { inBackground: false });
+  gBrowser.addTab("about:robots");
   is(gBrowser.tabs.length, 2, "we now have 2 tabs");
   registerCleanupFunction(function() {
     gBrowser.removeTab(gBrowser.tabs[1]);
   });
 
   afterAllTabsLoaded(function() {
-    showTabView(function() {
-      // Get normal tab urls
-      for (let a = 0; a < gBrowser.tabs.length; a++)
-        normalURLs.push(gBrowser.tabs[a].linkedBrowser.currentURI.spec);
+    // Get normal tab urls
+    for (let a = 0; a < gBrowser.tabs.length; a++)
+      normalURLs.push(gBrowser.tabs[a].linkedBrowser.currentURI.spec);
 
-      // verify that we're all set up for our test
-      verifyNormal();
+    // verify that we're all set up for our test
+    verifyNormal();
 
-      // go into private browsing and make sure Tab View becomes hidden
-      togglePBAndThen(function() {
-        whenTabViewIsHidden(function() {
-          ok(!TabView.isVisible(), "Tab View is no longer visible");
-
-          verifyPB();
+    // go into private browsing and make sure Tab View becomes hidden
+    togglePBAndThen(function() {
+      whenTabViewIsHidden(function() {
+        ok(!TabView.isVisible(), "Tab View is no longer visible");
+        verifyPB();
 
-          // exit private browsing and make sure Tab View is shown again
-          togglePBAndThen(function() {
-            whenTabViewIsShown(function() {
-              ok(TabView.isVisible(), "Tab View is visible again");
-              verifyNormal();
+        // exit private browsing and make sure Tab View is shown again
+        togglePBAndThen(function() {
+          whenTabViewIsShown(function() {
+            ok(TabView.isVisible(), "Tab View is visible again");
+            verifyNormal();
 
-              hideTabView(onTabViewHidden);
-            });
+            hideTabView(onTabViewHidden);
           });
         });
       });
-    }); 
+    });
   });
 }
 
 // -----------
 function onTabViewHidden() {
   ok(!TabView.isVisible(), "Tab View is not visible");
   
   // go into private browsing and make sure Tab View remains hidden
@@ -98,16 +95,18 @@ function onTabViewHidden() {
     
     // turn private browsing back off
     togglePBAndThen(function() {
       verifyNormal();
       
       // end game
       ok(!TabView.isVisible(), "we finish with Tab View not visible");
       registerCleanupFunction(verifyCleanState); // verify after all cleanups
+
+      gBrowser.selectedTab = gBrowser.tabs[0];
       finish();
     });
   });
 }
 
 // ----------
 function verifyCleanState(mode) {
   let prefix = "we " + (mode || "finish") + " with ";
--- a/browser/branding/aurora/Makefile.in
+++ b/browser/branding/aurora/Makefile.in
@@ -55,20 +55,16 @@ WINDOWS_BRANDING_FILES = \
 	firefox.ico \
 	document.ico \
 	branding.nsi \
 	wizHeader.bmp \
 	wizHeaderRTL.bmp \
 	wizWatermark.bmp \
 	$(NULL)
 
-ifdef MOZ_SPLASHSCREEN
-WINDOWS_BRANDING_FILES += splash.bmp
-endif
-
 OSX_BRANDING_FILES = \
 	background.png \
 	firefox.icns \
 	disk.icns \
 	document.icns \
 	dsstore \
 	$(NULL)
 
deleted file mode 100644
index 2ba119890cd21cd4498d6a8bb3274c7d41fc6cbc..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
--- a/browser/branding/nightly/Makefile.in
+++ b/browser/branding/nightly/Makefile.in
@@ -55,20 +55,16 @@ WINDOWS_BRANDING_FILES = \
 	firefox.ico \
 	document.ico \
 	branding.nsi \
 	wizHeader.bmp \
 	wizHeaderRTL.bmp \
 	wizWatermark.bmp \
 	$(NULL)
 
-ifdef MOZ_SPLASHSCREEN
-WINDOWS_BRANDING_FILES += splash.bmp
-endif
-
 OSX_BRANDING_FILES = \
 	background.png \
 	firefox.icns \
 	disk.icns \
 	document.icns \
 	dsstore \
 	$(NULL)
 
deleted file mode 100644
index 2ba119890cd21cd4498d6a8bb3274c7d41fc6cbc..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
--- a/browser/branding/official/Makefile.in
+++ b/browser/branding/official/Makefile.in
@@ -55,20 +55,16 @@ WINDOWS_BRANDING_FILES = \
 	firefox.ico \
 	document.ico \
 	branding.nsi \
 	wizHeader.bmp \
 	wizHeaderRTL.bmp \
 	wizWatermark.bmp \
 	$(NULL)
 
-ifdef MOZ_SPLASHSCREEN
-WINDOWS_BRANDING_FILES += splash.bmp
-endif
-
 OSX_BRANDING_FILES = \
 	background.png \
 	firefox.icns \
 	disk.icns \
 	document.icns \
 	dsstore \
 	$(NULL)
 
deleted file mode 100644
index a2b5e8b0867aebfa15f48f78a73549dc13662d69..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
--- a/browser/branding/unofficial/Makefile.in
+++ b/browser/branding/unofficial/Makefile.in
@@ -55,20 +55,16 @@ WINDOWS_BRANDING_FILES = \
 	firefox.ico \
 	document.ico \
 	branding.nsi \
 	wizHeader.bmp \
 	wizHeaderRTL.bmp \
 	wizWatermark.bmp \
 	$(NULL)
 
-ifdef MOZ_SPLASHSCREEN
-WINDOWS_BRANDING_FILES += splash.bmp
-endif
-
 OSX_BRANDING_FILES = \
 	background.png \
 	firefox.icns \
 	disk.icns \
 	document.icns \
 	dsstore \
 	$(NULL)
 
deleted file mode 100644
index d2afefdf82ea339497d69adeeae4ae9d3f25e467..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
--- a/browser/components/places/content/places.js
+++ b/browser/components/places/content/places.js
@@ -67,17 +67,17 @@ var PlacesOrganizer = {
   },
 
   init: function PO_init() {
     this._places = document.getElementById("placesList");
     this._content = document.getElementById("placeContent");
     this._initFolderTree();
 
     var leftPaneSelection = "AllBookmarks"; // default to all-bookmarks
-    if ("arguments" in window && window.arguments.length > 0)
+    if (window.arguments && window.arguments[0])
       leftPaneSelection = window.arguments[0];
 
     this.selectLeftPaneQuery(leftPaneSelection);
     // clear the back-stack
     this._backHistory.splice(0);
     document.getElementById("OrganizerCommand:Back").setAttribute("disabled", true);
 
     var view = this._content.treeBoxObject.view;
--- a/browser/components/places/src/PlacesUIUtils.jsm
+++ b/browser/components/places/src/PlacesUIUtils.jsm
@@ -51,17 +51,17 @@ Cu.import("resource://gre/modules/XPCOMU
 Cu.import("resource://gre/modules/Services.jsm");
 
 XPCOMUtils.defineLazyGetter(this, "PlacesUtils", function() {
   Cu.import("resource://gre/modules/PlacesUtils.jsm");
   return PlacesUtils;
 });
 
 var PlacesUIUtils = {
-  ORGANIZER_LEFTPANE_VERSION: 6,
+  ORGANIZER_LEFTPANE_VERSION: 7,
   ORGANIZER_FOLDER_ANNO: "PlacesOrganizer/OrganizerFolder",
   ORGANIZER_QUERY_ANNO: "PlacesOrganizer/OrganizerQuery",
 
   LOAD_IN_SIDEBAR_ANNO: "bookmarkProperties/loadInSidebar",
   DESCRIPTION_ANNO: "bookmarkProperties/description",
 
   TYPE_TAB_DROP: "application/x-moz-tabbrowser-tab",
 
@@ -807,18 +807,20 @@ var PlacesUIUtils = {
       args.AppendElement(uriList);      
       browserWindow = Services.ww.openWindow(aWindow,
                                              "chrome://browser/content/browser.xul",
                                              null, "chrome,dialog=no,all", args);
       return;
     }
 
     var loadInBackground = where == "tabshifted" ? true : false;
-    var replaceCurrentTab = where == "tab" ? false : true;
-    browserWindow.gBrowser.loadTabs(urls, loadInBackground, replaceCurrentTab);
+    // For consistency, we want all the bookmarks to open in new tabs, instead
+    // of having one of them replace the currently focused tab.  Hence we call
+    // loadTabs with aReplace set to false.
+    browserWindow.gBrowser.loadTabs(urls, loadInBackground, false);
   },
 
   /**
    * Helper method for methods which are forced to take a view/window
    * parameter as an optional parameter.  It will be removed post Fx4.
    */
   _getWindow: function PUIU__getWindow(aView) {
     if (aView) {
@@ -981,33 +983,34 @@ var PlacesUIUtils = {
     // Shortcuts to services.
     let bs = PlacesUtils.bookmarks;
     let as = PlacesUtils.annotations;
 
     // This is the list of the left pane queries.
     let queries = {
       "PlacesRoot": { title: "" },
       "History": { title: this.getString("OrganizerQueryHistory") },
+      "Downloads": { title: this.getString("OrganizerQueryDownloads") },
       "Tags": { title: this.getString("OrganizerQueryTags") },
       "AllBookmarks": { title: this.getString("OrganizerQueryAllBookmarks") },
       "BookmarksToolbar":
         { title: null,
           concreteTitle: PlacesUtils.getString("BookmarksToolbarFolderTitle"),
           concreteId: PlacesUtils.toolbarFolderId },
       "BookmarksMenu":
         { title: null,
           concreteTitle: PlacesUtils.getString("BookmarksMenuFolderTitle"),
           concreteId: PlacesUtils.bookmarksMenuFolderId },
       "UnfiledBookmarks":
         { title: null,
           concreteTitle: PlacesUtils.getString("UnsortedBookmarksFolderTitle"),
           concreteId: PlacesUtils.unfiledBookmarksFolderId },
     };
     // All queries but PlacesRoot.
-    const EXPECTED_QUERY_COUNT = 6;
+    const EXPECTED_QUERY_COUNT = 7;
 
     // Removes an item and associated annotations, ignoring eventual errors.
     function safeRemoveItem(aItemId) {
       try {
         if (as.itemHasAnnotation(aItemId, PlacesUIUtils.ORGANIZER_QUERY_ANNO) &&
             !(as.getItemAnnotation(aItemId, PlacesUIUtils.ORGANIZER_QUERY_ANNO) in queries)) {
           // Some extension annotated their roots with our query annotation,
           // so we should not delete them.
@@ -1170,17 +1173,22 @@ var PlacesUIUtils = {
 
         // History Query.
         this.create_query("History", leftPaneRoot,
                           "place:type=" +
                           Ci.nsINavHistoryQueryOptions.RESULTS_AS_DATE_QUERY +
                           "&sort=" +
                           Ci.nsINavHistoryQueryOptions.SORT_BY_DATE_DESCENDING);
 
-        // XXX: Downloads.
+        // Downloads.
+        this.create_query("Downloads", leftPaneRoot,
+                          "place:transition=" +
+                          Ci.nsINavHistoryService.TRANSITION_DOWNLOAD +
+                          "&sort=" +
+                          Ci.nsINavHistoryQueryOptions.SORT_BY_DATE_DESCENDING);
 
         // Tags Query.
         this.create_query("Tags", leftPaneRoot,
                           "place:type=" +
                           Ci.nsINavHistoryQueryOptions.RESULTS_AS_TAG_QUERY +
                           "&sort=" +
                           Ci.nsINavHistoryQueryOptions.SORT_BY_TITLE_ASCENDING);
 
--- a/browser/components/places/tests/browser/Makefile.in
+++ b/browser/components/places/tests/browser/Makefile.in
@@ -69,12 +69,13 @@ include $(topsrcdir)/config/rules.mk
 	browser_markPageAsFollowedLink.js \
 	framedPage.html \
 	frameLeft.html \
 	frameRight.html \
 	browser_toolbar_migration.js \
 	browser_library_batch_delete.js \
 	browser_555547.js \
 	browser_416459_cut.js \
+	browser_library_downloads.js \
 	$(NULL)
 
 libs:: $(_BROWSER_TEST_FILES)
 	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/browser/$(relativesrcdir)
new file mode 100644
--- /dev/null
+++ b/browser/components/places/tests/browser/browser_library_downloads.js
@@ -0,0 +1,89 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Places test code.
+ *
+ * The Initial Developer of the Original Code is Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Mehdi Mulani <mmulani@mozilla.com> (original author)
+ *   Jared Wein <jwein@mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+ * Tests bug 564900: Add folder specifically for downloads to Library left pane.
+ * https://bugzilla.mozilla.org/show_bug.cgi?id=564900
+ * This test visits various pages then opens the Library and ensures
+ * that both the Downloads folder shows up and that the correct visits
+ * are shown in it.
+ */
+
+let now = Date.now();
+
+function test() {
+  waitForExplicitFinish();
+
+  function onLibraryReady(win) {
+    // Add visits to compare contents with.
+    fastAddVisit("http://mozilla.com",
+                  PlacesUtils.history.TRANSITION_TYPED);
+    fastAddVisit("http://google.com",
+                  PlacesUtils.history.TRANSITION_DOWNLOAD);
+    fastAddVisit("http://en.wikipedia.org",
+                  PlacesUtils.history.TRANSITION_TYPED);
+    fastAddVisit("http://ubuntu.org",
+                  PlacesUtils.history.TRANSITION_DOWNLOAD);
+
+    // Make sure Downloads is present.
+    isnot(win.PlacesOrganizer._places.selectedNode, null,
+          "Downloads is present and selected");
+
+    // Make sure content in right pane exists.
+    let tree = win.document.getElementById("placeContent");
+    isnot(tree, null, "placeContent tree exists");
+
+    // Check results.
+    var contentRoot = tree.result.root;
+    var len = contentRoot.childCount;
+    var testUris = ["http://ubuntu.org/", "http://google.com/"];
+    for (var i = 0; i < len; i++) {
+      is(contentRoot.getChild(i).uri, testUris[i],
+          "Comparing downloads shown at index " + i);
+    }
+
+    win.close();
+    waitForClearHistory(finish);
+  }
+
+  openLibrary(onLibraryReady, "Downloads");
+}
+
+function fastAddVisit(uri, transition) {
+  PlacesUtils.history.addVisit(PlacesUtils._uri(uri), now++ * 1000,
+                               null, transition, false, 0);
+}
--- a/browser/components/places/tests/browser/head.js
+++ b/browser/components/places/tests/browser/head.js
@@ -1,28 +1,38 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+Components.utils.import("resource://gre/modules/NetUtil.jsm");
 
 // We need to cache this before test runs...
 let cachedLeftPaneFolderIdGetter;
 let (getter = PlacesUIUtils.__lookupGetter__("leftPaneFolderId")) {
   if (!cachedLeftPaneFolderIdGetter && typeof(getter) == "function")
     cachedLeftPaneFolderIdGetter = getter;
 }
 // ...And restore it when test ends.
 registerCleanupFunction(function(){
   let (getter = PlacesUIUtils.__lookupGetter__("leftPaneFolderId")) {
     if (cachedLeftPaneFolderIdGetter && typeof(getter) != "function")
       PlacesUIUtils.__defineGetter__("leftPaneFolderId",
                                      cachedLeftPaneFolderIdGetter);
   }
 });
 
-
-function openLibrary(callback) {
+function openLibrary(callback, aLeftPaneRoot) {
   let library = window.openDialog("chrome://browser/content/places/places.xul",
-                                  "", "chrome,toolbar=yes,dialog=no,resizable");
+                                  "", "chrome,toolbar=yes,dialog=no,resizable",
+                                  aLeftPaneRoot);
   waitForFocus(function () {
     callback(library);
   }, library);
 
   return library;
 }
 
-Components.utils.import("resource://gre/modules/NetUtil.jsm");
+function waitForClearHistory(aCallback) {
+  Services.obs.addObserver(function observeCH(aSubject, aTopic, aData) {
+    Services.obs.removeObserver(observeCH, PlacesUtils.TOPIC_EXPIRATION_FINISHED);
+    aCallback();
+  }, PlacesUtils.TOPIC_EXPIRATION_FINISHED, false);
+  PlacesUtils.bhistory.removeAllPages();
+}
--- a/browser/components/places/tests/chrome/test_0_bug510634.xul
+++ b/browser/components/places/tests/chrome/test_0_bug510634.xul
@@ -92,47 +92,59 @@
       return results;
     }
 
     function runTest() {
       // We need to cache and restore this getter in order to simulate
       // Bug 510634
       let cachedLeftPaneFolderIdGetter =
         PlacesUIUtils.__lookupGetter__("leftPaneFolderId");
+      // Must also cache and restore this getter as it is affected by
+      // leftPaneFolderId, from bug 564900.
+      let cachedAllBookmarksFolderIdGetter =
+        PlacesUIUtils.__lookupGetter__("allBookmarksFolderId");
 
       let leftPaneFolderId = PlacesUIUtils.leftPaneFolderId;
 
       // restore the getter
       PlacesUIUtils.__defineGetter__("leftPaneFolderId", cachedLeftPaneFolderIdGetter);
 
       // Setup the places tree contents.
       let tree = document.getElementById("tree");
       tree.place = "place:queryType=1&folder=" + leftPaneFolderId;
 
-      // Open All Bookmarks
-      PlacesUtils.asContainer(tree.view.nodeForTreeIndex(2)).containerOpen = true;
-      
       // The query-property is set on the title column for each row.
       let titleColumn = tree.treeBoxObject.columns.getColumnAt(0);
 
-      ["History", "Tags", "AllBookmarks", "BookmarksToolbar",
+      // Open All Bookmarks
+      tree.selectItems([PlacesUIUtils.leftPaneQueries["AllBookmarks"]]);
+      PlacesUtils.asContainer(tree.selectedNode).containerOpen = true;
+      is(PlacesUIUtils.allBookmarksFolderId, tree.selectedNode.itemId,
+         "Opened All Bookmarks");
+
+      ["History", "Downloads", "Tags", "AllBookmarks", "BookmarksToolbar",
        "BookmarksMenu", "UnfiledBookmarks"].forEach(
-         function(aQueryName, aRow) {
-           let rowProperties = createSupportsArray();
-           tree.view.getCellProperties(aRow, titleColumn, rowProperties);
-           rowProperties = convertPropertiesToJSArray(rowProperties);
-           ok(rowProperties.indexOf("OrganizerQuery_" + aQueryName) != -1,
-             "OrganizerQuery_" + aQueryName + " is set");
-         }
-       );
+        function(aQueryName, aRow) {
+          let found = false;
+          for (let i = 0; i < tree.view.rowCount && !found; i++) {
+            let rowProperties = createSupportsArray();
+            tree.view.getCellProperties(i, titleColumn, rowProperties);
+            rowProperties = convertPropertiesToJSArray(rowProperties);
+            found = rowProperties.indexOf("OrganizerQuery_" + aQueryName) != -1;
+          }
+          ok(found, "OrganizerQuery_" + aQueryName + " is set");
+        }
+      );
 
       // Close the root node
       tree.result.root.containerOpen = false;
 
-      // Restore the getter for the next test.
+      // Restore the getters for the next test.
       PlacesUIUtils.__defineGetter__("leftPaneFolderId", cachedLeftPaneFolderIdGetter);
+      PlacesUIUtils.__defineGetter__("allBookmarksFolderId",
+                                     cachedAllBookmarksFolderIdGetter);
 
       SimpleTest.finish();
     }
 
   ]]>
   </script>
 </window>
--- a/browser/components/places/tests/chrome/test_bug427633_no_newfolder_if_noip.xul
+++ b/browser/components/places/tests/chrome/test_bug427633_no_newfolder_if_noip.xul
@@ -80,17 +80,17 @@
                getService(Ci.nsINavBookmarksService);
       var ios = Cc["@mozilla.org/network/io-service;1"].
                 getService(Ci.nsIIOService);
       function uri(spec) {
         return ios.newURI(spec, null, null);
       }
 
       // Add a bookmark.
-      var itemId = bs.insertBookmark(bs.toolbarFolder,
+      var itemId = bs.insertBookmark(PlacesUtils.toolbarFolderId,
                                      uri("http://www.example.com/"),
                                      bs.DEFAULT_INDEX,
                                      "mozilla");
 
       // Init panel.
       ok(gEditItemOverlay, "gEditItemOverlay is in context");
       gEditItemOverlay.initPanel(itemId);
       ok(gEditItemOverlay._initialized, "gEditItemOverlay is initialized");
--- a/browser/components/preferences/aboutPermissions.js
+++ b/browser/components/preferences/aboutPermissions.js
@@ -87,28 +87,38 @@ Site.prototype = {
   /**
    * Gets the favicon to use for the site. The callback only gets called if
    * a favicon is found for either the http URI or the https URI.
    *
    * @param aCallback
    *        A callback function that takes a favicon image URL as a parameter.
    */
   getFavicon: function Site_getFavicon(aCallback) {
+    let callbackExecuted = false;
     function faviconDataCallback(aURI, aDataLen, aData, aMimeType) {
+      // We don't need a second callback, so we can ignore it to avoid making
+      // a second database query for the favicon data.
+      if (callbackExecuted) {
+        return;
+      }
       try {
-        aCallback(aURI.spec);
+        // Use getFaviconLinkForIcon to get image data from the database instead
+        // of using the favicon URI to fetch image data over the network.
+        aCallback(gFaviconService.getFaviconLinkForIcon(aURI).spec);
+        callbackExecuted = true;
       } catch (e) {
         Cu.reportError("AboutPermissions: " + e);
       }
     }
 
     // Try to find favicion for both URIs. Callback will only be called if a
-    // favicon URI is found, so this means we'll always prefer the https favicon.
+    // favicon URI is found. We'll ignore the second callback if it is called,
+    // so this means we'll always prefer the https favicon.
+    gFaviconService.getFaviconURLForPage(this.httpsURI, faviconDataCallback);
     gFaviconService.getFaviconURLForPage(this.httpURI, faviconDataCallback);
-    gFaviconService.getFaviconURLForPage(this.httpsURI, faviconDataCallback);
   },
 
   /**
    * Gets the number of history visits for the site.
    *
    * @param aCallback
    *        A function that takes the visit count (a number) as a parameter.
    */
--- a/browser/components/privatebrowsing/src/nsPrivateBrowsingService.js
+++ b/browser/components/privatebrowsing/src/nsPrivateBrowsingService.js
@@ -498,51 +498,53 @@ PrivateBrowsingService.prototype = {
     // Allowing observers to set the private browsing status from their
     // notification handlers is not desired, because it will change the
     // status of the service while it's in the process of another transition.
     // So, we detect a reentrant call here and throw an error.
     // This is documented in nsIPrivateBrowsingService.idl.
     if (this._currentStatus != STATE_IDLE)
       throw Cr.NS_ERROR_FAILURE;
 
+    if (val == this._inPrivateBrowsing)
+      return;
+
     try {
+      if (val) {
+        if (!this._canEnterPrivateBrowsingMode())
+          return;
+      }
+      else {
+        if (!this._canLeavePrivateBrowsingMode())
+          return;
+      }
+
+      this._ensureCanCloseWindows();
+
+      // start the transition now that we know that we can
       this._currentStatus = STATE_TRANSITION_STARTED;
 
-      if (val != this._inPrivateBrowsing) {
-        if (val) {
-          if (!this._canEnterPrivateBrowsingMode())
-            return;
-        }
-        else {
-          if (!this._canLeavePrivateBrowsingMode())
-            return;
-        }
+      this._autoStarted = this._prefs.getBoolPref("browser.privatebrowsing.autostart");
+      this._inPrivateBrowsing = val != false;
 
-        this._ensureCanCloseWindows();
+      let data = val ? "enter" : "exit";
 
-        this._autoStarted = this._prefs.getBoolPref("browser.privatebrowsing.autostart");
-        this._inPrivateBrowsing = val != false;
+      let quitting = Cc["@mozilla.org/supports-PRBool;1"].
+                     createInstance(Ci.nsISupportsPRBool);
+      quitting.data = this._quitting;
 
-        let data = val ? "enter" : "exit";
-
-        let quitting = Cc["@mozilla.org/supports-PRBool;1"].
-                       createInstance(Ci.nsISupportsPRBool);
-        quitting.data = this._quitting;
-
-        // notify observers of the pending private browsing mode change
-        this._obs.notifyObservers(quitting, "private-browsing-change-granted", data);
+      // notify observers of the pending private browsing mode change
+      this._obs.notifyObservers(quitting, "private-browsing-change-granted", data);
 
-        // destroy the current session and start initial cleanup
-        this._onBeforePrivateBrowsingModeChange();
+      // destroy the current session and start initial cleanup
+      this._onBeforePrivateBrowsingModeChange();
 
-        this._obs.notifyObservers(quitting, "private-browsing", data);
+      this._obs.notifyObservers(quitting, "private-browsing", data);
 
-        // load the appropriate session
-        this._onAfterPrivateBrowsingModeChange();
-      }
+      // load the appropriate session
+      this._onAfterPrivateBrowsingModeChange();
     } catch (ex) {
       // We aborted the transition to/from private browsing, we must restore the
       // beforeunload handling on all the windows for which we switched it off.
       for (let i = 0; i < this._windowsToClose.length; i++)
         this._windowsToClose[i].docShell.contentViewer.resetCloseWindow();
       // We don't log an error when the transition is canceled from beforeunload
       if (ex != Cr.NS_ERROR_ABORT)
         Cu.reportError("Exception thrown while processing the " +
--- a/browser/components/sessionstore/content/aboutSessionRestore.js
+++ b/browser/components/sessionstore/content/aboutSessionRestore.js
@@ -43,22 +43,18 @@ var gTreeData;
 
 // Page initialization
 
 window.onload = function() {
   // the crashed session state is kept inside a textbox so that SessionStore picks it up
   // (for when the tab is closed or the session crashes right again)
   var sessionData = document.getElementById("sessionData");
   if (!sessionData.value) {
-    var ss = Cc["@mozilla.org/browser/sessionstartup;1"].getService(Ci.nsISessionStartup);
-    sessionData.value = ss.state;
-    if (!sessionData.value) {
-      document.getElementById("errorTryAgain").disabled = true;
-      return;
-    }
+    document.getElementById("errorTryAgain").disabled = true;
+    return;
   }
 
   // remove unneeded braces (added for compatibility with Firefox 2.0 and 3.0)
   if (sessionData.value.charAt(0) == '(')
     sessionData.value = sessionData.value.slice(1, -1);
   try {
     gStateObject = JSON.parse(sessionData.value);
   }
--- a/browser/components/sessionstore/content/aboutSessionRestore.xhtml
+++ b/browser/components/sessionstore/content/aboutSessionRestore.xhtml
@@ -81,17 +81,16 @@
           <ul>
             <li>&restorepage.restoreSome;</li>
             <li>&restorepage.startNew;</li>
           </ul>
         </div>
 
         <!-- Short Description -->
         <div id="errorTrailerDesc">
-          <p>&nbsp;</p>
           <tree xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
                 id="tabList" flex="1" seltype="single" hidecolumnpicker="true"
                 onclick="onListClick(event);" onkeydown="onListKeyDown(event);"
                 _window_label="&restorepage.windowLabel;">
             <treecols>
               <treecol cycler="true" id="restore" type="checkbox" label="&restorepage.restoreHeader;"/>
               <splitter class="tree-splitter"/>
               <treecol primary="true" id="title" label="&restorepage.listHeader;" flex="1"/>
--- a/browser/components/sessionstore/src/nsSessionStartup.js
+++ b/browser/components/sessionstore/src/nsSessionStartup.js
@@ -107,18 +107,19 @@ SessionStartup.prototype = {
     let prefBranch = Cc["@mozilla.org/preferences-service;1"].
                      getService(Ci.nsIPrefService).getBranch("browser.");
 
     // get file references
     var dirService = Cc["@mozilla.org/file/directory_service;1"].
                      getService(Ci.nsIProperties);
     let sessionFile = dirService.get("ProfD", Ci.nsILocalFile);
     sessionFile.append("sessionstore.js");
-    
-    let doResumeSession = prefBranch.getBoolPref("sessionstore.resume_session_once") ||
+
+    let doResumeSessionOnce = prefBranch.getBoolPref("sessionstore.resume_session_once");
+    let doResumeSession = doResumeSessionOnce ||
                           prefBranch.getIntPref("startup.page") == 3;
 
     // only continue if the session file exists
     if (!sessionFile.exists())
       return;
 
     // get string containing session state
     let iniString = this._readStateFile(sessionFile);
@@ -132,16 +133,20 @@ SessionStartup.prototype = {
         iniString = iniString.slice(1, -1);
       try {
         this._initialState = JSON.parse(iniString);
       }
       catch (exJSON) {
         var s = new Cu.Sandbox("about:blank");
         this._initialState = Cu.evalInSandbox("(" + iniString + ")", s);
       }
+
+      // If this is a normal restore then throw away any previous session
+      if (!doResumeSessionOnce)
+        delete this._initialState.lastSessionState;
     }
     catch (ex) { debug("The session file is invalid: " + ex); }
 
     let resumeFromCrash = prefBranch.getBoolPref("sessionstore.resume_from_crash");
     let lastSessionCrashed =
       this._initialState && this._initialState.session &&
       this._initialState.session.state &&
       this._initialState.session.state == STATE_RUNNING_STR;
--- a/browser/components/sessionstore/src/nsSessionStore.js
+++ b/browser/components/sessionstore/src/nsSessionStore.js
@@ -230,17 +230,20 @@ SessionStoreService.prototype = {
   _tabsRestoringCount: 0,
 
   // number of tabs to restore concurrently, pref controlled.
   _maxConcurrentTabRestores: null,
   
   // whether to restore hidden tabs or not, pref controlled.
   _restoreHiddenTabs: null,
 
-  // The state from the previous session (after restoring pinned tabs)
+  // The state from the previous session (after restoring pinned tabs). This
+  // state is persisted and passed through to the next session during an app
+  // restart to make the third party add-on warning not trash the deferred
+  // session
   _lastSessionState: null,
 
   // Whether we've been initialized
   _initialized: false,
 
   // The original "sessionstore.resume_session_once" preference value before it
   // was modified by saveState.  saveState will set the
   // "sessionstore.resume_session_once" to true when the
@@ -326,16 +329,20 @@ SessionStoreService.prototype = {
           if (iniState.windows.length)
             this._initialState = iniState;
           else
             this._initialState = null;
           if (remainingState.windows.length)
             this._lastSessionState = remainingState;
         }
         else {
+          // Get the last deferred session in case the user still wants to
+          // restore it
+          this._lastSessionState = this._initialState.lastSessionState;
+
           let lastSessionCrashed =
             this._initialState.session && this._initialState.session.state &&
             this._initialState.session.state == STATE_RUNNING_STR;
           if (lastSessionCrashed) {
             this._recentCrashes = (this._initialState.session &&
                                    this._initialState.session.recentCrashes || 0) + 1;
             
             if (this._needsRestorePage(this._initialState, this._recentCrashes)) {
@@ -483,16 +490,22 @@ SessionStoreService.prototype = {
         // if the sessionstore.resume_session_once preference was changed by
         // saveState because crash recovery is disabled then restore the
         // preference back to the value it was prior to that.  This will prevent
         // SessionStore from always restoring the session when crash recovery is
         // disabled.
         this._prefBranch.setBoolPref("sessionstore.resume_session_once",
                                      this._resume_session_once_on_shutdown);
       }
+
+      if (aData != "restart") {
+        // Throw away the previous session on shutdown
+        this._lastSessionState = null;
+      }
+
       this._loadState = STATE_QUITTING; // just to be sure
       this._uninit();
       break;
     case "browser:purge-session-history": // catch sanitization 
       this._clearDisk();
       // If the browser is shutting down, simply return after clearing the
       // session data on disk as this notification fires after the
       // quit-application notification so the browser is about to exit.
@@ -3480,16 +3493,20 @@ SessionStoreService.prototype = {
     oState.session = {
       state: this._loadState == STATE_RUNNING ? STATE_RUNNING_STR : STATE_STOPPED_STR,
       lastUpdate: Date.now(),
       startTime: this._sessionStartTime
     };
     if (this._recentCrashes)
       oState.session.recentCrashes = this._recentCrashes;
 
+    // Persist the last session if we deferred restoring it
+    if (this._lastSessionState)
+      oState.lastSessionState = this._lastSessionState;
+
     this._saveStateObject(oState);
   },
 
   /**
    * write a state object to disk
    */
   _saveStateObject: function sss_saveStateObject(aStateObj) {
     var stateString = Cc["@mozilla.org/supports-string;1"].
--- a/browser/components/sessionstore/test/browser/browser_588426.js
+++ b/browser/components/sessionstore/test/browser/browser_588426.js
@@ -2,24 +2,40 @@
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 function test() {
   let state = { windows: [{ tabs: [
       {entries: [{url: "about:mozilla"}], hidden: true},
       {entries: [{url: "about:robots"}], hidden: true}
   ] }] };
 
-  let finalState = { windows: [{ tabs: [
-      {entries: [{url: "about:blank"}]}
-  ] }] };
-
   waitForExplicitFinish();
 
-  waitForBrowserState(state, function () {
-    is(gBrowser.tabs.length, 2, "two tabs were restored");
-    is(gBrowser.visibleTabs.length, 1, "one tab is visible");
+  newWindowWithState(state, function (win) {
+    registerCleanupFunction(function () win.close());
 
-    let tab = gBrowser.visibleTabs[0];
+    is(win.gBrowser.tabs.length, 2, "two tabs were restored");
+    is(win.gBrowser.visibleTabs.length, 1, "one tab is visible");
+
+    let tab = win.gBrowser.visibleTabs[0];
     is(tab.linkedBrowser.currentURI.spec, "about:mozilla", "visible tab is about:mozilla");
 
-    waitForBrowserState(finalState, finish);
+    finish();
   });
 }
+
+function newWindowWithState(state, callback) {
+  let opts = "chrome,all,dialog=no,height=800,width=800";
+  let win = window.openDialog(getBrowserURL(), "_blank", opts);
+
+  win.addEventListener("load", function onLoad() {
+    win.removeEventListener("load", onLoad, false);
+
+    executeSoon(function () {
+      win.addEventListener("SSWindowStateReady", function onReady() {
+        win.removeEventListener("SSWindowStateReady", onReady, false);
+        executeSoon(function () callback(win));
+      }, false);
+
+      ss.setWindowState(win, JSON.stringify(state), true);
+    });
+  }, false);
+}
--- a/browser/components/sessionstore/test/browser/browser_590563.js
+++ b/browser/components/sessionstore/test/browser/browser_590563.js
@@ -1,65 +1,78 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
-let stateBackup = ss.getBrowserState();
-
 function test() {
-  waitForExplicitFinish();
-
   let oldState = {
     windows: [{
       tabs: [
         { entries: [{ url: "about:robots" }], hidden: true },
         { entries: [{ url: "about:blank" }], hidden: false }
       ]
     }]
   };
   let pageData = {
     url: "about:sessionrestore",
     formdata: { "#sessionData": "(" + JSON.stringify(oldState) + ")" }
   };
   let state = { windows: [{ tabs: [{ entries: [pageData] }] }] };
 
-  // The form data will be restored before SSTabRestored, so we want to listen
-  // for that on the currently selected tab (it will be reused)
-  gBrowser.selectedTab.addEventListener("SSTabRestored", onSSTabRestored, true);
+  waitForExplicitFinish();
+
+  newWindowWithState(state, function (win) {
+    registerCleanupFunction(function () win.close());
+
+    is(gBrowser.tabs.length, 1, "The total number of tabs should be 1");
+    is(gBrowser.visibleTabs.length, 1, "The total number of visible tabs should be 1");
 
-  ss.setBrowserState(JSON.stringify(state));
+    executeSoon(function () {
+      waitForFocus(function () {
+        middleClickTest(win);
+        finish();
+      }, win);
+    });
+  });
 }
 
-function onSSTabRestored(aEvent) {
-  gBrowser.selectedTab.removeEventListener("SSTabRestored", onSSTabRestored, true);
-
-  is(gBrowser.tabs.length, 1, "The total number of tabs should be 1");
-  is(gBrowser.visibleTabs.length, 1, "The total number of visible tabs should be 1");
-
-  executeSoon(middleClickTest);
-}
-
-function middleClickTest() {
-  let tree = gBrowser.selectedBrowser.contentDocument.getElementById("tabList");
+function middleClickTest(win) {
+  let browser = win.gBrowser.selectedBrowser;
+  let tree = browser.contentDocument.getElementById("tabList");
   is(tree.view.rowCount, 3, "There should be three items");
 
   let x = {}, y = {}, width = {}, height = {};
 
   // click on the first tab item
   tree.treeBoxObject.getCoordsForCellItem(1, tree.columns[1], "text", x, y, width, height);
   EventUtils.synthesizeMouse(tree.body, x.value, y.value, { button: 1 },
-                             gBrowser.selectedBrowser.contentWindow);
+                             browser.contentWindow);
   // click on the second tab item
   tree.treeBoxObject.getCoordsForCellItem(2, tree.columns[1], "text", x, y, width, height);
   EventUtils.synthesizeMouse(tree.body, x.value, y.value, { button: 1 },
-                             gBrowser.selectedBrowser.contentWindow);
+                             browser.contentWindow);
 
-  is(gBrowser.tabs.length, 3,
+  is(win.gBrowser.tabs.length, 3,
      "The total number of tabs should be 3 after restoring 2 tabs by middle click.");
-  is(gBrowser.visibleTabs.length, 3,
+  is(win.gBrowser.visibleTabs.length, 3,
      "The total number of visible tabs should be 3 after restoring 2 tabs by middle click");
-
-  cleanup();
 }
 
-function cleanup() {
-   ss.setBrowserState(stateBackup);
-   executeSoon(finish);
+function newWindowWithState(state, callback) {
+  let opts = "chrome,all,dialog=no,height=800,width=800";
+  let win = window.openDialog(getBrowserURL(), "_blank", opts);
+
+  win.addEventListener("load", function onLoad() {
+    win.removeEventListener("load", onLoad, false);
+
+    let tab = win.gBrowser.selectedTab;
+
+    // The form data will be restored before SSTabRestored, so we want to listen
+    // for that on the currently selected tab (it will be reused)
+    tab.addEventListener("SSTabRestored", function onRestored() {
+      tab.removeEventListener("SSTabRestored", onRestored, true);
+      callback(win);
+    }, true);
+
+    executeSoon(function () {
+      ss.setWindowState(win, JSON.stringify(state), true);
+    });
+  }, false);
 }
--- a/browser/devtools/scratchpad/scratchpad.xul
+++ b/browser/devtools/scratchpad/scratchpad.xul
@@ -181,22 +181,22 @@
                 accesskey="&closeCmd.accesskey;"
                 command="sp-cmd-close"/>
     </menupopup>
   </menu>
 
   <menu id="sp-edit-menu" label="&editMenu.label;"
         accesskey="&editMenu.accesskey;">
     <menupopup id="sp-menu_editpopup">
-      <menuitem id="sp-menu_undo"
+      <menuitem id="sp-menu-undo"
                 label="&undoCmd.label;"
                 key="key_undo"
                 accesskey="&undoCmd.accesskey;"
                 disabled="true"
-                oncommand="cmd_undo"/>
+                command="cmd_undo"/>
       <menuitem id="sp-menu-redo"
                 label="&redoCmd.label;"
                 key="key_redo"
                 disabled="true"
                 accesskey="&redoCmd.accesskey;"
                 command="cmd_redo"/>
       <menuseparator/>
       <menuitem id="sp-menu-cut"
--- a/browser/devtools/webconsole/HUDService.jsm
+++ b/browser/devtools/webconsole/HUDService.jsm
@@ -461,17 +461,16 @@ ResponseListener.prototype =
     // Call update on all panels.
     this.httpActivity.panels.forEach(function(weakRef) {
       let panel = weakRef.get();
       if (panel) {
         panel.update();
       }
     });
     this.httpActivity.response.isDone = true;
-    this.httpActivity.response.listener = null;
     this.httpActivity = null;
     this.receivedData = "";
     this.request = null;
     this.sink = null;
     this.inputStream = null;
   },
 
   /**
@@ -1273,16 +1272,47 @@ function HUD_SERVICE()
 
   // Remembers the last console height, in pixels.
   this.lastConsoleHeight = Services.prefs.getIntPref("devtools.hud.height");
 
   // Network response bodies are piped through a buffer of the given size (in
   // bytes).
   this.responsePipeSegmentSize =
     Services.prefs.getIntPref("network.buffer.cache.size");
+
+  /**
+   * Collection of HUDIds that map to the tabs/windows/contexts
+   * that a HeadsUpDisplay can be activated for.
+   */
+  this.activatedContexts = [];
+
+  /**
+   * Collection of outer window IDs mapping to HUD IDs.
+   */
+  this.windowIds = {};
+
+  /**
+   * Each HeadsUpDisplay has a set of filter preferences
+   */
+  this.filterPrefs = {};
+
+  /**
+   * Keeps a reference for each HeadsUpDisplay that is created
+   */
+  this.hudReferences = {};
+
+  /**
+   * Requests that haven't finished yet.
+   */
+  this.openRequests = {};
+
+  /**
+   * Response headers for requests that haven't finished yet.
+   */
+  this.openResponseHeaders = {};
 };
 
 HUD_SERVICE.prototype =
 {
   /**
    * L10N shortcut function
    *
    * @param string aName
@@ -1309,38 +1339,22 @@ HUD_SERVICE.prototype =
    *
    * @returns object
    */
   get consoleUI() {
     return HeadsUpDisplayUICommands;
   },
 
   /**
-   * Collection of HUDIds that map to the tabs/windows/contexts
-   * that a HeadsUpDisplay can be activated for.
-   */
-  activatedContexts: [],
-
-  /**
-   * Collection of outer window IDs mapping to HUD IDs.
-   */
-  windowIds: {},
-
-  /**
    * The sequencer is a generator (after initialization) that returns unique
    * integers
    */
   sequencer: null,
 
   /**
-   * Each HeadsUpDisplay has a set of filter preferences
-   */
-  filterPrefs: {},
-
-  /**
    * Gets the ID of the outer window of this DOM window
    *
    * @param nsIDOMWindow aWindow
    * @returns integer
    */
   getWindowId: function HS_getWindowId(aWindow)
   {
     return aWindow.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils).outerWindowID;
@@ -1677,21 +1691,16 @@ HUD_SERVICE.prototype =
         node.classList.add("hud-filtered-by-string");
       }
     }
 
     this.regroupOutput(outputNode);
   },
 
   /**
-   * Keeps a reference for each HeadsUpDisplay that is created
-   */
-  hudReferences: {},
-
-  /**
    * Register a reference of each HeadsUpDisplay that is created
    */
   registerHUDReference:
   function HS_registerHUDReference(aHUD)
   {
     this.hudReferences[aHUD.hudId] = aHUD;
 
     let id = ConsoleUtils.supString(aHUD.hudId);
@@ -1725,16 +1734,18 @@ HUD_SERVICE.prototype =
   {
     let hud = this.getHudReferenceById(aHUDId);
 
     // Remove children from the output. If the output is not cleared, there can
     // be leaks as some nodes has node.onclick = function; set and GC can't
     // remove the nodes then.
     hud.jsterm.clearOutput();
 
+    hud.destroy();
+
     // Make sure that the console panel does not try to call
     // deactivateHUDForContext() again.
     hud.consoleWindowUnregisterOnHide = false;
 
     // Remove the HUDBox and the consolePanel if the Web Console is inside a
     // floating panel.
     hud.HUDBox.parentNode.removeChild(hud.HUDBox);
     if (hud.consolePanel) {
@@ -1821,16 +1832,18 @@ HUD_SERVICE.prototype =
     this.openRequests = {};
     this.openResponseHeaders = {};
 
     // delete the storage as it holds onto channels
     delete this.storage;
     delete this.defaultFilterPrefs;
     delete this.defaultGlobalConsolePrefs;
 
+    delete this.lastFinishedRequestCallback;
+
     HUDWindowObserver.uninit();
     HUDConsoleObserver.uninit();
     ConsoleAPIObserver.shutdown();
   },
 
   /**
    * Shutdown all HeadsUpDisplays on xpcom-shutdown
    *
@@ -2120,26 +2133,16 @@ HUD_SERVICE.prototype =
   /**
    * Registry of ApplicationHooks used by specified Gecko Apps
    *
    * @returns Specific Gecko 'ApplicationHooks' Object/Mixin
    */
   applicationHooks: null,
 
   /**
-   * Requests that haven't finished yet.
-   */
-  openRequests: {},
-
-  /**
-   * Response headers for requests that haven't finished yet.
-   */
-  openResponseHeaders: {},
-
-  /**
    * Assign a function to this property to listen for finished httpRequests.
    * Used by unit tests.
    */
   lastFinishedRequestCallback: null,
 
   /**
    * Opens a NetworkPanel.
    *
@@ -2234,41 +2237,40 @@ HUD_SERVICE.prototype =
             let loggedNode = self.logNetActivity(httpActivity);
 
             // In some cases loggedNode can be undefined (e.g. if an image was
             // requested). Don't continue in such a case.
             if (!loggedNode) {
               return;
             }
 
-            // Add listener for the response body.
-            let newListener = new ResponseListener(httpActivity);
             aChannel.QueryInterface(Ci.nsITraceableChannel);
 
-            httpActivity.response.listener = newListener;
-
-            let tee = Cc["@mozilla.org/network/stream-listener-tee;1"].
-                      createInstance(Ci.nsIStreamListenerTee);
-
             // The response will be written into the outputStream of this pipe.
             // This allows us to buffer the data we are receiving and read it
             // asynchronously.
             // Both ends of the pipe must be blocking.
             let sink = Cc["@mozilla.org/pipe;1"].createInstance(Ci.nsIPipe);
 
             // The streams need to be blocking because this is required by the
             // stream tee.
             sink.init(false, false, HUDService.responsePipeSegmentSize,
                       PR_UINT32_MAX, null);
 
+            // Add listener for the response body.
+            let newListener = new ResponseListener(httpActivity);
+
             // Remember the input stream, so it isn't released by GC.
             newListener.inputStream = sink.inputStream;
+            newListener.sink = sink;
+
+            let tee = Cc["@mozilla.org/network/stream-listener-tee;1"].
+                      createInstance(Ci.nsIStreamListenerTee);
 
             let originalListener = aChannel.setNewListener(tee);
-            newListener.sink = sink;
 
             tee.init(originalListener, sink.outputStream, newListener);
 
             // Copy the request header data.
             aChannel.visitRequestHeaders({
               visitHeader: function(aName, aValue) {
                 httpActivity.request.header[aName] = aValue;
               }
@@ -2302,17 +2304,17 @@ HUD_SERVICE.prototype =
                 this._panelOpen = true;
               }
             }, false);
           }
           else {
             // Iterate over all currently ongoing requests. If aChannel can't
             // be found within them, then exit this function.
             let httpActivity = null;
-            for each (var item in self.openRequests) {
+            for each (let item in self.openRequests) {
               if (item.channel !== aChannel) {
                 continue;
               }
               httpActivity = item;
               break;
             }
 
             if (!httpActivity) {
@@ -2415,17 +2417,18 @@ HUD_SERVICE.prototype =
                 let fullStatusText = "[" + statusText + " " + timeText + "]";
                 statusNode.setAttribute("value", fullStatusText);
 
                 let clipboardTextPieces =
                   [ httpActivity.method, httpActivity.url, fullStatusText ];
                 msgObject.messageNode.clipboardText =
                   clipboardTextPieces.join(" ");
 
-                delete self.openRequests[item.id];
+                delete httpActivity.messageObject;
+                delete self.openRequests[httpActivity.id];
                 updatePanel = true;
                 break;
               }
             }
 
             if (updatePanel) {
               httpActivity.panels.forEach(function(weakRef) {
                 let panel = weakRef.get();
@@ -2652,24 +2655,35 @@ HUD_SERVICE.prototype =
    * around.
    *
    * @param nsIDOMEvent aEvent
    *        The dispatched event.
    * @returns void
    */
   onWindowUnload: function HS_onWindowUnload(aEvent)
   {
-    let gBrowser = aEvent.target.defaultView.gBrowser;
+    let window = aEvent.target.defaultView;
+
+    window.removeEventListener("unload", this.onWindowUnload, false);
+
+    let gBrowser = window.gBrowser;
     let tabContainer = gBrowser.tabContainer;
 
+    tabContainer.removeEventListener("TabClose", this.onTabClose, false);
+
     let tab = tabContainer.firstChild;
     while (tab != null) {
       this.deactivateHUDForContext(tab, false);
       tab = tab.nextSibling;
     }
+
+    if (window.webConsoleCommandController) {
+      window.controllers.removeController(window.webConsoleCommandController);
+      window.webConsoleCommandController = null;
+    }
   },
 
   /**
    * windowInitializer - checks what Gecko app is running and inits the HUD
    *
    * @param nsIDOMWindow aContentWindow
    * @returns void
    */
@@ -2685,23 +2699,18 @@ HUD_SERVICE.prototype =
     let docElem = xulWindow.document.documentElement;
     if (!docElem || docElem.getAttribute("windowtype") != "navigator:browser" ||
         !xulWindow.gBrowser) {
       // Do not do anything unless we have a browser window.
       // This may be a view-source window or other type of non-browser window.
       return;
     }
 
-    xulWindow.addEventListener("unload", this.onWindowUnload, false);
-
     let gBrowser = xulWindow.gBrowser;
 
-    let container = gBrowser.tabContainer;
-    container.addEventListener("TabClose", this.onTabClose, false);
-
     let _browser = gBrowser.
       getBrowserForDocument(aContentWindow.top.document);
     let nBox = gBrowser.getNotificationBox(_browser);
     let nBoxId = nBox.getAttribute("id");
     let hudId = "hud_" + nBoxId;
     let windowUI = nBox.ownerDocument.getElementById("console_window_" + hudId);
     if (windowUI) {
       // The Web Console popup is already open, no need to continue.
@@ -2711,16 +2720,19 @@ HUD_SERVICE.prototype =
       }
       return;
     }
 
     if (!this.canActivateContext(hudId)) {
       return;
     }
 
+    xulWindow.addEventListener("unload", this.onWindowUnload, false);
+    gBrowser.tabContainer.addEventListener("TabClose", this.onTabClose, false);
+
     this.registerDisplay(hudId);
 
     let hudNode;
     let childNodes = nBox.childNodes;
 
     for (let i = 0; i < childNodes.length; i++) {
       let id = childNodes[i].getAttribute("id");
       // `id` is a string with the format "hud_<number>".
@@ -2770,19 +2782,20 @@ HUD_SERVICE.prototype =
    * Adds the command controller to the XUL window if it's not already present.
    *
    * @param nsIDOMWindow aWindow
    *        The browser XUL window.
    * @returns void
    */
   createController: function HUD_createController(aWindow)
   {
-    if (aWindow.commandController == null) {
-      aWindow.commandController = new CommandController(aWindow);
-      aWindow.controllers.insertControllerAt(0, aWindow.commandController);
+    if (aWindow.webConsoleCommandController == null) {
+      aWindow.webConsoleCommandController = new CommandController(aWindow);
+      aWindow.controllers.insertControllerAt(0,
+        aWindow.webConsoleCommandController);
     }
   },
 
   /**
    * Animates the Console appropriately.
    *
    * @param string aHUDId The ID of the console.
    * @param string aDirection Whether to animate the console appearing
@@ -3606,51 +3619,54 @@ HeadsUpDisplay.prototype = {
    * Creates the UI for re-positioning the console
    *
    * @return nsIDOMNode
    *         The toolbarbutton which holds the menu that allows the user to
    *         change the console position.
    */
   createPositionUI: function HUD_createPositionUI()
   {
-    let self = this;
+    this._positionConsoleAbove = (function HUD_positionAbove() {
+      this.positionConsole("above");
+    }).bind(this);
+
+    this._positionConsoleBelow = (function HUD_positionBelow() {
+      this.positionConsole("below");
+    }).bind(this);
+    this._positionConsoleWindow = (function HUD_positionWindow() {
+      this.positionConsole("window");
+    }).bind(this);
 
     let button = this.makeXULNode("toolbarbutton");
     button.setAttribute("type", "menu");
     button.setAttribute("label", this.getStr("webConsolePosition"));
     button.setAttribute("tooltip", this.getStr("webConsolePositionTooltip"));
 
     let menuPopup = this.makeXULNode("menupopup");
     button.appendChild(menuPopup);
 
     let itemAbove = this.makeXULNode("menuitem");
     itemAbove.setAttribute("label", this.getStr("webConsolePositionAbove"));
     itemAbove.setAttribute("type", "checkbox");
     itemAbove.setAttribute("autocheck", "false");
-    itemAbove.addEventListener("command", function() {
-      self.positionConsole("above");
-    }, false);
+    itemAbove.addEventListener("command", this._positionConsoleAbove, false);
     menuPopup.appendChild(itemAbove);
 
     let itemBelow = this.makeXULNode("menuitem");
     itemBelow.setAttribute("label", this.getStr("webConsolePositionBelow"));
     itemBelow.setAttribute("type", "checkbox");
     itemBelow.setAttribute("autocheck", "false");
-    itemBelow.addEventListener("command", function() {
-      self.positionConsole("below");
-    }, false);
+    itemBelow.addEventListener("command", this._positionConsoleBelow, false);
     menuPopup.appendChild(itemBelow);
 
     let itemWindow = this.makeXULNode("menuitem");
     itemWindow.setAttribute("label", this.getStr("webConsolePositionWindow"));
     itemWindow.setAttribute("type", "checkbox");
     itemWindow.setAttribute("autocheck", "false");
-    itemWindow.addEventListener("command", function() {
-      self.positionConsole("window");
-    }, false);
+    itemWindow.addEventListener("command", this._positionConsoleWindow, false);
     menuPopup.appendChild(itemWindow);
 
     this.positionMenuitems = {
       last: null,
       above: itemAbove,
       below: itemBelow,
       window: itemWindow,
     };
@@ -3766,26 +3782,27 @@ HeadsUpDisplay.prototype = {
    * Creates the close button on the toolbar.
    *
    * @param nsIDOMNode aParent
    *        The toolbar to attach the close button to.
    * @return void
    */
   makeCloseButton: function HUD_makeCloseButton(aToolbar)
   {
-    let onCommand = (function HUD_closeButton_onCommand() {
+    this.closeButtonOnCommand = (function HUD_closeButton_onCommand() {
       HUDService.animate(this.hudId, ANIMATE_OUT, (function() {
         HUDService.deactivateHUDForContext(this.tab, true);
       }).bind(this));
     }).bind(this);
 
-    let closeButton = this.makeXULNode("toolbarbutton");
-    closeButton.classList.add("webconsole-close-button");
-    closeButton.addEventListener("command", onCommand, false);
-    aToolbar.appendChild(closeButton);
+    this.closeButton = this.makeXULNode("toolbarbutton");
+    this.closeButton.classList.add("webconsole-close-button");
+    this.closeButton.addEventListener("command",
+      this.closeButtonOnCommand, false);
+    aToolbar.appendChild(this.closeButton);
   },
 
   /**
    * Creates the "Clear Console" button.
    *
    * @param nsIDOMNode aParent
    *        The toolbar to attach the "Clear Console" button to.
    * @param string aHUDId
@@ -3854,17 +3871,36 @@ HeadsUpDisplay.prototype = {
   {
     return this.outputNode.childNodes;
   },
 
   ERRORS: {
     HUD_BOX_DOES_NOT_EXIST: "Heads Up Display does not exist",
     TAB_ID_REQUIRED: "Tab DOM ID is required",
     PARENTNODE_NOT_FOUND: "parentNode element not found"
-  }
+  },
+
+  /**
+   * Destroy the HUD object. Call this method to avoid memory leaks when the Web
+   * Console is closed.
+   */
+  destroy: function HUD_destroy()
+  {
+    this.jsterm.destroy();
+
+    this.positionMenuitems.above.removeEventListener("command",
+      this._positionConsoleAbove, false);
+    this.positionMenuitems.below.removeEventListener("command",
+      this._positionConsoleBelow, false);
+    this.positionMenuitems.window.removeEventListener("command",
+      this._positionConsoleWindow, false);
+
+    this.closeButton.removeEventListener("command",
+      this.closeButtonOnCommand, false);
+  },
 };
 
 
 //////////////////////////////////////////////////////////////////////////////
 // ConsoleAPIObserver
 //////////////////////////////////////////////////////////////////////////////
 
 let ConsoleAPIObserver = {
@@ -4454,22 +4490,25 @@ JSTerm.prototype = {
   init: function JST_init()
   {
     this.createSandbox();
 
     this.inputNode = this.mixins.inputNode;
     this.outputNode = this.mixins.outputNode;
     this.completeNode = this.mixins.completeNode;
 
+    this._keyPress = this.keyPress.bind(this);
+    this._inputEventHandler = this.inputEventHandler.bind(this);
+
     this.inputNode.addEventListener("keypress",
-      this.keyPress.bind(this), false);
+      this._keyPress, false);
     this.inputNode.addEventListener("input",
-      this.inputEventHandler.bind(this), false);
+      this._inputEventHandler, false);
     this.inputNode.addEventListener("keyup",
-      this.inputEventHandler.bind(this), false);
+      this._inputEventHandler, false);
   },
 
   get codeInputString()
   {
     return this.inputNode.value;
   },
 
   generateUI: function JST_generateUI()
@@ -5240,16 +5279,26 @@ JSTerm.prototype = {
    *        The proposed suffix for the inputNode value.
    */
   updateCompleteNode: function JSTF_updateCompleteNode(aSuffix)
   {
     // completion prefix = input, with non-control chars replaced by spaces
     let prefix = aSuffix ? this.inputNode.value.replace(/[\S]/g, " ") : "";
     this.completeNode.value = prefix + aSuffix;
   },
+
+  /**
+   * Destroy the JSTerm object. Call this method to avoid memory leaks.
+   */
+  destroy: function JST_destroy()
+  {
+    this.inputNode.removeEventListener("keypress", this._keyPress, false);
+    this.inputNode.removeEventListener("input", this._inputEventHandler, false);
+    this.inputNode.removeEventListener("keyup", this._inputEventHandler, false);
+  },
 };
 
 /**
  * Generates and attaches the JS Terminal part of the Web Console, which
  * essentially consists of the interactive JavaScript input facility.
  *
  * @param nsWeakPtr<nsIDOMWindow> aContext
  *        A weak pointer to the DOM window that contains the Web Console.
@@ -6394,18 +6443,17 @@ CommandController.prototype = {
    */
   selectAll: function CommandController_selectAll(aOutputNode)
   {
     aOutputNode.selectAll();
   },
 
   supportsCommand: function CommandController_supportsCommand(aCommand)
   {
-    return this.isCommandEnabled(aCommand) &&
-           this._getFocusedOutputNode() != null;
+    return this.isCommandEnabled(aCommand);
   },
 
   isCommandEnabled: function CommandController_isCommandEnabled(aCommand)
   {
     let outputNode = this._getFocusedOutputNode();
     if (!outputNode) {
       return false;
     }
--- a/browser/devtools/webconsole/Makefile.in
+++ b/browser/devtools/webconsole/Makefile.in
@@ -44,16 +44,17 @@ VPATH		= @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
 EXTRA_JS_MODULES = \
 		HUDService.jsm \
 		PropertyPanel.jsm \
 		NetworkHelper.jsm \
 		AutocompletePopup.jsm \
+		gcli.jsm \
 		$(NULL)
 
 ifdef ENABLE_TESTS
 ifneq (mobile,$(MOZ_BUILD_APP))
 	DIRS += test
 endif
 endif
 
new file mode 100644
--- /dev/null
+++ b/browser/devtools/webconsole/gcli.jsm
@@ -0,0 +1,567 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is GCLI.
+ *
+ * The Initial Developer of the Original Code is
+ * The Mozilla Foundation
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Joe Walker <jwalker@mozilla.com> (Original Author)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *********************************** WARNING ***********************************
+ *
+ * Do not edit this file without understanding where it comes from,
+ * Your changes are likely to be overwritten without warning.
+ *
+ * The original source for this file is:
+ *  https://github.com/mozilla/gcli/
+ *
+ *******************************************************************************
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ */
+
+///////////////////////////////////////////////////////////////////////////////
+
+/*
+ * This build of GCLI for Firefox is really 4 bits of code:
+ * - Browser support code - Currently just an implementation of the console
+ *   object that uses dump. We may need to add other browser shims to this.
+ * - A very basic commonjs AMD (Asynchronous Modules Definition) 'require'
+ *   implementation (which is just good enough to load GCLI). For more, see
+ *   http://wiki.commonjs.org/wiki/Modules/AsynchronousDefinition.
+ *   This alleviates the need for requirejs (http://requirejs.org/) which is
+ *   used when running in the browser.
+ *   This section of code is a copy of mini_require.js without the header and
+ *   footers. Changes to one should be reflected in the other.
+ * - A build of GCLI itself, packaged using dryice (for more details see the
+ *   project https://github.com/mozilla/dryice and the build file in this
+ *   project at Makefile.dryice.js)
+ * - Lastly, code to require the gcli object as needed by EXPORTED_SYMBOLS.
+ */
+
+var EXPORTED_SYMBOLS = [ "gcli" ];
+
+
+///////////////////////////////////////////////////////////////////////////////
+
+/*
+ * This creates a console object that somewhat replicates Firebug's console
+ * object. It currently writes to dump(), but should write to the web
+ * console's chrome error section (when it has one)
+ */
+
+
+/**
+ * String utility to ensure that strings are a specified length. Strings
+ * that are too long are truncated to the max length and the last char is
+ * set to "_". Strings that are too short are left padded with spaces.
+ *
+ * @param {string} aStr
+ *        The string to format to the correct length
+ * @param {number} aMaxLen
+ *        The maximum allowed length of the returned string
+ * @param {number} aMinLen (optional)
+ *        The minimum allowed length of the returned string. If undefined,
+ *        then aMaxLen will be used
+ * @param {object} aOptions (optional)
+ *        An object allowing format customization. The only customization
+ *        allowed currently is 'truncate' which can take the value "start" to
+ *        truncate strings from the start as opposed to the end.
+ * @return {string}
+ *        The original string formatted to fit the specified lengths
+ */
+function fmt(aStr, aMaxLen, aMinLen, aOptions) {
+  if (aMinLen == undefined) {
+    aMinLen = aMaxLen;
+  }
+  if (aStr == null) {
+    aStr = "";
+  }
+  if (aStr.length > aMaxLen) {
+    if (aOptions && aOptions.truncate == "start") {
+      return "_" + aStr.substring(aStr.length - aMaxLen + 1);
+    }
+    else {
+      return aStr.substring(0, aMaxLen - 1) + "_";
+    }
+  }
+  if (aStr.length < aMinLen) {
+    return Array(aMinLen - aStr.length + 1).join(" ") + aStr;
+  }
+  return aStr;
+}
+
+/**
+ * Utility to extract the constructor name of an object.
+ * Object.toString gives: "[object ?????]"; we want the "?????".
+ *
+ * @param {object} aObj
+ *        The object from which to extract the constructor name
+ * @return {string}
+ *        The constructor name
+ */
+function getCtorName(aObj) {
+  return Object.prototype.toString.call(aObj).slice(8, -1);
+}
+
+/**
+ * A single line stringification of an object designed for use by humans
+ *
+ * @param {any} aThing
+ *        The object to be stringified
+ * @return {string}
+ *        A single line representation of aThing, which will generally be at
+ *        most 60 chars long
+ */
+function stringify(aThing) {
+  if (aThing === undefined) {
+    return "undefined";
+  }
+
+  if (aThing === null) {
+    return "null";
+  }
+
+  if (typeof aThing == "object") {
+    try {
+      return getCtorName(aThing) + " " + fmt(JSON.stringify(aThing), 50, 0);
+    }
+    catch (ex) {
+      return "[stringify error]";
+    }
+  }
+
+  var str = aThing.toString().replace(/\s+/g, " ");
+  return fmt(str, 60, 0);
+}
+
+/**
+ * A multi line stringification of an object, designed for use by humans
+ *
+ * @param {any} aThing
+ *        The object to be stringified
+ * @return {string}
+ *        A multi line representation of aThing
+ */
+function log(aThing) {
+  if (aThing == null) {
+    return "null";
+  }
+
+  if (aThing == undefined) {
+    return "undefined";
+  }
+
+  if (typeof aThing == "object") {
+    var reply = "";
+    var type = getCtorName(aThing);
+    if (type == "Error") {
+      reply += "  " + aThing.message + "\n";
+      reply += logProperty("stack", aThing.stack);
+    }
+    else {
+      var keys = Object.getOwnPropertyNames(aThing);
+      if (keys.length > 0) {
+        reply += type + "\n";
+        keys.forEach(function(aProp) {
+          reply += logProperty(aProp, aThing[aProp]);
+        }, this);
+      }
+      else {
+        reply += type + " (enumerated with for-in)\n";
+        var prop;
+        for (prop in aThing) {
+          reply += logProperty(prop, aThing[prop]);
+        }
+      }
+    }
+
+    return reply;
+  }
+
+  return "  " + aThing.toString() + "\n";
+}
+
+/**
+ * Helper for log() which converts a property/value pair into an output
+ * string
+ *
+ * @param {string} aProp
+ *        The name of the property to include in the output string
+ * @param {object} aValue
+ *        Value assigned to aProp to be converted to a single line string
+ * @return {string}
+ *        Multi line output string describing the property/value pair
+ */
+function logProperty(aProp, aValue) {
+  var reply = "";
+  if (aProp == "stack" && typeof value == "string") {
+    var trace = parseStack(aValue);
+    reply += formatTrace(trace);
+  }
+  else {
+    reply += "    - " + aProp + " = " + stringify(aValue) + "\n";
+  }
+  return reply;
+}
+
+/**
+ * Parse a stack trace, returning an array of stack frame objects, where
+ * each has file/line/call members
+ *
+ * @param {string} aStack
+ *        The serialized stack trace
+ * @return {object[]}
+ *        Array of { file: "...", line: NNN, call: "..." } objects
+ */
+function parseStack(aStack) {
+  var trace = [];
+  aStack.split("\n").forEach(function(line) {
+    if (!line) {
+      return;
+    }
+    var at = line.lastIndexOf("@");
+    var posn = line.substring(at + 1);
+    trace.push({
+      file: posn.split(":")[0],
+      line: posn.split(":")[1],
+      call: line.substring(0, at)
+    });
+  }, this);
+  return trace;
+}
+
+/**
+ * parseStack() takes output from an exception from which it creates the an
+ * array of stack frame objects, this has the same output but using data from
+ * Components.stack
+ *
+ * @param {string} aFrame
+ *        The stack frame from which to begin the walk
+ * @return {object[]}
+ *        Array of { file: "...", line: NNN, call: "..." } objects
+ */
+function getStack(aFrame) {
+  if (!aFrame) {
+    aFrame = Components.stack.caller;
+  }
+  var trace = [];
+  while (aFrame) {
+    trace.push({
+      file: aFrame.filename,
+      line: aFrame.lineNumber,
+      call: aFrame.name
+    });
+    aFrame = aFrame.caller;
+  }
+  return trace;
+};
+
+/**
+ * Take the output from parseStack() and convert it to nice readable
+ * output
+ *
+ * @param {object[]} aTrace
+ *        Array of trace objects as created by parseStack()
+ * @return {string} Multi line report of the stack trace
+ */
+function formatTrace(aTrace) {
+  var reply = "";
+  aTrace.forEach(function(frame) {
+    reply += fmt(frame.file, 20, 20, { truncate: "start" }) + " " +
+             fmt(frame.line, 5, 5) + " " +
+             fmt(frame.call, 75, 75) + "\n";
+  });
+  return reply;
+}
+
+/**
+ * Create a function which will output a concise level of output when used
+ * as a logging function
+ *
+ * @param {string} aLevel
+ *        A prefix to all output generated from this function detailing the
+ *        level at which output occurred
+ * @return {function}
+ *        A logging function
+ * @see createMultiLineDumper()
+ */
+function createDumper(aLevel) {
+  return function() {
+    var args = Array.prototype.slice.call(arguments, 0);
+    var data = args.map(function(arg) {
+      return stringify(arg);
+    });
+    dump(aLevel + ": " + data.join(", ") + "\n");
+  };
+}
+
+/**
+ * Create a function which will output more detailed level of output when
+ * used as a logging function
+ *
+ * @param {string} aLevel
+ *        A prefix to all output generated from this function detailing the
+ *        level at which output occurred
+ * @return {function}
+ *        A logging function
+ * @see createDumper()
+ */
+function createMultiLineDumper(aLevel) {
+  return function() {
+    dump(aLevel + "\n");
+    var args = Array.prototype.slice.call(arguments, 0);
+    args.forEach(function(arg) {
+      dump(log(arg));
+    });
+  };
+}
+
+/**
+ * The console object to expose
+ */
+var console = {
+  debug: createMultiLineDumper("debug"),
+  log: createDumper("log"),
+  info: createDumper("info"),
+  warn: createDumper("warn"),
+  error: createMultiLineDumper("error"),
+  trace: function Console_trace() {
+    var trace = getStack(Components.stack.caller);
+    dump(formatTrace(trace) + "\n");
+  },
+  clear: function Console_clear() {},
+
+  dir: createMultiLineDumper("dir"),
+  dirxml: createMultiLineDumper("dirxml"),
+  group: createDumper("group"),
+  groupEnd: createDumper("groupEnd")
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+
+// There are 2 virtually identical copies of this code:
+// - $GCLI_HOME/build/prefix-gcli.jsm
+// - $GCLI_HOME/build/mini_require.js
+// They should both be kept in sync
+
+var debugDependencies = false;
+
+/**
+ * Define a module along with a payload.
+ * @param {string} moduleName Name for the payload
+ * @param {ignored} deps Ignored. For compatibility with CommonJS AMD Spec
+ * @param {function} payload Function with (require, exports, module) params
+ */
+function define(moduleName, deps, payload) {
+  if (typeof moduleName != "string") {
+    console.error(this.depth + " Error: Module name is not a string.");
+    console.trace();
+    return;
+  }
+
+  if (arguments.length == 2) {
+    payload = deps;
+  }
+
+  if (debugDependencies) {
+    console.log("define: " + moduleName + " -> " + payload.toString()
+        .slice(0, 40).replace(/\n/, '\\n').replace(/\r/, '\\r') + "...");
+  }
+
+  if (moduleName in define.modules) {
+    console.error(this.depth + " Error: Redefining module: " + moduleName);
+  }
+  define.modules[moduleName] = payload;
+};
+
+/**
+ * The global store of un-instantiated modules
+ */
+define.modules = {};
+
+
+/**
+ * We invoke require() in the context of a Domain so we can have multiple
+ * sets of modules running separate from each other.
+ * This contrasts with JSMs which are singletons, Domains allows us to
+ * optionally load a CommonJS module twice with separate data each time.
+ * Perhaps you want 2 command lines with a different set of commands in each,
+ * for example.
+ */
+function Domain() {
+  this.modules = {};
+
+  if (debugDependencies) {
+    this.depth = "";
+  }
+}
+
+/**
+ * Lookup module names and resolve them by calling the definition function if
+ * needed.
+ * There are 2 ways to call this, either with an array of dependencies and a
+ * callback to call when the dependencies are found (which can happen
+ * asynchronously in an in-page context) or with a single string an no callback
+ * where the dependency is resolved synchronously and returned.
+ * The API is designed to be compatible with the CommonJS AMD spec and
+ * RequireJS.
+ * @param {string[]|string} deps A name, or names for the payload
+ * @param {function|undefined} callback Function to call when the dependencies
+ * are resolved
+ * @return {undefined|object} The module required or undefined for
+ * array/callback method
+ */
+Domain.prototype.require = function(deps, callback) {
+  if (Array.isArray(deps)) {
+    var params = deps.map(function(dep) {
+      return this.lookup(dep);
+    }, this);
+    if (callback) {
+      callback.apply(null, params);
+    }
+    return undefined;
+  }
+  else {
+    return this.lookup(deps);
+  }
+};
+
+/**
+ * Lookup module names and resolve them by calling the definition function if
+ * needed.
+ * @param {string} moduleName A name for the payload to lookup
+ * @return {object} The module specified by aModuleName or null if not found.
+ */
+Domain.prototype.lookup = function(moduleName) {
+  if (moduleName in this.modules) {
+    var module = this.modules[moduleName];
+    if (debugDependencies) {
+      console.log(this.depth + " Using module: " + moduleName);
+    }
+    return module;
+  }
+
+  if (!(moduleName in define.modules)) {
+    console.error(this.depth + " Missing module: " + moduleName);
+    return null;
+  }
+
+  var module = define.modules[moduleName];
+
+  if (debugDependencies) {
+    console.log(this.depth + " Compiling module: " + moduleName);
+  }
+
+  if (typeof module == "function") {
+    if (debugDependencies) {
+      this.depth += ".";
+    }
+
+    var exports = {};
+    try {
+      module(this.require.bind(this), exports, { id: moduleName, uri: "" });
+    }
+    catch (ex) {
+      console.error("Error using module: " + moduleName, ex);
+      throw ex;
+    }
+    module = exports;
+
+    if (debugDependencies) {
+      this.depth = this.depth.slice(0, -1);
+    }
+  }
+
+  // cache the resulting module object for next time
+  this.modules[moduleName] = module;
+
+  return module;
+};
+
+/**
+ * Expose the Domain constructor and a global domain (on the define function
+ * to avoid exporting more than we need. This is a common pattern with require
+ * systems)
+ */
+define.Domain = Domain;
+define.globalDomain = new Domain();
+
+/**
+ * Expose a default require function which is the require of the global
+ * sandbox to make it easy to use.
+ */
+var require = define.globalDomain.require.bind(define.globalDomain);
+
+
+///////////////////////////////////////////////////////////////////////////////
+
+/*
+ * The API of interest to people wanting to create GCLI commands is as
+ * follows. The implementation of this API is left to bug 659061 and other
+ * bugs.
+ */
+
+define('gcli/index', [ ], function(require, exports, module) {
+
+  exports.addCommand = function() { /* implementation goes here */ };
+  exports.removeCommand = function() { /* implementation goes here */ };
+  exports.startup = function() { /* implementation goes here */ };
+  exports.shutdown = function() { /* implementation goes here */ };
+
+});
+
+///////////////////////////////////////////////////////////////////////////////
+
+/*
+ * require GCLI so it can be exported as declared in EXPORTED_SYMBOLS
+ * The dependencies specified here should be the same as in Makefile.dryice.js
+ */
+var gcli = require("gcli/index");
+gcli.createView = require("gcli/ui/start/firefox");
+gcli._internal = { require: require, define: define, console: console };
+
--- a/browser/devtools/webconsole/test/browser/Makefile.in
+++ b/browser/devtools/webconsole/test/browser/Makefile.in
@@ -103,16 +103,17 @@ include $(topsrcdir)/config/rules.mk
 	browser_webconsole_bug_592442_closing_brackets.js \
 	browser_webconsole_bug_593003_iframe_wrong_hud.js \
 	browser_webconsole_bug_601909_remember_height.js \
 	browser_webconsole_bug_613013_console_api_iframe.js \
 	browser_webconsole_bug_597756_reopen_closed_tab.js \
 	browser_webconsole_bug_600183_charset.js \
 	browser_webconsole_bug_601177_log_levels.js \
 	browser_webconsole_bug_597460_filter_scroll.js \
+	browser_webconsole_gcli_require.js \
 	browser_webconsole_console_extras.js \
 	browser_webconsole_bug_598357_jsterm_output.js \
 	browser_webconsole_bug_603750_websocket.js \
 	browser_webconsole_abbreviate_source_url.js \
 	browser_webconsole_view_source.js \
 	browser_webconsole_bug_602572_log_bodies_checkbox.js \
 	browser_webconsole_bug_614793_jsterm_scroll.js \
 	browser_webconsole_bug_599725_response_headers.js \
--- a/browser/devtools/webconsole/test/browser/browser_webconsole_bug_586388_select_all.js
+++ b/browser/devtools/webconsole/test/browser/browser_webconsole_bug_586388_select_all.js
@@ -31,17 +31,17 @@ function testSelectionWhenMovingBetweenB
 
   outputNode = jsterm.outputNode;
 
   ok(outputNode.childNodes.length >= 3, "the output node has children after " +
      "executing some JavaScript");
 
   // Test that the global Firefox "Select All" functionality (e.g. Edit >
   // Select All) works properly in the Web Console.
-  let commandController = window.commandController;
+  let commandController = window.webConsoleCommandController;
   ok(commandController != null, "the window has a command controller object");
 
   commandController.selectAll(outputNode);
   is(outputNode.selectedCount, outputNode.childNodes.length, "all console " +
      "messages are selected after performing a regular browser select-all " +
      "operation");
 
   outputNode.selectedIndex = -1;
--- a/browser/devtools/webconsole/test/browser/browser_webconsole_bug_626484_output_copy_order.js
+++ b/browser/devtools/webconsole/test/browser/browser_webconsole_bug_626484_output_copy_order.js
@@ -1,11 +1,11 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
-let itemsSet;
+let itemsSet, HUD;
 
 function test() {
   addTab("data:text/html,Web Console test for bug 626484");
   browser.addEventListener("load", tabLoaded, true);
 }
 
 function tabLoaded(aEvent) {
   browser.removeEventListener(aEvent.type, arguments.callee, true);
@@ -25,16 +25,17 @@ function tabLoaded(aEvent) {
 
   nextTest();
 }
 
 function nextTest() {
   if (itemsSet.length === 0) {
     outputNode.clearSelection();
     HUD.jsterm.clearOutput();
+    HUD = null;
     finish();
   }
   else {
     outputNode.clearSelection();
     let items = itemsSet.shift();
     items.forEach(function (index) {
       outputNode.addItemToSelection(outputNode.getItemAtIndex(index));
     });
new file mode 100644
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser/browser_webconsole_gcli_require.js
@@ -0,0 +1,122 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Tests that source URLs in the Web Console can be clicked to display the
+// standard View Source window.
+
+var modules = { gcli: null };
+
+Components.utils.import("resource:///modules/gcli.jsm", modules);
+
+var define, require, console;
+
+function test() {
+
+  define = modules.gcli._internal.define;
+  require = modules.gcli._internal.require;
+  console = modules.gcli._internal.console;
+
+  define('gclitest/requirable', [], function(require, exports, module) {
+    exports.thing1 = 'thing1';
+    exports.thing2 = 2;
+
+    let status = 'initial';
+    exports.setStatus = function(aStatus) { status = aStatus; };
+    exports.getStatus = function() { return status; };
+  });
+
+  define('gclitest/unrequirable', [], function(require, exports, module) {
+    null.throwNPE();
+  });
+
+  define('gclitest/recurse', [], function(require, exports, module) {
+    require('gclitest/recurse');
+  });
+
+  testWorking();
+  testLeakage();
+  testMultiImport();
+  testRecursive();
+  testUncompilable();
+
+  finishTest();
+
+  delete define.modules['gclitest/requirable'];
+  delete define.globalDomain.modules['gclitest/requirable'];
+  delete define.modules['gclitest/unrequirable'];
+  delete define.globalDomain.modules['gclitest/unrequirable'];
+  delete define.modules['gclitest/recurse'];
+  delete define.globalDomain.modules['gclitest/recurse'];
+
+  define = null;
+  require = null;
+  console = null;
+
+  modules = null;
+}
+
+function testWorking() {
+  // There are lots of requirement tests that we could be doing here
+  // The fact that we can get anything at all working is a testament to
+  // require doing what it should - we don't need to test the
+  let requireable = require('gclitest/requirable');
+  ok('thing1' == requireable.thing1, 'thing1 was required');
+  ok(2 == requireable.thing2, 'thing2 was required');
+  ok(requireable.thing3 === undefined, 'thing3 was not required');
+}
+
+function testDomains() {
+  let requireable = require('gclitest/requirable');
+  ok(requireable.status === undefined, 'requirable has no status');
+  requireable.setStatus(null);
+  ok(null === requireable.getStatus(), 'requirable.getStatus changed to null');
+  ok(requireable.status === undefined, 'requirable still has no status');
+  requireable.setStatus('42');
+  ok('42' == requireable.getStatus(), 'requirable.getStatus changed to 42');
+  ok(requireable.status === undefined, 'requirable *still* has no status');
+
+  let domain = new define.Domain();
+  let requireable2 = domain.require('gclitest/requirable');
+  ok(requireable2.status === undefined, 'requirable2 has no status');
+  ok('initial' === requireable2.getStatus(), 'requirable2.getStatus is initial');
+  requireable2.setStatus(999);
+  ok(999 === requireable2.getStatus(), 'requirable2.getStatus changed to 999');
+  ok(requireable2.status === undefined, 'requirable2 still has no status');
+
+  t.verifyEqual('42', requireable.getStatus());
+  ok(requireable.status === undefined, 'requirable has no status (as expected)');
+
+  delete domain.modules['gclitest/requirable'];
+}
+
+function testLeakage() {
+  let requireable = require('gclitest/requirable');
+  ok(requireable.setup == null, 'leakage of setup');
+  ok(requireable.shutdown == null, 'leakage of shutdown');
+  ok(requireable.testWorking == null, 'leakage of testWorking');
+}
+
+function testMultiImport() {
+  let r1 = require('gclitest/requirable');
+  let r2 = require('gclitest/requirable');
+  ok(r1 === r2, 'double require was strict equal');
+}
+
+function testUncompilable() {
+  // It's not totally clear how a module loader should perform with unusable
+  // modules, however at least it should go into a flat spin ...
+  // GCLI mini_require reports an error as it should
+  try {
+    let unrequireable = require('gclitest/unrequirable');
+    fail();
+  }
+  catch (ex) {
+    // an exception is expected
+  }
+}
+
+function testRecursive() {
+  // See Bug 658583
+  // require('gclitest/recurse');
+  // Also see the comments in the testRecursive() function
+}
--- a/browser/devtools/webconsole/test/browser/head.js
+++ b/browser/devtools/webconsole/test/browser/head.js
@@ -52,18 +52,16 @@ function pprint(aObj)
     else {
       log(prop + ": " + aObj[prop]);
     }
   }
 }
 
 let tab, browser, hudId, hud, hudBox, filterBox, outputNode, cs;
 
-let win = gBrowser.selectedBrowser;
-
 function addTab(aURL)
 {
   gBrowser.selectedTab = gBrowser.addTab();
   content.location = aURL;
   tab = gBrowser.selectedTab;
   browser = gBrowser.getBrowserForTab(tab);
 }
 
@@ -180,11 +178,8 @@ function tearDown()
   }
   tab = browser = hudId = hud = filterBox = outputNode = cs = null;
 }
 
 registerCleanupFunction(tearDown);
 
 waitForExplicitFinish();
 
-// removed tests:
-// browser_webconsole_bug_580030_errors_after_page_reload.js \
-// browser_webconsole_bug_595350_multiple_windows_and_tabs.js \
--- a/browser/installer/package-manifest.in
+++ b/browser/installer/package-manifest.in
@@ -103,19 +103,16 @@
 #endif
 @BINPATH@/blocklist.xml
 #ifdef XP_UNIX
 @BINPATH@/run-mozilla.sh
 #ifndef XP_MACOSX
 @BINPATH@/mozilla-xremote-client
 #endif
 #endif
-#ifdef MOZ_SPLASHSCREEN
-@BINPATH@/splash.bmp
-#endif
 
 ; [Components]
 @BINPATH@/components/components.manifest
 @BINPATH@/components/alerts.xpt
 #ifdef ACCESSIBILITY
 #ifdef XP_WIN32
 @BINPATH@/AccessibleMarshal.dll
 @BINPATH@/components/accessibility-msaa.xpt
--- a/browser/locales/en-US/chrome/browser/preferences/advanced.dtd
+++ b/browser/locales/en-US/chrome/browser/preferences/advanced.dtd
@@ -59,17 +59,17 @@
 <!ENTITY updateTab.label                 "Update">
 
 <!ENTITY autoCheck.label                 "Automatically check for updates to:">
 <!ENTITY enableAppUpdate.label           "&brandShortName;">
 <!ENTITY enableAppUpdate.accesskey       "F">
 <!ENTITY enableAddonsUpdate2.label       "Add-ons">
 <!ENTITY enableAddonsUpdate2.accesskey   "n">
 <!ENTITY enableSearchUpdate.label        "Search Engines">
-<!ENTITY enableSearchUpdate.accesskey    "h">
+<!ENTITY enableSearchUpdate.accesskey    "E">
 <!ENTITY whenUpdatesFound.label          "When updates to &brandShortName; are found:">
 <!ENTITY askMe.label                     "Ask me what I want to do">
 <!ENTITY askMe.accesskey                 "k">
 <!ENTITY modeAutomatic.label             "Automatically download and install the update">
 <!ENTITY modeAutomatic.accesskey         "d">
 <!ENTITY modeAutoAddonWarn.label         "Warn me if this will disable any of my add-ons">
 <!ENTITY modeAutoAddonWarn.accesskey     "W">
 <!ENTITY updateHistory.label             "Show Update History">
--- a/browser/themes/gnomestripe/browser/aboutSessionRestore.css
+++ b/browser/themes/gnomestripe/browser/aboutSessionRestore.css
@@ -32,23 +32,49 @@
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 %endif
 
+html {
+  height: 100%;
+}
+
+body {
+  height: 100%;
+  text-align: center;
+}
+
 #errorPageContainer {
   background-image: url("moz-icon://stock/gtk-dialog-warning?size=dialog");
+  display: -moz-box;
+  width: -moz-available;
+  height: 70%;
+  -moz-box-orient: vertical;
+  text-align: start;
+}
+
+#errorShortDesc > p {
+  margin-top: 0.4em;
+  margin-bottom: 0;
+}
+
+#errorLongContent, #errorTrailerDesc {
+  display: -moz-box;
+  -moz-box-flex: 1;
+  -moz-box-orient: vertical;
 }
 
 #tabList {
+  margin-top: 2.5em;
   width: 100%;
-  height: 12em;
+  min-height: 12em;
 }
 
 treechildren::-moz-tree-image(icon),
 treechildren::-moz-tree-image(noicon) {
   padding-right: 2px;
   margin: 0px 2px;
   width: 16px;
   height: 16px;
--- a/browser/themes/gnomestripe/browser/browser.css
+++ b/browser/themes/gnomestripe/browser/browser.css
@@ -1313,40 +1313,45 @@ richlistitem[type~="action"][actiontype=
   -moz-appearance: none;
   list-style-image: url("chrome://browser/skin/reload-stop-go.png");
   margin: -1px;
   -moz-margin-start: 0;
   padding: 0 3px;
   background-origin: border-box;
   border: none;
   -moz-border-start: 1px solid rgba(0,0,0,.35);
+  box-shadow: 0 1px 0 rgba(0,0,0,.1) inset,
+              -1px -1px 1px rgba(255,255,255,.2) inset;
 }
 
 #urlbar:-moz-locale-dir(ltr) > toolbarbutton {
   border-top-right-radius: 2px;
   border-bottom-right-radius: 2px;
 }
 
 #urlbar:-moz-locale-dir(rtl) > toolbarbutton {
   border-top-left-radius: 2px;
   border-bottom-left-radius: 2px;
 }
 
-#urlbar > toolbarbutton:not([disabled]):active:hover {
+#urlbar > toolbarbutton:not([disabled]):active:hover,
+#urlbar-reload-button:not(:hover) {
+  -moz-border-start-style: none;
   -moz-padding-start: 4px;
-  -moz-border-start: none;
+  box-shadow: none;
+}
+
+#urlbar > toolbarbutton:not([disabled]):active:hover {
   box-shadow: 0 0 6.5px rgba(0,0,0,.4) inset,
               0 0 2px rgba(0,0,0,.4) inset;
 }
 
 #urlbar-go-button {
   -moz-image-region: rect(0px, 56px, 14px, 42px);
   background-image: -moz-linear-gradient(rgb(143,219,69), rgb(115,177,57));
-  box-shadow: 0 1px 0 rgba(0,0,0,.1) inset,
-              -1px -1px 0 rgba(255,255,255,.2) inset;
 }
 
 #urlbar-go-button:-moz-locale-dir(rtl) > .toolbarbutton-icon {
   -moz-transform: scaleX(-1);
 }
 
 #urlbar-go-button:hover {
   background-image: -moz-linear-gradient(rgb(163,232,92), rgb(137,196,81));
@@ -1354,25 +1359,21 @@ richlistitem[type~="action"][actiontype=
 
 #urlbar-reload-button {
   -moz-image-region: rect(0px, 14px, 14px, 0px);
 }
 
 #urlbar-reload-button:not([disabled]):hover {
   -moz-image-region: rect(0px, 28px, 14px, 14px);
   background-image: -moz-linear-gradient(rgb(137,183,233), rgb(79,130,195));
-  box-shadow: 0 1px 0 rgba(0,0,0,.1) inset,
-              -1px -1px 0 rgba(255,255,255,.2) inset;
 }
 
 #urlbar-stop-button {
   -moz-image-region: rect(0px, 42px, 14px, 28px);
   background-image: -moz-linear-gradient(rgb(226,99,99), rgb(199,68,68));
-  box-shadow: 0 1px 0 rgba(0,0,0,.1) inset,
-              -1px -1px 0 rgba(255,255,255,.2) inset;
 }
 
 #urlbar-stop-button:hover {
   background-image: -moz-linear-gradient(rgb(237,120,120), rgb(216,92,92));
 }
 
 /* Popup blocker button */
 #page-report-button {
--- a/browser/themes/gnomestripe/browser/jar.mn
+++ b/browser/themes/gnomestripe/browser/jar.mn
@@ -58,16 +58,17 @@ browser.jar:
   skin/classic/browser/places/organizer.css           (places/organizer.css)
 * skin/classic/browser/places/organizer.xml           (places/organizer.xml)
   skin/classic/browser/places/query.png               (places/query.png)
   skin/classic/browser/places/searching_16.png        (places/searching_16.png)
   skin/classic/browser/places/starPage.png            (places/starPage.png)
   skin/classic/browser/places/tag.png                 (places/tag.png)
   skin/classic/browser/places/toolbarDropMarker.png   (places/toolbarDropMarker.png)
   skin/classic/browser/places/unsortedBookmarks.png   (places/unsortedBookmarks.png)
+  skin/classic/browser/places/downloads.png           (places/downloads.png)
   skin/classic/browser/preferences/alwaysAsk.png      (preferences/alwaysAsk.png)
   skin/classic/browser/preferences/mail.png           (preferences/mail.png)
   skin/classic/browser/preferences/Options.png        (preferences/Options.png)
 #ifdef MOZ_SERVICES_SYNC
   skin/classic/browser/preferences/Options-sync.png   (preferences/Options-sync.png)
 #endif
 * skin/classic/browser/preferences/preferences.css    (preferences/preferences.css)
   skin/classic/browser/preferences/applications.css   (preferences/applications.css)
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..d641714aabe56751e54e0a24d1d6cb2188bee968
GIT binary patch
literal 599
zc$@)O0;v6oP)<h;3K|Lk000e1NJLTq000mG000mO1^@s6AM^iV0000PbVXQnQ*UN;
zcVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBUz`AI}URCwBA{Qv(y10{eFn*kAXq<0C*
zvAQy`K=}XuFfe?0{QKbY<fjf8ia`dT<BXm1|IdD0`~SiBGhlr7)7t-;yX60e&z9mx
zSIdIUSs<JLG5%pV@^Lnpug>Mfz{JXk)e9`R{Pz3*cZNUzf5O?g08Rt`{{IEn2x60L
z0Lb>A|GvQ4BpJZU!2~tnE8GB9c06GKjJ6wm5-jShoQw>toJ<Uy0?Z75{{3S31v3E1
z28l^%vwz6mr@-+0+kb{nFaF$Fk@8d(=7IticE)vHx@nwz>>^-+r#~+-{DOwThrdr5
zJf%t*7^HygAI}-KU!D(=$b}~)Mn*;kU>rM1D+_KhQ*-0I^JhQY`7prF#Lb|>;=pk7
z*6#1m?!Na~nfh!WSTD=~kYORyByDBYg|?ZiyK>+8eSqQTe~2L*OneN=EVc}%Zted1
z=*By*HCfLOL((9^0FVhF%<S7GZmn!6vdLW2mG{w~lMKN0#vsRH#&GKTp0D>Vy!GEy
z`tlGcW}ycBhZ(>GN`TNnWpOMKw$ODIUt_Fc%g+cj_sq@1U#{(c8MdeW4anv{Q2Y<5
z_aCwgU<R-QF^_RHzlEj;&t#x}rW-rI=ABvm;TTXHlrVlE8Soz^44{Uv0x=iJ5GV}-
l-=La7^ly-6SQr2V7yvlA508N*8PNa$002ovPDHLkV1kWpAIAUy
--- a/browser/themes/gnomestripe/browser/places/places.css
+++ b/browser/themes/gnomestripe/browser/places/places.css
@@ -65,16 +65,21 @@ treechildren::-moz-tree-image(container,
   -moz-image-region: auto;
 }
 
 /* query-nodes should be styled even if they're not expandable */
 treechildren::-moz-tree-image(title, query) {
   list-style-image: url("chrome://browser/skin/places/query.png");
 }
 
+treechildren::-moz-tree-image(query, OrganizerQuery_Downloads) {
+  list-style-image: url("chrome://browser/skin/places/downloads.png");
+  -moz-image-region: auto;
+}
+
 treechildren::-moz-tree-image(title, query, tagContainer),
 treechildren::-moz-tree-image(query, OrganizerQuery_Tags) {
   list-style-image: url("chrome://mozapps/skin/places/tagContainerIcon.png");
 }
 
 /* calendar icon for folders grouping items by date */
 treechildren::-moz-tree-image(title, query, dayContainer) {
   list-style-image: url("chrome://browser/skin/places/calendar.png");
--- a/browser/themes/pinstripe/browser/aboutSessionRestore.css
+++ b/browser/themes/pinstripe/browser/aboutSessionRestore.css
@@ -31,23 +31,49 @@
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 %endif
 
+html {
+  height: 100%;
+}
+
+body {
+  height: 100%;
+  text-align: center;
+}
+
 #errorPageContainer {
   background-image: url("chrome://global/skin/icons/warning-64.png");
+  display: -moz-box;
+  width: -moz-available;
+  height: 70%;
+  -moz-box-orient: vertical;
+  text-align: start;
+}
+
+#errorShortDesc > p {
+  margin-top: 0.4em;
+  margin-bottom: 0;
+}
+
+#errorLongContent, #errorTrailerDesc {
+  display: -moz-box;
+  -moz-box-flex: 1;
+  -moz-box-orient: vertical;
 }
 
 #tabList {
+  margin-top: 2.5em;
   width: 100%;
-  height: 12em;
+  min-height: 12em;
 }
 
 treechildren::-moz-tree-image(icon),
 treechildren::-moz-tree-image(noicon) {
   padding-right: 2px;
   margin: 0px 2px;
   width: 16px;
   height: 16px;
--- a/browser/themes/pinstripe/browser/browser.css
+++ b/browser/themes/pinstripe/browser/browser.css
@@ -1037,61 +1037,62 @@ richlistitem[type~="action"][actiontype=
 #urlbar > toolbarbutton {
   list-style-image: url("chrome://browser/skin/reload-stop-go.png");
   margin: 0;
   -moz-margin-start: 2px;
   padding: 0 3px;
   background-origin: border-box;
   border: none;
   -moz-border-start: 1px solid rgba(0,0,0,.25);
+  box-shadow: 0 1px 0 rgba(0,0,0,.1) inset,
+              -1px -1px 1px rgba(255,255,255,.15) inset;
 }
 
 #urlbar:-moz-locale-dir(ltr) > toolbarbutton {
   border-top-right-radius: 2px;
   border-bottom-right-radius: 2px;
 }
 
 #urlbar:-moz-locale-dir(rtl) > toolbarbutton {
   border-top-left-radius: 2px;
   border-bottom-left-radius: 2px;
 }
 
+#urlbar > toolbarbutton:not([disabled]):active:hover,
+#urlbar-reload-button:not(:hover) {
+  -moz-border-start-style: none;
+  -moz-padding-start: 4px;
+  box-shadow: none;
+}
+
 #urlbar > toolbarbutton:not([disabled]):active:hover {
   box-shadow: @toolbarbuttonPressedInnerShadow@;
-  -moz-padding-start: 4px;
-  -moz-border-start: none;
 }
 
 #urlbar-go-button {
   -moz-image-region: rect(0px, 56px, 14px, 42px);
   background-image: -moz-linear-gradient(rgb(184,221,142), rgb(154,201,111) 49%, rgb(130,187,92) 51%, rgb(114,171,79));
-  box-shadow: 0 1px 0 rgba(0,0,0,.1) inset,
-              -1px -1px 1px rgba(255,255,255,.15) inset;
 }
 
 #urlbar-go-button:-moz-locale-dir(rtl) > .toolbarbutton-icon {
   -moz-transform: scaleX(-1);
 }
 
 #urlbar-reload-button {
   -moz-image-region: rect(0px, 14px, 14px, 0px);
 }
 
 #urlbar-reload-button:not([disabled]):hover {
   -moz-image-region: rect(0px, 28px, 14px, 14px);
   background-image: -moz-linear-gradient(rgb(162,207,241), rgb(111,178,225) 49%, rgb(91,159,217) 51%, rgb(62,138,200));
-  box-shadow: 0 1px 0 rgba(0,0,0,.1) inset,
-              -1px -1px 1px rgba(255,255,255,.15) inset;
 }
 
 #urlbar-stop-button {
   -moz-image-region: rect(0px, 42px, 14px, 28px);
   background-image: -moz-linear-gradient(rgb(231,162,140), rgb(209,119,100) 49%, rgb(193,92,78) 51%, rgb(173,72,58));
-  box-shadow: 0 1px 0 rgba(0,0,0,.1) inset,
-              -1px -1px 1px rgba(255,255,255,.15) inset;
 }
 
 /* POPUP BLOCKER BUTTON */
 #page-report-button {
   list-style-image: url("chrome://browser/skin/urlbar-popup-blocked.png");
   -moz-image-region: rect(0, 16px, 16px, 0);
 }
 
--- a/browser/themes/pinstripe/browser/jar.mn
+++ b/browser/themes/pinstripe/browser/jar.mn
@@ -78,16 +78,17 @@ browser.jar:
   skin/classic/browser/places/pageStarred.png               (places/pageStarred.png)
   skin/classic/browser/places/searching_16.png              (places/searching_16.png)
   skin/classic/browser/places/starred48.png                 (places/starred48.png)
   skin/classic/browser/places/unstarred48.png               (places/unstarred48.png)
   skin/classic/browser/places/unfiledBookmarks.png          (places/unfiledBookmarks.png)
   skin/classic/browser/places/twisty-open.gif               (places/twisty-open.gif)
   skin/classic/browser/places/twisty-closed.gif             (places/twisty-closed.gif)
   skin/classic/browser/places/tag.png                       (places/tag.png)
+  skin/classic/browser/places/downloads.png                 (places/downloads.png)
   skin/classic/browser/places/expander-closed-active.png    (places/expander-closed-active.png)
   skin/classic/browser/places/expander-closed.png           (places/expander-closed.png)
   skin/classic/browser/places/expander-open-active.png      (places/expander-open-active.png)
   skin/classic/browser/places/expander-open.png             (places/expander-open.png)
   skin/classic/browser/preferences/alwaysAsk.png            (preferences/alwaysAsk.png)
   skin/classic/browser/preferences/application.png          (preferences/application.png)
   skin/classic/browser/preferences/Options.png              (preferences/Options.png)
 #ifdef MOZ_SERVICES_SYNC
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0756cb6806dd77f905f97344937c7bebe8fbbfba
GIT binary patch
literal 678
zc$@*I0$KfuP)<h;3K|Lk000e1NJLTq000mG000mO1^@s6AM^iV0000PbVXQnQ*UN;
zcVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBU!NJ&INRCwB?Q%z_SQ4pTDyUE711>2-5
zLbZY(1gk_MrFsy(2_jPbgHn&;!6<m`K|B<1B1Ev~N)aoT-t<%rQfgOivDlNM#Rgk7
zsbHJU?!G_Yyza&{)RP0V`{sKy-^`nNk4P!uf5gI1zIYi(9XNb%awfLd%#hf+Eg1m)
z%s=$!j&((Tm^arkyiTA&1zb}A%E<nGnR6%3!}jD3ZGU%{Vf5wbfuX^P_W1|JpZ75#
zsjEQ8*OkC+0Zs8O@YVaM?Y8(f;0Xa>{^JNTsv;C7I8=oTOmc1OwZbT4a#I3mfVmJ5
zsDOYoZ3l#FY@?7m0)3#rER3scf+`ZKZCoQ3_`K#ML;tXe66&W(Ev$gm2yjg;zDa&X
zKveeKed#Zx6FToE+X1!$7&|TSm=9H@C~*itv=~6Td1=ob<x^1=EWl!JgzVB4cow~B
zri@2@CokHm<}{eZf(7>zc%14~gs;NYgI9oeaaj7j3{MJAeNhxQYL(;{`{DNB_^I@v
z)L75qY{HLKLCB3wGl&6pkbtS#cV6jzx%bw<*=M<qhhRiQC=IPXUvhq&E=*5Xq-TQ9
zm^wnBHBb#itl&5m^g&<Q&<hf(*>u4^-qzhZmOYYb@vW-fj8PkA-p;vYXQkJD>`&mN
z!@M%OTSllBo#)>?@TSVvuQRDsI)Q_jeKWUKda-iJ8xLO9rr2<SNkpL3R@!W4jUM}G
zB9FNL+PlsjF{##T*mJxpN=3s9sFC0sOd?76M{&bo{L?5HH~t7P0D^rIGn}>e`v3p{
M07*qoM6N<$f^%9tk^lez
--- a/browser/themes/pinstripe/browser/places/places.css
+++ b/browser/themes/pinstripe/browser/places/places.css
@@ -139,16 +139,20 @@ treechildren::-moz-tree-image(container,
   list-style-image: url("chrome://browser/skin/places/unfiledBookmarks.png");
 }
 
 /* query-nodes should be styled even if they're not expandable */
 treechildren::-moz-tree-image(query) {
   list-style-image: url("chrome://browser/skin/places/query.png");
 }
 
+treechildren::-moz-tree-image(query, OrganizerQuery_Downloads) {
+  list-style-image: url("chrome://browser/skin/places/downloads.png");
+}
+
 treechildren::-moz-tree-image(title, query, tagContainer),
 treechildren::-moz-tree-image(query, OrganizerQuery_Tags) {
   list-style-image: url("chrome://mozapps/skin/places/tagContainerIcon.png");
 }
 
 /* calendar icon for folders grouping items by date */
 treechildren::-moz-tree-image(title, query, dayContainer) {
   list-style-image: url("chrome://browser/skin/places/history.png");
--- a/browser/themes/winstripe/browser/aboutSessionRestore.css
+++ b/browser/themes/winstripe/browser/aboutSessionRestore.css
@@ -31,23 +31,49 @@
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 %endif
 
+html {
+  height: 100%;
+}
+
+body {
+  height: 100%;
+  text-align: center;
+}
+
 #errorPageContainer {
   background-image: url("chrome://global/skin/icons/warning-large.png");
+  display: -moz-box;
+  width: -moz-available;
+  height: 70%;
+  -moz-box-orient: vertical;
+  text-align: start;
+}
+
+#errorShortDesc > p {
+  margin-top: 0.4em;
+  margin-bottom: 0;
+}
+
+#errorLongContent, #errorTrailerDesc {
+  display: -moz-box;
+  -moz-box-flex: 1;
+  -moz-box-orient: vertical;
 }
 
 #tabList {
+  margin-top: 2.5em;
   width: 100%;
-  height: 12em;
+  min-height: 12em;
 }
 
 treechildren::-moz-tree-image(icon),
 treechildren::-moz-tree-image(noicon) {
   padding-right: 2px;
   margin: 0px 2px;
   width: 16px;
   height: 16px;
--- a/browser/themes/winstripe/browser/browser-aero.css
+++ b/browser/themes/winstripe/browser/browser-aero.css
@@ -136,20 +136,20 @@
   #nav-bar + #customToolbars + #PersonalToolbar[collapsed=true] + #TabsToolbar[tabsontop=false]:last-child:not(:-moz-lwtheme) {
     background-color: transparent !important;
     color: black;
     text-shadow: 0 0 .5em white, 0 0 .5em white, 0 1px 0 rgba(255,255,255,.4);
     border-left-style: none !important;
     border-right-style: none !important;
   }
 
-  #toolbar-menubar :-moz-any(@primaryToolbarButtons@):not(#alltabs-button):not(#tabview-button):not(#new-tab-button) > .toolbarbutton-icon:not(:-moz-lwtheme),
-  #TabsToolbar[tabsontop=true] :-moz-any(@primaryToolbarButtons@):not(#alltabs-button):not(#tabview-button):not(#new-tab-button) > .toolbarbutton-icon:not(:-moz-lwtheme),
-  #navigator-toolbox[tabsontop=false] > #nav-bar :-moz-any(@primaryToolbarButtons@):not(#alltabs-button):not(#tabview-button):not(#new-tab-button) > .toolbarbutton-icon:not(:-moz-lwtheme),
-  #nav-bar + #customToolbars + #PersonalToolbar[collapsed=true] + #TabsToolbar[tabsontop=false]:last-child :-moz-any(@primaryToolbarButtons@):not(#alltabs-button):not(#tabview-button):not(#new-tab-button) > .toolbarbutton-icon:not(:-moz-lwtheme) {
+  #toolbar-menubar :-moz-any(@primaryToolbarButtons@):not(:-moz-any(#alltabs-button,#tabview-button,#new-tab-button,#sync-button[status])) > .toolbarbutton-icon:not(:-moz-lwtheme),
+  #TabsToolbar[tabsontop=true] :-moz-any(@primaryToolbarButtons@):not(:-moz-any(#alltabs-button,#tabview-button,#new-tab-button,#sync-button[status])) > .toolbarbutton-icon:not(:-moz-lwtheme),
+  #navigator-toolbox[tabsontop=false] > #nav-bar :-moz-any(@primaryToolbarButtons@):not(:-moz-any(#alltabs-button,#tabview-button,#new-tab-button,#sync-button[status])) > .toolbarbutton-icon:not(:-moz-lwtheme),
+  #nav-bar + #customToolbars + #PersonalToolbar[collapsed=true] + #TabsToolbar[tabsontop=false]:last-child :-moz-any(@primaryToolbarButtons@):not(:-moz-any(#alltabs-button,#tabview-button,#new-tab-button,#sync-button[status])) > .toolbarbutton-icon:not(:-moz-lwtheme) {
     list-style-image: url("chrome://browser/skin/Toolbar-inverted.png");
   }
 
   /* Vertical toolbar border */
   #main-window[sizemode=normal] #navigator-toolbox::after,
   #main-window[sizemode=normal] #navigator-toolbox[tabsontop=true] > toolbar:not(#toolbar-menubar):not(#TabsToolbar),
   #main-window[sizemode=normal] #navigator-toolbox[tabsontop=false] > toolbar:not(#toolbar-menubar):not(#nav-bar) {
     border-left: 1px solid @toolbarShadowColor@;
--- a/browser/themes/winstripe/browser/browser.css
+++ b/browser/themes/winstripe/browser/browser.css
@@ -669,17 +669,17 @@ menuitem.bookmark-item {
   counter-reset: smallicons;
 }
 
 @navbarLargeIcons@ {
   -moz-padding-start: 0;
   -moz-padding-end: 2px;
 }
 
-@navbarLargeIcons@ :-moz-any(@primaryToolbarButtons@):not(#alltabs-button):not(#tabview-button):not(#new-tab-button) > .toolbarbutton-icon {
+@navbarLargeIcons@ :-moz-any(@primaryToolbarButtons@):not(:-moz-any(#alltabs-button,#tabview-button,#new-tab-button,#sync-button[status])) > .toolbarbutton-icon {
   list-style-image: url("chrome://browser/skin/Toolbar.png") !important;
 }
 
 @navbarLargeIcons@ .toolbarbutton-1 > .toolbarbutton-menubutton-button,
 @navbarLargeIcons@ .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker,
 @navbarLargeIcons@ .toolbarbutton-1 {
   -moz-appearance: none;
   padding: 1px 5px;
@@ -1483,40 +1483,45 @@ richlistitem[type~="action"][actiontype=
   -moz-appearance: none;
   list-style-image: url("chrome://browser/skin/reload-stop-go.png");
   margin: -2px;
   -moz-margin-start: 0;
   padding: 0 3px;
   background-origin: border-box;
   border: none;
   -moz-border-start: 1px solid rgba(0,0,0,.25);
+  box-shadow: 0 1px 0 rgba(0,0,0,.1) inset,
+              -1px -1px 1px rgba(255,255,255,.25) inset;
 }
 
 #urlbar:-moz-locale-dir(ltr) > toolbarbutton {
   border-top-right-radius: 2px;
   border-bottom-right-radius: 2px;
 }
 
 #urlbar:-moz-locale-dir(rtl) > toolbarbutton {
   border-top-left-radius: 2px;
   border-bottom-left-radius: 2px;
 }
 
-#urlbar > toolbarbutton:not([disabled]):active:hover {
+#urlbar > toolbarbutton:not([disabled]):active:hover,
+#urlbar-reload-button:not(:hover) {
+  -moz-border-start-style: none;
   -moz-padding-start: 4px;
-  -moz-border-start: none;
+  box-shadow: none;
+}
+
+#urlbar > toolbarbutton:not([disabled]):active:hover {
   box-shadow: 0 0 6.5px rgba(0,0,0,.4) inset,
               0 0 2px rgba(0,0,0,.4) inset;
 }
 
 #urlbar-go-button {
   -moz-image-region: rect(0px, 56px, 14px, 42px);
   background-image: -moz-linear-gradient(rgb(115,213,115), rgb(96,190,96) 49%, rgb(82,174,82) 51%, rgb(79,155,79));
-  box-shadow: 0 1px 0 rgba(0,0,0,.1) inset,
-              -1px -1px 1px rgba(255,255,255,.25) inset;
 }
 
 #urlbar-go-button:-moz-locale-dir(rtl) > .toolbarbutton-icon {
   -moz-transform: scaleX(-1);
 }
 
 #urlbar-go-button:hover {
   background-image: -moz-linear-gradient(rgb(96,221,96), rgb(71,191,71) 49%, rgb(54,171,54) 51%, rgb(50,147,50));
@@ -1524,25 +1529,21 @@ richlistitem[type~="action"][actiontype=
 
 #urlbar-reload-button {
   -moz-image-region: rect(0px, 14px, 14px, 0px);
 }
 
 #urlbar-reload-button:not([disabled]):hover {
   -moz-image-region: rect(0px, 28px, 14px, 14px);
   background-image: -moz-linear-gradient(rgb(162,207,241), rgb(111,178,225) 49%, rgb(91,159,217) 51%, rgb(62,138,200));
-  box-shadow: 0 1px 0 rgba(0,0,0,.1) inset,
-              -1px -1px 1px rgba(255,255,255,.25) inset;
 }
 
 #urlbar-stop-button {
   -moz-image-region: rect(0px, 42px, 14px, 28px);
   background-image: -moz-linear-gradient(rgb(231,162,140), rgb(209,119,100) 49%, rgb(193,92,78) 51%, rgb(173,72,58));
-  box-shadow: 0 1px 0 rgba(0,0,0,.1) inset,
-              -1px -1px 1px rgba(255,255,255,.25) inset;
 }
 
 #urlbar-stop-button:hover {
   background-image: -moz-linear-gradient(rgb(244,156,128), rgb(215,101,77) 49%, rgb(194,66,48) 51%, rgb(170,41,23));
 }
 
 /* popup blocker button */
 
--- a/browser/themes/winstripe/browser/jar.mn
+++ b/browser/themes/winstripe/browser/jar.mn
@@ -70,16 +70,17 @@ browser.jar:
         skin/classic/browser/places/libraryToolbar.png               (places/libraryToolbar.png)
         skin/classic/browser/places/starred48.png                    (places/starred48.png)
         skin/classic/browser/places/unstarred48.png                  (places/unstarred48.png)
         skin/classic/browser/places/tag.png                          (places/tag.png)
         skin/classic/browser/places/history.png                      (places/history.png)
         skin/classic/browser/places/allBookmarks.png                 (places/allBookmarks.png)
         skin/classic/browser/places/unsortedBookmarks.png            (places/unsortedBookmarks.png)
         skin/classic/browser/places/searching_16.png                 (places/searching_16.png)
+        skin/classic/browser/places/downloads.png                    (places/downloads.png)
         skin/classic/browser/preferences/alwaysAsk.png               (preferences/alwaysAsk.png)
         skin/classic/browser/preferences/application.png             (preferences/application.png)
         skin/classic/browser/preferences/mail.png                    (preferences/mail.png)
         skin/classic/browser/preferences/Options.png                 (preferences/Options.png)
 #ifdef MOZ_SERVICES_SYNC
         skin/classic/browser/preferences/Options-sync.png            (preferences/Options-sync.png)
 #endif
         skin/classic/browser/preferences/saveFile.png                (preferences/saveFile.png)
@@ -184,16 +185,17 @@ browser.jar:
         skin/classic/aero/browser/places/libraryToolbar.png          (places/libraryToolbar-aero.png)
         skin/classic/aero/browser/places/starred48.png               (places/starred48-aero.png)
         skin/classic/aero/browser/places/unstarred48.png             (places/unstarred48.png)
         skin/classic/aero/browser/places/tag.png                     (places/tag-aero.png)
         skin/classic/aero/browser/places/history.png                 (places/history-aero.png)
         skin/classic/aero/browser/places/allBookmarks.png            (places/allBookmarks-aero.png)
         skin/classic/aero/browser/places/unsortedBookmarks.png       (places/unsortedBookmarks-aero.png)
         skin/classic/aero/browser/places/searching_16.png            (places/searching_16-aero.png)
+        skin/classic/aero/browser/places/downloads.png               (places/downloads.png)
         skin/classic/aero/browser/preferences/alwaysAsk.png          (preferences/alwaysAsk-aero.png)
         skin/classic/aero/browser/preferences/application.png        (preferences/application-aero.png)
         skin/classic/aero/browser/preferences/mail.png               (preferences/mail-aero.png)
         skin/classic/aero/browser/preferences/Options.png            (preferences/Options-aero.png)
 #ifdef MOZ_SERVICES_SYNC
         skin/classic/aero/browser/preferences/Options-sync.png       (preferences/Options-sync.png)
 #endif
         skin/classic/aero/browser/preferences/plugin.png             (preferences/plugin-aero.png)
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..d37bc40b642d3826e7a74f2e391706299ea455c8
GIT binary patch
literal 674
zc$@*E0$u%yP)<h;3K|Lk000e1NJLTq000mG000mO1^@s6AM^iV0000PbVXQnQ*UN;
zcVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBU!L`g(JRCwB?Q_pJ?Q4s##Zgyj%ZB62j
zQetb`gGDLYA|e$*dQ=fb?OD8eDR`2CH~#}q9t5%8dl63}SdwN<N|RQlR79ysj3zOg
zq|J{__Pu?+Y+?veO2C2HS?0a(+nH}>3FjRDV~&3%uiSYQ^G%;S1G#m~C{nT2^_R~c
zPIccU-4zi3jlsJM^My+@Q#jZs2*i2bU|0^tkdH==E<JgW*}H;1C%DUn0wYN1)J`2x
zh@FG#=%EEg0V4zq5=_#p&H}M>?Uwc=kOj~ZAW1|4wF#tV&Y+a{AR<AHF<1gn;}Ys3
zQp3Vmy@b+Fo%KM#QGtqNnIe#;*flvO1|)11If`GB?C;MBo4vJ=kVj7V%>9Fi%Pv$r
zKAayvj1T$d{Ykfs;O7j~Y#fKmMWC2N;r;4%eC@g4u3(4YzHTWmMvjl~JMDH0v1Mc`
zCRnXG1-&d|cFcqNu>oXrd91t*RZ%hS*^)ILsm<VKUiNAwuFee~@ha<CicDEZ$SmOu
zdGVg!slfvS8_{UB`YC)B(Z$zo0^1VN?TW)2$WiI`w0}tbWdLTKf>Q>k80V>eif}km
z%Ef}05qi4Z9$JSM1j*R<DqLFDblf~UHmnwe`VO&)C;KgE+Pkv8_U1Ywiz~L$T?A6g
z9Y}rrVbpjyZ7SC$M~9qVl|c(>yM^$pIczM2+M{Yk(ouob8mqIhy%?RjAWvL;Z2wDJ
zfq8rjHNYj|qB&4|K|2UKNfhBOo1_^VR%wA7(fk8$9Q+nw0BgSjtIXmUdH?_b07*qo
IM6N<$f=vW2H2?qr
--- a/browser/themes/winstripe/browser/places/places.css
+++ b/browser/themes/winstripe/browser/places/places.css
@@ -80,16 +80,21 @@ treechildren::-moz-tree-image(title, que
 }
 
 treechildren::-moz-tree-image(title, query, tagContainer),
 treechildren::-moz-tree-image(query, OrganizerQuery_Tags) {
   list-style-image: url("chrome://mozapps/skin/places/tagContainerIcon.png");
   -moz-image-region: auto;
 }
 
+treechildren::-moz-tree-image(query, OrganizerQuery_Downloads) {
+  list-style-image: url("chrome://browser/skin/places/downloads.png");
+  -moz-image-region: auto;
+}
+
 /* calendar icon for folders grouping items by date */
 treechildren::-moz-tree-image(title, query, dayContainer) {
   list-style-image: url("chrome://browser/skin/places/calendar.png");
   -moz-image-region: auto;
 }
 
 treechildren::-moz-tree-image(title, query, hostContainer) {
   list-style-image: url("chrome://global/skin/icons/folder-item.png");
--- a/config/autoconf.mk.in
+++ b/config/autoconf.mk.in
@@ -671,18 +671,16 @@ HAVE_DTRACE= @HAVE_DTRACE@
 
 VISIBILITY_FLAGS = @VISIBILITY_FLAGS@
 WRAP_SYSTEM_INCLUDES = @WRAP_SYSTEM_INCLUDES@
 
 HAVE_ARM_SIMD = @HAVE_ARM_SIMD@
 HAVE_ARM_NEON = @HAVE_ARM_NEON@
 HAVE_GCC_ALIGN_ARG_POINTER = @HAVE_GCC_ALIGN_ARG_POINTER@
 
-MOZ_SPLASHSCREEN = @MOZ_SPLASHSCREEN@
-
 MOZ_THEME_FASTSTRIPE = @MOZ_THEME_FASTSTRIPE@
 
 MOZ_SERVICES_SYNC = @MOZ_SERVICES_SYNC@
 
 MOZ_OFFICIAL_BRANDING = @MOZ_OFFICIAL_BRANDING@
 
 HAVE_CLOCK_MONOTONIC = @HAVE_CLOCK_MONOTONIC@
 REALTIME_LIBS = @REALTIME_LIBS@
--- a/config/nspr/Makefile.in
+++ b/config/nspr/Makefile.in
@@ -54,28 +54,22 @@ endif
 ifdef MOZ_NATIVE_NSPR
 $(error config/nspr/Makefile.in is not compatible with MOZ_NATIVE_NSPR)
 endif
 
 # Copy NSPR to the SDK
 ABS_DIST = $(call core_abspath,$(DIST))
 
 libs::
-	# Temporary, until bug 655058 lands on nspr. When that happens, we can
-	# revert the config/nspr/* part of bug 654975.
-	$(MAKE) -C $(DEPTH)/nsprpub PROFILE_USE_CFLAGS="$(PROFILE_USE_CFLAGS)"
 	$(MAKE) -C $(DEPTH)/nsprpub install prefix=$(ABS_DIST)/sdk exec_prefix=$(ABS_DIST)/sdk bindir=$(ABS_DIST)/sdk/dummy includedir=$(ABS_DIST)/include libdir=$(ABS_DIST)/sdk/lib datadir=$(ABS_DIST)/sdk/dummy DESTDIR=
 	$(INSTALL) $(DEPTH)/nsprpub/config/nspr-config $(DIST)/sdk/bin
 	$(RM) -rf $(DIST)/sdk/dummy
 ifneq (,$(filter OS2 WINNT,$(OS_ARCH))) # {
 	$(RM) -f $(DIST)/sdk/lib/$(DLL_PREFIX)nspr4$(DLL_SUFFIX) $(DIST)/sdk/lib/$(DLL_PREFIX)plc4$(DLL_SUFFIX) $(DIST)/sdk/lib/$(DLL_PREFIX)plds4$(DLL_SUFFIX)
 	$(RM) -f $(DIST)/sdk/lib/$(LIB_PREFIX)nspr4_s.$(LIB_SUFFIX) $(DIST)/sdk/lib/$(LIB_PREFIX)plc4_s.$(LIB_SUFFIX) $(DIST)/sdk/lib/$(LIB_PREFIX)plds4_s.$(LIB_SUFFIX)
 else # } {
 	$(RM) -f $(DIST)/sdk/lib/$(LIB_PREFIX)nspr4.$(LIB_SUFFIX) $(DIST)/sdk/lib/$(LIB_PREFIX)plc4.$(LIB_SUFFIX) $(DIST)/sdk/lib/$(LIB_PREFIX)plds4.$(LIB_SUFFIX)
 endif # }
 
 install::
 	$(MAKE) -C $(DEPTH)/nsprpub install DESTDIR=$(DESTDIR) libdir=$(mozappdir) includedir=$(includedir)/nspr
 	$(RM) -f $(addprefix $(DESTDIR)$(mozappdir)/$(LIB_PREFIX), $(addsuffix .$(LIB_SUFFIX), nspr4 plds4 plc4))
 	$(RM) -f $(addprefix $(DESTDIR)$(bindir)/,nspr-config compile-et.pl prerr.properties)
-
-clean distclean::
-	$(MAKE) -C $(DEPTH)/nsprpub $@
--- a/config/nspr/build.mk
+++ b/config/nspr/build.mk
@@ -33,10 +33,11 @@
 # the provisions above, a recipient may use your version of this file under
 # the terms of any one of the MPL, the GPL or the LGPL.
 #
 # ***** END LICENSE BLOCK *****
 
 TIERS += nspr
 
 ifndef MOZ_NATIVE_NSPR
+tier_nspr_staticdirs += nsprpub
 tier_nspr_dirs += config/nspr
 endif
--- a/configure.in
+++ b/configure.in
@@ -4849,17 +4849,16 @@ MOZ_PLACES=1
 MOZ_PREF_EXTENSIONS=1
 MOZ_PROFILELOCKING=1
 MOZ_PSM=1
 MOZ_RDF=1
 MOZ_REFLOW_PERF=
 MOZ_SAFE_BROWSING=
 MOZ_HELP_VIEWER=
 MOZ_SPELLCHECK=1
-MOZ_SPLASHSCREEN=
 MOZ_STORAGE=1
 MOZ_SVG_DLISTS=
 MOZ_TOOLKIT_SEARCH=1
 MOZ_UI_LOCALE=en-US
 MOZ_UNIVERSALCHARDET=1
 MOZ_URL_CLASSIFIER=
 MOZ_XSLT_STANDALONE=
 MOZ_XTF=1
@@ -6044,28 +6043,16 @@ linux*)
       PKG_CHECK_MODULES(MOZ_ALSA, alsa, ,
          [echo "$MOZ_ALSA_PKG_ERRORS"
           AC_MSG_ERROR([Need alsa for Ogg, Wave or WebM decoding on Linux.  Disable with --disable-ogg --disable-wave --disable-webm.  (On Ubuntu, you might try installing the package libasound2-dev.)])])
       ;;
    esac
 fi
 
 dnl ========================================================
-dnl Splashscreen
-dnl ========================================================
-AC_ARG_ENABLE(splashscreen,
-              [  --enable-splashscreen   display splashscreen while loading (default=no)],
-              [enable_splash="yes"],[enable_splash=""])
-if test "x$enable_splash" = "xyes"; then
-  MOZ_SPLASHSCREEN=1
-  AC_DEFINE(MOZ_SPLASHSCREEN)
-fi
-AC_SUBST(MOZ_SPLASHSCREEN)
-
-dnl ========================================================
 dnl Permissions System
 dnl ========================================================
 MOZ_ARG_DISABLE_BOOL(permissions,
 [  --disable-permissions   Disable permissions (popup and cookie blocking)],
     MOZ_PERMISSIONS=,
     MOZ_PERMISSIONS=1
 )
 
@@ -6989,18 +6976,16 @@ dnl ====================================
 
 dnl Defaults
 case "${CPU_ARCH}-${OS_TARGET}" in
 arm-Android)
     MOZ_THUMB=yes
     MOZ_ARCH=armv7-a
     MOZ_FPU=vfp
     MOZ_FLOAT_ABI=softfp
-    # Temporarily set nspr flags via configure, until bug 674880 lands
-    NSPR_CONFIGURE_FLAGS="--with-thumb --with-arch=armv7-a --with-fpu=vfp --with-float-abi=softfp"
     ;;
 arm-*)
     if test -n "$MOZ_PLATFORM_MAEMO"; then
         MOZ_THUMB=no
         MOZ_ARCH=armv7-a
         MOZ_FLOAT_ABI=softfp
     fi
     if test "$MOZ_PLATFORM_MAEMO" = 6; then
@@ -9567,17 +9552,16 @@ if test -z "$MOZ_NATIVE_NSPR"; then
        ac_configure_args="$ac_configure_args --enable-debug --disable-optimize"
     fi
     if test -n "$HAVE_64BIT_OS"; then
         ac_configure_args="$ac_configure_args --enable-64bit"
     fi
     if test -n "$USE_ARM_KUSER"; then
         ac_configure_args="$ac_configure_args --with-arm-kuser"
     fi
-    ac_configure_args="$ac_configure_args $NSPR_CONFIGURE_FLAGS"
     AC_OUTPUT_SUBDIRS(nsprpub)
     ac_configure_args="$_SUBDIR_CONFIG_ARGS"
 fi
 
 if test -z "$MOZ_NATIVE_NSPR"; then
     # Hack to deal with the fact that we use NSPR_CFLAGS everywhere
     AC_MSG_WARN([Recreating autoconf.mk with updated nspr-config output])
     if test "$OS_ARCH" != "WINNT"; then
--- a/content/base/src/nsContentSink.cpp
+++ b/content/base/src/nsContentSink.cpp
@@ -604,16 +604,19 @@ nsContentSink::LinkContextIsOurDocument(
 }
 
 nsresult
 nsContentSink::ProcessLinkHeader(nsIContent* aElement,
                                  const nsAString& aLinkData)
 {
   nsresult rv = NS_OK;
 
+  // keep track where we are within the header field
+  PRBool seenParameters = PR_FALSE;
+
   // parse link content and call process style link
   nsAutoString href;
   nsAutoString rel;
   nsAutoString title;
   nsAutoString type;
   nsAutoString media;
   nsAutoString anchor;
 
@@ -699,22 +702,25 @@ nsContentSink::ProcessLinkHeader(nsICont
 
     // end string here
     *end = kNullCh;
 
     if (start < end) {
       if ((*start == kLessThan) && (*last == kGreaterThan)) {
         *last = kNullCh;
 
-        if (href.IsEmpty()) { // first one wins
+        // first instance of <...> wins
+        // also, do not allow hrefs after the first param was seen
+        if (href.IsEmpty() && !seenParameters) {
           href = (start + 1);
           href.StripWhitespace();
         }
       } else {
         PRUnichar* equals = start;
+        seenParameters = PR_TRUE;
 
         while ((*equals != kNullCh) && (*equals != kEqual)) {
           equals++;
         }
 
         if (*equals != kNullCh) {
           *equals = kNullCh;
           nsAutoString  attr(start);
@@ -786,16 +792,18 @@ nsContentSink::ProcessLinkHeader(nsICont
       }
 
       href.Truncate();
       rel.Truncate();
       title.Truncate();
       type.Truncate();
       media.Truncate();
       anchor.Truncate();
+      
+      seenParameters = PR_FALSE;
     }
 
     start = ++end;
   }
                 
   href.Trim(" \t\n\r\f"); // trim HTML5 whitespace
   if (!href.IsEmpty() && !rel.IsEmpty()) {
     rv = ProcessLink(aElement, anchor, href, rel, title, type, media);
--- a/content/base/src/nsGkAtomList.h
+++ b/content/base/src/nsGkAtomList.h
@@ -39,17 +39,17 @@
   This file contains the list of all atoms used by gklayout;
   see nsGkAtoms for access to the atoms.
 */
 
 /*
   This file is designed to be used as inline input to nsGkAtoms.cpp and nsGkAtoms.h
   *only* through the magic of C preprocessing.
 
-  All entires must be enclosed in the macro GK_ATOM which will have cruel
+  All entries must be enclosed in the macro GK_ATOM which will have cruel
   and unusual things done to it
 
   The first argument to GK_ATOM is the C++ name of the atom
   The second argument it GK_ATOM is the string value of the atom
 */
 
 // OUTPUT_CLASS=nsGkAtoms
 // MACRO_NAME=GK_ATOM
--- a/content/canvas/src/CustomQS_Canvas2D.h
+++ b/content/canvas/src/CustomQS_Canvas2D.h
@@ -182,23 +182,23 @@ CreateImageData(JSContext* cx,
     JSObject* darray =
       js_CreateTypedArray(cx, js::TypedArray::TYPE_UINT8_CLAMPED, len.value());
     js::AutoObjectRooter rd(cx, darray);
     if (!darray) {
         return false;
     }
 
     if (self) {
-        js::TypedArray* tdest = js::TypedArray::fromJSObject(darray);
+        JSObject *tdest = js::TypedArray::getTypedArray(darray);
 
         // make the call
         nsresult rv =
             self->GetImageData_explicit(x, y, w, h,
-                                        static_cast<PRUint8*>(tdest->data),
-                                        tdest->byteLength);
+                                        static_cast<PRUint8*>(JS_GetTypedArrayData(tdest)),
+                                        JS_GetTypedArrayByteLength(tdest));
         if (NS_FAILED(rv)) {
             return xpc_qsThrowMethodFailed(cx, rv, vp);
         }
     }
 
     // Do JS_NewObject after CreateTypedArray, so that gc will get
     // triggered here if necessary
     JSObject* result = JS_NewObject(cx, NULL, NULL, NULL);
@@ -411,34 +411,34 @@ nsIDOMCanvasRenderingContext2D_PutImageD
 
     if (JSVAL_IS_PRIMITIVE(tv.jsval_value()))
         return xpc_qsThrow(cx, NS_ERROR_DOM_TYPE_MISMATCH_ERR);
 
     darray = JSVAL_TO_OBJECT(tv.jsval_value());
 
     js::AutoValueRooter tsrc_tvr(cx);
 
-    js::TypedArray *tsrc = NULL;
+    JSObject *tsrc = NULL;
     if (darray->getClass() == &js::TypedArray::fastClasses[js::TypedArray::TYPE_UINT8] ||
         darray->getClass() == &js::TypedArray::fastClasses[js::TypedArray::TYPE_UINT8_CLAMPED])
     {
-        tsrc = js::TypedArray::fromJSObject(darray);
+        tsrc = js::TypedArray::getTypedArray(darray);
     } else if (JS_IsArrayObject(cx, darray) || js_IsTypedArray(darray)) {
         // ugh, this isn't a uint8 typed array, someone made their own object; convert it to a typed array
         JSObject *nobj = js_CreateTypedArrayWithArray(cx, js::TypedArray::TYPE_UINT8, darray);
         if (!nobj)
             return JS_FALSE;
 
         *tsrc_tvr.jsval_addr() = OBJECT_TO_JSVAL(nobj);
-        tsrc = js::TypedArray::fromJSObject(nobj);
+        tsrc = js::TypedArray::getTypedArray(nobj);
     } else {
         // yeah, no.
         return xpc_qsThrow(cx, NS_ERROR_DOM_TYPE_MISMATCH_ERR);
     }
 
     // make the call
-    rv = self->PutImageData_explicit(x, y, w, h, (PRUint8*) tsrc->data, tsrc->byteLength, hasDirtyRect, dirtyX, dirtyY, dirtyWidth, dirtyHeight);
+    rv = self->PutImageData_explicit(x, y, w, h, (PRUint8*) JS_GetTypedArrayData(tsrc), JS_GetTypedArrayByteLength(tsrc), hasDirtyRect, dirtyX, dirtyY, dirtyWidth, dirtyHeight);
     if (NS_FAILED(rv))
         return xpc_qsThrowMethodFailed(cx, rv, vp);
 
     *vp = JSVAL_VOID;
     return JS_TRUE;
 }
--- a/content/canvas/src/CustomQS_WebGL.h
+++ b/content/canvas/src/CustomQS_WebGL.h
@@ -96,17 +96,17 @@ nsIDOMWebGLRenderingContext_BufferData(J
         return JS_FALSE;
 
     if (argc < 3)
         return xpc_qsThrow(cx, NS_ERROR_XPC_NOT_ENOUGH_ARGS);
 
     jsval *argv = JS_ARGV(cx, vp);
 
     int32 target;
-    js::TypedArray *wa = 0;
+    JSObject *wa = 0;
     JSObject *wb = 0;
     int32 size;
     int32 usage;
 
     if (!JS_ValueToECMAInt32(cx, argv[0], &target))
         return JS_FALSE;
     if (!JS_ValueToECMAInt32(cx, argv[2], &usage))
         return JS_FALSE;
@@ -115,17 +115,17 @@ nsIDOMWebGLRenderingContext_BufferData(J
 
     if (!nullobject) {
         if (!JSVAL_IS_PRIMITIVE(argv[1])) {
 
             JSObject *arg2 = JSVAL_TO_OBJECT(argv[1]);
             if (js_IsArrayBuffer(arg2)) {
                 wb = js::ArrayBuffer::getArrayBuffer(arg2);
             } else if (js_IsTypedArray(arg2)) {
-                wa = js::TypedArray::fromJSObject(arg2);
+                wa = js::TypedArray::getTypedArray(arg2);
             }
         }
 
         if (!wa && !wb &&
             !JS_ValueToECMAInt32(cx, argv[1], &size))
         {
             return JS_FALSE;
         }
@@ -170,17 +170,17 @@ nsIDOMWebGLRenderingContext_BufferSubDat
 
     if (argc < 3)
         return xpc_qsThrow(cx, NS_ERROR_XPC_NOT_ENOUGH_ARGS);
 
     jsval *argv = JS_ARGV(cx, vp);
 
     int32 target;
     int32 offset;
-    js::TypedArray *wa = 0;
+    JSObject *wa = 0;
     JSObject *wb = 0;
 
     if (!JS_ValueToECMAInt32(cx, argv[0], &target))
         return JS_FALSE;
     if (!JS_ValueToECMAInt32(cx, argv[1], &offset))
         return JS_FALSE;
 
     if (!JSVAL_IS_OBJECT(argv[2])) {
@@ -190,17 +190,17 @@ nsIDOMWebGLRenderingContext_BufferSubDat
 
     JSBool nullobject = JSVAL_IS_NULL(argv[2]);
 
     if (!nullobject) {
         JSObject *arg3 = JSVAL_TO_OBJECT(argv[2]);
         if (js_IsArrayBuffer(arg3)) {
             wb = js::ArrayBuffer::getArrayBuffer(arg3);
         } else if (js_IsTypedArray(arg3)) {
-            wa = js::TypedArray::fromJSObject(arg3);
+            wa = js::TypedArray::getTypedArray(arg3);
         } else {
             xpc_qsThrowBadArg(cx, NS_ERROR_FAILURE, vp, 2);
             return JS_FALSE;
         }
     }
 
     nsresult rv;
 
@@ -260,17 +260,17 @@ nsIDOMWebGLRenderingContext_ReadPixels(J
     {
         JSObject *argv6 = JSVAL_TO_OBJECT(argv[6]);
         if (js_IsArrayBuffer(argv6)) {
             rv = self->ReadPixels_buf(argv0, argv1, argv2, argv3,
                                       argv4, argv5, js::ArrayBuffer::getArrayBuffer(argv6));
         } else if (js_IsTypedArray(argv6)) {
             rv = self->ReadPixels_array(argv0, argv1, argv2, argv3,
                                         argv4, argv5,
-                                        js::TypedArray::fromJSObject(argv6));
+                                        js::TypedArray::getTypedArray(argv6));
         } else {
             xpc_qsThrowBadArg(cx, NS_ERROR_FAILURE, vp, 6);
             return JS_FALSE;
         }
     } else {
         xpc_qsThrow(cx, NS_ERROR_FAILURE);
         return JS_FALSE;
     }
@@ -360,17 +360,17 @@ nsIDOMWebGLRenderingContext_TexImage2D(J
             }
             if (!js_IsTypedArray(obj_data))
             {
                 xpc_qsThrowBadArg(cx, NS_ERROR_FAILURE, vp, 5);
                 return JS_FALSE;
             }
             rv = self->TexImage2D_imageData(argv0, argv1, argv2,
                                             int_width, int_height, 0,
-                                            argv3, argv4, js::TypedArray::fromJSObject(obj_data));
+                                            argv3, argv4, js::TypedArray::getTypedArray(obj_data));
         }
     } else if (argc > 8 &&
                JSVAL_IS_OBJECT(argv[8])) // here, we allow null !
     {
         // implement the variants taking a buffer/array as argv[8]
         GET_UINT32_ARG(argv2, 2);
         GET_INT32_ARG(argv3, 3);
         GET_INT32_ARG(argv4, 4);
@@ -387,17 +387,17 @@ nsIDOMWebGLRenderingContext_TexImage2D(J
                                       nsnull);
         } else if (js_IsArrayBuffer(argv8)) {
             rv = self->TexImage2D_buf(argv0, argv1, argv2, argv3,
                                       argv4, argv5, argv6, argv7,
                                       js::ArrayBuffer::getArrayBuffer(argv8));
         } else if (js_IsTypedArray(argv8)) {
             rv = self->TexImage2D_array(argv0, argv1, argv2, argv3,
                                         argv4, argv5, argv6, argv7,
-                                        js::TypedArray::fromJSObject(argv8));
+                                        js::TypedArray::getTypedArray(argv8));
         } else {
             xpc_qsThrowBadArg(cx, NS_ERROR_FAILURE, vp, 8);
             return JS_FALSE;
         }
     } else {
         xpc_qsThrow(cx, NS_ERROR_XPC_NOT_ENOUGH_ARGS);
         return JS_FALSE;
     }
@@ -486,17 +486,17 @@ nsIDOMWebGLRenderingContext_TexSubImage2
             if (!js_IsTypedArray(obj_data))
             {
                 xpc_qsThrowBadArg(cx, NS_ERROR_FAILURE, vp, 6);
                 return JS_FALSE;
             }
             rv = self->TexSubImage2D_imageData(argv0, argv1, argv2, argv3,
                                                int_width, int_height,
                                                argv4, argv5,
-                                               js::TypedArray::fromJSObject(obj_data));
+                                               js::TypedArray::getTypedArray(obj_data));
         }
     } else if (argc > 8 &&
                !JSVAL_IS_PRIMITIVE(argv[8]))
     {
         // implement the variants taking a buffer/array as argv[8]
         GET_INT32_ARG(argv4, 4);
         GET_INT32_ARG(argv5, 5);
         GET_UINT32_ARG(argv6, 6);
@@ -506,17 +506,17 @@ nsIDOMWebGLRenderingContext_TexSubImage2
         // try to grab either a js::ArrayBuffer or js::TypedArray
         if (js_IsArrayBuffer(argv8)) {
             rv = self->TexSubImage2D_buf(argv0, argv1, argv2, argv3,
                                          argv4, argv5, argv6, argv7,
                                          js::ArrayBuffer::getArrayBuffer(argv8));
         } else if (js_IsTypedArray(argv8)) {
             rv = self->TexSubImage2D_array(argv0, argv1, argv2, argv3,
                                            argv4, argv5, argv6, argv7,
-                                           js::TypedArray::fromJSObject(argv8));
+                                           js::TypedArray::getTypedArray(argv8));
         } else {
             xpc_qsThrowBadArg(cx, NS_ERROR_FAILURE, vp, 8);
             return JS_FALSE;
         }
     } else {
         xpc_qsThrow(cx, NS_ERROR_XPC_NOT_ENOUGH_ARGS);
         return JS_FALSE;
     }
@@ -562,29 +562,29 @@ helper_nsIDOMWebGLRenderingContext_Unifo
         xpc_qsThrowBadArg(cx, NS_ERROR_FAILURE, vp, 1);
         return JS_FALSE;
     }
 
     JSObject *arg1 = JSVAL_TO_OBJECT(argv[1]);
 
     js::AutoValueRooter obj_tvr(cx);
 
-    js::TypedArray *wa = 0;
+    JSObject *wa = 0;
 
     if (helper_isInt32Array(arg1)) {
-        wa = js::TypedArray::fromJSObject(arg1);
+        wa = js::TypedArray::getTypedArray(arg1);
     }  else if (JS_IsArrayObject(cx, arg1)) {
         JSObject *nobj = js_CreateTypedArrayWithArray(cx, js::TypedArray::TYPE_INT32, arg1);
         if (!nobj) {
             // XXX this will likely return a strange error message if it goes wrong
             return JS_FALSE;
         }
 
         *obj_tvr.jsval_addr() = OBJECT_TO_JSVAL(nobj);
-        wa = js::TypedArray::fromJSObject(nobj);
+        wa = js::TypedArray::getTypedArray(nobj);
     } else {
         xpc_qsThrowBadArg(cx, NS_ERROR_FAILURE, vp, 1);
         return JS_FALSE;
     }
 
     if (nElements == 1) {
         rv = self->Uniform1iv_array(location, wa);
     } else if (nElements == 2) {
@@ -636,29 +636,29 @@ helper_nsIDOMWebGLRenderingContext_Unifo
         xpc_qsThrowBadArg(cx, NS_ERROR_FAILURE, vp, 1);
         return JS_FALSE;
     }
 
     JSObject *arg1 = JSVAL_TO_OBJECT(argv[1]);
 
     js::AutoValueRooter obj_tvr(cx);
 
-    js::TypedArray *wa = 0;
+    JSObject *wa = 0;
 
     if (helper_isFloat32Array(arg1)) {
-        wa = js::TypedArray::fromJSObject(arg1);
+        wa = js::TypedArray::getTypedArray(arg1);
     }  else if (JS_IsArrayObject(cx, arg1)) {
         JSObject *nobj = js_CreateTypedArrayWithArray(cx, js::TypedArray::TYPE_FLOAT32, arg1);
         if (!nobj) {
             // XXX this will likely return a strange error message if it goes wrong
             return JS_FALSE;
         }
 
         *obj_tvr.jsval_addr() = OBJECT_TO_JSVAL(nobj);
-        wa = js::TypedArray::fromJSObject(nobj);
+        wa = js::TypedArray::getTypedArray(nobj);
     } else {
         xpc_qsThrowBadArg(cx, NS_ERROR_FAILURE, vp, 1);
         return JS_FALSE;
     }
 
     if (nElements == 1) {
         rv = self->Uniform1fv_array(location, wa);
     } else if (nElements == 2) {
@@ -712,29 +712,29 @@ helper_nsIDOMWebGLRenderingContext_Unifo
         xpc_qsThrowBadArg(cx, NS_ERROR_FAILURE, vp, 2);
         return JS_FALSE;
     }
 
     JSObject *arg2 = JSVAL_TO_OBJECT(argv[2]);
 
     js::AutoValueRooter obj_tvr(cx);
 
-    js::TypedArray *wa = 0;
+    JSObject *wa = 0;
 
     if (helper_isFloat32Array(arg2)) {
-        wa = js::TypedArray::fromJSObject(arg2);
+        wa = js::TypedArray::getTypedArray(arg2);
     }  else if (JS_IsArrayObject(cx, arg2)) {
         JSObject *nobj = js_CreateTypedArrayWithArray(cx, js::TypedArray::TYPE_FLOAT32, arg2);
         if (!nobj) {
             // XXX this will likely return a strange error message if it goes wrong
             return JS_FALSE;
         }
 
         *obj_tvr.jsval_addr() = OBJECT_TO_JSVAL(nobj);
-        wa = js::TypedArray::fromJSObject(nobj);
+        wa = js::TypedArray::getTypedArray(nobj);
     } else {
         xpc_qsThrowBadArg(cx, NS_ERROR_FAILURE, vp, 2);
         return JS_FALSE;
     }
 
     if (nElements == 2) {
         rv = self->UniformMatrix2fv_array(location, transpose ? 1 : 0, wa);
     } else if (nElements == 3) {
@@ -777,29 +777,29 @@ helper_nsIDOMWebGLRenderingContext_Verte
         xpc_qsThrowBadArg(cx, NS_ERROR_FAILURE, vp, 1);
         return JS_FALSE;
     }
 
     JSObject *arg1 = JSVAL_TO_OBJECT(argv[1]);
 
     js::AutoValueRooter obj_tvr(cx);
 
-    js::TypedArray *wa = 0;
+    JSObject *wa = 0;
 
     if (helper_isFloat32Array(arg1)) {
-        wa = js::TypedArray::fromJSObject(arg1);
+        wa = js::TypedArray::getTypedArray(arg1);
     }  else if (JS_IsArrayObject(cx, arg1)) {
         JSObject *nobj = js_CreateTypedArrayWithArray(cx, js::TypedArray::TYPE_FLOAT32, arg1);
         if (!nobj) {
             // XXX this will likely return a strange error message if it goes wrong
             return JS_FALSE;
         }
 
         *obj_tvr.jsval_addr() = OBJECT_TO_JSVAL(nobj);
-        wa = js::TypedArray::fromJSObject(nobj);
+        wa = js::TypedArray::getTypedArray(nobj);
     } else {
         xpc_qsThrowBadArg(cx, NS_ERROR_FAILURE, vp, 1);
         return JS_FALSE;
     }
 
     nsresult rv = NS_OK;
     if (nElements == 1) {
         rv = self->VertexAttrib1fv_array(location, wa);
@@ -939,30 +939,30 @@ helper_nsIDOMWebGLRenderingContext_Unifo
         = xpc_qsUnwrapThis(cx, locationobj, nsnull, &location,
                            &location_selfref.ptr, &location_anchor.get(),
                            nsnull);
     if (NS_FAILED(rv_convert_arg0)) {
         js_SetTraceableNativeFailed(cx);
         return;
     }
 
-    js::TypedArray *wa = 0;
+    JSObject *wa = 0;
 
     if (helper_isInt32Array(arg)) {
-        wa = js::TypedArray::fromJSObject(arg);
+        wa = js::TypedArray::getTypedArray(arg);
     }  else if (JS_IsArrayObject(cx, arg)) {
         JSObject *nobj = js_CreateTypedArrayWithArray(cx, js::TypedArray::TYPE_INT32, arg);
         if (!nobj) {
             // XXX this will likely return a strange error message if it goes wrong
             js_SetTraceableNativeFailed(cx);
             return;
         }
 
         *obj_tvr.jsval_addr() = OBJECT_TO_JSVAL(nobj);
-        wa = js::TypedArray::fromJSObject(nobj);
+        wa = js::TypedArray::getTypedArray(nobj);
     } else {
         xpc_qsThrowMethodFailedWithDetails(cx, NS_ERROR_FAILURE, "nsIDOMWebGLRenderingContext", "uniformNiv");
         js_SetTraceableNativeFailed(cx);
         return;
     }
 
     nsresult rv = NS_OK;
     if (nElements == 1) {
@@ -1010,30 +1010,30 @@ helper_nsIDOMWebGLRenderingContext_Unifo
         = xpc_qsUnwrapThis(cx, locationobj, nsnull, &location,
                            &location_selfref.ptr, &location_anchor.get(),
                            nsnull);
     if (NS_FAILED(rv_convert_arg0)) {
         js_SetTraceableNativeFailed(cx);
         return;
     }
 
-    js::TypedArray *wa = 0;
+    JSObject *wa = 0;
 
     if (helper_isFloat32Array(arg)) {
-        wa = js::TypedArray::fromJSObject(arg);
+        wa = js::TypedArray::getTypedArray(arg);
     }  else if (JS_IsArrayObject(cx, arg)) {
         JSObject *nobj = js_CreateTypedArrayWithArray(cx, js::TypedArray::TYPE_FLOAT32, arg);
         if (!nobj) {
             // XXX this will likely return a strange error message if it goes wrong
             js_SetTraceableNativeFailed(cx);
             return;
         }
 
         *obj_tvr.jsval_addr() = OBJECT_TO_JSVAL(nobj);
-        wa = js::TypedArray::fromJSObject(nobj);
+        wa = js::TypedArray::getTypedArray(nobj);
     } else {
         xpc_qsThrowMethodFailedWithDetails(cx, NS_ERROR_FAILURE, "nsIDOMWebGLRenderingContext", "uniformNfv");
         js_SetTraceableNativeFailed(cx);
         return;
     }
 
     nsresult rv = NS_OK;
     if (nElements == 1) {
@@ -1083,30 +1083,30 @@ helper_nsIDOMWebGLRenderingContext_Unifo
         = xpc_qsUnwrapThis(cx, locationobj, nsnull, &location,
                            &location_selfref.ptr, &location_anchor.get(),
                            nsnull);
     if (NS_FAILED(rv_convert_arg0)) {
         js_SetTraceableNativeFailed(cx);
         return;
     }
 
-    js::TypedArray *wa = 0;
+    JSObject *wa = 0;
 
     if (helper_isFloat32Array(arg)) {
-        wa = js::TypedArray::fromJSObject(arg);
+        wa = js::TypedArray::getTypedArray(arg);
     }  else if (JS_IsArrayObject(cx, arg)) {
         JSObject *nobj = js_CreateTypedArrayWithArray(cx, js::TypedArray::TYPE_FLOAT32, arg);
         if (!nobj) {
             // XXX this will likely return a strange error message if it goes wrong
             js_SetTraceableNativeFailed(cx);
             return;
         }
 
         *obj_tvr.jsval_addr() = OBJECT_TO_JSVAL(nobj);
-        wa = js::TypedArray::fromJSObject(nobj);
+        wa = js::TypedArray::getTypedArray(nobj);
     } else {
         xpc_qsThrowMethodFailedWithDetails(cx, NS_ERROR_FAILURE, "nsIDOMWebGLRenderingContext", "uniformMatrixNfv");
         js_SetTraceableNativeFailed(cx);
         return;
     }
 
     nsresult rv = NS_OK;
     if (nElements == 2) {
--- a/content/canvas/src/WebGLContextGL.cpp
+++ b/content/canvas/src/WebGLContextGL.cpp
@@ -482,17 +482,17 @@ WebGLContext::BufferData_buf(WebGLenum t
     boundBuffer->InvalidateCachedMaxElements();
     if (!boundBuffer->CopyDataIfElementArray(JS_GetArrayBufferData(wb)))
         return ErrorOutOfMemory("bufferData: out of memory");
 
     return NS_OK;
 }
 
 NS_IMETHODIMP
-WebGLContext::BufferData_array(WebGLenum target, js::TypedArray *wa, WebGLenum usage)
+WebGLContext::BufferData_array(WebGLenum target, JSObject *wa, WebGLenum usage)
 {
     WebGLBuffer *boundBuffer = NULL;
 
     if (target == LOCAL_GL_ARRAY_BUFFER) {
         boundBuffer = mBoundArrayBuffer;
     } else if (target == LOCAL_GL_ELEMENT_ARRAY_BUFFER) {
         boundBuffer = mBoundElementArrayBuffer;
     } else {
@@ -503,27 +503,27 @@ WebGLContext::BufferData_array(WebGLenum
         return NS_OK;
 
     if (!boundBuffer)
         return ErrorInvalidOperation("BufferData: no buffer bound!");
 
     MakeContextCurrent();
 
     GLenum error = CheckedBufferData(target,
-                                     wa->byteLength,
-                                     wa->data,
+                                     JS_GetTypedArrayByteLength(wa),
+                                     JS_GetTypedArrayData(wa),
                                      usage);
     if (error) {
         LogMessageIfVerbose("bufferData generated error %s", ErrorName(error));
         return NS_OK;
     }
 
-    boundBuffer->SetByteLength(wa->byteLength);
+    boundBuffer->SetByteLength(JS_GetTypedArrayByteLength(wa));
     boundBuffer->InvalidateCachedMaxElements();
-    if (!boundBuffer->CopyDataIfElementArray(wa->data))
+    if (!boundBuffer->CopyDataIfElementArray(JS_GetTypedArrayData(wa)))
         return ErrorOutOfMemory("bufferData: out of memory");
 
     return NS_OK;
 }
 
 NS_IMETHODIMP
 WebGLContext::BufferSubData(PRInt32)
 {
@@ -569,17 +569,17 @@ WebGLContext::BufferSubData_buf(GLenum t
     boundBuffer->InvalidateCachedMaxElements();
 
     gl->fBufferSubData(target, byteOffset, JS_GetArrayBufferByteLength(wb), JS_GetArrayBufferData(wb));
 
     return NS_OK;
 }
 
 NS_IMETHODIMP
-WebGLContext::BufferSubData_array(WebGLenum target, WebGLsizei byteOffset, js::TypedArray *wa)
+WebGLContext::BufferSubData_array(WebGLenum target, WebGLsizei byteOffset, JSObject *wa)
 {
     WebGLBuffer *boundBuffer = NULL;
 
     if (target == LOCAL_GL_ARRAY_BUFFER) {
         boundBuffer = mBoundArrayBuffer;
     } else if (target == LOCAL_GL_ELEMENT_ARRAY_BUFFER) {
         boundBuffer = mBoundElementArrayBuffer;
     } else {
@@ -587,30 +587,30 @@ WebGLContext::BufferSubData_array(WebGLe
     }
 
     if (byteOffset < 0)
         return ErrorInvalidValue("bufferSubData: negative offset");
 
     if (!boundBuffer)
         return ErrorInvalidOperation("BufferData: no buffer bound!");
 
-    CheckedUint32 checked_neededByteLength = CheckedUint32(byteOffset) + wa->byteLength;
+    CheckedUint32 checked_neededByteLength = CheckedUint32(byteOffset) + JS_GetTypedArrayByteLength(wa);
     if (!checked_neededByteLength.valid())
         return ErrorInvalidOperation("bufferSubData: integer overflow computing the needed byte length");
 
     if (checked_neededByteLength.value() > boundBuffer->ByteLength())
         return ErrorInvalidOperation("BufferSubData: not enough data -- operation requires %d bytes, but buffer only has %d bytes",
-                                     byteOffset, wa->byteLength, boundBuffer->ByteLength());
+                                     byteOffset, JS_GetTypedArrayByteLength(wa), boundBuffer->ByteLength());
 
     MakeContextCurrent();
 
-    boundBuffer->CopySubDataIfElementArray(byteOffset, wa->byteLength, wa->data);
+    boundBuffer->CopySubDataIfElementArray(byteOffset, JS_GetTypedArrayByteLength(wa), JS_GetTypedArrayData(wa));
     boundBuffer->InvalidateCachedMaxElements();
 
-    gl->fBufferSubData(target, byteOffset, wa->byteLength, wa->data);
+    gl->fBufferSubData(target, byteOffset, JS_GetTypedArrayByteLength(wa), JS_GetTypedArrayData(wa));
 
     return NS_OK;
 }
 
 NS_IMETHODIMP
 WebGLContext::CheckFramebufferStatus(WebGLenum target, WebGLenum *retval)
 {
     *retval = 0;
@@ -3135,21 +3135,21 @@ WebGLContext::ReadPixels_base(WebGLint x
         }            
     }
 
     return NS_OK;
 }
 
 NS_IMETHODIMP
 WebGLContext::ReadPixels_array(WebGLint x, WebGLint y, WebGLsizei width, WebGLsizei height,
-                               WebGLenum format, WebGLenum type, js::TypedArray *pixels)
+                               WebGLenum format, WebGLenum type, JSObject *pixels)
 {
     return ReadPixels_base(x, y, width, height, format, type,
-                           pixels ? pixels->data : 0,
-                           pixels ? pixels->byteLength : 0);
+                           pixels ? JS_GetTypedArrayData(pixels) : 0,
+                           pixels ? JS_GetTypedArrayByteLength(pixels) : 0);
 }
 
 NS_IMETHODIMP
 WebGLContext::ReadPixels_buf(WebGLint x, WebGLint y, WebGLsizei width, WebGLsizei height,
                              WebGLenum format, WebGLenum type, JSObject *pixels)
 {
     return ReadPixels_base(x, y, width, height, format, type,
                            pixels ? JS_GetArrayBufferData(pixels) : 0,
@@ -3656,45 +3656,45 @@ WebGLContext::DOMElementToImageSurface(n
     GLint location = location_object->Location();
 
 #define SIMPLE_ARRAY_METHOD_UNIFORM(name, cnt, arrayType, ptrType)      \
 NS_IMETHODIMP                                                           \
 WebGLContext::name(PRInt32) {                                     \
      return NS_ERROR_NOT_IMPLEMENTED;                                   \
 }                                                                       \
 NS_IMETHODIMP                                                           \
-WebGLContext::name##_array(nsIWebGLUniformLocation *ploc, js::TypedArray *wa) \
+WebGLContext::name##_array(nsIWebGLUniformLocation *ploc, JSObject *wa) \
 {                                                                       \
     OBTAIN_UNIFORM_LOCATION(#name ": location")                         \
-    if (!wa || wa->type != js::TypedArray::arrayType)                   \
+    if (!wa || JS_GetTypedArrayType(wa) != js::TypedArray::arrayType)   \
         return ErrorInvalidOperation(#name ": array must be " #arrayType);      \
-    if (wa->length == 0 || wa->length % cnt != 0)                       \
+    if (JS_GetTypedArrayLength(wa) == 0 || JS_GetTypedArrayLength(wa) % cnt != 0)\
         return ErrorInvalidValue(#name ": array must be > 0 elements and have a length multiple of %d", cnt); \
     MakeContextCurrent();                                               \
-    gl->f##name(location, wa->length / cnt, (ptrType *)wa->data);            \
+    gl->f##name(location, JS_GetTypedArrayLength(wa) / cnt, (ptrType *)JS_GetTypedArrayData(wa));            \
     return NS_OK;                                                       \
 }
 
 #define SIMPLE_MATRIX_METHOD_UNIFORM(name, dim, arrayType, ptrType)     \
 NS_IMETHODIMP                                                           \
 WebGLContext::name(PRInt32) {                                     \
      return NS_ERROR_NOT_IMPLEMENTED;                                   \
 }                                                                       \
 NS_IMETHODIMP                                                           \
-WebGLContext::name##_array(nsIWebGLUniformLocation *ploc, WebGLboolean transpose, js::TypedArray *wa)  \
+WebGLContext::name##_array(nsIWebGLUniformLocation *ploc, WebGLboolean transpose, JSObject *wa)  \
 {                                                                       \
     OBTAIN_UNIFORM_LOCATION(#name ": location")                         \
-    if (!wa || wa->type != js::TypedArray::arrayType)                   \
+    if (!wa || JS_GetTypedArrayType(wa) != js::TypedArray::arrayType)                   \
         return ErrorInvalidValue(#name ": array must be " #arrayType);      \
-    if (wa->length == 0 || wa->length % (dim*dim) != 0)                 \
+    if (JS_GetTypedArrayLength(wa) == 0 || JS_GetTypedArrayLength(wa) % (dim*dim) != 0)                 \
         return ErrorInvalidValue(#name ": array length must be >0 and multiple of %d", dim*dim); \
     if (transpose)                                                      \
         return ErrorInvalidValue(#name ": transpose must be FALSE as per the OpenGL ES 2.0 spec"); \
     MakeContextCurrent();                                               \
-    gl->f##name(location, wa->length / (dim*dim), transpose, (ptrType *)wa->data); \
+    gl->f##name(location, JS_GetTypedArrayLength(wa) / (dim*dim), transpose, (ptrType *)JS_GetTypedArrayData(wa)); \
     return NS_OK;                                                       \
 }
 
 #define SIMPLE_METHOD_UNIFORM_1(glname, name, t1)        \
 NS_IMETHODIMP WebGLContext::name(nsIWebGLUniformLocation *ploc, t1 a1) {      \
     OBTAIN_UNIFORM_LOCATION(#name ": location") \
     MakeContextCurrent(); gl->f##glname(location, a1); return NS_OK; \
 }
@@ -3819,24 +3819,24 @@ WebGLContext::VertexAttrib4f(PRUint32 in
 }
 
 #define SIMPLE_ARRAY_METHOD_NO_COUNT(name, cnt, arrayType, ptrType)  \
 NS_IMETHODIMP                                                           \
 WebGLContext::name(PRInt32) {                                     \
      return NS_ERROR_NOT_IMPLEMENTED;                                   \
 }                                                                       \
 NS_IMETHODIMP                                                           \
-WebGLContext::name##_array(WebGLuint idx, js::TypedArray *wa)           \
+WebGLContext::name##_array(WebGLuint idx, JSObject *wa)           \
 {                                                                       \
-    if (!wa || wa->type != js::TypedArray::arrayType)                   \
+    if (!wa || JS_GetTypedArrayType(wa) != js::TypedArray::arrayType)                   \
         return ErrorInvalidOperation(#name ": array must be " #arrayType); \
-    if (wa->length < cnt)                                               \
+    if (JS_GetTypedArrayLength(wa) < cnt)                                               \
         return ErrorInvalidOperation(#name ": array must be >= %d elements", cnt); \
     MakeContextCurrent();                                               \
-    ptrType *ptr = (ptrType *)wa->data;                                  \
+    ptrType *ptr = (ptrType *)JS_GetTypedArrayData(wa);                                  \
     if (idx) {                                                        \
         gl->f##name(idx, ptr);                                          \
     } else {                                                            \
         mVertexAttrib0Vector[0] = ptr[0];                               \
         mVertexAttrib0Vector[1] = cnt > 1 ? ptr[1] : ptrType(0);        \
         mVertexAttrib0Vector[2] = cnt > 2 ? ptr[2] : ptrType(0);        \
         mVertexAttrib0Vector[3] = cnt > 3 ? ptr[3] : ptrType(1);        \
         if (gl->IsGLES2())                                              \
@@ -4423,34 +4423,34 @@ WebGLContext::TexImage2D_buf(WebGLenum t
                            -1,
                            WebGLTexelFormat::Auto, PR_FALSE);
 }
 
 NS_IMETHODIMP
 WebGLContext::TexImage2D_array(WebGLenum target, WebGLint level, WebGLenum internalformat,
                                WebGLsizei width, WebGLsizei height, WebGLint border,
                                WebGLenum format, WebGLenum type,
-                               js::TypedArray *pixels)
+                               JSObject *pixels)
 {
     return TexImage2D_base(target, level, internalformat, width, height, 0, border, format, type,
-                           pixels ? pixels->data : 0,
-                           pixels ? pixels->byteLength : 0,
-                           (int) pixels->type,
+                           pixels ? JS_GetTypedArrayData(pixels) : 0,
+                           pixels ? JS_GetTypedArrayByteLength(pixels) : 0,
+                           (int) JS_GetTypedArrayType(pixels),
                            WebGLTexelFormat::Auto, PR_FALSE);
 }
 
 NS_IMETHODIMP
 WebGLContext::TexImage2D_imageData(WebGLenum target, WebGLint level, WebGLenum internalformat,
                                WebGLsizei width, WebGLsizei height, WebGLint border,
                                WebGLenum format, WebGLenum type,
-                               js::TypedArray *pixels)
+                               JSObject *pixels)
 {
     return TexImage2D_base(target, level, internalformat, width, height, 4*width, border, format, type,
-                           pixels ? pixels->data : 0,
-                           pixels ? pixels->byteLength : 0,
+                           pixels ? JS_GetTypedArrayData(pixels) : 0,
+                           pixels ? JS_GetTypedArrayByteLength(pixels) : 0,
                            -1,
                            WebGLTexelFormat::RGBA8, PR_FALSE);
 }
 
 NS_IMETHODIMP
 WebGLContext::TexImage2D_dom(WebGLenum target, WebGLint level, WebGLenum internalformat,
                              WebGLenum format, GLenum type, nsIDOMElement *elt)
 {
@@ -4607,41 +4607,41 @@ WebGLContext::TexSubImage2D_buf(WebGLenu
                               WebGLTexelFormat::Auto, PR_FALSE);
 }
 
 NS_IMETHODIMP
 WebGLContext::TexSubImage2D_array(WebGLenum target, WebGLint level,
                                   WebGLint xoffset, WebGLint yoffset,
                                   WebGLsizei width, WebGLsizei height,
                                   WebGLenum format, WebGLenum type,
-                                  js::TypedArray *pixels)
+                                  JSObject *pixels)
 {
     if (!pixels)
         return ErrorInvalidValue("TexSubImage2D: pixels must not be null!");
 
     return TexSubImage2D_base(target, level, xoffset, yoffset,
                               width, height, 0, format, type,
-                              pixels->data, pixels->byteLength,
-                              pixels->type,
+                              JS_GetTypedArrayData(pixels), JS_GetTypedArrayByteLength(pixels),
+                              JS_GetTypedArrayType(pixels),
                               WebGLTexelFormat::Auto, PR_FALSE);
 }
 
 NS_IMETHODIMP
 WebGLContext::TexSubImage2D_imageData(WebGLenum target, WebGLint level,
                                       WebGLint xoffset, WebGLint yoffset,
                                       WebGLsizei width, WebGLsizei height,
                                       WebGLenum format, WebGLenum type,
-                                      js::TypedArray *pixels)
+                                      JSObject *pixels)
 {
     if (!pixels)
         return ErrorInvalidValue("TexSubImage2D: pixels must not be null!");
 
     return TexSubImage2D_base(target, level, xoffset, yoffset,
                               width, height, 4*width, format, type,
-                              pixels->data, pixels->byteLength,
+                              JS_GetTypedArrayData(pixels), JS_GetTypedArrayByteLength(pixels),
                               -1,
                               WebGLTexelFormat::RGBA8, PR_FALSE);
 }
 
 NS_IMETHODIMP
 WebGLContext::TexSubImage2D_dom(WebGLenum target, WebGLint level,
                                 WebGLint xoffset, WebGLint yoffset,
                                 WebGLenum format, WebGLenum type,
--- a/content/events/src/nsDOMNotifyAudioAvailableEvent.cpp
+++ b/content/events/src/nsDOMNotifyAudioAvailableEvent.cpp
@@ -113,18 +113,18 @@ nsDOMNotifyAudioAvailableEvent::GetFrame
 
   mCachedArray = js_CreateTypedArray(aCx, js::TypedArray::TYPE_FLOAT32, mFrameBufferLength);
   if (!mCachedArray) {
     NS_DROP_JS_OBJECTS(this, nsDOMNotifyAudioAvailableEvent);
     NS_ERROR("Failed to get audio signal!");
     return NS_ERROR_FAILURE;
   }
 
-  js::TypedArray *tdest = js::TypedArray::fromJSObject(mCachedArray);
-  memcpy(tdest->data, mFrameBuffer.get(), mFrameBufferLength * sizeof(float));
+  JSObject *tdest = js::TypedArray::getTypedArray(mCachedArray);
+  memcpy(JS_GetTypedArrayData(tdest), mFrameBuffer.get(), mFrameBufferLength * sizeof(float));
 
   *aResult = OBJECT_TO_JSVAL(mCachedArray);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDOMNotifyAudioAvailableEvent::GetTime(float *aRetVal)
 {
--- a/content/events/src/nsEventStateManager.cpp
+++ b/content/events/src/nsEventStateManager.cpp
@@ -1510,18 +1510,18 @@ nsEventStateManager::ExecuteAccessKey(ns
 
 PRBool
 nsEventStateManager::GetAccessKeyLabelPrefix(nsAString& aPrefix)
 {
   aPrefix.Truncate();
   nsAutoString separator, modifierText;
   nsContentUtils::GetModifierSeparatorText(separator);
 
-  nsCOMPtr<nsISupports> container = mPresContext->GetContainer();
-  PRInt32 modifier = GetAccessModifierMask(container);
+  nsCOMPtr<nsISupports> container = mPresContext->GetContainer();
+  PRInt32 modifier = GetAccessModifierMask(container);
 
   if (modifier & NS_MODIFIER_CONTROL) {
     nsContentUtils::GetControlText(modifierText);
     aPrefix.Append(modifierText + separator);
   }
   if (modifier & NS_MODIFIER_META) {
     nsContentUtils::GetMetaText(modifierText);
     aPrefix.Append(modifierText + separator);
--- a/content/html/content/public/nsITextControlElement.h
+++ b/content/html/content/public/nsITextControlElement.h
@@ -44,18 +44,18 @@ class nsIContent;
 class nsAString;
 class nsIEditor;
 class nsISelectionController;
 class nsFrameSelection;
 class nsTextControlFrame;
 
 // IID for the nsITextControl interface
 #define NS_ITEXTCONTROLELEMENT_IID    \
-{ 0x66545dde, 0x3f4a, 0x49fd,    \
-  { 0x82, 0x73, 0x69, 0x7e, 0xab, 0x54, 0x06, 0x0a } }
+{ 0x2e758eee, 0xd023, 0x4fd1,    \
+  { 0x97, 0x93, 0xae, 0xeb, 0xbb, 0xf3, 0xa8, 0x3f } }
 
 /**
  * This interface is used for the text control frame to get the editor and
  * selection controller objects, and some helper properties.
  */
 class nsITextControlElement : public nsISupports {
 public:
 
@@ -213,15 +213,23 @@ public:
   typedef enum {
     eHTMLTextWrap_Off     = 1,    // "off"
     eHTMLTextWrap_Hard    = 2,    // "hard"
     eHTMLTextWrap_Soft    = 3     // the default
   } nsHTMLTextWrap;
 
   static PRBool
   GetWrapPropertyEnum(nsIContent* aContent, nsHTMLTextWrap& aWrapProp);
+
+  /**
+   * Does the editor have a selection cache?
+   *
+   * Note that this function has the side effect of making the editor for input
+   * elements be initialized eagerly.
+   */
+  NS_IMETHOD_(PRBool) HasCachedSelection() = 0;
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsITextControlElement,
                               NS_ITEXTCONTROLELEMENT_IID)
 
 #endif // nsITextControlElement_h___
 
--- a/content/html/content/src/nsGenericHTMLElement.cpp
+++ b/content/html/content/src/nsGenericHTMLElement.cpp
@@ -821,27 +821,27 @@ nsGenericHTMLElement::InsertAdjacentHTML
     }
   } else {
     destination = this;
   }
 
   nsIDocument* doc = GetOwnerDoc();
   NS_ENSURE_STATE(doc);
 
-  // Needed when insertAdjacentHTML is used in combination with contenteditable
-  mozAutoDocUpdate updateBatch(doc, UPDATE_CONTENT_MODEL, PR_TRUE);
-
   // Batch possible DOMSubtreeModified events.
   mozAutoSubtreeModified subtree(doc, nsnull);
 
   // Parse directly into destination if possible
   if (doc->IsHTML() &&
       (position == eBeforeEnd ||
        (position == eAfterEnd && !GetNextSibling()) ||
        (position == eAfterBegin && !GetFirstChild()))) {
+    // Needed when insertAdjacentHTML is used in combination with contenteditable
+    mozAutoDocUpdate updateBatch(doc, UPDATE_CONTENT_MODEL, PR_TRUE);
+
     PRInt32 oldChildCount = destination->GetChildCount();
     PRInt32 contextNs = destination->GetNameSpaceID();
     nsIAtom* contextLocal = destination->Tag();
     if (contextLocal == nsGkAtoms::html && contextNs == kNameSpaceID_XHTML) {
       // For compat with IE6 through IE9. Willful violation of HTML5 as of
       // 2011-04-06. CreateContextualFragment does the same already.
       // Spec bug: http://www.w3.org/Bugs/Public/show_bug.cgi?id=12434
       contextLocal = nsGkAtoms::body;
@@ -2956,25 +2956,25 @@ nsGenericHTMLFormElement::FormIdUpdated(
 
   return PR_TRUE;
 }
 
 PRBool 
 nsGenericHTMLFormElement::IsElementDisabledForEvents(PRUint32 aMessage, 
                                                     nsIFrame* aFrame)
 {
-  PRBool disabled = IsDisabled();
-  if (!disabled && aFrame) {
-    const nsStyleUserInterface* uiStyle = aFrame->GetStyleUserInterface();
-    disabled = uiStyle->mUserInput == NS_STYLE_USER_INPUT_NONE ||
-      uiStyle->mUserInput == NS_STYLE_USER_INPUT_DISABLED;
-
-  }
-  return disabled && aMessage != NS_MOUSE_MOVE;
-}
+  PRBool disabled = IsDisabled();
+  if (!disabled && aFrame) {
+    const nsStyleUserInterface* uiStyle = aFrame->GetStyleUserInterface();
+    disabled = uiStyle->mUserInput == NS_STYLE_USER_INPUT_NONE ||
+      uiStyle->mUserInput == NS_STYLE_USER_INPUT_DISABLED;
+
+  }
+  return disabled && aMessage != NS_MOUSE_MOVE;
+}
 
 void
 nsGenericHTMLFormElement::UpdateFormOwner(bool aBindToTree,
                                           Element* aFormIdElement)
 {
   NS_PRECONDITION(!aBindToTree || !aFormIdElement,
                   "aFormIdElement shouldn't be set if aBindToTree is true!");
 
--- a/content/html/content/src/nsHTMLAudioElement.cpp
+++ b/content/html/content/src/nsHTMLAudioElement.cpp
@@ -192,45 +192,45 @@ nsHTMLAudioElement::MozWriteAudio(const 
   }
 
   if (JSVAL_IS_PRIMITIVE(aData)) {
     return NS_ERROR_DOM_TYPE_MISMATCH_ERR;
   }
 
   JSObject *darray = JSVAL_TO_OBJECT(aData);
   js::AutoValueRooter tsrc_tvr(aCx);
-  js::TypedArray *tsrc = NULL;
+  JSObject *tsrc = NULL;
 
   // Allow either Float32Array or plain JS Array
   if (darray->getClass() == &js::TypedArray::fastClasses[js::TypedArray::TYPE_FLOAT32])
   {
-    tsrc = js::TypedArray::fromJSObject(darray);
+    tsrc = js::TypedArray::getTypedArray(darray);
   } else if (JS_IsArrayObject(aCx, darray)) {
     JSObject *nobj = js_CreateTypedArrayWithArray(aCx, js::TypedArray::TYPE_FLOAT32, darray);
     if (!nobj) {
       return NS_ERROR_DOM_TYPE_MISMATCH_ERR;
     }
     *tsrc_tvr.jsval_addr() = OBJECT_TO_JSVAL(nobj);
-    tsrc = js::TypedArray::fromJSObject(nobj);
+    tsrc = js::TypedArray::getTypedArray(nobj);
   } else {
     return NS_ERROR_DOM_TYPE_MISMATCH_ERR;
   }
 
-  PRUint32 dataLength = tsrc->length;
+  PRUint32 dataLength = JS_GetTypedArrayLength(tsrc);
 
   // Make sure that we are going to write the correct amount of data based
   // on number of channels.
   if (dataLength % mChannels != 0) {
     return NS_ERROR_DOM_INDEX_SIZE_ERR;
   }
 
   // Don't write more than can be written without blocking.
   PRUint32 writeLen = NS_MIN(mAudioStream->Available(), dataLength);
 
-  nsresult rv = mAudioStream->Write(tsrc->data, writeLen, PR_TRUE);
+  nsresult rv = mAudioStream->Write(JS_GetTypedArrayData(tsrc), writeLen, PR_TRUE);
   if (NS_FAILED(rv)) {
     return rv;
   }
 
   // Return the actual amount written.
   *aRetVal = writeLen;
   return rv;
 }
--- a/content/html/content/src/nsHTMLInputElement.cpp
+++ b/content/html/content/src/nsHTMLInputElement.cpp
@@ -2749,24 +2749,36 @@ nsHTMLInputElement::SetSelectionRange(PR
 
   return rv;
 }
 
 NS_IMETHODIMP
 nsHTMLInputElement::GetSelectionStart(PRInt32* aSelectionStart)
 {
   NS_ENSURE_ARG_POINTER(aSelectionStart);
-  
+
+  nsTextEditorState *state = GetEditorState();
+  if (state && state->IsSelectionCached()) {
+    *aSelectionStart = state->GetSelectionProperties().mStart;
+    return NS_OK;
+  }
+
   PRInt32 selEnd;
   return GetSelectionRange(aSelectionStart, &selEnd);
 }
 
 NS_IMETHODIMP
 nsHTMLInputElement::SetSelectionStart(PRInt32 aSelectionStart)
 {
+  nsTextEditorState *state = GetEditorState();
+  if (state && state->IsSelectionCached()) {
+    state->GetSelectionProperties().mStart = aSelectionStart;
+    return NS_OK;
+  }
+
   nsAutoString direction;
   nsresult rv = GetSelectionDirection(direction);
   NS_ENSURE_SUCCESS(rv, rv);
   PRInt32 start, end;
   rv = GetSelectionRange(&start, &end);
   NS_ENSURE_SUCCESS(rv, rv);
   start = aSelectionStart;
   if (end < start) {
@@ -2774,25 +2786,37 @@ nsHTMLInputElement::SetSelectionStart(PR
   }
   return SetSelectionRange(start, end, direction);
 }
 
 NS_IMETHODIMP
 nsHTMLInputElement::GetSelectionEnd(PRInt32* aSelectionEnd)
 {
   NS_ENSURE_ARG_POINTER(aSelectionEnd);
-  
+
+  nsTextEditorState *state = GetEditorState();
+  if (state && state->IsSelectionCached()) {
+    *aSelectionEnd = state->GetSelectionProperties().mEnd;
+    return NS_OK;
+  }
+
   PRInt32 selStart;
   return GetSelectionRange(&selStart, aSelectionEnd);
 }
 
 
 NS_IMETHODIMP
 nsHTMLInputElement::SetSelectionEnd(PRInt32 aSelectionEnd)
 {
+  nsTextEditorState *state = GetEditorState();
+  if (state && state->IsSelectionCached()) {
+    state->GetSelectionProperties().mEnd = aSelectionEnd;
+    return NS_OK;
+  }
+
   nsAutoString direction;
   nsresult rv = GetSelectionDirection(direction);
   NS_ENSURE_SUCCESS(rv, rv);
   PRInt32 start, end;
   rv = GetSelectionRange(&start, &end);
   NS_ENSURE_SUCCESS(rv, rv);
   end = aSelectionEnd;
   if (start > end) {
@@ -2833,46 +2857,70 @@ nsHTMLInputElement::GetSelectionRange(PR
     nsITextControlFrame* textControlFrame = do_QueryFrame(formControlFrame);
     if (textControlFrame)
       rv = textControlFrame->GetSelectionRange(aSelectionStart, aSelectionEnd);
   }
 
   return rv;
 }
 
+static void
+DirectionToName(nsITextControlFrame::SelectionDirection dir, nsAString& aDirection)
+{
+  if (dir == nsITextControlFrame::eNone) {
+    aDirection.AssignLiteral("none");
+  } else if (dir == nsITextControlFrame::eForward) {
+    aDirection.AssignLiteral("forward");
+  } else if (dir == nsITextControlFrame::eBackward) {
+    aDirection.AssignLiteral("backward");
+  } else {
+    NS_NOTREACHED("Invalid SelectionDirection value");
+  }
+}
+
 NS_IMETHODIMP
 nsHTMLInputElement::GetSelectionDirection(nsAString& aDirection)
 {
+  nsTextEditorState *state = GetEditorState();
+  if (state && state->IsSelectionCached()) {
+    DirectionToName(state->GetSelectionProperties().mDirection, aDirection);
+    return NS_OK;
+  }
+
   nsresult rv = NS_ERROR_FAILURE;
   nsIFormControlFrame* formControlFrame = GetFormControlFrame(PR_TRUE);
 
   if (formControlFrame) {
     nsITextControlFrame* textControlFrame = do_QueryFrame(formControlFrame);
     if (textControlFrame) {
       nsITextControlFrame::SelectionDirection dir;
       rv = textControlFrame->GetSelectionRange(nsnull, nsnull, &dir);
       if (NS_SUCCEEDED(rv)) {
-        if (dir == nsITextControlFrame::eNone) {
-          aDirection.AssignLiteral("none");
-        } else if (dir == nsITextControlFrame::eForward) {
-          aDirection.AssignLiteral("forward");
-        } else if (dir == nsITextControlFrame::eBackward) {
-          aDirection.AssignLiteral("backward");
-        } else {
-          NS_NOTREACHED("Invalid SelectionDirection value");
-        }
+        DirectionToName(dir, aDirection);
       }
     }
   }
 
   return rv;
 }
 
 NS_IMETHODIMP
 nsHTMLInputElement::SetSelectionDirection(const nsAString& aDirection) {
+  nsTextEditorState *state = GetEditorState();
+  if (state && state->IsSelectionCached()) {
+    nsITextControlFrame::SelectionDirection dir = nsITextControlFrame::eNone;
+    if (aDirection.EqualsLiteral("forward")) {
+      dir = nsITextControlFrame::eForward;
+    } else if (aDirection.EqualsLiteral("backward")) {
+      dir = nsITextControlFrame::eBackward;
+    }
+    state->GetSelectionProperties().mDirection = dir;
+    return NS_OK;
+  }
+
   PRInt32 start, end;
   nsresult rv = GetSelectionRange(&start, &end);
   if (NS_SUCCEEDED(rv)) {
     rv = SetSelectionRange(start, end, aDirection);
   }
 
   return rv;
 }
@@ -4132,16 +4180,32 @@ nsHTMLInputElement::OnValueChanged(PRBoo
   // However, we don't want to waste cycles if the state doesn't apply.
   if (PlaceholderApplies()
       && HasAttr(kNameSpaceID_None, nsGkAtoms::placeholder)
       && !nsContentUtils::IsFocusedContent((nsIContent*)(this))) {
     UpdateState(aNotify);
   }
 }
 
+NS_IMETHODIMP_(PRBool)
+nsHTMLInputElement::HasCachedSelection()
+{
+  PRBool isCached = PR_FALSE;
+  nsTextEditorState *state = GetEditorState();
+  if (state) {
+    isCached = state->IsSelectionCached() &&
+               state->HasNeverInitializedBefore() &&
+               !state->GetSelectionProperties().IsDefault();
+    if (isCached) {
+      state->WillInitEagerly();
+    }
+  }
+  return isCached;
+}
+
 void
 nsHTMLInputElement::FieldSetDisabledChanged(PRBool aNotify)
 {
   UpdateValueMissingValidityState();
   UpdateBarredFromConstraintValidation();
 
   nsGenericHTMLFormElement::FieldSetDisabledChanged(aNotify);
 }
--- a/content/html/content/src/nsHTMLInputElement.h
+++ b/content/html/content/src/nsHTMLInputElement.h
@@ -209,16 +209,17 @@ public:
   NS_IMETHOD CreateEditor();
   NS_IMETHOD_(nsIContent*) GetRootEditorNode();
   NS_IMETHOD_(nsIContent*) CreatePlaceholderNode();
   NS_IMETHOD_(nsIContent*) GetPlaceholderNode();
   NS_IMETHOD_(void) UpdatePlaceholderText(PRBool aNotify);
   NS_IMETHOD_(void) SetPlaceholderClass(PRBool aVisible, PRBool aNotify);
   NS_IMETHOD_(void) InitializeKeyboardEventListeners();
   NS_IMETHOD_(void) OnValueChanged(PRBool aNotify);
+  NS_IMETHOD_(PRBool) HasCachedSelection();
 
   void GetDisplayFileName(nsAString& aFileName) const;
   const nsCOMArray<nsIDOMFile>& GetFiles() const;
   void SetFiles(const nsCOMArray<nsIDOMFile>& aFiles, bool aSetValueChanged);
   void SetFiles(nsIDOMFileList* aFiles, bool aSetValueChanged);
 
   void SetCheckedChangedInternal(PRBool aCheckedChanged);
   PRBool GetCheckedChanged() const {
--- a/content/html/content/src/nsHTMLTextAreaElement.cpp
+++ b/content/html/content/src/nsHTMLTextAreaElement.cpp
@@ -155,16 +155,17 @@ public:
   NS_IMETHOD CreateEditor();
   NS_IMETHOD_(nsIContent*) GetRootEditorNode();
   NS_IMETHOD_(nsIContent*) CreatePlaceholderNode();
   NS_IMETHOD_(nsIContent*) GetPlaceholderNode();
   NS_IMETHOD_(void) UpdatePlaceholderText(PRBool aNotify);
   NS_IMETHOD_(void) SetPlaceholderClass(PRBool aVisible, PRBool aNotify);
   NS_IMETHOD_(void) InitializeKeyboardEventListeners();
   NS_IMETHOD_(void) OnValueChanged(PRBool aNotify);
+  NS_IMETHOD_(PRBool) HasCachedSelection();
 
   // nsIContent
   virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
                                nsIContent* aBindingParent,
                                PRBool aCompileEventHandlers);
   virtual void UnbindFromTree(PRBool aDeep = PR_TRUE,
                               PRBool aNullParent = PR_TRUE);
   virtual PRBool ParseAttribute(PRInt32 aNamespaceID,
@@ -816,24 +817,34 @@ nsHTMLTextAreaElement::GetTextLength(PRI
 
   return rv;
 }
 
 NS_IMETHODIMP
 nsHTMLTextAreaElement::GetSelectionStart(PRInt32 *aSelectionStart)
 {
   NS_ENSURE_ARG_POINTER(aSelectionStart);
-  
+
+  if (mState->IsSelectionCached()) {
+    *aSelectionStart = mState->GetSelectionProperties().mStart;
+    return NS_OK;
+  }
+
   PRInt32 selEnd;
   return GetSelectionRange(aSelectionStart, &selEnd);
 }
 
 NS_IMETHODIMP
 nsHTMLTextAreaElement::SetSelectionStart(PRInt32 aSelectionStart)
 {
+  if (mState->IsSelectionCached()) {
+    mState->GetSelectionProperties().mStart = aSelectionStart;
+    return NS_OK;
+  }
+
   nsAutoString direction;
   nsresult rv = GetSelectionDirection(direction);
   NS_ENSURE_SUCCESS(rv, rv);
   PRInt32 start, end;
   rv = GetSelectionRange(&start, &end);
   NS_ENSURE_SUCCESS(rv, rv);
   start = aSelectionStart;
   if (end < start) {
@@ -841,24 +852,34 @@ nsHTMLTextAreaElement::SetSelectionStart
   }
   return SetSelectionRange(start, end, direction);
 }
 
 NS_IMETHODIMP
 nsHTMLTextAreaElement::GetSelectionEnd(PRInt32 *aSelectionEnd)
 {
   NS_ENSURE_ARG_POINTER(aSelectionEnd);
-  
+
+  if (mState->IsSelectionCached()) {
+    *aSelectionEnd = mState->GetSelectionProperties().mEnd;
+    return NS_OK;
+  }
+
   PRInt32 selStart;
   return GetSelectionRange(&selStart, aSelectionEnd);
 }
 
 NS_IMETHODIMP
 nsHTMLTextAreaElement::SetSelectionEnd(PRInt32 aSelectionEnd)
 {
+  if (mState->IsSelectionCached()) {
+    mState->GetSelectionProperties().mEnd = aSelectionEnd;
+    return NS_OK;
+  }
+
   nsAutoString direction;
   nsresult rv = GetSelectionDirection(direction);
   NS_ENSURE_SUCCESS(rv, rv);
   PRInt32 start, end;
   rv = GetSelectionRange(&start, &end);
   NS_ENSURE_SUCCESS(rv, rv);
   end = aSelectionEnd;
   if (start > end) {
@@ -878,46 +899,68 @@ nsHTMLTextAreaElement::GetSelectionRange
     nsITextControlFrame* textControlFrame = do_QueryFrame(formControlFrame);
     if (textControlFrame)
       rv = textControlFrame->GetSelectionRange(aSelectionStart, aSelectionEnd);
   }
 
   return rv;
 }
 
+static void
+DirectionToName(nsITextControlFrame::SelectionDirection dir, nsAString& aDirection)
+{
+  if (dir == nsITextControlFrame::eNone) {
+    aDirection.AssignLiteral("none");
+  } else if (dir == nsITextControlFrame::eForward) {
+    aDirection.AssignLiteral("forward");
+  } else if (dir == nsITextControlFrame::eBackward) {
+    aDirection.AssignLiteral("backward");
+  } else {
+    NS_NOTREACHED("Invalid SelectionDirection value");
+  }
+}
+
 nsresult
 nsHTMLTextAreaElement::GetSelectionDirection(nsAString& aDirection)
 {
+  if (mState->IsSelectionCached()) {
+    DirectionToName(mState->GetSelectionProperties().mDirection, aDirection);
+    return NS_OK;
+  }
+
   nsresult rv = NS_ERROR_FAILURE;
   nsIFormControlFrame* formControlFrame = GetFormControlFrame(PR_TRUE);
 
   if (formControlFrame) {
     nsITextControlFrame* textControlFrame = do_QueryFrame(formControlFrame);
     if (textControlFrame) {
       nsITextControlFrame::SelectionDirection dir;
       rv = textControlFrame->GetSelectionRange(nsnull, nsnull, &dir);
       if (NS_SUCCEEDED(rv)) {
-        if (dir == nsITextControlFrame::eNone) {
-          aDirection.AssignLiteral("none");
-        } else if (dir == nsITextControlFrame::eForward) {
-          aDirection.AssignLiteral("forward");
-        } else if (dir == nsITextControlFrame::eBackward) {
-          aDirection.AssignLiteral("backward");
-        } else {
-          NS_NOTREACHED("Invalid SelectionDirection value");
-        }
+        DirectionToName(dir, aDirection);
       }
     }
   }
 
   return rv;
 }
 
 NS_IMETHODIMP
 nsHTMLTextAreaElement::SetSelectionDirection(const nsAString& aDirection) {
+  if (mState->IsSelectionCached()) {
+    nsITextControlFrame::SelectionDirection dir = nsITextControlFrame::eNone;
+    if (aDirection.EqualsLiteral("forward")) {
+      dir = nsITextControlFrame::eForward;
+    } else if (aDirection.EqualsLiteral("backward")) {
+      dir = nsITextControlFrame::eBackward;
+    }
+    mState->GetSelectionProperties().mDirection = dir;
+    return NS_OK;
+  }
+
   PRInt32 start, end;
   nsresult rv = GetSelectionRange(&start, &end);
   if (NS_SUCCEEDED(rv)) {
     rv = SetSelectionRange(start, end, aDirection);
   }
 
   return rv;
 }
@@ -1484,16 +1527,22 @@ nsHTMLTextAreaElement::OnValueChanged(PR
 
   if (validBefore != IsValid() ||
       (HasAttr(kNameSpaceID_None, nsGkAtoms::placeholder)
        && !nsContentUtils::IsFocusedContent((nsIContent*)(this)))) {
     UpdateState(aNotify);
   }
 }
 
+NS_IMETHODIMP_(PRBool)
+nsHTMLTextAreaElement::HasCachedSelection()
+{
+  return mState->IsSelectionCached();
+}
+
 void
 nsHTMLTextAreaElement::FieldSetDisabledChanged(PRBool aNotify)
 {
   UpdateValueMissingValidityState();
   UpdateBarredFromConstraintValidation();
 
   nsGenericHTMLFormElement::FieldSetDisabledChanged(aNotify);
 }
--- a/content/html/content/src/nsTextEditorState.cpp
+++ b/content/html/content/src/nsTextEditorState.cpp
@@ -69,53 +69,50 @@
 
 using namespace mozilla::dom;
 
 static NS_DEFINE_CID(kTextEditorCID, NS_TEXTEDITOR_CID);
 
 static nsINativeKeyBindings *sNativeInputBindings = nsnull;
 static nsINativeKeyBindings *sNativeTextAreaBindings = nsnull;
 
-struct SelectionState {
-  PRInt32 mStart;
-  PRInt32 mEnd;
-};
-
 class RestoreSelectionState : public nsRunnable {
 public:
-  RestoreSelectionState(nsTextEditorState *aState, nsTextControlFrame *aFrame,
-                        PRInt32 aStart, PRInt32 aEnd)
+  RestoreSelectionState(nsTextEditorState *aState, nsTextControlFrame *aFrame)
     : mFrame(aFrame),
-      mStart(aStart),
-      mEnd(aEnd),
       mTextEditorState(aState)
   {
   }
 
   NS_IMETHOD Run() {
     if (mFrame) {
       // SetSelectionRange leads to Selection::AddRange which flushes Layout -
       // need to block script to avoid nested PrepareEditor calls (bug 642800).
       nsAutoScriptBlocker scriptBlocker;
-      mFrame->SetSelectionRange(mStart, mEnd);
-      mTextEditorState->HideSelectionIfBlurred();
+       nsTextEditorState::SelectionProperties& properties =
+         mTextEditorState->GetSelectionProperties();
+       mFrame->SetSelectionRange(properties.mStart,
+                                 properties.mEnd,
+                                 properties.mDirection);
+      if (!mTextEditorState->mSelectionRestoreEagerInit) {
+        mTextEditorState->HideSelectionIfBlurred();
+      }
+      mTextEditorState->mSelectionRestoreEagerInit = PR_FALSE;
     }
     mTextEditorState->FinishedRestoringSelection();
     return NS_OK;
   }
 
   // Let the text editor tell us we're no longer relevant - avoids use of nsWeakFrame
   void Revoke() {
     mFrame = nsnull;
   }
 
 private:
   nsTextControlFrame* mFrame;
-  PRInt32 mStart;
-  PRInt32 mEnd;
   nsTextEditorState* mTextEditorState;
 };
 
 /*static*/
 PRBool
 nsITextControlElement::GetWrapPropertyEnum(nsIContent* aContent,
   nsITextControlElement::nsHTMLTextWrap& aWrapProp)
 {
@@ -928,19 +925,22 @@ nsTextInputListener::GetKeyBindings()
 
 // nsTextEditorState
 
 nsTextEditorState::nsTextEditorState(nsITextControlElement* aOwningElement)
   : mTextCtrlElement(aOwningElement),
     mRestoringSelection(nsnull),
     mBoundFrame(nsnull),
     mTextListener(nsnull),
+    mEverInited(PR_FALSE),
     mEditorInitialized(PR_FALSE),
     mInitializing(PR_FALSE),
-    mValueTransferInProgress(PR_FALSE)
+    mValueTransferInProgress(PR_FALSE),
+    mSelectionCached(PR_TRUE),
+    mSelectionRestoreEagerInit(PR_FALSE)
 {
   MOZ_COUNT_CTOR(nsTextEditorState);
 }
 
 nsTextEditorState::~nsTextEditorState()
 {
   MOZ_COUNT_DTOR(nsTextEditorState);
   Clear();
@@ -1344,33 +1344,36 @@ nsTextEditorState::PrepareEditor(const n
     // default value don't screw us up.
     // Since changing the control type does a reframe, we don't have to worry
     // about dynamic type changes here.
     newEditor->EnableUndo(PR_FALSE);
   }
 
   if (!mEditorInitialized) {
     newEditor->PostCreate();
+    mEverInited = PR_TRUE;
     mEditorInitialized = PR_TRUE;
   }
 
   if (mTextListener)
     newEditor->AddEditorObserver(mTextListener);
 
   // Restore our selection after being bound to a new frame
-  if (mSelState) {
+  if (mSelectionCached) {
     if (mRestoringSelection) // paranoia
       mRestoringSelection->Revoke();
-    mRestoringSelection = new RestoreSelectionState(this, mBoundFrame, mSelState->mStart, mSelState->mEnd);
+    mRestoringSelection = new RestoreSelectionState(this, mBoundFrame);
     if (mRestoringSelection) {
       nsContentUtils::AddScriptRunner(mRestoringSelection);
-      mSelState = nsnull;
     }
   }
 
+  // The selection cache is no longer going to be valid
+  mSelectionCached = PR_FALSE;
+
   return rv;
 }
 
 void
 nsTextEditorState::DestroyEditor()
 {
   // notify the editor that we are going away
   if (mEditorInitialized) {
@@ -1403,21 +1406,20 @@ nsTextEditorState::UnbindFromFrame(nsTex
 
   // Save our selection state if needed.
   // Note that nsTextControlFrame::GetSelectionRange attempts to initialize the
   // editor before grabbing the range, and because this is not an acceptable
   // side effect for unbinding from a text control frame, we need to call
   // GetSelectionRange before calling DestroyEditor, and only if
   // mEditorInitialized indicates that we actually have an editor available.
   if (mEditorInitialized) {
-    mSelState = new SelectionState();
-    nsresult rv = mBoundFrame->GetSelectionRange(&mSelState->mStart, &mSelState->mEnd);
-    if (NS_FAILED(rv)) {
-      mSelState = nsnull;
-    }
+    mBoundFrame->GetSelectionRange(&mSelectionProperties.mStart,
+                                   &mSelectionProperties.mEnd,
+                                   &mSelectionProperties.mDirection);
+    mSelectionCached = PR_TRUE;
   }
 
   // Destroy our editor
   DestroyEditor();
 
   // Clean up the controller
   if (!SuppressEventHandlers(mBoundFrame->PresContext()))
   {
--- a/content/html/content/src/nsTextEditorState.h
+++ b/content/html/content/src/nsTextEditorState.h
@@ -36,27 +36,27 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef nsTextEditorState_h__
 #define nsTextEditorState_h__
 
 #include "nsAutoPtr.h"
 #include "nsITextControlElement.h"
+#include "nsITextControlFrame.h"
 #include "nsCycleCollectionParticipant.h"
 
 class nsTextInputListener;
 class nsTextControlFrame;
 class nsTextInputSelectionImpl;
 class nsAnonDivObserver;
 class nsISelectionController;
 class nsFrameSelection;
 class nsIEditor;
 class nsITextControlElement;
-struct SelectionState;
 
 /**
  * nsTextEditorState is a class which is responsible for managing the state of
  * plaintext controls.  This currently includes the following HTML elements:
  *   <input type=text>
  *   <input type=password>
  *   <textarea>
  * and also XUL controls such as <textbox> which use one of these elements behind
@@ -111,16 +111,21 @@ struct SelectionState;
  *    when the frame is unbound from the text control element.
  *
  *  * The editor's cached value.  This value is stored in the mCachedValue member.
  *    It is used to improve the performance of append operations to the text
  *    control.  A mutation observer stored in the mMutationObserver has the job of
  *    invalidating this cache when the anonymous contect containing the value is
  *    changed.
  *
+ *  * The editor's cached selection properties.  These vales are stored in the
+ *    mSelectionProperties member, and include the selection's start, end and
+ *    direction. They are only used when there is no frame available for the
+ *    text field.
+ *
  *
  * As a general rule, nsTextEditorState objects own the value of the text control, and any
  * attempt to retrieve or set the value must be made through those objects.  Internally,
  * the value can be represented in several different ways, based on the state the control is
  * in.
  *
  *   * When the control is first initialized, its value is equal to the default value of
  *     the DOM node.  For <input> text controls, this default value is the value of the
@@ -209,16 +214,34 @@ public:
 
   /* called to free up native keybinding services */
   static NS_HIDDEN_(void) ShutDown();
 
   void ClearValueCache() { mCachedValue.Truncate(); }
 
   void HideSelectionIfBlurred();
 
+  struct SelectionProperties {
+    SelectionProperties() : mStart(0), mEnd(0),
+      mDirection(nsITextControlFrame::eForward) {}
+    bool IsDefault() const {
+      return mStart == 0 && mEnd == 0 &&
+             mDirection == nsITextControlFrame::eForward;
+    }
+    PRInt32 mStart, mEnd;
+    nsITextControlFrame::SelectionDirection mDirection;
+  };
+
+  PRBool IsSelectionCached() const { return mSelectionCached; }
+  SelectionProperties& GetSelectionProperties() {
+    return mSelectionProperties;
+  }
+  void WillInitEagerly() { mSelectionRestoreEagerInit = PR_TRUE; }
+  PRBool HasNeverInitializedBefore() const { return !mEverInited; }
+
 private:
   friend class RestoreSelectionState;
 
   // not copy constructible
   nsTextEditorState(const nsTextEditorState&);
   // not assignable
   void operator= (const nsTextEditorState&);
 
@@ -254,24 +277,27 @@ private:
     nsTextEditorState& mState;
     PRBool mGuardSet;
   };
   friend class InitializationGuard;
   friend class PrepareEditorEvent;
 
   nsITextControlElement* const mTextCtrlElement;
   nsRefPtr<nsTextInputSelectionImpl> mSelCon;
-  nsAutoPtr<SelectionState> mSelState;
   RestoreSelectionState* mRestoringSelection;
   nsCOMPtr<nsIEditor> mEditor;
   nsCOMPtr<nsIContent> mRootNode;
   nsCOMPtr<nsIContent> mPlaceholderDiv;
   nsTextControlFrame* mBoundFrame;
   nsTextInputListener* mTextListener;
   nsAutoPtr<nsCString> mValue;
   nsRefPtr<nsAnonDivObserver> mMutationObserver;
   mutable nsString mCachedValue; // Caches non-hard-wrapped value on a multiline control.
+  PRPackedBool mEverInited; // Have we ever been initialized?
   PRPackedBool mEditorInitialized;
   PRPackedBool mInitializing; // Whether we're in the process of initialization
   PRPackedBool mValueTransferInProgress; // Whether a value is being transferred to the frame
+  PRPackedBool mSelectionCached; // Whether mSelectionProperties is valid
+  mutable PRPackedBool mSelectionRestoreEagerInit; // Whether we're eager initing because of selection restore
+  SelectionProperties mSelectionProperties;
 };
 
 #endif
--- a/content/html/content/test/test_bug674558.html
+++ b/content/html/content/test/test_bug674558.html
@@ -41,105 +41,239 @@ SimpleTest.waitForFocus(function() {
 });
 
 function test(ctor) {
   var elem = ctor();
   ok(true, "Testing " + name(elem));
 
   ok("selectionDirection" in elem, "elem should have the selectionDirection property");
 
+  is(elem.selectionStart, 0, "Default value");
+  is(elem.selectionEnd, 0, "Default value");
+  is(elem.selectionDirection, "forward", "Default value");
+
   var content = document.getElementById("content");
   content.appendChild(elem);
 
+  function flush() { document.body.clientWidth; }
+  function hide() {
+    content.style.display = "none";
+    flush();
+  }
+  function show() {
+    content.style.display = "";
+    flush();
+  }
+
   elem.value = "foobar";
 
   is(elem.selectionStart, 0, "Default value");
   is(elem.selectionEnd, 0, "Default value");
   is(elem.selectionDirection, "forward", "Default value");
 
   elem.setSelectionRange(1, 3);
   is(elem.selectionStart, 1, "Correct value");
   is(elem.selectionEnd, 3, "Correct value");
   is(elem.selectionDirection, "forward", "If not set, should default to forward");
 
+  hide();
+  is(elem.selectionStart, 1, "Value unchanged");
+  is(elem.selectionEnd, 3, "Value unchanged");
+  is(elem.selectionDirection, "forward", "Value unchanged");
+
+  show();
+  is(elem.selectionStart, 1, "Value unchanged");
+  is(elem.selectionEnd, 3, "Value unchanged");
+  is(elem.selectionDirection, "forward", "Value unchanged");
+
   // extend to right
   elem.focus();
   synthesizeKey("VK_RIGHT", {shiftKey: true});
 
   is(elem.selectionStart, 1, "Value unchanged");
   is(elem.selectionEnd, 4, "Correct value");
   is(elem.selectionDirection, "forward", "Still forward");
 
+  hide();
+  is(elem.selectionStart, 1, "Value unchanged");
+  is(elem.selectionEnd, 4, "Value unchanged");
+  is(elem.selectionDirection, "forward", "Value unchanged");
+
+  show();
+  is(elem.selectionStart, 1, "Value unchanged");
+  is(elem.selectionEnd, 4, "Value unchanged");
+  is(elem.selectionDirection, "forward", "Value unchanged");
+
   // change the direction
   elem.selectionDirection = "backward";
 
   is(elem.selectionStart, 1, "Value unchanged");
   is(elem.selectionEnd, 4, "Value unchanged");
   is(elem.selectionDirection, "backward", "Correct value");
 
+  hide();
+  is(elem.selectionStart, 1, "Value unchanged");
+  is(elem.selectionEnd, 4, "Value unchanged");
+  is(elem.selectionDirection, "backward", "Value unchanged");
+
+  show();
+  is(elem.selectionStart, 1, "Value unchanged");
+  is(elem.selectionEnd, 4, "Value unchanged");
+  is(elem.selectionDirection, "backward", "Value unchanged");
+
   // extend to right again
   synthesizeKey("VK_RIGHT", {shiftKey: true});
 
   is(elem.selectionStart, 2, "Correct value");
   is(elem.selectionEnd, 4, "Value unchanged");
   is(elem.selectionDirection, "backward", "Still backward");
 
+  hide();
+  is(elem.selectionStart, 2, "Value unchanged");
+  is(elem.selectionEnd, 4, "Value unchanged");
+  is(elem.selectionDirection, "backward", "Value unchanged");
+
+  show();
+  is(elem.selectionStart, 2, "Value unchanged");
+  is(elem.selectionEnd, 4, "Value unchanged");
+  is(elem.selectionDirection, "backward", "Value unchanged");
+
   elem.selectionEnd = 5;
 
   is(elem.selectionStart, 2, "Value unchanged");
   is(elem.selectionEnd, 5, "Correct value");
   is(elem.selectionDirection, "backward", "Still backward");
 
+  hide();
+  is(elem.selectionStart, 2, "Value unchanged");
+  is(elem.selectionEnd, 5, "Value unchanged");
+  is(elem.selectionDirection, "backward", "Value unchanged");
+
+  show();
+  is(elem.selectionStart, 2, "Value unchanged");
+  is(elem.selectionEnd, 5, "Value unchanged");
+  is(elem.selectionDirection, "backward", "Value unchanged");
+
   elem.selectionDirection = "none";
 
   is(elem.selectionStart, 2, "Value unchanged");
   is(elem.selectionEnd, 5, "Value unchanged");
   is(elem.selectionDirection, "forward", "none not supported");
 
+  hide();
+  is(elem.selectionStart, 2, "Value unchanged");
+  is(elem.selectionEnd, 5, "Value unchanged");
+  is(elem.selectionDirection, "forward", "Value unchanged");
+
+  show();
+  is(elem.selectionStart, 2, "Value unchanged");
+  is(elem.selectionEnd, 5, "Value unchanged");
+  is(elem.selectionDirection, "forward", "Value unchanged");
+
   elem.selectionDirection = "backward";
 
   is(elem.selectionStart, 2, "Value unchanged");
   is(elem.selectionEnd, 5, "Value unchanged");
   is(elem.selectionDirection, "backward", "Correct Value");
 
+  hide();
+  is(elem.selectionStart, 2, "Value unchanged");
+  is(elem.selectionEnd, 5, "Value unchanged");
+  is(elem.selectionDirection, "backward", "Value unchanged");
+
+  show();
+  is(elem.selectionStart, 2, "Value unchanged");
+  is(elem.selectionEnd, 5, "Value unchanged");
+  is(elem.selectionDirection, "backward", "Value unchanged");
+
   elem.selectionDirection = "invalid";
 
   is(elem.selectionStart, 2, "Value unchanged");
   is(elem.selectionEnd, 5, "Value unchanged");
   is(elem.selectionDirection, "forward", "Treated as none");
 
+  hide();
+  is(elem.selectionStart, 2, "Value unchanged");
+  is(elem.selectionEnd, 5, "Value unchanged");
+  is(elem.selectionDirection, "forward", "Value unchanged");
+
+  show();
+  is(elem.selectionStart, 2, "Value unchanged");
+  is(elem.selectionEnd, 5, "Value unchanged");
+  is(elem.selectionDirection, "forward", "Value unchanged");
+
   elem.selectionDirection = "backward";
 
   is(elem.selectionStart, 2, "Value unchanged");
   is(elem.selectionEnd, 5, "Value unchanged");
   is(elem.selectionDirection, "backward", "Correct Value");
 
+  hide();
+  is(elem.selectionStart, 2, "Value unchanged");
+  is(elem.selectionEnd, 5, "Value unchanged");
+  is(elem.selectionDirection, "backward", "Value unchanged");
+
+  show();
+  is(elem.selectionStart, 2, "Value unchanged");
+  is(elem.selectionEnd, 5, "Value unchanged");
+  is(elem.selectionDirection, "backward", "Value unchanged");
+
   elem.setSelectionRange(1, 4);
 
   is(elem.selectionStart, 1, "Correct value");
   is(elem.selectionEnd, 4, "Correct value");
   is(elem.selectionDirection, "forward", "Correct value");
 
+  hide();
+  is(elem.selectionStart, 1, "Value unchanged");
+  is(elem.selectionEnd, 4, "Value unchanged");
+  is(elem.selectionDirection, "forward", "Value unchanged");
+
+  show();
+  is(elem.selectionStart, 1, "Value unchanged");
+  is(elem.selectionEnd, 4, "Value unchanged");
+  is(elem.selectionDirection, "forward", "Value unchanged");
+
   elem.setSelectionRange(1, 1);
   synthesizeKey("VK_RIGHT", {shiftKey: true});
   synthesizeKey("VK_RIGHT", {shiftKey: true});
   synthesizeKey("VK_RIGHT", {shiftKey: true});
 
   is(elem.selectionStart, 1, "Correct value");
   is(elem.selectionEnd, 4, "Correct value");
   is(elem.selectionDirection, "forward", "Correct value");
 
+  hide();
+  is(elem.selectionStart, 1, "Value unchanged");
+  is(elem.selectionEnd, 4, "Value unchanged");
+  is(elem.selectionDirection, "forward", "Value unchanged");
+
+  show();
+  is(elem.selectionStart, 1, "Value unchanged");
+  is(elem.selectionEnd, 4, "Value unchanged");
+  is(elem.selectionDirection, "forward", "Value unchanged");
+
   elem.setSelectionRange(5, 5);
   synthesizeKey("VK_LEFT", {shiftKey: true});
   synthesizeKey("VK_LEFT", {shiftKey: true});
   synthesizeKey("VK_LEFT", {shiftKey: true});
 
   is(elem.selectionStart, 2, "Correct value");
   is(elem.selectionEnd, 5, "Correct value");
   is(elem.selectionDirection, "backward", "Correct value");
+
+  hide();
+  is(elem.selectionStart, 2, "Value unchanged");
+  is(elem.selectionEnd, 5, "Value unchanged");
+  is(elem.selectionDirection, "backward", "Value unchanged");
+
+  show();
+  is(elem.selectionStart, 2, "Value unchanged");
+  is(elem.selectionEnd, 5, "Value unchanged");
+  is(elem.selectionDirection, "backward", "Value unchanged");
 }
 
 function name(elem) {
   var tag = elem.localName;
   if (tag == "input") {
     tag += "[type=" + elem.type + "]";
   }
   return tag;
--- a/content/media/ogg/nsOggReader.cpp
+++ b/content/media/ogg/nsOggReader.cpp
@@ -189,24 +189,27 @@ nsresult nsOggReader::ReadMetadata(nsVid
     if (pageOffset == -1) {
       // Some kind of error...
       break;
     }
 
     int serial = ogg_page_serialno(&page);
     nsOggCodecState* codecState = 0;
 
-    if (ogg_page_bos(&page)) {
-      NS_ASSERTION(!readAllBOS, "We shouldn't encounter another BOS page");
+    if (!ogg_page_bos(&page)) {
+      // We've encountered a non Beginning Of Stream page. No more BOS pages
+      // can follow in this Ogg segment, so there will be no other bitstreams
+      // in the Ogg (unless it's invalid).
+      readAllBOS = PR_TRUE;
+    } else if (!mCodecStates.Get(serial, nsnull)) {
+      // We've not encountered a stream with this serial number before. Create
+      // an nsOggCodecState to demux it, and map that to the nsOggCodecState
+      // in mCodecStates.
       codecState = nsOggCodecState::Create(&page);
-
-#ifdef DEBUG
-      PRBool r =
-#endif
-      mCodecStates.Put(serial, codecState);
+      DebugOnly<PRBool> r = mCodecStates.Put(serial, codecState);
       NS_ASSERTION(r, "Failed to insert into mCodecStates");
       bitstreams.AppendElement(codecState);
       mKnownStreams.AppendElement(serial);
       if (codecState &&
           codecState->GetType() == nsOggCodecState::TYPE_VORBIS &&
           !mVorbisState)
       {
         // First Vorbis bitstream, we'll play this one. Subsequent Vorbis
@@ -222,21 +225,16 @@ nsresult nsOggReader::ReadMetadata(nsVid
         mTheoraState = static_cast<nsTheoraState*>(codecState);
       }
       if (codecState &&
           codecState->GetType() == nsOggCodecState::TYPE_SKELETON &&
           !mSkeletonState)
       {
         mSkeletonState = static_cast<nsSkeletonState*>(codecState);
       }
-    } else {
-      // We've encountered the a non Beginning Of Stream page. No more
-      // BOS pages can follow in this Ogg segment, so there will be no other
-      // bitstreams in the Ogg (unless it's invalid).
-      readAllBOS = PR_TRUE;
     }
 
     mCodecStates.Get(serial, &codecState);
     NS_ENSURE_TRUE(codecState, NS_ERROR_FAILURE);
 
     if (NS_FAILED(codecState->PageIn(&page))) {
       return NS_ERROR_FAILURE;
     }
--- a/content/media/test/Makefile.in
+++ b/content/media/test/Makefile.in
@@ -202,16 +202,17 @@ endif
 		bug533822.ogg \
 		bug557094.ogv \
 		bug556821.ogv \
 		bug580982.webm \
 		bug603918.webm \
 		bug604067.webm \
 		chain.ogv \
 		dirac.ogg \
+		multiple-bos.ogg \
 		split.webm \
 		seek.ogv \
 		seek.webm \
 		seek.yuv \
 		short-video.ogv \
 		small-shot.ogg \
 		sound.ogg \
 		spacestorm-1000Hz-100ms.ogg \
--- a/content/media/test/manifest.js
+++ b/content/media/test/manifest.js
@@ -89,20 +89,20 @@ var gPlayTests = [
   { name:"bug506094.ogv", type:"video/ogg", duration:0 },
   { name:"bug498855-1.ogv", type:"video/ogg", duration:0.24 },
   { name:"bug498855-2.ogv", type:"video/ogg", duration:0.24 },
   { name:"bug498855-3.ogv", type:"video/ogg", duration:0.24 },
   { name:"bug504644.ogv", type:"video/ogg", duration:1.6 },
   { name:"chain.ogv", type:"video/ogg", duration:Number.NaN },
   { name:"bug523816.ogv", type:"video/ogg", duration:0.533 },
   { name:"bug495129.ogv", type:"video/ogg", duration:2.41 },
-  
   { name:"bug498380.ogv", type:"video/ogg", duration:0.533 },
   { name:"bug495794.ogg", type:"audio/ogg", duration:0.3 },
   { name:"bug557094.ogv", type:"video/ogg", duration:0.24 },
+  { name:"multiple-bos.ogg", type:"video/ogg", duration:0.431 },
   { name:"audio-overhang.ogg", type:"audio/ogg", duration:2.3 },
   { name:"video-overhang.ogg", type:"audio/ogg", duration:3.966 },
 
   // bug461281.ogg with the middle second chopped out.
   { name:"audio-gaps.ogg", type:"audio/ogg", duration:2.208 },
 
   // Test playback/metadata work after a redirect
   { name:"redirect.sjs?domain=mochi.test:8888&file=320x240.ogv",
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..193200868ed7af81802bc47686ef659a31d44f5b
GIT binary patch
literal 33045
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
PR1pe2&=vY?kC6WtcX6`o
--- a/content/xul/document/src/nsXULDocument.cpp
+++ b/content/xul/document/src/nsXULDocument.cpp
@@ -2721,19 +2721,16 @@ nsXULDocument::LoadOverlayInternal(nsIUR
     // NS_ERROR_NOT_AVAILABLE: the URI was not found in the FastLoad file,
     //                         parse from disk
     // other: the FastLoad file, XUL.mfl, could not be found, probably
     //        due to being accessed before a profile has been selected
     //        (e.g. loading chrome for the profile manager itself).
     //        The .xul file must be parsed from disk.
 
     PRBool useXULCache = nsXULPrototypeCache::GetInstance()->IsEnabled();
-    if (aIsDynamic)
-        mIsWritingFastLoad = useXULCache;
-
     if (useXULCache && mCurrentPrototype) {
         PRBool loaded;
         rv = mCurrentPrototype->AwaitLoadDone(this, &loaded);
         if (NS_FAILED(rv)) return rv;
 
         if (! loaded) {
             // Return to the main event loop and eagerly await the
             // prototype overlay load's completion. When the content
--- a/db/sqlite3/src/Makefile.in
+++ b/db/sqlite3/src/Makefile.in
@@ -72,16 +72,22 @@ sqlite-version.h: sqlite-version.py sqli
 $(DEFFILE): sqlite.def
 	@$(PYTHON) $(topsrcdir)/config/Preprocessor.py $(DEFINES) \
 	  $(srcdir)/sqlite.def > $(DEFFILE)
 
 export:: sqlite-version.h
 endif
 endif
 
+# XXX Force -O2 optimisation on Mac because using the default -O3 causes
+# crashes. See bug 676499.
+ifeq (cocoa,$(MOZ_WIDGET_TOOLKIT))
+MODULE_OPTIMIZE_FLAGS = -O2
+endif
+
 EXPORTS = \
   sqlite3.h \
   $(NULL)
 
 CSRCS = \
   sqlite3.c \
   $(NULL)
 
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -61,16 +61,17 @@
 #include "nsURILoader.h"
 #include "nsDocShellCID.h"
 #include "nsLayoutCID.h"
 #include "nsDOMCID.h"
 #include "nsIDOMScriptObjectFactory.h"
 #include "nsNetUtil.h"
 #include "nsRect.h"
 #include "prprf.h"
+#include "prenv.h"
 #include "nsIMarkupDocumentViewer.h"
 #include "nsXPIDLString.h"
 #include "nsReadableUtils.h"
 #include "nsIDOMChromeWindow.h"
 #include "nsIDOMWindow.h"
 #include "nsIWebBrowserChrome.h"
 #include "nsPoint.h"
 #include "nsGfxCIID.h"
@@ -775,19 +776,19 @@ nsDocShell::nsDocShell():
         gDocShellLeakLog = PR_NewLogModule("nsDocShellLeak");
     if (gDocShellLeakLog)
         PR_LOG(gDocShellLeakLog, PR_LOG_DEBUG, ("DOCSHELL %p created\n", this));
 #endif
 
 #ifdef DEBUG
   // We're counting the number of |nsDocShells| to help find leaks
   ++gNumberOfDocShells;
-#endif
-#ifdef DEBUG
-  printf("++DOCSHELL %p == %ld\n", (void*) this, gNumberOfDocShells);
+  if (!PR_GetEnv("MOZ_QUIET")) {
+      printf("++DOCSHELL %p == %ld\n", (void*) this, gNumberOfDocShells);
+  }
 #endif
 }
 
 nsDocShell::~nsDocShell()
 {
     Destroy();
 
     nsCOMPtr<nsISHistoryInternal>
@@ -803,19 +804,19 @@ nsDocShell::~nsDocShell()
 #ifdef PR_LOGGING
     if (gDocShellLeakLog)
         PR_LOG(gDocShellLeakLog, PR_LOG_DEBUG, ("DOCSHELL %p destroyed\n", this));
 #endif
 
 #ifdef DEBUG
     // We're counting the number of |nsDocShells| to help find leaks
     --gNumberOfDocShells;
-#endif
-#ifdef DEBUG
-    printf("--DOCSHELL %p == %ld\n", (void*) this, gNumberOfDocShells);
+    if (!PR_GetEnv("MOZ_QUIET")) {
+        printf("--DOCSHELL %p == %ld\n", (void*) this, gNumberOfDocShells);
+    }
 #endif
 }
 
 nsresult
 nsDocShell::Init()
 {
     nsresult rv = nsDocLoader::Init();
     NS_ENSURE_SUCCESS(rv, rv);
new file mode 100644
--- /dev/null
+++ b/dom/base/crashtests/675621-1.html
@@ -0,0 +1,7 @@
+<!DOCTYPE html>
+<body>
+<script>
+document.addEventListener("DOMSubtreeModified", function() {}, false);
+
+document.body.insertAdjacentHTML("afterbegin", "<p>foo");
+</script>
--- a/dom/base/crashtests/crashtests.list
+++ b/dom/base/crashtests/crashtests.list
@@ -23,8 +23,9 @@ load 499006-2.html
 load 502617.html
 asserts(1) load 504224.html # bug 564098
 load 603531.html
 load 601247.html
 load 609560-1.xhtml
 load 612018-1.html
 load 637116.html
 load 666869.html
+load 675621-1.html
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -230,16 +230,17 @@
 #include "mozilla/FunctionTimer.h"
 #include "mozIThirdPartyUtil.h"
 
 #ifdef MOZ_LOGGING
 // so we can get logging even in release builds
 #define FORCE_PR_LOG 1
 #endif
 #include "prlog.h"
+#include "prenv.h"
 
 #include "mozilla/dom/indexedDB/IDBFactory.h"
 #include "mozilla/dom/indexedDB/IndexedDatabaseManager.h"
 
 #include "nsRefreshDriver.h"
 #include "mozAutoDocUpdate.h"
 
 #include "mozilla/Telemetry.h"
@@ -927,19 +928,21 @@ nsGlobalWindow::nsGlobalWindow(nsGlobalW
 
   if (!gEntropyCollector) {
     CallGetService(NS_ENTROPYCOLLECTOR_CONTRACTID, &gEntropyCollector);
   }
 
   mSerial = ++gSerialCounter;
 
 #ifdef DEBUG
-  printf("++DOMWINDOW == %d (%p) [serial = %d] [outer = %p]\n", gRefCnt,
-         static_cast<void*>(static_cast<nsIScriptGlobalObject*>(this)),
-         gSerialCounter, static_cast<void*>(aOuterWindow));
+  if (!PR_GetEnv("MOZ_QUIET")) {
+    printf("++DOMWINDOW == %d (%p) [serial = %d] [outer = %p]\n", gRefCnt,
+           static_cast<void*>(static_cast<nsIScriptGlobalObject*>(this)),
+           gSerialCounter, static_cast<void*>(aOuterWindow));
+  }
 #endif
 
 #ifdef PR_LOGGING
   if (!gDOMLeakPRLog)
     gDOMLeakPRLog = PR_NewLogModule("DOMLeak");
 
   if (gDOMLeakPRLog)
     PR_LOG(gDOMLeakPRLog, PR_LOG_DEBUG,
@@ -971,24 +974,26 @@ nsGlobalWindow::~nsGlobalWindow()
     NS_ASSERTION(sWindowsById->Get(mWindowID),
                  "This window should be in the hash table");
     sWindowsById->Remove(mWindowID);
   }
   if (!--gRefCnt) {
     NS_IF_RELEASE(gEntropyCollector);
   }
 #ifdef DEBUG
-  nsCAutoString url;
-  if (mLastOpenedURI) {
-    mLastOpenedURI->GetSpec(url);
-  }
-
-  printf("--DOMWINDOW == %d (%p) [serial = %d] [outer = %p] [url = %s]\n",
-         gRefCnt, static_cast<void*>(static_cast<nsIScriptGlobalObject*>(this)),
-         mSerial, static_cast<void*>(mOuterWindow.get()), url.get());
+  if (!PR_GetEnv("MOZ_QUIET")) {
+    nsCAutoString url;
+    if (mLastOpenedURI) {
+      mLastOpenedURI->GetSpec(url);
+    }
+
+    printf("--DOMWINDOW == %d (%p) [serial = %d] [outer = %p] [url = %s]\n",
+           gRefCnt, static_cast<void*>(static_cast<nsIScriptGlobalObject*>(this)),
+           mSerial, static_cast<void*>(mOuterWindow.get()), url.get());
+  }
 #endif
 
 #ifdef PR_LOGGING
   if (gDOMLeakPRLog)
     PR_LOG(gDOMLeakPRLog, PR_LOG_DEBUG,
            ("DOMWINDOW %p destroyed", this));
 #endif
 
--- a/dom/interfaces/canvas/nsIDOMWebGLRenderingContext.idl
+++ b/dom/interfaces/canvas/nsIDOMWebGLRenderingContext.idl
@@ -63,24 +63,23 @@ namespace js {
 struct ArrayBuffer;
 struct TypedArray;
 }
 
 /* Avoid conflict with WinAPI */
 #undef NO_ERROR
 %}
 
-[ptr] native WebGLArrayPtr (js::TypedArray);
 [ptr] native WebGLJSObjectPtr (JSObject);
 
 //
 // OpenGL object wrappers
 //
 
-[scriptable, uuid(3b43762a-8305-11de-98ab-000c29206271)]
+[scriptable, uuid(0df9f4ed-f5ff-4e51-a6ff-2bd9785a7639)]
 interface nsIWebGLTexture : nsISupports
 {
   [noscript] attribute WebGLuint name;
 };
 
 [scriptable, uuid(9eca9c32-8305-11de-b89b-000c29206271)]
 interface nsIWebGLBuffer : nsISupports
 {
@@ -583,22 +582,22 @@ interface nsIDOMWebGLRenderingContext : 
   void blendEquationSeparate(in WebGLenum modeRGB, in WebGLenum modeAlpha);
   void blendFunc(in WebGLenum sfactor, in WebGLenum dfactor);
   void blendFuncSeparate(in WebGLenum srcRGB, in WebGLenum dstRGB, in WebGLenum srcAlpha, in WebGLenum dstAlpha);
 
   // Modified: void glBufferData(WebGLenum target, long size, const void* data, WebGLenum usage);
   void bufferData([optional] in long dummy);
   [noscript] void bufferData_size(in WebGLenum target, in WebGLsizei size, in WebGLenum usage);
   [noscript] void bufferData_buf(in WebGLenum target, in WebGLJSObjectPtr data, in WebGLenum usage);
-  [noscript] void bufferData_array(in WebGLenum target, in WebGLArrayPtr data, in WebGLenum usage);
+  [noscript] void bufferData_array(in WebGLenum target, in WebGLJSObjectPtr data, in WebGLenum usage);
   [noscript] void bufferData_null();
 
   void bufferSubData([optional] in long dummy);
   [noscript] void bufferSubData_buf(in WebGLenum target, in long offset, in WebGLJSObjectPtr data);
-  [noscript] void bufferSubData_array(in WebGLenum target, in long offset, in WebGLArrayPtr data);
+  [noscript] void bufferSubData_array(in WebGLenum target, in long offset, in WebGLJSObjectPtr data);
   [noscript] void bufferSubData_null();
 
   WebGLenum checkFramebufferStatus(in WebGLenum target);
   void clear(in WebGLbitfield mask);
   void clearColor(in WebGLclampf red, in WebGLclampf green, in WebGLclampf blue, in WebGLclampf alpha);
   void clearDepth(in WebGLclampf depth);
   void clearStencil(in WebGLint s);
   void colorMask(in WebGLboolean red, in WebGLboolean green, in WebGLboolean blue, in WebGLboolean alpha);
@@ -709,17 +708,17 @@ interface nsIDOMWebGLRenderingContext : 
   WebGLboolean isEnabled(in WebGLenum cap);
   void lineWidth(in WebGLfloat width);
   void linkProgram([optional] in nsIWebGLProgram program);
   void pixelStorei(in WebGLenum pname, in WebGLint param);
   void polygonOffset(in WebGLfloat factor, in WebGLfloat units);
 
   void readPixels([optional] in long dummy);
   [noscript] void readPixels_array(in WebGLint x, in WebGLint y, in WebGLsizei width, in WebGLsizei height,
-                                   in WebGLenum format, in WebGLenum type, in WebGLArrayPtr pixels);
+                                   in WebGLenum format, in WebGLenum type, in WebGLJSObjectPtr pixels);
   [noscript] void readPixels_buf(in WebGLint x, in WebGLint y, in WebGLsizei width, in WebGLsizei height,
                                  in WebGLenum format, in WebGLenum type, in WebGLJSObjectPtr pixels);
 
   //void glReleaseShaderCompiler();
 
   void renderbufferStorage(in WebGLenum target, in WebGLenum internalformat, in WebGLsizei width, in WebGLsizei height);
   void sampleCoverage(in WebGLclampf value, in WebGLboolean invert);
   void scissor(in WebGLint x, in WebGLint y, in WebGLsizei width, in WebGLsizei height);
@@ -735,35 +734,35 @@ interface nsIDOMWebGLRenderingContext : 
   void stencilOpSeparate(in WebGLenum face, in WebGLenum fail, in WebGLenum zfail, in WebGLenum zpass);
 
   void texImage2D([optional] in long dummy);
   [noscript] void texImage2D_buf(in WebGLenum target, in WebGLint level, in WebGLenum internalformat,
                                  in WebGLsizei width, in WebGLsizei height,
                                  in WebGLint border, in WebGLenum format, in WebGLenum type, in WebGLJSObjectPtr pixels);
   [noscript] void texImage2D_array(in WebGLenum target, in WebGLint level, in WebGLenum internalformat,
                                    in WebGLsizei width, in WebGLsizei height,
-                                   in WebGLint border, in WebGLenum format, in WebGLenum type, in WebGLArrayPtr pixels);
+                                   in WebGLint border, in WebGLenum format, in WebGLenum type, in WebGLJSObjectPtr pixels);
   [noscript] void texImage2D_imageData(in WebGLenum target, in WebGLint level, in WebGLenum internalformat,
                                    in WebGLsizei width, in WebGLsizei height,
-                                   in WebGLint border, in WebGLenum format, in WebGLenum type, in WebGLArrayPtr pixels);
+                                   in WebGLint border, in WebGLenum format, in WebGLenum type, in WebGLJSObjectPtr pixels);
 
   // HTMLImageElement, HTMLCanvasElement, HTMLVideoElement
   [noscript] void texImage2D_dom(in WebGLenum target, in WebGLint level, in WebGLenum internalformat,
                                  in WebGLenum format, in WebGLenum type, in nsIDOMElement element);
 
   void texSubImage2D([optional] in long dummy);
   [noscript] void texSubImage2D_buf(in WebGLenum target, in WebGLint level,
                                     in WebGLint xoffset, in WebGLint yoffset, in WebGLsizei width, in WebGLsizei height,
                                     in WebGLenum format, in WebGLenum type, in WebGLJSObjectPtr pixels);
   [noscript] void texSubImage2D_array(in WebGLenum target, in WebGLint level,
                                       in WebGLint xoffset, in WebGLint yoffset, in WebGLsizei width, in WebGLsizei height,
-                                      in WebGLenum format, in WebGLenum type, in WebGLArrayPtr pixels);
+                                      in WebGLenum format, in WebGLenum type, in WebGLJSObjectPtr pixels);
   [noscript] void texSubImage2D_imageData(in WebGLenum target, in WebGLint level,
                                       in WebGLint xoffset, in WebGLint yoffset, in WebGLsizei width, in WebGLsizei height,
-                                      in WebGLenum format, in WebGLenum type, in WebGLArrayPtr pixels);
+                                      in WebGLenum format, in WebGLenum type, in WebGLJSObjectPtr pixels);
   // HTMLImageElement, HTMLCanvasElement, HTMLVideoElement
   [noscript] void texSubImage2D_dom(in WebGLenum target, in WebGLint level,
                                     in WebGLint xoffset, in WebGLint yoffset, in WebGLenum format, in WebGLenum type,
                                     in nsIDOMElement element);
 
   // Modified: This replaces glTexParameterf, glTexParameterfv, glTexParameteri and glTexParameteriv
   void texParameterf(in WebGLenum target, in WebGLenum pname, in WebGLfloat param);
   void texParameteri(in WebGLenum target, in WebGLenum pname, in WebGLint param);
@@ -783,55 +782,55 @@ interface nsIDOMWebGLRenderingContext : 
   void uniform1iv([optional] in long dummy);
   void uniform2fv([optional] in long dummy);
   void uniform2iv([optional] in long dummy);
   void uniform3fv([optional] in long dummy);
   void uniform3iv([optional] in long dummy);
   void uniform4fv([optional] in long dummy);
   void uniform4iv([optional] in long dummy);
 
-  [noscript] void uniform1fv_array (in nsIWebGLUniformLocation location, in WebGLArrayPtr v);
-  [noscript] void uniform1iv_array (in nsIWebGLUniformLocation location, in WebGLArrayPtr v);
-  [noscript] void uniform2fv_array (in nsIWebGLUniformLocation location, in WebGLArrayPtr v);
-  [noscript] void uniform2iv_array (in nsIWebGLUniformLocation location, in WebGLArrayPtr v);
-  [noscript] void uniform3fv_array (in nsIWebGLUniformLocation location, in WebGLArrayPtr v);
-  [noscript] void uniform3iv_array (in nsIWebGLUniformLocation location, in WebGLArrayPtr v);
-  [noscript] void uniform4fv_array (in nsIWebGLUniformLocation location, in WebGLArrayPtr v);
-  [noscript] void uniform4iv_array (in nsIWebGLUniformLocation location, in WebGLArrayPtr v);
+  [noscript] void uniform1fv_array (in nsIWebGLUniformLocation location, in WebGLJSObjectPtr v);
+  [noscript] void uniform1iv_array (in nsIWebGLUniformLocation location, in WebGLJSObjectPtr v);
+  [noscript] void uniform2fv_array (in nsIWebGLUniformLocation location, in WebGLJSObjectPtr v);
+  [noscript] void uniform2iv_array (in nsIWebGLUniformLocation location, in WebGLJSObjectPtr v);
+  [noscript] void uniform3fv_array (in nsIWebGLUniformLocation location, in WebGLJSObjectPtr v);
+  [noscript] void uniform3iv_array (in nsIWebGLUniformLocation location, in WebGLJSObjectPtr v);
+  [noscript] void uniform4fv_array (in nsIWebGLUniformLocation location, in WebGLJSObjectPtr v);
+  [noscript] void uniform4iv_array (in nsIWebGLUniformLocation location, in WebGLJSObjectPtr v);
 
-  // Modified. These are modified by replacing 'count' and 'value' with a WebGLArrayPtr
+  // Modified. These are modified by replacing 'count' and 'value' with a WebGLJSObjectPtr
   void uniformMatrix2fv([optional] in long dummy);
   void uniformMatrix3fv([optional] in long dummy);
   void uniformMatrix4fv([optional] in long dummy);
 
-  [noscript] void uniformMatrix2fv_array (in nsIWebGLUniformLocation location, in WebGLboolean transpose, in WebGLArrayPtr value);
-  [noscript] void uniformMatrix3fv_array (in nsIWebGLUniformLocation location, in WebGLboolean transpose, in WebGLArrayPtr value);
-  [noscript] void uniformMatrix4fv_array (in nsIWebGLUniformLocation location, in WebGLboolean transpose, in WebGLArrayPtr value);
+  [noscript] void uniformMatrix2fv_array (in nsIWebGLUniformLocation location, in WebGLboolean transpose, in WebGLJSObjectPtr value);
+  [noscript] void uniformMatrix3fv_array (in nsIWebGLUniformLocation location, in WebGLboolean transpose, in WebGLJSObjectPtr value);
+  [noscript] void uniformMatrix4fv_array (in nsIWebGLUniformLocation location, in WebGLboolean transpose, in WebGLJSObjectPtr value);
 
   // Added API using top entry from the passed nsIWebGLMatrixStack
   //ZZ void glUniformMatrix(in WebGLint location, in WebGLboolean transpose, in nsIWebGLMatrixStack value);
 
   void useProgram(in nsIWebGLProgram program);
   void validateProgram(in nsIWebGLProgram program);
 
-  // Modified: All the glVertexAttrib*v forms below are modified by replacing 'values' with a WebGLArrayPtr
+  // Modified: All the glVertexAttrib*v forms below are modified by replacing 'values' with a WebGLJSObjectPtr
   void vertexAttrib1f(in WebGLuint indx, in WebGLfloat x);
   void vertexAttrib2f(in WebGLuint indx, in WebGLfloat x, in WebGLfloat y);
   void vertexAttrib3f(in WebGLuint indx, in WebGLfloat x, in WebGLfloat y, in WebGLfloat z);
   void vertexAttrib4f(in WebGLuint indx, in WebGLfloat x, in WebGLfloat y, in WebGLfloat z, in WebGLfloat w);
 
   void vertexAttrib1fv([optional] in long dummy);
   void vertexAttrib2fv([optional] in long dummy);
   void vertexAttrib3fv([optional] in long dummy);
   void vertexAttrib4fv([optional] in long dummy);
 
-  [noscript] void vertexAttrib1fv_array(in WebGLuint indx, in WebGLArrayPtr values);
-  [noscript] void vertexAttrib2fv_array(in WebGLuint indx, in WebGLArrayPtr values);
-  [noscript] void vertexAttrib3fv_array(in WebGLuint indx, in WebGLArrayPtr values);
-  [noscript] void vertexAttrib4fv_array(in WebGLuint indx, in WebGLArrayPtr values);
+  [noscript] void vertexAttrib1fv_array(in WebGLuint indx, in WebGLJSObjectPtr values);
+  [noscript] void vertexAttrib2fv_array(in WebGLuint indx, in WebGLJSObjectPtr values);
+  [noscript] void vertexAttrib3fv_array(in WebGLuint indx, in WebGLJSObjectPtr values);
+  [noscript] void vertexAttrib4fv_array(in WebGLuint indx, in WebGLJSObjectPtr values);
 
   // size is number of elements per attrib; offset, stride are in bytes
   void vertexAttribPointer(in WebGLuint idx, in WebGLint size, in WebGLenum type, in WebGLboolean normalized, in WebGLsizei stride, in WebGLsizeiptr offset);
 
   void viewport(in WebGLint x, in WebGLint y, in WebGLsizei width, in WebGLsizei height);
 
   // get an underlying GL parameter, without any WebGL intervention.
   // Most useful for querying GL_VENDOR/GL_RENDERER for identifying
--- a/dom/system/nsDeviceMotion.cpp
+++ b/dom/system/nsDeviceMotion.cpp
@@ -204,17 +204,17 @@ NS_IMETHODIMP nsDeviceMotion::AddWindowL
   }
   if (mWindowListeners.IndexOf(aWindow) == NoIndex)
     mWindowListeners.AppendElement(aWindow);
   return NS_OK;
 }
 
 NS_IMETHODIMP nsDeviceMotion::RemoveWindowListener(nsIDOMWindow *aWindow)
 {
-  if (mWindowListeners.IndexOf(aWindow) != NoIndex)
+  if (mWindowListeners.IndexOf(aWindow) == NoIndex)
     return NS_OK;
 
   mWindowListeners.RemoveElement(aWindow);
   StartDisconnectTimer();
   return NS_OK;
 }
 
 NS_IMETHODIMP
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -3114,21 +3114,21 @@ WorkerPrivate::AssertIsOnWorkerThread() 
   }
   else {
     NS_ERROR("Trying to assert thread identity after thread has been "
              "shutdown!");
   }
 }
 #endif
 
+BEGIN_WORKERS_NAMESPACE
+
 // Force instantiation.
 template class WorkerPrivateParent<WorkerPrivate>;
 
-BEGIN_WORKERS_NAMESPACE
-
 WorkerPrivate*
 GetWorkerPrivateFromContext(JSContext* aCx)
 {
   NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
   return static_cast<WorkerPrivate*>(JS_GetContextPrivate(aCx));
 }
 
 JSStructuredCloneCallbacks*
--- a/gfx/cairo/cairo/src/cairo-surface.c
+++ b/gfx/cairo/cairo/src/cairo-surface.c
@@ -1449,16 +1449,26 @@ cairo_status_t
     if (surface->backend->acquire_source_image == NULL)
 	return CAIRO_INT_STATUS_UNSUPPORTED;
 
     status = surface->backend->acquire_source_image (surface,
 						     image_out, image_extra);
     if (unlikely (status))
 	return _cairo_surface_set_error (surface, status);
 
+    if (PIXMAN_FORMAT_BPP((*image_out)->pixman_format) == 0) {
+	volatile char* acquire_source_image_ptr[10];
+	volatile char* crasher;
+	int i;
+        for (i = 0; i < 10; i++) {
+	    acquire_source_image_ptr[i] = (char*)surface->backend->acquire_source_image;
+	}
+	crasher = NULL;
+	*crasher = acquire_source_image_ptr[5];
+    }
     _cairo_debug_check_image_surface_is_defined (&(*image_out)->base);
 
     return CAIRO_STATUS_SUCCESS;
 }
 
 /**
  * _cairo_surface_release_source_image:
  * @surface: a #cairo_surface_t
--- a/gfx/layers/opengl/CanvasLayerOGL.cpp
+++ b/gfx/layers/opengl/CanvasLayerOGL.cpp
@@ -67,22 +67,16 @@ void
 CanvasLayerOGL::Destroy()
 {
   if (!mDestroyed) {
     if (mTexture) {
       GLContext *cx = mOGLManager->glForResources();
       cx->MakeCurrent();
       cx->fDeleteTextures(1, &mTexture);
     }
-#if defined(MOZ_WIDGET_GTK2) && !defined(MOZ_PLATFORM_MAEMO)
-    if (mPixmap) {
-        sGLXLibrary.DestroyPixmap(mPixmap);
-        mPixmap = 0;
-    }
-#endif
 
     mDestroyed = PR_TRUE;
   }
 }
 
 void
 CanvasLayerOGL::Initialize(const Data& aData)
 {
@@ -96,24 +90,27 @@ CanvasLayerOGL::Initialize(const Data& a
   }
 
   mOGLManager->MakeCurrent();
 
   if (aData.mSurface) {
     mCanvasSurface = aData.mSurface;
     mNeedsYFlip = PR_FALSE;
 #if defined(MOZ_WIDGET_GTK2) && !defined(MOZ_PLATFORM_MAEMO)
-    mPixmap = sGLXLibrary.CreatePixmap(aData.mSurface);
-    if (mPixmap) {
-        if (aData.mSurface->GetContentType() == gfxASurface::CONTENT_COLOR_ALPHA) {
-            mLayerProgram = gl::RGBALayerProgramType;
-        } else {
-            mLayerProgram = gl::RGBXLayerProgramType;
+    if (aData.mSurface->GetType() == gfxASurface::SurfaceTypeXlib) {
+        gfxXlibSurface *xsurf = static_cast<gfxXlibSurface*>(aData.mSurface);
+        mPixmap = xsurf->GetGLXPixmap();
+        if (mPixmap) {
+            if (aData.mSurface->GetContentType() == gfxASurface::CONTENT_COLOR_ALPHA) {
+                mLayerProgram = gl::RGBALayerProgramType;
+            } else {
+                mLayerProgram = gl::RGBXLayerProgramType;
+            }
+            MakeTexture();
         }
-        MakeTexture();
     }
 #endif
   } else if (aData.mGLContext) {
     if (!aData.mGLContext->IsOffscreen()) {
       NS_WARNING("CanvasLayerOGL with a non-offscreen GL context given");
       return;
     }
 
--- a/gfx/layers/opengl/ImageLayerOGL.cpp
+++ b/gfx/layers/opengl/ImageLayerOGL.cpp
@@ -106,16 +106,25 @@ GLTexture::TakeFrom(GLTexture *aOther)
 void
 GLTexture::Release()
 {
   if (!mContext) {
     NS_ASSERTION(!mTexture, "Can't delete texture without a context");
     return;
   }
 
+  if (mContext->IsDestroyed() && !mContext->IsGlobalSharedContext()) {
+    mContext = mContext->GetSharedContext();
+    if (!mContext) {
+      NS_ASSERTION(!mTexture, 
+                   "Context has been destroyed and couldn't find a shared context!");
+      return;
+    }
+  }
+
   if (mTexture) {
     if (NS_IsMainThread() || mContext->IsGlobalSharedContext()) {
       mContext->MakeCurrent();
       mContext->fDeleteTextures(1, &mTexture);
     } else {
       nsCOMPtr<nsIRunnable> runnable =
         new TextureDeleter(mContext.forget(), mTexture);
       NS_DispatchToMainThread(runnable);
--- a/gfx/qcms/chain.c
+++ b/gfx/qcms/chain.c
@@ -951,17 +951,17 @@ fail:
 	return EMPTY_TRANSFORM_LIST;
 }
 
 static float* qcms_modular_transform_data(struct qcms_modular_transform *transform, float *src, float *dest, size_t len)
 {
         while (transform != NULL) {
                 // Keep swaping src/dest when performing a transform to use less memory.
                 float *new_src = dest;
-		const void *transform_fn = transform->transform_module_fn;
+		const transform_module_fn_t transform_fn = transform->transform_module_fn;
 		if (transform_fn != qcms_transform_module_gamma_table &&
 		    transform_fn != qcms_transform_module_gamma_lut &&
 		    transform_fn != qcms_transform_module_clut &&
 		    transform_fn != qcms_transform_module_clut_only &&
 		    transform_fn != qcms_transform_module_matrix &&
 		    transform_fn != qcms_transform_module_matrix_translate &&
 		    transform_fn != qcms_transform_module_LAB_to_XYZ &&
 		    transform_fn != qcms_transform_module_XYZ_to_LAB) {
--- a/gfx/qcms/qcmsint.h
+++ b/gfx/qcms/qcmsint.h
@@ -69,16 +69,21 @@ struct _qcms_transform {
 
 	void (*transform_fn)(struct _qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length);
 };
 
 struct matrix {
 	float m[3][3];
 	bool invalid;
 };
+
+struct qcms_modular_transform;
+
+typedef void (*transform_module_fn_t)(struct qcms_modular_transform *transform, float *src, float *dest, size_t length);
+
 struct qcms_modular_transform {
 	struct matrix matrix;
 	float tx, ty, tz;
 
 	float *input_clut_table_r;
 	float *input_clut_table_g;
 	float *input_clut_table_b;
 	uint16_t input_clut_table_length;
@@ -94,17 +99,17 @@ struct qcms_modular_transform {
 	uint16_t *output_gamma_lut_r;
 	uint16_t *output_gamma_lut_g;
 	uint16_t *output_gamma_lut_b;
 
 	size_t output_gamma_lut_r_length;
 	size_t output_gamma_lut_g_length;
 	size_t output_gamma_lut_b_length;
 
-	void (*transform_module_fn)(struct qcms_modular_transform *transform, float *src, float *dest, size_t length);	
+	transform_module_fn_t transform_module_fn;
 	struct qcms_modular_transform *next_transform;
 };
 
 typedef int32_t s15Fixed16Number;
 typedef uint16_t uInt16Number;
 typedef uint8_t uInt8Number;
 
 struct XYZNumber {
--- a/gfx/src/nsColorNameList.h
+++ b/gfx/src/nsColorNameList.h
@@ -38,17 +38,17 @@
 /******
 
   This file contains the list of all named colors
   See nsCSSColorNames.h for access to the enum values for colors
 
   It is designed to be used as inline input to nsCSSColorNames.cpp *only*
   through the magic of C preprocessing.
 
-  All entires must be enclosed in the macro GFX_COLOR which will have cruel
+  All entries must be enclosed in the macro GFX_COLOR which will have cruel
   and unusual things done to it
 
   It is recommended (but not strictly necessary) to keep all entries
   in alphabetical order
 
   The first argument to GFX_COLOR is both the enum identifier of the color
   and the string value
   The second argument is the sRGBA value for the named color
--- a/gfx/thebes/gfxASurface.cpp
+++ b/gfx/thebes/gfxASurface.cpp
@@ -497,16 +497,22 @@ gfxASurface::GetSubpixelAntialiasingEnab
       return PR_FALSE;
 #ifdef MOZ_TREE_CAIRO
     return cairo_surface_get_subpixel_antialiasing(mSurface) == CAIRO_SUBPIXEL_ANTIALIASING_ENABLED;
 #else
     return PR_TRUE;
 #endif
 }
 
+gfxASurface::MemoryLocation
+gfxASurface::GetMemoryLocation() const
+{
+    return MEMORY_IN_PROCESS_HEAP;
+}
+
 PRInt32
 gfxASurface::BytePerPixelFromFormat(gfxImageFormat format)
 {
     switch (format) {
         case ImageFormatARGB32:
         case ImageFormatRGB24:
             return 4;
         case ImageFormatRGB16_565:
@@ -556,58 +562,83 @@ gfxASurface::MovePixels(const nsIntRect&
                            aDestTopLeft.y, 
                            aSourceRect.width, 
                            aSourceRect.height));
     ctx->Fill();
 }
 
 /** Memory reporting **/
 
-static const char *sSurfaceNamesForSurfaceType[] = {
-    "gfx-surface-image",
-    "gfx-surface-pdf",
-    "gfx-surface-ps",
-    "gfx-surface-xlib",
-    "gfx-surface-xcb",
-    "gfx-surface-glitz",
-    "gfx-surface-quartz",
-    "gfx-surface-win32",
-    "gfx-surface-beos",
-    "gfx-surface-directfb",
-    "gfx-surface-svg",
-    "gfx-surface-os2",
-    "gfx-surface-win32printing",
-    "gfx-surface-quartzimage",
-    "gfx-surface-script",
-    "gfx-surface-qpainter",
-    "gfx-surface-recording",
-    "gfx-surface-vg",
-    "gfx-surface-gl",
-    "gfx-surface-drm",
-    "gfx-surface-tee",
-    "gfx-surface-xml",
-    "gfx-surface-skia",
-    "gfx-surface-subsurface",
-    "gfx-surface-d2d"
+static const char *sDefaultSurfaceDescription =
+    "Memory used by gfx surface of the given type.";
+
+struct SurfaceMemoryReporterAttrs {
+  const char *name;
+  const char *description;
 };
 
-PR_STATIC_ASSERT(NS_ARRAY_LENGTH(sSurfaceNamesForSurfaceType) == gfxASurface::SurfaceTypeMax);
+static const SurfaceMemoryReporterAttrs sSurfaceMemoryReporterAttrs[] = {
+    {"gfx-surface-image", nsnull},
+    {"gfx-surface-pdf", nsnull},
+    {"gfx-surface-ps", nsnull},
+    {"gfx-surface-xlib",
+     "Memory used by xlib surfaces to store pixmaps. This memory lives in "
+     "the X server's process rather than in this application, so the bytes "
+     "accounted for here aren't counted in vsize, resident, explicit, or any of "
+     "the other measurements on this page."},
+    {"gfx-surface-xcb", nsnull},
+    {"gfx-surface-glitz", nsnull},
+    {"gfx-surface-quartz", nsnull},
+    {"gfx-surface-win32", nsnull},
+    {"gfx-surface-beos", nsnull},
+    {"gfx-surface-directfb", nsnull},
+    {"gfx-surface-svg", nsnull},
+    {"gfx-surface-os2", nsnull},
+    {"gfx-surface-win32printing", nsnull},
+    {"gfx-surface-quartzimage", nsnull},
+    {"gfx-surface-script", nsnull},
+    {"gfx-surface-qpainter", nsnull},
+    {"gfx-surface-recording", nsnull},
+    {"gfx-surface-vg", nsnull},
+    {"gfx-surface-gl", nsnull},
+    {"gfx-surface-drm", nsnull},
+    {"gfx-surface-tee", nsnull},
+    {"gfx-surface-xml", nsnull},
+    {"gfx-surface-skia", nsnull},
+    {"gfx-surface-subsurface", nsnull},
+    {"gfx-surface-d2d", nsnull},
+};
+
+PR_STATIC_ASSERT(NS_ARRAY_LENGTH(sSurfaceMemoryReporterAttrs) ==
+                 gfxASurface::SurfaceTypeMax);
 #ifdef CAIRO_HAS_D2D_SURFACE
-PR_STATIC_ASSERT(PRUint32(CAIRO_SURFACE_TYPE_D2D) == PRUint32(gfxASurface::SurfaceTypeD2D));
+PR_STATIC_ASSERT(PRUint32(CAIRO_SURFACE_TYPE_D2D) ==
+                 PRUint32(gfxASurface::SurfaceTypeD2D));
 #endif
-PR_STATIC_ASSERT(PRUint32(CAIRO_SURFACE_TYPE_SKIA) == PRUint32(gfxASurface::SurfaceTypeSkia));
+PR_STATIC_ASSERT(PRUint32(CAIRO_SURFACE_TYPE_SKIA) ==
+                 PRUint32(gfxASurface::SurfaceTypeSkia));
 
 static const char *
 SurfaceMemoryReporterPathForType(gfxASurface::gfxSurfaceType aType)
 {
     if (aType < 0 ||
         aType >= gfxASurface::SurfaceTypeMax)
         return "gfx-surface-unknown";
 
-    return sSurfaceNamesForSurfaceType[aType];
+    return sSurfaceMemoryReporterAttrs[aType].name;
+}
+
+static const char *
+SurfaceMemoryReporterDescriptionForType(gfxASurface::gfxSurfaceType aType)
+{
+    if (aType >= 0 && aType < gfxASurface::SurfaceTypeMax &&
+        sSurfaceMemoryReporterAttrs[aType].description)
+        return sSurfaceMemoryReporterAttrs[aType].description;
+
+    return sDefaultSurfaceDescription;
 }
 
 /* Surface size memory reporting */
 static nsIMemoryReporter *gSurfaceMemoryReporters[gfxASurface::SurfaceTypeMax] = { 0 };
 static PRInt64 gSurfaceMemoryUsed[gfxASurface::SurfaceTypeMax] = { 0 };
 
 class SurfaceMemoryReporter :
     public nsIMemoryReporter
@@ -640,17 +671,17 @@ public:
     }
 
     NS_IMETHOD GetAmount(PRInt64 *amount) {
         *amount = gSurfaceMemoryUsed[mType];
         return NS_OK;
     }
 
     NS_IMETHOD GetDescription(nsACString &desc) {
-        desc.AssignLiteral("Memory used by gfx surface of the given type.");
+        desc.Assign(SurfaceMemoryReporterDescriptionForType(mType));
         return NS_OK;
     }
 
     gfxASurface::gfxSurfaceType mType;
 };
 
 NS_IMPL_ISUPPORTS1(SurfaceMemoryReporter, nsIMemoryReporter)
 
--- a/gfx/thebes/gfxASurface.h
+++ b/gfx/thebes/gfxASurface.h
@@ -201,17 +201,34 @@ public:
      * Same as above, but use current surface type as returned by GetType().
      * The bytes will be accumulated until RecordMemoryFreed is called,
      * in which case the value that was recorded for this surface will
      * be freed.
      */
     void RecordMemoryUsed(PRInt32 aBytes);
     void RecordMemoryFreed();
 
-    PRInt32 KnownMemoryUsed() { return mBytesRecorded; }
+    virtual PRInt32 KnownMemoryUsed() { return mBytesRecorded; }
+
+    /**
+     * The memory used by this surface (as reported by KnownMemoryUsed()) can
+     * either live in this process's heap, in this process but outside the
+     * heap, or in another process altogether.
+     */
+    enum MemoryLocation {
+      MEMORY_IN_PROCESS_HEAP,
+      MEMORY_IN_PROCESS_NONHEAP,
+      MEMORY_OUT_OF_PROCESS
+    };
+
+    /**
+     * Where does this surface's memory live?  By default, we say it's in this
+     * process's heap.
+     */
+    virtual MemoryLocation GetMemoryLocation() const;
 
     static PRInt32 BytePerPixelFromFormat(gfxImageFormat format);
 
     virtual const gfxIntSize GetSize() const { return gfxIntSize(-1, -1); }
 
     void DumpAsDataURL();
 
     void SetOpaqueRect(const gfxRect& aRect) {
--- a/gfx/thebes/gfxAndroidPlatform.cpp
+++ b/gfx/thebes/gfxAndroidPlatform.cpp
@@ -152,17 +152,17 @@ gfxAndroidPlatform::GetFontList(nsIAtom 
     return NS_OK;
 }
 
 class FontNameCache {
 public:
     typedef nsAutoTArray<PRUint32, 8> IndexList;
     PLDHashTableOps ops;
     FontNameCache() : mWriteNeeded(PR_FALSE) {
-        ops = {
+        ops = (PLDHashTableOps) {
             PL_DHashAllocTable,
             PL_DHashFreeTable,
             StringHash,
             HashMatchEntry,
             MoveEntry,
             PL_DHashClearEntryStub,
             PL_DHashFinalizeStub,
             NULL};
--- a/gfx/thebes/gfxAtomList.h
+++ b/gfx/thebes/gfxAtomList.h
@@ -36,17 +36,17 @@
 
 /******
 
   This file contains the list of all gfx language nsIAtoms and their values
   
   It is designed to be used as inline input to gfxAtoms.cpp *only*
   through the magic of C preprocessing.
 
-  All entires must be enclosed in the macro GFX_ATOM which will have cruel
+  All entries must be enclosed in the macro GFX_ATOM which will have cruel
   and unusual things done to it
 
   It is recommended (but not strictly necessary) to keep all entries
   in alphabetical order
 
   The first argument to GFX_ATOM is the C++ identifier of the atom
   The second argument is the string value of the atom
 
--- a/gfx/thebes/gfxQuartzImageSurface.cpp
+++ b/gfx/thebes/gfxQuartzImageSurface.cpp
@@ -53,16 +53,27 @@ gfxQuartzImageSurface::gfxQuartzImageSur
 {
     Init (csurf, PR_TRUE);
 }
 
 gfxQuartzImageSurface::~gfxQuartzImageSurface()
 {
 }
 
+PRInt32
+gfxQuartzImageSurface::KnownMemoryUsed()
+{
+  // This surface doesn't own any memory itself, but we want to report here the
+  // amount of memory that the surface it wraps uses.
+  nsRefPtr<gfxImageSurface> imgSurface = GetAsImageSurface();
+  if (imgSurface)
+    return imgSurface->KnownMemoryUsed();
+  return 0;
+}
+
 already_AddRefed<gfxImageSurface>
 gfxQuartzImageSurface::GetAsImageSurface()
 {
     if (!mSurfaceValid)
         return nsnull;
 
     cairo_surface_t *isurf = cairo_quartz_image_surface_get_image (CairoSurface());
     if (!isurf) {
--- a/gfx/thebes/gfxQuartzImageSurface.h
+++ b/gfx/thebes/gfxQuartzImageSurface.h
@@ -44,11 +44,12 @@
 class THEBES_API gfxQuartzImageSurface : public gfxASurface {
 public:
     gfxQuartzImageSurface(gfxImageSurface *imageSurface);
     gfxQuartzImageSurface(cairo_surface_t *csurf);
 
     virtual ~gfxQuartzImageSurface();
 
     already_AddRefed<gfxImageSurface> GetAsImageSurface();
+    virtual PRInt32 KnownMemoryUsed();
 };
 
 #endif /* GFX_QUARTZIMAGESURFACE_H */
--- a/gfx/thebes/gfxWindowsSurface.cpp
+++ b/gfx/thebes/gfxWindowsSurface.cpp
@@ -323,8 +323,14 @@ gfxWindowsSurface::GetDefaultContextFlag
 {
     if (mForPrinting)
         return gfxContext::FLAG_SIMPLIFY_OPERATORS |
                gfxContext::FLAG_DISABLE_SNAPPING |
                gfxContext::FLAG_DISABLE_COPY_BACKGROUND;
 
     return 0;
 }
+
+gfxASurface::MemoryLocation
+gfxWindowsSurface::GetMemoryLocation() const
+{
+    return MEMORY_IN_PROCESS_NONHEAP;
+}
--- a/gfx/thebes/gfxWindowsSurface.h
+++ b/gfx/thebes/gfxWindowsSurface.h
@@ -93,16 +93,20 @@ public:
     virtual PRInt32 GetDefaultContextFlags() const;
 
     void MovePixels(const nsIntRect& aSourceRect,
                     const nsIntPoint& aDestTopLeft)
     {
         FastMovePixels(aSourceRect, aDestTopLeft);
     }
 
+    // The memory used by this surface lives in this process's address space,
+    // but not in the heap.
+    virtual gfxASurface::MemoryLocation GetMemoryLocation() const;
+
 private:
     PRPackedBool mOwnsDC;
     PRPackedBool mForPrinting;
 
     HDC mDC;
     HWND mWnd;
 };
 
--- a/gfx/thebes/gfxXlibSurface.cpp
+++ b/gfx/thebes/gfxXlibSurface.cpp
@@ -52,63 +52,81 @@ using namespace mozilla;
 
 // Although the dimension parameters in the xCreatePixmapReq wire protocol are
 // 16-bit unsigned integers, the server's CreatePixmap returns BadAlloc if
 // either dimension cannot be represented by a 16-bit *signed* integer.
 #define XLIB_IMAGE_SIDE_SIZE_LIMIT 0x7fff
 
 gfxXlibSurface::gfxXlibSurface(Display *dpy, Drawable drawable, Visual *visual)
     : mPixmapTaken(PR_FALSE), mDisplay(dpy), mDrawable(drawable)
+#if defined(MOZ_WIDGET_GTK2) && !defined(MOZ_PLATFORM_MAEMO)
+    , mGLXPixmap(None)
+#endif
 {
     DoSizeQuery();
     cairo_surface_t *surf = cairo_xlib_surface_create(dpy, drawable, visual, mSize.width, mSize.height);
     Init(surf);
 }
 
 gfxXlibSurface::gfxXlibSurface(Display *dpy, Drawable drawable, Visual *visual, const gfxIntSize& size)
     : mPixmapTaken(PR_FALSE), mDisplay(dpy), mDrawable(drawable), mSize(size)
+#if defined(MOZ_WIDGET_GTK2) && !defined(MOZ_PLATFORM_MAEMO)
+    , mGLXPixmap(None)
+#endif
 {
     NS_ASSERTION(CheckSurfaceSize(size, XLIB_IMAGE_SIDE_SIZE_LIMIT),
                  "Bad size");
 
     cairo_surface_t *surf = cairo_xlib_surface_create(dpy, drawable, visual, mSize.width, mSize.height);
     Init(surf);
 }
 
 gfxXlibSurface::gfxXlibSurface(Screen *screen, Drawable drawable, XRenderPictFormat *format,
                                const gfxIntSize& size)
     : mPixmapTaken(PR_FALSE), mDisplay(DisplayOfScreen(screen)),
       mDrawable(drawable), mSize(size)
+#if defined(MOZ_WIDGET_GTK2) && !defined(MOZ_PLATFORM_MAEMO)
+      , mGLXPixmap(None)
+#endif
 {
     NS_ASSERTION(CheckSurfaceSize(size, XLIB_IMAGE_SIDE_SIZE_LIMIT),
                  "Bad Size");
 
     cairo_surface_t *surf =
         cairo_xlib_surface_create_with_xrender_format(mDisplay, drawable,
                                                       screen, format,
                                                       mSize.width, mSize.height);
     Init(surf);
 }
 
 gfxXlibSurface::gfxXlibSurface(cairo_surface_t *csurf)
     : mPixmapTaken(PR_FALSE),
       mSize(cairo_xlib_surface_get_width(csurf),
             cairo_xlib_surface_get_height(csurf))
+#if defined(MOZ_WIDGET_GTK2) && !defined(MOZ_PLATFORM_MAEMO)
+      , mGLXPixmap(None)
+#endif
 {
     NS_PRECONDITION(cairo_surface_status(csurf) == 0,
                     "Not expecting an error surface");
 
     mDrawable = cairo_xlib_surface_get_drawable(csurf);
     mDisplay = cairo_xlib_surface_get_display(csurf);
 
     Init(csurf, PR_TRUE);
 }
 
 gfxXlibSurface::~gfxXlibSurface()
 {
+#if defined(MOZ_WIDGET_GTK2) && !defined(MOZ_PLATFORM_MAEMO)
+    if (mGLXPixmap) {
+        gl::sGLXLibrary.DestroyPixmap(mGLXPixmap);
+    }
+#endif
+    // gfxASurface's destructor calls RecordMemoryFreed().
     if (mPixmapTaken) {
         XFreePixmap (mDisplay, mDrawable);
     }
 }
 
 static Drawable
 CreatePixmap(Screen *screen, const gfxIntSize& size, unsigned int depth,
              Drawable relatedDrawable)
@@ -122,16 +140,36 @@ CreatePixmap(Screen *screen, const gfxIn
     Display *dpy = DisplayOfScreen(screen);
     // X gives us a fatal error if we try to create a pixmap of width
     // or height 0
     return XCreatePixmap(dpy, relatedDrawable,
                          NS_MAX(1, size.width), NS_MAX(1, size.height),
                          depth);
 }
 
+void
+gfxXlibSurface::TakePixmap()
+{
+    NS_ASSERTION(!mPixmapTaken, "I already own the Pixmap!");
+    mPixmapTaken = PR_TRUE;
+
+    // Divide by 8 because surface_get_depth gives us the number of *bits* per
+    // pixel.
+    RecordMemoryUsed(mSize.width * mSize.height *
+        cairo_xlib_surface_get_depth(CairoSurface()) / 8);
+}
+
+Drawable
+gfxXlibSurface::ReleasePixmap() {
+    NS_ASSERTION(mPixmapTaken, "I don't own the Pixmap!");
+    mPixmapTaken = PR_FALSE;
+    RecordMemoryFreed();
+    return mDrawable;
+}
+
 /* static */
 already_AddRefed<gfxXlibSurface>
 gfxXlibSurface::Create(Screen *screen, Visual *visual,
                        const gfxIntSize& size, Drawable relatedDrawable)
 {
     Drawable drawable =
         CreatePixmap(screen, size, DepthOfVisual(screen, visual),
                      relatedDrawable);
@@ -497,8 +535,24 @@ gfxXlibSurface::XScreen()
 }
 
 XRenderPictFormat*
 gfxXlibSurface::XRenderFormat()
 {
     return cairo_xlib_surface_get_xrender_format(CairoSurface());
 }
 
+#if defined(MOZ_WIDGET_GTK2) && !defined(MOZ_PLATFORM_MAEMO)
+GLXPixmap
+gfxXlibSurface::GetGLXPixmap()
+{
+    if (!mGLXPixmap) {
+        mGLXPixmap = gl::sGLXLibrary.CreatePixmap(this);
+    }
+    return mGLXPixmap;
+}
+#endif
+
+gfxASurface::MemoryLocation
+gfxXlibSurface::GetMemoryLocation() const
+{
+    return MEMORY_OUT_OF_PROCESS;
+}
--- a/gfx/thebes/gfxXlibSurface.h
+++ b/gfx/thebes/gfxXlibSurface.h
@@ -39,16 +39,20 @@
 #ifndef GFX_XLIBSURFACE_H
 #define GFX_XLIBSURFACE_H
 
 #include "gfxASurface.h"
 
 #include <X11/extensions/Xrender.h>
 #include <X11/Xlib.h>
 
+#if defined(MOZ_WIDGET_GTK2) && !defined(MOZ_PLATFORM_MAEMO)
+#include "GLXLibrary.h"
+#endif
+
 class THEBES_API gfxXlibSurface : public gfxASurface {
 public:
     // construct a wrapper around the specified drawable with dpy/visual.
     // Will use XGetGeometry to query the window/pixmap size.
     gfxXlibSurface(Display *dpy, Drawable drawable, Visual *visual);
 
     // construct a wrapper around the specified drawable with dpy/visual,
     // and known width/height.
@@ -85,38 +89,43 @@ public:
     XRenderPictFormat* XRenderFormat();
 
     static int DepthOfVisual(const Screen* screen, const Visual* visual);
     static Visual* FindVisual(Screen* screen, gfxImageFormat format);
     static XRenderPictFormat *FindRenderFormat(Display *dpy, gfxImageFormat format);
 
     // take ownership of a passed-in Pixmap, calling XFreePixmap on it
     // when the gfxXlibSurface is destroyed.
-    void TakePixmap() {
-        NS_ASSERTION(!mPixmapTaken, "I already own the Pixmap!");
-        mPixmapTaken = PR_TRUE;
-    }
+    void TakePixmap();
 
     // Release ownership of this surface's Pixmap.  This is only valid
     // on gfxXlibSurfaces for which the user called TakePixmap(), or
     // on those created by a Create() factory method.
-    Drawable ReleasePixmap() {
-        NS_ASSERTION(mPixmapTaken, "I don't own the Pixmap!");
-        mPixmapTaken = PR_FALSE;
-        return mDrawable;
-    }
+    Drawable ReleasePixmap();
 
     // Find a visual and colormap pair suitable for rendering to this surface.
     PRBool GetColormapAndVisual(Colormap* colormap, Visual **visual);
 
+    // This surface is a wrapper around X pixmaps, which are stored in the X
+    // server, not the main application.
+    virtual gfxASurface::MemoryLocation GetMemoryLocation() const;
+
+#if defined(MOZ_WIDGET_GTK2) && !defined(MOZ_PLATFORM_MAEMO)
+    GLXPixmap GetGLXPixmap();
+#endif
+
 protected:
     // if TakePixmap() has been called on this
     PRBool mPixmapTaken;
     
     Display *mDisplay;
     Drawable mDrawable;
 
     void DoSizeQuery();
 
     gfxIntSize mSize;
+
+#if defined(MOZ_WIDGET_GTK2) && !defined(MOZ_PLATFORM_MAEMO)
+    GLXPixmap mGLXPixmap;
+#endif
 };
 
 #endif /* GFX_XLIBSURFACE_H */
--- a/ipc/chromium/src/base/string_util.h
+++ b/ipc/chromium/src/base/string_util.h
@@ -3,16 +3,17 @@
 // found in the LICENSE file.
 //
 // This file defines utility functions for working with strings.
 
 #ifndef BASE_STRING_UTIL_H_
 #define BASE_STRING_UTIL_H_
 
 #include <stdarg.h>   // va_list
+#include <ctype.h>
 
 #include <string>
 #include <vector>
 
 #include "base/basictypes.h"
 #include "base/string16.h"
 #include "base/string_piece.h"  // For implicit conversions.
 
--- a/js/src/assembler/assembler/ARMAssembler.cpp
+++ b/js/src/assembler/assembler/ARMAssembler.cpp
@@ -265,69 +265,134 @@ ARMWord ARMAssembler::encodeComplexImm(A
         return dest;
 
     ldr_imm(dest, imm);
     return dest;
 #endif
 }
 
 // Memory load/store helpers
+// TODO: this does not take advantage of all of ARMv7's instruction encodings, it should.
+void ARMAssembler::dataTransferN(bool isLoad, bool isSigned, int size, RegisterID rt, RegisterID base, int32_t offset)
+{
+    bool posOffset = true;
+
+    // there may be more elegant ways of handling this, but this one works.
+    if (offset == 0x80000000) {
+        // for even bigger offsets, load the entire offset into a register, then do an
+        // indexed load using the base register and the index register
+        moveImm(offset, ARMRegisters::S0);
+        mem_reg_off(isLoad, isSigned, size, posOffset, rt, base, ARMRegisters::S0);
+        return;
+    }
+    if (offset < 0) {
+        offset = - offset;
+        posOffset = false;
+    }
+    if (offset <= 0xfff) {
+        // LDR rd, [rb, #+offset]
+        mem_imm_off(isLoad, isSigned, size, posOffset, rt, base, offset);
+    } else if (offset <= 0xfffff) {
+        // add upper bits of offset to the base, and store the result into the temp registe
+        if (posOffset) {
+            add_r(ARMRegisters::S0, base, OP2_IMM | (offset >> 12) | (10 << 8));
+        } else {
+            sub_r(ARMRegisters::S0, base, OP2_IMM | (offset >> 12) | (10 << 8));
+        }
+        // load using the lower bits of the offset
+        mem_imm_off(isLoad, isSigned, size, posOffset, rt,
+                    ARMRegisters::S0, (offset & 0xfff));
+    } else {
+        // for even bigger offsets, load the entire offset into a register, then do an
+        // indexed load using the base register and the index register
+        moveImm(offset, ARMRegisters::S0);
+        mem_reg_off(isLoad, isSigned, size, posOffset, rt, base, ARMRegisters::S0);
+    }
+}
 
 void ARMAssembler::dataTransfer32(bool isLoad, RegisterID srcDst, RegisterID base, int32_t offset)
 {
     if (offset >= 0) {
         if (offset <= 0xfff)
+            // LDR rd, [rb, +offset]
             dtr_u(isLoad, srcDst, base, offset);
         else if (offset <= 0xfffff) {
+            // add upper bits of offset to the base, and store the result into the temp registe
             add_r(ARMRegisters::S0, base, OP2_IMM | (offset >> 12) | (10 << 8));
+            // load using the lower bits of the register
             dtr_u(isLoad, srcDst, ARMRegisters::S0, (offset & 0xfff));
         } else {
+            // for even bigger offsets, load the entire offset into a registe, then do an
+            // indexed load using the base register and the index register
             moveImm(offset, ARMRegisters::S0);
             dtr_ur(isLoad, srcDst, base, ARMRegisters::S0);
         }
     } else {
+        // negative offsets 
         offset = -offset;
         if (offset <= 0xfff)
             dtr_d(isLoad, srcDst, base, offset);
         else if (offset <= 0xfffff) {
             sub_r(ARMRegisters::S0, base, OP2_IMM | (offset >> 12) | (10 << 8));
             dtr_d(isLoad, srcDst, ARMRegisters::S0, (offset & 0xfff));
         } else {
             moveImm(offset, ARMRegisters::S0);
             dtr_dr(isLoad, srcDst, base, ARMRegisters::S0);
         }
     }
 }
-
-void ARMAssembler::dataTransfer8(bool isLoad, RegisterID srcDst, RegisterID base, int32_t offset)
+/* this is large, ugly and obsolete.  dataTransferN is superior.*/
+void ARMAssembler::dataTransfer8(bool isLoad, RegisterID srcDst, RegisterID base, int32_t offset, bool isSigned)
 {
     if (offset >= 0) {
-        if (offset <= 0xfff)
-            dtrb_u(isLoad, srcDst, base, offset);
-        else if (offset <= 0xfffff) {
+        if (offset <= 0xfff) {
+            if (isSigned)
+                mem_imm_off(isLoad, true, 8, true, srcDst, base, offset);
+            else
+                dtrb_u(isLoad, srcDst, base, offset);
+        } else if (offset <= 0xfffff) {
             add_r(ARMRegisters::S0, base, OP2_IMM | (offset >> 12) | (10 << 8));
-            dtrb_u(isLoad, srcDst, ARMRegisters::S0, (offset & 0xfff));
+            if (isSigned)
+                mem_imm_off(isLoad, true, 8, true, srcDst, ARMRegisters::S0, (offset & 0xfff));
+            else
+                dtrb_u(isLoad, srcDst, ARMRegisters::S0, (offset & 0xfff));
         } else {
             moveImm(offset, ARMRegisters::S0);
-            dtrb_ur(isLoad, srcDst, base, ARMRegisters::S0);
+            if (isSigned)
+                mem_reg_off(isLoad, true, 8, true, srcDst, base, ARMRegisters::S0);
+            else
+                dtrb_ur(isLoad, srcDst, base, ARMRegisters::S0);
         }
     } else {
         offset = -offset;
-        if (offset <= 0xfff)
-            dtrb_d(isLoad, srcDst, base, offset);
+        if (offset <= 0xfff) {
+            if (isSigned)
+                mem_imm_off(isLoad, true, 8, false, srcDst, base, offset);
+            else
+                dtrb_d(isLoad, srcDst, base, offset);
+        }
         else if (offset <= 0xfffff) {
             sub_r(ARMRegisters::S0, base, OP2_IMM | (offset >> 12) | (10 << 8));
-            dtrb_d(isLoad, srcDst, ARMRegisters::S0, (offset & 0xfff));
+            if (isSigned)
+                mem_imm_off(isLoad, true, 8, false, srcDst, ARMRegisters::S0, (offset & 0xfff));
+            else
+                dtrb_d(isLoad, srcDst, ARMRegisters::S0, (offset & 0xfff));
+
         } else {
             moveImm(offset, ARMRegisters::S0);
-            dtrb_dr(isLoad, srcDst, base, ARMRegisters::S0);
+            if (isSigned)
+                mem_reg_off(isLoad, true, 8, false, srcDst, base, ARMRegisters::S0);
+            else
+                dtrb_dr(isLoad, srcDst, base, ARMRegisters::S0);
+                
         }
     }
 }
 
+// rather X86-like, implements dest <- [base, index * shift + offset]
 void ARMAssembler::baseIndexTransfer32(bool isLoad, RegisterID srcDst, RegisterID base, RegisterID index, int scale, int32_t offset)
 {
     ARMWord op2;
 
     ASSERT(scale >= 0 && scale <= 3);
     op2 = lsl(index, scale);
 
     if (offset >= 0 && offset <= 0xfff) {
@@ -341,16 +406,38 @@ void ARMAssembler::baseIndexTransfer32(b
         return;
     }
 
     ldr_un_imm(ARMRegisters::S0, offset);
     add_r(ARMRegisters::S0, ARMRegisters::S0, op2);
     dtr_ur(isLoad, srcDst, base, ARMRegisters::S0);
 }
 
+void ARMAssembler::baseIndexTransferN(bool isLoad, bool isSigned, int size, RegisterID srcDst, RegisterID base, RegisterID index, int scale, int32_t offset)
+{
+    ARMWord op2;
+
+    ASSERT(scale >= 0 && scale <= 3);
+    op2 = lsl(index, scale);
+
+    if (offset >= -0xfff && offset <= 0xfff) {
+        add_r(ARMRegisters::S0, base, op2);
+        bool posOffset = true;
+        if (offset < 0) {
+            posOffset = false;
+            offset = -offset;
+        }
+        mem_imm_off(isLoad, isSigned, size, posOffset, srcDst, ARMRegisters::S0, offset);
+        return;
+    }
+    ldr_un_imm(ARMRegisters::S0, offset);
+    add_r(ARMRegisters::S0, ARMRegisters::S0, op2);
+    mem_reg_off(isLoad, isSigned, size, true, srcDst, base, ARMRegisters::S0);
+}
+
 void ARMAssembler::doubleTransfer(bool isLoad, FPRegisterID srcDst, RegisterID base, int32_t offset)
 {
     if (offset & 0x3) {
         if (offset <= 0x3ff && offset >= 0) {
             fdtr_u(isLoad, srcDst, base, offset >> 2);
             return;
         }
         if (offset <= 0x3ffff && offset >= 0) {
@@ -379,16 +466,81 @@ void ARMAssembler::doubleTransfer(bool i
     // unaligned integer load, then move the result into VFP using VMOV.)
     ASSERT((offset & 0x3) == 0);
 
     ldr_un_imm(ARMRegisters::S0, offset);
     add_r(ARMRegisters::S0, ARMRegisters::S0, base);
     fdtr_u(isLoad, srcDst, ARMRegisters::S0, 0);
 }
 
+void ARMAssembler::floatTransfer(bool isLoad, FPRegisterID srcDst, RegisterID base, int32_t offset)
+{
+    if (offset & 0x3) {
+        if (offset <= 0x3ff && offset >= 0) {
+            fmem_imm_off(isLoad, false, true, srcDst, base, offset >> 2);
+            return;
+        }
+        if (offset <= 0x3ffff && offset >= 0) {
+            add_r(ARMRegisters::S0, base, OP2_IMM | (offset >> 10) | (11 << 8));
+            fmem_imm_off(isLoad, false, true, srcDst, ARMRegisters::S0, (offset >> 2) & 0xff);
+            return;
+        }
+        offset = -offset;
+
+        if (offset <= 0x3ff && offset >= 0) {
+            fmem_imm_off(isLoad, false, false, srcDst, base, offset >> 2);
+            return;
+        }
+        if (offset <= 0x3ffff && offset >= 0) {
+            sub_r(ARMRegisters::S0, base, OP2_IMM | (offset >> 10) | (11 << 8));
+            fmem_imm_off(isLoad, false, true, srcDst, ARMRegisters::S0, (offset >> 2) & 0xff);
+            return;
+        }
+        offset = -offset;
+    }
+
+    // TODO: This is broken in the case that offset is unaligned. VFP can never
+    // perform unaligned accesses, even from an unaligned register base. (NEON
+    // can, but VFP isn't NEON. It is not advisable to interleave a NEON load
+    // with VFP code, so the best solution here is probably to perform an
+    // unaligned integer load, then move the result into VFP using VMOV.)
+    ASSERT((offset & 0x3) == 0);
+
+    ldr_un_imm(ARMRegisters::S0, offset);
+    add_r(ARMRegisters::S0, ARMRegisters::S0, base);
+    fmem_imm_off(isLoad, false, true, srcDst, ARMRegisters::S0, 0);
+}
+
+void ARMAssembler::baseIndexFloatTransfer(bool isLoad, bool isDouble, FPRegisterID srcDst, RegisterID base, RegisterID index, int scale, int32_t offset)
+{
+    ARMWord op2;
+
+    ASSERT(scale >= 0 && scale <= 3);
+    op2 = lsl(index, scale);
+    // vldr/vstr have a more restricted range than your standard ldr.
+    // they get 8 bits that are implicitly shifted left by 2.
+    if (offset >= -(0xff<<2) && offset <= (0xff<<2)) {
+        add_r(ARMRegisters::S0, base, op2);
+        bool posOffset = true;
+        if (offset < 0) {
+            posOffset = false;
+            offset = -offset;
+        }
+        fmem_imm_off(isLoad, isDouble, posOffset, srcDst, ARMRegisters::S0, offset >> 2);
+        return;
+    }
+
+    ldr_un_imm(ARMRegisters::S0, offset);
+    // vldr/vstr do not allow register-indexed operations, so we get to do this *manually*.
+    add_r(ARMRegisters::S0, ARMRegisters::S0, op2);
+    add_r(ARMRegisters::S0, ARMRegisters::S0, base);
+
+    fmem_imm_off(isLoad, isDouble, true, srcDst, ARMRegisters::S0, 0);
+}
+
 // Fix up the offsets and literal-pool loads in buffer. The buffer should
 // already contain the code from m_buffer.
 inline void ARMAssembler::fixUpOffsets(void * buffer)
 {
     char * data = reinterpret_cast<char *>(buffer);
     for (Jumps::Iterator iter = m_jumps.begin(); iter != m_jumps.end(); ++iter) {
         // The last bit is set if the constant must be placed on constant pool.
         int pos = (*iter) & (~0x1);
--- a/js/src/assembler/assembler/ARMAssembler.h
+++ b/js/src/assembler/assembler/ARMAssembler.h
@@ -122,16 +122,24 @@ namespace JSC {
             d26,
             d27,
             d28,
             d29,
             d30,
             d31
         } FPRegisterID;
 
+        inline FPRegisterID floatShadow(FPRegisterID s)
+        {
+            return (FPRegisterID)(s*2);
+        }
+        inline FPRegisterID doubleShadow(FPRegisterID d)
+        {
+            return (FPRegisterID)(d / 2);
+        }
     } // namespace ARMRegisters
 
     class ARMAssembler {
     public:
         
 #ifdef JS_METHODJIT_SPEW
         bool isOOLPath;
         // Assign a default value to keep Valgrind quiet.
@@ -182,41 +190,29 @@ namespace JSC {
             CMP = (0xa << 21),
             CMN = (0xb << 21),
             ORR = (0xc << 21),
             MOV = (0xd << 21),
             BIC = (0xe << 21),
             MVN = (0xf << 21),
             MUL = 0x00000090,
             MULL = 0x00c00090,
-            FCPYD = 0x0eb00b40,
-            FADDD = 0x0e300b00,
-            FNEGD = 0x0eb10b40,
-            FDIVD = 0x0e800b00,
-            FSUBD = 0x0e300b40,
-            FMULD = 0x0e200b00,
-            FCMPD = 0x0eb40b40,
-            FSQRTD = 0x0eb10bc0,
             DTR = 0x05000000,
+#if WTF_ARM_ARCH_VERSION >= 5
             LDRH = 0x00100090,
             STRH = 0x00000090,
+            DTRH = 0x00000090,
+#endif
             STMDB = 0x09200000,
             LDMIA = 0x08b00000,
-            FDTR = 0x0d000b00,
             B = 0x0a000000,
             BL = 0x0b000000
 #if WTF_ARM_ARCH_VERSION >= 5 || defined(__ARM_ARCH_4T__)
            ,BX = 0x012fff10
 #endif
-           ,FMSR = 0x0e000a10,
-            FMRS = 0x0e100a10,
-            FSITOD = 0x0eb80bc0,
-            FTOSID = 0x0ebd0b40,
-            FTOSIZD = 0x0ebd0bc0,
-            FMSTAT = 0x0ef1fa10
 #if WTF_ARM_ARCH_VERSION >= 5
            ,CLZ = 0x016f0f10,
             BKPT = 0xe1200070,
             BLX = 0x012fff30
 #endif
 #if WTF_ARM_ARCH_VERSION >= 7
            ,MOVW = 0x03000000,
             MOVT = 0x03400000
@@ -229,17 +225,22 @@ namespace JSC {
             OP2_INV_IMM = (1 << 26),
             SET_CC = (1 << 20),
             OP2_OFSREG = (1 << 25),
             DT_UP = (1 << 23),
             DT_BYTE = (1 << 22),
             DT_WB = (1 << 21),
             // This flag is inlcuded in LDR and STR
             DT_PRE = (1 << 24),
+            // This flag makes switches the instruction between {ld,st}r{,s}h and {ld,st}rsb
             HDT_UH = (1 << 5),
+            // if this bit is on, we do a register offset, if it is off, we do an immediate offest.
+            HDT_IMM = (1 << 22), 
+            // Differentiates half word load/store between signed and unsigned (also enables signed byte loads.)
+            HDT_S = (1 << 6),
             DT_LOAD = (1 << 20)
         };
 
         // Masks of ARM instructions
         enum {
             BRANCH_MASK = 0x00ffffff,
             NONARM = 0xf0000000,
             SDT_MASK = 0x0c000000,
@@ -518,86 +519,17 @@ namespace JSC {
 
         void mull_r(int rdhi, int rdlo, int rn, int rm, Condition cc = AL)
         {
             js::JaegerSpew(js::JSpew_Insns,
                     IPFX   "%-15s %s, %s, %s, %s\n", MAYBE_PAD, "mull", nameGpReg(rdlo), nameGpReg(rdhi), nameGpReg(rn), nameGpReg(rm));
             m_buffer.putInt(static_cast<ARMWord>(cc) | MULL | RN(rdhi) | RD(rdlo) | RS(rn) | RM(rm));
         }
 
-        void fcpyd_r(int dd, int dm, Condition cc = AL)
-        {
-            js::JaegerSpew(js::JSpew_Insns,
-                    IPFX   "%-15s %s, %s, %s\n", MAYBE_PAD, "vmov.f64", nameFpRegD(dd), nameFpRegD(dm));
-            // TODO: emitInst doesn't work for VFP instructions, though it
-            // seems to work for current usage.
-            emitInst(static_cast<ARMWord>(cc) | FCPYD, dd, dd, dm);
-        }
-
-        void faddd_r(int dd, int dn, int dm, Condition cc = AL)
-        {
-            js::JaegerSpew(js::JSpew_Insns,
-                    IPFX   "%-15s %s, %s, %s\n", MAYBE_PAD, "vadd.f64", nameFpRegD(dd), nameFpRegD(dn), nameFpRegD(dm));
-            // TODO: emitInst doesn't work for VFP instructions, though it
-            // seems to work for current usage.
-            emitInst(static_cast<ARMWord>(cc) | FADDD, dd, dn, dm);
-        }
-
-        void fnegd_r(int dd, int dm, Condition cc = AL)
-        {
-            js::JaegerSpew(js::JSpew_Insns,
-                    IPFX   "%-15s %s, %s, %s, %s\n", MAYBE_PAD, "fnegd", nameFpRegD(dd), nameFpRegD(dm));
-            m_buffer.putInt(static_cast<ARMWord>(cc) | FNEGD | DD(dd) | DM(dm));
-        }
-
-        void fdivd_r(int dd, int dn, int dm, Condition cc = AL)
-        {
-            js::JaegerSpew(js::JSpew_Insns,
-                    IPFX   "%-15s %s, %s, %s\n", MAYBE_PAD, "vdiv.f64", nameFpRegD(dd), nameFpRegD(dn), nameFpRegD(dm));
-            // TODO: emitInst doesn't work for VFP instructions, though it
-            // seems to work for current usage.
-            emitInst(static_cast<ARMWord>(cc) | FDIVD, dd, dn, dm);
-        }
-
-        void fsubd_r(int dd, int dn, int dm, Condition cc = AL)
-        {
-            js::JaegerSpew(js::JSpew_Insns,
-                    IPFX   "%-15s %s, %s, %s\n", MAYBE_PAD, "vsub.f64", nameFpRegD(dd), nameFpRegD(dn), nameFpRegD(dm));
-            // TODO: emitInst doesn't work for VFP instructions, though it
-            // seems to work for current usage.
-            emitInst(static_cast<ARMWord>(cc) | FSUBD, dd, dn, dm);
-        }
-
-        void fmuld_r(int dd, int dn, int dm, Condition cc = AL)
-        {
-            js::JaegerSpew(js::JSpew_Insns,
-                    IPFX   "%-15s %s, %s, %s\n", MAYBE_PAD, "vmul.f64", nameFpRegD(dd), nameFpRegD(dn), nameFpRegD(dm));
-            // TODO: emitInst doesn't work for VFP instructions, though it
-            // seems to work for current usage.
-            emitInst(static_cast<ARMWord>(cc) | FMULD, dd, dn, dm);
-        }
-
-        void fcmpd_r(int dd, int dm, Condition cc = AL)
-        {
-            js::JaegerSpew(js::JSpew_Insns,
-                    IPFX   "%-15s %s, %s\n", MAYBE_PAD, "vcmp.f64", nameFpRegD(dd), nameFpRegD(dm));
-            // TODO: emitInst doesn't work for VFP instructions, though it
-            // seems to work for current usage.
-            emitInst(static_cast<ARMWord>(cc) | FCMPD, dd, 0, dm);
-        }
-
-        void fsqrtd_r(int dd, int dm, Condition cc = AL)
-        {
-            js::JaegerSpew(js::JSpew_Insns,
-                    IPFX   "%-15s %s, %s\n", MAYBE_PAD, "vsqrt.f64", nameFpRegD(dd), nameFpRegD(dm));
-            // TODO: emitInst doesn't work for VFP instructions, though it
-            // seems to work for current usage.
-            emitInst(static_cast<ARMWord>(cc) | FSQRTD, dd, 0, dm);
-        }
-
+        // pc relative loads (useful for loading from pools).
         void ldr_imm(int rd, ARMWord imm, Condition cc = AL)
         {
             char mnemonic[16];
             snprintf(mnemonic, 16, "ldr%s", nameCC(cc));
             js::JaegerSpew(js::JSpew_Insns,
                     IPFX    "%-15s %s, =0x%x @ (%d) (reusable pool entry)\n", MAYBE_PAD, mnemonic, nameGpReg(rd), imm, static_cast<int32_t>(imm));
             m_buffer.putIntWithConstantInt(static_cast<ARMWord>(cc) | DTR | DT_LOAD | DT_UP | RN(ARMRegisters::pc) | RD(rd), imm, true);
         }
@@ -606,16 +538,97 @@ namespace JSC {
         {
             char mnemonic[16];
             snprintf(mnemonic, 16, "ldr%s", nameCC(cc));
             js::JaegerSpew(js::JSpew_Insns,
                     IPFX    "%-15s %s, =0x%x @ (%d)\n", MAYBE_PAD, mnemonic, nameGpReg(rd), imm, static_cast<int32_t>(imm));
             m_buffer.putIntWithConstantInt(static_cast<ARMWord>(cc) | DTR | DT_LOAD | DT_UP | RN(ARMRegisters::pc) | RD(rd), imm);
         }
 
+        void mem_imm_off(bool isLoad, bool isSigned, int size, bool posOffset,
+                         int rd, int rb, ARMWord offset, Condition cc = AL)
+        {
+            ASSERT(size == 8 || size == 16 || size == 32);
+            char const * mnemonic_act = (isLoad) ? ("ld") : ("st");
+            char const * mnemonic_sign = (isSigned) ? ("s") : ("");
+            
+            char const * mnemonic_size = NULL;
+            switch (size / 8) {
+            case 1:
+                mnemonic_size = "b";
+                break;
+            case 2:
+                mnemonic_size = "h";
+                break;
+            case 4:
+                mnemonic_size = "";
+                break;
+            }
+            char const * off_sign = (posOffset) ? ("+") : ("-");
+            js::JaegerSpew(js::JSpew_Insns, 
+                           IPFX "%sr%s%s, [%s, #%s%u]\n", 
+                           MAYBE_PAD, mnemonic_act, mnemonic_sign, mnemonic_size,
+                           nameGpReg(rd), nameGpReg(rb), off_sign, offset);
+            if (size == 32 || (size == 8 && !isSigned)) {
+                /* All (the one) 32 bit ops and the unsigned 8 bit ops use the original encoding.*/
+                emitInst(static_cast<ARMWord>(cc) | DTR |
+                         (isLoad ? DT_LOAD : 0) |
+                         (size == 8 ? DT_BYTE : 0) |
+                         (posOffset ? DT_UP : 0), rd, rb, offset);
+            } else {
+                /* All 16 bit ops and 8 bit unsigned use the newer encoding.*/
+                /*these instructions don't exist before ARMv4*/
+                ASSERT(WTF_ARM_ARCH_VERSION >= 4);
+                emitInst(static_cast<ARMWord>(cc) | DTRH | HDT_IMM | DT_PRE |
+                         (isLoad ? DT_LOAD : 0) |
+                         (size == 16 ? HDT_UH : 0) |
+                         (isSigned ? HDT_S : 0) |
+                         (posOffset ? DT_UP : 0), rd, rb, offset);
+            }
+        }
+
+        void mem_reg_off(bool isLoad, bool isSigned, int size, bool posOffset, int rd, int rb, int rm, Condition cc = AL)
+        {
+            char const * mnemonic_act = (isLoad) ? ("ld") : ("st");
+            char const * mnemonic_sign = (isSigned) ? ("s") : ("");
+
+            char const * mnemonic_size = NULL;
+            switch (size / 8) {
+            case 1:
+                mnemonic_size = "b";
+                break;
+            case 2:
+                mnemonic_size = "h";
+                break;
+            case 4:
+                mnemonic_size = "";
+                break;
+            }
+            char const * off_sign = (posOffset) ? ("+") : ("-");
+            js::JaegerSpew(js::JSpew_Insns, 
+                           IPFX "%sr%s%s, [%s, #%s%s]\n", MAYBE_PAD, mnemonic_act, mnemonic_sign, mnemonic_size,
+                           nameGpReg(rd), nameGpReg(rb), off_sign, nameGpReg(rm));
+            if (size == 32 || (size == 8 && !isSigned)) {
+                /* All (the one) 32 bit ops and the signed 8 bit ops use the original encoding.*/
+                emitInst(static_cast<ARMWord>(cc) | DTR |
+                         (isLoad ? DT_LOAD : 0) |
+                         (size == 8 ? DT_BYTE : 0) |
+                         (posOffset ? DT_UP : 0) |
+                         OP2_OFSREG, rd, rb, rm);
+            } else {
+                /* All 16 bit ops and 8 bit unsigned use the newer encoding.*/
+                ASSERT(WTF_ARM_ARCH_VERSION >= 4);
+                emitInst(static_cast<ARMWord>(cc) | DTRH | DT_PRE |
+                         (isLoad ? DT_LOAD : 0) |
+                         (size == 16 ? HDT_UH : 0) |
+                         (isSigned ? HDT_S : 0) |
+                         (posOffset ? DT_UP : 0), rd, rb, rm);
+            }
+        }
+
         // Data transfers like this:
         //  LDR rd, [rb, +offset]
         //  STR rd, [rb, +offset]
         void dtr_u(bool isLoad, int rd, int rb, ARMWord offset, Condition cc = AL)
         {
             char const * mnemonic = (isLoad) ? ("ldr") : ("str");
             js::JaegerSpew(js::JSpew_Insns,
                     IPFX   "%-15s %s, [%s, #+%u]\n", MAYBE_PAD, mnemonic, nameGpReg(rd), nameGpReg(rb), offset);
@@ -662,38 +675,62 @@ namespace JSC {
         {
             char const * mnemonic = (isLoad) ? ("ldrb") : ("strb");
             js::JaegerSpew(js::JSpew_Insns,
                     IPFX   "%-15s %s, [%s, #+%u]\n", MAYBE_PAD, mnemonic, nameGpReg(rd), nameGpReg(rb), offset);
             emitInst(static_cast<ARMWord>(cc) | DTR | DT_BYTE | (isLoad ? DT_LOAD : 0) | DT_UP, rd, rb, offset);
         }
 
         // Data transfers like this:
+        //  LDRSB rd, [rb, +offset]
+        //  STRSB rd, [rb, +offset]
+        void dtrsb_u(bool isLoad, int rd, int rb, ARMWord offset, Condition cc = AL)
+        {
+            char const * mnemonic = (isLoad) ? ("ldrsb") : ("strb");
+            js::JaegerSpew(js::JSpew_Insns,
+                    IPFX   "%-15s %s, [%s, #+%u]\n", MAYBE_PAD, mnemonic, nameGpReg(rd), nameGpReg(rb), offset);
+            emitInst(static_cast<ARMWord>(cc) | DTRH | HDT_S | (isLoad ? DT_LOAD : 0) | DT_UP, rd, rb, offset);
+        }
+
+        // Data transfers like this:
         //  LDRB rd, [rb, +rm]
         //  STRB rd, [rb, +rm]
         void dtrb_ur(bool isLoad, int rd, int rb, int rm, Condition cc = AL)
         {
             char const * mnemonic = (isLoad) ? ("ldrb") : ("strb");
             js::JaegerSpew(js::JSpew_Insns,
                     IPFX   "%-15s %s, [%s, +%s]\n", MAYBE_PAD, mnemonic, nameGpReg(rd), nameGpReg(rb), nameGpReg(rm));
             emitInst(static_cast<ARMWord>(cc) | DTR | DT_BYTE | (isLoad ? DT_LOAD : 0) | DT_UP | OP2_OFSREG, rd, rb, rm);
         }
 
         // Data transfers like this:
-        //  LDRB rd, [rb, -offset]
-        //  STRB rd, [rb, -offset]
+        //  LDRB rd, [rb, #-offset]
+        //  STRB rd, [rb, #-offset]
         void dtrb_d(bool isLoad, int rd, int rb, ARMWord offset, Condition cc = AL)
         {
             char const * mnemonic = (isLoad) ? ("ldrb") : ("strb");
             js::JaegerSpew(js::JSpew_Insns,
                     IPFX   "%-15s %s, [%s, #-%u]\n", MAYBE_PAD, mnemonic, nameGpReg(rd), nameGpReg(rb), offset);
             emitInst(static_cast<ARMWord>(cc) | DTR | DT_BYTE | (isLoad ? DT_LOAD : 0), rd, rb, offset);
         }
 
         // Data transfers like this:
+        //  LDRSB rd, [rb, #-offset]
+        //  STRSB rd, [rb, #-offset]
+        // TODO: this instruction does not exist on arm v4 and earlier
+        void dtrsb_d(bool isLoad, int rd, int rb, ARMWord offset, Condition cc = AL)
+        {
+            ASSERT(isLoad); /*can only do signed byte loads, not stores*/
+            char const * mnemonic = (isLoad) ? ("ldrsb") : ("strb");
+            js::JaegerSpew(js::JSpew_Insns,
+                    IPFX   "%-15s %s, [%s, #-%u]\n", MAYBE_PAD, mnemonic, nameGpReg(rd), nameGpReg(rb), offset);
+            emitInst(static_cast<ARMWord>(cc) | DTRH | HDT_S | (isLoad ? DT_LOAD : 0), rd, rb, offset);
+        }
+
+        // Data transfers like this:
         //  LDRB rd, [rb, -rm]
         //  STRB rd, [rb, -rm]
         void dtrb_dr(bool isLoad, int rd, int rb, int rm, Condition cc = AL)
         {
             char const * mnemonic = (isLoad) ? ("ldrb") : ("strb");
             js::JaegerSpew(js::JSpew_Insns,
                     IPFX   "%-15s %s, [%s, -%s]\n", MAYBE_PAD, mnemonic, nameGpReg(rd), nameGpReg(rb), nameGpReg(rm));
             emitInst(static_cast<ARMWord>(cc) | DTR | DT_BYTE | (isLoad ? DT_LOAD : 0) | OP2_OFSREG, rd, rb, rm);
@@ -715,41 +752,37 @@ namespace JSC {
 
         void ldrh_u(int rd, int rb, ARMWord offset, Condition cc = AL)
         {
             js::JaegerSpew(js::JSpew_Insns,
                     IPFX   "%-15s %s, [%s, #+%u]\n", MAYBE_PAD, "ldrh", nameGpReg(rd), nameGpReg(rb), offset);
             emitInst(static_cast<ARMWord>(cc) | LDRH | HDT_UH | DT_UP | DT_PRE, rd, rb, offset);
         }
 
+        void ldrsh_d(int rd, int rb, ARMWord offset, Condition cc = AL)
+        {
+            js::JaegerSpew(js::JSpew_Insns,
+                    IPFX   "%-15s %s, [%s, #-%u]\n", MAYBE_PAD, "ldrsh", nameGpReg(rd), nameGpReg(rb), offset);
+            emitInst(static_cast<ARMWord>(cc) | LDRH | HDT_UH | HDT_S | DT_PRE, rd, rb, offset); 
+       }
+
+        void ldrsh_u(int rd, int rb, ARMWord offset, Condition cc = AL)
+        {
+            js::JaegerSpew(js::JSpew_Insns,
+                    IPFX   "%-15s %s, [%s, #+%u]\n", MAYBE_PAD, "ldrsh", nameGpReg(rd), nameGpReg(rb), offset);
+            emitInst(static_cast<ARMWord>(cc) | LDRH | HDT_UH | HDT_S | DT_UP | DT_PRE, rd, rb, offset);
+        }
+
         void strh_r(int rb, int rm, int rd, Condition cc = AL)
         {
             js::JaegerSpew(js::JSpew_Insns,
                     IPFX   "%-15s %s, [%s, +%s]\n", MAYBE_PAD, "strh", nameGpReg(rd), nameGpReg(rb), nameGpReg(rm));
             emitInst(static_cast<ARMWord>(cc) | STRH | HDT_UH | DT_UP | DT_PRE, rd, rb, rm);
         }
 
-        void fdtr_u(bool isLoad, int dd, int rn, ARMWord offset, Condition cc = AL)
-        {
-            char const * ins = isLoad ? "vldr.f64" : "vstr.f64";
-            js::JaegerSpew(js::JSpew_Insns,
-                    IPFX   "%-15s %s, [%s, #+%u]\n", MAYBE_PAD, ins, nameFpRegD(dd), nameGpReg(rn), offset);
-            ASSERT(offset <= 0xff);
-            emitInst(static_cast<ARMWord>(cc) | FDTR | DT_UP | (isLoad ? DT_LOAD : 0), dd, rn, offset);
-        }
-
-        void fdtr_d(bool isLoad, int dd, int rn, ARMWord offset, Condition cc = AL)
-        {
-            char const * ins = isLoad ? "vldr.f64" : "vstr.f64";
-            js::JaegerSpew(js::JSpew_Insns,
-                    IPFX   "%-15s %s, [%s, #-%u]\n", MAYBE_PAD, ins, nameFpRegD(dd), nameGpReg(rn), offset);
-            ASSERT(offset <= 0xff);
-            emitInst(static_cast<ARMWord>(cc) | FDTR | (isLoad ? DT_LOAD : 0), dd, rn, offset);
-        }
-
         void push_r(int reg, Condition cc = AL)
         {
             js::JaegerSpew(js::JSpew_Insns,
                     IPFX   "%-15s {%s}\n", MAYBE_PAD, "push", nameGpReg(reg));
             ASSERT(ARMWord(reg) <= 0xf);
             m_buffer.putInt(cc | DTR | DT_WB | RN(ARMRegisters::sp) | RD(reg) | 0x4);
         }
 
@@ -766,57 +799,17 @@ namespace JSC {
             dtr_d(false, ARMRegisters::sp, 0, reg, cc);
         }
 
         inline void peek_r(int reg, Condition cc = AL)
         {
             dtr_u(true, reg, ARMRegisters::sp, 0, cc);
         }
 
-        void fmsr_r(int dd, int rn, Condition cc = AL)
-        {
-            // TODO: emitInst doesn't work for VFP instructions, though it
-            // seems to work for current usage.
-            emitInst(static_cast<ARMWord>(cc) | FMSR, rn, dd, 0);
-        }
 
-        void fmrs_r(int rd, int dn, Condition cc = AL)
-        {
-            // TODO: emitInst doesn't work for VFP instructions, though it
-            // seems to work for current usage.
-            emitInst(static_cast<ARMWord>(cc) | FMRS, rd, dn, 0);
-        }
-
-        void fsitod_r(int dd, int dm, Condition cc = AL)
-        {
-            // TODO: emitInst doesn't work for VFP instructions, though it
-            // seems to work for current usage.
-            emitInst(static_cast<ARMWord>(cc) | FSITOD, dd, 0, dm);
-        }
-
-        void ftosid_r(int fd, int dm, Condition cc = AL)
-        {
-            // TODO: emitInst doesn't work for VFP instructions, though it
-            // seems to work for current usage.
-            emitInst(static_cast<ARMWord>(cc) | FTOSID, fd, 0, dm);
-        }
-
-        void ftosizd_r(int fd, int dm, Condition cc = AL)
-        {
-            // TODO: emitInst doesn't work for VFP instructions, though it
-            // seems to work for current usage.
-            emitInst(static_cast<ARMWord>(cc) | FTOSIZD, fd, 0, dm);
-        }
-
-        void fmstat(Condition cc = AL)
-        {
-            // TODO: emitInst doesn't work for VFP instructions, though it
-            // seems to work for current usage.
-            m_buffer.putInt(static_cast<ARMWord>(cc) | FMSTAT);
-        }
 
 #if WTF_ARM_ARCH_VERSION >= 5
         void clz_r(int rd, int rm, Condition cc = AL)
         {
             spewInsWithOp2("clz", cc, rd, static_cast<ARMWord>(rm));
             m_buffer.putInt(static_cast<ARMWord>(cc) | CLZ | RD(rd) | RM(rm));
         }
 #endif
@@ -1188,32 +1181,38 @@ namespace JSC {
             // Encode immediate data in the instruction if it is possible
             if (imm <= 0xff)
                 return getOp2Byte(imm);
             // Otherwise, store the data in a temporary register
             return encodeComplexImm(imm, tmpReg);
         }
 
         // Memory load/store helpers
+        void dataTransferN(bool isLoad, bool isSigned, int size, RegisterID srcDst, RegisterID base, int32_t offset);
 
         void dataTransfer32(bool isLoad, RegisterID srcDst, RegisterID base, int32_t offset);
-        void dataTransfer8(bool isLoad, RegisterID srcDst, RegisterID base, int32_t offset);
+        void dataTransfer8(bool isLoad, RegisterID srcDst, RegisterID base, int32_t offset, bool isSigned);
+        void baseIndexTransferN(bool isLoad, bool isSigned, int size, RegisterID srcDst, RegisterID base, RegisterID index, int scale, int32_t offset);
         void baseIndexTransfer32(bool isLoad, RegisterID srcDst, RegisterID base, RegisterID index, int scale, int32_t offset);
         void doubleTransfer(bool isLoad, FPRegisterID srcDst, RegisterID base, int32_t offset);
-
+        void floatTransfer(bool isLoad, FPRegisterID srcDst, RegisterID base, int32_t offset);
+        /**/
+        void baseIndexFloatTransfer(bool isLoad, bool isDouble, FPRegisterID srcDst, RegisterID base, RegisterID index, int scale, int32_t offset);
+ 
         // Constant pool hnadlers
 
         static ARMWord placeConstantPoolBarrier(int offset)
         {
             offset = (offset - sizeof(ARMWord)) >> 2;
             ASSERT((offset <= BOFFSET_MAX && offset >= BOFFSET_MIN));
             return AL | B | (offset & BRANCH_MASK);
         }
 
     private:
+        // pretty-printing functions
         static char const * nameGpReg(int reg)
         {
             ASSERT(reg <= 16);
             ASSERT(reg >= 0);
             static char const * names[] = {
                 "r0", "r1", "r2", "r3",
                 "r4", "r5", "r6", "r7",
                 "r8", "r9", "r10", "r11",
@@ -1233,16 +1232,32 @@ namespace JSC {
                 "d12",  "d13",  "d14",  "d15",
                 "d16",  "d17",  "d18",  "d19",
                 "d20",  "d21",  "d22",  "d23",
                 "d24",  "d25",  "d26",  "d27",
                 "d28",  "d29",  "d30",  "d31"
             };
             return names[reg];
         }
+        static char const * nameFpRegS(int reg)
+        {
+            ASSERT(reg <= 31);
+            ASSERT(reg >= 0);
+            static char const * names[] = {
+                 "s0",   "s1",   "s2",   "s3",
+                 "s4",   "s5",   "s6",   "s7",
+                 "s8",   "s9",  "s10",  "s11",
+                "s12",  "s13",  "s14",  "s15",
+                "s16",  "s17",  "s18",  "s19",
+                "s20",  "s21",  "s22",  "s23",
+                "s24",  "s25",  "s26",  "s27",
+                "s28",  "s29",  "s30",  "s31"
+            };
+            return names[reg];
+        }
 
         static char const * nameCC(Condition cc)
         {
             ASSERT(cc <= AL);
             ASSERT(cc >= 0);
             ASSERT((cc & 0x0fffffff) == 0);
 
             uint32_t    ccIndex = cc >> 28;
@@ -1395,24 +1410,320 @@ namespace JSC {
 
         ARMWord DM(int reg)
         {
             ASSERT(reg <= ARMRegisters::d31);
             // Encoded as bits [5,3:0].
             return ((reg << 1) & 0x20) | (reg & 0xf);
         }
 
+        ARMWord SD(int reg)
+        {
+            ASSERT(reg <= ARMRegisters::d31);
+            // Endoded as bits [15:12,22].
+            return ((reg << 11) | (reg << 22)) & 0x0040f000;
+        }
+
+        ARMWord SM(int reg)
+        {
+            ASSERT(reg <= ARMRegisters::d31);
+            // Encoded as bits [5,3:0].
+            return ((reg << 5) & 0x20) | ((reg >> 1) & 0xf);
+        }
+
         static ARMWord getConditionalField(ARMWord i)
         {
             return i & 0xf0000000;
         }
 
         int genInt(int reg, ARMWord imm, bool positive);
 
         ARMBuffer m_buffer;
         Jumps m_jumps;
+    public:
+        // VFP instruction constants
+        enum {
+            VFP_DATA  = 0x0E000A00,
+            VFP_EXT   = 0x0C000A00,
+            VFP_XFER  = 0x0E000A08,
+            VFP_DXFER = 0x0C400A00,
+
+            VFP_DBL   = (1<<8),
+            
+            /*integer conversions*/
+            VFP_ICVT  = 0x00B80040,
+            VFP_FPCVT = 0x00B700C0,
+            
+            VFP_DTR   = 0x01000000,
+            VFP_MOV     = 0x00000010,
+
+            FCPYD = 0x0eb00b40,
+            FADDD = 0x0e300b00,
+            FNEGD = 0x0eb10b40,
+            FDIVD = 0x0e800b00,
+            FSUBD = 0x0e300b40,
+            FMULD = 0x0e200b00,
+            FCMPD = 0x0eb40b40,
+            FSQRTD = 0x0eb10bc0,
+            FMSR = 0x0e000a10,
+            FMRS = 0x0e100a10,
+            FSITOD = 0x0eb80bc0,
+            FUITOD = 0x0eb80b40,
+            FTOSID = 0x0ebd0b40,
+            FTOSIZD = 0x0ebd0bc0,
+            FMSTAT = 0x0ef1fa10,
+            FDTR = 0x0d000b00
+
+        };
+        enum RegType {
+            SIntReg32,
+            UIntReg32,
+            FloatReg32,
+            FloatReg64
+        };
+
+        const char * nameType(RegType t)
+        {
+            const char * const name[4] =
+                {"S32", "U32", "F32", "F64"};
+            return name[t];
+        }
+
+        const char * nameTypedReg(RegType t, int reg)
+        {
+            switch(t) {
+            case SIntReg32:
+            case UIntReg32:
+                return nameGpReg(reg);
+            case FloatReg32:
+                return nameFpRegS(reg);
+            case FloatReg64:
+                return nameFpRegD(reg);
+            }
+            return "";
+        }
+
+        bool isFloatType(RegType rt)
+        {
+            if (rt == FloatReg32 || rt == FloatReg64)
+                return true;
+            return false;
+        }
+
+        bool isIntType(RegType rt)
+        {
+            if (rt == FloatReg32 || rt == FloatReg64)
+                return false;
+            return true;
+        }
+
+        // ********************************************************************
+        // *                            VFP Code:
+        //*********************************************************************
+        /* this is horrible. There needs to be some sane way of distinguishing D from S from R*/
+        void emitVFPInst(ARMWord op, ARMWord rd, ARMWord rn, ARMWord op2)
+        {
+            m_buffer.putInt(op | rn | rd | op2);
+        }
+
+        // NOTE: offset is the actual value that is going to be encoded.  It is the offset in words, NOT in bytes.
+        void fmem_imm_off(bool isLoad, bool isDouble, bool isUp, int dest, int rn, ARMWord offset, Condition cc = AL)
+        {
+            char const * ins = isLoad ? "vldr.f" : "vstr.f";
+            js::JaegerSpew(js::JSpew_Insns,
+                           IPFX   "%s%d %s, [%s, #%s%u]\n", MAYBE_PAD, 
+                           ins, (isDouble ? 64 : 32), (isDouble ? nameFpRegD(dest) : nameFpRegS(dest)),
+                           nameGpReg(rn), (isUp ? "+" : "-"), offset);
+            ASSERT(offset <= 0xff);
+            emitVFPInst(static_cast<ARMWord>(cc) | 
+                        VFP_EXT | VFP_DTR | 
+                        (isDouble ? VFP_DBL : 0) |
+                        (isUp ? DT_UP : 0) | 
+                        (isLoad ? DT_LOAD : 0), isDouble ? DD(dest) : SD(dest), RN(rn), offset);
+            
+        }
+
+        // WARNING: even for an int -> float conversion, all registers used
+        // are VFP registers.
+        void vcvt(RegType srcType, RegType dstType, int src, int dest, Condition cc = AL)
+        {
+            ASSERT(srcType != dstType);
+            ASSERT(isFloatType(srcType) || isFloatType(dstType));
+
+            js::JaegerSpew(js::JSpew_Insns,
+                           IPFX   "vcvt.%s.%-15s, %s,%s\n", MAYBE_PAD, 
+                           nameType(dstType), nameType(srcType),
+                           nameTypedReg(dstType,dest), nameTypedReg(srcType,src));
+            
+            if (isFloatType(srcType) && isFloatType (dstType)) {
+                // doing a float -> float conversion
+                bool dblToFloat = srcType == FloatReg64;
+                emitVFPInst(static_cast<ARMWord>(cc) | VFP_DATA | VFP_FPCVT |
+                            (dblToFloat ? VFP_DBL : 0),
+                            dblToFloat ? SD(dest) : DD(dest),
+                            dblToFloat ? DM(src) : SM(src), 0);
+            } else {
+                JS_NOT_REACHED("Other conversions did not seem useful on 2011/08/04");
+            }
+        }
+
+        // does r2:r1 -> dn, dn -> r2:r1, r2:r1 -> s2:s1, etc.
+        void vmov64 (bool fromFP, bool isDbl, int r1, int r2, int rFP, Condition cc = AL)
+        {
+            if (fromFP) {
+                js::JaegerSpew(js::JSpew_Insns,
+                               IPFX   "%-15s %s, %s, %s\n", MAYBE_PAD, "vmov", 
+                               nameGpReg(r1), nameGpReg(r2), nameFpRegD(rFP));
+            } else {
+                js::JaegerSpew(js::JSpew_Insns,
+                               IPFX   "%-15s %s, %s, %s\n", MAYBE_PAD, "vmov",
+                               nameFpRegD(rFP), nameGpReg(r1), nameGpReg(r2));
+            }
+            emitVFPInst(static_cast<ARMWord>(cc) | VFP_DXFER | VFP_MOV |
+                        (fromFP ? DT_LOAD : 0) |
+                        (isDbl ? VFP_DBL : 0), RD(r1), RN(r2), isDbl ? DM(rFP) : SM(rFP));
+            
+        }
+
+        void fcpyd_r(int dd, int dm, Condition cc = AL)
+        {
+            js::JaegerSpew(js::JSpew_Insns,
+                    IPFX   "%-15s %s, %s, %s\n", MAYBE_PAD, "vmov.f64", 
+                           nameFpRegD(dd), nameFpRegD(dm));
+            // TODO: emitInst doesn't work for VFP instructions, though it
+            // seems to work for current usage.
+            emitInst(static_cast<ARMWord>(cc) | FCPYD, dd, dd, dm);
+        }
+
+        void faddd_r(int dd, int dn, int dm, Condition cc = AL)
+        {
+            js::JaegerSpew(js::JSpew_Insns,
+                    IPFX   "%-15s %s, %s, %s\n", MAYBE_PAD, "vadd.f64", nameFpRegD(dd), nameFpRegD(dn), nameFpRegD(dm));
+            // TODO: emitInst doesn't work for VFP instructions, though it
+            // seems to work for current usage.
+            emitInst(static_cast<ARMWord>(cc) | FADDD, dd, dn, dm);
+        }
+
+        void fnegd_r(int dd, int dm, Condition cc = AL)
+        {
+            js::JaegerSpew(js::JSpew_Insns,
+                    IPFX   "%-15s %s, %s, %s, %s\n", MAYBE_PAD, "fnegd", nameFpRegD(dd), nameFpRegD(dm));
+            m_buffer.putInt(static_cast<ARMWord>(cc) | FNEGD | DD(dd) | DM(dm));
+        }
+
+        void fdivd_r(int dd, int dn, int dm, Condition cc = AL)
+        {
+            js::JaegerSpew(js::JSpew_Insns,
+                    IPFX   "%-15s %s, %s, %s\n", MAYBE_PAD, "vdiv.f64", nameFpRegD(dd), nameFpRegD(dn), nameFpRegD(dm));
+            // TODO: emitInst doesn't work for VFP instructions, though it
+            // seems to work for current usage.
+            emitInst(static_cast<ARMWord>(cc) | FDIVD, dd, dn, dm);
+        }
+
+        void fsubd_r(int dd, int dn, int dm, Condition cc = AL)
+        {
+            js::JaegerSpew(js::JSpew_Insns,
+                    IPFX   "%-15s %s, %s, %s\n", MAYBE_PAD, "vsub.f64", nameFpRegD(dd), nameFpRegD(dn), nameFpRegD(dm));
+            // TODO: emitInst doesn't work for VFP instructions, though it
+            // seems to work for current usage.
+            emitInst(static_cast<ARMWord>(cc) | FSUBD, dd, dn, dm);
+        }
+
+        void fmuld_r(int dd, int dn, int dm, Condition cc = AL)
+        {
+            js::JaegerSpew(js::JSpew_Insns,
+                    IPFX   "%-15s %s, %s, %s\n", MAYBE_PAD, "vmul.f64", nameFpRegD(dd), nameFpRegD(dn), nameFpRegD(dm));
+            // TODO: emitInst doesn't work for VFP instructions, though it
+            // seems to work for current usage.
+            emitInst(static_cast<ARMWord>(cc) | FMULD, dd, dn, dm);
+        }
+
+        void fcmpd_r(int dd, int dm, Condition cc = AL)
+        {
+            js::JaegerSpew(js::JSpew_Insns,
+                    IPFX   "%-15s %s, %s\n", MAYBE_PAD, "vcmp.f64", nameFpRegD(dd), nameFpRegD(dm));
+            // TODO: emitInst doesn't work for VFP instructions, though it
+            // seems to work for current usage.
+            emitInst(static_cast<ARMWord>(cc) | FCMPD, dd, 0, dm);
+        }
+
+        void fsqrtd_r(int dd, int dm, Condition cc = AL)
+        {
+            js::JaegerSpew(js::JSpew_Insns,
+                    IPFX   "%-15s %s, %s\n", MAYBE_PAD, "vsqrt.f64", nameFpRegD(dd), nameFpRegD(dm));
+            // TODO: emitInst doesn't work for VFP instructions, though it
+            // seems to work for current usage.
+            emitInst(static_cast<ARMWord>(cc) | FSQRTD, dd, 0, dm);
+        }
+
+        void fdtr_u(bool isLoad, int dd, int rn, ARMWord offset, Condition cc = AL)
+        {
+            char const * ins = isLoad ? "vldr.f64" : "vstr.f64";
+            js::JaegerSpew(js::JSpew_Insns,
+                    IPFX   "%-15s %s, [%s, #+%u]\n", MAYBE_PAD, ins, nameFpRegD(dd), nameGpReg(rn), offset);
+            ASSERT(offset <= 0xff);
+            emitInst(static_cast<ARMWord>(cc) | FDTR | DT_UP | (isLoad ? DT_LOAD : 0), dd, rn, offset);
+        }
+
+        void fdtr_d(bool isLoad, int dd, int rn, ARMWord offset, Condition cc = AL)
+        {
+            char const * ins = isLoad ? "vldr.f64" : "vstr.f64";
+            js::JaegerSpew(js::JSpew_Insns,
+                    IPFX   "%-15s %s, [%s, #-%u]\n", MAYBE_PAD, ins, nameFpRegD(dd), nameGpReg(rn), offset);
+            ASSERT(offset <= 0xff);
+            emitInst(static_cast<ARMWord>(cc) | FDTR | (isLoad ? DT_LOAD : 0), dd, rn, offset);
+        }
+
+        void fmsr_r(int dd, int rn, Condition cc = AL)
+        {
+            // TODO: emitInst doesn't work for VFP instructions, though it
+            // seems to work for current usage.
+            emitInst(static_cast<ARMWord>(cc) | FMSR, rn, dd, 0);
+        }
+
+        void fmrs_r(int rd, int dn, Condition cc = AL)
+        {
+            // TODO: emitInst doesn't work for VFP instructions, though it
+            // seems to work for current usage.
+            emitInst(static_cast<ARMWord>(cc) | FMRS, rd, dn, 0);
+        }
+
+        void fsitod_r(int dd, int dm, Condition cc = AL)
+        {
+            // TODO: emitInst doesn't work for VFP instructions, though it
+            // seems to work for current usage.
+            emitInst(static_cast<ARMWord>(cc) | FSITOD, dd, 0, dm);
+        }
+
+        void fuitod_r(int dd, int dm, Condition cc = AL)
+        {
+            // TODO: emitInst doesn't work for VFP instructions, though it
+            // seems to work for current usage.
+            emitInst(static_cast<ARMWord>(cc) | FUITOD, dd, 0, dm);
+        }
+
+        void ftosid_r(int fd, int dm, Condition cc = AL)
+        {
+            // TODO: emitInst doesn't work for VFP instructions, though it
+            // seems to work for current usage.
+            emitInst(static_cast<ARMWord>(cc) | FTOSID, fd, 0, dm);
+        }
+
+        void ftosizd_r(int fd, int dm, Condition cc = AL)
+        {
+            // TODO: emitInst doesn't work for VFP instructions, though it
+            // seems to work for current usage.
+            emitInst(static_cast<ARMWord>(cc) | FTOSIZD, fd, 0, dm);
+        }
+
+        void fmstat(Condition cc = AL)
+        {
+            // TODO: emitInst doesn't work for VFP instructions, though it
+            // seems to work for current usage.
+            m_buffer.putInt(static_cast<ARMWord>(cc) | FMSTAT);
+        }
     };
 
 } // namespace JSC
 
 #endif // ENABLE(ASSEMBLER) && CPU(ARM_TRADITIONAL)
 
 #endif // ARMAssembler_h
--- a/js/src/assembler/assembler/MacroAssemblerARM.h
+++ b/js/src/assembler/assembler/MacroAssemblerARM.h
@@ -246,19 +246,62 @@ public:
     }
 
     void xor32(Address src, RegisterID dest)
     {
         load32(src, ARMRegisters::S1);
         m_assembler.eors_r(dest, dest, ARMRegisters::S1);
     }
 
+    void load8SignExtend(ImplicitAddress address, RegisterID dest)
+    {
+        m_assembler.dataTransferN(true, true, 8, dest, address.base, address.offset);
+    } 
+
+    void load8ZeroExtend(ImplicitAddress address, RegisterID dest)
+    {
+        m_assembler.dataTransferN(true, false, 8, dest, address.base, address.offset);
+    }
+
+    void load8SignExtend(BaseIndex address, RegisterID dest)
+    {
+        m_assembler.baseIndexTransferN(true, true, 8, dest,
+                                       address.base, address.index, address.scale, address.offset);
+    }
+
+    void load8ZeroExtend(BaseIndex address, RegisterID dest)
+    {
+        m_assembler.baseIndexTransferN(true, false, 8, dest,
+                                       address.base, address.index, address.scale, address.offset);
+    }
+
+    /* this is *identical* to the zero extending case*/
     void load8(ImplicitAddress address, RegisterID dest)
     {
-        m_assembler.dataTransfer8(true, dest, address.base, address.offset);
+        load8ZeroExtend(address, dest);
+    }
+   
+    void load16SignExtend(ImplicitAddress address, RegisterID dest)
+    {
+        m_assembler.dataTransferN(true, true, 16, dest, address.base, address.offset);
+    } 
+
+    void load16ZeroExtend(ImplicitAddress address, RegisterID dest)
+    {
+        m_assembler.dataTransferN(true, false, 16, dest, address.base, address.offset);
+    }
+    void load16SignExtend(BaseIndex address, RegisterID dest)
+    {
+        m_assembler.baseIndexTransferN(true, true, 16, dest,
+                                       address.base, address.index, address.scale, address.offset);
+    }
+    void load16ZeroExtend(BaseIndex address, RegisterID dest)
+    {
+        m_assembler.baseIndexTransferN(true, false, 16, dest,
+                                       address.base, address.index, address.scale, address.offset);
     }
 
     void load32(ImplicitAddress address, RegisterID dest)
     {
         m_assembler.dataTransfer32(true, dest, address.base, address.offset);
     }
 
     void load32(BaseIndex address, RegisterID dest)
@@ -409,16 +452,102 @@ public:
         m_assembler.ldr_un_imm(ARMRegisters::S0, reinterpret_cast<ARMWord>(address));
         if (imm.m_isPointer)
             m_assembler.ldr_un_imm(ARMRegisters::S1, imm.m_value);
         else
             m_assembler.moveImm(imm.m_value, ARMRegisters::S1);
         m_assembler.dtr_u(false, ARMRegisters::S1, ARMRegisters::S0, 0);
     }
 
+    void store16(RegisterID src, ImplicitAddress address)
+    {
+        m_assembler.dataTransferN(false, false, 16,  src, address.base, address.offset);
+    }
+    void store16(RegisterID src, BaseIndex address)
+    {
+        m_assembler.baseIndexTransferN(false, false, 16, src, address.base, address.index, static_cast<int>(address.scale), address.offset);
+    }
+
+    void store16(TrustedImm32 imm, BaseIndex address)
+    {
+        if (imm.m_isPointer)
+            JS_ASSERT("What are you trying to do with 16 bits of a pointer?");
+        else
+            move(imm, ARMRegisters::S1);
+        store16(ARMRegisters::S1, address);
+    }
+    void store16(TrustedImm32 imm, ImplicitAddress address)
+    {
+        if (imm.m_isPointer)
+            JS_ASSERT("What are you trying to do with 16 bits of a pointer?");
+        else
+            move(imm, ARMRegisters::S1);
+        store16(ARMRegisters::S1, address);
+    }
+
+    void store16(RegisterID src, void* address)
+    {
+        m_assembler.ldr_un_imm(ARMRegisters::S0, reinterpret_cast<ARMWord>(address));
+        m_assembler.mem_imm_off(false, false, 16, true, src, ARMRegisters::S0, 0);
+    }
+
+    void store16(TrustedImm32 imm, void* address)
+    {
+        m_assembler.ldr_un_imm(ARMRegisters::S0, reinterpret_cast<ARMWord>(address));
+        if (imm.m_isPointer)
+            JS_ASSERT("What are you trying to do with 16 bits of a pointer?");
+        else
+            m_assembler.moveImm(imm.m_value, ARMRegisters::S1);
+        m_assembler.mem_imm_off(false, false, 16, true, ARMRegisters::S1, ARMRegisters::S0, 0);
+    }
+
+    void store8(RegisterID src, ImplicitAddress address)
+    {
+        m_assembler.dataTransferN(false, false, 16,  src, address.base, address.offset);
+    }
+
+    void store8(RegisterID src, BaseIndex address)
+    {
+        m_assembler.baseIndexTransferN(false, false, 8, src, address.base, address.index, static_cast<int>(address.scale), address.offset);
+    }
+
+    void store8(TrustedImm32 imm, BaseIndex address)
+    {
+        if (imm.m_isPointer)
+            JS_ASSERT("What are you trying to do with 8 bits of a pointer?");
+        else
+            move(imm, ARMRegisters::S1);
+        store8(ARMRegisters::S1, address);
+    }
+
+    void store8(TrustedImm32 imm, ImplicitAddress address)
+    {
+        if (imm.m_isPointer)
+            JS_ASSERT("What are you trying to do with 16 bits of a pointer?");
+        else
+            move(imm, ARMRegisters::S1);
+        store8(ARMRegisters::S1, address);
+    }
+
+    void store8(RegisterID src, void* address)
+    {
+        m_assembler.ldr_un_imm(ARMRegisters::S0, reinterpret_cast<ARMWord>(address));
+        m_assembler.mem_imm_off(false, false, 8, true, src, ARMRegisters::S0, 0);
+    }
+
+    void store8(TrustedImm32 imm, void* address)
+    {
+        m_assembler.ldr_un_imm(ARMRegisters::S0, reinterpret_cast<ARMWord>(address));
+        if (imm.m_isPointer)
+            JS_ASSERT("What are you trying to do with 16 bits of a pointer?");
+        else
+            m_assembler.moveImm(imm.m_value, ARMRegisters::S1);
+        m_assembler.mem_imm_off(false, false, 8, true, ARMRegisters::S1, ARMRegisters::S0, 0);
+    }
+
     void pop(RegisterID dest)
     {
         m_assembler.pop_r(dest);
     }
 
     void push(RegisterID src)
     {
         m_assembler.push_r(src);
@@ -541,16 +670,17 @@ public:
         ASSERT(left.base != ARMRegisters::S1);
         load32(left, ARMRegisters::S1);
         dataLabel = moveWithPatch(right, ARMRegisters::S0);
         return branch32(cond, ARMRegisters::S1, ARMRegisters::S0, true);
     }
 
     Jump branch32(Condition cond, RegisterID left, Address right)
     {
+        /*If the load only takes a single instruction, then we could just do a load into*/
         load32(right, ARMRegisters::S1);
         return branch32(cond, left, ARMRegisters::S1);
     }
 
     Jump branch32(Condition cond, Address left, RegisterID right)
     {
         load32(left, ARMRegisters::S1);
         return branch32(cond, ARMRegisters::S1, right);
@@ -992,28 +1122,118 @@ public:
         m_assembler.fcpyd_r(dest, src);
     }
 
     void loadDouble(ImplicitAddress address, FPRegisterID dest)
     {
         m_assembler.doubleTransfer(true, dest, address.base, address.offset);
     }
 
+    void loadDouble(BaseIndex address, FPRegisterID dest)
+    {
+        m_assembler.baseIndexFloatTransfer(true, true, dest,
+                                           address.base, address.index,
+                                           address.scale, address.offset);
+    }
+
     DataLabelPtr loadDouble(const void* address, FPRegisterID dest)
     {
         DataLabelPtr label = moveWithPatch(ImmPtr(address), ARMRegisters::S0);
         m_assembler.fdtr_u(true, dest, ARMRegisters::S0, 0);
         return label;
     }
 
+    void fastLoadDouble(RegisterID lo, RegisterID hi, FPRegisterID fpReg) {
+        m_assembler.vmov64(false, true, lo, hi, fpReg);
+    }
+
+    void loadFloat(ImplicitAddress address, FPRegisterID dest)
+    {
+        // as long as this is a sane mapping, (*2) should just work
+        dest = (FPRegisterID) (dest * 2);
+        ASSERT((address.offset & 0x3) == 0);
+        // address.offset is the offset in bytes, fmem_imm_off is expecting the offset in words.
+        m_assembler.fmem_imm_off(true, false, true, dest, address.base, address.offset >> 2);
+        m_assembler.vcvt(m_assembler.FloatReg32, m_assembler.FloatReg64, (FPRegisterID)(dest*2), dest);
+    }
+    void loadFloat(BaseIndex address, FPRegisterID dest)
+    {
+        m_assembler.baseIndexFloatTransfer(true, false, (FPRegisterID)(dest*2),
+                                           address.base, address.index,
+                                           address.scale, address.offset);
+        m_assembler.vcvt(m_assembler.FloatReg32, m_assembler.FloatReg64, (FPRegisterID)(dest*2), dest);
+    }
+
+    DataLabelPtr loadFloat(const void* address, FPRegisterID dest)
+    {
+        DataLabelPtr label = moveWithPatch(ImmPtr(address), ARMRegisters::S0);
+        m_assembler.fmem_imm_off(true, false, true, (FPRegisterID)(dest*2), ARMRegisters::S0, 0);
+        m_assembler.vcvt(m_assembler.FloatReg32, m_assembler.FloatReg64, (FPRegisterID)(dest*2), dest);
+        return label;
+    }
+ 
     void storeDouble(FPRegisterID src, ImplicitAddress address)
     {
         m_assembler.doubleTransfer(false, src, address.base, address.offset);
     }
 
+    void storeDouble(FPRegisterID dest, BaseIndex address)
+    {
+        m_assembler.baseIndexFloatTransfer(false, true, dest,
+                                           address.base, address.index,
+                                           address.scale, address.offset);
+    }
+
+    void storeDouble(ImmDouble imm, Address address)
+    {
+        store32(Imm32(imm.u.s.lsb), address);
+        store32(Imm32(imm.u.s.msb), Address(address.base, address.offset + 4));
+    }
+
+    void storeDouble(ImmDouble imm, BaseIndex address)
+    {
+        store32(Imm32(imm.u.s.lsb), address);
+        store32(Imm32(imm.u.s.msb),
+                BaseIndex(address.base, address.index, address.scale, address.offset + 4));
+    }
+    void fastStoreDouble(FPRegisterID fpReg, RegisterID lo, RegisterID hi) {
+        m_assembler.vmov64(true, true, lo, hi, fpReg);
+    }
+
+    void storeFloat(FPRegisterID src, ImplicitAddress address)
+    {
+        m_assembler.fmem_imm_off(false, false, true, src, address.base, address.offset);
+    }
+
+    void storeFloat(FPRegisterID src, BaseIndex address)
+    {
+        m_assembler.baseIndexFloatTransfer(false, false, src,
+                                           address.base, address.index,
+                                           address.scale, address.offset);
+    }
+    void storeFloat(ImmDouble imm, Address address)
+    {
+        union {
+            float f;
+            uint32 u32;
+        } u;
+        u.f = imm.u.d;
+        store32(Imm32(u.u32), address);
+    }
+
+    void storeFloat(ImmDouble imm, BaseIndex address)
+    {
+        union {
+            float f;
+            uint32 u32;
+        } u;
+        u.f = imm.u.d;
+        store32(Imm32(u.u32), address);
+    }
+
     void addDouble(FPRegisterID src, FPRegisterID dest)
     {
         m_assembler.faddd_r(dest, dest, src);
     }
 
     void addDouble(Address src, FPRegisterID dest)
     {
         loadDouble(src, ARMRegisters::SD0);
@@ -1065,32 +1285,43 @@ public:
     }
 
     void convertInt32ToDouble(RegisterID src, FPRegisterID dest)
     {
         m_assembler.fmsr_r(dest, src);
         m_assembler.fsitod_r(dest, dest);
     }
 
+    void convertUInt32ToDouble(RegisterID src, FPRegisterID dest)
+    {
+        m_assembler.fmsr_r(dest, src);
+        m_assembler.fuitod_r(dest, dest);
+    }
+
     void convertInt32ToDouble(Address src, FPRegisterID dest)
     {
         // flds does not worth the effort here
         load32(src, ARMRegisters::S1);
         convertInt32ToDouble(ARMRegisters::S1, dest);
     }
 
     void convertInt32ToDouble(AbsoluteAddress src, FPRegisterID dest)
     {
         ASSERT_NOT_REACHED(); // Untested
         // flds does not worth the effort here
         m_assembler.ldr_un_imm(ARMRegisters::S1, (ARMWord)src.m_ptr);
         m_assembler.dtr_u(true, ARMRegisters::S1, ARMRegisters::S1, 0);
         convertInt32ToDouble(ARMRegisters::S1, dest);
     }
 
+    void convertDoubleToFloat(FPRegisterID src, FPRegisterID dest)
+    {
+        m_assembler.vcvt(m_assembler.FloatReg64, m_assembler.FloatReg32, src, dest);
+    }
+
     Jump branchDouble(DoubleCondition cond, FPRegisterID left, FPRegisterID right)
     {
         m_assembler.fcmpd_r(left, right);
         m_assembler.fmstat();
         if (cond & DoubleConditionBitSpecial)
             m_assembler.cmp_r(ARMRegisters::S0, ARMRegisters::S0, ARMAssembler::VS);
         return Jump(m_assembler.jmp(static_cast<ARMAssembler::Condition>(cond & ~DoubleConditionMask)));
     }
--- a/js/src/configure.in
+++ b/js/src/configure.in
@@ -2776,16 +2776,17 @@ x86_64*-*)
     AC_DEFINE(JS_PUNBOX64)
     ;;
 arm*-*)
     ENABLE_TRACEJIT=1
     NANOJIT_ARCH=ARM
     ENABLE_METHODJIT=1
     ENABLE_MONOIC=1
     ENABLE_POLYIC=1
+    ENABLE_POLYIC_TYPED_ARRAY=1
     AC_DEFINE(JS_CPU_ARM)
     AC_DEFINE(JS_NUNBOX32)
     ;;
 sparc*-*)
     ENABLE_TRACEJIT=1
     NANOJIT_ARCH=Sparc
     ENABLE_METHODJIT=1
     ENABLE_MONOIC=1
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/basic/testBug676486.js
@@ -0,0 +1,10 @@
+var proxy = Proxy.createFunction(
+    {},
+    function() {
+        return (function () { eval("foo") })();
+    });
+
+try {
+    new proxy();
+} catch (e) {
+}
--- a/js/src/jsapi-tests/testDebugger.cpp
+++ b/js/src/jsapi-tests/testDebugger.cpp
@@ -98,8 +98,47 @@ BEGIN_TEST(testDebugger_getThisStrict)
          "strict.call(42);\n"
          "(42).strict();\n"
          "strict.call(undefined);\n"
          "strict.call(null);\n");
     CHECK(!anyWrapped);
     return true;
 }
 END_TEST(testDebugger_getThisStrict)
+
+bool called = false;
+
+static JSTrapStatus
+ThrowHook(JSContext *cx, JSScript *, jsbytecode *, jsval *rval, void *closure)
+{
+    called = true;
+
+    JSObject *global = JS_GetGlobalForScopeChain(cx);
+
+    char text[] = "new Error()";
+    jsval _;
+    JS_EvaluateScript(cx, global, text, strlen(text), "", 0, &_);
+
+    return JSTRAP_CONTINUE;
+}
+
+BEGIN_TEST(testDebugger_throwHook)
+{
+    uint32 newopts = JS_GetOptions(cx) | JSOPTION_METHODJIT | JSOPTION_METHODJIT_ALWAYS;
+    uint32 oldopts = JS_SetOptions(cx, newopts);
+
+    JSDebugHooks hooks = { 0 };
+    hooks.throwHook = ThrowHook;
+    JSDebugHooks *old = JS_SetContextDebugHooks(cx, &hooks);
+    EXEC("function foo() { throw 3 };\n"
+         "for (var i = 0; i < 10; ++i) { \n"
+         "  var x = <tag></tag>;\n"
+         "  try {\n"
+         "    foo(); \n"
+         "  } catch(e) {}\n"
+         "}\n");
+    CHECK(called);
+
+    JS_SetContextDebugHooks(cx, old);
+    JS_SetOptions(cx, oldopts);
+    return true;
+}
+END_TEST(testDebugger_throwHook)
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -3518,89 +3518,16 @@ JS_DefineProperties(JSContext *cx, JSObj
                             Valueify(ps->getter), Valueify(ps->setter),
                             ps->flags, Shape::HAS_SHORTID, ps->tinyid);
         if (!ok)
             break;
     }
     return ok;
 }
 
-JS_PUBLIC_API(JSBool)
-JS_AliasProperty(JSContext *cx, JSObject *obj, const char *name, const char *alias)
-{
-    JSObject *obj2;
-    JSProperty *prop;
-    JSBool ok;
-    Shape *shape;
-
-    CHECK_REQUEST(cx);
-    assertSameCompartment(cx, obj);
-
-    JSAtom *atom = js_Atomize(cx, name, strlen(name));
-    if (!atom)
-        return JS_FALSE;
-    if (!LookupPropertyById(cx, obj, ATOM_TO_JSID(atom), JSRESOLVE_QUALIFIED, &obj2, &prop))
-        return JS_FALSE;
-    if (!prop) {
-        js_ReportIsNotDefined(cx, name);
-        return JS_FALSE;
-    }
-    if (obj2 != obj || !obj->isNative()) {
-        JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_ALIAS,
-                             alias, name, obj2->getClass()->name);
-        return JS_FALSE;
-    }
-    atom = js_Atomize(cx, alias, strlen(alias));
-    if (!atom) {
-        ok = JS_FALSE;
-    } else {
-        shape = (Shape *)prop;
-        ok = (js_AddNativeProperty(cx, obj, ATOM_TO_JSID(atom),
-                                   shape->getter(), shape->setter(), shape->slot,
-                                   shape->attributes(), shape->getFlags() | Shape::ALIAS,
-                                   shape->shortid)
-              != NULL);
-    }
-    return ok;
-}
-
-JS_PUBLIC_API(JSBool)
-JS_AliasElement(JSContext *cx, JSObject *obj, const char *name, jsint alias)
-{
-    JSObject *obj2;
-    JSProperty *prop;
-    Shape *shape;
-
-    CHECK_REQUEST(cx);
-    assertSameCompartment(cx, obj);
-
-    JSAtom *atom = js_Atomize(cx, name, strlen(name));
-    if (!atom)
-        return JS_FALSE;
-    if (!LookupPropertyById(cx, obj, ATOM_TO_JSID(atom), JSRESOLVE_QUALIFIED, &obj2, &prop))
-        return JS_FALSE;
-    if (!prop) {
-        js_ReportIsNotDefined(cx, name);
-        return JS_FALSE;
-    }
-    if (obj2 != obj || !obj->isNative()) {
-        char numBuf[12];
-        JS_snprintf(numBuf, sizeof numBuf, "%ld", (long)alias);
-        JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_ALIAS,
-                             numBuf, name, obj2->getClass()->name);
-        return JS_FALSE;
-    }
-    shape = (Shape *)prop;
-    return js_AddNativeProperty(cx, obj, INT_TO_JSID(alias),
-                                shape->getter(), shape->setter(), shape->slot,
-                                shape->attributes(), shape->getFlags() | Shape::ALIAS,
-                                shape->shortid)
-           != NULL;
-}
-
 static JSBool
 GetPropertyDescriptorById(JSContext *cx, JSObject *obj, jsid id, uintN flags,
                           JSBool own, PropertyDescriptor *desc)
 {
     JSObject *obj2;
     JSProperty *prop;
 
     if (!LookupPropertyById(cx, obj, id, flags, &obj2, &prop))
@@ -4039,17 +3966,17 @@ JS_NextProperty(JSContext *cx, JSObject 
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, iterobj);
     i = iterobj->getSlot(JSSLOT_ITER_INDEX).toInt32();
     if (i < 0) {
         /* Native case: private data is a property tree node pointer. */
         JS_ASSERT(iterobj->getParent()->isNative());
         shape = (Shape *) iterobj->getPrivate();
 
-        while (shape->previous() && (!shape->enumerable() || shape->isAlias()))
+        while (shape->previous() && !shape->enumerable())
             shape = shape->previous();
 
         if (!shape->previous()) {
             JS_ASSERT(JSID_IS_EMPTY(shape->propid));
             *idp = JSID_VOID;
         } else {
             iterobj->setPrivate(const_cast<Shape *>(shape->previous()));
             *idp = shape->propid;
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -2304,20 +2304,16 @@ JS_SetPropertyAttributes(JSContext *cx, 
 
 extern JS_PUBLIC_API(JSBool)
 JS_DefinePropertyWithTinyId(JSContext *cx, JSObject *obj, const char *name,
                             int8 tinyid, jsval value,
                             JSPropertyOp getter, JSStrictPropertyOp setter,
                             uintN attrs);
 
 extern JS_PUBLIC_API(JSBool)
-JS_AliasProperty(JSContext *cx, JSObject *obj, const char *name,
-                 const char *alias);
-
-extern JS_PUBLIC_API(JSBool)
 JS_AlreadyHasOwnProperty(JSContext *cx, JSObject *obj, const char *name,
                          JSBool *foundp);
 
 extern JS_PUBLIC_API(JSBool)
 JS_AlreadyHasOwnPropertyById(JSContext *cx, JSObject *obj, jsid id,
                              JSBool *foundp);
 
 extern JS_PUBLIC_API(JSBool)
@@ -2489,19 +2485,16 @@ JS_GetArrayLength(JSContext *cx, JSObjec
 extern JS_PUBLIC_API(JSBool)
 JS_SetArrayLength(JSContext *cx, JSObject *obj, jsuint length);
 
 extern JS_PUBLIC_API(JSBool)
 JS_DefineElement(JSContext *cx, JSObject *obj, jsint index, jsval value,
                  JSPropertyOp getter, JSStrictPropertyOp setter, uintN attrs);
 
 extern JS_PUBLIC_API(JSBool)
-JS_AliasElement(JSContext *cx, JSObject *obj, const char *name, jsint alias);
-
-extern JS_PUBLIC_API(JSBool)
 JS_AlreadyHasOwnElement(JSContext *cx, JSObject *obj, jsint index,
                         JSBool *foundp);
 
 extern JS_PUBLIC_API(JSBool)
 JS_HasElement(JSContext *cx, JSObject *obj, jsint index, JSBool *foundp);
 
 extern JS_PUBLIC_API(JSBool)
 JS_LookupElement(JSContext *cx, JSObject *obj, jsint index, jsval *vp);
--- a/js/src/jsarray.cpp
+++ b/js/src/jsarray.cpp
@@ -115,75 +115,23 @@
 #include "jsstrinlines.h"
 
 #include "vm/ArgumentsObject-inl.h"
 #include "vm/Stack-inl.h"
 
 using namespace js;
 using namespace js::gc;
 
-/* 2^32 - 1 as a number and a string */
-#define MAXINDEX 4294967295u
-#define MAXSTR   "4294967295"
-
 static inline bool
 ENSURE_SLOW_ARRAY(JSContext *cx, JSObject *obj)
 {
     return obj->getClass() == &js_SlowArrayClass ||
            obj->makeDenseArraySlow(cx);
 }
 
-/*
- * Determine if the id represents an array index or an XML property index.
- *
- * An id is an array index according to ECMA by (15.4):
- *
- * "Array objects give special treatment to a certain class of property names.
- * A property name P (in the form of a string value) is an array index if and
- * only if ToString(ToUint32(P)) is equal to P and ToUint32(P) is not equal
- * to 2^32-1."
- *
- * In our implementation, it would be sufficient to check for JSVAL_IS_INT(id)
- * except that by using signed 31-bit integers we miss the top half of the
- * valid range. This function checks the string representation itself; note
- * that calling a standard conversion routine might allow strings such as
- * "08" or "4.0" as array indices, which they are not.
- *
- * 'id' is passed as a jsboxedword since the given id need not necessarily hold
- * an atomized string.
- */
-bool
-js_StringIsIndex(JSLinearString *str, jsuint *indexp)
-{
-    const jschar *cp = str->chars();
-    if (JS7_ISDEC(*cp) && str->length() < sizeof(MAXSTR)) {
-        jsuint index = JS7_UNDEC(*cp++);
-        jsuint oldIndex = 0;
-        jsuint c = 0;
-        if (index != 0) {
-            while (JS7_ISDEC(*cp)) {
-                oldIndex = index;
-                c = JS7_UNDEC(*cp);
-                index = 10*index + c;
-                cp++;
-            }
-        }
-
-        /* Ensure that all characters were consumed and we didn't overflow. */
-        if (*cp == 0 &&
-             (oldIndex < (MAXINDEX / 10) ||
-              (oldIndex == (MAXINDEX / 10) && c < (MAXINDEX % 10))))
-        {
-            *indexp = index;
-            return true;
-        }
-    }
-    return false;
-}
-
 JSBool
 js_GetLengthProperty(JSContext *cx, JSObject *obj, jsuint *lengthp)
 {
     if (obj->isArray()) {
         *lengthp = obj->getArrayLength();
         return true;
     }
 
@@ -203,16 +151,76 @@ js_GetLengthProperty(JSContext *cx, JSOb
         *lengthp = jsuint(jsint(tvr.value().toInt32())); /* jsuint cast does ToUint32 */
         return true;
     }
 
     JS_STATIC_ASSERT(sizeof(jsuint) == sizeof(uint32_t));
     return ValueToECMAUint32(cx, tvr.value(), (uint32_t *)lengthp);
 }
 
+namespace js {
+
+/*
+ * Determine if the id represents an array index or an XML property index.
+ *
+ * An id is an array index according to ECMA by (15.4):
+ *
+ * "Array objects give special treatment to a certain class of property names.
+ * A property name P (in the form of a string value) is an array index if and
+ * only if ToString(ToUint32(P)) is equal to P and ToUint32(P) is not equal
+ * to 2^32-1."
+ *
+ * This means the largest allowed index is actually 2^32-2 (4294967294).  
+ * 
+ * In our implementation, it would be sufficient to check for JSVAL_IS_INT(id)
+ * except that by using signed 31-bit integers we miss the top half of the
+ * valid range. This function checks the string representation itself; note
+ * that calling a standard conversion routine might allow strings such as
+ * "08" or "4.0" as array indices, which they are not.
+ *
+ */
+bool
+StringIsArrayIndex(JSLinearString *str, jsuint *indexp)
+{
+    const jschar *s = str->chars();
+    uint32 length = str->length();
+    const jschar *end = s + length;
+
+    if (length == 0 || length > (sizeof("4294967294") - 1) || !JS7_ISDEC(*s))
+        return false;
+
+    uint32 c = 0, previous = 0;    
+    uint32 index = JS7_UNDEC(*s++);
+
+    /* Don't allow leading zeros. */
+    if (index == 0 && s != end)
+        return false;
+
+    for (; s < end; s++) {
+        if (!JS7_ISDEC(*s))
+            return false;
+
+        previous = index;
+        c = JS7_UNDEC(*s);
+        index = 10 * index + c;
+    }
+
+    /* Make sure we didn't overflow. */
+    if (previous < (MAX_ARRAY_INDEX / 10) || (previous == (MAX_ARRAY_INDEX / 10) && 
+        c <= (MAX_ARRAY_INDEX % 10))) {
+        JS_ASSERT(index <= MAX_ARRAY_INDEX);
+        *indexp = index;
+        return true;
+    }
+    
+    return false;
+}
+
+}
+
 static JSBool
 BigIndexToId(JSContext *cx, JSObject *obj, jsuint index, JSBool createAtom,
              jsid *idp)
 {
     jschar buf[10], *start;
     Class *clasp;
     JSAtom *atom;
     JS_STATIC_ASSERT((jsuint)-1 == 4294967295U);
@@ -1368,17 +1376,17 @@ array_toLocaleString(JSContext *cx, uint
      *  locale-specific version.
      */
     return array_toString_sub(cx, obj, JS_TRUE, NULL, vp);
 }
 
 static JSBool
 InitArrayElements(JSContext *cx, JSObject *obj, jsuint start, jsuint count, Value *vector)
 {
-    JS_ASSERT(count < MAXINDEX);
+    JS_ASSERT(count <= MAX_ARRAY_INDEX);
 
     /*
      * Optimize for dense arrays so long as adding the given set of elements
      * wouldn't otherwise make the array slow.
      */
     do {
         if (!obj->isDenseArray())
             break;
@@ -1398,34 +1406,34 @@ InitArrayElements(JSContext *cx, JSObjec
 
         JS_ASSERT(count < uint32(-1) / sizeof(Value));
         obj->copyDenseArrayElements(start, vector, count);
         JS_ASSERT_IF(count != 0, !obj->getDenseArrayElement(newlen - 1).isMagic(JS_ARRAY_HOLE));
         return true;
     } while (false);
 
     Value* end = vector + count;
-    while (vector != end && start < MAXINDEX) {
+    while (vector != end && start <= MAX_ARRAY_INDEX) {
         if (!JS_CHECK_OPERATION_LIMIT(cx) ||
             !SetArrayElement(cx, obj, start++, *vector++)) {
             return JS_FALSE;
         }
     }
 
     if (vector == end)
         return JS_TRUE;
 
     /* Finish out any remaining elements past the max array index. */
     if (obj->isDenseArray() && !ENSURE_SLOW_ARRAY(cx, obj))
         return JS_FALSE;
 
-    JS_ASSERT(start == MAXINDEX);
+    JS_ASSERT(start == MAX_ARRAY_INDEX + 1);
     AutoValueRooter tvr(cx);
     AutoIdRooter idr(cx);
-    Value idval = DoubleValue(MAXINDEX);
+    Value idval = DoubleValue(MAX_ARRAY_INDEX + 1);
     do {
         *tvr.addr() = *vector++;
         if (!js_ValueToStringId(cx, idval, idr.addr()) ||
             !obj->setProperty(cx, idr.id(), tvr.addr(), true)) {
             return JS_FALSE;
         }
         idval.getDoubleRef() += 1;
     } while (vector != end);
--- a/js/src/jsarray.h
+++ b/js/src/jsarray.h
@@ -82,35 +82,41 @@ JSObject::ensureDenseArrayElements(JSCon
      */
     if (requiredCapacity > MIN_SPARSE_INDEX &&
         willBeSparseDenseArray(requiredCapacity, extra)) {
         return ED_SPARSE;
     }
     return growSlots(cx, requiredCapacity) ? ED_OK : ED_FAILED;
 }
 
+namespace js {
+/* 2^32-2, inclusive */
+const uint32 MAX_ARRAY_INDEX = 4294967294u;
+    
 extern bool
-js_StringIsIndex(JSLinearString *str, jsuint *indexp);
+StringIsArrayIndex(JSLinearString *str, jsuint *indexp);
+    
+}
 
 inline JSBool
 js_IdIsIndex(jsid id, jsuint *indexp)
 {
     if (JSID_IS_INT(id)) {
         jsint i;
         i = JSID_TO_INT(id);
         if (i < 0)
             return JS_FALSE;
         *indexp = (jsuint)i;
         return JS_TRUE;
     }
 
     if (JS_UNLIKELY(!JSID_IS_STRING(id)))
         return JS_FALSE;
 
-    return js_StringIsIndex(JSID_TO_ATOM(id), indexp);
+    return js::StringIsArrayIndex(JSID_TO_ATOM(id), indexp);
 }
 
 extern js::Class js_ArrayClass, js_SlowArrayClass;
 
 inline bool
 JSObject::isDenseArray() const
 {
     return getClass() == &js_ArrayClass;
--- a/js/src/jsatom.cpp
+++ b/js/src/jsatom.cpp
@@ -37,16 +37,19 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 /*
  * JS atom table.
  */
 #include <stdlib.h>
 #include <string.h>
+
+#include "mozilla/RangedPtr.h"
+
 #include "jstypes.h"
 #include "jsstdint.h"
 #include "jsutil.h"
 #include "jshash.h"
 #include "jsprf.h"
 #include "jsapi.h"
 #include "jsatom.h"
 #include "jsbit.h"
@@ -660,16 +663,37 @@ js_InitAtomMap(JSContext *cx, JSAtomMap 
             if (!atom)
                 continue;
             JS_ASSERT(it->value < map->length);
             map->vector[it->value] = atom;
         }
     }
 }
 
+namespace js {
+
+bool
+IndexToIdSlow(JSContext *cx, uint32 index, jsid *idp)
+{
+    JS_ASSERT(index > JSID_INT_MAX);
+
+    jschar buf[UINT32_CHAR_BUFFER_LENGTH];
+    RangedPtr<jschar> end(buf + JS_ARRAY_LENGTH(buf), buf, buf + JS_ARRAY_LENGTH(buf));
+    RangedPtr<jschar> start = BackfillIndexInCharBuffer(index, end);
+
+    JSAtom *atom = js_AtomizeChars(cx, start.get(), end - start);
+    if (!atom)
+        return false;
+
+    *idp = ATOM_TO_JSID(atom);
+    JS_ASSERT(js_CheckForStringIndex(*idp) == *idp);
+    return true;
+}
+
+} /* namespace js */
 
 /* JSBOXEDWORD_INT_MAX as a string */
 #define JSBOXEDWORD_INT_MAX_STRING "1073741823"
 
 /*
  * Convert string indexes that convert to int jsvals as ints to save memory.
  * Care must be taken to use this macro every time a property name is used, or
  * else double-sets, incorrect property cache misses, or other mistakes could
--- a/js/src/jsatominlines.h
+++ b/js/src/jsatominlines.h
@@ -35,16 +35,18 @@
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef jsatominlines_h___
 #define jsatominlines_h___
 
+#include "mozilla/RangedPtr.h"
+
 #include "jsatom.h"
 #include "jsnum.h"
 #include "jsobj.h"
 
 inline bool
 js_ValueToAtom(JSContext *cx, const js::Value &v, JSAtom **atomp)
 {
     if (!v.isString()) {
@@ -128,33 +130,57 @@ js_Int32ToId(JSContext* cx, int32 index,
     if (!str)
         return false;
 
     return js_ValueToStringId(cx, js::StringValue(str), id);
 }
 
 namespace js {
 
+static const size_t UINT32_CHAR_BUFFER_LENGTH = sizeof("4294967295") - 1;
+
+/*
+ * Write out character representing |index| to the memory just before |end|.
+ * Thus |*end| is not touched, but |end[-1]| and earlier are modified as
+ * appropriate.  There must be at least UINT32_CHAR_BUFFER_LENGTH elements
+ * before |end| to avoid buffer underflow.  The start of the characters written
+ * is returned and is necessarily before |end|.
+ */
+template <typename T>
+inline mozilla::RangedPtr<T>
+BackfillIndexInCharBuffer(uint32 index, mozilla::RangedPtr<T> end)
+{
+#ifdef DEBUG
+    /*
+     * Assert that the buffer we're filling will hold as many characters as we
+     * could write out, by dereferencing the index that would hold the most
+     * significant digit.
+     */
+    (void) *(end - UINT32_CHAR_BUFFER_LENGTH);
+#endif
+
+    do {
+        uint32 next = index / 10, digit = index % 10;
+        *--end = '0' + digit;
+        index = next;
+    } while (index > 0);
+
+    return end;
+}
+
 inline bool
 IndexToId(JSContext *cx, uint32 index, jsid *idp)
 {
     if (index <= JSID_INT_MAX) {
         *idp = INT_TO_JSID(index);
         return true;
     }
 
-    JSString *str = js_NumberToString(cx, index);
-    if (!str)
-        return false;
-
-    JSAtom *atom = js_AtomizeString(cx, str);
-    if (!atom)
-        return false;
-    *idp = ATOM_TO_JSID(atom);
-    return true;
+    extern bool IndexToIdSlow(JSContext *cx, uint32 index, jsid *idp);
+    return IndexToIdSlow(cx, index, idp);
 }
 
 static JS_ALWAYS_INLINE JSString *
 IdToString(JSContext *cx, jsid id)
 {
     if (JSID_IS_STRING(id))
         return JSID_TO_STRING(id);
     if (JS_LIKELY(JSID_IS_INT(id)))
--- a/js/src/jsclone.cpp
+++ b/js/src/jsclone.cpp
@@ -433,34 +433,34 @@ TagToArrayType(uint32_t tag)
 {
     JS_ASSERT(SCTAG_TYPED_ARRAY_MIN <= tag && tag <= SCTAG_TYPED_ARRAY_MAX);
     return tag - SCTAG_TYPED_ARRAY_MIN;
 }
 
 bool
 JSStructuredCloneWriter::writeTypedArray(JSObject *obj)
 {
-    TypedArray *arr = TypedArray::fromJSObject(obj);
-    if (!out.writePair(ArrayTypeToTag(arr->type), arr->length))
+    JSObject *arr = TypedArray::getTypedArray(obj);
+    if (!out.writePair(ArrayTypeToTag(TypedArray::getType(arr)), TypedArray::getLength(arr)))
         return false;
 
-    switch (arr->type) {
+    switch (TypedArray::getType(arr)) {
     case TypedArray::TYPE_INT8:
     case TypedArray::TYPE_UINT8:
     case TypedArray::TYPE_UINT8_CLAMPED:
-        return out.writeArray((const uint8_t *) arr->data, arr->length);
+        return out.writeArray((const uint8_t *) TypedArray::getDataOffset(arr), TypedArray::getLength(arr));
     case TypedArray::TYPE_INT16:
     case TypedArray::TYPE_UINT16:
-        return out.writeArray((const uint16_t *) arr->data, arr->length);
+        return out.writeArray((const uint16_t *) TypedArray::getDataOffset(arr), TypedArray::getLength(arr));
     case TypedArray::TYPE_INT32:
     case TypedArray::TYPE_UINT32:
     case TypedArray::TYPE_FLOAT32:
-        return out.writeArray((const uint32_t *) arr->data, arr->length);
+        return out.writeArray((const uint32_t *) TypedArray::getDataOffset(arr), TypedArray::getLength(arr));
     case TypedArray::TYPE_FLOAT64:
-        return out.writeArray((const uint64_t *) arr->data, arr->length);
+        return out.writeArray((const uint64_t *) TypedArray::getDataOffset(arr), TypedArray::getLength(arr));
     default:
         JS_NOT_REACHED("unknown TypedArray type");
         return false;
     }
 }
 
 bool
 JSStructuredCloneWriter::writeArrayBuffer(JSObject *obj)
@@ -656,33 +656,33 @@ bool
 JSStructuredCloneReader::readTypedArray(uint32_t tag, uint32_t nelems, Value *vp)
 {
     uint32_t atype = TagToArrayType(tag);
     JSObject *obj = js_CreateTypedArray(context(), atype, nelems);
     if (!obj)
         return false;
     vp->setObject(*obj);
 
-    TypedArray *arr = TypedArray::fromJSObject(obj);
-    JS_ASSERT(arr->length == nelems);
-    JS_ASSERT(arr->type == atype);
+    JSObject *arr = TypedArray::getTypedArray(obj);
+    JS_ASSERT(TypedArray::getLength(arr) == nelems);
+    JS_ASSERT(TypedArray::getType(arr) == atype);
     switch (atype) {
       case TypedArray::TYPE_INT8:
       case TypedArray::TYPE_UINT8:
       case TypedArray::TYPE_UINT8_CLAMPED:
-        return in.readArray((uint8_t *) arr->data, nelems);
+        return in.readArray((uint8_t *) TypedArray::getDataOffset(arr), nelems);
       case TypedArray::TYPE_INT16:
       case TypedArray::TYPE_UINT16:
-        return in.readArray((uint16_t *) arr->data, nelems);
+        return in.readArray((uint16_t *) TypedArray::getDataOffset(arr), nelems);
       case TypedArray::TYPE_INT32:
       case TypedArray::TYPE_UINT32:
       case TypedArray::TYPE_FLOAT32:
-        return in.readArray((uint32_t *) arr->data, nelems);
+        return in.readArray((uint32_t *) TypedArray::getDataOffset(arr), nelems);
       case TypedArray::TYPE_FLOAT64:
-        return in.readArray((uint64_t *) arr->data, nelems);
+        return in.readArray((uint64_t *) TypedArray::getDataOffset(arr), nelems);
       default:
         JS_NOT_REACHED("unknown TypedArray type");
         return false;
     }
 }
 
 bool
 JSStructuredCloneReader::readArrayBuffer(uint32_t nbytes, Value *vp)
--- a/js/src/jscntxt.cpp
+++ b/js/src/jscntxt.cpp
@@ -1429,16 +1429,22 @@ JSContext::generatorFor(StackFrame *fp) 
     for (size_t i = 0; i < genStack.length(); ++i) {
         if (genStack[i]->liveFrame() == fp)
             return genStack[i];
     }
     JS_NOT_REACHED("no matching generator");
     return NULL;
 }
 
+bool
+JSContext::runningWithTrustedPrincipals() const
+{
+    return !compartment || compartment->principals == runtime->trustedPrincipals();
+}
+
 JS_FRIEND_API(void)
 JSRuntime::onTooMuchMalloc()
 {
 #ifdef JS_THREADSAFE
     AutoLockGC lock(this);
 
     /*
      * We can be called outside a request and can race against a GC that
--- a/js/src/jscntxt.h
+++ b/js/src/jscntxt.h
@@ -1291,16 +1291,22 @@ struct JSContext
 #ifdef DEBUG
     /*
      * Controls whether a quadratic-complexity assertion is performed during
      * stack iteration, defaults to true.
      */
     bool stackIterAssertionEnabled;
 #endif
 
+    /*
+     * See JS_SetTrustedPrincipals in jsapi.h.
+     * Note: !cx->compartment is treated as trusted.
+     */
+    bool runningWithTrustedPrincipals() const;
+
   private:
     /*
      * The allocation code calls the function to indicate either OOM failure
      * when p is null or that a memory pressure counter has reached some
      * threshold when p is not null. The function takes the pointer and not
      * a boolean flag to minimize the amount of code in its inlined callers.
      */
     JS_FRIEND_API(void) checkMallocGCPressure(void *p);
--- a/js/src/jsemit.cpp
+++ b/js/src/jsemit.cpp
@@ -5228,20 +5228,20 @@ js_EmitTree(JSContext *cx, JSCodeGenerat
              * Emit code to get the next enumeration value and assign it to the
              * left hand side. The JSOP_POP after this assignment is annotated
              * so that the decompiler can distinguish 'for (x in y)' from
              * 'for (var x in y)'.
              */
             if (!EmitAssignment(cx, cg, pn2->pn_kid2, JSOP_NOP, NULL))
                 return false;
             tmp2 = CG_OFFSET(cg);
-            if (pn2->pn_kid1 && !js_NewSrcNote2(cx, cg, SRC_DECL,
-                                                (pn2->pn_kid1->pn_op == JSOP_DEFVAR)
-                                                ? SRC_DECL_VAR
-                                                : SRC_DECL_LET) < 0) {
+            if (pn2->pn_kid1 && js_NewSrcNote2(cx, cg, SRC_DECL,
+                                               (pn2->pn_kid1->pn_op == JSOP_DEFVAR)
+                                               ? SRC_DECL_VAR
+                                               : SRC_DECL_LET) < 0) {
                 return false;
             }
             if (js_Emit1(cx, cg, JSOP_POP) < 0)
                 return false;
 
             /* The stack should be balanced around the assignment opcode sequence. */
             JS_ASSERT(cg->stackDepth == loopDepth);
 
--- a/js/src/jsfriendapi.cpp
+++ b/js/src/jsfriendapi.cpp
@@ -75,8 +75,37 @@ JS_UnwrapObject(JSObject *obj)
     return obj->unwrap();
 }
 
 JS_FRIEND_API(JSObject *)
 JS_GetFrameScopeChainRaw(JSStackFrame *fp)
 {
     return &Valueify(fp)->scopeChain();
 }
+
+/*
+ * The below code is for temporary telemetry use. It can be removed when
+ * sufficient data has been harvested.
+ */
+
+extern size_t sE4XObjectsCreated;
+
+JS_FRIEND_API(size_t)
+JS_GetE4XObjectsCreated(JSContext *)
+{
+  return sE4XObjectsCreated;
+}
+
+extern size_t sSetProtoCalled;
+
+JS_FRIEND_API(size_t)
+JS_SetProtoCalled(JSContext *)
+{
+  return sSetProtoCalled;
+}
+
+extern size_t sCustomIteratorCount;
+
+JS_FRIEND_API(size_t)
+JS_GetCustomIteratorCount(JSContext *cx)
+{
+  return sCustomIteratorCount;
+}
--- a/js/src/jsfriendapi.h
+++ b/js/src/jsfriendapi.h
@@ -52,11 +52,20 @@ extern JS_FRIEND_API(JSObject *)
 JS_FindCompilationScope(JSContext *cx, JSObject *obj);
 
 extern JS_FRIEND_API(JSObject *)
 JS_UnwrapObject(JSObject *obj);
 
 extern JS_FRIEND_API(JSObject *)
 JS_GetFrameScopeChainRaw(JSStackFrame *fp);
 
+extern JS_FRIEND_API(size_t)
+JS_GetE4XObjectsCreated(JSContext *cx);
+
+extern JS_FRIEND_API(size_t)
+JS_SetProtoCalled(JSContext *cx);
+
+extern JS_FRIEND_API(size_t)
+JS_GetCustomIteratorCount(JSContext *cx);
+
 JS_END_EXTERN_C
 
 #endif /* jsfriendapi_h___ */
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -2903,8 +2903,21 @@ RunDebugGC(JSContext *cx)
         RunLastDitchGC(cx);
     }
 #endif
 }
 
 } /* namespace gc */
 
 } /* namespace js */
+
+#if JS_HAS_XML_SUPPORT
+extern size_t sE4XObjectsCreated;
+
+JSXML *
+js_NewGCXML(JSContext *cx)
+{
+    if (!cx->runningWithTrustedPrincipals())
+        ++sE4XObjectsCreated;
+
+    return NewGCThing<JSXML>(cx, js::gc::FINALIZE_XML, sizeof(JSXML));
+}
+#endif
--- a/js/src/jsgcinlines.h
+++ b/js/src/jsgcinlines.h
@@ -251,17 +251,13 @@ js_NewGCFunction(JSContext *cx)
 
 inline js::Shape *
 js_NewGCShape(JSContext *cx)
 {
     return NewGCThing<js::Shape>(cx, js::gc::FINALIZE_SHAPE, sizeof(js::Shape));
 }
 
 #if JS_HAS_XML_SUPPORT
-inline JSXML *
-js_NewGCXML(JSContext *cx)
-{
-    return NewGCThing<JSXML>(cx, js::gc::FINALIZE_XML, sizeof(JSXML));
-}
+extern JSXML *
+js_NewGCXML(JSContext *cx);
 #endif
 
-
 #endif /* jsgcinlines_h___ */
--- a/js/src/jshashtable.h
+++ b/js/src/jshashtable.h
@@ -752,30 +752,32 @@ class TaggedPointerEntry
 
     typedef TaggedPointerEntry<T> ThisT;
 
     static const uintptr_t NO_TAG_MASK = uintptr_t(-1) - 1;
 
   public:
     TaggedPointerEntry() : bits(0) {}
     TaggedPointerEntry(const TaggedPointerEntry &other) : bits(other.bits) {}
-    TaggedPointerEntry(T *ptr, bool tagged) : bits(uintptr_t(ptr) | tagged) {
+    TaggedPointerEntry(T *ptr, bool tagged)
+      : bits(uintptr_t(ptr) | uintptr_t(tagged))
+    {
         JS_ASSERT((uintptr_t(ptr) & 0x1) == 0);
     }
 
     bool isTagged() const {
         return bits & 0x1;
     }
 
     /*
      * Non-branching code sequence. Note that the const_cast is safe because
      * the hash function doesn't consider the tag to be a portion of the key.
      */
     void setTagged(bool enabled) const {
-        const_cast<ThisT *>(this)->bits |= enabled;
+        const_cast<ThisT *>(this)->bits |= uintptr_t(enabled);
     }
 
     T *asPtr() const {
         JS_ASSERT(bits != 0);
         return reinterpret_cast<T *>(bits & NO_TAG_MASK);
     }
 };
 
--- a/js/src/jsinterp.cpp
+++ b/js/src/jsinterp.cpp
@@ -83,16 +83,17 @@
 #include "jsatominlines.h"
 #include "jsinterpinlines.h"
 #include "jsobjinlines.h"
 #include "jsprobes.h"
 #include "jspropertycacheinlines.h"
 #include "jsscopeinlines.h"
 #include "jsscriptinlines.h"
 #include "jsopcodeinlines.h"
+#include "jstypedarrayinlines.h"
 
 #include "vm/Stack-inl.h"
 #include "vm/String-inl.h"
 
 #if JS_HAS_XML_SUPPORT
 #include "jsxml.h"
 #endif
 
@@ -2357,25 +2358,29 @@ BEGIN_CASE(JSOP_STOP)
         cx->stack.popInlineFrame(regs);
 
         /* Sync interpreter locals. */
         script = regs.fp()->script();
         pcCounts = script->pcCounters.get(JSRUNMODE_INTERP);
         argv = regs.fp()->maybeFormalArgs();
         atoms = FrameAtomBase(cx, regs.fp());
 
+        JS_ASSERT(*regs.pc == JSOP_TRAP || *regs.pc == JSOP_NEW || *regs.pc == JSOP_CALL ||
+                  *regs.pc == JSOP_FUNCALL || *regs.pc == JSOP_FUNAPPLY);
+
         /* Resume execution in the calling frame. */
         RESET_USE_METHODJIT();
         if (JS_LIKELY(interpReturnOK)) {
-            JS_ASSERT(js_CodeSpec[js_GetOpcode(cx, script, regs.pc)].length
-                      == JSOP_CALL_LENGTH);
             TRACE_0(LeaveFrame);
             len = JSOP_CALL_LENGTH;
             DO_NEXT_OP(len);
         }
+
+        /* Increment pc so that |sp - fp->slots == ReconstructStackDepth(pc)|. */
+        regs.pc += JSOP_CALL_LENGTH;
         goto error;
     } else {
         JS_ASSERT(regs.sp == regs.fp()->base());
     }
     interpReturnOK = true;
     goto exit;
 }
 
@@ -3555,18 +3560,18 @@ BEGIN_CASE(JSOP_LENGTH)
                     JS_ASSERT(length < INT32_MAX);
                     regs.sp[-1].setInt32(int32_t(length));
                     len = JSOP_LENGTH_LENGTH;
                     DO_NEXT_OP(len);
                 }
             }
 
             if (js_IsTypedArray(obj)) {
-                TypedArray *tarray = TypedArray::fromJSObject(obj);
-                regs.sp[-1].setNumber(tarray->length);
+                JSObject *tarray = TypedArray::getTypedArray(obj);
+                regs.sp[-1].setInt32(TypedArray::getLength(tarray));
                 len = JSOP_LENGTH_LENGTH;
                 DO_NEXT_OP(len);
             }
         }
 
         i = -2;
         goto do_getprop_with_lval;
     }
--- a/js/src/jsiter.cpp
+++ b/js/src/jsiter.cpp
@@ -203,17 +203,16 @@ EnumerateNativeProperties(JSContext *cx,
 {
     size_t initialLength = props->length();
 
     /* Collect all unique properties from this object's scope. */
     for (Shape::Range r = pobj->lastProperty()->all(); !r.empty(); r.popFront()) {
         const Shape &shape = r.front();
 
         if (!JSID_IS_DEFAULT_XML_NAMESPACE(shape.propid) &&
-            !shape.isAlias() &&
             !Enumerate(cx, obj, pobj, shape.propid, shape.enumerable(), flags, ht, props))
         {
             return false;
         }
     }
 
     ::Reverse(props->begin() + initialLength, props->end());
     return true;
@@ -334,30 +333,35 @@ VectorToIdArray(JSContext *cx, AutoIdVec
 JS_FRIEND_API(bool)
 GetPropertyNames(JSContext *cx, JSObject *obj, uintN flags, AutoIdVector *props)
 {
     return Snapshot(cx, obj, flags & (JSITER_OWNONLY | JSITER_HIDDEN), props);
 }
 
 }
 
+size_t sCustomIteratorCount = 0;
+
 static inline bool
 GetCustomIterator(JSContext *cx, JSObject *obj, uintN flags, Value *vp)
 {
     /* Check whether we have a valid __iterator__ method. */
     JSAtom *atom = cx->runtime->atomState.iteratorAtom;
     if (!js_GetMethod(cx, obj, ATOM_TO_JSID(atom), JSGET_NO_METHOD_BARRIER, vp))
         return false;
 
     /* If there is no custom __iterator__ method, we are done here. */
     if (!vp->isObject()) {
         vp->setUndefined();
         return true;
     }
 
+    if (!cx->runningWithTrustedPrincipals())
+        ++sCustomIteratorCount;
+
     /* Otherwise call it and return that object. */
     LeaveTrace(cx);
     Value arg = BooleanValue((flags & JSITER_FOREACH) == 0);
     if (!ExternalInvoke(cx, ObjectValue(*obj), *vp, 1, &arg, vp))
         return false;
     if (vp->isPrimitive()) {
         /*
          * We are always coming from js_ValueToIterator, and we are no longer on
--- a/js/src/jsnum.cpp
+++ b/js/src/jsnum.cpp
@@ -70,16 +70,17 @@
 #include "jsopcode.h"
 #include "jsprf.h"
 #include "jsscope.h"
 #include "jsstr.h"
 #include "jstracer.h"
 #include "jsvector.h"
 #include "jslibmath.h"
 
+#include "jsatominlines.h"
 #include "jsinterpinlines.h"
 #include "jsnuminlines.h"
 #include "jsobjinlines.h"
 #include "jsstrinlines.h"
 
 #include "vm/String-inl.h"
 
 using namespace js;
@@ -645,61 +646,45 @@ js_IntToString(JSContext *cx, int32 si)
     JSCompartment *c = cx->compartment;
     if (JSString *str = c->dtoaCache.lookup(10, si))
         return str;
 
     JSShortString *str = js_NewGCShortString(cx);
     if (!str)
         return NULL;
 
-    /* +1, since MAX_LENGTH does not count the null char. */
-    JS_STATIC_ASSERT(JSShortString::MAX_LENGTH + 1 >= sizeof("-2147483648"));
+    jschar *storage = str->inlineStorageBeforeInit();
+    RangedPtr<jschar> end(storage + JSShortString::MAX_SHORT_LENGTH,
+                          storage, JSShortString::MAX_SHORT_LENGTH + 1);
+    *end = '\0';
 
-    jschar *end = str->inlineStorageBeforeInit() + JSShortString::MAX_SHORT_LENGTH;
-    jschar *cp = end;
-    *cp = 0;
-
-    do {
-        jsuint newui = ui / 10, digit = ui % 10;  /* optimizers are our friends */
-        *--cp = '0' + digit;
-        ui = newui;
-    } while (ui != 0);
+    RangedPtr<jschar> start = BackfillIndexInCharBuffer(ui, end);
 
     if (si < 0)
-        *--cp = '-';
+        *--start = '-';
 
-    str->initAtOffsetInBuffer(cp, end - cp);
+    str->initAtOffsetInBuffer(start.get(), end - start);
 
     c->dtoaCache.cache(10, si, str);
     return str;
 }
 
 /* Returns a non-NULL pointer to inside cbuf.  */
 static char *
 IntToCString(ToCStringBuf *cbuf, jsint i, jsint base = 10)
 {
-    char *cp;
-    jsuint u;
-
-    u = (i < 0) ? -i : i;
+    jsuint u = (i < 0) ? -i : i;
 
-    cp = cbuf->sbuf + cbuf->sbufSize;   /* one past last buffer cell */
-    *--cp = '\0';                       /* null terminate the string to be */
+    RangedPtr<char> cp(cbuf->sbuf + cbuf->sbufSize - 1, cbuf->sbuf, cbuf->sbufSize);
+    *cp = '\0';
 
-    /*
-     * Build the string from behind. We use multiply and subtraction
-     * instead of modulus because that's much faster.
-     */
+    /* Build the string from behind. */
     switch (base) {
     case 10:
-      do {
-          jsuint newu = u / 10;
-          *--cp = (char)(u - newu * 10) + '0';
-          u = newu;
-      } while (u != 0);
+      cp = BackfillIndexInCharBuffer(u, cp);
       break;
     case 16:
       do {
           jsuint newu = u / 16;
           *--cp = "0123456789abcdef"[u - newu * 16];
           u = newu;
       } while (u != 0);
       break;
@@ -710,18 +695,17 @@ IntToCString(ToCStringBuf *cbuf, jsint i
           *--cp = "0123456789abcdefghijklmnopqrstuvwxyz"[u - newu * base];
           u = newu;
       } while (u != 0);
       break;
     }
     if (i < 0)
         *--cp = '-';
 
-    JS_ASSERT(cp >= cbuf->sbuf);
-    return cp;
+    return cp.get();
 }
 
 static JSString * JS_FASTCALL
 js_NumberToStringWithBase(JSContext *cx, jsdouble d, jsint base);
 
 static JSBool
 num_toString(JSContext *cx, uintN argc, Value *vp)
 {
@@ -1277,33 +1261,24 @@ IndexToString(JSContext *cx, uint32 inde
     JSCompartment *c = cx->compartment;
     if (JSFixedString *str = c->dtoaCache.lookup(10, index))
         return str;
 
     JSShortString *str = js_NewGCShortString(cx);
     if (!str)
         return NULL;
 
-    /* +1, since MAX_LENGTH does not count the null char. */
-    JS_STATIC_ASSERT(JSShortString::MAX_LENGTH + 1 >= sizeof("4294967295"));
-
     jschar *storage = str->inlineStorageBeforeInit();
     size_t length = JSShortString::MAX_SHORT_LENGTH;
     const RangedPtr<jschar> end(storage + length, storage, length + 1);
-    RangedPtr<jschar> cp = end;
-    *cp = '\0';
+    *end = '\0';
 
-    uint32 u = index;
-    do {
-        uint32 newu = u / 10, digit = u % 10;
-        *--cp = '0' + digit;
-        u = newu;
-    } while (u > 0);
+    RangedPtr<jschar> start = BackfillIndexInCharBuffer(index, end);
 
-    str->initAtOffsetInBuffer(cp.get(), end - cp);
+    str->initAtOffsetInBuffer(start.get(), end - start);
 
     c->dtoaCache.cache(10, index, str);
     return str;
 }
 
 bool JS_FASTCALL
 NumberValueToStringBuffer(JSContext *cx, const Value &v, StringBuffer &sb)
 {
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -160,19 +160,24 @@ static JSBool
 obj_getProto(JSContext *cx, JSObject *obj, jsid id, Val