merge the last green changeset on fx-team to m-c
authorTim Taubert <tim.taubert@gmx.de>
Sun, 07 Aug 2011 20:23:58 +0200
changeset 73950 eef25ec2d58e3f7d845438209ba2d95c44f0e441
parent 73949 4ec2052b0839249d086bdaffb34546cc58039906 (current diff)
parent 73942 c9441d911d5830336f164f127b23823bfe82d4d9 (diff)
child 73951 a62c4c474f2678b8186eb30a732701c37f18d8e4
child 74055 7715c3c492ae754211b4881fedb0fe8a045e69ff
child 74075 3d020dccebbeb3dda8b51a0dc25e9e1df8217d1b
push id20932
push usertim.taubert@gmx.de
push dateSun, 07 Aug 2011 18:24:43 +0000
treeherdermozilla-central@eef25ec2d58e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone8.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
merge the last green changeset on fx-team to m-c
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/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/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",
 
@@ -983,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.
@@ -1172,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/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/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/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.css
+++ b/browser/themes/winstripe/browser/browser.css
@@ -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/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, Value *vp)
 {
     /* Let CheckAccess get the slot's value, based on the access mode. */
     uintN attrs;
     id = ATOM_TO_JSID(cx->runtime->atomState.protoAtom);
     return CheckAccess(cx, obj, id, JSACC_PROTO, vp, &attrs);
 }
 
+size_t sSetProtoCalled = 0;
+
 static JSBool
 obj_setProto(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value *vp)
 {
+    if (!cx->runningWithTrustedPrincipals())
+        ++sSetProtoCalled;
+
     /* ECMAScript 5 8.6.2 forbids changing [[Prototype]] if not [[Extensible]]. */
     if (!obj->isExtensible()) {
         obj->reportNotExtensible(cx);
         return false;
     }
 
     if (!vp->isObjectOrNull())
         return JS_TRUE;
@@ -6494,17 +6499,16 @@ DumpProperty(JSObject *obj, const Shape 
     jsid id = shape.propid;
     uint8 attrs = shape.attributes();
 
     fprintf(stderr, "    ((Shape *) %p) ", (void *) &shape);
     if (attrs & JSPROP_ENUMERATE) fprintf(stderr, "enumerate ");
     if (attrs & JSPROP_READONLY) fprintf(stderr, "readonly ");
     if (attrs & JSPROP_PERMANENT) fprintf(stderr, "permanent ");
     if (attrs & JSPROP_SHARED) fprintf(stderr, "shared ");
-    if (shape.isAlias()) fprintf(stderr, "alias ");
     if (shape.isMethod()) fprintf(stderr, "method=%p ", (void *) &shape.methodObject());
 
     if (shape.hasGetterValue())
         fprintf(stderr, "getterValue=%p ", (void *) shape.getterObject());
     else if (!shape.hasDefaultGetter())
         fprintf(stderr, "getterOp=%p ", JS_FUNC_TO_DATA_PTR(void *, shape.getterOp()));
 
     if (shape.hasSetterValue())
--- a/js/src/jspropertytree.cpp
+++ b/js/src/jspropertytree.cpp
@@ -262,17 +262,16 @@ Shape::dump(JSContext *cx, FILE *fp) con
         fputs(") ", fp);
     }
 
     fprintf(fp, "flags %x ", flags);
     if (flags) {
         int first = 1;
         fputs("(", fp);
 #define DUMP_FLAG(name, display) if (flags & name) fputs(" " #display + first, fp), first = 0
-        DUMP_FLAG(ALIAS, alias);
         DUMP_FLAG(HAS_SHORTID, has_shortid);
         DUMP_FLAG(METHOD, method);
         DUMP_FLAG(IN_DICTIONARY, in_dictionary);
 #undef  DUMP_FLAG
         fputs(") ", fp);
     }
 
     fprintf(fp, "shortid %d\n", shortid);
--- a/js/src/jsregexp.cpp
+++ b/js/src/jsregexp.cpp
@@ -366,16 +366,19 @@ DEFINE_STATIC_SETTER(static_input_setter
 DEFINE_STATIC_SETTER(static_multiline_setter,
                      if (!JSVAL_IS_BOOLEAN(*vp) && !JS_ConvertValue(cx, *vp, JSTYPE_BOOLEAN, vp))
                          return false;
                      res->setMultiline(!!JSVAL_TO_BOOLEAN(*vp)))
 
 const uint8 REGEXP_STATIC_PROP_ATTRS    = JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_ENUMERATE;
 const uint8 RO_REGEXP_STATIC_PROP_ATTRS = REGEXP_STATIC_PROP_ATTRS | JSPROP_READONLY;
 
+const uint8 HIDDEN_PROP_ATTRS = JSPROP_PERMANENT | JSPROP_SHARED;
+const uint8 RO_HIDDEN_PROP_ATTRS = HIDDEN_PROP_ATTRS | JSPROP_READONLY;
+
 static JSPropertySpec regexp_static_props[] = {
     {"input",        0, REGEXP_STATIC_PROP_ATTRS,    static_input_getter, static_input_setter},
     {"multiline",    0, REGEXP_STATIC_PROP_ATTRS,    static_multiline_getter,
                                                      static_multiline_setter},
     {"lastMatch",    0, RO_REGEXP_STATIC_PROP_ATTRS, static_lastMatch_getter,    NULL},
     {"lastParen",    0, RO_REGEXP_STATIC_PROP_ATTRS, static_lastParen_getter,    NULL},
     {"leftContext",  0, RO_REGEXP_STATIC_PROP_ATTRS, static_leftContext_getter,  NULL},
     {"rightContext", 0, RO_REGEXP_STATIC_PROP_ATTRS, static_rightContext_getter, NULL},
@@ -383,16 +386,23 @@ static JSPropertySpec regexp_static_prop
     {"$2",           0, RO_REGEXP_STATIC_PROP_ATTRS, static_paren2_getter,       NULL},
     {"$3",           0, RO_REGEXP_STATIC_PROP_ATTRS, static_paren3_getter,       NULL},
     {"$4",           0, RO_REGEXP_STATIC_PROP_ATTRS, static_paren4_getter,       NULL},
     {"$5",           0, RO_REGEXP_STATIC_PROP_ATTRS, static_paren5_getter,       NULL},
     {"$6",           0, RO_REGEXP_STATIC_PROP_ATTRS, static_paren6_getter,       NULL},
     {"$7",           0, RO_REGEXP_STATIC_PROP_ATTRS, static_paren7_getter,       NULL},
     {"$8",           0, RO_REGEXP_STATIC_PROP_ATTRS, static_paren8_getter,       NULL},
     {"$9",           0, RO_REGEXP_STATIC_PROP_ATTRS, static_paren9_getter,       NULL},
+
+    {"$_",           0, HIDDEN_PROP_ATTRS,    static_input_getter, static_input_setter},
+    {"$*",           0, HIDDEN_PROP_ATTRS,    static_multiline_getter, static_multiline_setter},
+    {"$&",           0, RO_HIDDEN_PROP_ATTRS, static_lastMatch_getter, NULL},
+    {"$+",           0, RO_HIDDEN_PROP_ATTRS, static_lastParen_getter, NULL},
+    {"$`",           0, RO_HIDDEN_PROP_ATTRS, static_leftContext_getter, NULL},
+    {"$'",           0, RO_HIDDEN_PROP_ATTRS, static_rightContext_getter, NULL},
     {0,0,0,0,0}
 };
 
 static void
 regexp_finalize(JSContext *cx, JSObject *obj)
 {
     RegExp *re = RegExp::extractFrom(obj);
     if (!re)
@@ -824,23 +834,16 @@ js_InitRegExpClass(JSContext *cx, JSObje
                                                  CLASS_ATOM(cx, RegExp), 2);
     if (!ctor)
         return NULL;
 
     if (!LinkConstructorAndPrototype(cx, ctor, proto))
         return NULL;
 
     /* Add static properties to the RegExp constructor. */
-    if (!JS_DefineProperties(cx, ctor, regexp_static_props) ||
-        !JS_AliasProperty(cx, ctor, "input",        "$_") ||
-        !JS_AliasProperty(cx, ctor, "multiline",    "$*") ||
-        !JS_AliasProperty(cx, ctor, "lastMatch",    "$&") ||
-        !JS_AliasProperty(cx, ctor, "lastParen",    "$+") ||
-        !JS_AliasProperty(cx, ctor, "leftContext",  "$`") ||
-        !JS_AliasProperty(cx, ctor, "rightContext", "$'")) {
+    if (!JS_DefineProperties(cx, ctor, regexp_static_props))
         return NULL;
-    }
 
     if (!DefineConstructorAndPrototype(cx, global, JSProto_RegExp, ctor, proto))
         return NULL;
 
     return proto;
 }
--- a/js/src/jsscope.cpp
+++ b/js/src/jsscope.cpp
@@ -397,34 +397,30 @@ Shape::getChild(JSContext *cx, const js:
  */
 Shape *
 JSObject::getChildProperty(JSContext *cx, Shape *parent, Shape &child)
 {
     JS_ASSERT(!JSID_IS_VOID(child.propid));
     JS_ASSERT(!child.inDictionary());
 
     /*
-     * Aliases share another property's slot, passed in the |slot| parameter.
-     * Shared properties have no slot. Unshared properties that do not alias
-     * another property's slot allocate a slot here, but may lose it due to a
-     * JS_ClearScope call.
+     * Shared properties have no slot. Unshared properties allocate a slot here
+     * but may lose it due to a JS_ClearScope call.
      */
-    if (!child.isAlias()) {
-        if (child.attrs & JSPROP_SHARED) {
-            child.slot = SHAPE_INVALID_SLOT;
-        } else {
-            /*
-             * We may have set slot from a nearly-matching shape, above. If so,
-             * we're overwriting that nearly-matching shape, so we can reuse
-             * its slot -- we don't need to allocate a new one. Similarly, we
-             * use a specific slot if provided by the caller.
-             */
-            if (child.slot == SHAPE_INVALID_SLOT && !allocSlot(cx, &child.slot))
-                return NULL;
-        }
+    if (child.attrs & JSPROP_SHARED) {
+        child.slot = SHAPE_INVALID_SLOT;
+    } else {
+        /*
+         * We may have set slot from a nearly-matching shape, above. If so,
+         * we're overwriting that nearly-matching shape, so we can reuse its
+         * slot -- we don't need to allocate a new one. Similarly, we use a
+         * specific slot if provided by the caller.
+         */
+        if (child.slot == SHAPE_INVALID_SLOT && !allocSlot(cx, &child.slot))
+            return NULL;
     }
 
     Shape *shape;
 
     if (inDictionaryMode()) {
         JS_ASSERT(parent == lastProp);
         if (parent->frozen()) {
             parent = Shape::newDictionaryList(cx, &lastProp);
@@ -767,17 +763,17 @@ JSObject::putProperty(JSContext *cx, jsi
     if (!CheckCanChangeAttrs(cx, this, shape, &attrs))
         return NULL;
     
     /*
      * If the caller wants to allocate a slot, but doesn't care which slot,
      * copy the existing shape's slot into slot so we can match shape, if all
      * other members match.
      */
-    bool hadSlot = !shape->isAlias() && shape->hasSlot();
+    bool hadSlot = shape->hasSlot();
     uint32 oldSlot = shape->slot;
     if (!(attrs & JSPROP_SHARED) && slot == SHAPE_INVALID_SLOT && hadSlot)
         slot = oldSlot;
 
     /*
      * Now that we've possibly preserved slot, check whether all members match.
      * If so, this is a redundant "put" and we can return without more work.
      */
@@ -805,17 +801,17 @@ JSObject::putProperty(JSContext *cx, jsi
      * property that dictionaries exclusively own their mutable shape structs,
      * each of which has a unique shape number (not shared via a shape tree).
      *
      * This is more than an optimization: it is required to preserve for-in
      * enumeration order (see bug 601399).
      */
     if (inDictionaryMode()) {
         /* FIXME bug 593129 -- slot allocation and JSObject *this must move out of here! */
-        if (slot == SHAPE_INVALID_SLOT && !(attrs & JSPROP_SHARED) && !(flags & Shape::ALIAS)) {
+        if (slot == SHAPE_INVALID_SLOT && !(attrs & JSPROP_SHARED)) {
             if (!allocSlot(cx, &slot))
                 return NULL;
         }
 
         shape->slot = slot;
         if (slot != SHAPE_INVALID_SLOT && slot >= shape->slotSpan) {
             shape->slotSpan = slot + 1;
 
@@ -923,17 +919,17 @@ JSObject::changeProperty(JSContext *cx, 
 
     /*
      * Dictionary-mode objects exclusively own their mutable shape structs, so
      * we simply modify in place.
      */
     if (inDictionaryMode()) {
         /* FIXME bug 593129 -- slot allocation and JSObject *this must move out of here! */
         uint32 slot = shape->slot;
-        if (slot == SHAPE_INVALID_SLOT && !(attrs & JSPROP_SHARED) && !(flags & Shape::ALIAS)) {
+        if (slot == SHAPE_INVALID_SLOT && !(attrs & JSPROP_SHARED)) {
             if (!allocSlot(cx, &slot))
                 return NULL;
         }
 
         Shape *mutableShape = const_cast<Shape *>(shape);
         mutableShape->slot = slot;
         if (slot != SHAPE_INVALID_SLOT && slot >= shape->slotSpan) {
             mutableShape->slotSpan = slot + 1;
@@ -991,17 +987,17 @@ JSObject::removeProperty(JSContext *cx, 
 {
     Shape **spp = nativeSearch(id);
     Shape *shape = SHAPE_FETCH(spp);
     if (!shape)
         return true;
 
     /* First, if shape is unshared and not has a slot, free its slot number. */
     bool addedToFreelist = false;
-    bool hadSlot = !shape->isAlias() && shape->hasSlot();
+    bool hadSlot = shape->hasSlot();
     if (hadSlot) {
         addedToFreelist = freeSlot(cx, shape->slot);
         JS_ATOMIC_INCREMENT(&cx->runtime->propertyRemovals);
     }
 
     /* If shape is not the last property added, switch to dictionary mode. */
     if (shape != lastProp && !inDictionaryMode()) {
         if (!toDictionaryMode(cx))
--- a/js/src/jsscope.h
+++ b/js/src/jsscope.h
@@ -484,17 +484,19 @@ struct Shape : public js::gc::Cell
      */
     enum {
         SHARED_EMPTY    = 0x01,
 
         /* Property stored in per-object dictionary, not shared property tree. */
         IN_DICTIONARY   = 0x02,
 
         /* Prevent unwanted mutation of shared Bindings::lastBinding nodes. */
-        FROZEN          = 0x04
+        FROZEN          = 0x04,
+
+        UNUSED_BITS     = 0x38
     };
 
     Shape(jsid id, js::PropertyOp getter, js::StrictPropertyOp setter, uint32 slot, uintN attrs,
           uintN flags, intN shortid, uint32 shape = INVALID_SHAPE, uint32 slotSpan = 0);
 
     /* Used by EmptyShape (see jsscopeinlines.h). */
     Shape(JSCompartment *comp, Class *aclasp);
 
@@ -505,24 +507,22 @@ struct Shape : public js::gc::Cell
     bool frozen() const         { return (flags & FROZEN) != 0; }
     void setFrozen()            { flags |= FROZEN; }
 
     bool isEmptyShape() const   { JS_ASSERT_IF(!parent, JSID_IS_EMPTY(propid)); return !parent; }
 
   public:
     /* Public bits stored in shape->flags. */
     enum {
-        ALIAS           = 0x20,
         HAS_SHORTID     = 0x40,
         METHOD          = 0x80,
-        PUBLIC_FLAGS    = ALIAS | HAS_SHORTID | METHOD
+        PUBLIC_FLAGS    = HAS_SHORTID | METHOD
     };
 
     uintN getFlags() const  { return flags & PUBLIC_FLAGS; }
-    bool isAlias() const    { return (flags & ALIAS) != 0; }
     bool hasShortID() const { return (flags & HAS_SHORTID) != 0; }
     bool isMethod() const   { return (flags & METHOD) != 0; }
 
     JSObject &methodObject() const { JS_ASSERT(isMethod()); return *getterObj; }
 
     js::PropertyOp getter() const { return rawGetter; }
     bool hasDefaultGetter() const  { return !rawGetter; }
     js::PropertyOp getterOp() const { JS_ASSERT(!hasGetterValue()); return rawGetter; }
--- a/js/src/jsstr.cpp
+++ b/js/src/jsstr.cpp
@@ -2128,16 +2128,19 @@ JSBool
 js::str_replace(JSContext *cx, uintN argc, Value *vp)
 {
     ReplaceData rdata(cx);
     rdata.str = ThisToStringForStringProto(cx, vp);
     if (!rdata.str)
         return false;
     static const uint32 optarg = 2;
 
+    if (!rdata.g.init(argc, vp))
+        return false;
+
     /* Extract replacement string/function. */
     if (argc >= optarg && js_IsCallable(vp[3])) {
         rdata.lambda = &vp[3].toObject();
         rdata.elembase = NULL;
         rdata.repstr = NULL;
         rdata.dollar = rdata.dollarEnd = NULL;
 
         if (rdata.lambda->isFunction()) {
@@ -2183,19 +2186,16 @@ js::str_replace(JSContext *cx, uintN arg
         /* We're about to store pointers into the middle of our string. */
         JSFixedString *fixed = rdata.repstr->ensureFixed(cx);
         if (!fixed)
             return false;
         rdata.dollarEnd = fixed->chars() + fixed->length();
         rdata.dollar = js_strchr_limit(fixed->chars(), '$', rdata.dollarEnd);
     }
 
-    if (!rdata.g.init(argc, vp))
-        return false;
-
     /*
      * Unlike its |String.prototype| brethren, |replace| doesn't convert
      * its input to a regular expression. (Even if it contains metachars.)
      *
      * However, if the user invokes our (non-standard) |flags| argument
      * extension then we revert to creating a regular expression. Note that
      * this is observable behavior through the side-effect mutation of the
      * |RegExp| statics.
--- a/js/src/jstracer.cpp
+++ b/js/src/jstracer.cpp
@@ -86,16 +86,17 @@
 #include "jsfuninlines.h"
 #include "jsinterpinlines.h"
 #include "jspropertycacheinlines.h"
 #include "jsobjinlines.h"
 #include "jsscopeinlines.h"
 #include "jsscriptinlines.h"
 #include "jscntxtinlines.h"
 #include "jsopcodeinlines.h"
+#include "jstypedarrayinlines.h"
 
 #include "vm/Stack-inl.h"
 
 #ifdef JS_METHODJIT
 #include "methodjit/MethodJIT.h"
 #endif
 
 #include "tracejit/Writer-inl.h"
@@ -11571,17 +11572,17 @@ TraceRecorder::callNative(uintN argc, JS
         JS_ASSERT(((jsuword) clasp & 3) == 0);
 
         // Abort on |new Function|. (FIXME: This restriction might not
         // unnecessary now that the constructor creates the new function object
         // itself.)
         if (clasp == &js_FunctionClass)
             RETURN_STOP("new Function");
 
-        if (!clasp->isNative())
+        if (!IsFastTypedArrayClass(clasp) && !clasp->isNative())
             RETURN_STOP("new with non-native ops");
 
         // Don't trace |new Math.sin(0)|.
         if (!fun->isConstructor())
             RETURN_STOP("new with non-constructor native function");
 
         vp[1].setMagicWithObjectOrNullPayload(NULL);
         newobj_ins = w.immpMagicNull();
@@ -13192,32 +13193,38 @@ TraceRecorder::setElem(int lval_spindex,
                                              *cx->regs().pc == JSOP_INITELEM));
     } else if (OkToTraceTypedArrays && js_IsTypedArray(obj)) {
         // Fast path: assigning to element of typed array.
         VMSideExit* branchExit = snapshot(BRANCH_EXIT);
 
         // Ensure array is a typed array and is the same type as what was written
         guardClass(obj_ins, obj->getClass(), branchExit, LOAD_CONST);
 
-        js::TypedArray* tarray = js::TypedArray::fromJSObject(obj);
-
-        LIns* priv_ins = w.ldpObjPrivate(obj_ins);
+        JSObject* tarray = js::TypedArray::getTypedArray(obj);
 
         // The index was on the stack and is therefore a LIR float; force it to
         // be an integer.                              
         CHECK_STATUS_A(makeNumberInt32(idx_ins, &idx_ins));
 
+        LIns* slots_ins = w.ldpObjFixedSlots(obj_ins);
         // Ensure idx >= 0 && idx < length (by using uint32)
         CHECK_STATUS_A(guard(true,
-                             w.name(w.ltui(idx_ins, w.ldiConstTypedArrayLength(priv_ins)),
+                             w.name(w.ltui(idx_ins, w.ldiConstTypedArrayLength(slots_ins)),
                                     "inRange"),
                              OVERFLOW_EXIT, /* abortIfAlwaysExits = */true));
 
         // We're now ready to store
-        LIns* data_ins = w.ldpConstTypedArrayData(priv_ins);
+        LIns* data_base_ins = w.ldpConstTypedArrayData(slots_ins);
+        LIns* offset_ins = w.ldiConstTypedArrayByteOffset(slots_ins);
+#ifdef NANOJIT_64BIT
+        LIns* data_ins = w.addp(data_base_ins, w.ui2uq(offset_ins));
+#else
+        LIns* data_ins = w.addp(data_base_ins, offset_ins);
+#endif
+
         LIns* pidx_ins = w.ui2p(idx_ins);
         LIns* typed_v_ins = v_ins;
 
         // If it's not a number, convert objects to NaN,
         // null to 0, and call StringToNumber or BooleanOrUndefinedToNumber
         // for those.
         if (!v.isNumber()) {
             if (v.isNull()) {
@@ -13234,17 +13241,17 @@ TraceRecorder::setElem(int lval_spindex,
             } else if (v.isBoolean()) {
                 JS_ASSERT(v.isBoolean());
                 typed_v_ins = w.i2d(typed_v_ins);
             } else {
                 typed_v_ins = w.immd(js_NaN);
             }
         }
 
-        switch (tarray->type) {
+        switch (js::TypedArray::getType(tarray)) {
           case js::TypedArray::TYPE_INT8:
           case js::TypedArray::TYPE_INT16:
           case js::TypedArray::TYPE_INT32:
             typed_v_ins = d2i(typed_v_ins);
             break;
           case js::TypedArray::TYPE_UINT8:
           case js::TypedArray::TYPE_UINT16:
           case js::TypedArray::TYPE_UINT32:
@@ -13265,17 +13272,17 @@ TraceRecorder::setElem(int lval_spindex,
           case js::TypedArray::TYPE_FLOAT32:
           case js::TypedArray::TYPE_FLOAT64:
             // Do nothing, this is already a float
             break;
           default:
             JS_NOT_REACHED("Unknown typed array type in tracer");       
         }
 
-        switch (tarray->type) {
+        switch (js::TypedArray::getType(tarray)) {
           case js::TypedArray::TYPE_INT8:
           case js::TypedArray::TYPE_UINT8_CLAMPED:
           case js::TypedArray::TYPE_UINT8:
             w.sti2cTypedArrayElement(typed_v_ins, data_ins, pidx_ins);
             break;
           case js::TypedArray::TYPE_INT16:
           case js::TypedArray::TYPE_UINT16:
             w.sti2sTypedArrayElement(typed_v_ins, data_ins, pidx_ins);
@@ -14275,44 +14282,49 @@ TraceRecorder::typedArrayElement(Value& 
 
     JSObject* obj = &oval.toObject();
     LIns* obj_ins = get(&oval);
     jsint idx = ival.toInt32();
     LIns* idx_ins;
     CHECK_STATUS_A(makeNumberInt32(get(&ival), &idx_ins));
     LIns* pidx_ins = w.ui2p(idx_ins);
 
-    js::TypedArray* tarray = js::TypedArray::fromJSObject(obj);
+    JSObject* tarray = js::TypedArray::getTypedArray(obj);
     JS_ASSERT(tarray);
 
-    /* priv_ins will load the TypedArray* */
-    LIns* priv_ins = w.ldpObjPrivate(obj_ins);
+    LIns *slots_ins = w.ldpObjFixedSlots(obj_ins);
 
     /* Abort if out-of-range. */
-    if ((jsuint) idx >= tarray->length)
+    if ((jsuint) idx >= js::TypedArray::getLength(tarray))
         RETURN_STOP_A("out-of-range index on typed array");
 
     /*
      * Ensure idx < length
      *
      * NOTE! mLength is uint32, but it's guaranteed to fit in a Value
      * int, so we can treat it as either signed or unsigned.
      * If the index happens to be negative, when it's treated as
      * unsigned it'll be a very large int, and thus won't be less than
      * length.
      */
     guard(true,
-          w.name(w.ltui(idx_ins, w.ldiConstTypedArrayLength(priv_ins)), "inRange"),
+          w.name(w.ltui(idx_ins, w.ldiConstTypedArrayLength(slots_ins)), "inRange"),
           BRANCH_EXIT);
 
     /* We are now ready to load.  Do a different type of load
      * depending on what type of thing we're loading. */
-    LIns* data_ins = w.ldpConstTypedArrayData(priv_ins);
-
-    switch (tarray->type) {
+    LIns* data_base_ins = w.ldpConstTypedArrayData(slots_ins);
+    LIns* offset_ins = w.ldiConstTypedArrayByteOffset(slots_ins);
+#ifdef NANOJIT_64BIT
+    LIns* data_ins = w.addp(data_base_ins, w.ui2uq(offset_ins));
+#else
+    LIns* data_ins = w.addp(data_base_ins, offset_ins);
+#endif
+
+    switch (js::TypedArray::getType(tarray)) {
       case js::TypedArray::TYPE_INT8:
         v_ins = w.i2d(w.ldc2iTypedArrayElement(data_ins, pidx_ins));
         break;
       case js::TypedArray::TYPE_UINT8:
       case js::TypedArray::TYPE_UINT8_CLAMPED:
         // i2d on purpose here:  it's safe, because an 8-bit uint is guaranteed
         // to fit in a 32-bit int, and i2d gets more optimization than ui2d.
         v_ins = w.i2d(w.lduc2uiTypedArrayElement(data_ins, pidx_ins));
@@ -16331,17 +16343,17 @@ TraceRecorder::record_JSOP_LENGTH()
             guard(true, w.leui(v_ins, w.immi(JSVAL_INT_MAX)), BRANCH_EXIT);
             v_ins = w.i2d(v_ins);
         } else {
             v_ins = w.ui2d(v_ins);
         }
     } else if (OkToTraceTypedArrays && js_IsTypedArray(obj)) {
         // Ensure array is a typed array and is the same type as what was written
         guardClass(obj_ins, obj->getClass(), snapshot(BRANCH_EXIT), LOAD_NORMAL);
-        v_ins = w.i2d(w.ldiConstTypedArrayLength(w.ldpObjPrivate(obj_ins)));
+        v_ins = w.i2d(w.ldiConstTypedArrayLength(w.ldpObjFixedSlots(obj_ins)));
     } else {
         if (!obj->isNative())
             RETURN_STOP_A("can't trace length property access on non-array, non-native object");
         return getProp(obj, obj_ins);
     }
     set(&l, v_ins);
     return ARECORD_CONTINUE;
 }
--- a/js/src/jstypedarray.cpp
+++ b/js/src/jstypedarray.cpp
@@ -58,16 +58,18 @@
 #include "jsnum.h"
 #include "jsobj.h"
 #include "jsstaticcheck.h"
 #include "jsbit.h"
 #include "jsvector.h"
 #include "jstypedarray.h"
 #include "jsutil.h"
 
+#include "vm/GlobalObject.h"
+
 #include "jsobjinlines.h"
 #include "jstypedarrayinlines.h"
 
 using namespace js;
 using namespace js::gc;
 
 /* slots can only be upto 255 */
 static const uint8 ARRAYBUFFER_RESERVED_SLOTS = 16;
@@ -145,17 +147,17 @@ ArrayBuffer::class_constructor(JSContext
     JSObject *bufobj = create(cx, nbytes);
     if (!bufobj)
         return false;
     vp->setObject(*bufobj);
     return true;
 }
 
 static inline JSBool
-AllocateSlots(JSContext *cx, JSObject *obj, uint32 size)
+AllocateArrayBufferSlots(JSContext *cx, JSObject *obj, uint32 size)
 {
     uint32 bytes = size + sizeof(Value);
     if (size > sizeof(Value) * ARRAYBUFFER_RESERVED_SLOTS - sizeof(Value) ) {
         JS_ASSERT(!obj->hasSlotsArray());
         Value *tmpslots = (Value *)cx->calloc_(bytes);
         if (!tmpslots)
             return false;
         obj->setSlotsPtr(tmpslots);
@@ -199,17 +201,17 @@ ArrayBuffer::create(JSContext *cx, int32
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_ARRAY_LENGTH);
         return NULL;
     }
 
     /*
      * The first 8 bytes hold the length.
      * The rest of it is a flat data store for the array buffer.
      */
-    if (!AllocateSlots(cx, obj, nbytes))
+    if (!AllocateArrayBufferSlots(cx, obj, nbytes))
         return NULL;
 
     JS_ASSERT(obj->getClass() == &ArrayBuffer::slowClass);
     obj->setSharedNonNativeMap();
     obj->clasp = &ArrayBuffer::fastClass;
     return obj;
 }
 
@@ -295,34 +297,52 @@ ArrayBuffer::obj_getProperty(JSContext *
 
 JSBool
 ArrayBuffer::obj_setProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp, JSBool strict)
 {
     if (JSID_IS_ATOM(id, cx->runtime->atomState.byteLengthAtom))
         return true;
 
     if (JSID_IS_ATOM(id, cx->runtime->atomState.protoAtom)) {
-        if (!vp->isObjectOrNull())
-            return JS_TRUE;
-
-        JSObject *pobj = vp->toObjectOrNull();
-
+        // setting __proto__ = null
+        // effectively removes the prototype chain.
+        // any attempt to set __proto__ on native
+        // objects after setting them to null makes
+        // __proto__ just a plain property.
+        // the following code simulates this behaviour on arrays.
+        //
+        // we first attempt to set the prototype on
+        // the delegate which is a native object
+        // so that existing code handles the case
+        // of treating it as special or plain.
+        // if the delegate's prototype has now changed
+        // then we change our prototype too.
+        //
+        // otherwise __proto__ was a plain property
+        // and we don't modify our prototype chain
+        // since obj_getProperty will fetch it as a plain
+        // property from the delegate.
         JSObject *delegate = DelegateObject(cx, obj);
         if (!delegate)
             return false;
 
-        // save the old prototype
         JSObject *oldDelegateProto = delegate->getProto();
-        if (!SetProto(cx, delegate, pobj, true))
+
+        if (!js_SetPropertyHelper(cx, delegate, id, 0, vp, strict))
             return false;
 
-        if (!SetProto(cx, obj, pobj, true)) {
-            // restore proto on delegate
-            JS_ALWAYS_TRUE(SetProto(cx, delegate, oldDelegateProto, true));
-            return false;
+        if (delegate->getProto() != oldDelegateProto) {
+            // actual __proto__ was set and not a plain property called
+            // __proto__
+            if (!SetProto(cx, obj, vp->toObjectOrNull(), true)) {
+                // this can be caused for example by setting x.__proto__ = x
+                // restore delegate prototype chain
+                SetProto(cx, delegate, oldDelegateProto, true);
+                return false;
+            }
         }
         return true;
     }
 
     JSObject *delegate = DelegateObject(cx, obj);
     if (!delegate)
         return false;
 
@@ -389,134 +409,131 @@ ArrayBuffer::obj_typeOf(JSContext *cx, J
 /*
  * TypedArray
  *
  * The non-templated base class for the specific typed implementations.
  * This class holds all the member variables that are used by
  * the subclasses.
  */
 
-TypedArray *
-TypedArray::fromJSObject(JSObject *obj)
+JSObject *
+TypedArray::getTypedArray(JSObject *obj)
 {
     while (!js_IsTypedArray(obj))
         obj = obj->getProto();
-    return reinterpret_cast<TypedArray*>(obj->getPrivate());
+    return obj;
 }
 
 inline bool
-TypedArray::isArrayIndex(JSContext *cx, jsid id, jsuint *ip)
+TypedArray::isArrayIndex(JSContext *cx, JSObject *obj, jsid id, jsuint *ip)
 {
     jsuint index;
-    if (js_IdIsIndex(id, &index) && index < length) {
+    if (js_IdIsIndex(id, &index) && index < getLength(obj)) {
         if (ip)
             *ip = index;
         return true;
     }
 
     return false;
 }
 
-typedef Value (* TypedArrayPropertyGetter)(TypedArray *tarray);
+typedef Value (* TypedArrayPropertyGetter)(JSObject *tarray);
 
 template <TypedArrayPropertyGetter Get>
 class TypedArrayGetter {
   public:
     static inline bool get(JSContext *cx, JSObject *obj, jsid id, Value *vp) {
         do {
             if (js_IsTypedArray(obj)) {
-                TypedArray *tarray = TypedArray::fromJSObject(obj);
+                JSObject *tarray = TypedArray::getTypedArray(obj);
                 if (tarray)
                     *vp = Get(tarray);
                 return true;
             }
         } while ((obj = obj->getProto()) != NULL);
         return true;
     }
 };
 
+/*
+ * For now (until slots directly hold data)
+ * slots data element points to the JSObject representing the ArrayBuffer.
+ */
 inline Value
-getBuffer(TypedArray *tarray)
+getBufferValue(JSObject *tarray)
 {
-    return ObjectValue(*tarray->bufferJS);
+    JSObject *buffer = TypedArray::getBuffer(tarray);
+    return ObjectValue(*buffer);
 }
 
 JSBool
 TypedArray::prop_getBuffer(JSContext *cx, JSObject *obj, jsid id, Value *vp)
 {
-    return TypedArrayGetter<getBuffer>::get(cx, obj, id, vp);
+    return TypedArrayGetter<getBufferValue>::get(cx, obj, id, vp);
 }
 
 inline Value
-getByteOffset(TypedArray *tarray)
+getByteOffsetValue(JSObject *tarray)
 {
-    return Int32Value(tarray->byteOffset);
+    return Int32Value(TypedArray::getByteOffset(tarray));
 }
 
 JSBool
 TypedArray::prop_getByteOffset(JSContext *cx, JSObject *obj, jsid id, Value *vp)
 {
-    return TypedArrayGetter<getByteOffset>::get(cx, obj, id, vp);
+    return TypedArrayGetter<getByteOffsetValue>::get(cx, obj, id, vp);
 }
 
 inline Value
-getByteLength(TypedArray *tarray)
+getByteLengthValue(JSObject *tarray)
 {
-    return Int32Value(tarray->byteLength);
+    return Int32Value(TypedArray::getByteLength(tarray));
 }
 
 JSBool
 TypedArray::prop_getByteLength(JSContext *cx, JSObject *obj, jsid id, Value *vp)
 {
-    return TypedArrayGetter<getByteLength>::get(cx, obj, id, vp);
+    return TypedArrayGetter<getByteLengthValue>::get(cx, obj, id, vp);
 }
 
 inline Value
-getLength(TypedArray *tarray)
+getLengthValue(JSObject *tarray)
 {
-    return Int32Value(tarray->length);
+    return Int32Value(TypedArray::getLength(tarray));
 }
 
 JSBool
 TypedArray::prop_getLength(JSContext *cx, JSObject *obj, jsid id, Value *vp)
 {
-    return TypedArrayGetter<getLength>::get(cx, obj, id, vp);
+    return TypedArrayGetter<getLengthValue>::get(cx, obj, id, vp);
 }
 
 JSBool
 TypedArray::obj_lookupProperty(JSContext *cx, JSObject *obj, jsid id,
                                JSObject **objp, JSProperty **propp)
 {
-    TypedArray *tarray = fromJSObject(obj);
+    JSObject *tarray = getTypedArray(obj);
     JS_ASSERT(tarray);
 
-    if (tarray->isArrayIndex(cx, id)) {
+    if (isArrayIndex(cx, tarray, id)) {
         *propp = (JSProperty *) 1;  /* non-null to indicate found */
         *objp = obj;
         return true;
     }
 
     JSObject *proto = obj->getProto();
     if (!proto) {
         *objp = NULL;
         *propp = NULL;
         return true;
     }
 
     return proto->lookupProperty(cx, id, objp, propp);
 }
 
-void
-TypedArray::obj_trace(JSTracer *trc, JSObject *obj)
-{
-    TypedArray *tarray = fromJSObject(obj);
-    JS_ASSERT(tarray);
-    MarkObject(trc, *tarray->bufferJS, "typedarray.buffer");
-}
-
 JSBool
 TypedArray::obj_getAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp)
 {
     *attrsp = (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom))
               ? JSPROP_PERMANENT | JSPROP_READONLY
               : JSPROP_PERMANENT | JSPROP_ENUMERATE;
     return true;
 }
@@ -656,64 +673,61 @@ template<> inline const bool TypeIsUnsig
 template<> inline const bool TypeIsUnsigned<uint32>() { return true; }
 
 template<typename NativeType> static inline const bool TypeIsFloatingPoint() { return false; }
 template<> inline const bool TypeIsFloatingPoint<float>() { return true; }
 template<> inline const bool TypeIsFloatingPoint<double>() { return true; }
 
 template<typename NativeType> class TypedArrayTemplate;
 
-typedef TypedArrayTemplate<int8> Int8Array;
-typedef TypedArrayTemplate<uint8> Uint8Array;
-typedef TypedArrayTemplate<int16> Int16Array;
-typedef TypedArrayTemplate<uint16> Uint16Array;
-typedef TypedArrayTemplate<int32> Int32Array;
-typedef TypedArrayTemplate<uint32> Uint32Array;
-typedef TypedArrayTemplate<float> Float32Array;
-typedef TypedArrayTemplate<double> Float64Array;
-typedef TypedArrayTemplate<uint8_clamped> Uint8ClampedArray;
-
 template<typename NativeType>
 class TypedArrayTemplate
   : public TypedArray
 {
   public:
     typedef NativeType ThisType;
     typedef TypedArrayTemplate<NativeType> ThisTypeArray;
     static const int ArrayTypeID() { return TypeIDOfType<NativeType>(); }
     static const bool ArrayTypeIsUnsigned() { return TypeIsUnsigned<NativeType>(); }
     static const bool ArrayTypeIsFloatingPoint() { return TypeIsFloatingPoint<NativeType>(); }
 
-    static JSFunctionSpec jsfuncs[];
+    static const size_t BYTES_PER_ELEMENT = sizeof(ThisType);
 
     static inline Class *slowClass()
     {
         return &TypedArray::slowClasses[ArrayTypeID()];
     }
 
     static inline Class *fastClass()
     {
         return &TypedArray::fastClasses[ArrayTypeID()];
     }
 
+    static void
+    obj_trace(JSTracer *trc, JSObject *obj)
+    {
+        JSObject *buffer = static_cast<JSObject*>(getBuffer(obj));
+        if (buffer)
+            MarkObject(trc, *buffer, "typedarray.buffer");
+    }
+
     static JSBool
     obj_getProperty(JSContext *cx, JSObject *obj, JSObject *receiver, jsid id, Value *vp)
     {
-        ThisTypeArray *tarray = ThisTypeArray::fromJSObject(obj);
-        JS_ASSERT(tarray);
+        JSObject *tarray = getTypedArray(obj);
 
         if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)) {
-            vp->setNumber(tarray->length);
+            vp->setNumber(getLength(tarray));
             return true;
         }
 
         jsuint index;
-        if (tarray->isArrayIndex(cx, id, &index)) {
+        if (isArrayIndex(cx, tarray, id, &index)) {
             // this inline function is specialized for each type
-            tarray->copyIndexToValue(cx, index, vp);
+            copyIndexToValue(cx, tarray, index, vp);
         } else {
             JSObject *obj2;
             JSProperty *prop;
             const Shape *shape;
 
             JSObject *proto = obj->getProto();
             if (!proto) {
                 vp->setUndefined();
@@ -734,43 +748,43 @@ class TypedArrayTemplate
         }
 
         return true;
     }
 
     static JSBool
     obj_setProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp, JSBool strict)
     {
-        ThisTypeArray *tarray = ThisTypeArray::fromJSObject(obj);
+        JSObject *tarray = getTypedArray(obj);
         JS_ASSERT(tarray);
 
         if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)) {
-            vp->setNumber(tarray->length);
+            vp->setNumber(getLength(tarray));
             return true;
         }
 
         jsuint index;
         // We can't just chain to js_SetPropertyHelper, because we're not a normal object.
-        if (!tarray->isArrayIndex(cx, id, &index)) {
+        if (!isArrayIndex(cx, tarray, id, &index)) {
 #if 0
             JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
                                  JSMSG_TYPED_ARRAY_BAD_INDEX);
             return false;
 #endif
             // Silent ignore is better than an exception here, because
             // at some point we may want to support other properties on
             // these objects.  This is especially true when these arrays
             // are used to implement HTML Canvas 2D's PixelArray objects,
             // which used to be plain old arrays.
             vp->setUndefined();
             return true;
         }
 
         if (vp->isInt32()) {
-            tarray->setIndex(index, NativeType(vp->toInt32()));
+            setIndex(tarray, index, NativeType(vp->toInt32()));
             return true;
         }
 
         jsdouble d;
 
         if (vp->isDouble()) {
             d = vp->toDouble();
         } else if (vp->isNull()) {
@@ -790,29 +804,29 @@ class TypedArrayTemplate
         }
 
         // If the array is an integer array, we only handle up to
         // 32-bit ints from this point on.  if we want to handle
         // 64-bit ints, we'll need some changes.
 
         // Assign based on characteristics of the destination type
         if (ArrayTypeIsFloatingPoint()) {
-            tarray->setIndex(index, NativeType(d));
+            setIndex(tarray, index, NativeType(d));
         } else if (ArrayTypeIsUnsigned()) {
             JS_ASSERT(sizeof(NativeType) <= 4);
             uint32 n = js_DoubleToECMAUint32(d);
-            tarray->setIndex(index, NativeType(n));
+            setIndex(tarray, index, NativeType(n));
         } else if (ArrayTypeID() == TypedArray::TYPE_UINT8_CLAMPED) {
             // The uint8_clamped type has a special rounding converter
             // for doubles.
-            tarray->setIndex(index, NativeType(d));
+            setIndex(tarray, index, NativeType(d));
         } else {
             JS_ASSERT(sizeof(NativeType) <= 4);
             int32 n = js_DoubleToECMAInt32(d);
-            tarray->setIndex(index, NativeType(n));
+            setIndex(tarray, index, NativeType(n));
         }
 
         return true;
     }
 
     static JSBool
     obj_defineProperty(JSContext *cx, JSObject *obj, jsid id, const Value *v,
                        PropertyOp getter, StrictPropertyOp setter, uintN attrs)
@@ -827,64 +841,64 @@ class TypedArrayTemplate
     static JSBool
     obj_deleteProperty(JSContext *cx, JSObject *obj, jsid id, Value *rval, JSBool strict)
     {
         if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)) {
             rval->setBoolean(false);
             return true;
         }
 
-        TypedArray *tarray = TypedArray::fromJSObject(obj);
+        JSObject *tarray = TypedArray::getTypedArray(obj);
         JS_ASSERT(tarray);
 
-        if (tarray->isArrayIndex(cx, id)) {
+        if (isArrayIndex(cx, tarray, id)) {
             rval->setBoolean(false);
             return true;
         }
 
         rval->setBoolean(true);
         return true;
     }
 
     static JSBool
     obj_enumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op,
                   Value *statep, jsid *idp)
     {
-        ThisTypeArray *tarray = ThisTypeArray::fromJSObject(obj);
+        JSObject *tarray = getTypedArray(obj);
         JS_ASSERT(tarray);
 
         /*
          * Iteration is "length" (if JSENUMERATE_INIT_ALL), then [0, length).
          * *statep is JSVAL_TRUE if enumerating "length" and
          * JSVAL_TO_INT(index) when enumerating index.
          */
         switch (enum_op) {
           case JSENUMERATE_INIT_ALL:
             statep->setBoolean(true);
             if (idp)
-                *idp = ::INT_TO_JSID(tarray->length + 1);
+                *idp = ::INT_TO_JSID(getLength(tarray) + 1);
             break;
 
           case JSENUMERATE_INIT:
             statep->setInt32(0);
             if (idp)
-                *idp = ::INT_TO_JSID(tarray->length);
+                *idp = ::INT_TO_JSID(getLength(tarray));
             break;
 
           case JSENUMERATE_NEXT:
             if (statep->isTrue()) {
                 *idp = ATOM_TO_JSID(cx->runtime->atomState.lengthAtom);
                 statep->setInt32(0);
             } else {
                 uint32 index = statep->toInt32();
-                if (index < uint32(tarray->length)) {
+                if (index < getLength(tarray)) {
                     *idp = ::INT_TO_JSID(index);
                     statep->setInt32(index + 1);
                 } else {
-                    JS_ASSERT(index == tarray->length);
+                    JS_ASSERT(index == getLength(tarray));
                     statep->setNull();
                 }
             }
             break;
 
           case JSENUMERATE_DESTROY:
             statep->setNull();
             break;
@@ -897,28 +911,50 @@ class TypedArrayTemplate
     obj_typeOf(JSContext *cx, JSObject *obj)
     {
         return JSTYPE_OBJECT;
     }
 
     static JSObject *
     createTypedArray(JSContext *cx, JSObject *bufobj, uint32 byteOffset, uint32 len)
     {
+        JS_ASSERT(bufobj->getClass() == &ArrayBuffer::fastClass);
         JSObject *obj = NewBuiltinClassInstance(cx, slowClass());
         if (!obj)
             return NULL;
 
-        ThisTypeArray *tarray = cx->new_<ThisTypeArray>(bufobj, byteOffset, len);
-        if (!tarray)
-            return NULL;
+        obj->setSlot(FIELD_TYPE, Int32Value(ArrayTypeID()));
+
+        do {
+            obj->setSlot(FIELD_BUFFER, ObjectValue(*bufobj));
+            /*
+             * NOTE: unlike the earlier implementation where the 'data' pointed
+             * directly to the right offset in the ArrayBuffer
+             * this points to the base of the ArrayBuffer.
+             * getIndex is modified to get the right index.
+             *
+             * This is because on 64 bit systems the jsval.h Private API
+             * requires pointers stored in jsvals to be two-byte aligned.
+             * TM and JM both need a few extra instructions to add the offset.
+             */
+            obj->setSlot(FIELD_DATA, PrivateValue(ArrayBuffer::getDataOffset(bufobj)));
+        } while(0);
+
+        obj->setSlot(FIELD_LENGTH, Int32Value(len));
+        obj->setSlot(FIELD_BYTEOFFSET, Int32Value(byteOffset));
+        obj->setSlot(FIELD_BYTELENGTH, Int32Value(len * sizeof(NativeType)));
+
+        JS_ASSERT(ArrayBuffer::getByteLength(getBuffer(obj)) - getByteOffset(obj) >= getByteLength(obj));
+        JS_ASSERT(getByteOffset(obj) <= ArrayBuffer::getByteLength(getBuffer(obj)));
+        JS_ASSERT(ArrayBuffer::getDataOffset(getBuffer(obj)) <= getDataOffset(obj));
+        JS_ASSERT(getDataOffset(obj) <= offsetData(obj, ArrayBuffer::getByteLength(getBuffer(obj))));
 
         JS_ASSERT(obj->getClass() == slowClass());
         obj->setSharedNonNativeMap();
         obj->clasp = fastClass();
-        obj->setPrivate(tarray);
 
         // FIXME Bug 599008: make it ok to call preventExtensions here.
         obj->flags |= JSObject::NOT_EXTENSIBLE;
 
         return obj;
     }
 
     /*
@@ -959,26 +995,26 @@ class TypedArrayTemplate
                                  JSMSG_TYPED_ARRAY_BAD_ARGS);
             return NULL;
         }
 
         JSObject *dataObj = &argv[0].toObject();
 
         /* (typedArray) */
         if (js_IsTypedArray(dataObj)) {
-            TypedArray *otherTypedArray = TypedArray::fromJSObject(dataObj);
+            JSObject *otherTypedArray = getTypedArray(dataObj);
             JS_ASSERT(otherTypedArray);
 
-            uint32 len = otherTypedArray->length;
+            uint32 len = getLength(otherTypedArray);
             JSObject *bufobj = createBufferWithSizeAndCount(cx, len);
             if (!bufobj)
                 return NULL;
 
             JSObject *obj = createTypedArray(cx, bufobj, 0, len);
-            if (!obj || !copyFrom(cx, obj, otherTypedArray, 0))
+            if (!obj || !copyFromTypedArray(cx, obj, otherTypedArray, 0))
                 return NULL;
             return obj;
         }
 
         /* (obj, byteOffset, length). */
         int32_t byteOffset = -1;
         int32_t length = -1;
 
@@ -1001,45 +1037,37 @@ class TypedArrayTemplate
                 }
             }
         }
 
         /* (obj, byteOffset, length) */
         return createTypedArrayWithOffsetLength(cx, dataObj, byteOffset, length);
     }
 
-    static void
-    class_finalize(JSContext *cx, JSObject *obj)
-    {
-        ThisTypeArray *tarray = ThisTypeArray::fromJSObject(obj);
-        if (tarray)
-            cx->delete_(tarray);
-    }
-
     /* subarray(start[, end]) */
     static JSBool
     fun_subarray(JSContext *cx, uintN argc, Value *vp)
     {
         JSObject *obj = ToObject(cx, &vp[1]);
         if (!obj)
             return false;
 
         if (obj->getClass() != fastClass()) {
             // someone tried to apply this subarray() to the wrong class
             ReportIncompatibleMethod(cx, vp, fastClass());
             return false;
         }
 
-        ThisTypeArray *tarray = ThisTypeArray::fromJSObject(obj);
+        JSObject *tarray = getTypedArray(obj);
         if (!tarray)
             return true;
 
         // these are the default values
-        int32_t begin = 0, end = tarray->length;
-        int32_t length = int32(tarray->length);
+        int32_t begin = 0, end = getLength(tarray);
+        int32_t length = int32(getLength(tarray));
 
         if (argc > 0) {
             Value *argv = JS_ARGV(cx, vp);
             if (!ValueToInt32(cx, argv[0], &begin))
                 return false;
             if (begin < 0) {
                 begin += length;
                 if (begin < 0)
@@ -1080,29 +1108,29 @@ class TypedArrayTemplate
             return false;
 
         if (obj->getClass() != fastClass()) {
             // someone tried to apply this set() to the wrong class
             ReportIncompatibleMethod(cx, vp, fastClass());
             return false;
         }
 
-        ThisTypeArray *tarray = ThisTypeArray::fromJSObject(obj);
+        JSObject *tarray = getTypedArray(obj);
         if (!tarray)
             return true;
 
         // these are the default values
         int32_t off = 0;
 
         Value *argv = JS_ARGV(cx, vp);
         if (argc > 1) {
             if (!ValueToInt32(cx, argv[1], &off))
                 return false;
 
-            if (off < 0 || uint32_t(off) > tarray->length) {
+            if (off < 0 || uint32_t(off) > getLength(tarray)) {
                 // the given offset is bogus
                 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
                                      JSMSG_TYPED_ARRAY_BAD_ARGS);
                 return false;
             }
         }
 
         uint32 offset(off);
@@ -1111,76 +1139,48 @@ class TypedArrayTemplate
         if (argc == 0 || !argv[0].isObject()) {
             JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
                                  JSMSG_TYPED_ARRAY_BAD_ARGS);
             return false;
         }
 
         JSObject *arg0 = argv[0].toObjectOrNull();
         if (js_IsTypedArray(arg0)) {
-            TypedArray *src = TypedArray::fromJSObject(arg0);
+            JSObject *src = TypedArray::getTypedArray(arg0);
             if (!src ||
-                src->length > tarray->length - offset)
+                getLength(src) > getLength(tarray) - offset)
             {
                 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
                                      JSMSG_TYPED_ARRAY_BAD_ARGS);
                 return false;
             }
 
-            if (!copyFrom(cx, obj, src, offset))
+            if (!copyFromTypedArray(cx, obj, src, offset))
                 return false;
         } else {
             jsuint len;
             if (!js_GetLengthProperty(cx, arg0, &len))
                 return false;
 
             // avoid overflow; we know that offset <= length
-            if (len > tarray->length - offset) {
+            if (len > getLength(tarray) - offset) {
                 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
                                      JSMSG_TYPED_ARRAY_BAD_ARGS);
                 return false;
             }
 
-            if (!copyFrom(cx, obj, arg0, len, offset))
+            if (!copyFromArray(cx, obj, arg0, len, offset))
                 return false;
         }
 
         vp->setUndefined();
         return true;
     }
 
-    static ThisTypeArray *
-    fromJSObject(JSObject *obj)
-    {
-        JS_ASSERT(obj->getClass() == fastClass());
-        return reinterpret_cast<ThisTypeArray*>(obj->getPrivate());
-    }
-
   public:
-    TypedArrayTemplate(JSObject *bufobj, uint32 byteOffset, uint32 len)
-    {
-        JS_ASSERT(bufobj->getClass() == &ArrayBuffer::fastClass);
-
-        type = ArrayTypeID();
-        bufferJS = bufobj;
-        length = 0;
-
-        this->byteOffset = byteOffset;
-
-        JS_ASSERT(byteOffset <= ArrayBuffer::getByteLength(bufferJS));
-        this->data = offsetData(bufferJS, byteOffset);
-        JS_ASSERT(ArrayBuffer::getDataOffset(bufferJS) <= this->data);
-        JS_ASSERT(this->data <= offsetData(bufferJS, ArrayBuffer::getByteLength(bufferJS)));
-
-        this->byteLength = len * sizeof(NativeType);
-        JS_ASSERT(ArrayBuffer::getByteLength(bufferJS) - byteOffset >= this->byteLength);
-
-        this->length = len;
-    }
-
     static JSObject *
     createTypedArrayWithOffsetLength(JSContext *cx, JSObject *other,
                                      int32 byteOffsetInt, int32 lengthInt)
     {
         JS_ASSERT(!js_IsTypedArray(other));
 
         /* Handle creation from an ArrayBuffer not ArrayBuffer.prototype. */
         if (other->getClass() == &ArrayBuffer::fastClass) {
@@ -1231,54 +1231,54 @@ class TypedArrayTemplate
         if (!js_GetLengthProperty(cx, other, &len))
             return NULL;
 
         JSObject *bufobj = createBufferWithSizeAndCount(cx, len);
         if (!bufobj)
             return NULL;
 
         JSObject *obj = createTypedArray(cx, bufobj, 0, len);
-        if (!obj || !copyFrom(cx, obj, other, len))
+        if (!obj || !copyFromArray(cx, obj, other, len))
             return NULL;
         return obj;
     }
 
-    const NativeType
-    getIndex(uint32 index) const
+    static const NativeType
+    getIndex(JSObject *obj, uint32 index)
     {
-        return *(static_cast<const NativeType*>(data) + index);
+        return *(static_cast<const NativeType*>(getDataOffset(obj)) + index);
     }
 
-    void
-    setIndex(uint32 index, NativeType val)
+    static void
+    setIndex(JSObject *obj, uint32 index, NativeType val)
     {
-        *(static_cast<NativeType*>(data) + index) = val;
+        *(static_cast<NativeType*>(getDataOffset(obj)) + index) = val;
     }
 
-    inline void copyIndexToValue(JSContext *cx, uint32 index, Value *vp);
+    static void copyIndexToValue(JSContext *cx, JSObject *tarray, uint32 index, Value *vp);
 
     static JSObject *
-    createSubarray(JSContext *cx, ThisTypeArray *tarray, uint32 begin, uint32 end)
+    createSubarray(JSContext *cx, JSObject *tarray, uint32 begin, uint32 end)
     {
         JS_ASSERT(tarray);
 
         JS_ASSERT(0 <= begin);
-        JS_ASSERT(begin <= tarray->length);
+        JS_ASSERT(begin <= getLength(tarray));
         JS_ASSERT(0 <= end);
-        JS_ASSERT(end <= tarray->length);
+        JS_ASSERT(end <= getLength(tarray));
 
-        JSObject *bufobj = tarray->bufferJS;
+        JSObject *bufobj = getBuffer(tarray);
         JS_ASSERT(bufobj);
 
         JS_ASSERT(begin <= end);
         uint32 length = end - begin;
 
         JS_ASSERT(begin < UINT32_MAX / sizeof(NativeType));
-        JS_ASSERT(UINT32_MAX - begin * sizeof(NativeType) >= tarray->byteOffset);
-        uint32 byteOffset = tarray->byteOffset + begin * sizeof(NativeType);
+        JS_ASSERT(UINT32_MAX - begin * sizeof(NativeType) >= getByteOffset(tarray));
+        uint32 byteOffset = getByteOffset(tarray) + begin * sizeof(NativeType);
 
         return createTypedArray(cx, bufobj, byteOffset, length);
     }
 
   protected:
     static NativeType
     nativeFromValue(JSContext *cx, const Value &v)
     {
@@ -1304,25 +1304,25 @@ class TypedArrayTemplate
 
         if (ArrayTypeIsFloatingPoint())
             return NativeType(js_NaN);
 
         return NativeType(int32(0));
     }
 
     static bool
-    copyFrom(JSContext *cx, JSObject *thisTypedArrayObj,
+    copyFromArray(JSContext *cx, JSObject *thisTypedArrayObj,
              JSObject *ar, jsuint len, jsuint offset = 0)
     {
-        ThisTypeArray *thisTypedArray = fromJSObject(thisTypedArrayObj);
-        JS_ASSERT(thisTypedArray);
+        thisTypedArrayObj = getTypedArray(thisTypedArrayObj);
+        JS_ASSERT(thisTypedArrayObj);
 
-        JS_ASSERT(offset <= thisTypedArray->length);
-        JS_ASSERT(len <= thisTypedArray->length - offset);
-        NativeType *dest = static_cast<NativeType*>(thisTypedArray->data) + offset;
+        JS_ASSERT(offset <= getLength(thisTypedArrayObj));
+        JS_ASSERT(len <= getLength(thisTypedArrayObj) - offset);
+        NativeType *dest = static_cast<NativeType*>(getDataOffset(thisTypedArrayObj)) + offset;
 
         if (ar->isDenseArray() && ar->getDenseArrayCapacity() >= len) {
             JS_ASSERT(ar->getArrayLength() == len);
 
             const Value *src = ar->getDenseArrayElements();
 
             for (uintN i = 0; i < len; ++i)
                 *dest++ = nativeFromValue(cx, *src++);
@@ -1336,173 +1336,173 @@ class TypedArrayTemplate
                 *dest++ = nativeFromValue(cx, v);
             }
         }
 
         return true;
     }
 
     static bool
-    copyFrom(JSContext *cx, JSObject *thisTypedArrayObj, TypedArray *tarray, jsuint offset)
+    copyFromTypedArray(JSContext *cx, JSObject *thisTypedArrayObj, JSObject *tarray, jsuint offset)
     {
-        ThisTypeArray *thisTypedArray = fromJSObject(thisTypedArrayObj);
-        JS_ASSERT(thisTypedArray);
+        thisTypedArrayObj = getTypedArray(thisTypedArrayObj);
+        JS_ASSERT(thisTypedArrayObj);
 
-        JS_ASSERT(offset <= thisTypedArray->length);
-        JS_ASSERT(tarray->length <= thisTypedArray->length - offset);
-        if (tarray->bufferJS == thisTypedArray->bufferJS)
-            return thisTypedArray->copyFromWithOverlap(cx, tarray, offset);
+        JS_ASSERT(offset <= getLength(thisTypedArrayObj));
+        JS_ASSERT(getLength(tarray) <= getLength(thisTypedArrayObj) - offset);
+        if (getBuffer(tarray) == getBuffer(thisTypedArrayObj))
+            return copyFromWithOverlap(cx, thisTypedArrayObj, tarray, offset);
 
-        NativeType *dest = static_cast<NativeType*>(thisTypedArray->data) + offset;
+        NativeType *dest = static_cast<NativeType*>((void*)getDataOffset(thisTypedArrayObj)) + offset;
 
-        if (tarray->type == thisTypedArray->type) {
-            memcpy(dest, tarray->data, tarray->byteLength);
+        if (getType(tarray) == getType(thisTypedArrayObj)) {
+            memcpy(dest, getDataOffset(tarray), getByteLength(tarray));
             return true;
         }
 
-        uintN srclen = tarray->length;
-        switch (tarray->type) {
+        uintN srclen = getLength(tarray);
+        switch (getType(tarray)) {
           case TypedArray::TYPE_INT8: {
-            int8 *src = static_cast<int8*>(tarray->data);
+            int8 *src = static_cast<int8*>(getDataOffset(tarray));
             for (uintN i = 0; i < srclen; ++i)
                 *dest++ = NativeType(*src++);
             break;
           }
           case TypedArray::TYPE_UINT8:
           case TypedArray::TYPE_UINT8_CLAMPED: {
-            uint8 *src = static_cast<uint8*>(tarray->data);
+            uint8 *src = static_cast<uint8*>(getDataOffset(tarray));
             for (uintN i = 0; i < srclen; ++i)
                 *dest++ = NativeType(*src++);
             break;
           }
           case TypedArray::TYPE_INT16: {
-            int16 *src = static_cast<int16*>(tarray->data);
+            int16 *src = static_cast<int16*>(getDataOffset(tarray));
             for (uintN i = 0; i < srclen; ++i)
                 *dest++ = NativeType(*src++);
             break;
           }
           case TypedArray::TYPE_UINT16: {
-            uint16 *src = static_cast<uint16*>(tarray->data);
+            uint16 *src = static_cast<uint16*>(getDataOffset(tarray));
             for (uintN i = 0; i < srclen; ++i)
                 *dest++ = NativeType(*src++);
             break;
           }
           case TypedArray::TYPE_INT32: {
-            int32 *src = static_cast<int32*>(tarray->data);
+            int32 *src = static_cast<int32*>(getDataOffset(tarray));
             for (uintN i = 0; i < srclen; ++i)
                 *dest++ = NativeType(*src++);
             break;
           }
           case TypedArray::TYPE_UINT32: {
-            uint32 *src = static_cast<uint32*>(tarray->data);
+            uint32 *src = static_cast<uint32*>(getDataOffset(tarray));
             for (uintN i = 0; i < srclen; ++i)
                 *dest++ = NativeType(*src++);
             break;
           }
           case TypedArray::TYPE_FLOAT32: {
-            float *src = static_cast<float*>(tarray->data);
+            float *src = static_cast<float*>(getDataOffset(tarray));
             for (uintN i = 0; i < srclen; ++i)
                 *dest++ = NativeType(*src++);
             break;
           }
           case TypedArray::TYPE_FLOAT64: {
-            double *src = static_cast<double*>(tarray->data);
+            double *src = static_cast<double*>(getDataOffset(tarray));
             for (uintN i = 0; i < srclen; ++i)
                 *dest++ = NativeType(*src++);
             break;
           }
           default:
             JS_NOT_REACHED("copyFrom with a TypedArray of unknown type");
             break;
         }
 
         return true;
     }
 
-    bool
-    copyFromWithOverlap(JSContext *cx, TypedArray *tarray, jsuint offset)
+    static bool
+    copyFromWithOverlap(JSContext *cx, JSObject *self, JSObject *tarray, jsuint offset)
     {
-        JS_ASSERT(offset <= length);
+        JS_ASSERT(offset <= getLength(self));
 
-        NativeType *dest = static_cast<NativeType*>(data) + offset;
+        NativeType *dest = static_cast<NativeType*>(getDataOffset(self)) + offset;
 
-        if (tarray->type == type) {
-            memmove(dest, tarray->data, tarray->byteLength);
+        if (getType(tarray) == getType(self)) {
+            memmove(dest, getDataOffset(tarray), getByteLength(tarray));
             return true;
         }
 
         // We have to make a copy of the source array here, since
         // there's overlap, and we have to convert types.
-        void *srcbuf = cx->malloc_(tarray->byteLength);
+        void *srcbuf = cx->malloc_(getLength(tarray));
         if (!srcbuf)
             return false;
-        memcpy(srcbuf, tarray->data, tarray->byteLength);
+        memcpy(srcbuf, getDataOffset(tarray), getByteLength(tarray));
 
-        switch (tarray->type) {
+        switch (getType(tarray)) {
           case TypedArray::TYPE_INT8: {
             int8 *src = (int8*) srcbuf;
-            for (uintN i = 0; i < tarray->length; ++i)
+            for (uintN i = 0; i < getLength(tarray); ++i)
                 *dest++ = NativeType(*src++);
             break;
           }
           case TypedArray::TYPE_UINT8:
           case TypedArray::TYPE_UINT8_CLAMPED: {
             uint8 *src = (uint8*) srcbuf;
-            for (uintN i = 0; i < tarray->length; ++i)
+            for (uintN i = 0; i < getLength(tarray); ++i)
                 *dest++ = NativeType(*src++);
             break;
           }
           case TypedArray::TYPE_INT16: {
             int16 *src = (int16*) srcbuf;
-            for (uintN i = 0; i < tarray->length; ++i)
+            for (uintN i = 0; i < getLength(tarray); ++i)
                 *dest++ = NativeType(*src++);
             break;
           }
           case TypedArray::TYPE_UINT16: {
             uint16 *src = (uint16*) srcbuf;
-            for (uintN i = 0; i < tarray->length; ++i)
+            for (uintN i = 0; i < getLength(tarray); ++i)
                 *dest++ = NativeType(*src++);
             break;
           }
           case TypedArray::TYPE_INT32: {
             int32 *src = (int32*) srcbuf;
-            for (uintN i = 0; i < tarray->length; ++i)
+            for (uintN i = 0; i < getLength(tarray); ++i)
                 *dest++ = NativeType(*src++);
             break;
           }
           case TypedArray::TYPE_UINT32: {
             uint32 *src = (uint32*) srcbuf;
-            for (uintN i = 0; i < tarray->length; ++i)
+            for (uintN i = 0; i < getLength(tarray); ++i)
                 *dest++ = NativeType(*src++);
             break;
           }
           case TypedArray::TYPE_FLOAT32: {
             float *src = (float*) srcbuf;
-            for (uintN i = 0; i < tarray->length; ++i)
+            for (uintN i = 0; i < getLength(tarray); ++i)
                 *dest++ = NativeType(*src++);
             break;
           }
           case TypedArray::TYPE_FLOAT64: {
             double *src = (double*) srcbuf;
-            for (uintN i = 0; i < tarray->length; ++i)
+            for (uintN i = 0; i < getLength(tarray); ++i)
                 *dest++ = NativeType(*src++);
             break;
           }
           default:
             JS_NOT_REACHED("copyFromWithOverlap with a TypedArray of unknown type");
             break;
         }
 
         UnwantedForeground::free_(srcbuf);
         return true;
     }
 
-    void *
+    static void *
     offsetData(JSObject *obj, uint32 offs) {
-        return (void*)(((uint8*)ArrayBuffer::getDataOffset(obj)) + offs);
+        return (void*)(((uint8*)getDataOffset(obj)) + offs);
     }
 
     static JSObject *
     createBufferWithSizeAndCount(JSContext *cx, uint32 count)
     {
         size_t size = sizeof(NativeType);
         if (size != 0 && count >= INT32_MAX / size) {
             JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
@@ -1510,49 +1510,104 @@ class TypedArrayTemplate
             return NULL;
         }
 
         int32 bytelen = size * count;
         return ArrayBuffer::create(cx, bytelen);
     }
 };
 
+class Int8Array : public TypedArrayTemplate<int8> {
+  public:
+    enum { ACTUAL_TYPE = TYPE_INT8 };
+    static const JSProtoKey key = JSProto_Int8Array;
+    static JSFunctionSpec jsfuncs[];
+};
+class Uint8Array : public TypedArrayTemplate<uint8> {
+  public:
+    enum { ACTUAL_TYPE = TYPE_UINT8 };
+    static const JSProtoKey key = JSProto_Uint8Array;
+    static JSFunctionSpec jsfuncs[];
+};
+class Int16Array : public TypedArrayTemplate<int16> {
+  public:
+    enum { ACTUAL_TYPE = TYPE_INT16 };
+    static const JSProtoKey key = JSProto_Int16Array;
+    static JSFunctionSpec jsfuncs[];
+};
+class Uint16Array : public TypedArrayTemplate<uint16> {
+  public:
+    enum { ACTUAL_TYPE = TYPE_UINT16 };
+    static const JSProtoKey key = JSProto_Uint16Array;
+    static JSFunctionSpec jsfuncs[];
+};
+class Int32Array : public TypedArrayTemplate<int32> {
+  public:
+    enum { ACTUAL_TYPE = TYPE_INT32 };
+    static const JSProtoKey key = JSProto_Int32Array;
+    static JSFunctionSpec jsfuncs[];
+};
+class Uint32Array : public TypedArrayTemplate<uint32> {
+  public:
+    enum { ACTUAL_TYPE = TYPE_UINT32 };
+    static const JSProtoKey key = JSProto_Uint32Array;
+    static JSFunctionSpec jsfuncs[];
+};
+class Float32Array : public TypedArrayTemplate<float> {
+  public:
+    enum { ACTUAL_TYPE = TYPE_FLOAT32 };
+    static const JSProtoKey key = JSProto_Float32Array;
+    static JSFunctionSpec jsfuncs[];
+};
+class Float64Array : public TypedArrayTemplate<double> {
+  public:
+    enum { ACTUAL_TYPE = TYPE_FLOAT64 };
+    static const JSProtoKey key = JSProto_Float64Array;
+    static JSFunctionSpec jsfuncs[];
+};
+class Uint8ClampedArray : public TypedArrayTemplate<uint8_clamped> {
+  public:
+    enum { ACTUAL_TYPE = TYPE_UINT8_CLAMPED };
+    static const JSProtoKey key = JSProto_Uint8ClampedArray;
+    static JSFunctionSpec jsfuncs[];
+};
+
 // this default implementation is only valid for integer types
 // less than 32-bits in size.
 template<typename NativeType>
 void
-TypedArrayTemplate<NativeType>::copyIndexToValue(JSContext *cx, uint32 index, Value *vp)
+TypedArrayTemplate<NativeType>::copyIndexToValue(JSContext *cx, JSObject *tarray, uint32 index, Value *vp)
 {
     JS_STATIC_ASSERT(sizeof(NativeType) < 4);
 
-    vp->setInt32(getIndex(index));
+    vp->setInt32(getIndex(tarray, index));
 }
 
 // and we need to specialize for 32-bit integers and floats
 template<>
 void
-TypedArrayTemplate<int32>::copyIndexToValue(JSContext *cx, uint32 index, Value *vp)
+TypedArrayTemplate<int32>::copyIndexToValue(JSContext *cx, JSObject *tarray, uint32 index, Value *vp)
 {
-    int32 val = getIndex(index);
+    int32 val = getIndex(tarray, index);
     vp->setInt32(val);
 }
 
 template<>
 void
-TypedArrayTemplate<uint32>::copyIndexToValue(JSContext *cx, uint32 index, Value *vp)
+TypedArrayTemplate<uint32>::copyIndexToValue(JSContext *cx, JSObject *tarray, uint32 index, Value *vp)
 {
-    uint32 val = getIndex(index);
+    uint32 val = getIndex(tarray, index);
     vp->setNumber(val);
 }
 
 template<>
 void
-TypedArrayTemplate<float>::copyIndexToValue(JSContext *cx, uint32 index, Value *vp)
+TypedArrayTemplate<float>::copyIndexToValue(JSContext *cx, JSObject *tarray, uint32 index, Value *vp)
 {
-    float val = getIndex(index);
+    float val = getIndex(tarray, index);
     double dval = val;
 
     /*
      * Doubles in typed arrays could be typed-punned arrays of integers. This
      * could allow user code to break the engine-wide invariant that only
      * canonical nans are stored into jsvals, which means user code could
      * confuse the engine into interpreting a double-typed jsval as an
      * object-typed jsval.
@@ -1563,19 +1618,19 @@ TypedArrayTemplate<float>::copyIndexToVa
     if (JS_UNLIKELY(JSDOUBLE_IS_NaN(dval)))
         dval = js_NaN;
 
     vp->setDouble(dval);
 }
 
 template<>
 void
-TypedArrayTemplate<double>::copyIndexToValue(JSContext *cx, uint32 index, Value *vp)
+TypedArrayTemplate<double>::copyIndexToValue(JSContext *cx, JSObject *tarray, uint32 index, Value *vp)
 {
-    double val = getIndex(index);
+    double val = getIndex(tarray, index);
 
     /*
      * Doubles in typed arrays could be typed-punned arrays of integers. This
      * could allow user code to break the engine-wide invariant that only
      * canonical nans are stored into jsvals, which means user code could
      * confuse the engine into interpreting a double-typed jsval as an
      * object-typed jsval.
      */
@@ -1672,96 +1727,110 @@ JSPropertySpec TypedArray::jsprops[] = {
     {0,0,0,0,0}
 };
 
 /*
  * TypedArray boilerplate
  */
 
 #define IMPL_TYPED_ARRAY_STATICS(_typedArray)                                  \
-template<> JSFunctionSpec _typedArray::jsfuncs[] = {                           \
-    JS_FN("subarray", _typedArray::fun_subarray, 2, 0),                            \
-    JS_FN("set", _typedArray::fun_set, 2, 0),                                  \
+JSFunctionSpec _typedArray::jsfuncs[] = {                                      \
+    JS_FN("subarray", _typedArray::fun_subarray, 2, JSFUN_GENERIC_NATIVE),     \
+    JS_FN("set", _typedArray::fun_set, 2, JSFUN_GENERIC_NATIVE),               \
     JS_FS_END                                                                  \
 }
 
 #define IMPL_TYPED_ARRAY_SLOW_CLASS(_typedArray)                               \
 {                                                                              \
     #_typedArray,                                                              \
-    JSCLASS_HAS_PRIVATE | JSCLASS_HAS_CACHED_PROTO(JSProto_##_typedArray),     \
+    JSCLASS_HAS_RESERVED_SLOTS(TypedArray::FIELD_MAX) |                        \
+    JSCLASS_HAS_CACHED_PROTO(JSProto_##_typedArray),                           \
     PropertyStub,         /* addProperty */                                    \
     PropertyStub,         /* delProperty */                                    \
     PropertyStub,         /* getProperty */                                    \
     StrictPropertyStub,   /* setProperty */                                    \
     EnumerateStub,                                                             \
     ResolveStub,                                                               \
     ConvertStub,                                                               \
     FinalizeStub                                                               \
 }
 
 #define IMPL_TYPED_ARRAY_FAST_CLASS(_typedArray)                               \
 {                                                                              \
     #_typedArray,                                                              \
-    Class::NON_NATIVE | JSCLASS_HAS_PRIVATE,                                   \
+    JSCLASS_HAS_RESERVED_SLOTS(TypedArray::FIELD_MAX) |                        \
+    Class::NON_NATIVE,                                                         \
     PropertyStub,         /* addProperty */                                    \
     PropertyStub,         /* delProperty */                                    \
     PropertyStub,         /* getProperty */                                    \
     StrictPropertyStub,   /* setProperty */                                    \
     EnumerateStub,                                                             \
     ResolveStub,                                                               \
     ConvertStub,                                                               \
-    _typedArray::class_finalize,                                               \
+    NULL,           /* finalize    */                                          \
     NULL,           /* reserved0   */                                          \
     NULL,           /* checkAccess */                                          \
     NULL,           /* call        */                                          \
     NULL,           /* construct   */                                          \
     NULL,           /* xdrObject   */                                          \
     NULL,           /* hasInstance */                                          \
-    _typedArray::obj_trace,                                                    \
+    _typedArray::obj_trace,           /* trace       */                                          \
     JS_NULL_CLASS_EXT,                                                         \
     {                                                                          \
         _typedArray::obj_lookupProperty,                                       \
         _typedArray::obj_defineProperty,                                       \
         _typedArray::obj_getProperty,                                          \
         _typedArray::obj_setProperty,                                          \
         _typedArray::obj_getAttributes,                                        \
         _typedArray::obj_setAttributes,                                        \
         _typedArray::obj_deleteProperty,                                       \
         _typedArray::obj_enumerate,                                            \
         _typedArray::obj_typeOf,                                               \
         NULL,       /* thisObject      */                                      \
         NULL,       /* clear           */                                      \
     }                                                                          \
 }
 
-#define INIT_TYPED_ARRAY_CLASS(_typedArray,_type)                              \
-do {                                                                           \
-    proto = js_InitClass(cx, obj, NULL,                                        \
-                         &TypedArray::slowClasses[TypedArray::_type],          \
-                         _typedArray::class_constructor, 3,                    \
-                         _typedArray::jsprops,                                 \
-                         _typedArray::jsfuncs,                                 \
-                         NULL, NULL);                                          \
-    if (!proto)                                                                \
-        return NULL;                                                           \
-    JSObject *ctor = JS_GetConstructor(cx, proto);                             \
-    if (!ctor ||                                                               \
-        !JS_DefineProperty(cx, ctor, "BYTES_PER_ELEMENT",                      \
-                           INT_TO_JSVAL(sizeof(_typedArray::ThisType)),        \
-                           JS_PropertyStub, JS_StrictPropertyStub,             \
-                           JSPROP_PERMANENT | JSPROP_READONLY) ||              \
-        !JS_DefineProperty(cx, proto, "BYTES_PER_ELEMENT",                     \
-                           INT_TO_JSVAL(sizeof(_typedArray::ThisType)),        \
-                           JS_PropertyStub, JS_StrictPropertyStub,             \
-                           JSPROP_PERMANENT | JSPROP_READONLY))                \
-    {                                                                          \
-        return NULL;                                                           \
-    }                                                                          \
-    proto->setPrivate(0);                                                      \
-} while (0)
+template<class ArrayType>
+static inline JSObject *
+InitTypedArrayClass(JSContext *cx, GlobalObject *global)
+{
+    JSObject *proto = global->createBlankPrototype(cx, ArrayType::slowClass());
+    if (!proto)
+        return NULL;
+
+    JSFunction *ctor =
+        global->createConstructor(cx, ArrayType::class_constructor, ArrayType::fastClass(),
+                                  cx->runtime->atomState.classAtoms[ArrayType::key], 3);
+    if (!ctor)
+        return NULL;
+
+    if (!LinkConstructorAndPrototype(cx, ctor, proto))
+        return NULL;
+
+    if (!ctor->defineProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.BYTES_PER_ELEMENTAtom),
+                              Int32Value(ArrayType::BYTES_PER_ELEMENT),
+                              PropertyStub, StrictPropertyStub,
+                              JSPROP_PERMANENT | JSPROP_READONLY) ||
+        !proto->defineProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.BYTES_PER_ELEMENTAtom),
+                               Int32Value(ArrayType::BYTES_PER_ELEMENT),
+                               PropertyStub, StrictPropertyStub,
+                               JSPROP_PERMANENT | JSPROP_READONLY))
+    {
+        return NULL;
+    }
+
+    if (!DefinePropertiesAndBrand(cx, proto, ArrayType::jsprops, ArrayType::jsfuncs))
+        return NULL;
+
+    if (!DefineConstructorAndPrototype(cx, global, ArrayType::key, ctor, proto))
+        return NULL;
+
+    return proto;
+}
 
 IMPL_TYPED_ARRAY_STATICS(Int8Array);
 IMPL_TYPED_ARRAY_STATICS(Uint8Array);
 IMPL_TYPED_ARRAY_STATICS(Int16Array);
 IMPL_TYPED_ARRAY_STATICS(Uint16Array);
 IMPL_TYPED_ARRAY_STATICS(Int32Array);
 IMPL_TYPED_ARRAY_STATICS(Uint32Array);
 IMPL_TYPED_ARRAY_STATICS(Float32Array);
@@ -1787,63 +1856,94 @@ Class TypedArray::slowClasses[TYPE_MAX] 
     IMPL_TYPED_ARRAY_SLOW_CLASS(Uint16Array),
     IMPL_TYPED_ARRAY_SLOW_CLASS(Int32Array),
     IMPL_TYPED_ARRAY_SLOW_CLASS(Uint32Array),
     IMPL_TYPED_ARRAY_SLOW_CLASS(Float32Array),
     IMPL_TYPED_ARRAY_SLOW_CLASS(Float64Array),
     IMPL_TYPED_ARRAY_SLOW_CLASS(Uint8ClampedArray)
 };
 
+static JSObject *
+InitArrayBufferClass(JSContext *cx, GlobalObject *global)
+{
+    JSObject *arrayBufferProto = global->createBlankPrototype(cx, &ArrayBuffer::slowClass);
+    if (!arrayBufferProto)
+        return NULL;
+    arrayBufferProto->setPrivate(NULL);
+
+    /* Ensure ArrayBuffer.prototype is correctly empty. */
+    if (!AllocateArrayBufferSlots(cx, arrayBufferProto, 0))
+        return NULL;
+
+    JSFunction *ctor =
+        global->createConstructor(cx, ArrayBuffer::class_constructor, &ArrayBuffer::fastClass,
+                                  CLASS_ATOM(cx, ArrayBuffer), 1);
+    if (!ctor)
+        return NULL;
+
+    if (!LinkConstructorAndPrototype(cx, ctor, arrayBufferProto))
+        return NULL;
+
+    if (!DefinePropertiesAndBrand(cx, arrayBufferProto, ArrayBuffer::jsprops, NULL))
+        return NULL;
+
+    if (!DefineConstructorAndPrototype(cx, global, JSProto_ArrayBuffer, ctor, arrayBufferProto))
+        return NULL;
+
+    return arrayBufferProto;
+}
+
 JS_FRIEND_API(JSObject *)
 js_InitTypedArrayClasses(JSContext *cx, JSObject *obj)
 {
+    JS_ASSERT(obj->isNative());
+
+    GlobalObject *global = obj->asGlobal();
+
     /* Idempotency required: we initialize several things, possibly lazily. */
     JSObject *stop;
-    if (!js_GetClassObject(cx, obj, JSProto_ArrayBuffer, &stop))
+    if (!js_GetClassObject(cx, global, JSProto_ArrayBuffer, &stop))
         return NULL;
     if (stop)
         return stop;
 
-    JSObject *proto;
-
-    INIT_TYPED_ARRAY_CLASS(Int8Array,TYPE_INT8);
-    INIT_TYPED_ARRAY_CLASS(Uint8Array,TYPE_UINT8);
-    INIT_TYPED_ARRAY_CLASS(Int16Array,TYPE_INT16);
-    INIT_TYPED_ARRAY_CLASS(Uint16Array,TYPE_UINT16);
-    INIT_TYPED_ARRAY_CLASS(Int32Array,TYPE_INT32);
-    INIT_TYPED_ARRAY_CLASS(Uint32Array,TYPE_UINT32);
-    INIT_TYPED_ARRAY_CLASS(Float32Array,TYPE_FLOAT32);