Merge m-c to b-s.
authorKyle Huey <khuey@kylehuey.com>
Sun, 11 Sep 2011 05:32:38 -0400
changeset 78317 53f66dd0ebdd4b30e0e4255fa8e5738292fec86e
parent 78316 57d1c50198050d7afdbb28f25a5af803a73c0677 (current diff)
parent 78175 06b2977afb850d41f5cafc384eb5b8f7b2f13ff6 (diff)
child 78318 094d9a3fee33e1df096e530c8937f41b97c2494f
push id78
push userclegnitto@mozilla.com
push dateFri, 16 Dec 2011 17:32:24 +0000
treeherdermozilla-release@79d24e644fdd [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone9.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 m-c to b-s.
configure.in
content/canvas/test/webgl/crossorigin/image-allow-credentials.png
content/canvas/test/webgl/crossorigin/image-allow-credentials.png^headers^
content/canvas/test/webgl/crossorigin/image-allow-star.png
content/canvas/test/webgl/crossorigin/image-allow-star.png^headers^
content/canvas/test/webgl/crossorigin/image.png
content/canvas/test/webgl/crossorigin/test_webgl_crossorigin_textures.html
js/src/Makefile.in
js/src/configure.in
widget/public/nsILookAndFeel.h
xpcom/reflect/xptcall/src/md/unix/Makefile.in
--- a/accessible/src/xul/nsXULMenuAccessible.cpp
+++ b/accessible/src/xul/nsXULMenuAccessible.cpp
@@ -49,27 +49,24 @@
 #include "nsIDOMXULContainerElement.h"
 #include "nsIDOMXULSelectCntrlItemEl.h"
 #include "nsIDOMXULMultSelectCntrlEl.h"
 #include "nsIDOMKeyEvent.h"
 #include "nsIServiceManager.h"
 #include "nsIPresShell.h"
 #include "nsIContent.h"
 #include "nsGUIEvent.h"
-#include "nsILookAndFeel.h"
-#include "nsWidgetsCID.h"
 
 #include "mozilla/Preferences.h"
+#include "mozilla/LookAndFeel.h"
 #include "mozilla/dom/Element.h"
 
 using namespace mozilla;
 using namespace mozilla::a11y;
 
-static NS_DEFINE_CID(kLookAndFeelCID, NS_LOOKANDFEEL_CID);
-
 ////////////////////////////////////////////////////////////////////////////////
 // nsXULSelectableAccessible
 ////////////////////////////////////////////////////////////////////////////////
 
 nsXULSelectableAccessible::
   nsXULSelectableAccessible(nsIContent *aContent, nsIWeakReference *aShell) :
   nsAccessibleWrap(aContent, aShell)
 {
@@ -355,20 +352,18 @@ nsXULMenuitemAccessible::NativeState()
       } // isCollapsed
     } // isSelected
   } // ROLE_COMBOBOX_OPTION
 
   // Set focusable and selectable for items that are available
   // and whose metric setting does allow disabled items to be focused.
   if (state & states::UNAVAILABLE) {
     // Honour the LookAndFeel metric.
-    nsCOMPtr<nsILookAndFeel> lookNFeel(do_GetService(kLookAndFeelCID));
-    PRInt32 skipDisabledMenuItems = 0;
-    lookNFeel->GetMetric(nsILookAndFeel::eMetric_SkipNavigatingDisabledMenuItem,
-                         skipDisabledMenuItems);
+    PRInt32 skipDisabledMenuItems =
+      LookAndFeel::GetInt(LookAndFeel::eIntID_SkipNavigatingDisabledMenuItem);
     // We don't want the focusable and selectable states for combobox items,
     // so exclude them here as well.
     if (skipDisabledMenuItems || isComboboxOption) {
       return state;
     }
   }
   state |= (states::FOCUSABLE | states::SELECTABLE);
 
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -729,29 +729,21 @@ pref("urlclassifier.gethashnoise", 4);
 // The list of tables that use the gethash request to confirm partial results.
 pref("urlclassifier.gethashtables", "goog-phish-shavar,goog-malware-shavar");
 
 // If an urlclassifier table has not been updated in this number of seconds,
 // a gethash request will be forced to check that the result is still in
 // the database.
 pref("urlclassifier.confirm-age", 2700);
 
-#ifdef MOZ_WIDGET_GTK2
-#define RESTRICT_CACHEMAX
-#endif
-#ifdef XP_OS2
-#define RESTRICT_CACHEMAX
-#endif
+// Maximum size of the sqlite3 cache during an update, in bytes
+pref("urlclassifier.updatecachemax", 41943040);
 
-// Maximum size of the sqlite3 cache during an update, in bytes
-#ifdef RESTRICT_CACHEMAX
-pref("urlclassifier.updatecachemax", 104857600);
-#else
-pref("urlclassifier.updatecachemax", -1);
-#endif
+// Maximum size of the sqlite3 cache for lookups, in bytes
+pref("urlclassifier.lookupcachemax", 1048576);
 
 // URL for checking the reason for a malware warning.
 pref("browser.safebrowsing.malware.reportURL", "http://safebrowsing.clients.google.com/safebrowsing/diagnostic?client=%NAME%&hl=%LOCALE%&site=");
 
 #endif
 
 pref("browser.EULA.version", 3);
 pref("browser.rights.version", 3);
--- a/browser/base/content/highlighter.css
+++ b/browser/base/content/highlighter.css
@@ -7,19 +7,20 @@
   top: 0;
   left: 0;
 }
 
 #highlighter-veil-container {
   overflow: hidden;
 }
 
-.highlighter-veil,
-#highlighter-veil-middlebox,
-#highlighter-veil-transparentbox {
+#highlighter-veil-container:not([locked]) > .highlighter-veil,
+#highlighter-veil-container:not([locked]) > #highlighter-veil-middlebox,
+#highlighter-veil-container:not([locked]) > #highlighter-veil-middlebox > .highlighter-veil,
+#highlighter-veil-container:not([locked]) > #highlighter-veil-middlebox > #highlighter-veil-transparentbox {
   -moz-transition-property: width, height;
   -moz-transition-duration: 0.1s;
   -moz-transition-timing-function: linear;
 }
 
 #highlighter-veil-bottombox,
 #highlighter-veil-rightbox {
   -moz-box-flex: 1;
--- a/browser/base/content/inspector.js
+++ b/browser/base/content/inspector.js
@@ -105,31 +105,31 @@ Highlighter.prototype = {
     this.browser = aBrowser;
     let stack = this.browser.parentNode;
     this.win = this.browser.contentWindow;
     this._highlighting = false;
 
     this.highlighterContainer = document.createElement("stack");
     this.highlighterContainer.id = "highlighter-container";
 
-    let veilBox = document.createElement("vbox");
-    veilBox.id = "highlighter-veil-container";
+    this.veilContainer = document.createElement("vbox");
+    this.veilContainer.id = "highlighter-veil-container";
 
     let controlsBox = document.createElement("box");
     controlsBox.id = "highlighter-controls";
 
     // The veil will make the whole page darker except
     // for the region of the selected box.
-    this.buildVeil(veilBox);
+    this.buildVeil(this.veilContainer);
 
     // The controlsBox will host the different interactive
     // elements of the highlighter (buttons, toolbars, ...).
     this.buildControls(controlsBox);
 
-    this.highlighterContainer.appendChild(veilBox);
+    this.highlighterContainer.appendChild(this.veilContainer);
     this.highlighterContainer.appendChild(controlsBox);
 
     stack.appendChild(this.highlighterContainer);
 
     this.browser.addEventListener("resize", this, true);
     this.browser.addEventListener("scroll", this, true);
 
     this.handleResize();
@@ -218,16 +218,17 @@ Highlighter.prototype = {
     this.browser.removeEventListener("scroll", this, true);
     this.browser.removeEventListener("resize", this, true);
     this._highlightRect = null;
     this._highlighting = false;
     this.veilTopBox = null;
     this.veilLeftBox = null;
     this.veilMiddleBox = null;
     this.veilTransparentBox = null;
+    this.veilContainer = null;
     this.node = null;
     this.highlighterContainer.parentNode.removeChild(this.highlighterContainer);
     this.highlighterContainer = null;
     this.win = null
     this.browser = null;
     this.toolbar = null;
   },
 
@@ -920,17 +921,17 @@ var InspectorUI = {
     // if currently editing an attribute value, starting
     // "live inspection" mode closes the editor
     if (this.editingContext)
       this.closeEditor();
 
     document.getElementById("inspector-inspect-toolbutton").checked = true;
     this.attachPageListeners();
     this.inspecting = true;
-    this.highlighter.veilTransparentBox.removeAttribute("locked");
+    this.highlighter.veilContainer.removeAttribute("locked");
   },
 
   /**
    * Stop inspecting webpage, detach page listeners, disable highlighter
    * event listeners.
    * @param aPreventScroll
    *        Prevent scroll in the HTML tree?
    */
@@ -943,17 +944,17 @@ var InspectorUI = {
     document.getElementById("inspector-inspect-toolbutton").checked = false;
     this.detachPageListeners();
     this.inspecting = false;
     if (this.highlighter.node) {
       this.select(this.highlighter.node, true, true, !aPreventScroll);
     } else {
       this.select(null, true, true);
     }
-    this.highlighter.veilTransparentBox.setAttribute("locked", true);
+    this.highlighter.veilContainer.setAttribute("locked", true);
   },
 
   /**
    * Select an object in the tree view.
    * @param aNode
    *        node to inspect
    * @param forceUpdate
    *        force an update?
--- a/browser/base/content/nsContextMenu.js
+++ b/browser/base/content/nsContextMenu.js
@@ -1031,17 +1031,17 @@ nsContextMenu.prototype = {
     this.saveHelper(this.linkURL, this.linkText(), null, true, doc);
   },
 
   sendLink: function() {
     // we don't know the title of the link so pass in an empty string
     MailIntegration.sendMessage( this.linkURL, "" );
   },
 
-  // Backwards-compatability wrapper
+  // Backwards-compatibility wrapper
   saveImage : function() {
     if (this.onCanvas || this.onImage)
         this.saveMedia();
   },
 
   // Save URL of the clicked upon image, video, or audio.
   saveMedia: function() {
     var doc =  this.target.ownerDocument;
@@ -1057,17 +1057,17 @@ nsContextMenu.prototype = {
     }
     else if (this.onVideo || this.onAudio) {
       urlSecurityCheck(this.mediaURL, doc.nodePrincipal);
       var dialogTitle = this.onVideo ? "SaveVideoTitle" : "SaveAudioTitle";
       this.saveHelper(this.mediaURL, null, dialogTitle, false, doc);
     }
   },
 
-  // Backwards-compatability wrapper
+  // Backwards-compatibility wrapper
   sendImage : function() {
     if (this.onCanvas || this.onImage)
         this.sendMedia();
   },
 
   sendMedia: function() {
     MailIntegration.sendMessage(this.mediaURL, "");
   },
--- a/browser/base/content/syncGenericChange.js
+++ b/browser/base/content/syncGenericChange.js
@@ -192,16 +192,17 @@ let Change = {
 
   doChangePassphrase: function Change_doChangePassphrase() {
     let pp = Weave.Utils.normalizePassphrase(this._passphraseBox.value);
     if (this._updatingPassphrase) {
       Weave.Service.passphrase = pp;
       if (Weave.Service.login()) {
         this._updateStatus("change.recoverykey.success", "success");
         Weave.Service.persistLogin();
+        Weave.SyncScheduler.delayedAutoConnect(0);
       }
       else {
         this._updateStatus("new.passphrase.status.incorrect", "error");
       }
     }
     else {
       this._updateStatus("change.recoverykey.label", "active");
 
--- a/browser/base/content/syncSetup.js
+++ b/browser/base/content/syncSetup.js
@@ -108,16 +108,22 @@ var gSyncSetup = {
           Weave.Svc.Obs.add(topic, self[func], self);
         else
           Weave.Svc.Obs.remove(topic, self[func], self);
       });
     };
     addRem(true);
     window.addEventListener("unload", function() addRem(false), false);
 
+    window.setTimeout(function () {
+      // Force Service to be loaded so that engines are registered.
+      // See Bug 670082.
+      Weave.Service;
+    }, 0);
+
     this.captchaBrowser = document.getElementById("captcha");
     this.wizard = document.getElementById("accountSetup");
 
     if (window.arguments && window.arguments[0] == true) {
       // we're resetting sync
       this._resettingSync = true;
       this.wizard.pageIndex = OPTIONS_PAGE;
     }
--- a/browser/base/content/tabview/groupitems.js
+++ b/browser/base/content/tabview/groupitems.js
@@ -706,33 +706,44 @@ GroupItem.prototype = Utils.extend(new I
         }
       });
 
       this.droppable(false);
       this.removeTrenches();
       this._createUndoButton();
     } else
       this.close();
-    
-    this._makeClosestTabActive();
+
+    this._makeLastActiveGroupItemActive();
   },
   
   // ----------
   // Function: _makeClosestTabActive
   // Make the closest tab external to this group active.
   // Used when closing the group.
   _makeClosestTabActive: function GroupItem__makeClosestTabActive() {
     let closeCenter = this.getBounds().center();
     // Find closest tab to make active
     let closestTabItem = UI.getClosestTab(closeCenter);
     if (closestTabItem)
       UI.setActive(closestTabItem);
   },
 
   // ----------
+  // Function: _makeLastActiveGroupItemActive
+  // Makes the last active group item active.
+  _makeLastActiveGroupItemActive: function GroupItem__makeLastActiveGroupItemActive() {
+    let groupItem = GroupItems.getLastActiveGroupItem();
+    if (groupItem)
+      UI.setActive(groupItem);
+    else
+      this._makeClosestTabActive();
+  },
+
+  // ----------
   // Function: closeIfEmpty
   // Closes the group if it's empty, is closable, and autoclose is enabled
   // (see pauseAutoclose()). Returns true if the close occurred and false
   // otherwise.
   closeIfEmpty: function GroupItem_closeIfEmpty() {
     if (this.isEmpty() && !UI._closedLastVisibleTab &&
         !GroupItems.getUnclosableGroupItemId() && !GroupItems._autoclosePaused) {
       this.close();
@@ -1144,19 +1155,19 @@ GroupItem.prototype = Utils.extend(new I
         item.setResizable(true, options.immediately);
 
       // if a blank tab is selected while restoring a tab the blank tab gets
       // removed. we need to keep the group alive for the restored tab.
       if (item.isRemovedAfterRestore)
         options.dontClose = true;
 
       let closed = options.dontClose ? false : this.closeIfEmpty();
-      if (closed)
-        this._makeClosestTabActive();
-      else if (!options.dontArrange) {
+      if (closed) {
+        this._makeLastActiveGroupItemActive();
+      } else if (!options.dontArrange) {
         this.arrange({animate: !options.immediately});
         this._unfreezeItemSize({dontArrange: true});
       }
 
       this._sendToSubscribers("childRemoved",{ groupItemId: this.id, item: item });
     } catch(e) {
       Utils.log(e);
     }
@@ -1939,16 +1950,17 @@ let GroupItems = {
   _cleanupFunctions: [],
   _arrangePaused: false,
   _arrangesPending: [],
   _removingHiddenGroups: false,
   _delayedModUpdates: [],
   _autoclosePaused: false,
   minGroupHeight: 110,
   minGroupWidth: 125,
+  _lastActiveList: null,
 
   // ----------
   // Function: toString
   // Prints [GroupItems] for debug use
   toString: function GroupItems_toString() {
     return "[GroupItems count=" + this.groupItems.length + "]";
   },
 
@@ -1964,16 +1976,18 @@ let GroupItems = {
 
     // make sure any closed tabs are removed from the delay update list
     function handleClose(event) {
       let idx = self._delayedModUpdates.indexOf(event.target);
       if (idx != -1)
         self._delayedModUpdates.splice(idx, 1);
     }
 
+    this._lastActiveList = new MRUList();
+
     AllTabs.register("attrModified", handleAttrModified);
     AllTabs.register("close", handleClose);
     this._cleanupFunctions.push(function() {
       AllTabs.unregister("attrModified", handleAttrModified);
       AllTabs.unregister("close", handleClose);
     });
   },
 
@@ -2307,16 +2321,17 @@ let GroupItems = {
 
     if (groupItem == this._activeGroupItem)
       this._activeGroupItem = null;
 
     this._arrangesPending = this._arrangesPending.filter(function (pending) {
       return groupItem != pending.groupItem;
     });
 
+    this._lastActiveList.remove(groupItem);
     UI.updateTabButton();
   },
 
   // ----------
   // Function: groupItem
   // Given some sort of identifier, returns the appropriate groupItem.
   // Currently only supports groupItem ids.
   groupItem: function GroupItems_groupItem(a) {
@@ -2418,21 +2433,32 @@ let GroupItems = {
   setActiveGroupItem: function GroupItems_setActiveGroupItem(groupItem) {
     Utils.assert(groupItem, "groupItem must be given");
 
     if (this._activeGroupItem)
       iQ(this._activeGroupItem.container).removeClass('activeGroupItem');
 
     iQ(groupItem.container).addClass('activeGroupItem');
 
+    this._lastActiveList.update(groupItem);
     this._activeGroupItem = groupItem;
     this._save();
   },
 
   // ----------
+  // Function: getLastActiveGroupItem
+  // Gets last active group item.
+  // Returns the <groupItem>. If nothing is found, return null.
+  getLastActiveGroupItem: function GroupItem_getLastActiveGroupItem() {
+    return this._lastActiveList.peek(function(groupItem) {
+      return (groupItem && !groupItem.hidden && groupItem.getChildren().length > 0)
+    });
+  },
+
+  // ----------
   // Function: _updateTabBar
   // Hides and shows tabs in the tab bar based on the active groupItem
   _updateTabBar: function GroupItems__updateTabBar() {
     if (!window.UI)
       return; // called too soon
 
     Utils.assert(this._activeGroupItem, "There must be something to show in the tab bar!");
 
--- a/browser/base/content/tabview/modules/utils.jsm
+++ b/browser/base/content/tabview/modules/utils.jsm
@@ -45,17 +45,17 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 "use strict";
 
 // **********
 // Title: utils.js
 
-let EXPORTED_SYMBOLS = ["Point", "Rect", "Range", "Subscribable", "Utils"];
+let EXPORTED_SYMBOLS = ["Point", "Rect", "Range", "Subscribable", "Utils", "MRUList"];
 
 // #########
 const Ci = Components.interfaces;
 const Cu = Components.utils;
 
 Cu.import("resource://gre/modules/Services.jsm");
 
 // ##########
@@ -790,8 +790,68 @@ let Utils = {
       try {
         return args[i]();
       } catch (e) {}
     }
 
     return null;
   }
 };
+
+// ##########
+// Class: MRUList
+// A most recently used list.
+//
+// Constructor: MRUList
+// If a is an array of entries, creates a copy of it.
+function MRUList(a) {
+  if (Array.isArray(a))
+    this._list = a.concat();
+  else
+    this._list = [];
+};
+
+MRUList.prototype = {
+  // ----------
+  // Function: toString
+  // Prints [List (entry1, entry2, ...)] for debug use
+  toString: function MRUList_toString() {
+    return "[List (" + this._list.join(", ") + ")]";
+  },
+
+  // ----------
+  // Function: update
+  // Updates/inserts the given entry as the most recently used one in the list.
+  update: function MRUList_update(entry) {
+    this.remove(entry);
+    this._list.unshift(entry);
+  },
+
+  // ----------
+  // Function: remove
+  // Removes the given entry from the list.
+  remove: function MRUList_remove(entry) {
+    let index = this._list.indexOf(entry);
+    if (index > -1)
+      this._list.splice(index, 1);
+  },
+
+  // ----------
+  // Function: peek
+  // Returns the most recently used entry.  If a filter exists, gets the most 
+  // recently used entry which matches the filter.
+  peek: function MRUList_peek(filter) {
+    let match = null;
+    if (filter && typeof filter == "function")
+      this._list.some(function MRUList_peek_getEntry(entry) {
+        if (filter(entry)) {
+          match = entry
+          return true;
+        }
+        return false;
+      });
+    else 
+      match = this._list.length > 0 ? this._list[0] : null;
+
+    return match;
+  },
+};
+
--- a/browser/base/content/test/browser_sanitize-download-history.js
+++ b/browser/base/content/test/browser_sanitize-download-history.js
@@ -68,17 +68,17 @@ function test()
   {
     let doc = aWin.document;
     let downloads = doc.getElementById("downloads-checkbox");
     let history = doc.getElementById("history-checkbox");
 
     // Add download to DB
     let file = Cc["@mozilla.org/file/directory_service;1"].
                getService(Ci.nsIProperties).get("TmpD", Ci.nsIFile);
-    file.append("satitize-dm-test.file");
+    file.append("sanitize-dm-test.file");
     file.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0666);
     let testPath = Services.io.newFileURI(file).spec;
     let data = {
       name: "381603.patch",
       source: "https://bugzilla.mozilla.org/attachment.cgi?id=266520",
       target: testPath,
       startTime: 1180493839859230,
       endTime: 1180493839859239,
--- a/browser/base/content/test/tabview/Makefile.in
+++ b/browser/base/content/test/tabview/Makefile.in
@@ -125,16 +125,17 @@ include $(topsrcdir)/config/rules.mk
                  browser_tabview_bug630157.js \
                  browser_tabview_bug631662.js \
                  browser_tabview_bug631752.js \
                  browser_tabview_bug633788.js \
                  browser_tabview_bug634077.js \
                  browser_tabview_bug634085.js \
                  browser_tabview_bug634672.js \
                  browser_tabview_bug635696.js \
+                 browser_tabview_bug637840.js \
                  browser_tabview_bug640765.js \
                  browser_tabview_bug641802.js \
                  browser_tabview_bug642793.js \
                  browser_tabview_bug643392.js \
                  browser_tabview_bug644097.js \
                  browser_tabview_bug648882.js \
                  browser_tabview_bug649006.js \
                  browser_tabview_bug649307.js \
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/tabview/browser_tabview_bug637840.js
@@ -0,0 +1,92 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+let cw;
+
+function test() {
+  waitForExplicitFinish();
+
+  newWindowWithTabView(function(win) {
+    registerCleanupFunction(function() {
+      win.close();
+    });
+
+    cw = win.TabView.getContentWindow();
+
+    let groupItemOne = cw.GroupItems.groupItems[0];
+    is(groupItemOne.getChildren().length, 1, "Group one has 1 tab item");
+
+    let groupItemTwo = createGroupItemWithBlankTabs(win, 300, 300, 40, 2);
+    is(groupItemTwo.getChildren().length, 2, "Group two has 2 tab items");
+
+    let groupItemThree = createGroupItemWithBlankTabs(win, 300, 300, 40, 2);
+    is(groupItemThree.getChildren().length, 2, "Group three has 2 tab items");
+
+    testMoreRecentlyUsedGroup(groupItemOne, groupItemTwo, function() {
+      testMoreRecentlyUsedGroup(groupItemOne, groupItemThree, function() {
+        testRemoveGroupAndCheckMoreRecentlyUsedGroup(groupItemOne, groupItemTwo);
+      });
+    });
+  });
+}
+
+function testMoreRecentlyUsedGroup(groupItemOne, otherGroupItem, callback) {
+  let tabItem = otherGroupItem.getChild(1);
+  cw.UI.setActive(tabItem);
+  is(otherGroupItem.getActiveTab(), tabItem, "The second item in the other group is active");
+  is(cw.GroupItems.getActiveGroupItem(), otherGroupItem, "The other group is active");
+
+  let tabItemInGroupItemOne = groupItemOne.getChild(0);
+  cw.UI.setActive(tabItemInGroupItemOne);
+  is(groupItemOne.getActiveTab(), tabItemInGroupItemOne, "The first item in group one is active");
+  is(cw.GroupItems.getActiveGroupItem(), groupItemOne, "The group one is active");
+
+  groupItemOne.addSubscriber("groupHidden", function onHide() {
+    groupItemOne.removeSubscriber("groupHidden", onHide);
+
+    // group item three should have the focus
+    is(otherGroupItem.getActiveTab(), tabItem, "The second item in the other group is active after group one is hidden");
+    is(cw.GroupItems.getActiveGroupItem(), otherGroupItem, "The other group is active active after group one is hidden");
+
+    groupItemOne.addSubscriber("groupShown", function onShown() {
+      groupItemOne.removeSubscriber("groupShown", onShown);
+
+      is(groupItemOne.getActiveTab(), tabItemInGroupItemOne, "The first item in group one is active after it is shown");
+      is(cw.GroupItems.getActiveGroupItem(), groupItemOne, "The group one is active after it is shown");
+
+      callback();
+    });
+    // click on the undo button
+    EventUtils.sendMouseEvent(
+      { type: "click" }, groupItemOne.$undoContainer[0], cw);
+  });
+  // click on the close button of group item one
+  let closeButton = groupItemOne.container.getElementsByClassName("close");
+  ok(closeButton[0], "Group item one close button exists");
+  EventUtils.sendMouseEvent({ type: "click" }, closeButton[0], cw);
+}
+
+function testRemoveGroupAndCheckMoreRecentlyUsedGroup(groupItemOne, groupItemTwo) {
+  let tabItem = groupItemTwo.getChild(0);
+  cw.UI.setActive(tabItem);
+
+  is(groupItemTwo.getActiveTab(), tabItem, "The first item in the group two is active");
+  is(cw.GroupItems.getActiveGroupItem(), groupItemTwo, "The group two is active");
+
+  let tabItemInGroupItemOne = groupItemOne.getChild(0);
+
+  tabItemInGroupItemOne.addSubscriber("close", function onClose() {
+    tabItemInGroupItemOne.removeSubscriber("close", onClose);
+
+    is(groupItemTwo.getActiveTab(), tabItem, "The first item in the group two is still active after group one is closed");
+    is(cw.GroupItems.getActiveGroupItem(), groupItemTwo, "The group two is still active after group one is closed");
+
+    finish();
+  });
+  // close the tab item and the group item
+  let closeButton = tabItemInGroupItemOne.container.getElementsByClassName("close");
+  ok(closeButton[0], "Tab item close button exists");
+  EventUtils.sendMouseEvent({ type: "mousedown" }, closeButton[0], cw);
+  EventUtils.sendMouseEvent({ type: "mouseup" }, closeButton[0], cw);
+}
+
--- a/browser/branding/official/pref/firefox-branding.js
+++ b/browser/branding/official/pref/firefox-branding.js
@@ -1,9 +1,10 @@
-pref("startup.homepage_override_url","http://www.mozilla.com/%LOCALE%/%APP%/%VERSION%/whatsnew/");
+// Fight update fatigue by suppressing whatsnew tab opening after update (bug 685727)
+pref("startup.homepage_override_url","");
 pref("startup.homepage_welcome_url","http://www.mozilla.com/%LOCALE%/%APP%/%VERSION%/firstrun/");
 // Interval: Time between checks for a new version (in seconds)
 // nightly=6 hours, official=24 hours
 pref("app.update.interval", 86400);
 // The time interval between the downloading of mar file chunks in the
 // background (in seconds)
 pref("app.update.download.backgroundInterval", 600);
 // URL user can browse to manually if for some reason all update installation
--- a/browser/components/feeds/src/nsFeedSniffer.cpp
+++ b/browser/components/feeds/src/nsFeedSniffer.cpp
@@ -124,61 +124,28 @@ nsFeedSniffer::ConvertEncodedData(nsIReq
 template<int N>
 static PRBool
 StringBeginsWithLowercaseLiteral(nsAString& aString,
                                  const char (&aSubstring)[N])
 {
   return StringHead(aString, N).LowerCaseEqualsLiteral(aSubstring);
 }
 
-// XXXsayrer put this in here to get on the branch with minimal delay.
-// Trunk really needs to factor this out. This is the third usage.
 PRBool
 HasAttachmentDisposition(nsIHttpChannel* httpChannel)
 {
   if (!httpChannel)
     return PR_FALSE;
-  
-  nsCAutoString contentDisposition;
-  nsresult rv = 
-    httpChannel->GetResponseHeader(NS_LITERAL_CSTRING("content-disposition"),
-                                   contentDisposition);
-  
-  if (NS_SUCCEEDED(rv) && !contentDisposition.IsEmpty()) {
-    nsCOMPtr<nsIURI> uri;
-    httpChannel->GetURI(getter_AddRefs(uri));
-    nsCOMPtr<nsIMIMEHeaderParam> mimehdrpar =
-      do_GetService(NS_MIMEHEADERPARAM_CONTRACTID, &rv);
-    if (NS_SUCCEEDED(rv))
-    {
-      nsCAutoString fallbackCharset;
-      if (uri)
-        uri->GetOriginCharset(fallbackCharset);
-      nsAutoString dispToken;
-      // Get the disposition type
-      rv = mimehdrpar->GetParameter(contentDisposition, "", fallbackCharset,
-                                    PR_TRUE, nsnull, dispToken);
-      // RFC 2183, section 2.8 says that an unknown disposition
-      // value should be treated as "attachment"
-      // XXXbz this code is duplicated in GetFilenameAndExtensionFromChannel in
-      // nsExternalHelperAppService.  Factor it out!
-      if (NS_FAILED(rv) || 
-          (!dispToken.IsEmpty() &&
-           !StringBeginsWithLowercaseLiteral(dispToken, "inline") &&
-           // Broken sites just send
-           // Content-Disposition: filename="file"
-           // without a disposition token... screen those out.
-           !StringBeginsWithLowercaseLiteral(dispToken, "filename") &&
-           // Also in use is Content-Disposition: name="file"
-           !StringBeginsWithLowercaseLiteral(dispToken, "name")))
-        // We have a content-disposition of "attachment" or unknown
-        return PR_TRUE;
-    }
-  } 
-  
+
+  PRUint32 disp;
+  nsresult rv = httpChannel->GetContentDisposition(&disp);
+
+  if (NS_SUCCEEDED(rv) && disp == nsIChannel::DISPOSITION_ATTACHMENT)
+    return PR_TRUE;
+
   return PR_FALSE;
 }
 
 /**
  * @return the first occurrence of a character within a string buffer,
  *         or nsnull if not found
  */
 static const char*
--- a/browser/devtools/styleinspector/CssHtmlTree.jsm
+++ b/browser/devtools/styleinspector/CssHtmlTree.jsm
@@ -42,17 +42,17 @@
 const Cu = Components.utils;
 
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/PluralForm.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource:///modules/devtools/CssLogic.jsm");
 Cu.import("resource:///modules/devtools/Templater.jsm");
 
-var EXPORTED_SYMBOLS = ["CssHtmlTree"];
+var EXPORTED_SYMBOLS = ["CssHtmlTree", "PropertyView"];
 
 /**
  * CssHtmlTree is a panel that manages the display of a table sorted by style.
  * There should be one instance of CssHtmlTree per style display (of which there
  * will generally only be one).
  *
  * @params {Document} aStyleWin The main XUL browser document
  * @params {CssLogic} aCssLogic How we dig into the CSS. See CssLogic.jsm
@@ -337,42 +337,42 @@ PropertyView.prototype = {
    */
   get propertyInfo()
   {
     return this.tree.cssLogic.getPropertyInfo(this.name);
   },
 
   /**
    * Compute the title of the property view. The title includes the number of
-   * rules that hold the current property.
+   * selectors that match the currently selected element.
    *
    * @param {nsIDOMElement} aElement reference to the DOM element where the rule
    * title needs to be displayed.
    * @return {string} The rule title.
    */
   ruleTitle: function PropertyView_ruleTitle(aElement)
   {
     let result = "";
-    let matchedRuleCount = this.propertyInfo.matchedRuleCount;
+    let matchedSelectorCount = this.propertyInfo.matchedSelectors.length;
 
-    if (matchedRuleCount > 0) {
+    if (matchedSelectorCount > 0) {
       aElement.classList.add("rule-count");
       aElement.firstElementChild.className = "expander";
 
-      let str = CssHtmlTree.l10n("property.numberOfRules");
-      result = PluralForm.get(matchedRuleCount, str)
-          .replace("#1", matchedRuleCount);
+      let str = CssHtmlTree.l10n("property.numberOfSelectors");
+      result = PluralForm.get(matchedSelectorCount, str)
+          .replace("#1", matchedSelectorCount);
     } else if (this.showUnmatchedLink) {
       aElement.classList.add("rule-unmatched");
       aElement.firstElementChild.className = "expander";
 
-      let unmatchedRuleCount = this.propertyInfo.unmatchedRuleCount;
-      let str = CssHtmlTree.l10n("property.numberOfUnmatchedRules");
-      result = PluralForm.get(unmatchedRuleCount, str)
-          .replace("#1", unmatchedRuleCount);
+      let unmatchedSelectorCount = this.propertyInfo.unmatchedSelectors.length;
+      let str = CssHtmlTree.l10n("property.numberOfUnmatchedSelectors");
+      result = PluralForm.get(unmatchedSelectorCount, str)
+          .replace("#1", unmatchedSelectorCount);
     }
     return result;
   },
 
   /**
    * Close the property view.
    */
   close: function PropertyView_close()
@@ -424,18 +424,19 @@ PropertyView.prototype = {
 
   /**
    * The UI has a link to allow the user to display unmatched selectors.
    * This provides localized link text.
    */
   get showUnmatchedLinkText()
   {
     let smur = CssHtmlTree.l10n("rule.showUnmatchedLink");
-    let plural = PluralForm.get(this.propertyInfo.unmatchedRuleCount, smur);
-    return plural.replace("#1", this.propertyInfo.unmatchedRuleCount);
+    let unmatchedSelectorCount = this.propertyInfo.unmatchedSelectors.length;
+    let plural = PluralForm.get(unmatchedSelectorCount, smur);
+    return plural.replace("#1", unmatchedSelectorCount);
   },
 
   /**
    * The action when a user clicks the 'show unmatched' link.
    */
   showUnmatchedLinkClick: function PropertyView_showUnmatchedLinkClick(aEvent)
   {
     this.showUnmatched = true;
--- a/browser/devtools/styleinspector/CssLogic.jsm
+++ b/browser/devtools/styleinspector/CssLogic.jsm
@@ -736,16 +736,18 @@ function CssSheet(aCssLogic, aDomSheet, 
 
   // Cached CssRules from the given stylesheet.
   this._rules = {};
 
   this._ruleCount = -1;
 }
 
 CssSheet.prototype = {
+  _passId: null,
+
   /**
    * Get a source for a stylesheet, taking into account embedded stylesheets
    * for which we need to use document.defaultView.location.href rather than
    * sheet.href
    *
    * @return {string} the address of the stylesheet.
    */
   get href()
@@ -945,16 +947,18 @@ function CssRule(aCssSheet, aDomRule, aE
     this.source = CssLogic.l10n("rule.sourceElement");
     this.href = "#";
     this.systemRule = false;
     this.sourceElement = aElement;
   }
 }
 
 CssRule.prototype = {
+  _passId: null,
+
   /**
    * Check if the parent stylesheet is allowed by the CssLogic.sourceFilter.
    *
    * @return {boolean} true if the parent stylesheet is allowed by the current
    * sourceFilter, or false otherwise.
    */
   get sheetAllowed()
   {
@@ -1086,16 +1090,18 @@ function CssSelector(aCssRule, aSelector
 {
   this._cssRule = aCssRule;
   this.text = aSelector;
   this.elementStyle = this.text == "@element.style";
   this._specificity = null;
 }
 
 CssSelector.prototype = {
+  _matchId: null,
+
   /**
    * Retrieve the CssSelector source, which is the source of the CssSheet owning
    * the selector.
    *
    * @return {string} the selector source.
    */
   get source()
   {
--- a/browser/devtools/styleinspector/StyleInspector.jsm
+++ b/browser/devtools/styleinspector/StyleInspector.jsm
@@ -84,43 +84,58 @@ var StyleInspector = {
     let vbox = win.document.createElement("vbox");
     vbox.setAttribute("flex", "1");
     panel.appendChild(vbox);
 
     let iframe = win.document.createElementNS(ns, "iframe");
     iframe.setAttribute("flex", "1");
     iframe.setAttribute("tooltip", "aHTMLTooltip");
     iframe.setAttribute("src", "chrome://browser/content/csshtmltree.xhtml");
+    iframe.addEventListener("load", SI_iframeOnload, true);
     vbox.appendChild(iframe);
 
     let hbox = win.document.createElement("hbox");
     hbox.setAttribute("class", "resizerbox");
     vbox.appendChild(hbox);
 
     let spacer = win.document.createElement("spacer");
     spacer.setAttribute("flex", "1");
     hbox.appendChild(spacer);
 
     let resizer = win.document.createElement("resizer");
     resizer.setAttribute("dir", "bottomend");
     hbox.appendChild(resizer);
     popupSet.appendChild(panel);
 
     /**
+     * Iframe's onload event
+     */
+    let iframeReady = false;
+    function SI_iframeOnload() {
+      iframe.removeEventListener("load", SI_iframeOnload, true);
+      panel.cssLogic = new CssLogic();
+      panel.cssHtmlTree = new CssHtmlTree(iframe, panel.cssLogic, panel);
+      iframeReady = true;
+      if (panelReady) {
+        SI_popupShown.call(panel);
+      }
+    }
+
+    /**
      * Initialize the popup when it is first shown
      */
+    let panelReady = false;
     function SI_popupShown() {
-      if (!this.cssHtmlTree) {
-        this.cssLogic = new CssLogic();
-        this.cssHtmlTree = new CssHtmlTree(iframe, this.cssLogic, this);
+      panelReady = true;
+      if (iframeReady) {
+        let selectedNode = this.selectedNode || null;
+        this.cssLogic.highlight(selectedNode);
+        this.cssHtmlTree.highlight(selectedNode);
+        Services.obs.notifyObservers(null, "StyleInspector-opened", null);
       }
-
-      this.cssLogic.highlight(this.selectedNode);
-      this.cssHtmlTree.highlight(this.selectedNode);
-      Services.obs.notifyObservers(null, "StyleInspector-opened", null);
     }
 
     /**
      * Hide the popup and conditionally destroy it
      */
     function SI_popupHidden() {
       if (panel.preserveOnHide) {
         Services.obs.notifyObservers(null, "StyleInspector-closed", null);
--- a/browser/devtools/styleinspector/test/browser/Makefile.in
+++ b/browser/devtools/styleinspector/test/browser/Makefile.in
@@ -43,20 +43,22 @@ VPATH     = @srcdir@
 relativesrcdir  = browser/devtools/styleinspector/test/browser
 
 include $(DEPTH)/config/autoconf.mk
 include $(topsrcdir)/config/rules.mk
 
 _BROWSER_TEST_FILES = \
   browser_styleinspector.js \
   browser_styleinspector_webconsole.js \
+  browser_bug683672.js \
   head.js \
   $(NULL)
 
 _BROWSER_TEST_PAGES = \
   browser_styleinspector_webconsole.htm \
+  browser_bug683672.html \
   $(NULL)
 
 libs:: $(_BROWSER_TEST_FILES)
 	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/browser/$(relativesrcdir)
 
 libs:: $(_BROWSER_TEST_PAGES)
 	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/browser/$(relativesrcdir)
new file mode 100644
--- /dev/null
+++ b/browser/devtools/styleinspector/test/browser/browser_bug683672.html
@@ -0,0 +1,32 @@
+<!-- Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/ -->
+<html>
+  <head>
+    <style>
+      .matched1, .matched2, .matched3, .matched4, .matched5 {
+        color: #000;
+      }
+
+      .unmatched1, .unmatched2, .unmatched3, .unmatched4, .unmatched5, .unmatched6, .unmatched7 {
+        color: #f00;
+      }
+
+      div {
+        position: absolute;
+        top: 40px;
+        left: 20px;
+        border: 1px solid #000;
+        color: #111;
+        width: 100px;
+        height: 50px;
+      }
+    </style>
+  </head>
+  <body>
+    inspectstyle($("test"));
+    <div id="test" class="matched1 matched2 matched3 matched4 matched5">Test div</div>
+    <div id="dummy">
+      <div></div>
+    </div>
+  </body>
+</html>
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/browser/devtools/styleinspector/test/browser/browser_bug683672.js
@@ -0,0 +1,115 @@
+/* vim: set ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Tests that the style inspector works properly
+
+let doc;
+let stylePanel;
+
+const TEST_URI = "http://example.com/browser/browser/devtools/styleinspector/test/browser/browser_bug683672.html";
+
+Cu.import("resource:///modules/devtools/CssHtmlTree.jsm");
+
+function test()
+{
+  waitForExplicitFinish();
+  addTab(TEST_URI);
+  browser.addEventListener("load", tabLoaded, true);
+}
+
+function tabLoaded()
+{
+  ok(window.StyleInspector, "StyleInspector exists");
+  ok(StyleInspector.isEnabled, "style inspector preference is enabled");
+  stylePanel = StyleInspector.createPanel();
+  Services.obs.addObserver(runTests, "StyleInspector-opened", false);
+  stylePanel.openPopup();
+}
+
+function runTests()
+{
+  Services.obs.removeObserver(runTests, "StyleInspector-opened", false);
+
+  ok(stylePanel.isOpen(), "style inspector is open");
+
+  testMatchedSelectors();
+  testUnmatchedSelectors();
+
+  info("finishing up");
+  Services.obs.addObserver(finishUp, "StyleInspector-closed", false);
+  stylePanel.hidePopup();
+}
+
+function testMatchedSelectors()
+{
+  info("checking selector counts, matched rules and titles");
+  let div = content.document.getElementById("test");
+  ok(div, "captain, we have the div");
+
+  info("selecting the div");
+  stylePanel.selectNode(div);
+
+  let htmlTree = stylePanel.cssHtmlTree;
+
+  is(div, htmlTree.viewedElement,
+      "style inspector node matches the selected node");
+
+  let propertyView = new PropertyView(htmlTree, "color");
+  let numMatchedSelectors = propertyView.propertyInfo.matchedSelectors.length;
+
+  is(numMatchedSelectors, 6,
+      "CssLogic returns the correct number of matched selectors for div");
+
+  let dummy = content.document.getElementById("dummy");
+  let returnedRuleTitle = propertyView.ruleTitle(dummy);
+  let str = CssHtmlTree.l10n("property.numberOfSelectors");
+  let calculatedRuleTitle = PluralForm.get(numMatchedSelectors, str)
+                                      .replace("#1", numMatchedSelectors);
+
+  info("returnedRuleTitle: '" + returnedRuleTitle + "'");
+
+  is(returnedRuleTitle, calculatedRuleTitle,
+      "returned title for matched rules is correct");
+}
+
+function testUnmatchedSelectors()
+{
+  info("checking selector counts, unmatched rules and titles");
+  let body = content.document.body;
+  ok(body, "captain, we have a body");
+
+  info("selecting content.document.body");
+  stylePanel.selectNode(body);
+
+  let htmlTree = stylePanel.cssHtmlTree;
+
+  is(body, htmlTree.viewedElement,
+      "style inspector node matches the selected node");
+
+  let propertyView = new PropertyView(htmlTree, "color");
+  let numUnmatchedSelectors = propertyView.propertyInfo.unmatchedSelectors.length;
+
+  is(numUnmatchedSelectors, 13,
+      "CssLogic returns the correct number of unmatched selectors for body");
+
+  let dummy = content.document.getElementById("dummy");
+  let returnedRuleTitle = propertyView.ruleTitle(dummy);
+  let str = CssHtmlTree.l10n("property.numberOfUnmatchedSelectors");
+  let calculatedRuleTitle = PluralForm.get(numUnmatchedSelectors, str)
+                                      .replace("#1", numUnmatchedSelectors);
+
+  info("returnedRuleTitle: '" + returnedRuleTitle + "'");
+
+  is(returnedRuleTitle, calculatedRuleTitle,
+      "returned title for unmatched rules is correct");
+}
+
+function finishUp()
+{
+  Services.obs.removeObserver(finishUp, "StyleInspector-closed", false);
+  ok(!stylePanel.isOpen(), "style inspector is closed");
+  doc = stylePanel = null;
+  gBrowser.removeCurrentTab();
+  finish();
+}
--- a/browser/devtools/webconsole/HUDService.jsm
+++ b/browser/devtools/webconsole/HUDService.jsm
@@ -3610,30 +3610,36 @@ HeadsUpDisplay.prototype = {
         ]
       }
     ];
 
     let toolbar = this.makeXULNode("toolbar");
     toolbar.setAttribute("class", "hud-console-filter-toolbar");
     toolbar.setAttribute("mode", "full");
 
+#ifdef XP_MAC
     this.makeCloseButton(toolbar);
+#endif
 
     for (let i = 0; i < BUTTONS.length; i++) {
       this.makeFilterButton(toolbar, BUTTONS[i]);
     }
 
     toolbar.appendChild(this.filterSpacer);
 
     let positionUI = this.createPositionUI();
     toolbar.appendChild(positionUI);
 
     toolbar.appendChild(this.filterBox);
     this.makeClearConsoleButton(toolbar);
 
+#ifndef XP_MAC
+    this.makeCloseButton(toolbar);
+#endif
+
     return toolbar;
   },
 
   /**
    * Creates the UI for re-positioning the console
    *
    * @return nsIDOMNode
    *         The toolbarbutton which holds the menu that allows the user to
--- a/browser/devtools/webconsole/Makefile.in
+++ b/browser/devtools/webconsole/Makefile.in
@@ -40,22 +40,25 @@
 DEPTH		= ../../..
 topsrcdir	= @top_srcdir@
 srcdir		= @srcdir@
 VPATH		= @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
 EXTRA_JS_MODULES = \
-		HUDService.jsm \
 		PropertyPanel.jsm \
 		NetworkHelper.jsm \
 		AutocompletePopup.jsm \
 		gcli.jsm \
 		$(NULL)
 
+EXTRA_PP_JS_MODULES = \
+		HUDService.jsm \
+		$(NULL)
+
 ifdef ENABLE_TESTS
 ifneq (mobile,$(MOZ_BUILD_APP))
 	DIRS += test
 endif
 endif
 
 include $(topsrcdir)/config/rules.mk
--- a/browser/locales/en-US/chrome/browser/styleinspector.properties
+++ b/browser/locales/en-US/chrome/browser/styleinspector.properties
@@ -1,26 +1,25 @@
 # LOCALIZATION NOTE These strings are used inside the Style Inspector.
 
 # LOCALIZATION NOTE (panelTitle): This is the panel title
 panelTitle=Style Inspector
 
-# LOCALIZATION NOTE (property.numberOfRules): For each style property the panel
-# shows the number of rules which hold that specific property, counted from all
-# of the stylesheets in the web page inspected.
+# LOCALIZATION NOTE (property.numberOfSelectors): For each style property the
+# panel shows the number of selectors which match the currently selected
+# element, counted from all stylesheets in the web page inspected.
 # See: http://developer.mozilla.org/en/docs/Localization_and_Plurals
-property.numberOfRules=#1 rule;#1 rules
+property.numberOfSelectors=1 selector;#1 selectors
 
-# LOCALIZATION NOTE (property.numberOfUnmatchedRules): Each style property is
-# inside a rule. A rule is a selector that can match (or not) the highlighted
-# element in the web page. The property view shows no unmatched rules. If the
-# user wants to expand the property to view unmatched rules, he/she must click
-# this link displayed to the right of each property.
+# LOCALIZATION NOTE (property.numberOfUnmatchedSelectors): For each style
+# property the panel shows the number of selectors which do not match the
+# currently selected element, counted from all stylesheets in the web page
+# inspected.
 # See: http://developer.mozilla.org/en/docs/Localization_and_Plurals
-property.numberOfUnmatchedRules=One unmatched rule;#1 unmatched rules
+property.numberOfUnmatchedSelectors=1 unmatched selector;#1 unmatched selectors
 
 # LOCALIZATION NOTE (rule.status): For each style property the panel shows
 # the rules which hold that specific property. For every rule, the rule status
 # is also displayed: a rule can be the best match, a match, a parent match, or a
 # rule did not match the element the user has highlighted.
 rule.status.BEST=Best Match
 rule.status.MATCHED=Matched
 rule.status.PARENT_MATCH=Parent Match
@@ -28,24 +27,22 @@ rule.status.UNMATCHED=Unmatched
 
 # LOCALIZATION NOTE (rule.sourceElement, rule.sourceInline): For each
 # style property the panel shows the rules which hold that specific property.
 # For every rule, the rule source is also displayed: a rule can come from a
 # file, from the same page (inline), or from the element itself (element).
 rule.sourceInline=inline
 rule.sourceElement=element
 
-# LOCALIZATION NOTE (rule.showUnmatchedLink): Each style property
-# is inside a rule. A rule is a selector that can match (or not) the highlighted
-# element in the web page. The property view shows only a few of the unmatched
-# rules. If the user wants to see all of the unmatched rules, he/she must click
-# the link displayed at the bottom of the rules table. That link shows how many
-# rules are not displayed. This is the string used when the link is generated.
+# LOCALIZATION NOTE (rule.showUnmatchedLink): For each style
+# property the panel shows the number of selectors which do not match the
+# currently selected element, counted from all stylesheets in the web page
+# inspected.
 # See: http://developer.mozilla.org/en/docs/Localization_and_Plurals
-rule.showUnmatchedLink=One unmatched rule...;#1 unmatched rules...
+rule.showUnmatchedLink=1 unmatched selector…;#1 unmatched selectors…
 
 # LOCALIZATION NOTE (group): Style properties are displayed in categories and
 # these are the category names.
 group.Text_Fonts_and_Color=Text, Fonts & Color
 group.Background=Background
 group.Dimensions=Dimensions
 group.Positioning_and_Page_Flow=Positioning and Page Flow
 group.Borders=Borders
--- a/browser/themes/gnomestripe/browser/browser.css
+++ b/browser/themes/gnomestripe/browser/browser.css
@@ -1979,12 +1979,12 @@ panel[dimmed="true"] {
 }
 
 #highlighter-veil-transparentbox {
   box-shadow: 0 0 0 1px rgba(0,0,0,0.5);
   outline: 1px dashed rgba(255,255,255,0.5);
   outline-offset: -1px;
 }
 
-#highlighter-veil-transparentbox[locked] {
+#highlighter-veil-container[locked] > #highlighter-veil-middlebox > #highlighter-veil-transparentbox {
   box-shadow: 0 0 0 1px black;
   outline-color: white;
 }
--- a/browser/themes/pinstripe/browser/browser.css
+++ b/browser/themes/pinstripe/browser/browser.css
@@ -2570,17 +2570,17 @@ panel[dimmed="true"] {
 }
 
 #highlighter-veil-transparentbox {
   box-shadow: 0 0 0 1px rgba(0,0,0,0.5);
   outline: 1px dashed rgba(255,255,255,0.5);
   outline-offset: -1px;
 }
 
-#highlighter-veil-transparentbox[locked] {
+#highlighter-veil-container[locked] > #highlighter-veil-middlebox > #highlighter-veil-transparentbox {
   box-shadow: 0 0 0 1px black;
   outline-color: white;
 }
 
 /* Highlighter toolbar */
 
 #inspector-toolbar {
   -moz-appearance: none;
--- a/browser/themes/winstripe/browser/browser.css
+++ b/browser/themes/winstripe/browser/browser.css
@@ -2547,12 +2547,12 @@ panel[dimmed="true"] {
 }
 
 #highlighter-veil-transparentbox {
   box-shadow: 0 0 0 1px rgba(0,0,0,0.5);
   outline: 1px dashed rgba(255,255,255,0.5);
   outline-offset: -1px;
 }
 
-#highlighter-veil-transparentbox[locked] {
+#highlighter-veil-container[locked] > #highlighter-veil-middlebox > #highlighter-veil-transparentbox {
   box-shadow: 0 0 0 1px black;
   outline-color: white;
 }
--- a/build/automation.py.in
+++ b/build/automation.py.in
@@ -787,20 +787,21 @@ user_pref("camino.use_system_proxy_setti
       fixerStatus = stackFixerProcess.wait()
       if fixerStatus != 0 and not didTimeout and not hitMaxTime:
         self.log.info("TEST-UNEXPECTED-FAIL | automation.py | Stack fixer process exited with code %d during test run", fixerStatus)
     return status
 
   def buildCommandLine(self, app, debuggerInfo, profileDir, testURL, extraArgs):
     """ build the application command line """
 
-    cmd = app
-    if self.IS_MAC and not self.IS_CAMINO and not cmd.endswith("-bin"):
+    cmd = os.path.abspath(app)
+    if self.IS_MAC and not self.IS_CAMINO and os.path.exists(cmd + "-bin"):
+      # Prefer 'app-bin' in case 'app' is a shell script.
+      # We can remove this hack once bug 673899 etc are fixed.
       cmd += "-bin"
-    cmd = os.path.abspath(cmd)
 
     args = []
 
     if debuggerInfo:
       args.extend(debuggerInfo["args"])
       args.append(cmd)
       cmd = os.path.abspath(debuggerInfo["path"])
 
--- a/chrome/src/nsChromeRegistryChrome.cpp
+++ b/chrome/src/nsChromeRegistryChrome.cpp
@@ -53,41 +53,41 @@
 #include "nsArrayEnumerator.h"
 #include "nsAppDirectoryServiceDefs.h"
 #include "nsComponentManager.h"
 #include "nsEnumeratorUtils.h"
 #include "nsNetUtil.h"
 #include "nsStringEnumerator.h"
 #include "nsTextFormatter.h"
 #include "nsUnicharUtils.h"
-#include "nsWidgetsCID.h"
 #include "nsXPCOMCIDInternal.h"
 #include "nsZipArchive.h"
 
+#include "mozilla/LookAndFeel.h"
+
 #include "nsICommandLine.h"
 #include "nsILocaleService.h"
 #include "nsILocalFile.h"
-#include "nsILookAndFeel.h"
 #include "nsIObserverService.h"
 #include "nsIPrefBranch2.h"
 #include "nsIPrefService.h"
 #include "nsIResProtocolHandler.h"
 #include "nsIScriptError.h"
 #include "nsIVersionComparator.h"
 #include "nsIXPConnect.h"
 #include "nsIXULAppInfo.h"
 #include "nsIXULRuntime.h"
 
 #define UILOCALE_CMD_LINE_ARG "UILocale"
 
 #define MATCH_OS_LOCALE_PREF "intl.locale.matchOS"
 #define SELECTED_LOCALE_PREF "general.useragent.locale"
 #define SELECTED_SKIN_PREF   "general.skins.selectedSkin"
 
-static NS_DEFINE_CID(kLookAndFeelCID, NS_LOOKANDFEEL_CID);
+using namespace mozilla;
 
 static PLDHashOperator
 RemoveAll(PLDHashTable *table, PLDHashEntryHdr *entry, PRUint32 number, void *arg)
 {
   return (PLDHashOperator) (PL_DHASH_NEXT | PL_DHASH_REMOVE);
 }
 
 // We use a "best-fit" algorithm for matching locales and themes. 
@@ -205,36 +205,29 @@ nsChromeRegistryChrome::Init()
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsChromeRegistryChrome::CheckForOSAccessibility()
 {
-  nsresult rv;
-
-  nsCOMPtr<nsILookAndFeel> lookAndFeel (do_GetService(kLookAndFeelCID));
-  if (lookAndFeel) {
-    PRInt32 useAccessibilityTheme = 0;
-
-    rv = lookAndFeel->GetMetric(nsILookAndFeel::eMetric_UseAccessibilityTheme,
-                                useAccessibilityTheme);
+  PRInt32 useAccessibilityTheme =
+    LookAndFeel::GetInt(LookAndFeel::eIntID_UseAccessibilityTheme, 0);
 
-    if (NS_SUCCEEDED(rv) && useAccessibilityTheme) {
-      /* Set the skin to classic and remove pref observers */
-      if (!mSelectedSkin.EqualsLiteral("classic/1.0")) {
-        mSelectedSkin.AssignLiteral("classic/1.0");
-        RefreshSkins();
-      }
+  if (useAccessibilityTheme) {
+    /* Set the skin to classic and remove pref observers */
+    if (!mSelectedSkin.EqualsLiteral("classic/1.0")) {
+      mSelectedSkin.AssignLiteral("classic/1.0");
+      RefreshSkins();
+    }
 
-      nsCOMPtr<nsIPrefBranch2> prefs (do_GetService(NS_PREFSERVICE_CONTRACTID));
-      if (prefs) {
-        prefs->RemoveObserver(SELECTED_SKIN_PREF, this);
-      }
+    nsCOMPtr<nsIPrefBranch2> prefs (do_GetService(NS_PREFSERVICE_CONTRACTID));
+    if (prefs) {
+      prefs->RemoveObserver(SELECTED_SKIN_PREF, this);
     }
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsChromeRegistryChrome::GetLocalesForPackage(const nsACString& aPackage,
--- a/client.mk
+++ b/client.mk
@@ -263,16 +263,17 @@ configure depend realbuild install expor
 else
 
 # MOZ_CURRENT_PROJECT: either doing a single-project build, or building an
 # individual project in a multi-project build.
 
 ####################################
 # Configure
 
+MAKEFILE      = $(wildcard $(OBJDIR)/Makefile)
 CONFIG_STATUS = $(wildcard $(OBJDIR)/config.status)
 CONFIG_CACHE  = $(wildcard $(OBJDIR)/config.cache)
 
 EXTRA_CONFIG_DEPS := \
 	$(TOPSRCDIR)/aclocal.m4 \
 	$(wildcard $(TOPSRCDIR)/build/autoconf/*.m4) \
 	$(TOPSRCDIR)/js/src/aclocal.m4 \
 	$(NULL)
@@ -311,17 +312,23 @@ endif
 	@if test ! -d $(OBJDIR); then $(MKDIR) $(OBJDIR); else true; fi
 	@echo cd $(OBJDIR);
 	@echo $(CONFIGURE) $(CONFIGURE_ARGS)
 	@cd $(OBJDIR) && $(BUILD_PROJECT_ARG) $(CONFIGURE_ENV_ARGS) $(CONFIGURE) $(CONFIGURE_ARGS) \
 	  || ( echo "*** Fix above errors and then restart with\
                \"$(MAKE) -f client.mk build\"" && exit 1 )
 	@touch $(OBJDIR)/Makefile
 
-$(OBJDIR)/Makefile $(OBJDIR)/config.status: $(CONFIG_STATUS_DEPS)
+ifneq (,$(MAKEFILE))
+$(OBJDIR)/Makefile: $(OBJDIR)/config.status
+
+$(OBJDIR)/config.status: $(CONFIG_STATUS_DEPS)
+else
+$(OBJDIR)/Makefile: $(CONFIG_STATUS_DEPS)
+endif
 	@$(MAKE) -f $(TOPSRCDIR)/client.mk configure
 
 ifneq (,$(CONFIG_STATUS))
 $(OBJDIR)/config/autoconf.mk: $(TOPSRCDIR)/config/autoconf.mk.in
 	cd $(OBJDIR); \
 	  CONFIG_FILES=config/autoconf.mk ./config.status
 endif
 
--- a/configure.in
+++ b/configure.in
@@ -1277,17 +1277,17 @@ if test -n "$CROSS_COMPILE"; then
     OS_TARGET="${target_os}"
     OS_ARCH=`echo $target_os | sed -e 's|/|_|g'`
     OS_RELEASE=
     case "${target_os}" in
         linux*)       OS_ARCH=Linux OS_TARGET=Linux ;;
         kfreebsd*-gnu) OS_ARCH=GNU_kFreeBSD OS_TARGET=GNU_kFreeBSD ;;
         gnu*)         OS_ARCH=GNU ;;
         solaris*)     OS_ARCH=SunOS OS_RELEASE=5 ;;
-        mingw*)       OS_ARCH=WINNT ;;
+        mingw*)       OS_ARCH=WINNT OS_TARGET=WINNT ;;
         darwin*)      OS_ARCH=Darwin OS_TARGET=Darwin ;;
     esac
     case "${target}" in
         *-android*|*-linuxandroid*) OS_ARCH=Linux OS_TARGET=Android ;;
     esac
 else
     OS_TARGET=`uname -s`
     OS_ARCH=`uname -s | sed -e 's|/|_|g'`
@@ -5694,16 +5694,20 @@ if test -n "$MOZ_CRASHREPORTER"; then
   if (test "$OS_TARGET" = "Linux" -o "$OS_ARCH" = "SunOS") && \
     test -z "$SKIP_LIBRARY_CHECKS"; then
     PKG_CHECK_MODULES(MOZ_GTHREAD, gthread-2.0)
     AC_SUBST(MOZ_GTHREAD_CFLAGS)
     AC_SUBST(MOZ_GTHREAD_LIBS)
 
     MOZ_CHECK_HEADERS([curl/curl.h], [], [AC_MSG_ERROR([Couldn't find curl/curl.h which is required for the crash reporter.  Use --disable-crashreporter to disable the crash reporter.])])
   fi
+
+  if (test "$OS_ARCH" != "$HOST_OS_ARCH"); then
+    AC_MSG_ERROR([Breakpad tools do not support compiling on $HOST_OS_ARCH while targeting $OS_ARCH.  Use --disable-crashreporter.])
+  fi
 fi
 
 MOZ_ARG_WITH_STRING(crashreporter-enable-percent,
 [  --with-crashreporter-enable-percent=NN
                           Enable sending crash reports by default on NN% of users. (default=100)],
 [ val=`echo $withval | sed 's/[^0-9]//g'`
     MOZ_CRASHREPORTER_ENABLE_PERCENT="$val"])
 
new file mode 100644
--- /dev/null
+++ b/content/base/crashtests/679459.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script>
+
+function boom()
+{
+  var t = document.createTextNode("a");
+  document.body.appendChild(t);
+  var r1 = document.createRange();
+  r1.setEnd(t, 1);
+  var r2 = document.createRange();
+  r2.setEnd(t, 0);
+  r2.deleteContents();
+}
+
+</script>
+</head>
+
+<body onload="boom();"></body>
+</html>
--- a/content/base/crashtests/crashtests.list
+++ b/content/base/crashtests/crashtests.list
@@ -88,9 +88,10 @@ load 610571-1.html
 load 604262-1.html
 load 628599-1.html
 load 637214-1.svg
 load 637214-2.svg
 load 642022-1.html
 load 646184.html
 load 658845-1.svg
 load 667336-1.html
+load 679459.html
 load 679689-1.html
--- a/content/base/public/nsIContentPolicy.idl
+++ b/content/base/public/nsIContentPolicy.idl
@@ -131,16 +131,18 @@ interface nsIContentPolicy : nsISupports
    */
   const unsigned long TYPE_FONT = 14;
 
   /**
    * Indicates a video or audio load.
    */
   const unsigned long TYPE_MEDIA = 15;  
 
+  /* Please update nsContentBlocker when adding new content types. */
+
   //////////////////////////////////////////////////////////////////////
 
   /**
    * Returned from shouldLoad or shouldProcess if the load or process request
    * is rejected based on details of the request.
    */
   const short REJECT_REQUEST = -1;
 
--- a/content/base/src/nsDocument.cpp
+++ b/content/base/src/nsDocument.cpp
@@ -2873,17 +2873,17 @@ nsDocument::NodesFromRectHelper(float aX
   nsIPresShell *ps = GetShell();
   NS_ENSURE_STATE(ps);
   nsIFrame *rootFrame = ps->GetRootFrame();
 
   // XUL docs, unlike HTML, have no frame tree until everything's done loading
   if (!rootFrame)
     return NS_OK; // return nothing to premature XUL callers as a reminder to wait
 
-  nsTArray<nsIFrame*> outFrames;
+  nsAutoTArray<nsIFrame*,8> outFrames;
   nsLayoutUtils::GetFramesForArea(rootFrame, rect, outFrames,
                                   PR_TRUE, aIgnoreRootScrollFrame);
 
   PRInt32 length = outFrames.Length();
   if (!length)
     return NS_OK;
 
   // Used to filter out repeated elements in sequence.
@@ -6744,24 +6744,21 @@ nsDocument::RetrieveRelevantHeaders(nsIC
 
         if (NS_SUCCEEDED(rv)) {
           PRInt64 intermediateValue;
           LL_I2L(intermediateValue, PR_USEC_PER_MSEC);
           LL_MUL(modDate, msecs, intermediateValue);
         }
       }
     } else {
-      nsCOMPtr<nsIMultiPartChannel> partChannel = do_QueryInterface(aChannel);
-      if (partChannel) {
-        nsCAutoString contentDisp;
-        rv = partChannel->GetContentDisposition(contentDisp);
-        if (NS_SUCCEEDED(rv) && !contentDisp.IsEmpty()) {
-          SetHeaderData(nsGkAtoms::headerContentDisposition,
-                        NS_ConvertASCIItoUTF16(contentDisp));
-        }
+      nsCAutoString contentDisp;
+      rv = aChannel->GetContentDispositionHeader(contentDisp);
+      if (NS_SUCCEEDED(rv)) {
+        SetHeaderData(nsGkAtoms::headerContentDisposition,
+                      NS_ConvertASCIItoUTF16(contentDisp));
       }
     }
   }
 
   if (LL_IS_ZERO(modDate)) {
     // We got nothing from our attempt to ask nsIFileChannel and
     // nsIHttpChannel for the last modified time. Return the current
     // time.
--- a/content/base/src/nsGenericDOMDataNode.cpp
+++ b/content/base/src/nsGenericDOMDataNode.cpp
@@ -323,22 +323,23 @@ nsGenericDOMDataNode::SetTextInternal(PR
       endOffset,
       aLength,
       aDetails
     };
     nsNodeUtils::CharacterDataWillChange(this, &info);
   }
 
   if (aOffset == 0 && endOffset == textLength) {
-    // Replacing whole text or old text was empty
-    mText.SetTo(aBuffer, aLength);
+    // Replacing whole text or old text was empty.  Don't bother to check for
+    // bidi in this string if the document already has bidi enabled.
+    mText.SetTo(aBuffer, aLength, !document || !document->GetBidiEnabled());
   }
   else if (aOffset == textLength) {
     // Appending to existing
-    mText.Append(aBuffer, aLength);
+    mText.Append(aBuffer, aLength, !document || !document->GetBidiEnabled());
   }
   else {
     // Merging old and new
 
     // Allocate new buffer
     PRInt32 newLength = textLength - aCount + aLength;
     PRUnichar* to = new PRUnichar[newLength];
     NS_ENSURE_TRUE(to, NS_ERROR_OUT_OF_MEMORY);
@@ -350,22 +351,26 @@ nsGenericDOMDataNode::SetTextInternal(PR
     if (aLength) {
       memcpy(to + aOffset, aBuffer, aLength * sizeof(PRUnichar));
     }
     if (endOffset != textLength) {
       mText.CopyTo(to + aOffset + aLength, endOffset, textLength - endOffset);
     }
 
     // XXX Add OOM checking to this
-    mText.SetTo(to, newLength);
+    mText.SetTo(to, newLength, !document || !document->GetBidiEnabled());
 
     delete [] to;
   }
 
-  UpdateBidiStatus(aBuffer, aLength);
+  if (document && mText.IsBidi()) {
+    // If we found bidi characters in mText.SetTo() above, indicate that the
+    // document contains bidi characters.
+    document->SetBidiEnabled();
+  }
 
   // Notify observers
   if (aNotify) {
     CharacterDataChangeInfo info = {
       aOffset == textLength,
       aOffset,
       endOffset,
       aLength,
@@ -743,17 +748,18 @@ nsGenericDOMDataNode::SplitData(PRUint32
   if (!newContent) {
     return NS_ERROR_OUT_OF_MEMORY;
   }
   newContent->SetText(cutText, PR_TRUE); // XXX should be PR_FALSE?
 
   CharacterDataChangeInfo::Details details = {
     CharacterDataChangeInfo::Details::eSplit, newContent
   };
-  rv = SetTextInternal(cutStartOffset, cutLength, nsnull, 0, PR_TRUE, &details);
+  rv = SetTextInternal(cutStartOffset, cutLength, nsnull, 0, PR_TRUE,
+                       aCloneAfterOriginal ? &details : nsnull);
   if (NS_FAILED(rv)) {
     return rv;
   }
 
   nsCOMPtr<nsINode> parent = GetNodeParent();
   if (parent) {
     PRInt32 insertionIndex = parent->IndexOf(this);
     if (aCloneAfterOriginal) {
@@ -965,31 +971,16 @@ nsGenericDOMDataNode::TextIsOnlyWhitespa
 }
 
 void
 nsGenericDOMDataNode::AppendTextTo(nsAString& aResult)
 {
   mText.AppendTo(aResult);
 }
 
-void nsGenericDOMDataNode::UpdateBidiStatus(const PRUnichar* aBuffer, PRUint32 aLength)
-{
-  nsIDocument *document = GetCurrentDoc();
-  if (document && document->GetBidiEnabled()) {
-    // OK, we already know it's Bidi, so we won't test again
-    return;
-  }
-
-  mText.UpdateBidiFlag(aBuffer, aLength);
-
-  if (document && mText.IsBidi()) {
-    document->SetBidiEnabled();
-  }
-}
-
 already_AddRefed<nsIAtom>
 nsGenericDOMDataNode::GetCurrentValueAtom()
 {
   nsAutoString val;
   GetData(val);
   return NS_NewAtom(val);
 }
 
--- a/content/base/src/nsGenericDOMDataNode.h
+++ b/content/base/src/nsGenericDOMDataNode.h
@@ -359,14 +359,12 @@ protected:
    * @return the clone
    */
   virtual nsGenericDOMDataNode *CloneDataNode(nsINodeInfo *aNodeInfo,
                                               PRBool aCloneText) const = 0;
 
   nsTextFragment mText;
 
 private:
-  void UpdateBidiStatus(const PRUnichar* aBuffer, PRUint32 aLength);
-
   already_AddRefed<nsIAtom> GetCurrentValueAtom();
 };
 
 #endif /* nsGenericDOMDataNode_h___ */
--- a/content/base/src/nsGenericElement.cpp
+++ b/content/base/src/nsGenericElement.cpp
@@ -5529,18 +5529,20 @@ nsGenericElement::SizeOf() const
 #define TOUCH_EVENT EVENT
 #include "nsEventNameList.h"
 #undef TOUCH_EVENT
 #undef EVENT
 
 PRBool
 nsINode::Contains(const nsINode* aOther) const
 {
+  if (aOther == this) {
+    return PR_TRUE;
+  }
   if (!aOther ||
-      aOther == this ||
       GetOwnerDoc() != aOther->GetOwnerDoc() ||
       IsInDoc() != aOther->IsInDoc() ||
       !(aOther->IsElement() ||
         aOther->IsNodeOfType(nsINode::eCONTENT)) ||
       !GetFirstChild()) {
     return PR_FALSE;
   }
 
--- a/content/base/src/nsTextFragment.cpp
+++ b/content/base/src/nsTextFragment.cpp
@@ -112,16 +112,17 @@ nsTextFragment::~nsTextFragment()
 void
 nsTextFragment::ReleaseText()
 {
   if (mState.mLength && m1b && mState.mInHeap) {
     nsMemory::Free(m2b); // m1b == m2b as far as nsMemory is concerned
   }
 
   m1b = nsnull;
+  mState.mIsBidi = PR_FALSE;
 
   // Set mState.mIs2b, mState.mInHeap, and mState.mLength = 0 with mAllBits;
   mAllBits = 0;
 }
 
 nsTextFragment&
 nsTextFragment::operator=(const nsTextFragment& aOther)
 {
@@ -140,18 +141,18 @@ nsTextFragment::operator=(const nsTextFr
     if (m1b) {
       mAllBits = aOther.mAllBits;
     }
   }
 
   return *this;
 }
 
-static inline PRBool
-Is8BitUnvectorized(const PRUnichar *str, const PRUnichar *end)
+static inline PRInt32
+FirstNon8BitUnvectorized(const PRUnichar *str, const PRUnichar *end)
 {
 #if PR_BYTES_PER_WORD == 4
   const size_t mask = 0xff00ff00;
   const PRUint32 alignMask = 0x3;
   const PRUint32 numUnicharsPerWord = 2;
 #elif PR_BYTES_PER_WORD == 8
   const size_t mask = 0xff00ff00ff00ff00;
   const PRUint32 alignMask = 0x7;
@@ -163,58 +164,65 @@ Is8BitUnvectorized(const PRUnichar *str,
   const PRInt32 len = end - str;
   PRInt32 i = 0;
 
   // Align ourselves to a word boundary.
   PRInt32 alignLen =
     NS_MIN(len, PRInt32(((-NS_PTR_TO_INT32(str)) & alignMask) / sizeof(PRUnichar)));
   for (; i < alignLen; i++) {
     if (str[i] > 255)
-      return PR_FALSE;
+      return i;
   }
 
   // Check one word at a time.
   const PRInt32 wordWalkEnd = ((len - i) / numUnicharsPerWord) * numUnicharsPerWord;
   for (; i < wordWalkEnd; i += numUnicharsPerWord) {
     const size_t word = *reinterpret_cast<const size_t*>(str + i);
     if (word & mask)
-      return PR_FALSE;
+      return i;
   }
 
   // Take care of the remainder one character at a time.
   for (; i < len; i++) {
     if (str[i] > 255)
-      return PR_FALSE;
+      return i;
   }
 
-  return PR_TRUE;
+  return -1;
 }
 
 #ifdef MOZILLA_MAY_SUPPORT_SSE2
 namespace mozilla {
   namespace SSE2 {
-    PRBool Is8Bit(const PRUnichar *str, const PRUnichar *end);
+    PRInt32 FirstNon8Bit(const PRUnichar *str, const PRUnichar *end);
   }
 }
 #endif
 
-static inline PRBool
-Is8Bit(const PRUnichar *str, const PRUnichar *end)
+/*
+ * This function returns -1 if all characters in str are 8 bit characters.
+ * Otherwise, it returns a value less than or equal to the index of the first
+ * non-8bit character in str. For example, if first non-8bit character is at
+ * position 25, it may return 25, or for example 24, or 16. But it guarantees
+ * there is no non-8bit character before returned value.
+ */
+static inline PRInt32
+FirstNon8Bit(const PRUnichar *str, const PRUnichar *end)
 {
 #ifdef MOZILLA_MAY_SUPPORT_SSE2
   if (mozilla::supports_sse2()) {
-    return mozilla::SSE2::Is8Bit(str, end);
+    return mozilla::SSE2::FirstNon8Bit(str, end);
   }
 #endif
 
-  return Is8BitUnvectorized(str, end);
+  return FirstNon8BitUnvectorized(str, end);
 }
 
 void
-nsTextFragment::SetTo(const PRUnichar* aBuffer, PRInt32 aLength)
+nsTextFragment::SetTo(const PRUnichar* aBuffer, PRInt32 aLength, PRBool aUpdateBidi)
 {
   ReleaseText();
 
   if (aLength == 0) {
     return;
   }
   
   PRUnichar firstChar = *aBuffer;
@@ -263,41 +271,47 @@ nsTextFragment::SetTo(const PRUnichar* a
       mState.mIs2b = PR_FALSE;
       mState.mLength = aLength;
 
       return;        
     }
   }
 
   // See if we need to store the data in ucs2 or not
-  PRBool need2 = !Is8Bit(ucp, uend);
+  PRInt32 first16bit = FirstNon8Bit(ucp, uend);
 
-  if (need2) {
+  if (first16bit != -1) { // aBuffer contains no non-8bit character
     // Use ucs2 storage because we have to
     m2b = (PRUnichar *)nsMemory::Clone(aBuffer,
                                        aLength * sizeof(PRUnichar));
     if (!m2b) {
       return;
     }
+
+    mState.mIs2b = PR_TRUE;
+    if (aUpdateBidi) {
+      UpdateBidiFlag(aBuffer + first16bit, aLength - first16bit);
+    }
+
   } else {
     // Use 1 byte storage because we can
     char* buff = (char *)nsMemory::Alloc(aLength * sizeof(char));
     if (!buff) {
       return;
     }
 
     // Copy data
     LossyConvertEncoding16to8 converter(buff);
     copy_string(aBuffer, aBuffer+aLength, converter);
     m1b = buff;
+    mState.mIs2b = PR_FALSE;
   }
 
   // Setup our fields
   mState.mInHeap = PR_TRUE;
-  mState.mIs2b = need2;
   mState.mLength = aLength;
 }
 
 void
 nsTextFragment::CopyTo(PRUnichar *aDest, PRInt32 aOffset, PRInt32 aCount)
 {
   NS_ASSERTION(aOffset >= 0, "Bad offset passed to nsTextFragment::CopyTo()!");
   NS_ASSERTION(aCount >= 0, "Bad count passed to nsTextFragment::CopyTo()!");
@@ -318,69 +332,77 @@ nsTextFragment::CopyTo(PRUnichar *aDest,
       const char *end = cp + aCount;
       LossyConvertEncoding8to16 converter(aDest);
       copy_string(cp, end, converter);
     }
   }
 }
 
 void
-nsTextFragment::Append(const PRUnichar* aBuffer, PRUint32 aLength)
+nsTextFragment::Append(const PRUnichar* aBuffer, PRUint32 aLength, PRBool aUpdateBidi)
 {
   // This is a common case because some callsites create a textnode
   // with a value by creating the node and then calling AppendData.
   if (mState.mLength == 0) {
-    SetTo(aBuffer, aLength);
+    SetTo(aBuffer, aLength, aUpdateBidi);
 
     return;
   }
 
   // Should we optimize for aData.Length() == 0?
 
   if (mState.mIs2b) {
     // Already a 2-byte string so the result will be too
     PRUnichar* buff = (PRUnichar*)nsMemory::Realloc(m2b, (mState.mLength + aLength) * sizeof(PRUnichar));
     if (!buff) {
       return;
     }
-    
+
     memcpy(buff + mState.mLength, aBuffer, aLength * sizeof(PRUnichar));
     mState.mLength += aLength;
     m2b = buff;
 
+    if (aUpdateBidi) {
+      UpdateBidiFlag(aBuffer, aLength);
+    }
+
     return;
   }
 
   // Current string is a 1-byte string, check if the new data fits in one byte too.
+  PRInt32 first16bit = FirstNon8Bit(aBuffer, aBuffer + aLength);
 
-  if (!Is8Bit(aBuffer, aBuffer + aLength)) {
+  if (first16bit != -1) { // aBuffer contains no non-8bit character
     // The old data was 1-byte, but the new is not so we have to expand it
     // all to 2-byte
     PRUnichar* buff = (PRUnichar*)nsMemory::Alloc((mState.mLength + aLength) *
                                                   sizeof(PRUnichar));
     if (!buff) {
       return;
     }
 
     // Copy data into buff
     LossyConvertEncoding8to16 converter(buff);
     copy_string(m1b, m1b+mState.mLength, converter);
 
     memcpy(buff + mState.mLength, aBuffer, aLength * sizeof(PRUnichar));
-
     mState.mLength += aLength;
     mState.mIs2b = PR_TRUE;
 
     if (mState.mInHeap) {
       nsMemory::Free(m2b);
     }
     m2b = buff;
 
     mState.mInHeap = PR_TRUE;
 
+    if (aUpdateBidi) {
+      UpdateBidiFlag(aBuffer + first16bit, aLength - first16bit);
+    }
+
     return;
   }
 
   // The new and the old data is all 1-byte
   char* buff;
   if (mState.mInHeap) {
     buff = (char*)nsMemory::Realloc(const_cast<char*>(m1b),
                                     (mState.mLength + aLength) * sizeof(char));
--- a/content/base/src/nsTextFragment.h
+++ b/content/base/src/nsTextFragment.h
@@ -1,9 +1,8 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* ***** 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/
  *
@@ -109,18 +108,18 @@ public:
    */
   PRBool Is2b() const
   {
     return mState.mIs2b;
   }
 
   /**
    * Return PR_TRUE if this fragment contains Bidi text
-   * For performance reasons this flag is not set automatically, but
-   * requires an explicit call to UpdateBidiFlag()
+   * For performance reasons this flag is only set if explicitely requested (by
+   * setting the aUpdateBidi argument on SetTo or Append to true).
    */
   PRBool IsBidi() const
   {
     return mState.mIsBidi;
   }
 
   /**
    * Get a pointer to constant PRUnichar data.
@@ -151,24 +150,27 @@ public:
 
   PRBool CanGrowBy(size_t n) const
   {
     return n < (1 << 29) && mState.mLength + n < (1 << 29);
   }
 
   /**
    * Change the contents of this fragment to be a copy of the given
-   * buffer.
+   * buffer. If aUpdateBidi is true, contents of the fragment will be scanned,
+   * and mState.mIsBidi will be turned on if it includes any Bidi characters.
    */
-  void SetTo(const PRUnichar* aBuffer, PRInt32 aLength);
+  void SetTo(const PRUnichar* aBuffer, PRInt32 aLength, PRBool aUpdateBidi);
 
   /**
-   * Append aData to the end of this fragment.
+   * Append aData to the end of this fragment. If aUpdateBidi is true, contents
+   * of the fragment will be scanned, and mState.mIsBidi will be turned on if
+   * it includes any Bidi characters.
    */
-  void Append(const PRUnichar* aBuffer, PRUint32 aLength);
+  void Append(const PRUnichar* aBuffer, PRUint32 aLength, PRBool aUpdateBidi);
 
   /**
    * Append the contents of this string fragment to aString
    */
   void AppendTo(nsAString& aString) const {
     if (mState.mIs2b) {
       aString.Append(m2b, mState.mLength);
     } else {
@@ -203,22 +205,16 @@ public:
    * index. This always returns a PRUnichar.
    */
   PRUnichar CharAt(PRInt32 aIndex) const
   {
     NS_ASSERTION(PRUint32(aIndex) < mState.mLength, "bad index");
     return mState.mIs2b ? m2b[aIndex] : static_cast<unsigned char>(m1b[aIndex]);
   }
 
-  /**
-   * Scan the contents of the fragment and turn on mState.mIsBidi if it
-   * includes any Bidi characters.
-   */
-  void UpdateBidiFlag(const PRUnichar* aBuffer, PRUint32 aLength);
-
   struct FragmentBits {
     // PRUint32 to ensure that the values are unsigned, because we
     // want 0/1, not 0/-1!
     // Making these PRPackedBool causes Windows to not actually pack them,
     // which causes crashes because we assume this structure is no more than
     // 32 bits!
     PRUint32 mInHeap : 1;
     PRUint32 mIs2b : 1;
@@ -235,16 +231,22 @@ public:
     PRInt64 size = sizeof(*this);
     size += GetLength() * Is2b() ? sizeof(*m2b) : sizeof(*m1b);
     return size;
   }
 
 private:
   void ReleaseText();
 
+  /**
+   * Scan the contents of the fragment and turn on mState.mIsBidi if it
+   * includes any Bidi characters.
+   */
+  void UpdateBidiFlag(const PRUnichar* aBuffer, PRUint32 aLength);
+ 
   union {
     PRUnichar *m2b;
     const char *m1b; // This is const since it can point to shared data
   };
 
   union {
     PRUint32 mAllBits;
     FragmentBits mState;
--- a/content/base/src/nsTextFragmentSSE2.cpp
+++ b/content/base/src/nsTextFragmentSSE2.cpp
@@ -10,18 +10,18 @@ namespace SSE2 {
 
 static inline bool
 is_zero (__m128i x)
 {
   return
     _mm_movemask_epi8(_mm_cmpeq_epi8(x, _mm_setzero_si128())) == 0xffff;
 }
 
-PRBool
-Is8Bit(const PRUnichar *str, const PRUnichar *end)
+PRInt32
+FirstNon8Bit(const PRUnichar *str, const PRUnichar *end)
 {
   const PRUint32 numUnicharsPerVector = 8;
 
 #if PR_BYTES_PER_WORD == 4
   const size_t mask = 0xff00ff00;
   const PRUint32 numUnicharsPerWord = 2;
 #elif PR_BYTES_PER_WORD == 8
   const size_t mask = 0xff00ff00ff00ff00;
@@ -34,40 +34,40 @@ Is8Bit(const PRUnichar *str, const PRUni
   PRInt32 i = 0;
 
   // Align ourselves to a 16-byte boundary, as required by _mm_load_si128
   // (i.e. MOVDQA).
   PRInt32 alignLen =
     NS_MIN(len, PRInt32(((-NS_PTR_TO_INT32(str)) & 0xf) / sizeof(PRUnichar)));
   for (; i < alignLen; i++) {
     if (str[i] > 255)
-      return PR_FALSE;
+      return i;
   }
 
   // Check one XMM register (16 bytes) at a time.
   const PRInt32 vectWalkEnd = ((len - i) / numUnicharsPerVector) * numUnicharsPerVector;
   __m128i vectmask = _mm_set1_epi16(0xff00);
   for(; i < vectWalkEnd; i += numUnicharsPerVector) {
     const __m128i vect = *reinterpret_cast<const __m128i*>(str + i);
     if (!is_zero(_mm_and_si128(vect, vectmask)))
-      return PR_FALSE;
+      return i;
   }
 
   // Check one word at a time.
   const PRInt32 wordWalkEnd = ((len - i) / numUnicharsPerWord) * numUnicharsPerWord;
   for(; i < wordWalkEnd; i += numUnicharsPerWord) {
     const size_t word = *reinterpret_cast<const size_t*>(str + i);
     if (word & mask)
-      return PR_FALSE;
+      return i;
   }
 
   // Take care of the remainder one character at a time.
   for (; i < len; i++) {
     if (str[i] > 255) {
-      return PR_FALSE;
+      return i;
     }
   }
 
-  return PR_TRUE;
+  return -1;
 }
 
 } // namespace SSE2
 } // namespace mozilla
--- a/content/base/src/nsXMLHttpRequest.cpp
+++ b/content/base/src/nsXMLHttpRequest.cpp
@@ -421,17 +421,18 @@ nsXMLHttpRequest::nsXMLHttpRequest()
   : mResponseType(XML_HTTP_RESPONSE_TYPE_DEFAULT),
     mRequestObserver(nsnull), mState(XML_HTTP_REQUEST_UNSENT),
     mUploadTransferred(0), mUploadTotal(0), mUploadComplete(PR_TRUE),
     mUploadProgress(0), mUploadProgressMax(0),
     mErrorLoad(PR_FALSE), mTimerIsActive(PR_FALSE),
     mProgressEventWasDelayed(PR_FALSE),
     mLoadLengthComputable(PR_FALSE), mLoadTotal(0),
     mFirstStartRequestSeen(PR_FALSE),
-    mResultArrayBuffer(nsnull) 
+    mResultArrayBuffer(nsnull),
+    mResultJSON(JSVAL_VOID)
 {
   mResponseBodyUnicode.SetIsVoid(PR_TRUE);
   nsLayoutStatics::AddRef();
 }
 
 nsXMLHttpRequest::~nsXMLHttpRequest()
 {
   if (mListenerManager) {
@@ -579,16 +580,17 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_
 
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR_AMBIGUOUS(mUpload,
                                                        nsIXMLHttpRequestUpload)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsXMLHttpRequest,
                                                 nsXHREventTarget)
   tmp->mResultArrayBuffer = nsnull;
+  tmp->mResultJSON = JSVAL_VOID;
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mContext)
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mChannel)
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mReadRequest)
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mResponseXML)
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mCORSPreflightChannel)
 
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mOnUploadProgressListener)
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mOnReadystatechangeListener)
@@ -602,16 +604,20 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_IN
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(nsXMLHttpRequest,
                                                nsXHREventTarget)
   if(tmp->mResultArrayBuffer) {
     NS_IMPL_CYCLE_COLLECTION_TRACE_JS_CALLBACK(tmp->mResultArrayBuffer,
                                                "mResultArrayBuffer")
   }
+  if (JSVAL_IS_GCTHING(tmp->mResultJSON)) {
+    void *gcThing = JSVAL_TO_GCTHING(tmp->mResultJSON);
+    NS_IMPL_CYCLE_COLLECTION_TRACE_JS_CALLBACK(gcThing, "mResultJSON")
+  }
 NS_IMPL_CYCLE_COLLECTION_TRACE_END
 
 DOMCI_DATA(XMLHttpRequest, nsXMLHttpRequest)
 
 // QueryInterface implementation for nsXMLHttpRequest
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsXMLHttpRequest)
   NS_INTERFACE_MAP_ENTRY(nsIXMLHttpRequest)
   NS_INTERFACE_MAP_ENTRY(nsIJSXMLHttpRequest)
@@ -849,20 +855,40 @@ NS_IMETHODIMP nsXMLHttpRequest::GetRespo
   if (mState & (XML_HTTP_REQUEST_DONE |
                 XML_HTTP_REQUEST_LOADING)) {
     rv = ConvertBodyToText(aResponseText);
   }
 
   return rv;
 }
 
-nsresult nsXMLHttpRequest::CreateResponseArrayBuffer(JSContext *aCx)
+nsresult
+nsXMLHttpRequest::CreateResponseParsedJSON(JSContext* aCx)
 {
-  if (!aCx)
+  if (!aCx) {
+    return NS_ERROR_FAILURE;
+  }
+
+  nsString bodyString;
+  ConvertBodyToText(bodyString);
+  if (!JS_ParseJSON(aCx,
+                    (jschar*)PromiseFlatString(bodyString).get(),
+                    bodyString.Length(), &mResultJSON)) {
     return NS_ERROR_FAILURE;
+  }
+
+  return NS_OK;
+}
+
+nsresult
+nsXMLHttpRequest::CreateResponseArrayBuffer(JSContext *aCx)
+{
+  if (!aCx){
+    return NS_ERROR_FAILURE;
+  }
 
   PRInt32 dataLen = mResponseBody.Length();
   RootResultArrayBuffer();
   mResultArrayBuffer = js_CreateArrayBuffer(aCx, dataLen);
   if (!mResultArrayBuffer) {
     return NS_ERROR_FAILURE;
   }
 
@@ -889,16 +915,19 @@ NS_IMETHODIMP nsXMLHttpRequest::GetRespo
     aResponseType.AssignLiteral("blob");
     break;
   case XML_HTTP_RESPONSE_TYPE_DOCUMENT:
     aResponseType.AssignLiteral("document");
     break;
   case XML_HTTP_RESPONSE_TYPE_TEXT:
     aResponseType.AssignLiteral("text");
     break;
+  case XML_HTTP_RESPONSE_TYPE_JSON:
+    aResponseType.AssignLiteral("moz-json");
+    break;
   default:
     NS_ERROR("Should not happen");
   }
 
   return NS_OK;
 }
 
 /* attribute AString responseType; */
@@ -916,16 +945,18 @@ NS_IMETHODIMP nsXMLHttpRequest::SetRespo
   } else if (aResponseType.EqualsLiteral("arraybuffer")) {
     mResponseType = XML_HTTP_RESPONSE_TYPE_ARRAYBUFFER;
   } else if (aResponseType.EqualsLiteral("blob")) {
     mResponseType = XML_HTTP_RESPONSE_TYPE_BLOB;
   } else if (aResponseType.EqualsLiteral("document")) {
     mResponseType = XML_HTTP_RESPONSE_TYPE_DOCUMENT;
   } else if (aResponseType.EqualsLiteral("text")) {
     mResponseType = XML_HTTP_RESPONSE_TYPE_TEXT;
+  } else if (aResponseType.EqualsLiteral("moz-json")) {
+    mResponseType = XML_HTTP_RESPONSE_TYPE_JSON;
   }
   // If the given value is not the empty string, "arraybuffer",
   // "blob", "document", or "text" terminate these steps.
 
   // If the state is OPENED, SetCacheAsFile would have no effect here
   // because the channel hasn't initialized the cache entry yet.
   // SetCacheAsFile will be called from OnStartRequest.
   // If the state is HEADERS_RECEIVED, however, we need to call
@@ -957,17 +988,17 @@ NS_IMETHODIMP nsXMLHttpRequest::GetRespo
       if (buf) {
         str.ForgetSharedBuffer();
       }
     }
     break;
 
   case XML_HTTP_RESPONSE_TYPE_ARRAYBUFFER:
     if (mState & XML_HTTP_REQUEST_DONE) {
-      if (!mResultArrayBuffer) {  
+      if (!mResultArrayBuffer) {
          rv = CreateResponseArrayBuffer(aCx);
          NS_ENSURE_SUCCESS(rv, rv);
       }
       *aResult = OBJECT_TO_JSVAL(mResultArrayBuffer);
     } else {
       *aResult = JSVAL_NULL;
     }
     break;
@@ -987,16 +1018,31 @@ NS_IMETHODIMP nsXMLHttpRequest::GetRespo
       JSObject* scope = JS_GetScopeChain(aCx);
       rv = nsContentUtils::WrapNative(aCx, scope, mResponseXML, aResult,
                                       nsnull, PR_TRUE);
     } else {
       *aResult = JSVAL_NULL;
     }
     break;
 
+  case XML_HTTP_RESPONSE_TYPE_JSON:
+    if (mState & XML_HTTP_REQUEST_DONE) {
+      if (mResultJSON == JSVAL_VOID) {
+        rv = CreateResponseParsedJSON(aCx);
+        NS_ENSURE_SUCCESS(rv, rv);
+
+        mResponseBody.Truncate();
+        mResponseBodyUnicode.SetIsVoid(PR_TRUE);
+      }
+      *aResult = mResultJSON;
+    } else {
+      *aResult = JSVAL_NULL;
+    }
+    break;
+
   default:
     NS_ERROR("Should not happen");
   }
 
   return rv;
 }
 
 /* readonly attribute unsigned long status; */
@@ -1081,16 +1127,17 @@ nsXMLHttpRequest::Abort()
   }
   mResponseXML = nsnull;
   PRUint32 responseLength = mResponseBody.Length();
   mResponseBody.Truncate();
   mResponseBodyUnicode.SetIsVoid(PR_TRUE);
   mResponseBlob = nsnull;
   mState |= XML_HTTP_REQUEST_ABORTED;
   mResultArrayBuffer = nsnull;
+  mResultJSON = JSVAL_VOID;
   
   if (!(mState & (XML_HTTP_REQUEST_UNSENT |
                   XML_HTTP_REQUEST_OPENED |
                   XML_HTTP_REQUEST_DONE))) {
     ChangeState(XML_HTTP_REQUEST_DONE, PR_TRUE);
   }
 
   if (!(mState & XML_HTTP_REQUEST_SYNCLOOPING)) {
@@ -2078,16 +2125,38 @@ GetRequestBody(nsIVariant* aBody, nsIInp
       return NS_OK;
     }
 
     // nsIXHRSendable?
     nsCOMPtr<nsIXHRSendable> sendable = do_QueryInterface(supports);
     if (sendable) {
       return sendable->GetSendInfo(aResult, aContentType, aCharset);
     }
+
+    // ArrayBuffer?
+    jsval realVal;
+    JSObject* obj;
+    nsresult rv = aBody->GetAsJSVal(&realVal);
+    if (NS_SUCCEEDED(rv) && !JSVAL_IS_PRIMITIVE(realVal) &&
+        (obj = JSVAL_TO_OBJECT(realVal)) &&
+        (js_IsArrayBuffer(obj))) {
+
+      aContentType.SetIsVoid(PR_TRUE);
+      PRInt32 abLength = JS_GetArrayBufferByteLength(obj);
+      char* data = (char*)JS_GetArrayBufferData(obj);
+
+      nsCOMPtr<nsIInputStream> stream;
+      nsresult rv = NS_NewByteInputStream(getter_AddRefs(stream), data,
+                                          abLength, NS_ASSIGNMENT_COPY);
+      NS_ENSURE_SUCCESS(rv, rv);
+      stream.forget(aResult);
+      aCharset.Truncate();
+
+      return NS_OK;
+    }
   }
   else if (dataType == nsIDataType::VTYPE_VOID ||
            dataType == nsIDataType::VTYPE_EMPTY) {
     // Makes us act as if !aBody, don't upload anything
     return NS_OK;
   }
 
   PRUnichar* data = nsnull;
--- a/content/base/src/nsXMLHttpRequest.h
+++ b/content/base/src/nsXMLHttpRequest.h
@@ -204,16 +204,17 @@ protected:
   nsresult DetectCharset(nsACString& aCharset);
   nsresult ConvertBodyToText(nsAString& aOutBuffer);
   static NS_METHOD StreamReaderFunc(nsIInputStream* in,
                 void* closure,
                 const char* fromRawSegment,
                 PRUint32 toOffset,
                 PRUint32 count,
                 PRUint32 *writeCount);
+  nsresult CreateResponseParsedJSON(JSContext* aCx);
   nsresult CreateResponseArrayBuffer(JSContext* aCx);
   void CreateResponseBlob(nsIRequest *request);
   // Change the state of the object with this. The broadcast argument
   // determines if the onreadystatechange listener should be called.
   nsresult ChangeState(PRUint32 aState, PRBool aBroadcast = PR_TRUE);
   already_AddRefed<nsILoadGroup> GetLoadGroup() const;
   nsIURI *GetBaseURI();
 
@@ -277,17 +278,18 @@ protected:
   // will cause us to clear the cached value anyway.
   nsString mResponseBodyUnicode;
 
   enum {
     XML_HTTP_RESPONSE_TYPE_DEFAULT,
     XML_HTTP_RESPONSE_TYPE_ARRAYBUFFER,
     XML_HTTP_RESPONSE_TYPE_BLOB,
     XML_HTTP_RESPONSE_TYPE_DOCUMENT,
-    XML_HTTP_RESPONSE_TYPE_TEXT
+    XML_HTTP_RESPONSE_TYPE_TEXT,
+    XML_HTTP_RESPONSE_TYPE_JSON
   } mResponseType;
 
   nsCOMPtr<nsIDOMBlob> mResponseBlob;
 
   nsCString mOverrideMimeType;
 
   /**
    * The notification callbacks the channel had when Send() was
@@ -323,16 +325,17 @@ protected:
   PRUint64 mLoadTotal; // 0 if not known.
   nsCOMPtr<nsITimer> mProgressNotifier;
 
   PRPackedBool mFirstStartRequestSeen;
   
   nsCOMPtr<nsIAsyncVerifyRedirectCallback> mRedirectCallback;
   nsCOMPtr<nsIChannel> mNewRedirectChannel;
   
+  jsval mResultJSON;
   JSObject* mResultArrayBuffer;
 
   struct RequestHeader
   {
     nsCString header;
     nsCString value;
   };
   nsTArray<RequestHeader> mModifiedRequestHeaders;
--- a/content/base/test/Makefile.in
+++ b/content/base/test/Makefile.in
@@ -63,17 +63,19 @@ XPCSHELL_TESTS = \
 ifneq ($(OS_ARCH),Darwin)
 XPCSHELL_TESTS += unit_ipc
 endif
 
 include $(topsrcdir)/config/rules.mk
 
 # Split files arbitrarily in two groups to not run into too-long command lines
 # which break on Windows (see bug 563151)
-_TEST_FILES1 = 	test_bug5141.html \
+_TEST_FILES1 = \
+		responseIdentical.sjs \
+		test_bug5141.html \
 		test_bug51034.html \
 		test_bug166235.html \
 		test_bug199959.html \
 		test_bug218236.html \
 		file_bug218236_multipart.txt \
 		file_bug218236_multipart.txt^headers^ \
 		test_bug218277.html \
 		test_bug238409.html \
@@ -499,16 +501,19 @@ include $(topsrcdir)/config/rules.mk
 		somedatas.resource \
 		somedatas.resource^headers^ \
 		delayedServerEvents.sjs \
 		test_bug664916.html \
 		test_bug666604.html \
 		test_bug675121.html \
 		file_bug675121.sjs \
 		test_bug654352.html \
+		test_bug682592.html \
+		bug682592-subframe.html \
+		bug682592-subframe-ref.html \
 		$(NULL)
 
 _CHROME_FILES =	\
 		test_bug357450.js \
 		$(NULL)
 
 # This test fails on the Mac for some reason
 ifneq (,$(filter gtk2 windows,$(MOZ_WIDGET_TOOLKIT)))
new file mode 100644
--- /dev/null
+++ b/content/base/test/bug682592-subframe-ref.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" >
+    <title></title>
+</head>
+<body>
+<p id="content"></p>
+</body>
+</html>
+
new file mode 100644
--- /dev/null
+++ b/content/base/test/bug682592-subframe.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" >
+    <title></title>
+</head>
+<body>
+<p id="content"></p>
+</body>
+</html>
--- a/content/base/test/chrome/test_bug683852.xul
+++ b/content/base/test/chrome/test_bug683852.xul
@@ -16,23 +16,25 @@ https://bugzilla.mozilla.org/show_bug.cg
 
   <!-- test code goes here -->
   <script type="application/javascript">
   <![CDATA[
   /** Test for Bug 683852 **/
   SimpleTest.waitForExplicitFinish();
 
   function startTest() {
-    is(document.contains(document), false, "Document should not contain itself!");
+    is(document.contains(document), true, "Document should contain itself!");
 
     var tb = document.getElementById("testbutton");
     is(document.contains(tb), true, "Document should contain element in it!");
+    is(tb.contains(tb), true, "Element should contain itself.")
     var anon = document.getAnonymousElementByAttribute(tb, "anonid", "button-box");
     is(document.contains(anon), false, "Document should not contain anonymous element in it!");
     is(tb.contains(anon), false, "Element should not contain anonymous element in it!");
+    is(anon.contains(anon), true, "Anonymous element should contain itself.")
     is(document.documentElement.contains(tb), true, "Element should contain element in it!");
     is(document.contains(document.createElement("foo")), false, "Document shouldn't contain element which is't in the document");
     is(document.contains(document.createTextNode("foo")), false, "Document shouldn't contain text node which is't in the document");
 
     var link = document.getElementById("link");
     is(document.contains(link.firstChild), true,
        "Document should contain a text node in it.");
     is(link.contains(link.firstChild), true,
@@ -45,17 +47,17 @@ https://bugzilla.mozilla.org/show_bug.cg
     is(pi.contains(document), false, "Processing instruction shouldn't contain document");
     document.documentElement.appendChild(pi);
     document.contains(pi, true, "Document should contain processing instruction");
 
     var df = document.createRange().createContextualFragment("<div>foo</div>");
     is(df.contains(df.firstChild), true, "Document fragment should contain its child");
     is(df.contains(df.firstChild.firstChild), true,
        "Document fragment should contain its descendant");
-    is(df.contains(df), false, "Document fragment shouldn't contain itself.");
+    is(df.contains(df), true, "Document fragment should contain itself.");
 
     var d = document.implementation.createHTMLDocument("");
     is(document.contains(d), false,
        "Document shouldn't contain another document.");
     is(document.contains(d.createElement("div")), false,
        "Document shouldn't contain an element from another document.");
 
     SimpleTest.finish();
new file mode 100644
--- /dev/null
+++ b/content/base/test/responseIdentical.sjs
@@ -0,0 +1,17 @@
+const CC = Components.Constructor;
+const BinaryInputStream = CC("@mozilla.org/binaryinputstream;1",
+                             "nsIBinaryInputStream",
+                             "setInputStream");
+
+// Simply sending back the same data that is received
+function handleRequest(request, response)
+{
+  var body = "";
+  var bodyStream = new BinaryInputStream(request.bodyInputStream);
+  var bytes = [], avail = 0;
+  while ((avail = bodyStream.available()) > 0)
+    body += String.fromCharCode.apply(String, bodyStream.readByteArray(avail));
+
+  response.setHeader("Content-Type", "application/octet-stream", false);
+  response.write(body);
+}
--- a/content/base/test/test_XHR.html
+++ b/content/base/test/test_XHR.html
@@ -9,16 +9,51 @@
 <p id="display"></p>
 <div id="content" style="display: none">
   
 </div>
 <pre id="test">
 <script class="testbody" type="text/javascript">
 SimpleTest.waitForExplicitFinish();
 
+// test receiving as JSON
+function testJSON(aJsonStr, invalid) {
+  var errorThrown = false;
+  var anotherErrorThrown = false;
+  var xhr = new XMLHttpRequest();
+  
+  var didthrow = false;
+  try { xhr.responseType = 'moz-json'; } catch (e) { didthrow = true; }
+  ok(didthrow, 
+     "should have thrown when setting responseType to moz-json before open");
+
+  xhr.open("POST", 'responseIdentical.sjs', false);
+  xhr.responseType = 'moz-json';
+  xhr.send(aJsonStr);
+
+  if (!invalid) {
+    is(JSON.stringify(xhr.response), aJsonStr);
+    is(xhr.response, xhr.response, "returning the same object on each access");
+  }
+  else {
+    var didThrow = false;
+    try { xhr.response } catch(ex) { didThrow = true; }
+    ok(didThrow, "accessing response should throw");
+
+    didThrow = false;
+    try { xhr.response } catch(ex) { didThrow = true; }
+    ok(didThrow, "accessing response should throw");
+  } 
+}
+
+var jsonStr = '{"title":"aBook","author":"john"}';
+testJSON(jsonStr, false);
+var invalidJson = '{ "abc": }'
+testJSON(invalidJson, true);
+
 var path = "/tests/content/base/test/";
 
 var passFiles = [['file_XHR_pass1.xml', 'GET'],
                  ['file_XHR_pass2.txt', 'GET'],
                  ['file_XHR_pass3.txt', 'GET'],
                  ];
 
 var failFiles = [['//example.com' + path + 'file_XHR_pass1.xml', 'GET'],
--- a/content/base/test/test_XHRSendData.html
+++ b/content/base/test/test_XHRSendData.html
@@ -35,16 +35,27 @@ is(testDoc2.inputEncoding, null, "wrong 
 netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
 
 var testData = "blahblahblahblahblahblahblaaaaaaaah. blah.";
 var extensions = [".txt",".png",".jpg",".gif",".xml", "noext"];
 var fileTypes = ["text/plain", "image/png", "image/jpeg", "image/gif", "text/xml", null];
 var testFiles = new Array;
 var testDOMFiles = new Array;
 
+// arraybuffer test objects
+var shortArray = new ArrayBuffer(1);
+var shortInt8View = new Uint8Array(shortArray);
+shortInt8View[0] = 3;
+
+var longArray = new ArrayBuffer(512);
+var longInt8View = new Uint8Array(longArray);
+for (var i = 0; i < longInt8View.length; i++) {
+  longInt8View[i] = i % 255;
+}
+
 extensions.forEach(
     function (extension) {
       var testFile = createFileWithDataExt(testData, extension);
       testFiles.push(testFile);
 
       var fileList = document.getElementById('fileList');
       fileList.value = testFile.path;
       testDOMFiles.push(fileList.files[0]);
@@ -139,47 +150,60 @@ tests = [{ body: null,
            contentType: "foo/bar; charset=uTf-8",
            resBody: "<!-- doc 2 -->\n<res>text</res>",
            resContentType: "foo/bar; charset=uTf-8",
          },
          { //will trigger a redirect test server-side
            body: ("TEST_REDIRECT_STR&url=" + window.location.host + window.location.pathname),
            redirect: true,
          },
+         { body: shortArray,
+           resBody: shortArray,
+           resType: "arraybuffer"
+         },
+         { body: longArray,
+           resBody: longArray,
+           resType: "arraybuffer"
+         },
          ];
 
 for (var i = 0; i < testDOMFiles.length; i++) {
   tests.push({ body: testDOMFiles[i],
                resBody: testData,
                resContentType: fileTypes[i],
                resContentLength: testData.length,
               });
 }
 
 try {
   for each(test in tests) {
     xhr = new XMLHttpRequest;
     xhr.open("POST", "file_XHRSendData.sjs", false);
     if (test.contentType)
       xhr.setRequestHeader("Content-Type", test.contentType);
+    if (test.resType)
+      xhr.responseType = test.resType;
     xhr.send(test.body);
 
     if (test.resContentType) {
       is(xhr.getResponseHeader("Result-Content-Type"), test.resContentType,
          "Wrong Content-Type sent");
     }
     else {
       is(xhr.getResponseHeader("Result-Content-Type"), null);
     }
 
     if (test.resContentLength) {
       is(xhr.getResponseHeader("Result-Content-Length"), test.resContentLength, "Wrong Content-Length sent");
     }
 
-    if (test.body instanceof Document) {
+    if (test.resType == "arraybuffer") {
+      is_identical_arraybuffer(xhr.response, test.resBody);
+    }
+    else if (test.body instanceof Document) {
       is(xhr.responseText.replace("\r\n", "\n"), test.resBody, "Wrong body");
     }
     else if (!test.redirect) {
       is(xhr.responseText, test.resBody, "Wrong body");
     }
     else {
       // If we're testing redirect, determine whether the body is
       // this document by looking for the relevant bug url
@@ -197,12 +221,20 @@ function cleanUpData() {
       function (testFile) {
         try {
           testFile.remove(false);
         } catch (e) {}
       }
   );
 }
 
+function is_identical_arraybuffer(ab1, ab2) {
+  is(ab1.byteLength, ab2.byteLength, "arraybuffer byteLengths not equal");
+  u8v1 = new Uint8Array(ab1);
+  u8v2 = new Uint8Array(ab2);
+  is(String.fromCharCode.apply(String, u8v1),
+     String.fromCharCode.apply(String, u8v2), "arraybuffer values not equal");
+}
+
 </script>
 </pre>
 </body>
 </html>
new file mode 100644
--- /dev/null
+++ b/content/base/test/test_bug682592.html
@@ -0,0 +1,170 @@
+<!DOCTYPE html>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=682592
+-->
+<head>
+    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" >
+    <title>Test for bug 682592</title>
+    <script type="text/javascript" src="/tests/SimpleTest/WindowSnapshot.js"></script>
+    <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+    <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<p id="display"></p>
+<div id="content">
+<iframe id="iframe-ref" src="bug682592-subframe-ref.html"></iframe>
+<iframe id="iframe-test"></iframe>
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript;version=1.7">
+/** Test for Bug 682592 **/
+
+/* 
+   We want to check that bidi is detected correctly. So, we have a reference
+   document where ltr is set explicitely with <bdo> element. Then, we compare
+   it with test document.
+
+   In mozilla, once bidi has been detected in a document, document always
+   consider it's in bidi mode. So, if one fragment enables bidi correctly, and
+   we create or update a fragment in the same document, that operation may not
+   enable bidi by itself, but it will not be detected. So, we need to have new
+   document for each test.
+
+   So, instead of many diferent reftests, this mochitest implements a
+   reftest-like. It creates reference text fragments in reference iframe, test
+   text fragments in test iframe, and compare the documents. Then, it reloads
+   test iframe. Reference iframe does not need to be reloaded between tests.
+   It's ok (and maybe, desired) to keep bidi always enabled in that document. 
+*/
+
+SimpleTest.waitForExplicitFinish();
+var refFrame = document.getElementById("iframe-ref")
+var testFrame = document.getElementById("iframe-test");
+
+refFrame.addEventListener("load", function() {
+  testFrame.addEventListener("load", function() {
+    try {
+      tests.next();
+      ok(compareSnapshots(snapshotWindow(testFrame.contentWindow), 
+                          snapshotWindow(refFrame.contentWindow), true)[0], 
+         "bidi is not detected correctly");
+
+      testFrame.contentWindow.location.reload();
+    } catch (err if err instanceof StopIteration) {
+      SimpleTest.finish();
+    }
+  }, false);
+  testFrame.src = "bug682592-subframe.html"
+}, false);
+
+var rtl = "עִבְרִית";
+var non8bit =  "ʃ";
+var is8bit = "a";
+
+// concats aStr aNumber of times
+function strMult(aStr, aNumber) {
+  if (aNumber === 0) {
+    return "";
+  }
+  return strMult(aStr, aNumber - 1) + aStr;
+}
+
+function runTests () {
+  var ltr = "", prefix = null;
+  var refContainer = refFrame.contentDocument.getElementById('content');
+  var testContainer, textNode;
+  var i = 0;
+
+  // 8bit chars + bidi
+  for (i = 0; i <= 16; i++) {
+    ltr = strMult(is8bit, i);
+    refContainer.innerHTML = ltr + '<bdo dir="rtl">' + rtl + '</bdo>';
+    testContainer = testFrame.contentDocument.getElementById('content');
+    testContainer.innerHTML = ltr + rtl;
+    yield;
+  }
+
+  // non-8bit char + 8bit chars + bidi
+  for (i = 0; i <= 16; i++) {
+    ltr = non8bit + strMult(is8bit, i);
+    refContainer.innerHTML = ltr + '<bdo dir="rtl">' + rtl + '</bdo>';
+    testContainer = testFrame.contentDocument.getElementById('content');
+    testContainer.innerHTML = ltr + rtl;
+    yield;
+  }
+
+  // appendData
+  for (i = 0; i <= 16; i++) {
+    ltr = strMult(is8bit, i);
+    refContainer.innerHTML = ltr + '<bdo dir="rtl">' + rtl + '</bdo>';
+    testContainer = testFrame.contentDocument.getElementById('content');
+    textNode = document.createTextNode("");
+    testContainer.appendChild(textNode);
+    textNode.appendData(ltr + rtl);
+    yield;
+  }
+
+  for (i = 0; i <= 16; i++) {
+    ltr = non8bit + strMult(is8bit, i);
+    refContainer.innerHTML = ltr + '<bdo dir="rtl">' + rtl + '</bdo>';
+    testContainer = testFrame.contentDocument.getElementById('content');
+    textNode = document.createTextNode("");
+    testContainer.appendChild(textNode);
+    textNode.appendData(ltr + rtl);
+    yield;
+  }
+
+  // appendData with 8bit prefix
+  for (i = 0; i <= 16; i++) {
+    prefix = is8bit;
+    ltr = strMult(is8bit, i);
+    refContainer.innerHTML = prefix + ltr + '<bdo dir="rtl">' + rtl + '</bdo>';
+    testContainer = testFrame.contentDocument.getElementById('content');
+    textNode = document.createTextNode(prefix);
+    testContainer.appendChild(textNode);
+    textNode.appendData(ltr + rtl);
+    yield;
+  }
+
+  for (i = 0; i <= 16; i++) {
+    prefix = is8bit;
+    ltr = non8bit + strMult(is8bit, i);
+    refContainer.innerHTML = prefix + ltr + '<bdo dir="rtl">' + rtl + '</bdo>';
+    testContainer = testFrame.contentDocument.getElementById('content');
+    textNode = document.createTextNode(prefix);
+    testContainer.appendChild(textNode);
+    textNode.appendData(ltr + rtl);
+    yield;
+  }
+
+  // appendData with non-8bit prefix
+  for (i = 0; i <= 16; i++) {
+    prefix = non8bit;
+    ltr = strMult(is8bit, i);
+    refContainer.innerHTML = prefix + ltr + '<bdo dir="rtl">' + rtl + '</bdo>';
+    testContainer = testFrame.contentDocument.getElementById('content');
+    textNode = document.createTextNode(prefix);
+    testContainer.appendChild(textNode);
+    textNode.appendData(ltr + rtl);
+    yield;
+  }
+
+  for (i = 0; i <= 16; i++) {
+    prefix = non8bit;
+    ltr = non8bit + strMult(is8bit, i);
+    refContainer.innerHTML = prefix + ltr + '<bdo dir="rtl">' + rtl + '</bdo>';
+    testContainer = testFrame.contentDocument.getElementById('content');
+    textNode = document.createTextNode(prefix);
+    testContainer.appendChild(textNode);
+    textNode.appendData(ltr + rtl);
+    yield;
+  }
+};
+
+var tests = runTests();
+
+</script>
+</pre>
+</body>
+</html>
--- a/content/canvas/src/CanvasUtils.cpp
+++ b/content/canvas/src/CanvasUtils.cpp
@@ -60,17 +60,18 @@
 #include "mozilla/gfx/Matrix.h"
 
 namespace mozilla {
 namespace CanvasUtils {
 
 void
 DoDrawImageSecurityCheck(nsHTMLCanvasElement *aCanvasElement,
                          nsIPrincipal *aPrincipal,
-                         PRBool forceWriteOnly)
+                         PRBool forceWriteOnly,
+                         PRBool CORSUsed)
 {
     // Callers should ensure that mCanvasElement is non-null before calling this
     if (!aCanvasElement) {
         NS_WARNING("DoDrawImageSecurityCheck called without canvas element!");
         return;
     }
 
     if (aCanvasElement->IsWriteOnly())
@@ -80,16 +81,20 @@ DoDrawImageSecurityCheck(nsHTMLCanvasEle
     if (forceWriteOnly) {
         aCanvasElement->SetWriteOnly();
         return;
     }
 
     if (aPrincipal == nsnull)
         return;
 
+    // No need to do a security check if the image used CORS for the load
+    if (CORSUsed)
+        return;
+
     PRBool subsumes;
     nsresult rv =
         aCanvasElement->NodePrincipal()->Subsumes(aPrincipal, &subsumes);
 
     if (NS_SUCCEEDED(rv) && subsumes) {
         // This canvas has access to that image anyway
         return;
     }
--- a/content/canvas/src/CanvasUtils.h
+++ b/content/canvas/src/CanvasUtils.h
@@ -69,17 +69,18 @@ inline PRBool CheckSaneSubrectSize(PRInt
         checked_ymost.value() <= realHeight;
 }
 
 // Flag aCanvasElement as write-only if drawing an image with aPrincipal
 // onto it would make it such.
 
 void DoDrawImageSecurityCheck(nsHTMLCanvasElement *aCanvasElement,
                               nsIPrincipal *aPrincipal,
-                              PRBool forceWriteOnly);
+                              PRBool forceWriteOnly,
+                              PRBool CORSUsed);
 
 void LogMessage (const nsCString& errorString);
 void LogMessagef (const char *fmt, ...);
 
 // Make a double out of |v|, treating undefined values as 0.0 (for
 // the sake of sparse arrays).  Return true iff coercion
 // succeeded.
 bool CoerceDouble(jsval v, double* d);
--- a/content/canvas/src/WebGLContext.h
+++ b/content/canvas/src/WebGLContext.h
@@ -497,17 +497,19 @@ protected:
     PRBool ValidateFaceEnum(WebGLenum face, const char *info);
     PRBool ValidateBufferUsageEnum(WebGLenum target, const char *info);
     PRBool ValidateTexFormatAndType(WebGLenum format, WebGLenum type, int jsArrayType,
                                       PRUint32 *texelSize, const char *info);
     PRBool ValidateDrawModeEnum(WebGLenum mode, const char *info);
     PRBool ValidateAttribIndex(WebGLuint index, const char *info);
     PRBool ValidateStencilParamsForDrawCall();
     
-    bool  ValidateGLSLIdentifier(const nsAString& name, const char *info);
+    bool ValidateGLSLVariableName(const nsAString& name, const char *info);
+    bool ValidateGLSLCharacter(PRUnichar c);
+    bool ValidateGLSLString(const nsAString& string, const char *info);
 
     static PRUint32 GetTexelSize(WebGLenum format, WebGLenum type);
 
     void Invalidate();
     void DestroyResourcesAndContext();
 
     void MakeContextCurrent() { gl->MakeCurrent(); }
 
@@ -808,37 +810,41 @@ public:
     void SetByteLength(GLuint byteLength) { mByteLength = byteLength; }
     void SetTarget(GLenum target) { mTarget = target; }
 
     // element array buffers are the only buffers for which we need to keep a copy of the data.
     // this method assumes that the byte length has previously been set by calling SetByteLength.
     PRBool CopyDataIfElementArray(const void* data) {
         if (mTarget == LOCAL_GL_ELEMENT_ARRAY_BUFFER) {
             mData = realloc(mData, mByteLength);
-            if (!mData)
+            if (!mData) {
+                mByteLength = 0;
                 return PR_FALSE;
+            }
             memcpy(mData, data, mByteLength);
         }
         return PR_TRUE;
     }
 
     // same comments as for CopyElementArrayData
     PRBool ZeroDataIfElementArray() {
         if (mTarget == LOCAL_GL_ELEMENT_ARRAY_BUFFER) {
             mData = realloc(mData, mByteLength);
-            if (!mData)
+            if (!mData) {
+                mByteLength = 0;
                 return PR_FALSE;
+            }
             memset(mData, 0, mByteLength);
         }
         return PR_TRUE;
     }
 
     // same comments as for CopyElementArrayData
     void CopySubDataIfElementArray(GLuint byteOffset, GLuint byteLength, const void* data) {
-        if (mTarget == LOCAL_GL_ELEMENT_ARRAY_BUFFER) {
+        if (mTarget == LOCAL_GL_ELEMENT_ARRAY_BUFFER && mByteLength) {
             memcpy((void*) (size_t(mData)+byteOffset), data, byteLength);
         }
     }
 
     // this method too is only for element array buffers. It returns the maximum value in the part of
     // the buffer starting at given offset, consisting of given count of elements. The type T is the type
     // to interprete the array elements as, must be GLushort or GLubyte.
     template<typename T>
@@ -1040,20 +1046,16 @@ protected:
     }
 
     PRBool CheckFloatTextureFilterParams() const {
         // Without OES_texture_float_linear, only NEAREST and NEAREST_MIMPAMP_NEAREST are supported
         return (mMagFilter == LOCAL_GL_NEAREST) &&
             (mMinFilter == LOCAL_GL_NEAREST || mMinFilter == LOCAL_GL_NEAREST_MIPMAP_NEAREST);
     }
 
-    PRBool DoesMinFilterRequireMipmap() const {
-        return !(mMinFilter == LOCAL_GL_NEAREST || mMinFilter == LOCAL_GL_LINEAR);
-    }
-
     PRBool AreBothWrapModesClampToEdge() const {
         return mWrapS == LOCAL_GL_CLAMP_TO_EDGE && mWrapT == LOCAL_GL_CLAMP_TO_EDGE;
     }
 
     PRBool DoesTexture2DMipmapHaveAllLevelsConsistentlyDefined(size_t face) const {
         if (mHaveGeneratedMipmap)
             return PR_TRUE;
 
@@ -1147,16 +1149,22 @@ public:
     void SetWrapS(WebGLenum aWrapS) {
         mWrapS = aWrapS;
         SetDontKnowIfNeedFakeBlack();
     }
     void SetWrapT(WebGLenum aWrapT) {
         mWrapT = aWrapT;
         SetDontKnowIfNeedFakeBlack();
     }
+    
+    WebGLenum MinFilter() const { return mMinFilter; }
+
+    PRBool DoesMinFilterRequireMipmap() const {
+        return !(mMinFilter == LOCAL_GL_NEAREST || mMinFilter == LOCAL_GL_LINEAR);
+    }
 
     void SetGeneratedMipmap() {
         if (!mHaveGeneratedMipmap) {
             mHaveGeneratedMipmap = PR_TRUE;
             SetDontKnowIfNeedFakeBlack();
         }
     }
 
@@ -1361,44 +1369,44 @@ public:
     PRBool Deleted() { return mDeleted && mAttachCount == 0; }
     WebGLuint GLName() { return mName; }
     WebGLenum ShaderType() { return mType; }
 
     PRUint32 AttachCount() { return mAttachCount; }
     void IncrementAttachCount() { mAttachCount++; }
     void DecrementAttachCount() { mAttachCount--; }
 
-    void SetSource(const nsCString& src) {
+    void SetSource(const nsAString& src) {
         // XXX do some quick gzip here maybe -- getting this will be very rare
         mSource.Assign(src);
     }
 
-    const nsCString& Source() const { return mSource; }
+    const nsString& Source() const { return mSource; }
 
     void SetNeedsTranslation() { mNeedsTranslation = true; }
     bool NeedsTranslation() const { return mNeedsTranslation; }
 
     void SetTranslationSuccess() {
         mTranslationLog.SetIsVoid(PR_TRUE);
         mNeedsTranslation = false;
     }
 
     void SetTranslationFailure(const nsCString& msg) {
-        mTranslationLog.Assign(msg);
+        mTranslationLog.Assign(msg); 
     }
 
     const nsCString& TranslationLog() const { return mTranslationLog; }
 
     NS_DECL_ISUPPORTS
     NS_DECL_NSIWEBGLSHADER
 protected:
     WebGLuint mName;
     PRBool mDeleted;
     WebGLenum mType;
-    nsCString mSource;
+    nsString mSource;
     nsCString mTranslationLog;
     bool mNeedsTranslation;
     PRUint32 mAttachCount;
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(WebGLShader, WEBGLSHADER_PRIVATE_IID)
 
 #define WEBGLPROGRAM_PRIVATE_IID \
--- a/content/canvas/src/WebGLContextGL.cpp
+++ b/content/canvas/src/WebGLContextGL.cpp
@@ -57,16 +57,17 @@
 #include "jstypedarray.h"
 
 #if defined(USE_ANGLE)
 // shader translator
 #include "angle/ShaderLang.h"
 #endif
 
 #include "WebGLTexelConversions.h"
+#include "WebGLValidateStrings.h"
 
 using namespace mozilla;
 
 static PRBool BaseTypeAndSizeFromUniformType(WebGLenum uType, WebGLenum *baseType, WebGLint *unitSize);
 static WebGLenum InternalFormatForFormatAndType(WebGLenum format, WebGLenum type, bool isGLES2);
 
 /* Helper macros for when we're just wrapping a gl method, so that
  * we can avoid having to type this 500 times.  Note that these MUST
@@ -177,18 +178,18 @@ WebGLContext::AttachShader(nsIWebGLProgr
 
 NS_IMETHODIMP
 WebGLContext::BindAttribLocation(nsIWebGLProgram *pobj, WebGLuint location, const nsAString& name)
 {
     WebGLuint progname;
     if (!GetGLName<WebGLProgram>("bindAttribLocation: program", pobj, &progname))
         return NS_OK;
 
-    if (name.IsEmpty())
-        return ErrorInvalidValue("BindAttribLocation: name can't be null or empty");
+    if (!ValidateGLSLVariableName(name, "bindAttribLocation"))
+        return NS_OK;
 
     if (!ValidateAttribIndex(location, "bindAttribLocation"))
         return NS_OK;
 
     MakeContextCurrent();
 
     gl->fBindAttribLocation(progname, location, NS_LossyConvertUTF16toASCII(name).get());
 
@@ -1745,17 +1746,38 @@ WebGLContext::GenerateMipmap(WebGLenum t
 
     if (!tex->AreAllLevel0ImageInfosEqual()) {
         return ErrorInvalidOperation("generateMipmap: the six faces of this cube map have different dimensions, format, or type.");
     }
 
     tex->SetGeneratedMipmap();
 
     MakeContextCurrent();
+
+#ifdef XP_MACOSX
+    // On Mac, glGenerateMipmap on a texture whose minification filter does NOT require a mipmap at the time of the call,
+    // will happily grab random video memory into certain mipmap levels. See bug 684882. Also, this is Apple bug 9129398.
+    // Thanks to Kenneth Russell / Google for figuring this out.
+    // So we temporarily spoof the minification filter, call glGenerateMipmap,
+    // and restore it. If that turned out to not be enough, we would have to avoid calling glGenerateMipmap altogether and
+    // emulate it.
+    if (tex->DoesMinFilterRequireMipmap()) {
+        gl->fGenerateMipmap(target);
+    } else {
+        // spoof the min filter as something that requires a mipmap. The particular choice of a filter doesn't matter as
+        // we're not rendering anything here. Since LINEAR_MIPMAP_LINEAR is by far the most common use case, and we're trying
+        // to work around a bug triggered by "unexpected" min filters, it seems to be the safest choice.
+        gl->fTexParameteri(target, LOCAL_GL_TEXTURE_MIN_FILTER, LOCAL_GL_LINEAR_MIPMAP_LINEAR);
+        gl->fGenerateMipmap(target);
+        gl->fTexParameteri(target, LOCAL_GL_TEXTURE_MIN_FILTER, tex->MinFilter());
+    }
+#else
     gl->fGenerateMipmap(target);
+#endif
+    
     return NS_OK;
 }
 
 NS_IMETHODIMP
 WebGLContext::GetActiveUniform(nsIWebGLProgram *pobj, PRUint32 index, nsIWebGLActiveInfo **retval)
 {
     *retval = nsnull;
 
@@ -1851,17 +1873,17 @@ WebGLContext::GetAttribLocation(nsIWebGL
                                 PRInt32 *retval)
 {
     *retval = 0;
 
     WebGLuint progname;
     if (!GetGLName<WebGLProgram>("getAttribLocation: program", pobj, &progname))
         return NS_OK;
 
-    if (!ValidateGLSLIdentifier(name, "getAttribLocation"))
+    if (!ValidateGLSLVariableName(name, "getAttribLocation"))
         return NS_OK; 
 
     MakeContextCurrent();
     *retval = gl->fGetAttribLocation(progname, NS_LossyConvertUTF16toASCII(name).get());
     return NS_OK;
 }
 
 NS_IMETHODIMP
@@ -2666,17 +2688,17 @@ WebGLContext::GetUniformLocation(nsIWebG
 {
     *retval = nsnull;
 
     WebGLuint progname;
     WebGLProgram *prog;
     if (!GetConcreteObjectAndGLName("getUniformLocation: program", pobj, &prog, &progname))
         return NS_OK;
 
-    if (!ValidateGLSLIdentifier(name, "getUniformLocation"))
+    if (!ValidateGLSLVariableName(name, "getUniformLocation"))
         return NS_OK; 
 
     MakeContextCurrent();
 
     GLint intlocation = gl->fGetUniformLocation(progname, NS_LossyConvertUTF16toASCII(name).get());
 
     nsRefPtr<nsIWebGLUniformLocation> loc = prog->GetUniformLocationObject(intlocation);
     *retval = loc.forget().get();
@@ -3579,29 +3601,23 @@ WebGLContext::DOMElementToImageSurface(n
     // To prevent a loophole where a Canvas2D would be used as a proxy to load
     // cross-domain textures, we also disallow loading textures from write-only
     // Canvas2D's.
 
     // part 1: check that the DOM element is same-origin, or has otherwise been
     // validated for cross-domain use.
     // if res.mPrincipal == null, no need for the origin check. See DoDrawImageSecurityCheck.
     // this case happens in the mochitest for images served from mochi.test:8888
-    if (res.mPrincipal) {
+    if (res.mPrincipal && !res.mCORSUsed) {
         PRBool subsumes;
         nsresult rv = HTMLCanvasElement()->NodePrincipal()->Subsumes(res.mPrincipal, &subsumes);
         if (NS_FAILED(rv) || !subsumes) {
-            PRInt32 corsmode;
-            if (!res.mImageRequest || NS_FAILED(res.mImageRequest->GetCORSMode(&corsmode))) {
-                corsmode = imgIRequest::CORS_NONE;
-            }
-            if (corsmode == imgIRequest::CORS_NONE) {
-                LogMessageIfVerbose("It is forbidden to load a WebGL texture from a cross-domain element that has not been validated with CORS. "
-                                    "See https://developer.mozilla.org/en/WebGL/Cross-Domain_Textures");
-                return NS_ERROR_DOM_SECURITY_ERR;
-            }
+            LogMessageIfVerbose("It is forbidden to load a WebGL texture from a cross-domain element that has not been validated with CORS. "
+                                "See https://developer.mozilla.org/en/WebGL/Cross-Domain_Textures");
+            return NS_ERROR_DOM_SECURITY_ERR;
         }
     }
 
     // part 2: if the DOM element is a canvas, check that it's not write-only. That would indicate a tainted canvas,
     // i.e. a canvas that could contain cross-domain image data.
     nsCOMPtr<nsIContent> maybeDOMCanvas = do_QueryInterface(imageOrCanvas);
     if (maybeDOMCanvas && maybeDOMCanvas->IsHTML(nsGkAtoms::canvas)) {
         nsHTMLCanvasElement *canvas = static_cast<nsHTMLCanvasElement*>(maybeDOMCanvas.get());
@@ -3971,18 +3987,35 @@ WebGLContext::CompileShader(nsIWebGLShad
         resources.MaxFragmentUniformVectors = mGLMaxFragmentUniformVectors;
         resources.MaxDrawBuffers = 1;
 
         compiler = ShConstructCompiler((ShShaderType) shader->ShaderType(),
                                        SH_WEBGL_SPEC,
                                        gl->IsGLES2() ? SH_ESSL_OUTPUT : SH_GLSL_OUTPUT,
                                        &resources);
 
-        nsPromiseFlatCString src(shader->Source());
-        const char *s = src.get();
+        // We're storing an actual instance of StripComments because, if we don't, the 
+        // cleanSource nsAString instance will be destroyed before the reference is
+        // actually used.
+        StripComments stripComments(shader->Source());
+        const nsAString& cleanSource = nsString(stripComments.result().Elements(), stripComments.length());
+        if (!ValidateGLSLString(cleanSource, "compileShader"))
+            return NS_OK;
+
+        const nsPromiseFlatString& flatSource = PromiseFlatString(cleanSource);
+
+        // shaderSource() already checks that the source stripped of comments is in the
+        // 7-bit ASCII range, so we can skip the NS_IsAscii() check.
+        const nsCString& sourceCString = NS_LossyConvertUTF16toASCII(flatSource);
+    
+        const PRUint32 maxSourceLength = (PRUint32(1)<<18) - 1;
+        if (sourceCString.Length() > maxSourceLength)
+            return ErrorInvalidValue("compileShader: source has more than %d characters", maxSourceLength);
+
+        const char *s = sourceCString.get();
 
         if (!ShCompile(compiler, &s, 1, SH_OBJECT_CODE)) {
             int len = 0;
             ShGetInfo(compiler, SH_INFO_LOG_LENGTH, &len);
 
             if (len) {
                 nsCAutoString info;
                 info.SetLength(len);
@@ -4013,25 +4046,20 @@ WebGLContext::CompileShader(nsIWebGLShad
             gl->fShaderSource(shadername, 1, &ts, NULL);
         } else {
             gl->fShaderSource(shadername, 1, &s, NULL);
         }
 
         shader->SetTranslationSuccess();
 
         ShDestruct(compiler);
-    } else
+
+        gl->fCompileShader(shadername);
+    }
 #endif
-    {
-        const char *s = nsDependentCString(shader->Source()).get();
-        gl->fShaderSource(shadername, 1, &s, NULL);
-        shader->SetTranslationSuccess();
-    }
-
-    gl->fCompileShader(shadername);
 
     return NS_OK;
 }
 
 
 NS_IMETHODIMP
 WebGLContext::GetShaderParameter(nsIWebGLShader *sobj, WebGLenum pname, nsIVariant **retval)
 {
@@ -4120,41 +4148,38 @@ WebGLContext::GetShaderInfoLog(nsIWebGLS
 NS_IMETHODIMP
 WebGLContext::GetShaderSource(nsIWebGLShader *sobj, nsAString& retval)
 {
     WebGLShader *shader;
     WebGLuint shadername;
     if (!GetConcreteObjectAndGLName("getShaderSource: shader", sobj, &shader, &shadername))
         return NS_OK;
 
-    CopyASCIItoUTF16(shader->Source(), retval);
+    retval.Assign(shader->Source());
 
     return NS_OK;
 }
 
 NS_IMETHODIMP
 WebGLContext::ShaderSource(nsIWebGLShader *sobj, const nsAString& source)
 {
     WebGLShader *shader;
     WebGLuint shadername;
     if (!GetConcreteObjectAndGLName("shaderSource: shader", sobj, &shader, &shadername))
         return NS_OK;
-    
-    const nsPromiseFlatString& flatSource = PromiseFlatString(source);
-
-    if (!NS_IsAscii(flatSource.get()))
-        return ErrorInvalidValue("shaderSource: non-ascii characters found in source");
-
-    const nsCString& sourceCString = NS_LossyConvertUTF16toASCII(flatSource);
-    
-    const PRUint32 maxSourceLength = (PRUint32(1)<<18) - 1;
-    if (sourceCString.Length() > maxSourceLength)
-        return ErrorInvalidValue("shaderSource: source has more than %d characters", maxSourceLength);
-    
-    shader->SetSource(sourceCString);
+
+    // We're storing an actual instance of StripComments because, if we don't, the 
+    // cleanSource nsAString instance will be destroyed before the reference is
+    // actually used.
+    StripComments stripComments(source);
+    const nsAString& cleanSource = nsString(stripComments.result().Elements(), stripComments.length());
+    if (!ValidateGLSLString(cleanSource, "compileShader"))
+        return NS_OK;
+
+    shader->SetSource(source);
 
     shader->SetNeedsTranslation();
 
     return NS_OK;
 }
 
 NS_IMETHODIMP
 WebGLContext::VertexAttribPointer(WebGLuint index, WebGLint size, WebGLenum type,
--- a/content/canvas/src/WebGLContextValidate.cpp
+++ b/content/canvas/src/WebGLContextValidate.cpp
@@ -323,24 +323,41 @@ PRBool WebGLContext::ValidateDrawModeEnu
         case LOCAL_GL_LINES:
             return PR_TRUE;
         default:
             ErrorInvalidEnumInfo(info, mode);
             return PR_FALSE;
     }
 }
 
-bool WebGLContext::ValidateGLSLIdentifier(const nsAString& name, const char *info)
+bool WebGLContext::ValidateGLSLVariableName(const nsAString& name, const char *info)
 {
-    const PRUint32 maxSize = 4095;
+    const PRUint32 maxSize = 255;
     if (name.Length() > maxSize) {
         ErrorInvalidValue("%s: identifier is %d characters long, exceeds the maximum allowed length of %d characters",
                           info, name.Length(), maxSize);
         return false;
     }
+
+    if (!ValidateGLSLString(name, info)) {
+        return false;
+    }
+
+    return true;
+}
+
+bool WebGLContext::ValidateGLSLString(const nsAString& string, const char *info)
+{
+    for (PRUint32 i = 0; i < string.Length(); ++i) {
+        if (!ValidateGLSLCharacter(string.CharAt(i))) {
+             ErrorInvalidValue("%s: string contains the illegal character '%d'", info, string.CharAt(i));
+             return false;
+        }
+    }
+
     return true;
 }
 
 PRUint32 WebGLContext::GetTexelSize(WebGLenum format, WebGLenum type)
 {
     if (type == LOCAL_GL_UNSIGNED_BYTE || type == LOCAL_GL_FLOAT) {
         int multiplier = type == LOCAL_GL_FLOAT ? 4 : 1;
         switch (format) {
new file mode 100644
--- /dev/null
+++ b/content/canvas/src/WebGLValidateStrings.h
@@ -0,0 +1,251 @@
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ * Copyright (C) 2011 Mozilla Corporation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef WEBGLVALIDATESTRINGS_H_
+#define WEBGLVALIDATESTRINGS_H_
+
+#include "WebGLContext.h"
+
+namespace mozilla {
+
+// The following code was taken from the WebKit WebGL implementation,
+// which can be found here:
+// http://trac.webkit.org/browser/trunk/Source/WebCore/html/canvas/WebGLRenderingContext.cpp?rev=93625#L121
+// Note that some modifications were done to adapt it to Mozilla.
+/****** BEGIN CODE TAKEN FROM WEBKIT ******/
+    bool WebGLContext::ValidateGLSLCharacter(PRUnichar c)
+    {
+        // Printing characters are valid except " $ ` @ \ ' DEL.
+        if (c >= 32 && c <= 126 &&
+            c != '"' && c != '$' && c != '`' && c != '@' && c != '\\' && c != '\'')
+        {
+             return true;
+        }
+
+        // Horizontal tab, line feed, vertical tab, form feed, carriage return are also valid.
+        if (c >= 9 && c <= 13) {
+             return true;
+        }
+
+        return false;
+    }
+
+    // Strips comments from shader text. This allows non-ASCII characters
+    // to be used in comments without potentially breaking OpenGL
+    // implementations not expecting characters outside the GLSL ES set.
+    class StripComments {
+    public:
+        StripComments(const nsAString& str)
+            : m_parseState(BeginningOfLine)
+            , m_end(str.EndReading())
+            , m_current(str.BeginReading())
+            , m_position(0)
+        {
+            m_result.SetLength(str.Length());
+            parse();
+        }
+
+        const nsTArray<PRUnichar>& result()
+        {
+            return m_result;
+        }
+
+        size_t length()
+        {
+            return m_position;
+        }
+
+    private:
+        bool hasMoreCharacters()
+        {
+            return (m_current < m_end);
+        }
+
+        void parse()
+        {
+            while (hasMoreCharacters()) {
+                process(current());
+                // process() might advance the position.
+                if (hasMoreCharacters())
+                    advance();
+            }
+        }
+
+        void process(PRUnichar);
+
+        bool peek(PRUnichar& character)
+        {
+            if (m_current + 1 >= m_end)
+                return false;
+            character = *(m_current + 1);
+            return true;
+        }
+
+        PRUnichar current()
+        {
+            //ASSERT(m_position < m_length);
+            return *m_current;
+        }
+
+        void advance()
+        {
+            ++m_current;
+        }
+
+        bool isNewline(PRUnichar character)
+        {
+            // Don't attempt to canonicalize newline related characters.
+            return (character == '\n' || character == '\r');
+        }
+
+        void emit(PRUnichar character)
+        {
+            m_result[m_position++] = character;
+        }
+
+        enum ParseState {
+            // Have not seen an ASCII non-whitespace character yet on
+            // this line. Possible that we might see a preprocessor
+            // directive.
+            BeginningOfLine,
+
+            // Have seen at least one ASCII non-whitespace character
+            // on this line.
+            MiddleOfLine,
+
+            // Handling a preprocessor directive. Passes through all
+            // characters up to the end of the line. Disables comment
+            // processing.
+            InPreprocessorDirective,
+
+            // Handling a single-line comment. The comment text is
+            // replaced with a single space.
+            InSingleLineComment,
+
+            // Handling a multi-line comment. Newlines are passed
+            // through to preserve line numbers.
+            InMultiLineComment
+        };
+
+        ParseState m_parseState;
+        const PRUnichar* m_end;
+        const PRUnichar* m_current;
+        size_t m_position;
+        nsTArray<PRUnichar> m_result;
+    };
+
+    void StripComments::process(PRUnichar c)
+    {
+        if (isNewline(c)) {
+            // No matter what state we are in, pass through newlines
+            // so we preserve line numbers.
+            emit(c);
+
+            if (m_parseState != InMultiLineComment)
+                m_parseState = BeginningOfLine;
+
+            return;
+        }
+
+        PRUnichar temp = 0;
+        switch (m_parseState) {
+        case BeginningOfLine:
+            // If it's an ASCII space.
+            if (c <= ' ' && (c == ' ' || (c <= 0xD && c >= 0x9))) {
+                emit(c);
+                break;
+            }
+
+            if (c == '#') {
+                m_parseState = InPreprocessorDirective;
+                emit(c);
+                break;
+            }
+
+            // Transition to normal state and re-handle character.
+            m_parseState = MiddleOfLine;
+            process(c);
+            break;
+
+        case MiddleOfLine:
+            if (c == '/' && peek(temp)) {
+                if (temp == '/') {
+                    m_parseState = InSingleLineComment;
+                    emit(' ');
+                    advance();
+                    break;
+                }
+
+                if (temp == '*') {
+                    m_parseState = InMultiLineComment;
+                    // Emit the comment start in case the user has
+                    // an unclosed comment and we want to later
+                    // signal an error.
+                    emit('/');
+                    emit('*');
+                    advance();
+                    break;
+                }
+            }
+
+            emit(c);
+            break;
+
+        case InPreprocessorDirective:
+            // No matter what the character is, just pass it
+            // through. Do not parse comments in this state. This
+            // might not be the right thing to do long term, but it
+            // should handle the #error preprocessor directive.
+            emit(c);
+            break;
+
+        case InSingleLineComment:
+            // The newline code at the top of this function takes care
+            // of resetting our state when we get out of the
+            // single-line comment. Swallow all other characters.
+            break;
+
+        case InMultiLineComment:
+            if (c == '*' && peek(temp) && temp == '/') {
+                emit('*');
+                emit('/');
+                m_parseState = MiddleOfLine;
+                advance();
+                break;
+            }
+
+            // Swallow all other characters. Unclear whether we may
+            // want or need to just emit a space per character to try
+            // to preserve column numbers for debugging purposes.
+            break;
+        }
+    }
+
+/****** END CODE TAKEN FROM WEBKIT ******/
+
+} // end namespace mozilla
+
+#endif // WEBGLVALIDATESTRINGS_H_
--- a/content/canvas/src/nsCanvasRenderingContext2D.cpp
+++ b/content/canvas/src/nsCanvasRenderingContext2D.cpp
@@ -241,36 +241,40 @@ NS_INTERFACE_MAP_END
     { 0xb85c6c8a, 0x0624, 0x4530, { 0xb8, 0xee, 0xff, 0xdf, 0x42, 0xe8, 0x21, 0x6d } }
 class nsCanvasPattern : public nsIDOMCanvasPattern
 {
 public:
     NS_DECLARE_STATIC_IID_ACCESSOR(NS_CANVASPATTERN_PRIVATE_IID)
 
     nsCanvasPattern(gfxPattern* pat,
                     nsIPrincipal* principalForSecurityCheck,
-                    PRBool forceWriteOnly)
+                    PRBool forceWriteOnly,
+                    PRBool CORSUsed)
         : mPattern(pat),
           mPrincipal(principalForSecurityCheck),
-          mForceWriteOnly(forceWriteOnly)
+          mForceWriteOnly(forceWriteOnly),
+          mCORSUsed(CORSUsed)
     {
     }
 
-    gfxPattern* GetPattern() {
+    gfxPattern* GetPattern() const {
         return mPattern;
     }
 
-    nsIPrincipal* Principal() { return mPrincipal; }
-    PRBool GetForceWriteOnly() { return mForceWriteOnly; }
+    nsIPrincipal* Principal() const { return mPrincipal; }
+    PRBool GetForceWriteOnly() const { return mForceWriteOnly; }
+    PRBool GetCORSUsed() const { return mCORSUsed; }
 
     NS_DECL_ISUPPORTS
 
 protected:
     nsRefPtr<gfxPattern> mPattern;
     nsCOMPtr<nsIPrincipal> mPrincipal;
-    PRPackedBool mForceWriteOnly;
+    const PRPackedBool mForceWriteOnly;
+    const PRPackedBool mCORSUsed;
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsCanvasPattern, NS_CANVASPATTERN_PRIVATE_IID)
 
 NS_IMPL_ADDREF(nsCanvasPattern)
 NS_IMPL_RELEASE(nsCanvasPattern)
 
 DOMCI_DATA(CanvasPattern, nsCanvasPattern)
@@ -989,17 +993,18 @@ nsCanvasRenderingContext2D::ApplyStyle(S
         mDirtyStyle[aWhichStyle] = PR_FALSE;
     mLastStyle = aWhichStyle;
 
     nsCanvasPattern* pattern = CurrentState().patternStyles[aWhichStyle];
     if (pattern) {
         if (mCanvasElement)
             CanvasUtils::DoDrawImageSecurityCheck(HTMLCanvasElement(),
                                                   pattern->Principal(),
-                                                  pattern->GetForceWriteOnly());
+                                                  pattern->GetForceWriteOnly(),
+                                                  pattern->GetCORSUsed());
 
         gfxPattern* gpat = pattern->GetPattern();
 
         if (CurrentState().imageSmoothingEnabled)
             gpat->SetFilter(gfxPattern::FILTER_GOOD);
         else
             gpat->SetFilter(gfxPattern::FILTER_NEAREST);
 
@@ -1837,17 +1842,18 @@ nsCanvasRenderingContext2D::CreatePatter
     if (!res.mSurface)
         return NS_ERROR_NOT_AVAILABLE;
 
     nsRefPtr<gfxPattern> thebespat = new gfxPattern(res.mSurface);
 
     thebespat->SetExtend(extend);
 
     nsRefPtr<nsCanvasPattern> pat = new nsCanvasPattern(thebespat, res.mPrincipal,
-                                                        res.mIsWriteOnly);
+                                                        res.mIsWriteOnly,
+                                                        res.mCORSUsed);
     if (!pat)
         return NS_ERROR_OUT_OF_MEMORY;
 
     *_retval = pat.forget().get();
     return NS_OK;
 }
 
 //
@@ -3433,17 +3439,19 @@ nsCanvasRenderingContext2D::DrawImage(ns
                 return NS_ERROR_NOT_AVAILABLE;
         }
 
         imgsurf = res.mSurface.forget();
         imgSize = res.mSize;
 
         if (mCanvasElement) {
             CanvasUtils::DoDrawImageSecurityCheck(HTMLCanvasElement(),
-                                                  res.mPrincipal, res.mIsWriteOnly);
+                                                  res.mPrincipal,
+                                                  res.mIsWriteOnly,
+                                                  res.mCORSUsed);
         }
 
         if (res.mImageRequest) {
             CanvasImageCache::NotifyDrawImage(imgElt, HTMLCanvasElement(),
                                               res.mImageRequest, imgsurf, imgSize);
         }
     }
 
--- a/content/canvas/src/nsCanvasRenderingContext2DAzure.cpp
+++ b/content/canvas/src/nsCanvasRenderingContext2DAzure.cpp
@@ -301,30 +301,33 @@ public:
     REPEATX,
     REPEATY,
     NOREPEAT
   };
 
   nsCanvasPatternAzure(SourceSurface* aSurface,
                        RepeatMode aRepeat,
                        nsIPrincipal* principalForSecurityCheck,
-                       PRBool forceWriteOnly)
+                       PRBool forceWriteOnly,
+                       PRBool CORSUsed)
     : mSurface(aSurface)
     , mRepeat(aRepeat)
     , mPrincipal(principalForSecurityCheck)
     , mForceWriteOnly(forceWriteOnly)
+    , mCORSUsed(CORSUsed)
   {
   }
 
   NS_DECL_ISUPPORTS
 
   RefPtr<SourceSurface> mSurface;
-  RepeatMode mRepeat;
+  const RepeatMode mRepeat;
   nsCOMPtr<nsIPrincipal> mPrincipal;
-  PRPackedBool mForceWriteOnly;
+  const PRPackedBool mForceWriteOnly;
+  const PRPackedBool mCORSUsed;
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsCanvasPatternAzure, NS_CANVASPATTERNAZURE_PRIVATE_IID)
 
 NS_IMPL_ADDREF(nsCanvasPatternAzure)
 NS_IMPL_RELEASE(nsCanvasPatternAzure)
 
 // XXX
@@ -793,17 +796,18 @@ protected:
 
         mPattern = new (mRadialGradientPattern.addr())
           RadialGradientPattern(gradient->mCenter1, gradient->mCenter2, gradient->mRadius1,
                                 gradient->mRadius2, gradient->GetGradientStopsForTarget(aRT));
       } else if (state.patternStyles[aStyle]) {
         if (aCtx->mCanvasElement) {
           CanvasUtils::DoDrawImageSecurityCheck(aCtx->HTMLCanvasElement(),
                                                 state.patternStyles[aStyle]->mPrincipal,
-                                                state.patternStyles[aStyle]->mForceWriteOnly);
+                                                state.patternStyles[aStyle]->mForceWriteOnly,
+                                                state.patternStyles[aStyle]->mCORSUsed);
         }
 
         ExtendMode mode;
         if (state.patternStyles[aStyle]->mRepeat == nsCanvasPatternAzure::NOREPEAT) {
           mode = EXTEND_CLAMP;
         } else {
           mode = EXTEND_WRAP;
         }
@@ -1907,27 +1911,26 @@ nsCanvasRenderingContext2DAzure::CreateP
   if (canvas) {
     nsIntSize size = canvas->GetSize();
     if (size.width == 0 || size.height == 0) {
       return NS_ERROR_DOM_INVALID_STATE_ERR;
     }
   }
 
   // Special case for Canvas, which could be an Azure canvas!
-  nsCOMPtr<nsINode> node = do_QueryInterface(image);
-  if (canvas && node) {
+  if (canvas) {
     if (canvas->CountContexts() == 1) {
       nsICanvasRenderingContextInternal *srcCanvas = canvas->GetContextAtIndex(0);
 
       // This might not be an Azure canvas!
       if (srcCanvas) {
         RefPtr<SourceSurface> srcSurf = srcCanvas->GetSurfaceSnapshot();
 
         nsRefPtr<nsCanvasPatternAzure> pat =
-          new nsCanvasPatternAzure(srcSurf, repeatMode, node->NodePrincipal(), canvas->IsWriteOnly());
+          new nsCanvasPatternAzure(srcSurf, repeatMode, content->NodePrincipal(), canvas->IsWriteOnly(), PR_FALSE);
 
         *_retval = pat.forget().get();
         return NS_OK;
       }
     }
   }
 
   // The canvas spec says that createPattern should use the first frame
@@ -1944,17 +1947,18 @@ nsCanvasRenderingContext2DAzure::CreateP
   if (!res.mSurface->CairoSurface()) {
     return NS_OK;
   }
 
   RefPtr<SourceSurface> srcSurf =
     gfxPlatform::GetPlatform()->GetSourceSurfaceForSurface(mTarget, res.mSurface);
 
   nsRefPtr<nsCanvasPatternAzure> pat =
-    new nsCanvasPatternAzure(srcSurf, repeatMode, res.mPrincipal, res.mIsWriteOnly);
+    new nsCanvasPatternAzure(srcSurf, repeatMode, res.mPrincipal,
+                             res.mIsWriteOnly, res.mCORSUsed);
 
   *_retval = pat.forget().get();
   return NS_OK;
 }
 
 //
 // shadows
 //
@@ -3695,17 +3699,18 @@ nsCanvasRenderingContext2DAzure::DrawIma
       return NS_OK;
     }
 
     imgsurf = res.mSurface.forget();
     imgSize = res.mSize;
 
     if (mCanvasElement) {
       CanvasUtils::DoDrawImageSecurityCheck(HTMLCanvasElement(),
-                                            res.mPrincipal, res.mIsWriteOnly);
+                                            res.mPrincipal, res.mIsWriteOnly,
+                                            res.mCORSUsed);
     }
 
     if (res.mImageRequest) {
       CanvasImageCache::NotifyDrawImage(imgElt, HTMLCanvasElement(),
                                         res.mImageRequest, imgsurf, imgSize);
     }
 
     srcSurf = gfxPlatform::GetPlatform()->GetSourceSurfaceForSurface(mTarget, imgsurf);
--- a/content/canvas/test/Makefile.in
+++ b/content/canvas/test/Makefile.in
@@ -36,17 +36,17 @@
 #
 # ***** END LICENSE BLOCK *****
 
 DEPTH		= ../../..
 topsrcdir	= @top_srcdir@
 srcdir		= @srcdir@
 VPATH		= @srcdir@
 relativesrcdir  = content/canvas/test
-DIRS		+= webgl
+DIRS		+= webgl crossorigin
 
 include $(DEPTH)/config/autoconf.mk
 include $(topsrcdir)/config/rules.mk
 _TEST_FILES_0 = \
 	test_canvas.html \
 	image_transparent50.png \
 	image_redtransparent.png \
 	image_yellow.png \
new file mode 100644
--- /dev/null
+++ b/content/canvas/test/crossorigin/Makefile.in
@@ -0,0 +1,57 @@
+#
+# ***** 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 mozilla.org code.
+#
+# The Initial Developer of the Original Code is
+# Mozilla Corporation.
+# Portions created by the Initial Developer are Copyright (C) 2010
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either of 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 *****
+
+DEPTH		= ../../../..
+topsrcdir	= @top_srcdir@
+srcdir		= @srcdir@
+VPATH		= @srcdir@
+relativesrcdir  = content/canvas/test/crossorigin
+
+include $(DEPTH)/config/autoconf.mk
+include $(topsrcdir)/config/rules.mk
+_TEST_FILES = \
+	image-allow-credentials.png \
+	image-allow-credentials.png^headers^ \
+	image-allow-star.png \
+	image-allow-star.png^headers^ \
+	image.png \
+	test_canvas2d_crossorigin.html \
+	test_webgl_crossorigin_textures.html \
+	$(NULL)
+
+libs:: $(_TEST_FILES)
+	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/tests/$(relativesrcdir)
rename from content/canvas/test/webgl/crossorigin/image-allow-credentials.png
rename to content/canvas/test/crossorigin/image-allow-credentials.png
rename from content/canvas/test/webgl/crossorigin/image-allow-credentials.png^headers^
rename to content/canvas/test/crossorigin/image-allow-credentials.png^headers^
rename from content/canvas/test/webgl/crossorigin/image-allow-star.png
rename to content/canvas/test/crossorigin/image-allow-star.png
rename from content/canvas/test/webgl/crossorigin/image-allow-star.png^headers^
rename to content/canvas/test/crossorigin/image-allow-star.png^headers^
rename from content/canvas/test/webgl/crossorigin/image.png
rename to content/canvas/test/crossorigin/image.png
new file mode 100644
--- /dev/null
+++ b/content/canvas/test/crossorigin/test_canvas2d_crossorigin.html
@@ -0,0 +1,197 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=685518
+-->
+<head>
+  <title>Test for Bug 685518</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=685518">Mozilla Bug 685518</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+  
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 685518 **/
+
+SimpleTest.waitForExplicitFinish();
+
+const SECURITY_ERR = 0x805303e8;
+const BAD_URI_ERR = 0x805303f4;
+const OK = 0;
+
+function nameForErrorCode(code) {
+  switch(code) {
+    case OK: return "no error";
+    case SECURITY_ERR: return "security error";
+    case BAD_URI_ERR: return "bad URI error"
+  }
+  return "unexpected error (" + code + ")";
+}
+
+function verifyError(actual_error, expected_error, message) {
+  ok(actual_error == expected_error,
+     message + ": expected " + nameForErrorCode(expected_error)
+             + ", got " + nameForErrorCode(actual_error));
+}
+
+var number_of_tests_live = 0;
+
+function testDone() {
+  number_of_tests_live--;
+        
+  if (number_of_tests_live == 0)
+    SimpleTest.finish();
+}
+
+function testImage(url, crossOriginAttribute, expected_result) {
+  ++number_of_tests_live;
+  var image;
+  if (crossOriginAttribute == "just-crossOrigin-without-value") {
+    var div = document.createElement('div');
+    div.innerHTML="<img crossOrigin>";
+    image = div.children[0];
+  }
+  else {
+    image = new Image();
+    if (crossOriginAttribute != "missing-value-default") {
+      image.crossOrigin = crossOriginAttribute;
+    }
+  }
+
+  image.onload = function() {
+    var c = document.createElement("canvas");
+    c.width = this.width;
+    c.height = this.height;
+    var ctx = c.getContext("2d");
+    ctx.drawImage(this, 0, 0);
+
+    var data;
+    var actual_result;
+    try {
+      data = ctx.getImageData(0, 0, 1, 1);
+      actual_result = OK;
+    } catch (e) {
+      actual_result = e.result;
+    }
+
+    verifyError(actual_result, expected_result,
+                "drawImage then get image data on " + url +
+                " with crossOrigin=" + this.crossOrigin);
+
+    // Now test patterns
+    c = document.createElement("canvas");
+    c.width = this.width;
+    c.height = this.height;
+    ctx = c.getContext("2d");
+    ctx.fillStyle = ctx.createPattern(this, "");
+    ctx.fillRect(0, 0, c.width, c.height);
+    try {
+      data = ctx.getImageData(0, 0, 1, 1);
+      actual_result = OK;
+    } catch (e) {
+      actual_result = e.result;
+    }
+
+    verifyError(actual_result, expected_result,
+                "createPattern+fill then get image data on " + url +
+                " with crossOrigin=" + this.crossOrigin);
+
+    testDone();
+  };
+
+  image.onerror = function(event) {
+    verifyError(BAD_URI_ERR, expected_result,
+                "image error handler for " + url +
+                " with crossOrigin=" + this.crossOrigin);
+
+    testDone();
+  }
+
+  image.src = url;
+}
+
+// Now kick off the tests.
+const testPath = "/tests/content/canvas/test/crossorigin/"
+
+// First column is image file, second column is what CORS headers the server sends
+const imageFiles = [
+ [ "image.png", "none" ],
+ [ "image-allow-star.png", "allow-all-anon" ],
+ [ "image-allow-credentials.png", "allow-single-server-creds" ]
+];
+
+const hostnames = [
+  [ "mochi.test:8888", "same-origin" ],
+  [ "example.com", "cross-origin" ]
+];
+
+// First column is the value; second column is the expected resulting CORS mode
+const attrValues = [
+  [ "missing-value-default", "none" ],
+  [ "", "anonymous" ],
+  [ "just-crossOrigin-without-value", "anonymous" ],
+  [ "anonymous", "anonymous" ],
+  [ "use-credentials", "use-credentials" ],
+  [ "foobar", "anonymous" ]
+];
+
+for (var imgIdx = 0; imgIdx < imageFiles.length; ++imgIdx) {
+  for (var hostnameIdx = 0; hostnameIdx < hostnames.length; ++hostnameIdx) {
+    var hostnameData = hostnames[hostnameIdx];
+    var url = "http://" + hostnameData[0] + testPath + imageFiles[imgIdx][0];
+    for (var attrValIdx = 0; attrValIdx < attrValues.length; ++attrValIdx) {
+      var attrValData = attrValues[attrValIdx];
+      // Now compute the expected result
+      var expected_result;
+      if (hostnameData[1] == "same-origin") {
+        // Same-origin; these should all Just Work
+        expected_result = OK;
+      } else {
+        // Cross-origin
+        is(hostnameData[1], "cross-origin",
+           "what sort of host is " + hostnameData[0]);
+        var CORSMode = attrValData[1];
+        if (CORSMode == "none") {
+          // Doesn't matter what headers the server sends; we're not
+          // using CORS on our end.
+          expected_result = SECURITY_ERR;
+        } else {
+          // Check whether the server will let us talk to them
+          var CORSHeaders = imageFiles[imgIdx][1];
+          // We're going to look for CORS headers from the server
+          if (CORSHeaders == "none") {
+            // No CORS headers from server; load will fail.
+            expected_result = BAD_URI_ERR;
+          } else if (CORSHeaders == "allow-all-anon") {
+            // Server only allows anonymous requests
+            if (CORSMode == "anonymous") {
+              expected_result = OK;
+            } else {
+              is(CORSMode, "use-credentials",
+                 "What other CORS modes are there?");
+              // A load with credentials against a server that only
+              // allows anonymous loads will fail.
+              expected_result = BAD_URI_ERR;
+            }
+          } else {
+            is(CORSHeaders, "allow-single-server-creds",
+               "What other CORS headers could there be?");
+            // Our server should allow both anonymous and non-anonymous requests
+            expected_result = OK;
+          }
+        }
+      }
+      testImage(url, attrValData[0], expected_result);
+    }
+  }
+}
+</script>
+</pre>
+</body>
+</html>
rename from content/canvas/test/webgl/crossorigin/test_webgl_crossorigin_textures.html
rename to content/canvas/test/crossorigin/test_webgl_crossorigin_textures.html
--- a/content/canvas/test/webgl/crossorigin/test_webgl_crossorigin_textures.html
+++ b/content/canvas/test/crossorigin/test_webgl_crossorigin_textures.html
@@ -79,76 +79,76 @@
     try {
       gl = canvas.getContext("experimental-webgl");
     } catch (e) {
       SimpleTest.finish();
       return;
     }
 
 
-    testTexture("http://mochi.test:8888/tests/content/canvas/test/webgl/crossorigin/image.png",
+    testTexture("http://mochi.test:8888/tests/content/canvas/test/crossorigin/image.png",
                 "missing-value-default",
                 OK);
-    testTexture("http://mochi.test:8888/tests/content/canvas/test/webgl/crossorigin/image.png",
+    testTexture("http://mochi.test:8888/tests/content/canvas/test/crossorigin/image.png",
                 "",
                 OK);
-    testTexture("http://mochi.test:8888/tests/content/canvas/test/webgl/crossorigin/image.png",
+    testTexture("http://mochi.test:8888/tests/content/canvas/test/crossorigin/image.png",
                 "just-crossOrigin-without-value",
                 OK);
-    testTexture("http://example.com/tests/content/canvas/test/webgl/crossorigin/image.png",
+    testTexture("http://example.com/tests/content/canvas/test/crossorigin/image.png",
                 "missing-value-default",
                 SECURITY_ERR);
-    testTexture("http://example.com/tests/content/canvas/test/webgl/crossorigin/image.png",
+    testTexture("http://example.com/tests/content/canvas/test/crossorigin/image.png",
                 "",
                 SECURITY_ERR);
-    testTexture("http://example.com/tests/content/canvas/test/webgl/crossorigin/image.png",
+    testTexture("http://example.com/tests/content/canvas/test/crossorigin/image.png",
                 "just-crossOrigin-without-value",
                 SECURITY_ERR);
 
-    testTexture("http://example.com/tests/content/canvas/test/webgl/crossorigin/image-allow-star.png",
+    testTexture("http://example.com/tests/content/canvas/test/crossorigin/image-allow-star.png",
                 "missing-value-default",
                 SECURITY_ERR);
-    testTexture("http://example.com/tests/content/canvas/test/webgl/crossorigin/image-allow-star.png",
+    testTexture("http://example.com/tests/content/canvas/test/crossorigin/image-allow-star.png",
                 "",
                 OK);
-    testTexture("http://example.com/tests/content/canvas/test/webgl/crossorigin/image-allow-star.png",
+    testTexture("http://example.com/tests/content/canvas/test/crossorigin/image-allow-star.png",
                 "just-crossOrigin-without-value",
                 OK);
-    testTexture("http://example.com/tests/content/canvas/test/webgl/crossorigin/image-allow-star.png",
+    testTexture("http://example.com/tests/content/canvas/test/crossorigin/image-allow-star.png",
                 "anonymous",
                 OK);
-    testTexture("http://example.com/tests/content/canvas/test/webgl/crossorigin/image-allow-star.png",
+    testTexture("http://example.com/tests/content/canvas/test/crossorigin/image-allow-star.png",
                 "use-credentials",
                 SECURITY_ERR);
 
-    testTexture("http://example.com/tests/content/canvas/test/webgl/crossorigin/image-allow-credentials.png",
+    testTexture("http://example.com/tests/content/canvas/test/crossorigin/image-allow-credentials.png",
                 "missing-value-default",
                 SECURITY_ERR);
-    testTexture("http://example.com/tests/content/canvas/test/webgl/crossorigin/image-allow-credentials.png",
+    testTexture("http://example.com/tests/content/canvas/test/crossorigin/image-allow-credentials.png",
                 "",
                 OK);
-    testTexture("http://example.com/tests/content/canvas/test/webgl/crossorigin/image-allow-credentials.png",
+    testTexture("http://example.com/tests/content/canvas/test/crossorigin/image-allow-credentials.png",
                 "just-crossOrigin-without-value",
                 OK);
-    testTexture("http://example.com/tests/content/canvas/test/webgl/crossorigin/image-allow-credentials.png",
+    testTexture("http://example.com/tests/content/canvas/test/crossorigin/image-allow-credentials.png",
                 "anonymous",
                 OK);
-    testTexture("http://example.com/tests/content/canvas/test/webgl/crossorigin/image-allow-credentials.png",
+    testTexture("http://example.com/tests/content/canvas/test/crossorigin/image-allow-credentials.png",
                 "use-credentials",
                 OK);
 
     // Test that bad values for crossorigin="..." are interpreted as invalid-value-default which is "anonymous".
-    testTexture("http://mochi.test:8888/tests/content/canvas/test/webgl/crossorigin/image.png",
+    testTexture("http://mochi.test:8888/tests/content/canvas/test/crossorigin/image.png",
                 "foobar",
                 OK);
-    testTexture("http://example.com/tests/content/canvas/test/webgl/crossorigin/image.png",
+    testTexture("http://example.com/tests/content/canvas/test/crossorigin/image.png",
                 "foobar",
                 SECURITY_ERR);
-    testTexture("http://example.com/tests/content/canvas/test/webgl/crossorigin/image-allow-star.png",
+    testTexture("http://example.com/tests/content/canvas/test/crossorigin/image-allow-star.png",
                 "foobar",
                 OK);
-    testTexture("http://example.com/tests/content/canvas/test/webgl/crossorigin/image-allow-credentials.png",
+    testTexture("http://example.com/tests/content/canvas/test/crossorigin/image-allow-credentials.png",
                 "foobar",
                 OK);
 
     all_tests_started = true;
   });
 </script>
--- a/content/canvas/test/test_mozGetAsFile.html
+++ b/content/canvas/test/test_mozGetAsFile.html
@@ -2,26 +2,30 @@
 <title>Canvas test: mozGetAsFile</title>
 <script src="/MochiKit/MochiKit.js"></script>
 <script src="/tests/SimpleTest/SimpleTest.js"></script>
 <link rel="stylesheet" href="/tests/SimpleTest/test.css">
 <body>
 <canvas id="c" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
 <script>
 
+var gCompares = 0;
+
 function compareAsync(file, canvas, type)
 {
-  SimpleTest.waitForExplicitFinish();
+  ++gCompares;
 
   var reader = new FileReader();
   reader.onload = 
     function(e) {
       is(e.target.result, canvas.toDataURL(type),
  "<canvas>.mozGetAsFile().getAsDataURL() should equal <canvas>.toDataURL()");
-      SimpleTest.finish();
+      if (--gCompares == 0) {
+        SimpleTest.finish();
+      }
     };
   reader.readAsDataURL(file);
 }
 
 SimpleTest.waitForExplicitFinish();
 addLoadEvent(function () {
 
 var canvas = document.getElementById('c');
@@ -35,14 +39,12 @@ compareAsync(pngfile, canvas, "image/png
 is(pngfile.name, "foo.png", "File name should be what we passed in");
 
 var jpegfile = canvas.mozGetAsFile("bar.jpg", "image/jpeg");
 is(jpegfile.type, "image/jpeg",
    "When a valid type is specified that should be returned");
 compareAsync(jpegfile, canvas, "image/jpeg");
 is(jpegfile.name, "bar.jpg", "File name should be what we passed in");
 
-SimpleTest.finish();
-
 });
 </script>
 <img src="image_yellow75.png" id="yellow75.png" class="resource">
 
--- a/content/canvas/test/webgl/Makefile.in
+++ b/content/canvas/test/webgl/Makefile.in
@@ -51,10 +51,9 @@ include $(topsrcdir)/config/rules.mk
   failing_tests_mac.txt \
   $(NULL)
 
 libs:: $(_TEST_FILES)
 	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/tests/$(relativesrcdir)
 	$(TAR) -cf - -C $(srcdir) \
 	  resources \
 	  conformance \
-          crossorigin \
 	  | $(TAR) -xf - -C $(DEPTH)/_tests/testing/mochitest/tests/$(relativesrcdir)
--- a/content/canvas/test/webgl/failing_tests_linux.txt
+++ b/content/canvas/test/webgl/failing_tests_linux.txt
@@ -3,21 +3,19 @@ conformance/drawingbuffer-test.html
 conformance/framebuffer-object-attachment.html
 conformance/shaders/glsl-features/../../glsl-features.html?feature=abs-frag&reffs=shaders/glsl-features/abs-ref.frag&testfs=shaders/glsl-features/abs.frag
 conformance/shaders/glsl-features/../../glsl-features.html?feature=abs-vert-vec2&refvs=shaders/glsl-features/abs-vec2-ref.vert&testvs=shaders/glsl-features/abs-vec2.vert
 conformance/shaders/glsl-features/../../glsl-features.html?feature=abs-vert-vec3&refvs=shaders/glsl-features/abs-vec3-ref.vert&testvs=shaders/glsl-features/abs-vec3.vert
 conformance/shaders/glsl-features/../../glsl-features.html?feature=abs-vert-vec4&refvs=shaders/glsl-features/abs-vec4-ref.vert&testvs=shaders/glsl-features/abs-vec4.vert
 conformance/shaders/glsl-features/../../glsl-features.html?feature=sign-frag-vec4&reffs=shaders/glsl-features/sign-vec4-ref.frag&testfs=shaders/glsl-features/sign-vec4.frag
 conformance/shaders/glsl-features/../../glsl-features.html?feature=sign-vert-vec4&refvs=shaders/glsl-features/sign-vec4-ref.vert&testvs=shaders/glsl-features/sign-vec4.vert
 conformance/gl-get-active-attribute.html
-conformance/gl-getshadersource.html
 conformance/gl-uniform-bool.html
 conformance/glsl-conformance.html
 conformance/glsl-long-variable-names.html
-conformance/invalid-passed-params.html
 conformance/premultiplyalpha-test.html
 conformance/read-pixels-test.html
 conformance/uninitialized-test.html
 conformance/more/conformance/quickCheckAPI.html
 conformance/more/functions/copyTexImage2D.html
 conformance/more/functions/copyTexSubImage2D.html
 conformance/more/functions/deleteBufferBadArgs.html
 conformance/more/functions/uniformfArrayLen1.html
--- a/content/canvas/test/webgl/failing_tests_mac.txt
+++ b/content/canvas/test/webgl/failing_tests_mac.txt
@@ -1,17 +1,15 @@
 conformance/context-attributes-alpha-depth-stencil-antialias.html
 conformance/drawingbuffer-static-canvas-test.html
 conformance/drawingbuffer-test.html
 conformance/framebuffer-object-attachment.html
-conformance/gl-getshadersource.html
 conformance/gl-object-get-calls.html
 conformance/glsl-conformance.html
 conformance/glsl-long-variable-names.html
-conformance/invalid-passed-params.html
 conformance/premultiplyalpha-test.html
 conformance/program-test.html
 conformance/read-pixels-test.html
 conformance/tex-input-validation.html
 conformance/texture-npot.html
 conformance/more/conformance/quickCheckAPI.html
 conformance/more/functions/copyTexImage2D.html
 conformance/more/functions/copyTexSubImage2D.html
--- a/content/canvas/test/webgl/failing_tests_windows.txt
+++ b/content/canvas/test/webgl/failing_tests_windows.txt
@@ -1,14 +1,12 @@
 conformance/drawingbuffer-static-canvas-test.html
 conformance/drawingbuffer-test.html
 conformance/framebuffer-object-attachment.html
-conformance/gl-getshadersource.html
 conformance/glsl-conformance.html
 conformance/glsl-long-variable-names.html
-conformance/invalid-passed-params.html
 conformance/premultiplyalpha-test.html
 conformance/read-pixels-test.html
 conformance/more/conformance/quickCheckAPI.html
 conformance/more/functions/copyTexImage2D.html
 conformance/more/functions/copyTexSubImage2D.html
 conformance/more/functions/deleteBufferBadArgs.html
 conformance/more/functions/uniformfArrayLen1.html
--- a/content/events/src/nsEventStateManager.cpp
+++ b/content/events/src/nsEventStateManager.cpp
@@ -99,18 +99,16 @@
 #include "nsIDOMMouseScrollEvent.h"
 #include "nsIDOMDragEvent.h"
 #include "nsIDOMEventTarget.h"
 #include "nsIDOMUIEvent.h"
 #include "nsDOMDragEvent.h"
 #include "nsIDOMNSEditableElement.h"
 
 #include "nsCaret.h"
-#include "nsILookAndFeel.h"
-#include "nsWidgetsCID.h"
 
 #include "nsSubDocumentFrame.h"
 #include "nsIFrameTraversal.h"
 #include "nsLayoutCID.h"
 #include "nsLayoutUtils.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsUnicharUtils.h"
 #include "nsContentUtils.h"
@@ -133,32 +131,31 @@
 #endif
 #include "nsIController.h"
 #include "nsICommandParams.h"
 #include "mozilla/Services.h"
 #include "mozAutoDocUpdate.h"
 #include "nsHTMLLabelElement.h"
 
 #include "mozilla/Preferences.h"
+#include "mozilla/LookAndFeel.h"
 
 #ifdef XP_MACOSX
 #import <ApplicationServices/ApplicationServices.h>
 #endif
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 //#define DEBUG_DOCSHELL_FOCUS
 
 #define NS_USER_INTERACTION_INTERVAL 5000 // ms
 
 static NS_DEFINE_CID(kFrameTraversalCID, NS_FRAMETRAVERSAL_CID);
 
-static NS_DEFINE_CID(kLookAndFeelCID, NS_LOOKANDFEEL_CID);
-
 static PRBool sLeftClickOnly = PR_TRUE;
 static PRBool sKeyCausesActivation = PR_TRUE;
 static PRUint32 sESMInstanceCount = 0;
 static PRInt32 sChromeAccessModifier = 0, sContentAccessModifier = 0;
 PRInt32 nsEventStateManager::sUserInputEventDepth = 0;
 PRBool nsEventStateManager::sNormalLMouseEventInProcess = PR_FALSE;
 nsEventStateManager* nsEventStateManager::sActiveESM = nsnull;
 nsIDocument* nsEventStateManager::sMouseOverDocument = nsnull;
@@ -2045,19 +2042,20 @@ nsEventStateManager::GenerateDragGesture
       StopTrackingDragGesture();
       return;
     }
 
     static PRInt32 pixelThresholdX = 0;
     static PRInt32 pixelThresholdY = 0;
 
     if (!pixelThresholdX) {
-      nsILookAndFeel *lf = aPresContext->LookAndFeel();
-      lf->GetMetric(nsILookAndFeel::eMetric_DragThresholdX, pixelThresholdX);
-      lf->GetMetric(nsILookAndFeel::eMetric_DragThresholdY, pixelThresholdY);
+      pixelThresholdX =
+        LookAndFeel::GetInt(LookAndFeel::eIntID_DragThresholdX, 0);
+      pixelThresholdY =
+        LookAndFeel::GetInt(LookAndFeel::eIntID_DragThresholdY, 0);
       if (!pixelThresholdX)
         pixelThresholdX = 5;
       if (!pixelThresholdY)
         pixelThresholdY = 5;
     }
 
     // fire drag gesture if mouse has moved enough
     nsIntPoint pt = aEvent->refPoint + aEvent->widget->WidgetToScreenOffset();
new file mode 100644
--- /dev/null
+++ b/content/html/content/crashtests/682058.xhtml
@@ -0,0 +1,11 @@
+<?xml version="1.0"?>
+<html xmlns="http://www.w3.org/1999/xhtml">
+  <body onload="test()">
+    <script>
+      function test() {
+        document.body.innerHTML = "Foobar";
+      }
+      document.addEventListener("DOMNodeRemoved", function() {});
+    </script>
+  </body>
+</html>
--- a/content/html/content/crashtests/crashtests.list
+++ b/content/html/content/crashtests/crashtests.list
@@ -24,9 +24,10 @@ load 604807.html
 load 605264.html
 load 606430-1.html
 load 602117.html
 load 613027.html
 load 614279.html
 load 614988-1.html
 load 620078-1.html
 load 620078-2.html
+load 682058.xhtml
 load 682460.html
--- a/content/html/content/src/nsGenericHTMLElement.cpp
+++ b/content/html/content/src/nsGenericHTMLElement.cpp
@@ -780,16 +780,21 @@ nsGenericHTMLElement::SetInnerHTML(const
     // HTML5 parser has notified, but not fired mutation events.
     FireMutationEventsForDirectParsing(doc, this, oldChildCount);
   } else {
     rv = nsContentUtils::CreateContextualFragment(this, aInnerHTML,
                                                   PR_TRUE,
                                                   getter_AddRefs(df));
     nsCOMPtr<nsINode> fragment = do_QueryInterface(df);
     if (NS_SUCCEEDED(rv)) {
+      // Suppress assertion about node removal mutation events that can't have
+      // listeners anyway, because no one has had the chance to register mutation
+      // listeners on the fragment that comes from the parser.
+      nsAutoScriptBlockerSuppressNodeRemoved scriptBlocker;
+
       static_cast<nsINode*>(this)->AppendChild(fragment, &rv);
     }
   }
 
   return rv;
 }
 
 enum nsAdjacentPosition {
--- a/content/html/content/src/nsHTMLFrameSetElement.cpp
+++ b/content/html/content/src/nsHTMLFrameSetElement.cpp
@@ -317,17 +317,17 @@ nsHTMLFrameSetElement::ParseRowCol(const
       // Treat 0* as 1* in quirks mode (bug 40383)
       if (isInQuirks) {
         if ((eFramesetUnit_Relative == specs[i].mUnit) &&
           (0 == specs[i].mValue)) {
           specs[i].mValue = 1;
         }
       }
         
-      // Catch zero and negative frame sizes for Nav compatability
+      // Catch zero and negative frame sizes for Nav compatibility
       // Nav resized absolute and relative frames to "1" and
       // percent frames to an even percentage of the width
       //
       //if (isInQuirks && (specs[i].mValue <= 0)) {
       //  if (eFramesetUnit_Percent == specs[i].mUnit) {
       //    specs[i].mValue = 100 / count;
       //  } else {
       //    specs[i].mValue = 1;
--- a/content/html/content/src/nsHTMLInputElement.cpp
+++ b/content/html/content/src/nsHTMLInputElement.cpp
@@ -80,18 +80,16 @@
 #include "nsIDOMNSEvent.h"
 #include "nsIDOMNodeList.h"
 #include "nsIDOMHTMLCollection.h"
 #include "nsLinebreakConverter.h" //to strip out carriage returns
 #include "nsReadableUtils.h"
 #include "nsUnicharUtils.h"
 #include "nsEventDispatcher.h"
 #include "nsLayoutUtils.h"
-#include "nsWidgetsCID.h"
-#include "nsILookAndFeel.h"
 
 #include "nsIDOMMutationEvent.h"
 #include "nsIDOMEventTarget.h"
 #include "nsMutationEvent.h"
 #include "nsEventListenerManager.h"
 
 #include "nsRuleData.h"
 
@@ -113,22 +111,24 @@
 #include "nsImageLoadingContent.h"
 
 #include "mozAutoDocUpdate.h"
 #include "nsContentCreatorFunctions.h"
 #include "nsCharSeparatedTokenizer.h"
 #include "nsContentUtils.h"
 #include "nsRadioVisitor.h"
 
+#include "mozilla/LookAndFeel.h"
+
+using namespace mozilla;
 using namespace mozilla::dom;
 
 // XXX align=left, hspace, vspace, border? other nav4 attrs
 
 static NS_DEFINE_CID(kXULControllersCID,  NS_XULCONTROLLERS_CID);
-static NS_DEFINE_CID(kLookAndFeelCID, NS_LOOKANDFEEL_CID);
 
 // First bits are needed for the control type.
 #define NS_OUTER_ACTIVATE_EVENT   (1 << 9)
 #define NS_ORIGINAL_CHECKED_VALUE (1 << 10)
 #define NS_NO_CONTENT_DISPATCH    (1 << 11)
 #define NS_ORIGINAL_INDETERMINATE_VALUE (1 << 12)
 #define NS_CONTROL_TYPE(bits)  ((bits) & ~( \
   NS_OUTER_ACTIVATE_EVENT | NS_ORIGINAL_CHECKED_VALUE | NS_NO_CONTENT_DISPATCH | \
@@ -1918,26 +1918,25 @@ nsHTMLInputElement::PreHandleEvent(nsEve
 
   return nsGenericHTMLFormElement::PreHandleEvent(aVisitor);
 }
 
 static PRBool
 SelectTextFieldOnFocus()
 {
   if (!gSelectTextFieldOnFocus) {
-    nsCOMPtr<nsILookAndFeel> lookNFeel(do_GetService(kLookAndFeelCID));
-    if (lookNFeel) {
-      PRInt32 selectTextfieldsOnKeyFocus = -1;
-      lookNFeel->GetMetric(nsILookAndFeel::eMetric_SelectTextfieldsOnKeyFocus,
-                           selectTextfieldsOnKeyFocus);
+    PRInt32 selectTextfieldsOnKeyFocus = -1;
+    nsresult rv =
+      LookAndFeel::GetInt(LookAndFeel::eIntID_SelectTextfieldsOnKeyFocus,
+                          &selectTextfieldsOnKeyFocus);
+    if (NS_FAILED(rv)) {
+      gSelectTextFieldOnFocus = -1;
+    } else {
       gSelectTextFieldOnFocus = selectTextfieldsOnKeyFocus != 0 ? 1 : -1;
     }
-    else {
-      gSelectTextFieldOnFocus = -1;
-    }
   }
 
   return gSelectTextFieldOnFocus == 1;
 }
 
 nsresult
 nsHTMLInputElement::PostHandleEvent(nsEventChainPostVisitor& aVisitor)
 {
--- a/content/html/document/src/nsHTMLDocument.cpp
+++ b/content/html/document/src/nsHTMLDocument.cpp
@@ -270,29 +270,31 @@ NS_IMPL_CYCLE_COLLECTION_CLASS(nsHTMLDoc
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsHTMLDocument, nsDocument)
   NS_ASSERTION(!nsCCUncollectableMarker::InGeneration(cb, tmp->GetMarkedCCGeneration()),
                "Shouldn't traverse nsHTMLDocument!");
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mImages)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mApplets)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mEmbeds)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mLinks)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mAnchors)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mScripts)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR_AMBIGUOUS(mForms, nsIDOMNodeList)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR_AMBIGUOUS(mFormControls,
                                                        nsIDOMNodeList)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mWyciwygChannel)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mMidasCommandManager)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsHTMLDocument, nsDocument)
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mImages)
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mApplets)
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mEmbeds)
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mLinks)
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mAnchors)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mScripts)
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mForms)
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mFormControls)
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mWyciwygChannel)
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mMidasCommandManager)
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_IMPL_ADDREF_INHERITED(nsHTMLDocument, nsDocument)
 NS_IMPL_RELEASE_INHERITED(nsHTMLDocument, nsDocument)
@@ -343,16 +345,17 @@ nsHTMLDocument::ResetToURI(nsIURI *aURI,
 
   nsDocument::ResetToURI(aURI, aLoadGroup, aPrincipal);
 
   mImages = nsnull;
   mApplets = nsnull;
   mEmbeds = nsnull;
   mLinks = nsnull;
   mAnchors = nsnull;
+  mScripts = nsnull;
 
   mForms = nsnull;
 
   NS_ASSERTION(!mWyciwygChannel,
                "nsHTMLDocument::Reset() - Wyciwyg Channel  still exists!");
 
   mWyciwygChannel = nsnull;
 
@@ -1439,16 +1442,29 @@ nsHTMLDocument::GetAnchors(nsIDOMHTMLCol
 
   *aAnchors = mAnchors;
   NS_ADDREF(*aAnchors);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
+nsHTMLDocument::GetScripts(nsIDOMHTMLCollection** aScripts)
+{
+  if (!mScripts) {
+    mScripts = new nsContentList(this, kNameSpaceID_XHTML, nsGkAtoms::script, nsGkAtoms::script);
+  }
+
+  *aScripts = mScripts;
+  NS_ADDREF(*aScripts);
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 nsHTMLDocument::GetCookie(nsAString& aCookie)
 {
   aCookie.Truncate(); // clear current cookie in case service fails;
                       // no cookie isn't an error condition.
 
   if (mDisableCookieAccess) {
     return NS_OK;
   }
--- a/content/html/document/src/nsHTMLDocument.h
+++ b/content/html/document/src/nsHTMLDocument.h
@@ -242,16 +242,17 @@ protected:
     return kNameSpaceID_XHTML;
   }
 
   nsCOMPtr<nsIDOMHTMLCollection> mImages;
   nsCOMPtr<nsIDOMHTMLCollection> mApplets;
   nsCOMPtr<nsIDOMHTMLCollection> mEmbeds;
   nsCOMPtr<nsIDOMHTMLCollection> mLinks;
   nsCOMPtr<nsIDOMHTMLCollection> mAnchors;
+  nsCOMPtr<nsIDOMHTMLCollection> mScripts;
   nsRefPtr<nsContentList> mForms;
   nsRefPtr<nsContentList> mFormControls;
 
   /** # of forms in the document, synchronously set */
   PRInt32 mNumForms;
 
   static PRUint32 gWyciwygSessionCnt;
 
--- a/content/html/document/test/browser_bug592641.js
+++ b/content/html/document/test/browser_bug592641.js
@@ -12,17 +12,17 @@ function test() {
   ctx.tab1 = gBrowser.addTab(testPath + "bug592641_img.jpg");
   ctx.tab1Browser = gBrowser.getBrowserForTab(ctx.tab1);
   ctx.tab1Browser.addEventListener("load", load1Soon, true);
 }
 
 function checkTitle(title) {
 
   ctx.loadsDone++;
-  ok(/^bug592641_img\.jpg \(JPEG Image, 1500x1500 pixels\)/.test(title),
+  ok(/^bug592641_img\.jpg \(JPEG Image, 1500\u00A0\u00D7\u00A01500 pixels\)/.test(title),
      "Title should be correct on load #" + ctx.loadsDone);
 }
 
 function load1Soon() {
   ctx.tab1Browser.removeEventListener("load", load1Soon, true);
   // onload is fired in OnStopDecode, so let's use executeSoon() to make sure
   // that any other OnStopDecode event handlers get the chance to fire first.
   executeSoon(load1Done);
--- a/content/media/ogg/nsOggCodecState.cpp
+++ b/content/media/ogg/nsOggCodecState.cpp
@@ -392,17 +392,17 @@ nsTheoraState::PageIn(ogg_page* aPage)
       mPackets.Append(packet);
     }
     mUnstamped.Clear();
   }
   return NS_OK;
 }
 
 // Returns 1 if the Theora info struct is decoding a media of Theora
-// verion (maj,min,sub) or later, otherwise returns 0.
+// version (maj,min,sub) or later, otherwise returns 0.
 int
 TheoraVersion(th_info* info,
               unsigned char maj,
               unsigned char min,
               unsigned char sub)
 {
   ogg_uint32_t ver = (maj << 16) + (min << 8) + sub;
   ogg_uint32_t th_ver = (info->version_major << 16) +
--- a/content/media/ogg/nsOggCodecState.h
+++ b/content/media/ogg/nsOggCodecState.h
@@ -268,17 +268,17 @@ public:
   // Asserts that the number of samples predicted for aPacket is aSamples.
   // This function has no effect if VALIDATE_VORBIS_SAMPLE_CALCULATION
   // is not defined.
   void ValidateVorbisPacketSamples(ogg_packet* aPacket, long aSamples);
 
 };
 
 // Returns 1 if the Theora info struct is decoding a media of Theora
-// verion (maj,min,sub) or later, otherwise returns 0.
+// version (maj,min,sub) or later, otherwise returns 0.
 int TheoraVersion(th_info* info,
                   unsigned char maj,
                   unsigned char min,
                   unsigned char sub);
 
 class nsTheoraState : public nsOggCodecState {
 public:
   nsTheoraState(ogg_page* aBosPage);
--- a/docshell/base/nsDocShell.h
+++ b/docshell/base/nsDocShell.h
@@ -726,17 +726,21 @@ protected:
     nsCOMPtr<nsISHistory>      mSessionHistory;
     nsCOMPtr<nsIGlobalHistory2> mGlobalHistory;
     nsCOMPtr<nsIWebBrowserFind> mFind;
     nsCOMPtr<nsICommandManager> mCommandManager;
     // Reference to the SHEntry for this docshell until the page is destroyed.
     // Somebody give me better name
     nsCOMPtr<nsISHEntry>       mOSHE;
     // Reference to the SHEntry for this docshell until the page is loaded
-    // Somebody give me better name
+    // Somebody give me better name.
+    // If mLSHE is non-null, non-pushState subframe loads don't create separate
+    // root history entries. That is, frames loaded during the parent page
+    // load don't generate history entries the way frame navigation after the
+    // parent has loaded does. (This isn't the only purpose of mLSHE.)
     nsCOMPtr<nsISHEntry>       mLSHE;
 
     // Holds a weak pointer to a RestorePresentationEvent object if any that
     // holds a weak pointer back to us.  We use this pointer to possibly revoke
     // the event whenever necessary.
     nsRevocableEventPtr<RestorePresentationEvent> mRestorePresentationEvent;
 
     // Editor data, if this document is designMode or contentEditable.
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -514,23 +514,24 @@ static const char kDOMStringBundleURL[] 
 
 // NOTE: DEFAULT_SCRIPTABLE_FLAGS and DOM_DEFAULT_SCRIPTABLE_FLAGS
 //       are defined in nsIDOMClassInfo.h.
 
 #define WINDOW_SCRIPTABLE_FLAGS                                               \
  (nsIXPCScriptable::WANT_GETPROPERTY |                                        \
   nsIXPCScriptable::WANT_PRECREATE |                                          \
   nsIXPCScriptable::WANT_FINALIZE |                                           \
-  nsIXPCScriptable::WANT_EQUALITY |                                           \
   nsIXPCScriptable::WANT_ENUMERATE |                                          \
   nsIXPCScriptable::DONT_ENUM_QUERY_INTERFACE |                               \
+  nsIXPCScriptable::USE_STUB_EQUALITY_HOOK |                                  \
   nsIXPCScriptable::WANT_OUTER_OBJECT)
 
 #define NODE_SCRIPTABLE_FLAGS                                                 \
  ((DOM_DEFAULT_SCRIPTABLE_FLAGS |                                             \
+   nsIXPCScriptable::USE_STUB_EQUALITY_HOOK |                                 \
    nsIXPCScriptable::WANT_GETPROPERTY |                                       \
    nsIXPCScriptable::WANT_ADDPROPERTY |                                       \
    nsIXPCScriptable::WANT_SETPROPERTY) &                                      \
   ~nsIXPCScriptable::USE_JSSTUB_FOR_ADDPROPERTY)
 
 // We need to let JavaScript QI elements to interfaces that are not in
 // the classinfo since XBL can be used to dynamically implement new
 // unknown interfaces on elements, accessibility relies on this being
@@ -6380,29 +6381,40 @@ LocationSetterGuts(JSContext *cx, JSObje
 
   nsCOMPtr<Interface> xpcomObj = do_QueryWrappedNative(wrapper);
   NS_ENSURE_TRUE(xpcomObj, NS_ERROR_UNEXPECTED);
 
   nsCOMPtr<nsIDOMLocation> location;
   nsresult rv = xpcomObj->GetLocation(getter_AddRefs(location));
   NS_ENSURE_SUCCESS(rv, rv);
 
+  // Grab the value we're being set to before we stomp on |vp|
   JSString *val = ::JS_ValueToString(cx, *vp);
   NS_ENSURE_TRUE(val, NS_ERROR_UNEXPECTED);
 
+  // Make sure |val| stays alive below
+  JS::Anchor<JSString *> anchor(val);
+
+  // We have to wrap location into vp before null-checking location, to
+  // avoid assigning the wrong thing into the slot.
+  nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
+  rv = WrapNative(cx, JS_GetGlobalForScopeChain(cx), location,
+                  &NS_GET_IID(nsIDOMLocation), PR_TRUE, vp,
+                  getter_AddRefs(holder));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  if (!location) {
+    // Make this a no-op
+    return NS_OK;
+  }
+
   nsDependentJSString depStr;
   NS_ENSURE_TRUE(depStr.init(cx, val), NS_ERROR_UNEXPECTED);
   
-  rv = location->SetHref(depStr);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
-  return WrapNative(cx, JS_GetGlobalForScopeChain(cx), location,
-                    &NS_GET_IID(nsIDOMLocation), PR_TRUE, vp,
-                    getter_AddRefs(holder));
+  return location->SetHref(depStr);
 }
 
 template<class Interface>
 static JSBool
 LocationSetter(JSContext *cx, JSObject *obj, jsid id, JSBool strict,
                jsval *vp)
 {
   nsresult rv = LocationSetterGuts<Interface>(cx, obj, vp);
@@ -6903,47 +6915,16 @@ nsWindowSH::Finalize(nsIXPConnectWrapped
   NS_ENSURE_TRUE(sgo, NS_ERROR_UNEXPECTED);
 
   sgo->OnFinalize(obj);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsWindowSH::Equality(nsIXPConnectWrappedNative *wrapper, JSContext * cx,
-                     JSObject * obj, const jsval &val, PRBool *bp)
-{
-  *bp = PR_FALSE;
-
-  if (JSVAL_IS_PRIMITIVE(val)) {
-    return NS_OK;
-  }
-
-  nsCOMPtr<nsIXPConnectWrappedNative> other_wrapper;
-  nsContentUtils::XPConnect()->
-    GetWrappedNativeOfJSObject(cx, JSVAL_TO_OBJECT(val),
-                               getter_AddRefs(other_wrapper));
-  if (!other_wrapper) {
-    // Not equal.
-
-    return NS_OK;
-  }
-
-  nsGlobalWindow *win = nsGlobalWindow::FromWrapper(wrapper);
-
-  nsCOMPtr<nsPIDOMWindow> other = do_QueryWrappedNative(other_wrapper);
-
-  if (other) {
-    *bp = win->GetOuterWindow() == other->GetOuterWindow();
-  }
-
-  return NS_OK;
-}
-
-NS_IMETHODIMP
 nsWindowSH::OuterObject(nsIXPConnectWrappedNative *wrapper, JSContext * cx,
                         JSObject * obj, JSObject * *_retval)
 {
   nsGlobalWindow *origWin = nsGlobalWindow::FromWrapper(wrapper);
   nsGlobalWindow *win = origWin->GetOuterWindowInternal();
 
   if (!win) {
     // If we no longer have an outer window. No code should ever be
--- a/dom/base/nsDOMClassInfo.h
+++ b/dom/base/nsDOMClassInfo.h
@@ -409,18 +409,16 @@ public:
                          JSObject *obj, jsid id, jsval *vp, PRBool *_retval);
   NS_IMETHOD Enumerate(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
                        JSObject *obj, PRBool *_retval);
   NS_IMETHOD NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
                         JSObject *obj, jsid id, PRUint32 flags,
                         JSObject **objp, PRBool *_retval);
   NS_IMETHOD Finalize(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
                       JSObject *obj);
-  NS_IMETHOD Equality(nsIXPConnectWrappedNative *wrapper, JSContext * cx,
-                      JSObject * obj, const jsval &val, PRBool *bp);
   NS_IMETHOD OuterObject(nsIXPConnectWrappedNative *wrapper, JSContext * cx,
                          JSObject * obj, JSObject * *_retval);
 
   static JSBool GlobalScopePolluterNewResolve(JSContext *cx, JSObject *obj,
                                               jsid id, uintN flags,
                                               JSObject **objp);
   static JSBool GlobalScopePolluterGetProperty(JSContext *cx, JSObject *obj,
                                                jsid id, jsval *vp);
--- a/dom/base/nsFocusManager.cpp
+++ b/dom/base/nsFocusManager.cpp
@@ -67,29 +67,28 @@
 #include "nsIContentViewer.h"
 #include "nsFrameTraversal.h"
 #include "nsObjectFrame.h"
 #include "nsEventDispatcher.h"
 #include "nsEventStateManager.h"
 #include "nsIMEStateManager.h"
 #include "nsIWebNavigation.h"
 #include "nsCaret.h"
-#include "nsWidgetsCID.h"
-#include "nsILookAndFeel.h"
 #include "nsIWidget.h"
 #include "nsIBaseWindow.h"
 #include "nsIViewManager.h"
 #include "nsFrameSelection.h"
 #include "nsXULPopupManager.h"
 #include "nsIDOMNodeFilter.h"
 #include "nsIScriptObjectPrincipal.h"
 #include "nsIPrincipal.h"
 #include "mozilla/dom/Element.h"
 #include "mozAutoDocUpdate.h"
 #include "mozilla/Preferences.h"
+#include "mozilla/LookAndFeel.h"
 
 #ifdef MOZ_XUL
 #include "nsIDOMXULTextboxElement.h"
 #include "nsIDOMXULMenuListElement.h"
 #endif
 
 using namespace mozilla;
 using namespace mozilla::dom;
@@ -150,18 +149,16 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mActiveWindow)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mFocusedWindow)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mFocusedContent)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mFirstBlurEvent)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mFirstFocusEvent)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mWindowBeingLowered)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
-static NS_DEFINE_CID(kLookAndFeelCID, NS_LOOKANDFEEL_CID);
-
 nsFocusManager* nsFocusManager::sInstance = nsnull;
 PRBool nsFocusManager::sMouseFocusesFormControl = PR_FALSE;
 
 static const char* kObservedPrefs[] = {
   "accessibility.browsewithcaret",
   "accessibility.tabfocus_applies_to_xul",
   "accessibility.mouse_focuses_formcontrol",
   NULL
@@ -2288,19 +2285,18 @@ nsFocusManager::DetermineElementToMoveFo
   nsCOMPtr<nsIDocument> doc;
   if (startContent)
     doc = startContent->GetCurrentDoc();
   else
     doc = do_QueryInterface(aWindow->GetExtantDocument());
   if (!doc)
     return NS_OK;
 
-  nsCOMPtr<nsILookAndFeel> lookNFeel(do_GetService(kLookAndFeelCID));
-  lookNFeel->GetMetric(nsILookAndFeel::eMetric_TabFocusModel,
-                       nsIContent::sTabFocusModel);
+  LookAndFeel::GetInt(LookAndFeel::eIntID_TabFocusModel,
+                      &nsIContent::sTabFocusModel);
 
   if (aType == MOVEFOCUS_ROOT) {
     NS_IF_ADDREF(*aNextContent = GetRootForFocus(aWindow, doc, PR_FALSE, PR_FALSE));
     return NS_OK;
   }
   if (aType == MOVEFOCUS_FORWARDDOC) {
     NS_IF_ADDREF(*aNextContent = GetNextTabbableDocument(PR_TRUE));
     return NS_OK;
--- a/dom/interfaces/html/nsIDOMHTMLDocument.idl
+++ b/dom/interfaces/html/nsIDOMHTMLDocument.idl
@@ -42,17 +42,17 @@
 /**
  * The nsIDOMHTMLDocument interface is the interface to a [X]HTML
  * document object.
  *
  * @see <http://www.whatwg.org/html/>
  */
 interface nsISelection;
 
-[scriptable, uuid(3ab3e856-361d-435a-8a4d-b462799945cd)]
+[scriptable, uuid(efe95e19-f5df-4349-89fb-804ba016f0a2)]
 interface nsIDOMHTMLDocument : nsIDOMDocument
 {
   readonly attribute DOMString            URL;
            attribute DOMString            domain;
            attribute DOMString            cookie;
   // returns "BackCompat" if we're in quirks mode,
   // or "CSS1Compat" if we're in strict mode
   readonly attribute DOMString            compatMode;
@@ -61,16 +61,17 @@ interface nsIDOMHTMLDocument : nsIDOMDoc
            attribute nsIDOMHTMLElement    body;
 
   readonly attribute nsIDOMHTMLCollection images;
   readonly attribute nsIDOMHTMLCollection embeds;
   // mapped to attribute embeds for NS4 compat
   readonly attribute nsIDOMHTMLCollection plugins;
   readonly attribute nsIDOMHTMLCollection links;
   readonly attribute nsIDOMHTMLCollection forms;
+  readonly attribute nsIDOMHTMLCollection scripts;
   nsIDOMNodeList            getElementsByName(in DOMString elementName);
 
   // If aContentType is not something supported by nsHTMLDocument and
   // the HTML content sink, trying to write to the document will
   // probably throw.
   // Pass aReplace = true to trigger a replacement of the previous
   // document in session history; pass false for normal history handling.
   [implicit_jscontext, optional_argc]
--- a/dom/locales/en-US/chrome/layout/MediaDocument.properties
+++ b/dom/locales/en-US/chrome/layout/MediaDocument.properties
@@ -38,19 +38,19 @@
 # ***** END LICENSE BLOCK *****
 
 #LOCALIZATION NOTE (ImageTitleWithDimensionsAndFile): first %S is filename, second %S is type, third %S is width and fourth %S is height
 #LOCALIZATION NOTE (ImageTitleWithoutDimensions): first %S is filename, second %S is type
 #LOCALIZATION NOTE (ImageTitleWithDimensions): first %S is type, second %S is width and third %S is height
 #LOCALIZATION NOTE (ImageTitleWithNeitherDimensionsNorFile): first %S is type
 #LOCALIZATION NOTE (MediaTitleWithFile): first %S is filename, second %S is type
 #LOCALIZATION NOTE (MediaTitleWithNoInfo): first %S is type
-ImageTitleWithDimensionsAndFile=%S (%S Image, %Sx%S pixels)
+ImageTitleWithDimensionsAndFile=%S (%S Image, %S\u00A0\u00D7\u00A0%S pixels)
 ImageTitleWithoutDimensions=%S (%S Image)
-ImageTitleWithDimensions=(%S Image, %Sx%S pixels)
+ImageTitleWithDimensions=(%S Image, %S\u00A0\u00D7\u00A0%S pixels)
 ImageTitleWithNeitherDimensionsNorFile=(%S Image)
 MediaTitleWithFile=%S (%S Object)
 MediaTitleWithNoInfo=(%S Object)
 
 InvalidImage=The image \u201c%S\u201d cannot be displayed because it contains errors.
 ScaledImage=Scaled (%S%%)
 
 TitleWithStatus=%S - %S
--- a/dom/src/jsurl/nsJSProtocolHandler.cpp
+++ b/dom/src/jsurl/nsJSProtocolHandler.cpp
@@ -1023,16 +1023,34 @@ nsJSChannel::GetContentCharset(nsACStrin
 
 NS_IMETHODIMP
 nsJSChannel::SetContentCharset(const nsACString &aContentCharset)
 {
     return mStreamChannel->SetContentCharset(aContentCharset);
 }
 
 NS_IMETHODIMP
+nsJSChannel::GetContentDisposition(PRUint32 *aContentDisposition)
+{
+    return mStreamChannel->GetContentDisposition(aContentDisposition);
+}
+
+NS_IMETHODIMP
+nsJSChannel::GetContentDispositionFilename(nsAString &aContentDispositionFilename)
+{
+    return mStreamChannel->GetContentDispositionFilename(aContentDispositionFilename);
+}
+
+NS_IMETHODIMP
+nsJSChannel::GetContentDispositionHeader(nsACString &aContentDispositionHeader)
+{
+    return mStreamChannel->GetContentDispositionHeader(aContentDispositionHeader);
+}
+
+NS_IMETHODIMP
 nsJSChannel::GetContentLength(PRInt32 *aContentLength)
 {
     return mStreamChannel->GetContentLength(aContentLength);
 }
 
 NS_IMETHODIMP
 nsJSChannel::SetContentLength(PRInt32 aContentLength)
 {
--- a/dom/tests/mochitest/bugs/Makefile.in
+++ b/dom/tests/mochitest/bugs/Makefile.in
@@ -136,16 +136,17 @@ include $(topsrcdir)/config/rules.mk
 		test_bug617296.html \
 		test_bug620947.html \
 		test_bug622361.html \
 		test_bug633133.html \
 		test_bug641552.html \
 		test_bug642026.html \
 		test_bug648465.html \
 		test_bug654137.html \
+		test_bug684544.html \
 		test_window_bar.html \
 		file_window_bar.html \
 		test_resize_move_windows.html \
 		test_devicemotion_multiple_listeners.html \
 		devicemotion_outer.html \
 		devicemotion_inner.html \
 		$(NULL)
 
new file mode 100644
--- /dev/null
+++ b/dom/tests/mochitest/bugs/test_bug684544.html
@@ -0,0 +1,48 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=
+-->
+<head>
+  <title>Test for Bug </title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=">Mozilla Bug </a>
+<p id="display"></p>
+<div id="content" style="display: none">
+  
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug  **/
+
+var f = document.createElement("iframe");
+document.body.appendChild(f);
+var win = f.contentWindow;
+
+// Set location once to make sure it's resolved
+win.location = "data:text/html,1";
+
+// Now try to make the location object go away.
+f.parentNode.removeChild(f);
+
+// Check that location is now null.  If it's not, the test needs changing
+// (e.g. to use window.close() so that it's null).
+is("location" in win, true, "Should still have a location property");
+todo_is(win.location, null, "There should be no location object now");
+
+// Just set the location.  This should not crash.
+win.location = "data:text/html,2";
+
+// And check that we didn't override the slot in the process.
+is(typeof(win.location), "object", "Location should not have become a string");
+is(win.location, null,
+   "There should be no location object for real after the set");
+
+</script>
+</pre>
+</body>
+</html>
--- a/dom/tests/mochitest/whatwg/Makefile.in
+++ b/dom/tests/mochitest/whatwg/Makefile.in
@@ -75,16 +75,17 @@ include $(topsrcdir)/config/rules.mk
 		postMessage_closed_helper.html \
 		test_postMessage_jar.html \
 		postMessage.jar \
 		postMessage.jar^headers^ \
 		test_bug477323.html \
 		test_bug500328.html \
 		file_bug500328_1.html \
 		file_bug500328_2.html \
+		test_document_scripts.html \
 		test_postMessage_structured_clone.html \
 		postMessage_structured_clone_helper.js \
 		postMessage_structured_clone_helper.html \
 		$(NULL)
 
 _CHROME_FILES	= \
 		test_postMessage_chrome.html \
 		$(NULL)		
new file mode 100644
--- /dev/null
+++ b/dom/tests/mochitest/whatwg/test_document_scripts.html
@@ -0,0 +1,55 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=685774
+-->
+<head>
+  <title>Test for document.scripts (Bug 685774)</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=685774">Mozilla Bug 685774</a>
+<script type="application/javascript">
+
+/** Test for Bug 685774 **/
+
+function testSameCollection(a, b, c) {
+  is(a.length, c, "unexpected count of script elements");
+  is(b.length, c, "unexpected count of script elements");
+  for (var i = 0; i < a.length; i++) {
+    is(a[i], b[i], "document.scripts is not supported");
+  }
+}
+
+SimpleTest.waitForExplicitFinish();
+
+testSameCollection(document.scripts, document.getElementsByTagName("script"), 3);
+
+</script>
+<script type="application/javascript">
+
+testSameCollection(document.scripts, document.getElementsByTagName("script"), 4);
+
+function start() {
+  testSameCollection(document.scripts, document.getElementsByTagName("script"), 5);
+
+  var e = document.createElement("script");
+  testSameCollection(document.scripts, document.getElementsByTagName("script"), 5);
+  document.body.appendChild(e);
+  testSameCollection(document.scripts, document.getElementsByTagName("script"), 6);
+
+  SimpleTest.finish();
+}
+
+addLoadEvent(start);
+
+</script>
+<script type="application/javascript">
+
+testSameCollection(document.scripts, document.getElementsByTagName("script"), 5);
+
+</script>
+</body>
+</html>
--- a/editor/composer/src/crashtests/crashtests.list
+++ b/editor/composer/src/crashtests/crashtests.list
@@ -1,6 +1,6 @@
 asserts-if(Android,2) load 351236-1.html
 load 407062-1.html
 load 419563-1.xhtml
 skip-if(winWidget) load 428844-1.html # bug 471185
 load 461049-1.html
-asserts(0-1) asserts-if(winWidget,0-2) load removing-editable-xslt.html # bug 500847
+asserts(0-1) asserts-if(winWidget||Android,0-2) load removing-editable-xslt.html # bug 500847
--- a/editor/libeditor/base/nsEditor.cpp
+++ b/editor/libeditor/base/nsEditor.cpp
@@ -1959,17 +1959,17 @@ nsEditor::GetWidget(nsIWidget **aWidget)
 
 NS_IMETHODIMP
 nsEditor::ForceCompositionEnd()
 {
 
 // We can test mInIMEMode and do some optimization for Mac and Window
 // Howerver, since UNIX support over-the-spot, we cannot rely on that 
 // flag for Unix.
-// We should use nsILookAndFeel to resolve this
+// We should use LookAndFeel to resolve this
 
 #if defined(XP_MACOSX) || defined(XP_WIN) || defined(XP_OS2)
   // XXXmnakano see bug 558976, ResetInputState() has two meaning which are
   // "commit the composition" and "cursor is moved".  This method name is
   // "ForceCompositionEnd", so, ResetInputState() should be used only for the
   // former here.  However, ResetInputState() is also used for the latter here
   // because even if we don't have composition, we call ResetInputState() on
   // Linux.  Currently, nsGtkIMModule can know the timing of the cursor move,
--- a/editor/libeditor/base/nsEditorEventListener.cpp
+++ b/editor/libeditor/base/nsEditorEventListener.cpp
@@ -48,17 +48,16 @@
 #include "nsIDocument.h"
 #include "nsIPresShell.h"
 #include "nsISelection.h"
 #include "nsISelectionController.h"
 #include "nsIDOMKeyEvent.h"
 #include "nsIDOMMouseEvent.h"
 #include "nsIPrivateTextEvent.h"
 #include "nsIEditorMailSupport.h"
-#include "nsILookAndFeel.h"
 #include "nsFocusManager.h"
 #include "nsEventListenerManager.h"
 #include "mozilla/Preferences.h"
 
 // Drag & Drop, Clipboard
 #include "nsIServiceManager.h"
 #include "nsIClipboard.h"
 #include "nsIDragService.h"
new file mode 100644
--- /dev/null
+++ b/editor/libeditor/html/crashtests/682650-1.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script>
+
+function repeatChar(s, n)
+{
+  while (s.length < n)
+    s += s;
+  return s.substr(0, n);
+}
+
+function boom()
+{
+  document.documentElement.contentEditable = "true";
+  document.execCommand("inserthtml", false, "<button><\/button>");
+  document.execCommand("inserthtml", false, repeatChar("i", 34646));
+  document.execCommand("contentReadOnly", false, null);
+  document.execCommand("removeformat", false, null);
+  document.execCommand("hilitecolor", false, "red");
+  document.execCommand("inserthtml", false, "a");
+  document.execCommand("delete", false, null);
+}
+
+</script>
+</head>
+
+<body onload="boom();"></body>
+
+</html>
--- a/editor/libeditor/html/crashtests/crashtests.list
+++ b/editor/libeditor/html/crashtests/crashtests.list
@@ -17,8 +17,9 @@ load 503709-1.xhtml
 load 513375-1.xhtml
 load 535632-1.xhtml
 load 574558-1.xhtml
 load 582138-1.xhtml
 load 612565-1.html
 asserts(0-6) load 615015-1.html # Bug 439258
 load 615450-1.html
 load 643786-1.html
+load 682650-1.html
--- a/editor/libeditor/html/nsHTMLAnonymousUtils.cpp
+++ b/editor/libeditor/html/nsHTMLAnonymousUtils.cpp
@@ -363,39 +363,41 @@ nsHTMLEditor::CheckSelectionStateForAnon
   if (mIsInlineTableEditingEnabled && mInlineEditedCell &&
       mInlineEditedCell != cellElement) {
     res = HideInlineTableEditingUI();
     NS_ENSURE_SUCCESS(res, res);
     NS_ASSERTION(!mInlineEditedCell, "HideInlineTableEditingUI failed");
   }
 
   // now, let's display all contextual UI for good
+  nsIContent* hostContent = GetActiveEditingHost();
+  nsCOMPtr<nsIDOMNode> hostNode = do_QueryInterface(hostContent);
 
   if (mIsObjectResizingEnabled && focusElement &&
-      IsModifiableNode(focusElement)) {
+      IsModifiableNode(focusElement) && focusElement != hostNode) {
     if (nsEditProperty::img == focusTagAtom)
       mResizedObjectIsAnImage = PR_TRUE;
     if (mResizedObject)
       res = RefreshResizers();
     else
       res = ShowResizers(focusElement);
     NS_ENSURE_SUCCESS(res, res);
   }
 
   if (mIsAbsolutelyPositioningEnabled && absPosElement &&
-      IsModifiableNode(absPosElement)) {
+      IsModifiableNode(absPosElement) && absPosElement != hostNode) {
     if (mAbsolutelyPositionedObject)
       res = RefreshGrabber();
     else
       res = ShowGrabberOnElement(absPosElement);
     NS_ENSURE_SUCCESS(res, res);
   }
 
   if (mIsInlineTableEditingEnabled && cellElement &&
-      IsModifiableNode(cellElement)) {
+      IsModifiableNode(cellElement) && cellElement != hostNode) {
     if (mInlineEditedCell)
       res = RefreshInlineTableEditingUI();
     else
       res = ShowInlineTableEditingUI(cellElement);
   }
 
   return res;
 }
--- a/editor/libeditor/html/nsHTMLObjectResizer.cpp
+++ b/editor/libeditor/html/nsHTMLObjectResizer.cpp
@@ -57,25 +57,22 @@
 #include "nsEditorUtils.h"
 #include "nsHTMLEditUtils.h"
 
 #include "nsPoint.h"
 
 #include "nsIServiceManager.h"
 #include "mozilla/Preferences.h"
 
-#include "nsILookAndFeel.h"
-#include "nsWidgetsCID.h"
+#include "mozilla/LookAndFeel.h"
 
 using namespace mozilla;
 
 class nsHTMLEditUtils;
 
-static NS_DEFINE_CID(kLookAndFeelCID, NS_LOOKANDFEEL_CID);
-
 // ==================================================================
 // DocumentResizeEventListener
 // ==================================================================
 NS_IMPL_ISUPPORTS1(DocumentResizeEventListener, nsIDOMEventListener)
 
 DocumentResizeEventListener::DocumentResizeEventListener(nsIHTMLEditor * aEditor) 
 {
   mEditor = do_GetWeakReference(aEditor);
@@ -890,22 +887,20 @@ nsHTMLEditor::MouseMove(nsIDOMEvent* aMo
   }
 
   if (mGrabberClicked) {
     nsCOMPtr<nsIDOMMouseEvent> mouseEvent ( do_QueryInterface(aMouseEvent) );
     PRInt32 clientX, clientY;
     mouseEvent->GetClientX(&clientX);
     mouseEvent->GetClientY(&clientY);
 
-    nsCOMPtr<nsILookAndFeel> look = do_GetService(kLookAndFeelCID);
-    NS_ASSERTION(look, "Look and feel service must be implemented for this toolkit");
-
-    PRInt32 xThreshold=1, yThreshold=1;
-    look->GetMetric(nsILookAndFeel::eMetric_DragThresholdX, xThreshold);
-    look->GetMetric(nsILookAndFeel::eMetric_DragThresholdY, yThreshold);
+    PRInt32 xThreshold =
+      LookAndFeel::GetInt(LookAndFeel::eIntID_DragThresholdX, 1);
+    PRInt32 yThreshold =
+      LookAndFeel::GetInt(LookAndFeel::eIntID_DragThresholdY, 1);
 
     if (NS_ABS(clientX - mOriginalX ) * 2 >= xThreshold ||
         NS_ABS(clientY - mOriginalY ) * 2 >= yThreshold) {
       mGrabberClicked = PR_FALSE;
       StartMoving(nsnull);
     }
   }
   if (mIsMoving) {
--- a/editor/libeditor/html/nsWSRunObject.h
+++ b/editor/libeditor/html/nsWSRunObject.h
@@ -224,19 +224,19 @@ class NS_STACK_CLASS nsWSRunObject
     // WSPoint struct ------------------------------------------------------------
     // A WSPoint struct represents a unique location within the ws run.  It is 
     // always within a textnode that is one of the nodes stored in the list
     // in the wsRunObject.  For convenience, the character at that point is also 
     // stored in the struct.
     struct NS_STACK_CLASS WSPoint
     {
       nsCOMPtr<nsIContent> mTextNode;
-      PRInt16 mOffset;
+      PRUint32 mOffset;
       PRUnichar mChar;
-      
+
       WSPoint() : mTextNode(0),mOffset(0),mChar(0) {}
       WSPoint(nsIDOMNode *aNode, PRInt32 aOffset, PRUnichar aChar) : 
                      mTextNode(do_QueryInterface(aNode)),mOffset(aOffset),mChar(aChar)
       {
         if (!mTextNode->IsNodeOfType(nsINode::eDATA_NODE)) {
           // Not sure if this is needed, but it'll maintain the same
           // functionality
           mTextNode = nsnull;
--- a/editor/libeditor/text/nsInternetCiter.cpp
+++ b/editor/libeditor/text/nsInternetCiter.cpp
@@ -78,17 +78,17 @@ nsInternetCiter::GetCiteString(const nsA
 
   // Loop over the string:
   while (beginIter != endIter)
   {
     if (uch == nl)
     {
       aOutString.Append(gt);
       // No space between >: this is ">>> " style quoting, for
-      // compatability with RFC 2646 and format=flowed.
+      // compatibility with RFC 2646 and format=flowed.
       if (*beginIter != gt)
         aOutString.Append(space);
     }
 
     uch = *beginIter;
     ++beginIter;
 
     aOutString += uch;
--- a/editor/libeditor/text/nsTextEditRules.cpp
+++ b/editor/libeditor/text/nsTextEditRules.cpp
@@ -54,31 +54,28 @@
 #include "nsIDOMNSRange.h"
 #include "nsIDOMCharacterData.h"
 #include "nsIContent.h"
 #include "nsIContentIterator.h"
 #include "nsEditorUtils.h"
 #include "EditTxn.h"
 #include "nsEditProperty.h"
 #include "nsUnicharUtils.h"
-#include "nsILookAndFeel.h"
-#include "nsWidgetsCID.h"
 #include "DeleteTextTxn.h"
 #include "nsNodeIterator.h"
 #include "nsIDOMNodeFilter.h"
 
 // for IBMBIDI
 #include "nsFrameSelection.h"
 
 #include "mozilla/Preferences.h"
+#include "mozilla/LookAndFeel.h"
 
 using namespace mozilla;
 
-static NS_DEFINE_CID(kLookAndFeelCID, NS_LOOKANDFEEL_CID);
-
 #define CANCEL_OPERATION_IF_READONLY_OR_DISABLED \
   if (IsReadonly() || IsDisabled()) \
   {                     \
     *aCancel = PR_TRUE; \
     return NS_OK;       \
   };
 
 
@@ -677,18 +674,17 @@ nsTextEditRules::WillInsertText(PRInt32 
     outString->Assign(tString);
   }
 
   if (IsPasswordEditor())
   {
     // manage the password buffer
     mPasswordText.Insert(*outString, start);
 
-    nsCOMPtr<nsILookAndFeel> lookAndFeel = do_GetService(kLookAndFeelCID);
-    if (lookAndFeel->GetEchoPassword() && !DontEchoPassword()) {
+    if (LookAndFeel::GetEchoPassword() && !DontEchoPassword()) {
       HideLastPWInput();
       mLastStart = start;
       mLastLength = outString->Length();
       if (mTimer)
       {
         mTimer->Cancel();
       }
       else
@@ -827,19 +823,18 @@ nsTextEditRules::WillDeleteSelection(nsI
   {
     res = mEditor->ExtendSelectionForDelete(aSelection, &aCollapsedAction);
     NS_ENSURE_SUCCESS(res, res);
 
     // manage the password buffer
     PRUint32 start, end;
     mEditor->GetTextSelectionOffsets(aSelection, start, end);
     NS_ENSURE_SUCCESS(res, res);
-    nsCOMPtr<nsILookAndFeel> lookAndFeel = do_GetService(kLookAndFeelCID);
 
-    if (lookAndFeel->GetEchoPassword()) {
+    if (LookAndFeel::GetEchoPassword()) {
       HideLastPWInput();
       mLastStart = start;
       mLastLength = 0;
       if (mTimer)
       {
         mTimer->Cancel();
       }
     }
@@ -1333,22 +1328,17 @@ nsresult nsTextEditRules::HideLastPWInpu
 
 // static
 nsresult
 nsTextEditRules::FillBufWithPWChars(nsAString *aOutString, PRInt32 aLength)
 {
   if (!aOutString) {return NS_ERROR_NULL_POINTER;}
 
   // change the output to the platform password character
-  PRUnichar passwordChar = PRUnichar('*');
-  nsCOMPtr<nsILookAndFeel> lookAndFeel = do_GetService(kLookAndFeelCID);
-  if (lookAndFeel)
-  {
-    passwordChar = lookAndFeel->GetPasswordCharacter();
-  }
+  PRUnichar passwordChar = LookAndFeel::GetPasswordCharacter();
 
   PRInt32 i;
   aOutString->Truncate();
   for (i=0; i < aLength; i++)
     aOutString->Append(passwordChar);
 
   return NS_OK;
 }
--- a/embedding/android/AndroidManifest.xml.in
+++ b/embedding/android/AndroidManifest.xml.in
@@ -5,17 +5,17 @@
       android:installLocation="auto"
       android:versionCode="@ANDROID_VERSION_CODE@"
       android:versionName="@MOZ_APP_VERSION@"
 #ifdef MOZ_ANDROID_SHARED_ID
       android:sharedUserId="@MOZ_ANDROID_SHARED_ID@"
 #endif
       >
     <uses-sdk android:minSdkVersion="5"
-              android:targetSdkVersion="5"/>
+              android:targetSdkVersion="11"/>
 
     <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
     <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
     <uses-permission android:name="android.permission.INTERNET"/>
     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
     <uses-permission android:name="android.permission.READ_PHONE_STATE"/>
     <uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT"/>
 
--- a/embedding/android/resources/layout/notification_icon_text.xml
+++ b/embedding/android/resources/layout/notification_icon_text.xml
@@ -10,25 +10,25 @@
         android:layout_height="wrap_content"
         android:orientation="horizontal"
         >
         <ImageView android:id="@+id/notificationImage"
             android:layout_width="25dp"
             android:layout_height="25dp"
             android:scaleType="fitCenter" />
         <TextView android:id="@+id/notificationTitle"
+            android:textAppearance="@android:style/TextAppearance.StatusBar.EventContent.Title"
             android:layout_width="fill_parent"
             android:layout_height="wrap_content"
             android:layout_weight="1"
             android:singleLine="true"
             android:ellipsize="marquee"
             android:fadingEdge="horizontal"
-            android:textStyle="bold"
-            android:textSize="18sp"
             android:paddingLeft="4dp"
-            android:textColor="#ff000000" />
+            />
     </LinearLayout>
     <TextView android:id="@+id/notificationText"
+          android:textAppearance="@android:style/TextAppearance.StatusBar.EventContent"
 	      android:layout_width="fill_parent"
 	      android:layout_height="wrap_content"
 	      android:paddingLeft="4dp"
-	      android:textColor="#ff000000" />
+	      />
 </LinearLayout>
--- a/embedding/android/resources/layout/notification_progress.xml
+++ b/embedding/android/resources/layout/notification_progress.xml
@@ -11,38 +11,38 @@
         android:layout_height="wrap_content"
         android:orientation="horizontal"
         >
         <ImageView android:id="@+id/notificationImage"
             android:layout_width="25dp"
             android:layout_height="25dp"
             android:scaleType="fitCenter" />
         <TextView android:id="@+id/notificationTitle"
+            android:textAppearance="@android:style/TextAppearance.StatusBar.EventContent.Title"
             android:layout_width="fill_parent"
             android:layout_height="wrap_content"
             android:layout_weight="1"
             android:singleLine="true"
             android:ellipsize="marquee"
             android:fadingEdge="horizontal"
-            android:textStyle="bold"
-            android:textSize="18sp"
             android:paddingLeft="10dp"
-            android:textColor="#ff000000" />
+            />
     </LinearLayout>
 
     <LinearLayout
         android:layout_width="fill_parent"
         android:layout_height="wrap_content"
         android:orientation="horizontal"
         >
         <TextView android:id="@+id/notificationText"
+            android:textAppearance="@android:style/TextAppearance.StatusBar.EventContent"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:paddingLeft="3dp"
-            android:textColor="#ff000000" />
+            />
 
         <ProgressBar android:id="@+id/notificationProgressbar"
             style="?android:attr/progressBarStyleHorizontal"
             android:layout_width="fill_parent"
             android:layout_height="wrap_content"
             android:layout_marginTop="1dip"
             android:layout_marginBottom="1dip"
             android:layout_marginLeft="4dip"
--- a/embedding/android/resources/layout/notification_progress_text.xml
+++ b/embedding/android/resources/layout/notification_progress_text.xml
@@ -10,37 +10,37 @@
         android:layout_height="wrap_content"
         android:orientation="horizontal"
         >
         <ImageView android:id="@+id/notificationImage"
             android:layout_width="25dp"
             android:layout_height="25dp"
             android:scaleType="fitCenter" />
         <TextView android:id="@+id/notificationTitle"
+            android:textAppearance="@android:style/TextAppearance.StatusBar.EventContent.Title"
             android:layout_width="fill_parent"
             android:layout_height="wrap_content"
             android:layout_weight="1"
             android:singleLine="true"
             android:ellipsize="marquee"
             android:fadingEdge="horizontal"
-            android:textStyle="bold"
-            android:textSize="18sp"
             android:paddingLeft="4dp"
-            android:textColor="#ff000000" />
+            />
     </LinearLayout>
 
     <ProgressBar android:id="@+id/notificationProgressbar"
         style="?android:attr/progressBarStyleHorizontal"
         android:layout_width="fill_parent"
         android:layout_height="16dip"
         android:layout_marginTop="1dip"
         android:layout_marginBottom="1dip"
         android:layout_marginLeft="10dip"
         android:layout_marginRight="10dip"
         android:layout_centerHorizontal="true" />
 
     <TextView android:id="@+id/notificationText"
+        android:textAppearance="@android:style/TextAppearance.StatusBar.EventContent"
         android:layout_width="fill_parent"
         android:layout_height="wrap_content"
         android:paddingLeft="4dp"
-        android:textColor="#ff000000" />
+        />
 
 </LinearLayout>
--- a/embedding/browser/webBrowser/nsWebBrowser.cpp
+++ b/embedding/browser/webBrowser/nsWebBrowser.cpp
@@ -70,33 +70,33 @@
 #include "nsCWebBrowserPersist.h"
 #include "nsIServiceManager.h"
 #include "nsAutoPtr.h"
 #include "nsFocusManager.h"
 #include "Layers.h"
 #include "gfxContext.h"
 
 // for painting the background window
-#include "nsILookAndFeel.h"
+#include "mozilla/LookAndFeel.h"
 
 // Printing Includes
 #ifdef NS_PRINTING
 #include "nsIWebBrowserPrint.h"
 #include "nsIContentViewer.h"
 #endif
 
 // PSM2 includes
 #include "nsISecureBrowserUI.h"
 #include "nsXULAppAPI.h"
 
+using namespace mozilla;
 using namespace mozilla::layers;
 
 static NS_DEFINE_IID(kWindowCID, NS_WINDOW_CID);
 static NS_DEFINE_CID(kChildCID, NS_CHILD_CID);
-static NS_DEFINE_CID(kLookAndFeelCID, NS_LOOKANDFEEL_CID);
 
 
 //*****************************************************************************
 //***    nsWebBrowser: Object Management
 //*****************************************************************************
 
 nsWebBrowser::nsWebBrowser() : mDocShellTreeOwner(nsnull), 
    mInitInfo(nsnull),
@@ -1159,22 +1159,19 @@ NS_IMETHODIMP nsWebBrowser::Create()
                               nsnull, nsnull, nsnull, &widgetInit);  
       }
 
     nsCOMPtr<nsIDocShell> docShell(do_CreateInstance("@mozilla.org/docshell;1", &rv));
     NS_ENSURE_SUCCESS(rv, rv);
     rv = SetDocShell(docShell);
     NS_ENSURE_SUCCESS(rv, rv);
 
-   // get the system default window background colour
-   {
-      nsCOMPtr<nsILookAndFeel> laf = do_GetService(kLookAndFeelCID);
-        if (laf)
-      laf->GetColor(nsILookAndFeel::eColor_WindowBackground, mBackgroundColor);
-   }
+    // get the system default window background colour
+    LookAndFeel::GetColor(LookAndFeel::eColorID_WindowBackground,
+                          &mBackgroundColor);
 
    // the docshell has been set so we now have our listener registrars.
    if (mListenerArray) {
       // we had queued up some listeners, let's register them now.
       PRUint32 count = mListenerArray->Length();
       PRUint32 i = 0;
       NS_ASSERTION(count > 0, "array construction problem");
       while (i < count) {
--- a/extensions/permissions/nsContentBlocker.cpp
+++ b/extensions/permissions/nsContentBlocker.cpp
@@ -48,30 +48,34 @@
 
 // Possible behavior pref values
 // Those map to the nsIPermissionManager values where possible
 #define BEHAVIOR_ACCEPT nsIPermissionManager::ALLOW_ACTION
 #define BEHAVIOR_REJECT nsIPermissionManager::DENY_ACTION
 #define BEHAVIOR_NOFOREIGN 3
 
 // From nsIContentPolicy
-static const char *kTypeString[NUMBER_OF_TYPES] = {"other", 
-                                                   "script",
-                                                   "image",
-                                                   "stylesheet",
-                                                   "object",
-                                                   "document",
-                                                   "subdocument",
-                                                   "refresh",
-                                                   "xbl",
-                                                   "ping",
-                                                   "xmlhttprequest",
-                                                   "objectsubrequest",
-                                                   "dtd"};
+static const char *kTypeString[] = {"other",
+                                    "script",
+                                    "image",
+                                    "stylesheet",
+                                    "object",
+                                    "document",
+                                    "subdocument",
+                                    "refresh",
+                                    "xbl",
+                                    "ping",
+                                    "xmlhttprequest",
+                                    "objectsubrequest",
+                                    "dtd",
+                                    "font",
+                                    "media"};
 
+#define NUMBER_OF_TYPES NS_ARRAY_LENGTH(kTypeString)
+PRUint8 nsContentBlocker::mBehaviorPref[NUMBER_OF_TYPES];
 
 NS_IMPL_ISUPPORTS3(nsContentBlocker, 
                    nsIContentPolicy,
                    nsIObserver,
                    nsSupportsWeakReference)
 
 nsContentBlocker::nsContentBlocker()
 {
--- a/extensions/permissions/nsContentBlocker.h
+++ b/extensions/permissions/nsContentBlocker.h
@@ -41,19 +41,16 @@
 #include "nsWeakReference.h"
 #include "nsIPermissionManager.h"
 #include "nsIPrefBranch2.h"
 
 class nsIPrefBranch;
 
 ////////////////////////////////////////////////////////////////////////////////
 
-// number of permission types in nsIContentPolicy
-#define NUMBER_OF_TYPES 13
-
 class nsContentBlocker : public nsIContentPolicy,
                          public nsIObserver,
                          public nsSupportsWeakReference
 {
 public:
 
   // nsISupports
   NS_DECL_ISUPPORTS
@@ -70,17 +67,17 @@ private:
   nsresult TestPermission(nsIURI *aCurrentURI,
                           nsIURI *aFirstURI,
                           PRInt32 aContentType,
                           PRBool *aPermission,
                           PRBool *aFromPrefs);
 
   nsCOMPtr<nsIPermissionManager> mPermissionManager;
   nsCOMPtr<nsIPrefBranch2> mPrefBranchInternal;
-  PRUint8 mBehaviorPref[NUMBER_OF_TYPES];
+  static PRUint8 mBehaviorPref[];
 };
 
 #define NS_CONTENTBLOCKER_CID \
 { 0x4ca6b67b, 0x5cc7, 0x4e71, \
   { 0xa9, 0x8a, 0x97, 0xaf, 0x1c, 0x13, 0x48, 0x62 } }
 
 #define NS_CONTENTBLOCKER_CONTRACTID "@mozilla.org/permissions/contentblocker;1"
 
--- a/gfx/angle/Makefile.in
+++ b/gfx/angle/Makefile.in
@@ -123,16 +123,18 @@ CSRCS   = \
         memory.c \
         scanner.c \
         symbols.c \
         tokens.c \
 	$(NULL)
 
 DEFINES += -DANGLE_USE_NSPR -DANGLE_BUILD
 
+EXTRA_DSO_LDOPTS = $(MOZALLOC_LIB)
+
 ifdef MOZ_ANGLE
 
 # libEGL depends on (links against!) libGLESv2!
 DIRS = src/libGLESv2 src/libEGL
 
 libs::
 	expand "$(MOZ_D3DX9_CAB)" -F:$(MOZ_D3DX9_DLL) "$(DIST)/bin"
 	expand "$(MOZ_D3DCOMPILER_CAB)" -F:$(MOZ_D3DCOMPILER_DLL) "$(DIST)/bin"
--- a/gfx/angle/README.mozilla
+++ b/gfx/angle/README.mozilla
@@ -4,16 +4,17 @@ Current revision: r740
 
 == Applied local patches ==
 
 In this order:
   angle-nspr-misc.patch - don't bother with ANGLE_OS detection with NSPR
   angle-renaming.patch - rename debug.h to compilerdebug.h to avoid conflict in our makefiles
   angle-intrinsic-msvc2005.patch - work around a MSVC 2005 compile error
   angle-limit-identifiers-to-250-chars.patch - see bug 675625
+  angle-use-xmalloc.patch - see bug 680840. Can drop this patch whenever the new preprocessor lands.
 
 In addition to these patches, the Makefile.in files are ours, they're not present in upsteam ANGLE.
 
 == How to update this ANGLE copy ==
 
 1. Unapply patches
 2. Apply diff with new ANGLE version
 3. Reapply patches.
--- a/gfx/angle/src/compiler/preprocessor/atom.c
+++ b/gfx/angle/src/compiler/preprocessor/atom.c
@@ -48,16 +48,18 @@ NVIDIA HAS BEEN ADVISED OF THE POSSIBILI
 
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
 
 #include "compiler/compilerdebug.h"
 #include "compiler/preprocessor/slglobals.h"
 
+#include "../../../../../memory/mozalloc/mozalloc.h"
+
 #undef malloc
 #undef realloc
 #undef free
 
 ///////////////////////////////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////// String table: //////////////////////////////////////
 ///////////////////////////////////////////////////////////////////////////////////////////////
 
@@ -318,31 +320,23 @@ static int AddAtomFixed(AtomTable *atabl
  */
 
 static int GrowAtomTable(AtomTable *atable, int size)
 {
     int *newmap, *newrev;
 
     if (atable->size < size) {
         if (atable->amap) {
-            newmap = realloc(atable->amap, sizeof(int)*size);
-            newrev = realloc(atable->arev, sizeof(int)*size);
+            newmap = moz_xrealloc(atable->amap, sizeof(int)*size);
+            newrev = moz_xrealloc(atable->arev, sizeof(int)*size);
         } else {
-            newmap = malloc(sizeof(int)*size);
-            newrev = malloc(sizeof(int)*size);
+            newmap = moz_xmalloc(sizeof(int)*size);
+            newrev = moz_xmalloc(sizeof(int)*size);
             atable->size = 0;
         }
-        if (!newmap || !newrev) {
-            /* failed to grow -- error */
-            if (newmap)
-                atable->amap = newmap;
-            if (newrev)
-                atable->arev = newrev;
-            return -1;
-        }
         memset(&newmap[atable->size], 0, (size - atable->size) * sizeof(int));
         memset(&newrev[atable->size], 0, (size - atable->size) * sizeof(int));
         atable->amap = newmap;
         atable->arev = newrev;
         atable->size = size;
     }
     return 0;
 } // GrowAtomTable
--- a/gfx/angle/src/libEGL/Makefile.in
+++ b/gfx/angle/src/libEGL/Makefile.in
@@ -150,8 +150,10 @@ RCFILE = $(srcdir)/libEGL.rc
 include $(topsrcdir)/config/rules.mk
 
 EXTRA_DSO_LDOPTS = "$(MOZ_DIRECTX_SDK_PATH)/lib/$(MOZ_DIRECTX_SDK_CPU_SUFFIX)/d3d9.lib" \
                    "$(MOZ_DIRECTX_SDK_PATH)/lib/$(MOZ_DIRECTX_SDK_CPU_SUFFIX)/dxguid.lib" \
 		   "$(DIST)/lib/libGLESv2.lib" \
 		   dwmapi.lib \
 		   delayimp.lib \
 		   /delayload:dwmapi.dll
+
+EXTRA_DSO_LDOPTS += $(MOZALLOC_LIB)
--- a/gfx/angle/src/libGLESv2/Makefile.in
+++ b/gfx/angle/src/libGLESv2/Makefile.in
@@ -159,8 +159,10 @@ CPPSRCS	+= \
 DEFFILE = $(srcdir)/libGLESv2.def
 RCFILE = $(srcdir)/libGLESv2.rc
 
 include $(topsrcdir)/config/rules.mk
 
 EXTRA_DSO_LDOPTS = "$(MOZ_DIRECTX_SDK_PATH)/lib/$(MOZ_DIRECTX_SDK_CPU_SUFFIX)/d3d9.lib" \
                    "$(MOZ_DIRECTX_SDK_PATH)/lib/$(MOZ_DIRECTX_SDK_CPU_SUFFIX)/d3dx9.lib" \
 		   "$(MOZ_DIRECTX_SDK_PATH)/lib/$(MOZ_DIRECTX_SDK_CPU_SUFFIX)/D3DCompiler.lib"
+
+EXTRA_DSO_LDOPTS += $(MOZALLOC_LIB)
--- a/gfx/layers/opengl/LayerManagerOGL.cpp
+++ b/gfx/layers/opengl/LayerManagerOGL.cpp
@@ -1013,23 +1013,23 @@ LayerManagerOGL::CopyToTarget()
 
   nsRefPtr<gfxImageSurface> imageSurface =
     new gfxImageSurface(gfxIntSize(width, height),
                         gfxASurface::ImageFormatARGB32);
 
   mGLContext->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER,
                                mGLContext->IsDoubleBuffered() ? 0 : mBackBufferFBO);
 
+#ifndef USE_GLES2
+  // GLES2 promises that binding to any custom FBO will attach
+  // to GL_COLOR_ATTACHMENT0 attachment point.
   if (mGLContext->IsDoubleBuffered()) {
     mGLContext->fReadBuffer(LOCAL_GL_BACK);
   }
-#ifndef USE_GLES2
   else {
-  // GLES2 promises that binding to any custom FBO will attach
-  // to GL_COLOR_ATTACHMENT0 attachment point.
     mGLContext->fReadBuffer(LOCAL_GL_COLOR_ATTACHMENT0);
   }
 #endif
 
   GLenum format = LOCAL_GL_RGBA;
   if (mHasBGRA)
     format = LOCAL_GL_BGRA;
 
--- a/gfx/thebes/GLContext.cpp
+++ b/gfx/thebes/GLContext.cpp
@@ -1843,18 +1843,24 @@ GLContext::TexImage2D(GLenum target, GLi
     bool useUnpackRowLength = true;
 #else
     // A Khronos extension, GL_EXT_unpack_subimage, that restores support
     // for GL_UNPACK_ROW_LENGTH, GL_UNPACK_SKIP_ROWS and GL_UNPACK_SKIP_PIXELS
     // exists on Tegra 2 (and possibly other chipsets)
     bool useUnpackRowLength = IsExtensionSupported(EXT_unpack_subimage);
 #endif
 
+    // Don't use UNPACK_ROW_LENGTH if the length would be greater than the
+    // maximum texture size
+    int rowLength = stride/pixelsize;
+    if (rowLength > mMaxTextureSize)
+      useUnpackRowLength = false;
+
     if (useUnpackRowLength)
-        fPixelStorei(LOCAL_GL_UNPACK_ROW_LENGTH, stride/pixelsize);
+        fPixelStorei(LOCAL_GL_UNPACK_ROW_LENGTH, rowLength);
     else if (stride != width * pixelsize) {
         // Not using the whole row of texture data and GLES doesn't 
         // support GL_UNPACK_ROW_LENGTH. We need to upload each row
         // separately.
         fTexImage2D(target,
                     border,
                     internalformat,
                     width,
--- a/gfx/thebes/gfxFT2FontList.cpp
+++ b/gfx/thebes/gfxFT2FontList.cpp
@@ -222,17 +222,19 @@ gfxFT2FontList::FindFonts()
         {
             nsCString s("/system/fonts");
             s.Append("/");
             s.Append(nsDependentCString(ent->d_name));
 
             AppendFacesFromFontFile(nsPromiseFlatCString(s).get());
         }
     }
-
+    if (d) {
+      closedir(d);
+    }
     mCodepointsWithNoFonts.SetRange(0,0x1f);     // C0 controls
     mCodepointsWithNoFonts.SetRange(0x7f,0x9f);  // C1 controls
 
 #endif // XP_WIN && ANDROID
 }
 
 nsresult
 gfxFT2FontList::InitFontList()
--- a/intl/lwbrk/src/nsJISx4501LineBreaker.cpp
+++ b/intl/lwbrk/src/nsJISx4501LineBreaker.cpp
@@ -455,17 +455,17 @@ GetClass(PRUnichar u)
      c = GETCLASSFROMTABLE(gLBClass20, l);
    } else if (0x2100 == h) {
      c = GETCLASSFROMTABLE(gLBClass21, l);
    } else if (0x3000 == h) {
      c = GETCLASSFROMTABLE(gLBClass30, l);
    } else if (((0x3200 <= u) && (u <= 0xA4CF)) || // CJK and Yi
               ((0xAC00 <= h) && (h <= 0xD7FF)) || // Hangul
               ((0xf900 <= h) && (h <= 0xfaff))) {
-     c = CLASS_BREAKABLE; // CJK character, Han, and Han Compatability
+     c = CLASS_BREAKABLE; // CJK character, Han, and Han Compatibility
    } else if (0xff00 == h) {
      if (l < 0x0060) { // Fullwidth ASCII variant
        c = GETCLASSFROMTABLE(gLBClass00, (l+0x20));
      } else if (l < 0x00a0) {
        switch (l) {
          case 0x61: c = GetClass(0x3002); break;
          case 0x62: c = GetClass(0x300c); break;
          case 0x63: c = GetClass(0x300d); break;
--- a/intl/uconv/src/nsUnicodeToUTF8.cpp
+++ b/intl/uconv/src/nsUnicodeToUTF8.cpp
@@ -48,17 +48,17 @@ NS_IMPL_ISUPPORTS1(nsUnicodeToUTF8, nsIU
 
 NS_IMETHODIMP nsUnicodeToUTF8::GetMaxLength(const PRUnichar * aSrc, 
                                               PRInt32 aSrcLength,
                                               PRInt32 * aDestLength)
 {
   // aSrc is interpreted as UTF16, 3 is normally enough.
   // But when previous buffer only contains part of the surrogate pair, we 
   // need to complete it here. If the first word in following buffer is not
-  // in valid surrogate rang, we need to convert the remaining of last buffer 
+  // in valid surrogate range, we need to convert the remaining of last buffer
   // to 3 bytes.
   *aDestLength = 3*aSrcLength + 3;
   return NS_OK;
 }
 
 NS_IMETHODIMP nsUnicodeToUTF8::Convert(const PRUnichar * aSrc, 
                                 PRInt32 * aSrcLength, 
                                 char * aDest, 
--- a/ipc/chromium/src/base/histogram.cc
+++ b/ipc/chromium/src/base/histogram.cc
@@ -125,16 +125,27 @@ void Histogram::Add(int value) {
   if (value < 0)
     value = 0;
   size_t index = BucketIndex(value);
   DCHECK_GE(value, ranges(index));
   DCHECK_LT(value, ranges(index + 1));
   Accumulate(value, 1, index);
 }
 
+void Histogram::Subtract(int value) {
+  if (value > kSampleType_MAX - 1)
+    value = kSampleType_MAX - 1;
+  if (value < 0)
+    value = 0;
+  size_t index = BucketIndex(value);
+  DCHECK_GE(value, ranges(index));
+  DCHECK_LT(value, ranges(index + 1));
+  Accumulate(value, -1, index);
+}
+
 void Histogram::AddBoolean(bool value) {
   DCHECK(false);
 }
 
 void Histogram::AddSampleSet(const SampleSet& sample) {
   sample_.Add(sample);
 }
 
--- a/ipc/chromium/src/base/histogram.h
+++ b/ipc/chromium/src/base/histogram.h
@@ -376,16 +376,17 @@ class Histogram {
                                Flags flags);
   static Histogram* FactoryTimeGet(const std::string& name,
                                    base::TimeDelta minimum,
                                    base::TimeDelta maximum,
                                    size_t bucket_count,
                                    Flags flags);
 
   void Add(int value);
+  void Subtract(int value);
 
   // This method is an interface, used only by BooleanHistogram.
   virtual void AddBoolean(bool value);
 
   // Accept a TimeDelta to increment.
   void AddTime(TimeDelta time) {
     Add(static_cast<int>(time.InMilliseconds()));
   }
--- a/js/jsd/jsd_xpc.cpp
+++ b/js/jsd/jsd_xpc.cpp
@@ -55,19 +55,16 @@
 #include "jsdebug.h"
 #include "nsReadableUtils.h"
 #include "nsCRT.h"
 
 /* XXX DOM dependency */
 #include "nsIScriptContext.h"
 #include "nsIJSContextStack.h"
 
-/* XXX private JS headers. */
-#include "jscompartment.h"
-
 /*
  * defining CAUTIOUS_SCRIPTHOOK makes jsds disable GC while calling out to the
  * script hook.  This was a hack to avoid some js engine problems that should
  * be fixed now (see Mozilla bug 77636).
  */
 #undef CAUTIOUS_SCRIPTHOOK
 
 #ifdef DEBUG_verbose
--- a/js/src/Makefile.in
+++ b/js/src/Makefile.in
@@ -150,16 +150,17 @@ CPPSRCS		= \
 		jsutil.cpp \
 		jswatchpoint.cpp \
 		jsweakmap.cpp \
 		jswrapper.cpp \
 		jsxdrapi.cpp \
 		jsxml.cpp \
 		prmjtime.cpp \
 		sharkctl.cpp \
+		CallObject.cpp \
 		Debugger.cpp \
 		GlobalObject.cpp \
 		Stack.cpp \
 		String.cpp \
 		ParseMaps.cpp \
 		Unicode.cpp \
 		$(NULL)
 
@@ -186,17 +187,16 @@ INSTALLED_HEADERS = \
 		jsdhash.h \
 		jsemit.h \
 		jsfun.h \
 		jsfriendapi.h \
 		jsgc.h \
 		jscell.h \
 		jsgcchunk.h \
 		jsgcstats.h \
-		jscompartment.h \
 		jshash.h \
 		jsinfer.h \
 		jsinferinlines.h \
 		jsinterp.h \
 		jsinttypes.h \
 		jsiter.h \
 		jslock.h \
 		jsobj.h \
@@ -242,16 +242,17 @@ VPATH		+= \
 		$(srcdir)/vm \
 		$(srcdir)/frontend \
 		$(NULL)
 
 EXPORTS_NAMESPACES = vm
 
 EXPORTS_vm = \
 		ArgumentsObject.h \
+		CallObject.h \
 		GlobalObject.h \
 		Stack.h \
 		String.h \
 		StringObject.h \
 		Unicode.h  \
 		$(NULL)
 
 ###############################################
@@ -385,32 +386,30 @@ CPPSRCS += 	checks.cc \
 		platform.cc \
 		utils.cc \
 		$(NONE)
 
 #
 # END enclude sources for V8 dtoa
 #############################################
 
+# For architectures without YARR JIT, PCRE is faster than the YARR
+# interpreter (bug 684559).
+
 ifeq (,$(filter arm% sparc %86 x86_64,$(TARGET_CPU)))
 
-VPATH +=	$(srcdir)/assembler \
-		$(srcdir)/assembler/wtf \
-		$(srcdir)/yarr\
+VPATH +=        $(srcdir)/yarr/pcre \
 		$(NULL)
 
 CPPSRCS += \
-		Assertions.cpp \
-		OSAllocatorOS2.cpp \
-		OSAllocatorPosix.cpp \
-		OSAllocatorWin.cpp \
-		PageBlock.cpp \
-		YarrInterpreter.cpp \
-		YarrPattern.cpp \
-		YarrSyntaxChecker.cpp \
+                pcre_compile.cpp \
+                pcre_exec.cpp \
+                pcre_tables.cpp \
+                pcre_xclass.cpp \
+                pcre_ucp_searchfuncs.cpp \
 		$(NULL)
 else
 
 ###############################################
 # BEGIN include sources for the Nitro assembler
 #
 
 ENABLE_YARR_JIT = 1
--- a/js/src/configure.in
+++ b/js/src/configure.in
@@ -1224,17 +1224,17 @@ if test -n "$CROSS_COMPILE"; then
     OS_TARGET="${target_os}"
     OS_ARCH=`echo $target_os | sed -e 's|/|_|g'`
     OS_RELEASE=
     case "${target_os}" in
         linux*)       OS_ARCH=Linux OS_TARGET=Linux ;;
         kfreebsd*-gnu) OS_ARCH=GNU_kFreeBSD OS_TARGET=GNU_kFreeBSD ;;
         gnu*)         OS_ARCH=GNU ;;
         solaris*)     OS_ARCH=SunOS OS_RELEASE=5 ;;
-        mingw*)       OS_ARCH=WINNT ;;
+        mingw*)       OS_ARCH=WINNT OS_TARGET=WINNT ;;
         darwin*)      OS_ARCH=Darwin OS_TARGET=Darwin ;;
     esac
     case "${target}" in
         *-android*|*-linuxandroid*) OS_ARCH=Linux OS_TARGET=Android ;;
     esac
 else
     OS_TARGET=`uname -s`
     OS_ARCH=`uname -s | sed -e 's|/|_|g'`
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/closures/bug684178.js
@@ -0,0 +1,9 @@
+var obj = {};
+(function() {
+    if (obj) {
+        function f() { obj.x = 1; }
+        obj.m = function() { f(); };
+    }
+})();
+obj.m();
+assertEq(obj.x, 1);
--- a/js/src/jit-test/tests/sunspider/check-3d-raytrace.js
+++ b/js/src/jit-test/tests/sunspider/check-3d-raytrace.js
@@ -307,17 +307,16 @@ Camera.prototype.render = function(scene
     var row = 0;
     renderRows(cam, scene, pixels, width, height, 0, height);
 }
 
 
 
 function raytraceScene()
 {
-    var startDate = new Date().getTime();
     var numTriangles = 2 * 6;
     var triangles = new Array();//numTriangles);
     var tfl = createVector(-10,  10, -10);
     var tfr = createVector( 10,  10, -10);
     var tbl = createVector(-10,  10,  10);
     var tbr = createVector( 10,  10,  10);
     var bfl = createVector(-10, -10, -10);
     var bfr = createVector( 10, -10, -10);
--- a/js/src/jit-test/tests/sunspider/check-crypto-aes.js
+++ b/js/src/jit-test/tests/sunspider/check-crypto-aes.js
@@ -171,17 +171,18 @@ function AESEncryptCtr(plaintext, passwo
   for (var i=0; i<nBytes; i++) pwBytes[i] = password.charCodeAt(i) & 0xff;
   var key = Cipher(pwBytes, KeyExpansion(pwBytes));
   key = key.concat(key.slice(0, nBytes-16));  // key is now 16/24/32 bytes long
 
   // initialise counter block (NIST SP800-38A §B.2): millisecond time-stamp for nonce in 1st 8 bytes,
   // block counter in 2nd 8 bytes
   var blockSize = 16;  // block size fixed at 16 bytes / 128 bits (Nb=4) for AES
   var counterBlock = new Array(blockSize);  // block size fixed at 16 bytes / 128 bits (Nb=4) for AES
-  var nonce = (new Date()).getTime();  // milliseconds since 1-Jan-1970
+  var nonce = (new Date("2000-01-01")).getTime();  // milliseconds since 1-Jan-1970;
+                                                   // fixed for repeatability
 
   // encode nonce in two stages to cater for JavaScript 32-bit limit on bitwise ops
   for (var i=0; i<4; i++) counterBlock[i] = (nonce >>> i*8) & 0xff;
   for (var i=0; i<4; i++) counterBlock[i+4] = (nonce/0x100000000 >>> i*8) & 0xff; 
 
   // generate key schedule - an expansion of the key into distinct Key Rounds for each round
   var keySchedule = KeyExpansion(key);
 
--- a/js/src/jit-test/tests/sunspider/check-math-cordic.js
+++ b/js/src/jit-test/tests/sunspider/check-math-cordic.js
@@ -79,22 +79,16 @@ function cordicsincos() {
     return CurrAngle;
 }
 
 ///// End CORDIC
 
 function cordic( runs ) {
   var actual;
 
-  var start = new Date();
-
   for ( var i = 0 ; i < runs ; i++ ) {
     actual = cordicsincos();
   }
 
-  var end = new Date();
-
   assertEq(actual, 1834995.3515519998)
-
-  return end.getTime() - start.getTime();
 }
 
 cordic(25000);
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -1643,17 +1643,16 @@ static JSStdName standard_class_names[] 
 
 #if JS_HAS_XML_SUPPORT
     {js_InitXMLClass,           LAZY_ATOM(XMLList), CLASP(XML)},
     {js_InitXMLClass,           LAZY_ATOM(isXMLName), CLASP(XML)},
 #endif
 
 #if JS_HAS_GENERATORS
     {js_InitIteratorClasses,    EAGER_ATOM_AND_CLASP(Iterator)},
-    {js_InitIteratorClasses,    EAGER_ATOM_AND_CLASP(Generator)},
 #endif
 
     /* Typed Arrays */
     {js_InitTypedArrayClasses,  EAGER_CLASS_ATOM(ArrayBuffer),  &ArrayBufferClass},
     {js_InitTypedArrayClasses,  EAGER_CLASS_ATOM(Int8Array),    TYPED_ARRAY_CLASP(TYPE_INT8)},
     {js_InitTypedArrayClasses,  EAGER_CLASS_ATOM(Uint8Array),   TYPED_ARRAY_CLASP(TYPE_UINT8)},
     {js_InitTypedArrayClasses,  EAGER_CLASS_ATOM(Int16Array),   TYPED_ARRAY_CLASP(TYPE_INT16)},
     {js_InitTypedArrayClasses,  EAGER_CLASS_ATOM(Uint16Array),  TYPED_ARRAY_CLASP(TYPE_UINT16)},
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -1990,17 +1990,17 @@ struct JSClass {
     JSCheckAccessOp     checkAccess;
     JSNative            call;
     JSNative            construct;
     JSXDRObjectOp       xdrObject;
     JSHasInstanceOp     hasInstance;
     JSTraceOp           trace;
 
     JSClassInternal     reserved1;
-    void                *reserved[19];
+    void                *reserved[26];
 };
 
 #define JSCLASS_HAS_PRIVATE             (1<<0)  /* objects have private slot */
 #define JSCLASS_NEW_ENUMERATE           (1<<1)  /* has JSNewEnumerateOp hook */
 #define JSCLASS_NEW_RESOLVE             (1<<2)  /* has JSNewResolveOp hook */
 #define JSCLASS_PRIVATE_IS_NSISUPPORTS  (1<<3)  /* private is (nsISupports *) */
 #define JSCLASS_CONCURRENT_FINALIZER    (1<<4)  /* finalize is called on background thread */
 #define JSCLASS_NEW_RESOLVE_GETS_START  (1<<5)  /* JSNewResolveOp gets starting
@@ -2047,17 +2047,17 @@ struct JSClass {
  * member initial value.  The "original ... value" verbiage is there because
  * in ECMA-262, global properties naming class objects are read/write and
  * deleteable, for the most part.
  *
  * Implementing this efficiently requires that global objects have classes
  * with the following flags. Failure to use JSCLASS_GLOBAL_FLAGS was
  * prevously allowed, but is now an ES5 violation and thus unsupported.
  */
-#define JSCLASS_GLOBAL_SLOT_COUNT      (JSProto_LIMIT * 3 + 7)
+#define JSCLASS_GLOBAL_SLOT_COUNT      (JSProto_LIMIT * 3 + 8)
 #define JSCLASS_GLOBAL_FLAGS                                                  \
     (JSCLASS_IS_GLOBAL | JSCLASS_HAS_RESERVED_SLOTS(JSCLASS_GLOBAL_SLOT_COUNT))
 
 /* Fast access to the original value of each standard class's prototype. */
 #define JSCLASS_CACHED_PROTO_SHIFT      (JSCLASS_HIGH_FLAGS_SHIFT + 8)
 #define JSCLASS_CACHED_PROTO_WIDTH      8
 #define JSCLASS_CACHED_PROTO_MASK       JS_BITMASK(JSCLASS_CACHED_PROTO_WIDTH)
 #define JSCLASS_HAS_CACHED_PROTO(key)   ((key) << JSCLASS_CACHED_PROTO_SHIFT)
--- a/js/src/jsarray.cpp
+++ b/js/src/jsarray.cpp
@@ -718,16 +718,26 @@ array_lookupProperty(JSContext *cx, JSOb
     if (!proto) {
         *objp = NULL;
         *propp = NULL;
         return JS_TRUE;
     }
     return proto->lookupProperty(cx, id, objp, propp);
 }
 
+static JSBool
+array_lookupElement(JSContext *cx, JSObject *obj, uint32 index, JSObject **objp,
+                    JSProperty **propp)
+{
+    jsid id;
+    if (!IndexToId(cx, index, &id))
+        return false;
+    return array_lookupProperty(cx, obj, id, objp, propp);
+}
+
 JSBool
 js_GetDenseArrayElementValue(JSContext *cx, JSObject *obj, jsid id, Value *vp)
 {
     JS_ASSERT(obj->isDenseArray());
 
     uint32 i;
     if (!js_IdIsIndex(id, &i)) {
         JS_ASSERT(JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom));
@@ -785,16 +795,25 @@ array_getProperty(JSContext *cx, JSObjec
     /* Type information for dense array elements must be correct. */
     JS_ASSERT_IF(!obj->hasSingletonType(),
                  js::types::TypeHasProperty(cx, obj->type(), JSID_VOID, *vp));
 
     return JS_TRUE;
 }
 
 static JSBool
+array_getElement(JSContext *cx, JSObject *obj, JSObject *receiver, uint32 index, Value *vp)
+{
+    jsid id;
+    if (!IndexToId(cx, index, &id))
+        return false;
+    return array_getProperty(cx, obj, receiver, id, vp);
+}
+
+static JSBool
 slowarray_addProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp)
 {
     jsuint index, length;
 
     if (!js_IdIsIndex(id, &index))
         return JS_TRUE;
     length = obj->getArrayLength();
     if (index >= length)
@@ -839,16 +858,25 @@ array_setProperty(JSContext *cx, JSObjec
         return true;
     } while (false);
 
     if (!obj->makeDenseArraySlow(cx))
         return false;
     return js_SetPropertyHelper(cx, obj, id, 0, vp, strict);
 }
 
+static JSBool
+array_setElement(JSContext *cx, JSObject *obj, uint32 index, Value *vp, JSBool strict)
+{
+    jsid id;
+    if (!IndexToId(cx, index, &id))
+        return false;
+    return array_setProperty(cx, obj, id, vp, strict);
+}
+
 JSBool
 js_PrototypeHasIndexedProperties(JSContext *cx, JSObject *obj)
 {
     /*
      * Walk up the prototype chain and see if this indexed element already
      * exists. If we hit the end of the prototype chain, it's safe to set the
      * element on the original object.
      */
@@ -863,16 +891,17 @@ js_PrototypeHasIndexedProperties(JSConte
         if (obj->isIndexed())
             return JS_TRUE;
     }
     return JS_FALSE;
 }
 
 namespace js {
 
+/* non-static for direct definition of array elements within the engine */
 JSBool
 array_defineProperty(JSContext *cx, JSObject *obj, jsid id, const Value *value,
                      PropertyOp getter, StrictPropertyOp setter, uintN attrs)
 {
     if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom))
         return JS_TRUE;
 
     if (!obj->isDenseArray())
@@ -898,36 +927,66 @@ array_defineProperty(JSContext *cx, JSOb
         return true;
     } while (false);
 
     if (!obj->makeDenseArraySlow(cx))
         return false;
     return js_DefineProperty(cx, obj, id, value, getter, setter, attrs);
 }
 
+/* non-static for direct definition of array elements within the engine */
+JSBool
+array_defineElement(JSContext *cx, JSObject *obj, uint32 index, const Value *value,
+                    PropertyOp getter, StrictPropertyOp setter, uintN attrs)
+{
+    jsid id;
+    if (!IndexToId(cx, index, &id))
+        return false;
+    return array_defineProperty(cx, obj, id, value, getter, setter, attrs);
+}
+
 } // namespace js
 
 static JSBool
 array_getAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp)
 {
     *attrsp = JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)
         ? JSPROP_PERMANENT : JSPROP_ENUMERATE;
     return JS_TRUE;
 }
 
 static JSBool
+array_getElementAttributes(JSContext *cx, JSObject *obj, uint32 index, uintN *attrsp)
+{
+    jsid id;
+    if (!IndexToId(cx, index, &id))
+        return false;
+    return array_getAttributes(cx, obj, id, attrsp);
+}
+
+static JSBool
 array_setAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp)
 {
     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
                          JSMSG_CANT_SET_ARRAY_ATTRS);
     return JS_FALSE;
 }
 
+static JSBool
+array_setElementAttributes(JSContext *cx, JSObject *obj, uint32 index, uintN *attrsp)
+{
+    jsid id;
+    if (!IndexToId(cx, index, &id))
+        return false;
+    return array_setAttributes(cx, obj, id, attrsp);
+}
+
 namespace js {
 
+/* non-static for direct deletion of array elements within the engine */
 JSBool
 array_deleteProperty(JSContext *cx, JSObject *obj, jsid id, Value *rval, JSBool strict)
 {
     uint32 i;
 
     if (!obj->isDenseArray())
         return js_DeleteProperty(cx, obj, id, rval, strict);
 
@@ -943,16 +1002,26 @@ array_deleteProperty(JSContext *cx, JSOb
 
     if (!js_SuppressDeletedProperty(cx, obj, id))
         return false;
 
     rval->setBoolean(true);
     return JS_TRUE;
 }
 
+/* non-static for direct deletion of array elements within the engine */
+JSBool
+array_deleteElement(JSContext *cx, JSObject *obj, uint32 index, Value *rval, JSBool strict)
+{
+    jsid id;
+    if (!IndexToId(cx, index, &id))
+        return false;
+    return array_deleteProperty(cx, obj, id, rval, strict);
+}
+
 } // namespace js
 
 static void
 array_trace(JSTracer *trc, JSObject *obj)
 {
     JS_ASSERT(obj->isDenseArray());
 
     uint32 initLength = obj->getDenseArrayInitializedLength();
@@ -992,22 +1061,29 @@ Class js::ArrayClass = {
     NULL,           /* call        */
     NULL,           /* construct   */
     NULL,           /* xdrObject   */
     NULL,           /* hasInstance */
     array_trace,    /* trace       */
     JS_NULL_CLASS_EXT,
     {
         array_lookupProperty,
+        array_lookupElement,
         array_defineProperty,
+        array_defineElement,
         array_getProperty,
+        array_getElement,
         array_setProperty,
+        array_setElement,
         array_getAttributes,
+        array_getElementAttributes,
         array_setAttributes,
+        array_setElementAttributes,
         array_deleteProperty,
+        array_deleteElement,
         NULL,       /* enumerate      */
         array_typeOf,
         array_fix,
         NULL,       /* thisObject     */
         NULL,       /* clear          */
     }
 };
 
--- a/js/src/jscntxt.cpp
+++ b/js/src/jscntxt.cpp
@@ -644,17 +644,17 @@ ReportError(JSContext *cx, const char *m
         reportp->errorNumber == JSMSG_UNCAUGHT_EXCEPTION)
         reportp->flags |= JSREPORT_EXCEPTION;
 
     /*
      * Call the error reporter only if an exception wasn't raised.
      *
      * If an exception was raised, then we call the debugErrorHook
      * (if present) to give it a chance to see the error before it
-     * propagates out of scope.  This is needed for compatability
+     * propagates out of scope.  This is needed for compatibility
      * with the old scheme.
      */
     if (!JS_IsRunning(cx) ||
         !js_ErrorToException(cx, message, reportp, callback, userRef)) {
         js_ReportErrorAgain(cx, message, reportp);
     } else if (cx->debugHooks->debugErrorHook && cx->errorReporter) {
         JSDebugErrorHook hook = cx->debugHooks->debugErrorHook;
         /* test local in case debugErrorHook changed on another thread */
--- a/js/src/jscntxt.h
+++ b/js/src/jscntxt.h
@@ -1087,17 +1087,17 @@ struct JSContext
             clearVersionOverride();
         }
     }
 
     /*
      * Return:
      * - The override version, if there is an override version.
      * - The newest scripted frame's version, if there is such a frame.
-     * - The default verion.
+     * - The default version.
      *
      * Note: if this ever shows up in a profile, just add caching!
      */
     JSVersion findVersion() const {
         if (hasVersionOverride)
             return versionOverride;
 
         if (stack.hasfp()) {
--- a/js/src/jscompartment.cpp
+++ b/js/src/jscompartment.cpp
@@ -591,22 +591,24 @@ JSCompartment::sweep(JSContext *cx, uint
 #endif
 
     if (activeAnalysis) {
         /*
          * Analysis information is in use, so don't clear the analysis pool.
          * jitcode still needs to be released, if this is a shape-regenerating
          * GC then shape numbers baked into the code may change.
          */
+#ifdef JS_METHODJIT
         if (types.inferenceEnabled) {
             for (CellIterUnderGC i(this, FINALIZE_SCRIPT); !i.done(); i.next()) {
                 JSScript *script = i.get<JSScript>();
                 mjit::ReleaseScriptCode(cx, script);
             }
         }
+#endif
     } else {
         /*
          * Clear the analysis pool, but don't release its data yet. While
          * sweeping types any live data will be allocated into the pool.
          */
         JSArenaPool oldPool;
         MoveArenaPool(&pool, &oldPool);
 
--- a/js/src/jscompartment.h
+++ b/js/src/jscompartment.h
@@ -280,19 +280,19 @@ struct TraceMonitor {
     void sweep(JSContext *cx);
 
     /* Mark any tracer stacks that are active. */
     void mark(JSTracer *trc);
 
     bool outOfMemory() const;
 
     JS_FRIEND_API(void) getCodeAllocStats(size_t &total, size_t &frag_size, size_t &free_size) const;
-    JS_FRIEND_API(size_t) getVMAllocatorsMainSize() const;
-    JS_FRIEND_API(size_t) getVMAllocatorsReserveSize() const;
-    JS_FRIEND_API(size_t) getTraceMonitorSize() const;
+    JS_FRIEND_API(size_t) getVMAllocatorsMainSize(JSUsableSizeFun usf) const;
+    JS_FRIEND_API(size_t) getVMAllocatorsReserveSize(JSUsableSizeFun usf) const;
+    JS_FRIEND_API(size_t) getTraceMonitorSize(JSUsableSizeFun usf) const;
 };
 
 namespace mjit {
 class JaegerCompartment;
 }
 }
 
 /* Defined in jsapi.cpp */
--- a/js/src/jsemit.h
+++ b/js/src/jsemit.h
@@ -257,17 +257,17 @@ struct JSStmtInfo {
  */
 #define TCF_HAS_SINGLETONS       0x8000000
 
 /*
  * Some enclosing scope is a with-statement or E4X filter-expression.
  */
 #define TCF_IN_WITH             0x10000000
 
-/* 
+/*
  * This function does something that can extend the set of bindings in its
  * call objects --- it does a direct eval in non-strict code, or includes a
  * function statement (as opposed to a function definition).
  *
  * This flag is *not* inherited by enclosed or enclosing functions; it
  * applies only to the function in whose flags it appears.
  */
 #define TCF_FUN_EXTENSIBLE_SCOPE 0x20000000
@@ -421,17 +421,17 @@ struct JSTreeContext {              /* t
     bool inStatement(JSStmtType type);
 
     bool inStrictMode() const {
         return flags & TCF_STRICT_MODE_CODE;
     }
 
     inline bool needStrictChecks();
 
-    /* 
+    /*
      * sharpSlotBase is -1 or first slot of pair for [sharpArray, sharpDepth].
      * The parser calls ensureSharpSlots to allocate these two stack locals.
      */
     int sharpSlotBase;
     bool ensureSharpSlots();
 
     js::Compiler *compiler() { return (js::Compiler *)parser; }
 
@@ -673,17 +673,17 @@ struct JSCodeGenerator : public JSTreeCo
      * the arena pool "tops-of-stack" space above their codeMark, noteMark, and
      * tempMark points.  This means you cannot alloc from tempPool and save the
      * pointer beyond the next JSCodeGenerator destructor call.
      */
     ~JSCodeGenerator();
 
     /*
      * Adds a use of a variable that is statically known to exist on the
-     * global object. 
+     * global object.
      *
      * The actual slot of the variable on the global object is not known
      * until after compilation. Properties must be resolved before being
      * added, to avoid aliasing properties that should be resolved. This makes
      * slot prediction based on the global object's free slot impossible. So,
      * we use the slot to index into cg->globalScope->defs, and perform a
      * fixup of the script at the very end of compilation.
      *
--- a/js/src/jsfriendapi.cpp
+++ b/js/src/jsfriendapi.cpp
@@ -39,16 +39,17 @@
 
 #include "jscntxt.h"
 #include "jscompartment.h"
 #include "jsfriendapi.h"
 
 #include "jsobjinlines.h"
 
 using namespace js;
+using namespace JS;
 
 JS_FRIEND_API(JSString *)
 JS_GetAnonymousString(JSRuntime *rt)
 {
     JS_ASSERT(rt->state == JSRTS_UP);
     return rt->atomState.anonymousAtom;
 }
 
@@ -107,16 +108,63 @@ JS_NewObjectWithUniqueType(JSContext *cx
 JS_FRIEND_API(uint32)
 JS_ObjectCountDynamicSlots(JSObject *obj)
 {
     if (obj->hasSlotsArray())
         return obj->numDynamicSlots(obj->numSlots());
     return 0;
 }
 
+JS_FRIEND_API(JSPrincipals *)
+JS_GetCompartmentPrincipals(JSCompartment *compartment)
+{
+    return compartment->principals;
+}
+
+JS_FRIEND_API(JSBool)
+JS_WrapPropertyDescriptor(JSContext *cx, js::PropertyDescriptor *desc)
+{
+    return cx->compartment->wrap(cx, desc);
+}
+
+AutoPreserveCompartment::AutoPreserveCompartment(JSContext *cx
+                                                 JS_GUARD_OBJECT_NOTIFIER_PARAM_NO_INIT)
+  : cx(cx), oldCompartment(cx->compartment)
+{
+    JS_GUARD_OBJECT_NOTIFIER_INIT;
+}
+
+AutoPreserveCompartment::~AutoPreserveCompartment()
+{
+    /* The old compartment may have been destroyed, so we can't use cx->setCompartment. */
+    cx->compartment = oldCompartment;
+}
+
+AutoSwitchCompartment::AutoSwitchCompartment(JSContext *cx, JSCompartment *newCompartment
+                                             JS_GUARD_OBJECT_NOTIFIER_PARAM_NO_INIT)
+  : cx(cx), oldCompartment(cx->compartment)
+{
+    JS_GUARD_OBJECT_NOTIFIER_INIT;
+    cx->setCompartment(newCompartment);
+}
+
+AutoSwitchCompartment::AutoSwitchCompartment(JSContext *cx, JSObject *target
+                                             JS_GUARD_OBJECT_NOTIFIER_PARAM_NO_INIT)
+  : cx(cx), oldCompartment(cx->compartment)
+{
+    JS_GUARD_OBJECT_NOTIFIER_INIT;
+    cx->setCompartment(target->compartment());
+}
+
+AutoSwitchCompartment::~AutoSwitchCompartment()
+{
+    /* The old compartment may have been destroyed, so we can't use cx->setCompartment. */
+    cx->compartment = oldCompartment;
+}
+
 /*
  * 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)
--- a/js/src/jsfriendapi.h
+++ b/js/src/jsfriendapi.h
@@ -88,11 +88,50 @@ typedef struct TypeInferenceMemoryStats
 extern JS_FRIEND_API(void)
 JS_GetTypeInferenceMemoryStats(JSContext *cx, JSCompartment *compartment,
                                TypeInferenceMemoryStats *stats);
 
 extern JS_FRIEND_API(void)
 JS_GetTypeInferenceObjectStats(/*TypeObject*/ void *object,
                                TypeInferenceMemoryStats *stats);
 
+extern JS_FRIEND_API(JSPrincipals *)
+JS_GetCompartmentPrincipals(JSCompartment *compartment);
+
+#ifdef __cplusplus
+
+extern JS_FRIEND_API(JSBool)
+JS_WrapPropertyDescriptor(JSContext *cx, js::PropertyDescriptor *desc);
+
+#endif
+
 JS_END_EXTERN_C
 
+#ifdef __cplusplus
+
+namespace JS {
+
+class JS_FRIEND_API(AutoPreserveCompartment) {
+  private:
+    JSContext *cx;
+    JSCompartment *oldCompartment;
+  public:
+    AutoPreserveCompartment(JSContext *cx JS_GUARD_OBJECT_NOTIFIER_PARAM);
+    ~AutoPreserveCompartment();
+    JS_DECL_USE_GUARD_OBJECT_NOTIFIER
+};
+
+class JS_FRIEND_API(AutoSwitchCompartment) {
+  private:
+    JSContext *cx;
+    JSCompartment *oldCompartment;
+  public:
+    AutoSwitchCompartment(JSContext *cx, JSCompartment *newCompartment
+                          JS_GUARD_OBJECT_NOTIFIER_PARAM);
+    AutoSwitchCompartment(JSContext *cx, JSObject *target JS_GUARD_OBJECT_NOTIFIER_PARAM);
+    ~AutoSwitchCompartment();
+    JS_DECL_USE_GUARD_OBJECT_NOTIFIER
+};
+
+}
+#endif
+
 #endif /* jsfriendapi_h___ */
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -67,16 +67,17 @@
 #include "jsproxy.h"
 #include "jsscan.h"
 #include "jsscope.h"
 #include "jsscript.h"
 #include "jsstr.h"
 #include "jsexn.h"
 #include "jsstaticcheck.h"
 #include "jstracer.h"
+#include "vm/CallObject.h"
 #include "vm/Debugger.h"
 
 #if JS_HAS_GENERATORS
 # include "jsiter.h"
 #endif
 
 #if JS_HAS_XDR
 # include "jsxdrapi.h"
@@ -86,17 +87,17 @@
 #include "methodjit/MethodJIT.h"
 #endif
 
 #include "jsatominlines.h"
 #include "jsfuninlines.h"
 #include "jsinferinlines.h"
 #include "jsobjinlines.h"
 #include "jsscriptinlines.h"
-
+#include "vm/CallObject-inl.h"
 #include "vm/ArgumentsObject-inl.h"
 #include "vm/Stack-inl.h"
 
 using namespace js;
 using namespace js::gc;
 using namespace js::types;
 
 inline JSObject *
@@ -278,32 +279,32 @@ js_GetArgsObject(JSContext *cx, StackFra
      * ensures this by synthesizing an arguments access at the start of any
      * strict mode function that contains an assignment to a parameter, or
      * that calls eval.)  Non-strict mode arguments use the frame pointer to
      * retrieve up-to-date parameter values.
      */
     if (argsobj->isStrictArguments())
         fp->forEachCanonicalActualArg(PutArg(argsobj->data()->slots));
     else
-        argsobj->setPrivate(fp);
+        argsobj->setStackFrame(fp);
 
     fp->setArgsObj(*argsobj);
     return argsobj;
 }
 
 void
 js_PutArgsObject(StackFrame *fp)
 {
     ArgumentsObject &argsobj = fp->argsObj();
     if (argsobj.isNormalArguments()) {
-        JS_ASSERT(argsobj.getPrivate() == fp);
+        JS_ASSERT(argsobj.maybeStackFrame() == fp);
         fp->forEachCanonicalActualArg(PutArg(argsobj.data()->slots));
-        argsobj.setPrivate(NULL);
+        argsobj.setStackFrame(NULL);
     } else {
-        JS_ASSERT(!argsobj.getPrivate());
+        JS_ASSERT(!argsobj.maybeStackFrame());
     }
 }
 
 #ifdef JS_TRACER
 
 /*
  * Traced versions of js_GetArgsObject and js_PutArgsObject.
  */
@@ -314,47 +315,47 @@ js_NewArgumentsOnTrace(JSContext *cx, ui
     if (!argsobj)
         return NULL;
 
     if (argsobj->isStrictArguments()) {
         /*
          * Strict mode callers must copy arguments into the created arguments
          * object. The trace-JITting code is in TraceRecorder::newArguments.
          */
-        JS_ASSERT(!argsobj->getPrivate());
+        JS_ASSERT(!argsobj->maybeStackFrame());
     } else {
-        argsobj->setPrivate(JS_ARGUMENTS_OBJECT_ON_TRACE);
+        argsobj->setOnTrace();
     }
 
     return argsobj;
 }
 JS_DEFINE_CALLINFO_3(extern, OBJECT, js_NewArgumentsOnTrace, CONTEXT, UINT32, OBJECT,
                      0, nanojit::ACCSET_STORE_ANY)
 
 /* FIXME change the return type to void. */
 JSBool JS_FASTCALL
 js_PutArgumentsOnTrace(JSContext *cx, JSObject *obj, Value *argv)
 {
     NormalArgumentsObject *argsobj = obj->asNormalArguments();
 
-    JS_ASSERT(argsobj->getPrivate() == JS_ARGUMENTS_OBJECT_ON_TRACE);
+    JS_ASSERT(argsobj->onTrace());
 
     /*
      * TraceRecorder::putActivationObjects builds a single, contiguous array of
      * the arguments, regardless of whether #actuals > #formals so there is no
      * need to worry about actual vs. formal arguments.
      */
     Value *srcend = argv + argsobj->initialLength();
     Value *dst = argsobj->data()->slots;
     for (Value *src = argv; src < srcend; ++src, ++dst) {
         if (!dst->isMagic(JS_ARGS_HOLE))
             *dst = *src;
     }
 
-    argsobj->setPrivate(NULL);
+    argsobj->clearOnTrace();
     return true;
 }
 JS_DEFINE_CALLINFO_3(extern, BOOL, js_PutArgumentsOnTrace, CONTEXT, OBJECT, VALUEPTR, 0,
                      nanojit::ACCSET_STORE_ANY)
 
 #endif /* JS_TRACER */
 
 static JSBool
@@ -385,17 +386,17 @@ ArgGetter(JSContext *cx, JSObject *obj, 
     if (JSID_IS_INT(id)) {
         /*
          * arg can exceed the number of arguments if a script changed the
          * prototype to point to another Arguments object with a bigger argc.
          */
         uintN arg = uintN(JSID_TO_INT(id));
         if (arg < argsobj->initialLength()) {
             JS_ASSERT(!argsobj->element(arg).isMagic(JS_ARGS_HOLE));
-            if (StackFrame *fp = reinterpret_cast<StackFrame *>(argsobj->getPrivate()))
+            if (StackFrame *fp = argsobj->maybeStackFrame())
                 *vp = fp->canonicalActualArg(arg);
             else
                 *vp = argsobj->element(arg);
         }
     } else if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)) {
         if (!argsobj->hasOverriddenLength())
             vp->setInt32(argsobj->initialLength());
     } else {
@@ -422,17 +423,17 @@ ArgSetter(JSContext *cx, JSObject *obj, 
     if (!obj->isNormalArguments())
         return true;
 
     NormalArgumentsObject *argsobj = obj->asNormalArguments();
 
     if (JSID_IS_INT(id)) {
         uintN arg = uintN(JSID_TO_INT(id));
         if (arg < argsobj->initialLength()) {
-            if (StackFrame *fp = reinterpret_cast<StackFrame *>(argsobj->getPrivate())) {
+            if (StackFrame *fp = argsobj->maybeStackFrame()) {
                 JSScript *script = fp->functionScript();
                 if (script->usesArguments) {
                     if (arg < fp->numFormalArgs())
                         TypeScript::SetArgument(cx, script, arg, *vp);
                     fp->canonicalActualArg(arg) = *vp;
                 }
                 return true;
             }
@@ -668,17 +669,17 @@ MaybeMarkGenerator(JSTracer *trc, JSObje
     }
 #endif
 }
 
 static void
 args_trace(JSTracer *trc, JSObject *obj)
 {
     ArgumentsObject *argsobj = obj->asArguments();
-    if (argsobj->getPrivate() == JS_ARGUMENTS_OBJECT_ON_TRACE) {
+    if (argsobj->onTrace()) {
         JS_ASSERT(!argsobj->isStrictArguments());
         return;
     }
 
     ArgumentsData *data = argsobj->data();
     if (data->callee.isObject())
         MarkObject(trc, data->callee.toObject(), js_callee_str);
     MarkValueRange(trc, argsobj->initialLength(), data->slots, js_arguments_str);
@@ -752,67 +753,16 @@ Class js::DeclEnvClass = {
     PropertyStub,         /* delProperty */
     PropertyStub,         /* getProperty */
     StrictPropertyStub,   /* setProperty */
     EnumerateStub,
     ResolveStub,
     ConvertStub
 };
 
-/*
- * Construct a call object for the given bindings.  If this is a call object
- * for a function invocation, callee should be the function being called.
- * Otherwise it must be a call object for eval of strict mode code, and callee
- * must be null.
- */
-static JSObject *
-NewCallObject(JSContext *cx, JSScript *script, JSObject &scopeChain, JSObject *callee)
-{
-    Bindings &bindings = script->bindings;
-    size_t argsVars = bindings.countArgsAndVars();
-    size_t slots = JSObject::CALL_RESERVED_SLOTS + argsVars;
-    gc::AllocKind kind = gc::GetGCObjectKind(slots);
-
-    /*
-     * Make sure that the arguments and variables in the call object all end up
-     * in a contiguous range of slots. We need this to be able to embed the
-     * args/vars arrays in the TypeScriptNesting for the function, after the
-     * call object's frame has finished.
-     */
-    if (cx->typeInferenceEnabled() && gc::GetGCKindSlots(kind) < slots) {
-        kind = gc::GetGCObjectKind(JSObject::CALL_RESERVED_SLOTS);
-        JS_ASSERT(gc::GetGCKindSlots(kind) == JSObject::CALL_RESERVED_SLOTS);
-    }
-
-    JSObject *callobj = js_NewGCObject(cx, kind);
-    if (!callobj)
-        return NULL;
-
-    /* Init immediately to avoid GC seeing a half-init'ed object. */
-    callobj->initCall(cx, bindings, &scopeChain);
-    callobj->makeVarObj();
-
-    /* This must come after callobj->lastProp has been set. */
-    if (!callobj->ensureInstanceReservedSlots(cx, argsVars))
-        return NULL;
-
-#ifdef DEBUG
-    for (Shape::Range r = callobj->lastProp; !r.empty(); r.popFront()) {
-        const Shape &s = r.front();
-        if (s.slot != SHAPE_INVALID_SLOT) {
-            JS_ASSERT(s.slot + 1 == callobj->slotSpan());
-            break;
-        }
-    }
-#endif
-
-    callobj->setCallObjCallee(callee);
-    return callobj;
-}
-
 static inline JSObject *
 NewDeclEnvObject(JSContext *cx, StackFrame *fp)
 {
     JSObject *envobj = js_NewGCObject(cx, FINALIZE_OBJECT2);
     if (!envobj)
         return NULL;
 
     EmptyShape *emptyDeclEnvShape = EmptyShape::getEmptyDeclEnvShape(cx);
@@ -821,17 +771,17 @@ NewDeclEnvObject(JSContext *cx, StackFra
     envobj->init(cx, &DeclEnvClass, &emptyTypeObject, &fp->scopeChain(), fp, false);
     envobj->setMap(emptyDeclEnvShape);
 
     return envobj;
 }
 
 namespace js {
 
-JSObject *
+CallObject *
 CreateFunCallObject(JSContext *cx, StackFrame *fp)
 {
     JS_ASSERT(fp->isNonEvalFunctionFrame());
     JS_ASSERT(!fp->hasCallObj());
 
     JSObject *scopeChain = &fp->scopeChain();
     JS_ASSERT_IF(scopeChain->isWith() || scopeChain->isBlock() || scopeChain->isCall(),
                  scopeChain->getPrivate() != fp);
@@ -847,260 +797,261 @@ CreateFunCallObject(JSContext *cx, Stack
 
         if (!DefineNativeProperty(cx, scopeChain, ATOM_TO_JSID(lambdaName),
                                   ObjectValue(fp->callee()), NULL, NULL,
                                   JSPROP_PERMANENT | JSPROP_READONLY, 0, 0)) {
             return NULL;
         }
     }
 
-    JSObject *callobj = NewCallObject(cx, fp->script(), *scopeChain, &fp->callee());
+    CallObject *callobj = CallObject::create(cx, fp->script(), *scopeChain, &fp->callee());
     if (!callobj)
         return NULL;
 
-    callobj->setPrivate(fp);
+    callobj->setStackFrame(fp);
     fp->setScopeChainWithOwnCallObj(*callobj);
     return callobj;
 }
 
-JSObject *
+CallObject *
 CreateEvalCallObject(JSContext *cx, StackFrame *fp)
 {
-    JSObject *callobj = NewCallObject(cx, fp->script(), fp->scopeChain(), NULL);
+    CallObject *callobj = CallObject::create(cx, fp->script(), fp->scopeChain(), NULL);
     if (!callobj)
         return NULL;
 
-    callobj->setPrivate(fp);
+    callobj->setStackFrame(fp);
     fp->setScopeChainWithOwnCallObj(*callobj);
     return callobj;
 }
 
 } // namespace js
 
 JSObject * JS_FASTCALL
 js_CreateCallObjectOnTrace(JSContext *cx, JSFunction *fun, JSObject *callee, JSObject *scopeChain)
 {
     JS_ASSERT(!js_IsNamedLambda(fun));
     JS_ASSERT(scopeChain);
     JS_ASSERT(callee);
-    return NewCallObject(cx, fun->script(), *scopeChain, callee);
+    return CallObject::create(cx, fun->script(), *scopeChain, callee);
 }
 
 JS_DEFINE_CALLINFO_4(extern, OBJECT, js_CreateCallObjectOnTrace, CONTEXT, FUNCTION, OBJECT, OBJECT,
                      0, nanojit::ACCSET_STORE_ANY)
 
-inline static void
-CopyValuesToCallObject(JSObject &callobj, uintN nargs, Value *argv, uintN nvars, Value *slots)
-{
-    JS_ASSERT(callobj.numSlots() >= JSObject::CALL_RESERVED_SLOTS + nargs + nvars);
-    callobj.copySlotRange(JSObject::CALL_RESERVED_SLOTS, argv, nargs);
-    callobj.copySlotRange(JSObject::CALL_RESERVED_SLOTS + nargs, slots, nvars);
-}
-
 void
 js_PutCallObject(StackFrame *fp)
 {
-    JSObject &callobj = fp->callObj();
-    JS_ASSERT(callobj.getPrivate() == fp);
+    CallObject &callobj = fp->callObj().asCall();
+    JS_ASSERT(callobj.maybeStackFrame() == fp);
     JS_ASSERT_IF(fp->isEvalFrame(), fp->isStrictEvalFrame());
-    JS_ASSERT(fp->isEvalFrame() == callobj.callIsForEval());
+    JS_ASSERT(fp->isEvalFrame() == callobj.isForEval());
 
     /* Get the arguments object to snapshot fp's actual argument values. */
     if (fp->hasArgsObj()) {
         if (!fp->hasOverriddenArgs())
-            callobj.setCallObjArguments(ObjectValue(fp->argsObj()));
+            callobj.setArguments(ObjectValue(fp->argsObj()));
         js_PutArgsObject(fp);
     }
 
     JSScript *script = fp->script();
     Bindings &bindings = script->bindings;
 
-    if (callobj.callIsForEval()) {
+    if (callobj.isForEval()) {
         JS_ASSERT(script->strictModeCode);
         JS_ASSERT(bindings.countArgs() == 0);
 
         /* This could be optimized as below, but keep it simple for now. */
-        CopyValuesToCallObject(callobj, 0, NULL, bindings.countVars(), fp->slots());
+        callobj.copyValues(0, NULL, bindings.countVars(), fp->slots());
     } else {
         JSFunction *fun = fp->fun();
-        JS_ASSERT(fun == callobj.getCallObjCalleeFunction());
+        JS_ASSERT(fun == callobj.getCalleeFunction());
         JS_ASSERT(script == fun->script());
 
         uintN n = bindings.countArgsAndVars();
         if (n > 0) {
-            JS_ASSERT(JSObject::CALL_RESERVED_SLOTS + n <= callobj.numSlots());
+            JS_ASSERT(CallObject::RESERVED_SLOTS + n <= callobj.numSlots());
 
             uint32 nvars = bindings.countVars();
             uint32 nargs = bindings.countArgs();
             JS_ASSERT(fun->nargs == nargs);
             JS_ASSERT(nvars + nargs == n);
 
             JSScript *script = fun->script();
             if (script->usesEval
 #ifdef JS_METHODJIT
                 || script->debugMode
 #endif
                 ) {
-                CopyValuesToCallObject(callobj, nargs, fp->formalArgs(), nvars, fp->slots());
+                callobj.copyValues(nargs, fp->formalArgs(), nvars, fp->slots());
             } else {
                 /*
                  * For each arg & var that is closed over, copy it from the stack
                  * into the call object.
                  */
                 uint32 nclosed = script->nClosedArgs;
                 for (uint32 i = 0; i < nclosed; i++) {
                     uint32 e = script->getClosedArg(i);
-                    callobj.setSlot(JSObject::CALL_RESERVED_SLOTS + e, fp->formalArg(e));
+                    callobj.setArg(e, fp->formalArg(e));
                 }
 
                 nclosed = script->nClosedVars;
                 for (uint32 i = 0; i < nclosed; i++) {
                     uint32 e = script->getClosedVar(i);
-                    callobj.setSlot(JSObject::CALL_RESERVED_SLOTS + nargs + e, fp->slots()[e]);
+                    callobj.setVar(e, fp->slots()[e]);
                 }
             }
 
             /*
              * Update the args and vars for the active call if this is an outer
              * function in a script nesting.
              */
             types::TypeScriptNesting *nesting = script->nesting();
             if (nesting && script->isOuterFunction) {
-                nesting->argArray = callobj.callObjArgArray();
-                nesting->varArray = callobj.callObjVarArray();
+                nesting->argArray = callobj.argArray();
+                nesting->varArray = callobj.varArray();
             }
         }
 
         /* Clear private pointers to fp, which is about to go away. */
         if (js_IsNamedLambda(fun)) {
             JSObject *env = callobj.getParent();
 
             JS_ASSERT(env->isDeclEnv());
             JS_ASSERT(env->getPrivate() == fp);
             env->setPrivate(NULL);
         }
     }
 
-    callobj.setPrivate(NULL);
+    callobj.setStackFrame(NULL);
 }
 
 JSBool JS_FASTCALL
-js_PutCallObjectOnTrace(JSObject *callobj, uint32 nargs, Value *argv,
+js_PutCallObjectOnTrace(JSObject *obj, uint32 nargs, Value *argv,
                         uint32 nvars, Value *slots)
 {
-    JS_ASSERT(callobj->isCall());
-    JS_ASSERT(!callobj->getPrivate());
+    CallObject &callobj = obj->asCall();
+    JS_ASSERT(!callobj.maybeStackFrame());
 
     uintN n = nargs + nvars;
     if (n != 0)
-        CopyValuesToCallObject(*callobj, nargs, argv, nvars, slots);
+        callobj.copyValues(nargs, argv, nvars, slots);
 
     return true;
 }
 
 JS_DEFINE_CALLINFO_5(extern, BOOL, js_PutCallObjectOnTrace, OBJECT, UINT32, VALUEPTR,
                      UINT32, VALUEPTR, 0, nanojit::ACCSET_STORE_ANY)
 
 namespace js {
 
 static JSBool
 GetCallArguments(JSContext *cx, JSObject *obj, jsid id, Value *vp)
 {
-    StackFrame *fp = obj->maybeCallObjStackFrame();
+    CallObject &callobj = obj->asCall();
+
+    StackFrame *fp = callobj.maybeStackFrame();
     if (fp && !fp->hasOverriddenArgs()) {
         JSObject *argsobj = js_GetArgsObject(cx, fp);
         if (!argsobj)
             return false;
         vp->setObject(*argsobj);
     } else {
-        *vp = obj->getCallObjArguments();
+        *vp = callobj.getArguments();
     }
     return true;
 }
 
 static JSBool
 SetCallArguments(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value *vp)
 {
-    if (StackFrame *fp = obj->maybeCallObjStackFrame())
+    CallObject &callobj = obj->asCall();
+
+    if (StackFrame *fp = callobj.maybeStackFrame())
         fp->setOverriddenArgs();
-    obj->setCallObjArguments(*vp);
+    callobj.setArguments(*vp);
     return true;
 }
 
 JSBool
 GetCallArg(JSContext *cx, JSObject *obj, jsid id, Value *vp)
 {
+    CallObject &callobj = obj->asCall();
     JS_ASSERT((int16) JSID_TO_INT(id) == JSID_TO_INT(id));
     uintN i = (uint16) JSID_TO_INT(id);
 
-    if (StackFrame *fp = obj->maybeCallObjStackFrame())
+    if (StackFrame *fp = callobj.maybeStackFrame())
         *vp = fp->formalArg(i);
     else
-        *vp = obj->callObjArg(i);
+        *vp = callobj.arg(i);
     return true;
 }
 
 JSBool
 SetCallArg(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value *vp)
 {
+    CallObject &callobj = obj->asCall();
     JS_ASSERT((int16) JSID_TO_INT(id) == JSID_TO_INT(id));
     uintN i = (uint16) JSID_TO_INT(id);
 
-    if (StackFrame *fp = obj->maybeCallObjStackFrame())
+    if (StackFrame *fp = callobj.maybeStackFrame())
         fp->formalArg(i) = *vp;
     else
-        obj->setCallObjArg(i, *vp);
-
-    JSFunction *fun = obj->getCallObjCalleeFunction();
+        callobj.setArg(i, *vp);
+
+    JSFunction *fun = callobj.getCalleeFunction();
     JSScript *script = fun->script();
     if (!script->ensureHasTypes(cx, fun))
         return false;
 
     TypeScript::SetArgument(cx, script, i, *vp);
 
     return true;
 }
 
 JSBool
 GetCallUpvar(JSContext *cx, JSObject *obj, jsid id, Value *vp)
 {
+    CallObject &callobj = obj->asCall();
     JS_ASSERT((int16) JSID_TO_INT(id) == JSID_TO_INT(id));
     uintN i = (uint16) JSID_TO_INT(id);
 
-    *vp = obj->getCallObjCallee()->getFlatClosureUpvar(i);
+    *vp = callobj.getCallee()->getFlatClosureUpvar(i);
     return true;
 }
 
 JSBool
 SetCallUpvar(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value *vp)
 {
+    CallObject &callobj = obj->asCall();
     JS_ASSERT((int16) JSID_TO_INT(id) == JSID_TO_INT(id));
     uintN i = (uint16) JSID_TO_INT(id);
 
-    obj->getCallObjCallee()->setFlatClosureUpvar(i, *vp);
+    callobj.getCallee()->setFlatClosureUpvar(i, *vp);
     return true;
 }
 
 JSBool
 GetCallVar(JSContext *cx, JSObject *obj, jsid id, Value *vp)
 {
+    CallObject &callobj = obj->asCall();
     JS_ASSERT((int16) JSID_TO_INT(id) == JSID_TO_INT(id));
     uintN i = (uint16) JSID_TO_INT(id);
 
-    if (StackFrame *fp = obj->maybeCallObjStackFrame())
+    if (StackFrame *fp = callobj.maybeStackFrame())
         *vp = fp->varSlot(i);
     else
-        *vp = obj->callObjVar(i);
+        *vp = callobj.var(i);
     return true;
 }
 
 JSBool
 SetCallVar(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value *vp)
 {
-    JS_ASSERT(obj->isCall());
+    CallObject &callobj = obj->asCall();
 
     JS_ASSERT((int16) JSID_TO_INT(id) == JSID_TO_INT(id));
     uintN i = (uint16) JSID_TO_INT(id);
 
     /*
      * As documented in TraceRecorder::attemptTreeCall(), when recording an
      * inner tree call, the recorder assumes the inner tree does not mutate
      * any tracked upvars. The abort here is a pessimistic precaution against
@@ -1110,22 +1061,22 @@ SetCallVar(JSContext *cx, JSObject *obj,
 #ifdef JS_TRACER
     if (JS_ON_TRACE(cx)) {
         TraceMonitor *tm = JS_TRACE_MONITOR_ON_TRACE(cx);
         if (tm->recorder && tm->tracecx)
             AbortRecording(cx, "upvar write in nested tree");
     }
 #endif
 
-    if (StackFrame *fp = obj->maybeCallObjStackFrame())
+    if (StackFrame *fp = callobj.maybeStackFrame())
         fp->varSlot(i) = *vp;
     else
-        obj->setCallObjVar(i, *vp);
-
-    JSFunction *fun = obj->getCallObjCalleeFunction();
+        callobj.setVar(i, *vp);
+
+    JSFunction *fun = callobj.getCalleeFunction();
     JSScript *script = fun->script();
     if (!script->ensureHasTypes(cx, fun))
         return false;
 
     TypeScript::SetLocal(cx, script, i, *vp);
 
     return true;
 }
@@ -1148,26 +1099,24 @@ js_SetCallVar(JSContext *cx, JSObject *o
     Value argcopy = ValueArgToConstRef(arg);
     return SetCallVar(cx, obj, slotid, false /* STRICT DUMMY */, &argcopy);
 }
 JS_DEFINE_CALLINFO_4(extern, BOOL, js_SetCallVar, CONTEXT, OBJECT, JSID, VALUE, 0,
                      nanojit::ACCSET_STORE_ANY)
 #endif
 
 static JSBool
-call_resolve(JSContext *cx, JSObject *obj, jsid id, uintN flags,
-             JSObject **objp)
+call_resolve(JSContext *cx, JSObject *obj, jsid id, uintN flags, JSObject **objp)
 {
-    JS_ASSERT(obj->isCall());
     JS_ASSERT(!obj->getProto());
 
     if (!JSID_IS_ATOM(id))
         return true;
 
-    JSObject *callee = obj->getCallObjCallee();
+    JSObject *callee = obj->asCall().getCallee();
 #ifdef DEBUG
     if (callee) {
         JSScript *script = callee->getFunctionPrivate()->script();
         JS_ASSERT(!script->bindings.hasBinding(cx, JSID_TO_ATOM(id)));
     }
 #endif
 
     /*
@@ -1199,17 +1148,17 @@ call_trace(JSTracer *trc, JSObject *obj)
     JS_ASSERT(obj->isCall());
 
     MaybeMarkGenerator(trc, obj);
 }
 
 JS_PUBLIC_DATA(Class) js::CallClass = {
     "Call",
     JSCLASS_HAS_PRIVATE |
-    JSCLASS_HAS_RESERVED_SLOTS(JSObject::CALL_RESERVED_SLOTS) |
+    JSCLASS_HAS_RESERVED_SLOTS(CallObject::RESERVED_SLOTS) |
     JSCLASS_NEW_RESOLVE | JSCLASS_IS_ANONYMOUS,
     PropertyStub,         /* addProperty */
     PropertyStub,         /* delProperty */
     PropertyStub,         /* getProperty */
     StrictPropertyStub,   /* setProperty */
     JS_EnumerateStub,
     (JSResolveOp)call_resolve,
     NULL,                 /* convert: Leave it NULL so we notice if calls ever escape */
--- a/js/src/jsfun.h
+++ b/js/src/jsfun.h
@@ -498,20 +498,20 @@ extern void
 js_PutCallObject(js::StackFrame *fp);
 
 extern JSBool JS_FASTCALL
 js_PutCallObjectOnTrace(JSObject *scopeChain, uint32 nargs, js::Value *argv,
                         uint32 nvars, js::Value *slots);
 
 namespace js {
 
-JSObject *
+CallObject *
 CreateFunCallObject(JSContext *cx, StackFrame *fp);
 
-JSObject *
+CallObject *
 CreateEvalCallObject(JSContext *cx, StackFrame *fp);
 
 extern JSBool
 GetCallArg(JSContext *cx, JSObject *obj, jsid id, js::Value *vp);
 
 extern JSBool
 GetCallVar(JSContext *cx, JSObject *obj, jsid id, js::Value *vp);
 
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -90,16 +90,17 @@
 
 #include "methodjit/MethodJIT.h"
 #include "vm/String.h"
 #include "vm/Debugger.h"
 
 #include "jsobjinlines.h"
 
 #include "vm/String-inl.h"
+#include "vm/CallObject-inl.h"
 
 #ifdef MOZ_VALGRIND
 # define JS_VALGRIND
 #endif
 #ifdef JS_VALGRIND
 # include <valgrind/memcheck.h>
 #endif
 
@@ -233,38 +234,34 @@ Arena::finalize(JSContext *cx, AllocKind
 
     FreeSpan nextFree(aheader.getFirstFreeSpan());
     nextFree.checkSpan();
 
     FreeSpan newListHead;
     FreeSpan *newListTail = &newListHead;
     uintptr_t newFreeSpanStart = 0;
     bool allClear = true;
-#ifdef DEBUG
-    size_t nmarked = 0;
-#endif
+    DebugOnly<size_t> nmarked = 0;
     for (;; thing += thingSize) {
         JS_ASSERT(thing <= lastByte + 1);
         if (thing == nextFree.first) {
             JS_ASSERT(nextFree.last <= lastByte);
             if (nextFree.last == lastByte)
                 break;
             JS_ASSERT(Arena::isAligned(nextFree.last, thingSize));
             if (!newFreeSpanStart)
                 newFreeSpanStart = thing;
             thing = nextFree.last;
             nextFree = *nextFree.nextSpan();
             nextFree.checkSpan();
         } else {
             T *t = reinterpret_cast<T *>(thing);
             if (t->isMarked()) {
                 allClear = false;
-#ifdef DEBUG
                 nmarked++;
-#endif
                 if (newFreeSpanStart) {
                     JS_ASSERT(thing >= thingsStart(thingKind) + thingSize);
                     newListTail->first = newFreeSpanStart;
                     newListTail->last = thing - thingSize;
                     newListTail = newListTail->nextSpanUnchecked(thingSize);
                     newFreeSpanStart = 0;
                 }
             } else {
@@ -1552,19 +1549,17 @@ GCMarker::GCMarker(JSContext *cx)
     unmarkedArenaStackTop(MarkingDelay::stackBottom()),
     objStack(cx->runtime->gcMarkStackObjs, sizeof(cx->runtime->gcMarkStackObjs)),
     ropeStack(cx->runtime->gcMarkStackRopes, sizeof(cx->runtime->gcMarkStackRopes)),
     typeStack(cx->runtime->gcMarkStackTypes, sizeof(cx->runtime->gcMarkStackTypes)),
     xmlStack(cx->runtime->gcMarkStackXMLs, sizeof(cx->runtime->gcMarkStackXMLs)),
     largeStack(cx->runtime->gcMarkStackLarges, sizeof(cx->runtime->gcMarkStackLarges))
 {
     JS_TRACER_INIT(this, cx, NULL);
-#ifdef DEBUG
     markLaterArenas = 0;
-#endif
 #ifdef JS_DUMP_CONSERVATIVE_GC_ROOTS
     conservativeDumpFileName = getenv("JS_DUMP_CONSERVATIVE_GC_ROOTS");
     memset(&conservativeStats, 0, sizeof(conservativeStats));
 #endif
 }
 
 GCMarker::~GCMarker()
 {
@@ -1579,19 +1574,17 @@ GCMarker::delayMarkingChildren(const voi
     const Cell *cell = reinterpret_cast<const Cell *>(thing);
     ArenaHeader *aheader = cell->arenaHeader();
     if (aheader->getMarkingDelay()->link) {
         /* Arena already scheduled to be marked later */
         return;
     }
     aheader->getMarkingDelay()->link = unmarkedArenaStackTop;
     unmarkedArenaStackTop = aheader;
-#ifdef DEBUG
     markLaterArenas++;
-#endif
 }
 
 static void
 MarkDelayedChildren(JSTracer *trc, ArenaHeader *aheader)
 {
     AllocKind thingKind = aheader->getAllocKind();
     JSGCTraceKind traceKind = MapAllocToTraceKind(thingKind);
     size_t thingSize = aheader->getThingSize();
@@ -1612,20 +1605,18 @@ GCMarker::markDelayedChildren()
          * If marking gets delayed at the same arena again, we must repeat
          * marking of its things. For that we pop arena from the stack and
          * clear its nextDelayedMarking before we begin the marking.
          */
         ArenaHeader *aheader = unmarkedArenaStackTop;
         unmarkedArenaStackTop = aheader->getMarkingDelay()->link;
         JS_ASSERT(unmarkedArenaStackTop);
         aheader->getMarkingDelay()->link = NULL;
-#ifdef DEBUG
         JS_ASSERT(markLaterArenas);
         markLaterArenas--;
-#endif
         MarkDelayedChildren(this, aheader);
     }
     JS_ASSERT(!markLaterArenas);
 }
 
 } /* namespace js */
 
 #ifdef DEBUG
@@ -2264,17 +2255,17 @@ MarkAndSweep(JSContext *cx, JSCompartmen
     MarkRuntime(&gcmarker);
     gcmarker.drainMarkStack();
 
     /*
      * Mark weak roots.
      */
     while (WatchpointMap::markAllIteratively(&gcmarker) ||
            WeakMapBase::markAllIteratively(&gcmarker) ||
-           Debugger::markAllIteratively(&gcmarker, gckind))
+           Debugger::markAllIteratively(&gcmarker))
     {
         gcmarker.drainMarkStack();
     }
 
     rt->gcMarkingTracer = NULL;
 
     if (rt->gcCallback)
         (void) rt->gcCallback(cx, JSGC_MARK_END);
--- a/js/src/jsgc.h
+++ b/js/src/jsgc.h
@@ -1475,21 +1475,20 @@ static const size_t TYPE_MARK_STACK_SIZE
 static const size_t LARGE_MARK_STACK_SIZE = 64 * sizeof(LargeMarkItem);
 
 struct GCMarker : public JSTracer {
   private:
     /* The color is only applied to objects, functions and xml. */
     uint32 color;
 
   public:
-    /* See comments before delayMarkingChildren is jsgc.cpp. */
+    /* Pointer to the top of the stack of arenas we are delaying marking on. */
     js::gc::ArenaHeader *unmarkedArenaStackTop;
-#ifdef DEBUG
-    size_t              markLaterArenas;
-#endif
+    /* Count of arenas that are currently in the stack. */
+    DebugOnly<size_t> markLaterArenas;
 
 #ifdef JS_DUMP_CONSERVATIVE_GC_ROOTS
     js::gc::ConservativeGCStats conservativeStats;
     Vector<void *, 0, SystemAllocPolicy> conservativeRoots;
     const char *conservativeDumpFileName;
     void dumpConservativeRoots();
 #endif
 
--- a/js/src/jshashtable.h
+++ b/js/src/jshashtable.h
@@ -645,18 +645,24 @@ class HashTable : private AllocPolicy
     uint32 count() const {
         return entryCount;
     }
 
     uint32 generation() const {
         return gen;
     }
 
-    size_t tableSize() const {
-        return tableCapacity * sizeof(Entry);
+    /*
+     * This counts the HashTable's |table| array.  If |countMe| is true is also
+     * counts the HashTable object itself.
+     */
+    size_t sizeOf(JSUsableSizeFun usf, bool countMe) const {
+        size_t usable = usf(table) + (countMe ? usf((void*)this) : 0);
+        return usable ? usable
+                      : (tableCapacity * sizeof(Entry)) + (countMe ? sizeof(HashTable) : 0);
     }
 
     Ptr lookup(const Lookup &l) const {
         ReentrancyGuard g(*this);
         HashNumber keyHash = prepareHash(l);
         return Ptr(lookup(l, keyHash, 0));
     }
 
@@ -1077,17 +1083,17 @@ class HashMap
      *   for (HM::Range r = h.all(); !r.empty(); r.popFront())
      *     char c = r.front().value;
      *
      * Also see the definition of Range in HashTable above (with T = Entry).
      */
     typedef typename Impl::Range Range;
     Range all() const                                 { return impl.all(); }
     size_t count() const                              { return impl.count(); }
-    size_t tableSize() const                          { return impl.tableSize(); }
+    size_t sizeOf(JSUsableSizeFun usf, bool cm) const { return impl.sizeOf(usf, cm); }
 
     /*
      * Typedef for the enumeration class. An Enum may be used to examine and
      * remove table entries:
      *
      *   typedef HashMap<int,char> HM;
      *   HM s;
      *   for (HM::Enum e(s); !e.empty(); e.popFront())
@@ -1279,17 +1285,17 @@ class HashSet
      *   for (HS::Range r = h.all(); !r.empty(); r.popFront())
      *     int i = r.front();
      *
      * Also see the definition of Range in HashTable above.
      */
     typedef typename Impl::Range Range;
     Range all() const                                 { return impl.all(); }
     size_t count() const                              { return impl.count(); }
-    size_t tableSize() const                          { return impl.tableSize(); }
+    size_t sizeOf(JSUsableSizeFun usf, bool cm) const { return impl.sizeOf(usf, cm); }
 
     /*
      * Typedef for the enumeration class. An Enum may be used to examine and
      * remove table entries:
      *
      *   typedef HashSet<int> HS;
      *   HS s;
      *   for (HS::Enum e(s); !e.empty(); e.popFront())
--- a/js/src/jsinfer.cpp
+++ b/js/src/jsinfer.cpp
@@ -3962,17 +3962,20 @@ ScriptAnalysis::analyzeTypesBytecode(JSC
 
       case JSOP_UNBRAND:
         poppedTypes(pc, 0)->addSubset(cx, &pushed[0]);
         break;
 
       case JSOP_GENERATOR:
         if (script->hasFunction) {
             if (script->hasGlobal()) {
-                TypeObject *object = TypeScript::StandardType(cx, script, JSProto_Generator);
+                JSObject *proto = script->global()->getOrCreateGeneratorPrototype(cx);
+                if (!proto)
+                    return false;
+                TypeObject *object = proto->getNewType(cx);
                 if (!object)
                     return false;
                 TypeScript::ReturnTypes(script)->addType(cx, Type::ObjectType(object));
             } else {
                 TypeScript::ReturnTypes(script)->addType(cx, Type::UnknownType());
             }
         }
         break;
@@ -5050,18 +5053,18 @@ TypeScript::SetScope(JSContext *cx, JSSc
     JS_ASSERT(script->hasFunction == (fun != NULL));
     JS_ASSERT_IF(!fun, !script->isOuterFunction && !script->isInnerFunction);
     JS_ASSERT_IF(!scope, fun && !script->isInnerFunction);
 
     /*
      * The scope object must be the initial one for the script, before any call
      * object has been created in the heavyweight case.
      */
-    JS_ASSERT_IF(scope && scope->isCall() && !scope->callIsForEval(),
-                 scope->getCallObjCalleeFunction() != fun);
+    JS_ASSERT_IF(scope && scope->isCall() && !scope->asCall().isForEval(),
+                 scope->asCall().getCalleeFunction() != fun);
 
     if (!script->compileAndGo) {
         script->types->global = NULL;
         return true;
     }
 
     JS_ASSERT_IF(fun && scope, fun->getGlobal() == scope->getGlobal());
     script->types->global = fun ? fun->getGlobal() : scope->getGlobal();
@@ -5084,21 +5087,23 @@ TypeScript::SetScope(JSContext *cx, JSSc
 
     /*
      * Walk the scope chain to the next call object, which will be the function
      * the script is nested inside.
      */
     while (!scope->isCall())
         scope = scope->getParent();
 
+    CallObject &call = scope->asCall();
+
     /* The isInnerFunction test ensures there is no intervening strict eval call object. */
-    JS_ASSERT(!scope->callIsForEval());
+    JS_ASSERT(!call.isForEval());
 
     /* Don't track non-heavyweight parents, NAME ops won't reach into them. */
-    JSFunction *parentFun = scope->getCallObjCalleeFunction();
+    JSFunction *parentFun = call.getCalleeFunction();
     if (!parentFun || !parentFun->isHeavyweight())
         return true;
     JSScript *parent = parentFun->script();
     JS_ASSERT(parent->isOuterFunction);
 
     /*
      * We only need the nesting in the child if it has NAME accesses going
      * into the parent. We won't know for sure whether this is the case until
@@ -5116,18 +5121,18 @@ TypeScript::SetScope(JSContext *cx, JSSc
      * marked as reentrant.
      */
     if (!parent->ensureHasTypes(cx, parentFun))
         return false;
     if (!parent->types->hasScope()) {
         if (!SetScope(cx, parent, scope->getParent()))
             return false;
         parent->nesting()->activeCall = scope;
-        parent->nesting()->argArray = scope->callObjArgArray();
-        parent->nesting()->varArray = scope->callObjVarArray();
+        parent->nesting()->argArray = call.argArray();
+        parent->nesting()->varArray = call.varArray();
     }
 
     JS_ASSERT(!script->types->nesting);
 
     /* Construct and link nesting information for the two functions. */
 
     script->types->nesting = cx->new_<TypeScriptNesting>();
     if (!script->types->nesting)
@@ -5207,17 +5212,17 @@ ClearActiveNesting(JSScript *start)
  */
 static void
 CheckNestingParent(JSContext *cx, JSObject *scope, JSScript *script)
 {
   restart:
     JSScript *parent = script->nesting()->parent;
     JS_ASSERT(parent);
 
-    while (!scope->isCall() || scope->getCallObjCalleeFunction()->script() != parent)
+    while (!scope->isCall() || scope->asCall().getCalleeFunction()->script() != parent)
         scope = scope->getParent();
 
     if (scope != parent->nesting()->activeCall) {
         parent->reentrantOuterFunction = true;
         MarkTypeObjectFlags(cx, parent->function(), OBJECT_FLAG_REENTRANT_FUNCTION);
 
         /*
          * Continue checking parents to see if this is reentrant for them too.
--- a/js/src/jsinfer.h
+++ b/js/src/jsinfer.h
@@ -50,17 +50,17 @@
 #include "jsvalue.h"
 #include "jshashtable.h"
 
 namespace js {
     class CallArgs;
     namespace analyze {
         class ScriptAnalysis;
     }
-    struct GlobalObject;
+    class GlobalObject;
 }
 
 namespace js {
 namespace types {
 
 /* Forward declarations. */
 class TypeSet;
 struct TypeCallsite;
--- a/js/src/jsinterp.cpp
+++ b/js/src/jsinterp.cpp
@@ -679,116 +679,16 @@ js::InvokeKernel(JSContext *cx, const Ca
     }
 
     args.rval() = fp->returnValue();
     JS_ASSERT_IF(ok && construct, !args.rval().isPrimitive());
     return ok;
 }
 
 bool
-InvokeSessionGuard::start(JSContext *cx, const Value &calleev, const Value &thisv, uintN argc)
-{
-#ifdef JS_TRACER
-    if (TRACE_RECORDER(cx))
-        AbortRecording(cx, "attempt to reenter VM while recording");
-    LeaveTrace(cx);
-#endif
-
-    /* Always push arguments, regardless of optimized/normal invoke. */
-    ContextStack &stack = cx->stack;
-    if (!stack.pushInvokeArgs(cx, argc, &args_))
-        return false;
-
-    /* Callees may clobber 'this' or 'callee'. */
-    savedCallee_ = args_.calleev() = calleev;
-    savedThis_ = args_.thisv() = thisv;
-
-    /* If anyone (through jsdbgapi) finds this frame, make it safe. */
-    MakeRangeGCSafe(args_.argv(), args_.argc());
-
-    do {
-        /* Hoist dynamic checks from scripted Invoke. */
-        if (!calleev.isObject())
-            break;
-        JSObject &callee = calleev.toObject();
-        if (callee.getClass() != &FunctionClass)
-            break;
-        JSFunction *fun = callee.getFunctionPrivate();
-        if (fun->isNative())
-            break;
-        script_ = fun->script();
-        if (!script_->ensureRanAnalysis(cx, fun, callee.getParent()))
-            return false;
-        if (FunctionNeedsPrologue(cx, fun) || script_->isEmpty())
-            break;
-
-        /*
-         * The frame will remain pushed even when the callee isn't active which
-         * will affect the observable current global, so avoid any change.
-         */
-        if (callee.getGlobal() != GetGlobalForScopeChain(cx))
-            break;
-
-        /* Push the stack frame once for the session. */
-        if (!stack.pushInvokeFrame(cx, args_, INITIAL_NONE, &ifg_))
-            return false;
-
-        /*
-         * Update the 'this' type of the callee according to the value given,
-         * along with the types of any missing arguments. These will be the
-         * same across all calls.
-         */
-        TypeScript::SetThis(cx, script_, thisv);
-        for (unsigned i = argc; i < fun->nargs; i++)
-            TypeScript::SetArgument(cx, script_, i, types::Type::UndefinedType());
-
-        StackFrame *fp = ifg_.fp();
-#ifdef JS_METHODJIT
-        /* Hoist dynamic checks from RunScript. */
-        mjit::CompileStatus status = mjit::CanMethodJIT(cx, script_, false,
-                                                        mjit::CompileRequest_JIT);
-        if (status == mjit::Compile_Error)
-            return false;
-        if (status != mjit::Compile_Okay)
-            break;
-        /* Cannot also cache the raw code pointer; it can change. */
-
-        /* Hoist dynamic checks from CheckStackAndEnterMethodJIT. */
-        JS_CHECK_RECURSION(cx, return false);
-        stackLimit_ = stack.space().getStackLimit(cx, REPORT_ERROR);
-        if (!stackLimit_)
-            return false;
-
-        stop_ = script_->code + script_->length - 1;
-        JS_ASSERT(*stop_ == JSOP_STOP);
-#endif
-
-        /* Cached to avoid canonicalActualArg in InvokeSessionGuard::operator[]. */
-        nformals_ = fp->numFormalArgs();
-        formals_ = fp->formalArgs();
-        actuals_ = args_.argv();
-        JS_ASSERT(actuals_ == fp->actualArgs());
-        return true;
-    } while (0);
-
-    /*
-     * Use the normal invoke path.
-     *
-     * The callee slot gets overwritten during an unoptimized Invoke, so we
-     * cache it here and restore it before every Invoke call. The 'this' value
-     * does not get overwritten, so we can fill it here once.
-     */
-    if (ifg_.pushed())
-        ifg_.pop();
-    formals_ = actuals_ = args_.argv();
-    nformals_ = (unsigned)-1;
-    return true;
-}
-
-bool
 js::Invoke(JSContext *cx, const Value &thisv, const Value &fval, uintN argc, Value *argv,
            Value *rval)
 {
     InvokeArgsGuard args;
     if (!cx->stack.pushInvokeArgs(cx, argc, &args))
         return false;
 
     args.calleev() = fval;
@@ -3995,17 +3895,17 @@ BEGIN_CASE(JSOP_GETELEM)
             }
         } else if (obj->isArguments()) {
             uint32 arg = uint32(i);
             ArgumentsObject *argsobj = obj->asArguments();
 
             if (arg < argsobj->initialLength()) {
                 copyFrom = &argsobj->element(arg);
                 if (!copyFrom->isMagic(JS_ARGS_HOLE)) {
-                    if (StackFrame *afp = reinterpret_cast<StackFrame *>(argsobj->getPrivate()))
+                    if (StackFrame *afp = argsobj->maybeStackFrame())
                         copyFrom = &afp->canonicalActualArg(arg);
                     goto end_getelem;
                 }
             }
         }
         if (JS_LIKELY(INT_FITS_IN_JSID(i)))
             id = INT_TO_JSID(i);
         else
--- a/js/src/jsinterpinlines.h
+++ b/js/src/jsinterpinlines.h
@@ -66,137 +66,16 @@ class AutoPreserveEnumerators {
     }
 
     ~AutoPreserveEnumerators()
     {
         cx->enumerators = enumerators;
     }
 };
 
-class InvokeSessionGuard
-{
-    InvokeArgsGuard args_;
-    InvokeFrameGuard ifg_;
-    Value savedCallee_, savedThis_;
-    Value *formals_, *actuals_;
-    unsigned nformals_;
-    JSScript *script_;
-    Value *stackLimit_;
-    jsbytecode *stop_;
-
-    bool optimized() const { return ifg_.pushed(); }
-
-  public:
-    InvokeSessionGuard() : args_(), ifg_() {}
-    ~InvokeSessionGuard() {}
-
-    bool start(JSContext *cx, const Value &callee, const Value &thisv, uintN argc);
-    bool invoke(JSContext *cx);
-
-    bool started() const {
-        return args_.pushed();
-    }
-
-    Value &operator[](unsigned i) const {
-        JS_ASSERT(i < argc());
-        Value &arg = i < nformals_ ? formals_[i] : actuals_[i];
-        JS_ASSERT_IF(optimized(), &arg == &ifg_.fp()->canonicalActualArg(i));
-        JS_ASSERT_IF(!optimized(), &arg == &args_[i]);
-        return arg;
-    }
-
-    uintN argc() const {
-        return args_.argc();
-    }
-
-    const Value &rval() const {
-        return optimized() ? ifg_.fp()->returnValue() : args_.rval();
-    }
-};
-
-inline bool
-InvokeSessionGuard::invoke(JSContext *cx)
-{
-    /* N.B. Must be kept in sync with Invoke */
-
-    /* Refer to canonical (callee, this) for optimized() sessions. */
-    formals_[-2] = savedCallee_;
-    formals_[-1] = savedThis_;
-
-    /* Prevent spurious accessing-callee-after-rval assert. */
-    args_.calleeHasBeenReset();
-
-    if (!optimized())
-        return Invoke(cx, args_);
-
-    /*
-     * Update the types of each argument. The 'this' type and missing argument
-     * types were handled when the invoke session was created.
-     */
-    for (unsigned i = 0; i < Min(argc(), nformals_); i++)
-        types::TypeScript::SetArgument(cx, script_, i, (*this)[i]);
-
-#ifdef JS_METHODJIT
-    mjit::JITScript *jit = script_->getJIT(false /* !constructing */);
-    if (!jit) {
-        /* Watch in case the code was thrown away due a recompile. */
-        mjit::CompileStatus status = mjit::TryCompile(cx, script_, false);
-        if (status == mjit::Compile_Error)
-            return false;
-        JS_ASSERT(status == mjit::Compile_Okay);
-        jit = script_->getJIT(false);
-    }
-    void *code;
-    if (!(code = jit->invokeEntry))
-        return Invoke(cx, args_);
-#endif
-
-    StackFrame *fp = ifg_.fp();
-
-    /*
-     * Clear any activation objects on the frame. Normally the frame should not
-     * have any, but since we leave it on the stack between calls to invoke()
-     * the debugger can start operating on it. See markFunctionEpilogueDone()
-     * calls below. :XXX: this is pretty gross, and slows us down. Can the
-     * debugger be prevented from observing this frame?
-     */
-    fp->functionEpilogue(/* activationOnly = */ true);
-    fp->markFunctionEpilogueDone(/* activationOnly = */ true);
-
-    fp->resetCallFrame(script_);
-
-    JSBool ok;
-    {
-        AutoPreserveEnumerators preserve(cx);
-        args_.setActive();  /* From js::Invoke(InvokeArgsGuard) overload. */
-        Probes::enterJSFun(cx, fp->fun(), script_);
-#ifdef JS_METHODJIT
-        ok = mjit::EnterMethodJIT(cx, fp, code, stackLimit_, /* partial = */ false);
-        cx->regs().pc = stop_;
-#else
-        cx->regs().pc = script_->code;
-        ok = Interpret(cx, cx->fp());
-
-        /* Interpret does not perform the entry frame's epilogue, unlike EnterMethodJIT. */
-        cx->fp()->functionEpilogue();
-#endif
-        Probes::exitJSFun(cx, fp->fun(), script_);
-        args_.setInactive();
-    }
-
-    /*
-     * Clear activation object flags, for the functionEpilogue() call in the
-     * next invoke().
-     */
-    fp->markFunctionEpilogueDone(/* activationOnly = */ true);
-
-    /* Don't clobber callee with rval; rval gets read from fp->rval. */
-    return ok;
-}
-
 namespace detail {
 
 template<typename T> class PrimitiveBehavior { };
 
 template<>
 class PrimitiveBehavior<JSString *> {
   public:
     static inline bool isType(const Value &v) { return v.isString(); }
--- a/js/src/jsiter.cpp
+++ b/js/src/jsiter.cpp
@@ -1106,19 +1106,18 @@ generator_trace(JSTracer *trc, JSObject 
      * this code and save someone an hour later.
      */
     MarkStackRangeConservatively(trc, gen->floatingStack, fp->formalArgsEnd());
     js_TraceStackFrame(trc, fp);
     MarkStackRangeConservatively(trc, fp->slots(), gen->regs.sp);
 }
 
 Class js::GeneratorClass = {
-    js_Generator_str,
-    JSCLASS_HAS_PRIVATE | JSCLASS_HAS_CACHED_PROTO(JSProto_Generator) |
-    JSCLASS_IS_ANONYMOUS,
+    "Generator",
+    JSCLASS_HAS_PRIVATE,
     PropertyStub,         /* addProperty */
     PropertyStub,         /* delProperty */
     PropertyStub,         /* getProperty */
     StrictPropertyStub,   /* setProperty */
     EnumerateStub,
     ResolveStub,
     ConvertStub,
     generator_finalize,
@@ -1144,25 +1143,29 @@ Class js::GeneratorClass = {
  * JSGenerator object, which contains its own StackFrame that we populate
  * from *fp.  We know that upon return, the JSOP_GENERATOR opcode will return
  * from the activation in fp, so we can steal away fp->callobj and fp->argsobj
  * if they are non-null.
  */
 JS_REQUIRES_STACK JSObject *
 js_NewGenerator(JSContext *cx)
 {
-    JSObject *obj = NewBuiltinClassInstance(cx, &GeneratorClass);
-    if (!obj)
-        return NULL;
-
     FrameRegs &stackRegs = cx->regs();
     StackFrame *stackfp = stackRegs.fp();
     JS_ASSERT(stackfp->base() == cx->regs().sp);
     JS_ASSERT(stackfp->actualArgs() <= stackfp->formalArgs());
 
+    GlobalObject *global = stackfp->scopeChain().getGlobal();
+    JSObject *proto = global->getOrCreateGeneratorPrototype(cx);
+    if (!proto)
+        return NULL;
+    JSObject *obj = NewNonFunction<WithProto::Given>(cx, &GeneratorClass, proto, global);
+    if (!obj)
+        return NULL;
+
     /* Load and compute stack slot counts. */
     Value *stackvp = stackfp->actualArgs() - 2;
     uintN vplen = stackfp->formalArgsEnd() - stackvp;
 
     /* Compute JSGenerator size. */
     uintN nbytes = sizeof(JSGenerator) +
                    (-1 + /* one Value included in JSGenerator */
                     vplen +
@@ -1438,32 +1441,26 @@ InitIteratorClass(JSContext *cx, GlobalO
         return false;
 
     if (!DefinePropertiesAndBrand(cx, iteratorProto, NULL, iterator_methods))
         return false;
 
     return DefineConstructorAndPrototype(cx, global, JSProto_Iterator, ctor, iteratorProto);
 }
 
-static bool
-InitGeneratorClass(JSContext *cx, GlobalObject *global)
+bool
+GlobalObject::initGeneratorClass(JSContext *cx)
 {
 #if JS_HAS_GENERATORS
-    JSObject *proto = global->createBlankPrototype(cx, &GeneratorClass);
-    if (!proto)
-        return false;
-
-    if (!DefinePropertiesAndBrand(cx, proto, NULL, generator_methods))
+    JSObject *proto = createBlankPrototype(cx, &GeneratorClass);
+    if (!proto || !DefinePropertiesAndBrand(cx, proto, NULL, generator_methods))
         return false;
-
-    /* This should use a non-JSProtoKey'd slot, but this is easier for now. */
-    return DefineConstructorAndPrototype(cx, global, JSProto_Generator, proto, proto);
-#else
+    setReservedSlot(GENERATOR_PROTO, ObjectValue(*proto));
+#endif
     return true;
-#endif
 }
 
 static JSObject *
 InitStopIterationClass(JSContext *cx, GlobalObject *global)
 {
     JSObject *proto = global->createBlankPrototype(cx, &StopIterationClass);
     if (!proto || !proto->freeze(cx))
         return NULL;
@@ -1491,12 +1488,12 @@ js_InitIteratorClasses(JSContext *cx, JS
      * Iterator class a second time will assert.
      */
     JSObject *iter;
     if (!js_GetClassObject(cx, global, JSProto_Iterator, &iter))
         return NULL;
     if (iter)
         return iter;
 
-    if (!InitIteratorClass(cx, global) || !InitGeneratorClass(cx, global))
+    if (!InitIteratorClass(cx, global) || !global->initGeneratorClass(cx))
         return NULL;
     return InitStopIterationClass(cx, global);
 }
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -2713,21 +2713,21 @@ obj_preventExtensions(JSContext *cx, uin
     if (!obj->isExtensible())
         return true;
 
     AutoIdVector props(cx);
     return obj->preventExtensions(cx, &props);
 }
 
 size_t
-JSObject::sizeOfSlotsArray(size_t(*mus)(void *))
+JSObject::sizeOfSlotsArray(JSUsableSizeFun usf)
 {
     if (!hasSlotsArray())
         return 0;
-    size_t usable = mus((void *)slots);
+    size_t usable = usf((void *)slots);
     return usable ? usable : numSlots() * sizeof(js::Value);
 }
 
 bool
 JSObject::sealOrFreeze(JSContext *cx, ImmutabilityType it)
 {
     assertSameCompartment(cx, this);
     JS_ASSERT(it == SEAL || it == FREEZE);
@@ -3264,46 +3264,101 @@ with_LookupProperty(JSContext *cx, JSObj
     if (flags == RESOLVE_INFER)
         flags = js_InferFlags(cx, flags);
     flags |= JSRESOLVE_WITH;
     JSAutoResolveFlags rf(cx, flags);
     return obj->getProto()->lookupProperty(cx, id, objp, propp);
 }
 
 static JSBool
+with_LookupElement(JSContext *cx, JSObject *obj, uint32 index, JSObject **objp,
+                   JSProperty **propp)
+{
+    jsid id;
+    if (!IndexToId(cx, index, &id))
+        return false;
+    return with_LookupProperty(cx, obj, id, objp, propp);
+}
+
+static JSBool
 with_GetProperty(JSContext *cx, JSObject *obj, JSObject *receiver, jsid id, Value *vp)
 {
     return obj->getProto()->getProperty(cx, id, vp);
 }
 
 static JSBool
+with_GetElement(JSContext *cx, JSObject *obj, JSObject *receiver, uint32 index, Value *vp)
+{
+    jsid id;
+    if (!IndexToId(cx, index, &id))
+        return false;
+    return with_GetProperty(cx, obj, receiver, id, vp);
+}
+
+static JSBool
 with_SetProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp, JSBool strict)
 {
     return obj->getProto()->setProperty(cx, id, vp, strict);
 }
 
 static JSBool
+with_SetElement(JSContext *cx, JSObject *obj, uint32 index, Value *vp, JSBool strict)
+{
+    jsid id;
+    if (!IndexToId(cx, index, &id))
+        return false;
+    return with_SetProperty(cx, obj, id, vp, strict);
+}
+
+static JSBool
 with_GetAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp)
 {
     return obj->getProto()->getAttributes(cx, id, attrsp);
 }
 
 static JSBool
+with_GetElementAttributes(JSContext *cx, JSObject *obj, uint32 index, uintN *attrsp)
+{
+    jsid id;
+    if (!IndexToId(cx, index, &id))
+        return false;
+    return with_GetAttributes(cx, obj, id, attrsp);
+}
+
+static JSBool
 with_SetAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp)
 {
     return obj->getProto()->setAttributes(cx, id, attrsp);
 }
 
 static JSBool
+with_SetElementAttributes(JSContext *cx, JSObject *obj, uint32 index, uintN *attrsp)
+{
+    jsid id;
+    if (!IndexToId(cx, index, &id))
+        return false;
+    return with_SetAttributes(cx, obj, id, attrsp);
+}
+
+static JSBool
 with_DeleteProperty(JSContext *cx, JSObject *obj, jsid id, Value *rval, JSBool strict)
 {
     return obj->getProto()->deleteProperty(cx, id, rval, strict);
 }
 
 static JSBool
+with_DeleteElement(JSContext *cx, JSObject *obj, uint32 index, Value *rval, JSBool strict)
+{
+    jsid id;
+    if (!IndexToId(cx, index, &id))
+        return false;
+    return with_DeleteProperty(cx, obj, id, rval, strict);
+}
+
+static JSBool
 with_Enumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op,
                Value *statep, jsid *idp)
 {
     return obj->getProto()->enumerate(cx, enum_op, statep, idp);
 }
 
 static JSType
 with_TypeOf(JSContext *cx, JSObject *obj)
@@ -3333,22 +3388,29 @@ Class js::WithClass = {
     NULL,                 /* call        */
     NULL,                 /* construct   */
     NULL,                 /* xdrObject   */
     NULL,                 /* hasInstance */
     NULL,                 /* trace       */
     JS_NULL_CLASS_EXT,
     {
         with_LookupProperty,
+        with_LookupElement,
         NULL,             /* defineProperty */
+        NULL,             /* defineElement */
         with_GetProperty,
+        with_GetElement,
         with_SetProperty,
+        with_SetElement,
         with_GetAttributes,
+        with_GetElementAttributes,
         with_SetAttributes,
+        with_SetElementAttributes,
         with_DeleteProperty,
+        with_DeleteElement,
         with_Enumerate,
         with_TypeOf,
         NULL,             /* fix   */
         with_ThisObject,
         NULL,             /* clear */
     }
 };
 
@@ -4424,17 +4486,17 @@ bool
 JSObject::growSlots(JSContext *cx, size_t newcap)
 {
     /*
      * Slots are only allocated for call objects when new properties are
      * added to them, which can only happen while the call is still on the
      * stack (and an eval, DEFFUN, etc. happens). We thus do not need to
      * worry about updating any active outer function args/vars.
      */
-    JS_ASSERT_IF(isCall(), maybeCallObjStackFrame() != NULL);
+    JS_ASSERT_IF(isCall(), asCall().maybeStackFrame() != NULL);
 
     /*
      * When an object with CAPACITY_DOUBLING_MAX or fewer slots needs to
      * grow, double its capacity, to add N elements in amortized O(N) time.
      *
      * Above this limit, grow by 12.5% each time. Speed is still amortized
      * O(N), with a higher constant factor, and we waste less space.
      */
--- a/js/src/jsobj.h
+++ b/js/src/jsobj.h
@@ -61,16 +61,17 @@
 
 namespace nanojit { class ValidateWriter; }
 
 namespace js {
 
 class AutoPropDescArrayRooter;
 class JSProxyHandler;
 class RegExp;
+class CallObject;
 struct GCMarker;
 struct NativeIterator;
 
 namespace mjit { class Compiler; }
 
 static inline PropertyOp
 CastAsPropertyOp(JSObject *object)
 {
@@ -473,17 +474,17 @@ struct JSObject : js::gc::Cell {
     union {
         /* If prototype, type of values using this as their prototype. */
         js::types::TypeObject *newType;
 
         /* If dense array, the initialized length (see jsarray.cpp). */
         jsuword initializedLength;
     };
 
-    JS_FRIEND_API(size_t) sizeOfSlotsArray(size_t(*mus)(void *));
+    JS_FRIEND_API(size_t) sizeOfSlotsArray(JSUsableSizeFun usf);
 
     JSObject    *parent;                    /* object's parent */
     void        *privateData;               /* private data */
     jsuword     capacity;                   /* total number of available slots */
 
   private:
     js::Value   *slots;                     /* dynamically allocated slots,
                                                or pointer to fixedSlots() for
@@ -728,16 +729,18 @@ struct JSObject : js::gc::Cell {
     /* Whether this object has any dynamic slots at all. */
     inline bool hasSlotsArray() const;
 
     /* Get the number of dynamic slots required for a given capacity. */
     inline size_t numDynamicSlots(size_t capacity) const;
 
   private:
     inline js::Value* fixedSlots() const;
+
+  protected:
     inline bool hasContiguousSlots(size_t start, size_t count) const;
 
   public:
     /* Minimum size for dynamically allocated slots. */
     static const uint32 SLOT_CAPACITY_MIN = 8;
 
     bool allocSlots(JSContext *cx, size_t nslots);
     bool growSlots(JSContext *cx, size_t nslots);
@@ -1060,68 +1063,20 @@ struct JSObject : js::gc::Cell {
     inline uint32 arrayBufferByteLength();
     inline uint8 * arrayBufferDataOffset();
 
   public:
     inline js::ArgumentsObject *asArguments();
     inline js::NormalArgumentsObject *asNormalArguments();
     inline js::StrictArgumentsObject *asStrictArguments();
 
-  private:
-    /*
-     * Reserved slot structure for Call objects:
-     *
-     * private               - the stack frame corresponding to the Call object
-     *                         until js_PutCallObject or its on-trace analog
-     *                         is called, null thereafter
-     * JSSLOT_CALL_CALLEE    - callee function for the stack frame, or null if
-     *                         the stack frame is for strict mode eval code
-     * JSSLOT_CALL_ARGUMENTS - arguments object for non-strict mode eval stack
-     *                         frames (not valid for strict mode eval frames)
-     */
-    static const uint32 JSSLOT_CALL_CALLEE = 0;
-    static const uint32 JSSLOT_CALL_ARGUMENTS = 1;
+  public:
+    inline js::CallObject &asCall();
 
   public:
-    /* Number of reserved slots. */
-    static const uint32 CALL_RESERVED_SLOTS = 2;
-
-    /* True if this is for a strict mode eval frame or for a function call. */
-    inline bool callIsForEval() const;
-
-    /* The stack frame for this Call object, if the frame is still active. */
-    inline js::StackFrame *maybeCallObjStackFrame() const;
-
-    /*
-     * The callee function if this Call object was created for a function
-     * invocation, or null if it was created for a strict mode eval frame.
-     */
-    inline JSObject *getCallObjCallee() const;
-    inline JSFunction *getCallObjCalleeFunction() const; 
-    inline void setCallObjCallee(JSObject *callee);
-
-    inline const js::Value &getCallObjArguments() const;
-    inline void setCallObjArguments(const js::Value &v);
-
-    /* Returns the formal argument at the given index. */
-    inline const js::Value &callObjArg(uintN i) const;
-    inline void setCallObjArg(uintN i, const js::Value &v);
-
-    /* Returns the variable at the given index. */
-    inline const js::Value &callObjVar(uintN i) const;
-    inline void setCallObjVar(uintN i, const js::Value &v);
-
-    /*
-     * Get the actual arrays of arguments and variables. Only call if type
-     * inference is enabled, where we ensure that call object variables are in
-     * contiguous slots (see NewCallObject).
-     */
-    inline js::Value *callObjArgArray();
-    inline js::Value *callObjVarArray();
-
     /*
      * Date-specific getters and setters.
      */
 
     static const uint32 JSSLOT_DATE_UTC_TIME = 0;
 
     /*
      * Cached slots holding local properties of the date.
@@ -1921,20 +1876,17 @@ static const uintN RESOLVE_INFER = 0xfff
  * non-global objects without prototype or with prototype that never mutates,
  * see bug 462734 and bug 487039.
  */
 static inline bool
 IsCacheableNonGlobalScope(JSObject *obj)
 {
     JS_ASSERT(obj->getParent());
 
-    js::Class *clasp = obj->getClass();
-    bool cacheable = (clasp == &CallClass ||
-                      clasp == &BlockClass ||
-                      clasp == &DeclEnvClass);
+    bool cacheable = (obj->isCall() || obj->isBlock() || obj->isDeclEnv());
 
     JS_ASSERT_IF(cacheable, !obj->getOps()->lookupProperty);
     return cacheable;
 }
 
 }
 
 /*
--- a/js/src/jsobjinlines.h
+++ b/js/src/jsobjinlines.h
@@ -535,122 +535,16 @@ JSObject::shrinkDenseArrayElements(JSCon
 
 inline bool
 JSObject::denseArrayHasInlineSlots() const
 {
     JS_ASSERT(isDenseArray() && slots);
     return slots == fixedSlots();
 }
 
-inline bool
-JSObject::callIsForEval() const
-{
-    JS_ASSERT(isCall());
-    JS_ASSERT(getFixedSlot(JSSLOT_CALL_CALLEE).isObjectOrNull());
-    JS_ASSERT_IF(getFixedSlot(JSSLOT_CALL_CALLEE).isObject(),
-                 getFixedSlot(JSSLOT_CALL_CALLEE).toObject().isFunction());
-    return getFixedSlot(JSSLOT_CALL_CALLEE).isNull();
-}
-
-inline js::StackFrame *
-JSObject::maybeCallObjStackFrame() const
-{
-    JS_ASSERT(isCall());
-    return reinterpret_cast<js::StackFrame *>(getPrivate());
-}
-
-inline void
-JSObject::setCallObjCallee(JSObject *callee)
-{
-    JS_ASSERT(isCall());
-    JS_ASSERT_IF(callee, callee->isFunction());
-    setFixedSlot(JSSLOT_CALL_CALLEE, js::ObjectOrNullValue(callee));
-}
-
-inline JSObject *
-JSObject::getCallObjCallee() const
-{
-    JS_ASSERT(isCall());
-    return getFixedSlot(JSSLOT_CALL_CALLEE).toObjectOrNull();
-}
-
-inline JSFunction *
-JSObject::getCallObjCalleeFunction() const
-{
-    JS_ASSERT(isCall());
-    return getFixedSlot(JSSLOT_CALL_CALLEE).toObject().getFunctionPrivate();
-}
-
-inline const js::Value &
-JSObject::getCallObjArguments() const
-{
-    JS_ASSERT(isCall());
-    JS_ASSERT(!callIsForEval());
-    return getFixedSlot(JSSLOT_CALL_ARGUMENTS);
-}
-
-inline void
-JSObject::setCallObjArguments(const js::Value &v)
-{
-    JS_ASSERT(isCall());
-    JS_ASSERT(!callIsForEval());
-    setFixedSlot(JSSLOT_CALL_ARGUMENTS, v);
-}
-
-inline const js::Value &
-JSObject::callObjArg(uintN i) const
-{
-    JS_ASSERT(isCall());
-    JS_ASSERT(i < getCallObjCalleeFunction()->nargs);
-    return getSlot(JSObject::CALL_RESERVED_SLOTS + i);
-}
-
-inline void
-JSObject::setCallObjArg(uintN i, const js::Value &v)
-{
-    JS_ASSERT(isCall());
-    JS_ASSERT(i < getCallObjCalleeFunction()->nargs);
-    setSlot(JSObject::CALL_RESERVED_SLOTS + i, v);
-}
-
-inline js::Value *
-JSObject::callObjArgArray()
-{
-    js::DebugOnly<JSFunction*> fun = getCallObjCalleeFunction();
-    JS_ASSERT(hasContiguousSlots(JSObject::CALL_RESERVED_SLOTS, fun->nargs));
-    return getSlotAddress(JSObject::CALL_RESERVED_SLOTS);
-}
-
-inline const js::Value &
-JSObject::callObjVar(uintN i) const
-{
-    JSFunction *fun = getCallObjCalleeFunction();
-    JS_ASSERT(fun->nargs == fun->script()->bindings.countArgs());
-    JS_ASSERT(i < fun->script()->bindings.countVars());
-    return getSlot(JSObject::CALL_RESERVED_SLOTS + fun->nargs + i);
-}
-
-inline void
-JSObject::setCallObjVar(uintN i, const js::Value &v)
-{
-    JSFunction *fun = getCallObjCalleeFunction();
-    JS_ASSERT(fun->nargs == fun->script()->bindings.countArgs());
-    JS_ASSERT(i < fun->script()->bindings.countVars());
-    setSlot(JSObject::CALL_RESERVED_SLOTS + fun->nargs + i, v);
-}
-
-inline js::Value *
-JSObject::callObjVarArray()
-{
-    JSFunction *fun = getCallObjCalleeFunction();
-    JS_ASSERT(hasContiguousSlots(JSObject::CALL_RESERVED_SLOTS + fun->nargs,
-                                 fun->script()->bindings.countVars()));
-    return getSlotAddress(JSObject::CALL_RESERVED_SLOTS + fun->nargs);
-}
-
 namespace js {
 
 /*
  * Any name atom for a function which will be added as a DeclEnv object to the
  * scope chain above call objects for fun.
  */
 static inline JSAtom *
 CallObjectLambdaName(JSFunction *fun)
--- a/js/src/jsparse.cpp
+++ b/js/src/jsparse.cpp
@@ -315,17 +315,17 @@ JSFunctionBox::joinable() const
                        TCF_FUN_USES_OWN_NAME |
                        TCF_COMPILE_N_GO)) == TCF_COMPILE_N_GO;
 }
 
 bool
 JSFunctionBox::inAnyDynamicScope() const
 {
     for (const JSFunctionBox *funbox = this; funbox; funbox = funbox->parent) {
-        if (funbox->tcflags & (TCF_IN_WITH | TCF_FUN_CALLS_EVAL))
+        if (funbox->tcflags & (TCF_IN_WITH | TCF_FUN_EXTENSIBLE_SCOPE))
             return true;
     }
     return false;
 }
 
 bool
 JSFunctionBox::scopeIsExtensible() const
 {
@@ -6729,17 +6729,17 @@ class GenexpGuard {
         }
         startYieldCount = tc->yieldCount;
         startArgumentsCount = tc->argumentsCount;
         tc->parenDepth++;
     }
 
     void endBody();
     bool checkValidBody(JSParseNode *pn);
-    bool maybeNoteGenerator();
+    bool maybeNoteGenerator(JSParseNode *pn);
 };
 
 void
 GenexpGuard::endBody()
 {
     tc->parenDepth--;
 }
 
@@ -6775,25 +6775,32 @@ GenexpGuard::checkValidBody(JSParseNode 
 /*
  * Check whether a |yield| token has been encountered in the body expression,
  * and if so, note that the current function is a generator function.
  *
  * Call this after endBody() when determining that the body *was not* in a
  * generator expression.
  */
 bool
-GenexpGuard::maybeNoteGenerator()
+GenexpGuard::maybeNoteGenerator(JSParseNode *pn)
 {
     if (tc->yieldCount > 0) {
         tc->flags |= TCF_FUN_IS_GENERATOR;
         if (!tc->inFunction()) {
             tc->parser->reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_BAD_RETURN_OR_YIELD,
                                           js_yield_str);
             return false;
         }
+        if (tc->flags & TCF_RETURN_EXPR) {
+            /* At the time we saw the yield, we might not have set TCF_FUN_IS_GENERATOR yet. */
+            ReportBadReturn(tc->parser->context, tc, pn, JSREPORT_ERROR,
+                            JSMSG_BAD_GENERATOR_RETURN,
+                            JSMSG_BAD_ANON_GENERATOR_RETURN);
+            return false;
+        }
     }
     return true;
 }
 
 /*
  * Any definitions nested within the comprehension expression of a generator
  * expression must move "down" one static level, which of course increases the
  * upvar-frame-skip count.
@@ -7124,17 +7131,17 @@ Parser::comprehensionTail(JSParseNode *k
         MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_FOR_CTRL);
 
         guard.endBody();
 
         if (isGenexp) {
             if (!guard.checkValidBody(pn2))
                 return NULL;
         } else {
-            if (!guard.maybeNoteGenerator())
+            if (!guard.maybeNoteGenerator(pn2))
                 return NULL;
         }
 
         switch (tt) {
 #if JS_HAS_DESTRUCTURING
           case TOK_LB:
           case TOK_LC:
             if (!CheckDestructuring(context, &data, pn3, tc))
@@ -7354,17 +7361,17 @@ Parser::argumentList(JSParseNode *listNo
             if (listNode->pn_count > 1 ||
                 tokenStream.peekToken() == TOK_COMMA) {
                 reportErrorNumber(argNode, JSREPORT_ERROR, JSMSG_BAD_GENERATOR_SYNTAX,
                                   js_generator_str);
                 return JS_FALSE;
             }
         } else
 #endif
-        if (arg0 && !guard.maybeNoteGenerator())
+        if (arg0 && !guard.maybeNoteGenerator(argNode))
             return JS_FALSE;
 
         arg0 = false;
 
         listNode->append(argNode);
     } while (tokenStream.matchToken(TOK_COMMA));
 
     if (tokenStream.getToken() != TOK_RP) {
@@ -8449,17 +8456,16 @@ Parser::primaryExpr(TokenKind tt, JSBool
             MUST_MATCH_TOKEN(TOK_RB, JSMSG_BRACKET_AFTER_LIST);
         }
         pn->pn_pos.end = tokenStream.currentToken().pos.end;
         return pn;
       }
 
       case TOK_LC:
       {
-        JSBool afterComma;
         JSParseNode *pnval;
 
         /*
          * A map from property names we've seen thus far to a mask of property
          * assignment types, stored and retrieved with ALE_SET_INDEX/ALE_INDEX.
          */
         AtomIndexMap seen(context);
 
@@ -8471,17 +8477,16 @@ Parser::primaryExpr(TokenKind tt, JSBool
 
         pn = ListNode::create(tc);
         if (!pn)
             return NULL;
         pn->pn_type = TOK_RC;
         pn->pn_op = JSOP_NEWINIT;
         pn->makeEmpty();
 
-        afterComma = JS_FALSE;
         for (;;) {
             JSAtom *atom;
             tt = tokenStream.getToken(TSF_KEYWORD_IS_NAME);
             switch (tt) {
               case TOK_NUMBER:
                 pn3 = NullaryNode::create(tc);
                 if (!pn3)
                     return NULL;
@@ -8630,17 +8635,16 @@ Parser::primaryExpr(TokenKind tt, JSBool
 
             tt = tokenStream.getToken();
             if (tt == TOK_RC)
                 goto end_obj_init;
             if (tt != TOK_COMMA) {
                 reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_CURLY_AFTER_LIST);
                 return NULL;
             }
-            afterComma = JS_TRUE;
         }
 
       end_obj_init:
         pn->pn_pos.end = tokenStream.currentToken().pos.end;
         return pn;
       }
 
 #if JS_HAS_BLOCK_SCOPE
@@ -8975,17 +8979,17 @@ Parser::parenExpr(JSBool *genexp)
                 return NULL;
             }
             pn->pn_pos.end = tokenStream.currentToken().pos.end;
             *genexp = JS_TRUE;
         }
     } else
 #endif /* JS_HAS_GENERATOR_EXPRS */
 
-    if (!guard.maybeNoteGenerator())
+    if (!guard.maybeNoteGenerator(pn))
         return NULL;
 
     return pn;
 }
 
 /*
  * Fold from one constant type to another.
  * XXX handles only strings and numbers for now
--- a/js/src/jsparse.h
+++ b/js/src/jsparse.h
@@ -1057,21 +1057,21 @@ struct JSFunctionBoxQueue {
     size_t count()  { return head - tail; }
     size_t length() { return lengthMask + 1; }
 
     JSFunctionBoxQueue()
       : vector(NULL), head(0), tail(0), lengthMask(0) { }
 
     bool init(uint32 count) {
         lengthMask = JS_BITMASK(JS_CeilingLog2(count));
-        vector = js::OffTheBooks::array_new<JSFunctionBox*>(length());
+        vector = (JSFunctionBox **) js::OffTheBooks::malloc_(sizeof(JSFunctionBox) * length());
         return !!vector;
     }
 
-    ~JSFunctionBoxQueue() { js::UnwantedForeground::array_delete(vector); }
+    ~JSFunctionBoxQueue() { js::UnwantedForeground::free_(vector); }
 
     void push(JSFunctionBox *funbox) {
         if (!funbox->queued) {
             JS_ASSERT(count() < length());
             vector[head++ & lengthMask] = funbox;
             funbox->queued = true;
         }
     }
--- a/js/src/jsproto.tbl
+++ b/js/src/jsproto.tbl
@@ -45,22 +45,16 @@
 # define XMLFILTER_INIT                 js_InitXMLFilterClass
 #else
 # define XML_INIT                       js_InitNullClass
 # define NAMESPACE_INIT                 js_InitNullClass
 # define QNAME_INIT                     js_InitNullClass
 # define XMLFILTER_INIT                 js_InitNullClass
 #endif
 
-#if JS_HAS_GENERATORS
-# define GENERATOR_INIT                 js_InitIteratorClasses
-#else
-# define GENERATOR_INIT                 js_InitNullClass
-#endif
-
 /*
  * Enumerator codes in the second column must not change -- they are part of
  * the JS XDR API.  Client modules including jsproto.tbl should consider
  * wrapping the inclusion with JS_BEGIN_EXTERN_C and JS_END_EXTERN_C.
  */
 JS_PROTO(Null,                   0,     js_InitNullClass)
 JS_PROTO(Object,                 1,     js_InitFunctionAndObjectClasses)
 JS_PROTO(Function,               2,     js_InitFunctionAndObjectClasses)
@@ -78,29 +72,27 @@ JS_PROTO(QName,                 13,     
 JS_PROTO(Error,                 14,     js_InitExceptionClasses)
 JS_PROTO(InternalError,         15,     js_InitExceptionClasses)
 JS_PROTO(EvalError,             16,     js_InitExceptionClasses)
 JS_PROTO(RangeError,            17,     js_InitExceptionClasses)
 JS_PROTO(ReferenceError,        18,     js_InitExceptionClasses)
 JS_PROTO(SyntaxError,           19,     js_InitExceptionClasses)
 JS_PROTO(TypeError,             20,     js_InitExceptionClasses)
 JS_PROTO(URIError,              21,     js_InitExceptionClasses)
-JS_PROTO(Generator,             22,     GENERATOR_INIT)
-JS_PROTO(Iterator,              23,     js_InitIteratorClasses)
-JS_PROTO(StopIteration,         24,     js_InitIteratorClasses)
-JS_PROTO(ArrayBuffer,           25,     js_InitTypedArrayClasses)
-JS_PROTO(Int8Array,             26,     js_InitTypedArrayClasses)
-JS_PROTO(Uint8Array,            27,     js_InitTypedArrayClasses)
-JS_PROTO(Int16Array,            28,     js_InitTypedArrayClasses)
-JS_PROTO(Uint16Array,           29,     js_InitTypedArrayClasses)
-JS_PROTO(Int32Array,            30,     js_InitTypedArrayClasses)
-JS_PROTO(Uint32Array,           31,     js_InitTypedArrayClasses)
-JS_PROTO(Float32Array,          32,     js_InitTypedArrayClasses)
-JS_PROTO(Float64Array,          33,     js_InitTypedArrayClasses)
-JS_PROTO(Uint8ClampedArray,     34,     js_InitTypedArrayClasses)
-JS_PROTO(Proxy,                 35,     js_InitProxyClass)
-JS_PROTO(AnyName,               36,     js_InitNullClass)
-JS_PROTO(WeakMap,               37,     js_InitWeakMapClass)
+JS_PROTO(Iterator,              22,     js_InitIteratorClasses)
+JS_PROTO(StopIteration,         23,     js_InitIteratorClasses)
+JS_PROTO(ArrayBuffer,           24,     js_InitTypedArrayClasses)
+JS_PROTO(Int8Array,             25,     js_InitTypedArrayClasses)
+JS_PROTO(Uint8Array,            26,     js_InitTypedArrayClasses)
+JS_PROTO(Int16Array,            27,     js_InitTypedArrayClasses)
+JS_PROTO(Uint16Array,           28,     js_InitTypedArrayClasses)
+JS_PROTO(Int32Array,            29,     js_InitTypedArrayClasses)
+JS_PROTO(Uint32Array,           30,     js_InitTypedArrayClasses)
+JS_PROTO(Float32Array,          31,     js_InitTypedArrayClasses)
+JS_PROTO(Float64Array,          32,     js_InitTypedArrayClasses)
+JS_PROTO(Uint8ClampedArray,     33,     js_InitTypedArrayClasses)
+JS_PROTO(Proxy,                 34,     js_InitProxyClass)
+JS_PROTO(AnyName,               35,     js_InitNullClass)
+JS_PROTO(WeakMap,               36,     js_InitWeakMapClass)
 
 #undef XML_INIT
 #undef NAMESPACE_INIT
 #undef QNAME_INIT
-#undef GENERATOR_INIT
--- a/js/src/jsproxy.cpp
+++ b/js/src/jsproxy.cpp
@@ -897,73 +897,138 @@ proxy_LookupProperty(JSContext *cx, JSOb
     } else {
         *objp = NULL;
         *propp = NULL;
     }
     return true;
 }
 
 static JSBool
+proxy_LookupElement(JSContext *cx, JSObject *obj, uint32 index, JSObject **objp,
+                    JSProperty **propp)
+{
+    jsid id;
+    if (!IndexToId(cx, index, &id))
+        return false;
+    return proxy_LookupProperty(cx, obj, id, objp, propp);
+}
+
+static JSBool
 proxy_DefineProperty(JSContext *cx, JSObject *obj, jsid id, const Value *value,
                      PropertyOp getter, StrictPropertyOp setter, uintN attrs)
 {
     AutoPropertyDescriptorRooter desc(cx);
     desc.obj = obj;
     desc.value = *value;
     desc.attrs = (attrs & (~JSPROP_SHORTID));
     desc.getter = getter;
     desc.setter = setter;
     desc.shortid = 0;
     return JSProxy::defineProperty(cx, obj, id, &desc);
 }
 
 static JSBool
+proxy_DefineElement(JSContext *cx, JSObject *obj, uint32 index, const Value *value,
+                    PropertyOp getter, StrictPropertyOp setter, uintN attrs)
+{
+    jsid id;
+    if (!IndexToId(cx, index, &id))
+        return false;
+    return proxy_DefineProperty(cx, obj, id, value, getter, setter, attrs);
+}
+
+static JSBool
 proxy_GetProperty(JSContext *cx, JSObject *obj, JSObject *receiver, jsid id, Value *vp)
 {
     return JSProxy::get(cx, obj, receiver, id, vp);
 }
 
 static JSBool
+proxy_GetElement(JSContext *cx, JSObject *obj, JSObject *receiver, uint32 index, Value *vp)
+{
+    jsid id;
+    if (!IndexToId(cx, index, &id))
+        return false;
+    return proxy_GetProperty(cx, obj, receiver, id, vp);
+}
+
+static JSBool
 proxy_SetProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp, JSBool strict)
 {
     return JSProxy::set(cx, obj, obj, id, strict, vp);
 }
 
 static JSBool
+proxy_SetElement(JSContext *cx, JSObject *obj, uint32 index, Value *vp, JSBool strict)
+{
+    jsid id;
+    if (!IndexToId(cx, index, &id))
+        return false;
+    return proxy_SetProperty(cx, obj, id, vp, strict);
+}
+
+static JSBool
 proxy_GetAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp)
 {
     AutoPropertyDescriptorRooter desc(cx);
     if (!JSProxy::getOwnPropertyDescriptor(cx, obj, id, false, &desc))
         return false;
     *attrsp = desc.attrs;
     return true;
 }
 
 static JSBool
+proxy_GetElementAttributes(JSContext *cx, JSObject *obj, uint32 index, uintN *attrsp)
+{
+    jsid id;
+    if (!IndexToId(cx, index, &id))
+        return false;
+    return proxy_GetAttributes(cx, obj, id, attrsp);
+}
+
+static JSBool
 proxy_SetAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp)
 {
     /* Lookup the current property descriptor so we have setter/getter/value. */
     AutoPropertyDescriptorRooter desc(cx);
     if (!JSProxy::getOwnPropertyDescriptor(cx, obj, id, true, &desc))
         return false;
     desc.attrs = (*attrsp & (~JSPROP_SHORTID));
     return JSProxy::defineProperty(cx, obj, id, &desc);
 }
 
 static JSBool
+proxy_SetElementAttributes(JSContext *cx, JSObject *obj, uint32 index, uintN *attrsp)
+{
+    jsid id;
+    if (!IndexToId(cx, index, &id))
+        return false;
+    return proxy_SetAttributes(cx, obj, id, attrsp);
+}
+
+static JSBool
 proxy_DeleteProperty(JSContext *cx, JSObject *obj, jsid id, Value *rval, JSBool strict)
 {
     // TODO: throwing away strict
     bool deleted;
     if (!JSProxy::delete_(cx, obj, id, &deleted) || !js_SuppressDeletedProperty(cx, obj, id))
         return false;
     rval->setBoolean(deleted);
     return true;
 }
 
+static JSBool
+proxy_DeleteElement(JSContext *cx, JSObject *obj, uint32 index, Value *rval, JSBool strict)
+{
+    jsid id;
+    if (!IndexToId(cx, index, &id))
+        return false;
+    return proxy_DeleteProperty(cx, obj, id, rval, strict);
+}
+
 static void
 proxy_TraceObject(JSTracer *trc, JSObject *obj)
 {
     obj->getProxyHandler()->trace(trc, obj);
     MarkCrossCompartmentValue(trc, obj->getProxyPrivate(), "private");
     MarkCrossCompartmentValue(trc, obj->getProxyExtra(), "extra");
     if (obj->isFunctionProxy()) {
         MarkCrossCompartmentValue(trc, GetCall(obj), "call");
@@ -1041,22 +1106,29 @@ JS_FRIEND_DATA(Class) js::ObjectProxyCla
     NULL,                 /* call        */
     NULL,                 /* construct   */
     NULL,                 /* xdrObject   */
     proxy_HasInstance,    /* hasInstance */
     proxy_TraceObject,    /* trace       */
     JS_NULL_CLASS_EXT,
     {
         proxy_LookupProperty,
+        proxy_LookupElement,
         proxy_DefineProperty,
+        proxy_DefineElement,
         proxy_GetProperty,
+        proxy_GetElement,
         proxy_SetProperty,
+        proxy_SetElement,
         proxy_GetAttributes,
+        proxy_GetElementAttributes,
         proxy_SetAttributes,
+        proxy_SetElementAttributes,
         proxy_DeleteProperty,
+        proxy_DeleteElement,
         NULL,             /* enumerate       */
         proxy_TypeOf,
         proxy_Fix,        /* fix             */
         NULL,             /* thisObject      */
         NULL,             /* clear           */
     }
 };
 
@@ -1081,22 +1153,29 @@ JS_FRIEND_DATA(Class) js::OuterWindowPro
     {
         NULL,             /* equality    */
         NULL,             /* outerObject */
         proxy_innerObject,
         NULL        /* unused */
     },
     {
         proxy_LookupProperty,
+        proxy_LookupElement,
         proxy_DefineProperty,
+        proxy_DefineElement,
         proxy_GetProperty,
+        proxy_GetElement,
         proxy_SetProperty,
+        proxy_SetElement,
         proxy_GetAttributes,
+        proxy_GetElementAttributes,
         proxy_SetAttributes,
+        proxy_SetElementAttributes,
         proxy_DeleteProperty,
+        proxy_DeleteElement,
         NULL,             /* enumerate       */
         NULL,             /* typeof          */
         NULL,             /* fix             */
         NULL,             /* thisObject      */
         NULL,             /* clear           */
     }
 };
 
@@ -1133,22 +1212,29 @@ JS_FRIEND_DATA(Class) js::FunctionProxyC
     proxy_Call,
     proxy_Construct,
     NULL,                 /* xdrObject   */
     FunctionClass.hasInstance,
     proxy_TraceFunction,  /* trace       */
     JS_NULL_CLASS_EXT,
     {
         proxy_LookupProperty,
+        proxy_LookupElement,
         proxy_DefineProperty,
+        proxy_DefineElement,
         proxy_GetProperty,
+        proxy_GetElement,
         proxy_SetProperty,
+        proxy_SetElement,
         proxy_GetAttributes,
+        proxy_GetElementAttributes,
         proxy_SetAttributes,
+        proxy_SetElementAttributes,
         proxy_DeleteProperty,
+        proxy_DeleteElement,
         NULL,             /* enumerate       */
         proxy_TypeOf,
         NULL,             /* fix             */
         NULL,             /* thisObject      */
         NULL,             /* clear           */
     }
 };
 
--- a/js/src/jsprvtd.h
+++ b/js/src/jsprvtd.h
@@ -179,16 +179,17 @@ class HashSet;
 
 template <typename K,
           typename V,
           size_t InlineElems>
 class InlineMap;
 
 class PropertyCache;
 struct PropertyCacheEntry;
+struct PropertyDescriptor;
 
 struct Shape;
 struct EmptyShape;
 class Bindings;
 
 class MultiDeclRange;
 class ParseMapPool;
 class DefnOrHeader;
@@ -323,21 +324,16 @@ typedef struct JSDebugHooks {
  * exception, true on success.  On success, return null in *propp if id was
  * not found.  If id was found, return the first object searching from obj
  * along its prototype chain in which id names a direct property in *objp, and
  * return a non-null, opaque property pointer in *propp.
  *
  * If JSLookupPropOp succeeds and returns with *propp non-null, that pointer
  * may be passed as the prop parameter to a JSAttributesOp, as a short-cut
  * that bypasses id re-lookup.
- *
- * NB: successful return with non-null *propp means the implementation may
- * have locked *objp and added a reference count associated with *propp, so
- * callers should not risk deadlock by nesting or interleaving other lookups
- * or any obj-bearing ops before dropping *propp.
  */
 typedef JSBool
 (* JSLookupPropOp)(JSContext *cx, JSObject *obj, jsid id, JSObject **objp,
                    JSProperty **propp);
 
 /*
  * Get or set attributes of the property obj[id]. Return false on error or
  * exception, true with current attributes in *attrsp.
--- a/js/src/jsregexp.cpp
+++ b/js/src/jsregexp.cpp
@@ -189,16 +189,50 @@ js_ObjectIsRegExp(JSObject *obj)
 {
     return obj->isRegExp();
 }
 
 /*
  * js::RegExp
  */
 
+#if !ENABLE_YARR_JIT
+void
+RegExp::reportPCREError(JSContext *cx, int error)
+{
+#define REPORT(msg_) \
+    JS_ReportErrorFlagsAndNumberUC(cx, JSREPORT_ERROR, js_GetErrorMessage, NULL, msg_); \
+    return
+    switch (error) {
+      case -2: REPORT(JSMSG_REGEXP_TOO_COMPLEX);
+      case 0: JS_NOT_REACHED("Precondition violation: an error must have occurred."); 
+      case 1: REPORT(JSMSG_TRAILING_SLASH);
+      case 2: REPORT(JSMSG_TRAILING_SLASH); 
+      case 3: REPORT(JSMSG_REGEXP_TOO_COMPLEX);
+      case 4: REPORT(JSMSG_BAD_QUANTIFIER);
+      case 5: REPORT(JSMSG_BAD_QUANTIFIER);
+      case 6: REPORT(JSMSG_BAD_CLASS_RANGE);
+      case 7: REPORT(JSMSG_REGEXP_TOO_COMPLEX);
+      case 8: REPORT(JSMSG_BAD_CLASS_RANGE);
+      case 9: REPORT(JSMSG_BAD_QUANTIFIER);
+      case 10: REPORT(JSMSG_UNMATCHED_RIGHT_PAREN);
+      case 11: REPORT(JSMSG_REGEXP_TOO_COMPLEX);
+      case 12: REPORT(JSMSG_UNMATCHED_RIGHT_PAREN);
+      case 13: REPORT(JSMSG_REGEXP_TOO_COMPLEX);
+      case 14: REPORT(JSMSG_MISSING_PAREN);
+      case 15: REPORT(JSMSG_BAD_BACKREF);
+      case 16: REPORT(JSMSG_REGEXP_TOO_COMPLEX);
+      case 17: REPORT(JSMSG_REGEXP_TOO_COMPLEX);
+      default:
+        JS_NOT_REACHED("Precondition violation: unknown PCRE error code.");
+    }
+#undef REPORT
+}
+#endif
+
 void
 RegExp::reportYarrError(JSContext *cx, TokenStream *ts, JSC::Yarr::ErrorCode error)
 {
     switch (error) {
       case JSC::Yarr::NoError:
         JS_NOT_REACHED("Called reportYarrError with value for no error");
         return;
 #define COMPILE_EMSG(__code, __msg)                                                              \
--- a/js/src/jsregexpinlines.h
+++ b/js/src/jsregexpinlines.h
@@ -50,16 +50,18 @@
 
 #include "methodjit/MethodJIT.h"
 #include "assembler/wtf/Platform.h"
 #include "yarr/BumpPointerAllocator.h"
 
 #include "yarr/Yarr.h"
 #if ENABLE_YARR_JIT
 #include "yarr/YarrJIT.h"
+#else
+#include "yarr/pcre/pcre.h"
 #endif
 
 namespace js {
 
 /*
  * res = RegExp statics.
  */
 
@@ -93,53 +95,64 @@ regexp_statics_construct(JSContext *cx, 
  * Note: refCount cannot overflow because that would require more referring
  * regexp objects than there is space for in addressable memory.
  */
 class RegExp
 {
 #if ENABLE_YARR_JIT
     /* native code is valid only if codeBlock.isFallBack() == false */
     JSC::Yarr::YarrCodeBlock    codeBlock;
+    JSC::Yarr::BytecodePattern  *byteCode;
+#else
+    JSRegExp                    *compiled;
 #endif
-    JSC::Yarr::BytecodePattern  *byteCode;
     JSLinearString              *source;
     size_t                      refCount;
     unsigned                    parenCount; /* Must be |unsigned| to interface with YARR. */
     uint32                      flags;
 #ifdef DEBUG
   public:
     JSCompartment               *compartment;
 
   private:
 #endif
 
     RegExp(JSLinearString *source, uint32 flags, JSCompartment *compartment)
       :
 #if ENABLE_YARR_JIT
         codeBlock(),
+        byteCode(NULL),
+#else
+        compiled(NULL),
 #endif
-        byteCode(NULL), source(source), refCount(1), parenCount(0), flags(flags)
+        source(source), refCount(1), parenCount(0), flags(flags)
 #ifdef DEBUG
         , compartment(compartment)
 #endif
     { }
 
     JS_DECLARE_ALLOCATION_FRIENDS_FOR_PRIVATE_CONSTRUCTOR;
 
     ~RegExp() {
 #if ENABLE_YARR_JIT
         codeBlock.release();
-#endif
         if (byteCode)
             Foreground::delete_<JSC::Yarr::BytecodePattern>(byteCode);
+#else
+        if (compiled)
+            jsRegExpFree(compiled);
+#endif
     }
 
     bool compileHelper(JSContext *cx, JSLinearString &pattern, TokenStream *ts);
     bool compile(JSContext *cx, TokenStream *ts);
     static const uint32 allFlags = JSREG_FOLD | JSREG_GLOB | JSREG_MULTILINE | JSREG_STICKY;
+#if !ENABLE_YARR_JIT
+    void reportPCREError(JSContext *cx, int error);
+#endif
     void reportYarrError(JSContext *cx, TokenStream *ts, JSC::Yarr::ErrorCode error);
     static inline bool initArena(JSContext *cx);
     static inline void checkMatchPairs(JSString *input, int *buf, size_t matchItemCount);
     static JSObject *createResult(JSContext *cx, JSString *input, int *buf, size_t matchItemCount);
     inline bool executeInternal(JSContext *cx, RegExpStatics *res, JSString *input,
                                 size_t *lastIndex, bool test, Value *rval);
 
   public:
@@ -365,23 +378,30 @@ RegExp::executeInternal(JSContext *cx, R
 
     int result;
 #if ENABLE_YARR_JIT
     if (!codeBlock.isFallBack())
         result = JSC::Yarr::execute(codeBlock, chars, *lastIndex - inputOffset, len, buf);
     else
         result = JSC::Yarr::interpret(byteCode, chars, *lastIndex - inputOffset, len, buf);
 #else
-    result = JSC::Yarr::interpret(byteCode, chars, *lastIndex - inputOffset, len, buf);
+    result = jsRegExpExecute(cx, compiled, chars, len, *lastIndex - inputOffset, buf, bufCount);
 #endif
     if (result == -1) {
         *rval = NullValue();
         return true;
     }
 
+#if !ENABLE_YARR_JIT
+    if (result < 0) {
+        reportPCREError(cx, result);
+        return false;
+    }
+#endif
+
     /* 
      * Adjust buf for the inputOffset. Use of sticky is rare and the matchItemCount is small, so
      * just do another pass.
      */
     if (JS_UNLIKELY(inputOffset)) {
         for (size_t i = 0; i < matchItemCount; ++i)
             buf[i] = buf[i] < 0 ? -1 : buf[i] + inputOffset;
     }
@@ -467,42 +487,52 @@ EnableYarrJIT(JSContext *cx)
 #else
     return true;
 #endif
 }
 
 inline bool
 RegExp::compileHelper(JSContext *cx, JSLinearString &pattern, TokenStream *ts)
 {
+#if ENABLE_YARR_JIT
     JSC::Yarr::ErrorCode yarrError;
     JSC::Yarr::YarrPattern yarrPattern(pattern, ignoreCase(), multiline(), &yarrError);
     if (yarrError) {
         reportYarrError(cx, ts, yarrError);
         return false;
     }
     parenCount = yarrPattern.m_numSubpatterns;
 
-#if ENABLE_YARR_JIT && defined(JS_METHODJIT)
+#if defined(JS_METHODJIT)
     if (EnableYarrJIT(cx) && !yarrPattern.m_containsBackreferences) {
         bool ok = cx->compartment->ensureJaegerCompartmentExists(cx);
         if (!ok)
             return false;
         JSC::Yarr::JSGlobalData globalData(cx->compartment->jaegerCompartment()->execAlloc());
         JSC::Yarr::jitCompile(yarrPattern, &globalData, codeBlock);
         if (!codeBlock.isFallBack())
             return true;
     }
 #endif
 
-#if ENABLE_YARR_JIT
     codeBlock.setFallBack(true);
+    byteCode = JSC::Yarr::byteCompile(yarrPattern, cx->compartment->regExpAllocator).get();
+    return true;
+#else
+    int error = 0;
+    compiled = jsRegExpCompile(pattern.chars(), pattern.length(),
+        ignoreCase() ? JSRegExpIgnoreCase : JSRegExpDoNotIgnoreCase,
+        multiline() ? JSRegExpMultiline : JSRegExpSingleLine,
+        &parenCount, &error);
+    if (error) {
+        reportPCREError(cx, error);
+        return false;
+    }
+    return true;
 #endif
-    byteCode = JSC::Yarr::byteCompile(yarrPattern, cx->compartment->regExpAllocator).get();
-
-    return true;
 }
 
 inline bool
 RegExp::compile(JSContext *cx, TokenStream *ts)
 {
     /* Flatten source early for the rest of compilation. */
     if (!source->ensureLinear(cx))
         return false;
--- a/js/src/jsscope.h
+++ b/js/src/jsscope.h
@@ -246,23 +246,23 @@ struct PropertyTable {
     }
 
     /* By definition, hashShift = JS_DHASH_BITS - log2(capacity). */
     uint32 capacity() const { return JS_BIT(JS_DHASH_BITS - hashShift); }
 
     /* Computes the size of the entries array for a given capacity. */
     static size_t sizeOfEntries(size_t cap) { return cap * sizeof(Shape *); }
 
-    size_t sizeOf(size_t(*mus)(void *)) const {
-        if (mus) {
-            size_t usable = mus((void*)this) + mus(entries);
-            if (usable)
-                return usable;
-        }
-        return sizeOfEntries(capacity()) + sizeof(PropertyTable);
+    /*
+     * This counts the PropertyTable object itself (which must be
+     * heap-allocated) and its |entries| array.
+     */
+    size_t sizeOf(JSUsableSizeFun usf) const {
+        size_t usable = usf((void*)this) + usf(entries);
+        return usable ? usable : sizeOfEntries(capacity()) + sizeof(PropertyTable);
     }
 
     /* Whether we need to grow.  We want to do this if the load factor is >= 0.75 */
     bool needsToGrow() const {
         uint32 size = capacity();
         return entryCount + removedCount >= size - (size >> 2);
     }
 
@@ -352,16 +352,17 @@ struct Shape : public js::gc::Cell
   private:
     uint8               attrs;          /* attributes, see jsapi.h JSPROP_* */
     mutable uint8       flags;          /* flags, see below for defines */
   public:
     int16               shortid;        /* tinyid, or local arg/var index */
 
   protected:
     mutable js::Shape   *parent;        /* parent node, reverse for..in order */
+    /* kids is valid when !inDictionary(), listp is valid when inDictionary(). */
     union {
         mutable js::KidsPointer kids;   /* null, single child, or a tagged ptr
                                            to many-kids data structure */
         mutable js::Shape **listp;      /* dictionary list starting at lastProp
                                            has a double-indirect back pointer,
                                            either to shape->parent if not last,
                                            else to obj->lastProp */
     };
@@ -440,16 +441,27 @@ struct Shape : public js::gc::Cell
         return numLinearSearches > PropertyTable::MAX_LINEAR_SEARCHES;
     }
 
     js::PropertyTable *getTable() const {
         JS_ASSERT(hasTable());
         return table;
     }
 
+    size_t sizeOfPropertyTable(JSUsableSizeFun usf) const {
+        return hasTable() ? getTable()->sizeOf(usf) : 0;
+    }
+
+    size_t sizeOfKids(JSUsableSizeFun usf) const {
+        /* Nb: |countMe| is true because the kids HashTable is on the heap. */
+        return (!inDictionary() && kids.isHash())
+             ? kids.toHash()->sizeOf(usf, /* countMe */true)
+             : 0;
+    }
+
     bool isNative() const { return this != &sharedNonNative; }
 
     const js::Shape *previous() const {
         return parent;
     }
 
     class Range {
       protected:
--- a/js/src/jsscript.cpp
+++ b/js/src/jsscript.cpp
@@ -115,17 +115,17 @@ Bindings::add(JSContext *cx, JSAtom *nam
      * of the Call objects enumerable. ES5 reformulated all of its Clause 10 to
      * avoid objects as activations, something we should do too.
      */
     uintN attrs = JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED;
 
     uint16 *indexp;
     PropertyOp getter;
     StrictPropertyOp setter;
-    uint32 slot = JSObject::CALL_RESERVED_SLOTS;
+    uint32 slot = CallObject::RESERVED_SLOTS;
 
     if (kind == ARGUMENT) {
         JS_ASSERT(nvars == 0);
         JS_ASSERT(nupvars == 0);
         indexp = &nargs;
         getter = GetCallArg;
         setter = SetCallArg;
         slot += nargs;
@@ -1284,16 +1284,28 @@ JSScript::dataSize()
         return 0;
 #endif
 
     uint8 *dataEnd = code + length * sizeof(jsbytecode) + numNotes() * sizeof(jssrcnote);
     JS_ASSERT(dataEnd >= data);
     return dataEnd - data;
 }
 
+size_t
+JSScript::dataSize(JSUsableSizeFun usf)
+{
+#if JS_SCRIPT_INLINE_DATA_LIMIT
+    if (data == inlineData)
+        return 0;
+#endif
+
+    size_t usable = usf(data);
+    return usable ? usable : dataSize();
+}
+
 void
 JSScript::setOwnerObject(JSObject *owner)
 {
 #ifdef JS_CRASH_DIAGNOSTICS
     CheckScriptOwner(this, JS_NEW_SCRIPT);
     ownerObject = owner;
 #endif
 }
--- a/js/src/jsscript.h
+++ b/js/src/jsscript.h
@@ -678,25 +678,31 @@ struct JSScript : public js::gc::Cell {
         if (addr == NULL)
             return JITScript_None;
         if (addr == JS_UNJITTABLE_SCRIPT)
             return JITScript_Invalid;
         return JITScript_Valid;
     }
 
     /* Size of the JITScript and all sections.  (This method is implemented in MethodJIT.h.) */
-    JS_FRIEND_API(size_t) jitDataSize(size_t(*mus)(void *));
+    JS_FRIEND_API(size_t) jitDataSize(JSUsableSizeFun usf);
     
 #endif
 
     jsbytecode *main() {
         return code + mainOffset;
     }
 
-    JS_FRIEND_API(size_t) dataSize();   /* Size of all data sections */
+    /*
+     * The first dataSize() is the in-use size of all the data sections, the
+     * second is the size of the block allocated to hold all the data sections
+     * (which can be larger than the in-use size).
+     */
+    JS_FRIEND_API(size_t) dataSize();                       /* Size of all data sections */
+    JS_FRIEND_API(size_t) dataSize(JSUsableSizeFun usf);    /* Size of all data sections */
     uint32 numNotes();                  /* Number of srcnote slots in the srcnotes section */
 
     /* Script notes are allocated right after the code. */
     jssrcnote *notes() { return (jssrcnote *)(code + length); }
 
     static const uint8 INVALID_OFFSET = 0xFF;
     static bool isValidOffset(uint8 offset) { return offset != INVALID_OFFSET; }
 
--- a/js/src/jstracer.cpp
+++ b/js/src/jstracer.cpp
@@ -88,16 +88,17 @@
 #include "jspropertycacheinlines.h"
 #include "jsobjinlines.h"
 #include "jsscopeinlines.h"
 #include "jsscriptinlines.h"
 #include "jscntxtinlines.h"
 #include "jsopcodeinlines.h"
 #include "jstypedarrayinlines.h"
 
+#include "vm/CallObject-inl.h"
 #include "vm/Stack-inl.h"
 
 #ifdef JS_METHODJIT
 #include "methodjit/MethodJIT.h"
 #endif
 
 #include "tracejit/Writer-inl.h"
 
@@ -2493,43 +2494,53 @@ TraceMonitor::getCodeAllocStats(size_t &
     } else {
         total = 0;
         frag_size = 0;
         free_size = 0;
     }
 }
 
 size_t
-TraceMonitor::getVMAllocatorsMainSize() const
+TraceMonitor::getVMAllocatorsMainSize(JSUsableSizeFun usf) const
 {
     size_t n = 0;
     if (dataAlloc)
-        n += dataAlloc->getBytesAllocated();
+        n += dataAlloc->getBytesAllocated(usf);
     if (traceAlloc)
-        n += traceAlloc->getBytesAllocated();
+        n += traceAlloc->getBytesAllocated(usf);
     if (tempAlloc)
-        n += tempAlloc->getBytesAllocated();
+        n += tempAlloc->getBytesAllocated(usf);
     return n;
 }
 
 size_t
-TraceMonitor::getVMAllocatorsReserveSize() const
-{
-    return dataAlloc->mReserveSize +
-           traceAlloc->mReserveSize +
-           tempAlloc->mReserveSize;
+TraceMonitor::getVMAllocatorsReserveSize(JSUsableSizeFun usf) const
+{
+    size_t usable = usf(dataAlloc->mReserve) +
+                    usf(traceAlloc->mReserve) +
+                    usf(tempAlloc->mReserve);
+    return usable ? usable : dataAlloc->mReserveSize +
+                             traceAlloc->mReserveSize +
+                             tempAlloc->mReserveSize;
 }
 
 size_t
-TraceMonitor::getTraceMonitorSize() const
-{
-    return sizeof(TraceMonitor) +           // TraceMonitor
-           sizeof(*storage) +               // TraceNativeStorage
-           recordAttempts->tableSize() +    // RecordAttemptMap
-           loopProfiles->tableSize();       // LoopProfileMap
+TraceMonitor::getTraceMonitorSize(JSUsableSizeFun usf) const
+{
+    /*
+     * Measures: TraceMonitor, TraceNativeStorage, RecordAttemptMap,
+     * LoopProfileMap.  |countMe| is true for both sizeOf() calls because the
+     * two HashMaps are not inline in TraceMonitor.
+     */
+    size_t usableTM  = usf((void *)this);
+    size_t usableTNS = usf(storage);
+    return (usableTM  ? usableTM  : sizeof(*this)) +
+           (usableTNS ? usableTNS : sizeof(*storage)) +
+           recordAttempts->sizeOf(usf, /* countMe */true) +
+           loopProfiles->sizeOf(usf, /* countMe */true);
 }
 
 /*
  * This function destroys the recorder after a successful recording, possibly
  * starting a suspended outer recorder.
  */
 AbortableRecordingStatus
 TraceRecorder::finishSuccessfully()
@@ -3271,37 +3282,37 @@ public:
         debug_only_printf(LC_TMTracer, "%s%u=", stackSlotKind(), 0);
         JSObject *frameobj = *(JSObject **)mStack;
         JS_ASSERT((frameobj == NULL) == (*mTypeMap == JSVAL_TYPE_NULL));
         if (p == fp->addressOfArgs()) {
             if (frameobj) {
                 JS_ASSERT_IF(fp->hasArgsObj(), frameobj == &fp->argsObj());
                 fp->setArgsObj(*frameobj->asArguments());
                 if (frameobj->isNormalArguments())
-                    frameobj->setPrivate(fp);
+                    frameobj->asArguments()->setStackFrame(fp);
                 else
-                    JS_ASSERT(!frameobj->getPrivate());
+                    JS_ASSERT(!frameobj->asArguments()->maybeStackFrame());
                 debug_only_printf(LC_TMTracer,
                                   "argsobj<%p> ",
                                   (void *)frameobj);
             } else {
                 JS_ASSERT(!fp->hasArgsObj());
                 debug_only_print0(LC_TMTracer,
                                   "argsobj<null> ");
             }
             /* else, SynthesizeFrame has initialized fp->args.nactual */
         } else {
             JS_ASSERT(p == fp->addressOfScopeChain());
             if (frameobj->isCall() &&
-                !frameobj->getPrivate() &&
-                fp->maybeCalleev().toObjectOrNull() == frameobj->getCallObjCallee())
+                !frameobj->asCall().maybeStackFrame() &&
+                fp->maybeCalleev().toObjectOrNull() == frameobj->asCall().getCallee())
             {
                 JS_ASSERT(&fp->scopeChain() == StackFrame::sInvalidScopeChain);
-                frameobj->setPrivate(fp);
-                fp->setScopeChainWithOwnCallObj(*frameobj);
+                frameobj->asCall().setStackFrame(fp);
+                fp->setScopeChainWithOwnCallObj(frameobj->asCall());
             } else {
                 fp->setScopeChainNoCallObj(*frameobj);
             }
             debug_only_printf(LC_TMTracer,
                               "scopechain<%p> ",
                               (void *)frameobj);
         }
 #ifdef DEBUG
@@ -3524,17 +3535,17 @@ GetFromClosure(JSContext* cx, JSObject* 
             //   is different.
             JS_NOT_REACHED("JSOP_NAME variable found in outer trace");
         }
     }
 #endif
 
     // We already guarded on trace that we aren't touching an outer tree's entry frame
     VOUCH_DOES_NOT_REQUIRE_STACK();
-    StackFrame* fp = (StackFrame*) call->getPrivate();
+    StackFrame* fp = call->asCall().maybeStackFrame();
     JS_ASSERT(fp != cx->fp());
 
     Value v;
     if (fp) {
         v = T::get_slot(fp, cv->slot);
     } else {
         /*
          * Get the value from the object. We know we have a Call object, and
@@ -3562,22 +3573,22 @@ struct ArgClosureTraits
 
     // Get the right object slots to use our slot index with.
     static inline Value get_slot(JSObject* obj, unsigned slot) {
         return obj->getSlot(slot_offset(obj) + slot);
     }
 
     // Get the offset of our object slots from the object's slots pointer.
     static inline uint32 slot_offset(JSObject* obj) {
-        return JSObject::CALL_RESERVED_SLOTS;
+        return CallObject::RESERVED_SLOTS;
     }
 
     // Get the maximum slot index of this type that should be allowed
     static inline uint16 slot_count(JSObject* obj) {
-        return obj->getCallObjCalleeFunction()->nargs;
+        return obj->asCall().getCalleeFunction()->nargs;
     }
 
 private:
     ArgClosureTraits();
 };
 
 uint32 JS_FASTCALL
 GetClosureArg(JSContext* cx, JSObject* callee, const ClosureVarInfo* cv, double* result)
@@ -3593,22 +3604,22 @@ struct VarClosureTraits
         return fp->slots()[slot];
     }
 
     static inline Value get_slot(JSObject* obj, unsigned slot) {
         return obj->getSlot(slot_offset(obj) + slot);
     }
 
     static inline uint32 slot_offset(JSObject* obj) {
-        return JSObject::CALL_RESERVED_SLOTS +
-               obj->getCallObjCalleeFunction()->nargs;
+        return CallObject::RESERVED_SLOTS +
+               obj->asCall().getCalleeFunction()->nargs;
     }
 
     static inline uint16 slot_count(JSObject* obj) {
-        return obj->getCallObjCalleeFunction()->script()->bindings.countVars();
+        return obj->asCall().getCalleeFunction()->script()->bindings.countVars();
     }
 
 private:
     VarClosureTraits();
 };
 
 uint32 JS_FASTCALL
 GetClosureVar(JSContext* cx, JSObject* callee, const ClosureVarInfo* cv, double* result)
@@ -8134,19 +8145,20 @@ TraceRecorder::entryFrameIns() const
 }
 
 /*
  * Return the frame of a call object if that frame is part of the current
  * trace. |depthp| is an optional outparam: if it is non-null, it will be
  * filled in with the depth of the call object's frame relevant to cx->fp().
  */
 JS_REQUIRES_STACK StackFrame*
-TraceRecorder::frameIfInRange(JSObject* obj, unsigned* depthp) const
-{
-    StackFrame* ofp = (StackFrame*) obj->getPrivate();
+TraceRecorder::frameIfInRange(JSObject *obj, unsigned* depthp) const
+{
+    JS_ASSERT(obj->isCall() || obj->isArguments());
+    StackFrame* ofp = (StackFrame *) obj->getPrivate();
     StackFrame* fp = cx->fp();
     for (unsigned depth = 0; depth <= callDepth; ++depth) {
         if (fp == ofp) {
             if (depthp)
                 *depthp = depth;
             return ofp;
         }
         if (!(fp = fp->prev()))
@@ -8249,34 +8261,35 @@ TraceRecorder::callProp(JSObject* obj, J
     JSOp op = JSOp(*cx->regs().pc);
     uint32 setflags = (js_CodeSpec[op].format & (JOF_SET | JOF_INCDEC | JOF_FOR));
     if (setflags && !shape->writable())
         RETURN_STOP("writing to a read-only property");
 
     uintN slot = uint16(shape->shortid);
 
     vp = NULL;
-    StackFrame* cfp = (StackFrame*) obj->getPrivate();
+    CallObject &callobj = obj->asCall();
+    StackFrame* cfp = callobj.maybeStackFrame();
     if (cfp) {
         if (shape->getterOp() == GetCallArg) {
             JS_ASSERT(slot < cfp->numFormalArgs());
             vp = &cfp->formalArg(slot);
             nr.v = *vp;
         } else if (shape->getterOp() == GetCallVar) {
             JS_ASSERT(slot < cfp->numSlots());
             vp = &cfp->slots()[slot];
             nr.v = *vp;
         } else {
             RETURN_STOP("dynamic property of Call object");
         }
 
         // Now assert that our use of shape->shortid was in fact kosher.
         JS_ASSERT(shape->hasShortID());
 
-        if (frameIfInRange(obj)) {
+        if (frameIfInRange(&callobj)) {
             // At this point we are guaranteed to be looking at an active call oject
             // whose properties are stored in the corresponding StackFrame.
             ins = get(vp);
             nr.tracked = true;
             return RECORD_CONTINUE;
         }
     } else {
         // Call objects do not yet have shape->isMethod() properties, but they
@@ -12284,21 +12297,23 @@ TraceRecorder::setUpwardTrackedVar(Value
     }
 
     set(stackVp, v_ins, promote);
 
     return RECORD_CONTINUE;
 }
 
 JS_REQUIRES_STACK RecordingStatus
-TraceRecorder::setCallProp(JSObject *callobj, LIns *callobj_ins, const Shape *shape,
+TraceRecorder::setCallProp(JSObject *obj, LIns *callobj_ins, const Shape *shape,
                            LIns *v_ins, const Value &v)
 {
+    CallObject &callobj = obj->asCall();
+
     // Set variables in on-trace-stack call objects by updating the tracker.
-    StackFrame *fp = frameIfInRange(callobj);
+    StackFrame *fp = frameIfInRange(&callobj);
     if (fp) {
         if (shape->setterOp() == SetCallArg) {
             JS_ASSERT(shape->hasShortID());
             uintN slot = uint16(shape->shortid);
             Value *vp2 = &fp->formalArg(slot);
             CHECK_STATUS(setUpwardTrackedVar(vp2, v, v_ins));
             return RECORD_CONTINUE;
         }
@@ -12307,40 +12322,40 @@ TraceRecorder::setCallProp(JSObject *cal
             uintN slot = uint16(shape->shortid);
             Value *vp2 = &fp->slots()[slot];
             CHECK_STATUS(setUpwardTrackedVar(vp2, v, v_ins));
             return RECORD_CONTINUE;
         }
         RETURN_STOP("can't trace special CallClass setter");
     }
 
-    if (!callobj->getPrivate()) {
+    if (!callobj.maybeStackFrame()) {
         // Because the parent guard in guardCallee ensures this Call object
         // will be the same object now and on trace, and because once a Call
         // object loses its frame it never regains one, on trace we will also
         // have a null private in the Call object. So all we need to do is
         // write the value to the Call object's slot.
         intN slot = uint16(shape->shortid);
         if (shape->setterOp() == SetCallArg) {
-            JS_ASSERT(slot < ArgClosureTraits::slot_count(callobj));
-            slot += ArgClosureTraits::slot_offset(callobj);
+            JS_ASSERT(slot < ArgClosureTraits::slot_count(&callobj));
+            slot += ArgClosureTraits::slot_offset(obj);
         } else if (shape->setterOp() == SetCallVar) {
-            JS_ASSERT(slot < VarClosureTraits::slot_count(callobj));
-            slot += VarClosureTraits::slot_offset(callobj);
+            JS_ASSERT(slot < VarClosureTraits::slot_count(&callobj));
+            slot += VarClosureTraits::slot_offset(obj);
         } else {
             RETURN_STOP("can't trace special CallClass setter");
         }
 
         // Now assert that the shortid get we did above was ok. Have to do it
         // after the RETURN_STOP above, since in that case we may in fact not
         // have a valid shortid; but we don't use it in that case anyway.
         JS_ASSERT(shape->hasShortID());
 
         LIns* slots_ins = NULL;
-        stobj_set_slot(callobj, callobj_ins, slot, slots_ins, v, v_ins);
+        stobj_set_slot(&callobj, callobj_ins, slot, slots_ins, v, v_ins);
         return RECORD_CONTINUE;
     }
 
     // This is the hard case: we have a StackFrame private, but it's not in
     // range.  During trace execution we may or may not have a StackFrame
     // anymore.  Call the standard builtins, which handle that situation.
 
     // Set variables in off-trace-stack call objects by calling standard builtins.
@@ -14982,17 +14997,17 @@ TraceRecorder::record_JSOP_POPN()
 {
     return ARECORD_CONTINUE;
 }
 
 static inline bool
 IsFindableCallObj(JSObject *obj)
 {
     return obj->isCall() &&
-           (obj->callIsForEval() || obj->getCallObjCalleeFunction()->isHeavyweight());
+           (obj->asCall().isForEval() || obj->asCall().getCalleeFunction()->isHeavyweight());
 }
 
 /*
  * Generate LIR to reach |obj2| from |obj| by traversing the scope chain. The
  * generated code also ensures that any call objects found have not changed shape.
  *
  *      obj               starting object
  *      obj_ins           LIR instruction representing obj
@@ -15119,18 +15134,17 @@ TraceRecorder::record_JSOP_BINDNAME()
             JS_ASSERT(obj);
         }
 
         /*
          * If this is a strict mode eval frame, we will have a Call object for
          * it. For now just don't trace this case.
          */
         if (obj != globalObj) {
-            JS_ASSERT(obj->isCall());
-            JS_ASSERT(obj->callIsForEval());
+            JS_ASSERT(obj->asCall().isForEval());
             RETURN_STOP_A("BINDNAME within strict eval code");
         }
 
         /*
          * The trace is specialized to this global object. Furthermore, we know
          * it is the sole 'global' object on the scope chain: we set globalObj
          * to the scope chain element with no parent, and we reached it
          * starting from the function closure or the current scopeChain, so
--- a/js/src/jstracer.h
+++ b/js/src/jstracer.h
@@ -1267,17 +1267,17 @@ class TraceRecorder
         JSObject         *obj;           // Call object where name was found
         nanojit::LIns    *obj_ins;       // LIR value for obj
         js::Shape        *shape;         // shape name was resolved to
     };
 
     JS_REQUIRES_STACK nanojit::LIns* scopeChain();
     JS_REQUIRES_STACK nanojit::LIns* entryScopeChain() const;
     JS_REQUIRES_STACK nanojit::LIns* entryFrameIns() const;
-    JS_REQUIRES_STACK StackFrame* frameIfInRange(JSObject* obj, unsigned* depthp = NULL) const;
+    JS_REQUIRES_STACK StackFrame* frameIfInRange(JSObject *obj, unsigned* depthp = NULL) const;
     JS_REQUIRES_STACK RecordingStatus traverseScopeChain(JSObject *obj, nanojit::LIns *obj_ins, JSObject *obj2, nanojit::LIns *&obj2_ins);
     JS_REQUIRES_STACK AbortableRecordingStatus scopeChainProp(JSObject* obj, const Value*& vp, nanojit::LIns*& ins, NameResult& nr, JSObject **scopeObjp = NULL);
     JS_REQUIRES_STACK RecordingStatus callProp(JSObject* obj, JSProperty* shape, jsid id, const Value*& vp, nanojit::LIns*& ins, NameResult& nr);
 
     JS_REQUIRES_STACK nanojit::LIns* arg(unsigned n);
     JS_REQUIRES_STACK void arg(unsigned n, nanojit::LIns* i);
     JS_REQUIRES_STACK nanojit::LIns* var(unsigned n);
     JS_REQUIRES_STACK void var(unsigned n, nanojit::LIns* i);
--- a/js/src/jstypedarray.cpp
+++ b/js/src/jstypedarray.cpp
@@ -60,16 +60,17 @@
 #include "jsstaticcheck.h"
 #include "jsbit.h"
 #include "jsvector.h"
 #include "jstypedarray.h"
 #include "jsutil.h"
 
 #include "vm/GlobalObject.h"
 
+#include "jsatominlines.h"
 #include "jsinferinlines.h"
 #include "jsobjinlines.h"
 #include "jstypedarrayinlines.h"
 
 using namespace js;
 using namespace js::gc;
 using namespace js::types;
 
@@ -272,44 +273,73 @@ ArrayBuffer::obj_lookupProperty(JSContex
         *propp = NULL;
         return true;
     }
 
     return proto->lookupProperty(cx, id, objp, propp);
 }
 
 JSBool
+ArrayBuffer::obj_lookupElement(JSContext *cx, JSObject *obj, uint32 index,
+                               JSObject **objp, JSProperty **propp)
+{
+    jsid id;
+    if (!IndexToId(cx, index, &id))
+        return false;
+    return obj_lookupProperty(cx, obj, id, objp, propp);
+}
+
+JSBool
 ArrayBuffer::obj_defineProperty(JSContext *cx, JSObject *obj, jsid id, const Value *v,
                    PropertyOp getter, StrictPropertyOp setter, uintN attrs)
 {
     if (JSID_IS_ATOM(id, cx->runtime->atomState.byteLengthAtom))
         return true;
 
     JSObject *delegate = DelegateObject(cx, obj);
     if (!delegate)
         return false;
     return js_DefineProperty(cx, delegate, id, v, getter, setter, attrs);
 }
 
 JSBool
+ArrayBuffer::obj_defineElement(JSContext *cx, JSObject *obj, uint32 index, const Value *v,
+                   PropertyOp getter, StrictPropertyOp setter, uintN attrs)
+{
+    jsid id;
+    if (!IndexToId(cx, index, &id))
+        return false;
+    return obj_defineProperty(cx, obj, id, v, getter, setter, attrs);
+}
+
+JSBool
 ArrayBuffer::obj_getProperty(JSContext *cx, JSObject *obj, JSObject *receiver, jsid id, Value *vp)
 {
     obj = getArrayBuffer(obj);
     if (JSID_IS_ATOM(id, cx->runtime->atomState.byteLengthAtom)) {
         vp->setInt32(obj->arrayBufferByteLength());
         return true;
     }
 
     JSObject *delegate = DelegateObject(cx, obj);
     if (!delegate)
         return false;
     return js_GetProperty(cx, delegate, receiver, id, vp);
 }
 
 JSBool
+ArrayBuffer::obj_getElement(JSContext *cx, JSObject *obj, JSObject *receiver, uint32 index, Value *vp)
+{
+    jsid id;
+    if (!IndexToId(cx, index, &id))
+        return false;
+    return obj_getProperty(cx, obj, receiver, id, vp);
+}
+
+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)) {
         // setting __proto__ = null
         // effectively removes the prototype chain.
@@ -354,59 +384,95 @@ ArrayBuffer::obj_setProperty(JSContext *
     JSObject *delegate = DelegateObject(cx, obj);
     if (!delegate)
         return false;
 
     return js_SetPropertyHelper(cx, delegate, id, 0, vp, strict);
 }
 
 JSBool
+ArrayBuffer::obj_setElement(JSContext *cx, JSObject *obj, uint32 index, Value *vp, JSBool strict)
+{
+    jsid id;
+    if (!IndexToId(cx, index, &id))
+        return false;
+    return obj_setProperty(cx, obj, id, vp, strict);
+}
+
+JSBool
 ArrayBuffer::obj_getAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp)
 {
     if (JSID_IS_ATOM(id, cx->runtime->atomState.byteLengthAtom)) {
         *attrsp = JSPROP_PERMANENT | JSPROP_READONLY;
         return true;
     }
 
     JSObject *delegate = DelegateObject(cx, obj);
     if (!delegate)
         return false;
     return js_GetAttributes(cx, delegate, id, attrsp);
 }
 
 JSBool
+ArrayBuffer::obj_getElementAttributes(JSContext *cx, JSObject *obj, uint32 index, uintN *attrsp)
+{
+    jsid id;
+    if (!IndexToId(cx, index, &id))
+        return false;
+    return obj_getAttributes(cx, obj, id, attrsp);
+}
+
+JSBool
 ArrayBuffer::obj_setAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp)
 {
     if (JSID_IS_ATOM(id, cx->runtime->atomState.byteLengthAtom)) {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
                              JSMSG_CANT_SET_ARRAY_ATTRS);
         return false;
     }
 
     JSObject *delegate = DelegateObject(cx, obj);
     if (!delegate)
         return false;
     return js_SetAttributes(cx, delegate, id, attrsp);
 }
 
 JSBool
+ArrayBuffer::obj_setElementAttributes(JSContext *cx, JSObject *obj, uint32 index, uintN *attrsp)
+{
+    jsid id;
+    if (!IndexToId(cx, index, &id))
+        return false;
+    return obj_setAttributes(cx, obj, id, attrsp);
+}
+
+JSBool
 ArrayBuffer::obj_deleteProperty(JSContext *cx, JSObject *obj, jsid id, Value *rval, JSBool strict)
 {
     if (JSID_IS_ATOM(id, cx->runtime->atomState.byteLengthAtom)) {
         rval->setBoolean(false);
         return true;
     }
 
     JSObject *delegate = DelegateObject(cx, obj);
     if (!delegate)
         return false;
     return js_DeleteProperty(cx, delegate, id, rval, strict);
 }
 
 JSBool
+ArrayBuffer::obj_deleteElement(JSContext *cx, JSObject *obj, uint32 index, Value *rval, JSBool strict)
+{
+    jsid id;
+    if (!IndexToId(cx, index, &id))
+        return false;
+    return obj_deleteElement(cx, obj, index, rval, strict);
+}
+
+JSBool
 ArrayBuffer::obj_enumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op,
               Value *statep, jsid *idp)
 {
     statep->setNull();
     return true;
 }
 
 JSType
@@ -534,32 +600,60 @@ TypedArray::obj_lookupProperty(JSContext
         *propp = NULL;
         return true;
     }
 
     return proto->lookupProperty(cx, id, objp, propp);
 }
 
 JSBool
+TypedArray::obj_lookupElement(JSContext *cx, JSObject *obj, uint32 index,
+                              JSObject **objp, JSProperty **propp)
+{
+    jsid id;
+    if (!IndexToId(cx, index, &id))
+        return false;
+    return obj_lookupProperty(cx, obj, id, objp, propp);
+}
+
+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;
 }
 
 JSBool
+TypedArray::obj_getElementAttributes(JSContext *cx, JSObject *obj, uint32 index, uintN *attrsp)
+{
+    jsid id;
+    if (!IndexToId(cx, index, &id))
+        return false;
+    return obj_getAttributes(cx, obj, id, attrsp);
+}
+
+JSBool
 TypedArray::obj_setAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp)
 {
     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
                          JSMSG_CANT_SET_ARRAY_ATTRS);
     return false;
 }
 
+JSBool
+TypedArray::obj_setElementAttributes(JSContext *cx, JSObject *obj, uint32 index, uintN *attrsp)
+{
+    jsid id;
+    if (!IndexToId(cx, index, &id))
+        return false;
+    return obj_setAttributes(cx, obj, id, attrsp);
+}
+
 /* static */ int
 TypedArray::lengthOffset()
 {
     return JSObject::getFixedSlotOffset(FIELD_LENGTH) + offsetof(jsval_layout, s.payload);
 }
 
 /* static */ int
 TypedArray::dataOffset()
@@ -773,16 +867,25 @@ class TypedArrayTemplate
                 }
             }
         }
 
         return true;
     }
 
     static JSBool
+    obj_getElement(JSContext *cx, JSObject *obj, JSObject *receiver, uint32 index, Value *vp)
+    {
+        jsid id;
+        if (!IndexToId(cx, index, &id))
+            return false;
+        return obj_getProperty(cx, obj, receiver, id, vp);
+    }
+
+    static JSBool
     obj_setProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp, JSBool strict)
     {
         JSObject *tarray = getTypedArray(obj);
         JS_ASSERT(tarray);
 
         if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)) {
             vp->setNumber(getLength(tarray));
             return true;
@@ -850,27 +953,46 @@ class TypedArrayTemplate
             int32 n = js_DoubleToECMAInt32(d);
             setIndex(tarray, index, NativeType(n));
         }
 
         return true;
     }
 
     static JSBool
+    obj_setElement(JSContext *cx, JSObject *obj, uint32 index, Value *vp, JSBool strict)
+    {
+        jsid id;
+        if (!IndexToId(cx, index, &id))
+            return false;
+        return obj_setProperty(cx, obj, id, vp, strict);
+    }
+
+    static JSBool
     obj_defineProperty(JSContext *cx, JSObject *obj, jsid id, const Value *v,
                        PropertyOp getter, StrictPropertyOp setter, uintN attrs)
     {
         if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom))
             return true;
 
         Value tmp = *v;
         return obj_setProperty(cx, obj, id, &tmp, false);
     }
 
     static JSBool
+    obj_defineElement(JSContext *cx, JSObject *obj, uint32 index, const Value *v,
+                       PropertyOp getter, StrictPropertyOp setter, uintN attrs)
+    {
+        jsid id;
+        if (!IndexToId(cx, index, &id))
+            return false;
+        return obj_defineProperty(cx, obj, id, v, getter, setter, attrs);
+    }
+
+    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;
         }
 
         JSObject *tarray = TypedArray::getTypedArray(obj);
@@ -881,16 +1003,25 @@ class TypedArrayTemplate
             return true;
         }
 
         rval->setBoolean(true);
         return true;
     }
 
     static JSBool
+    obj_deleteElement(JSContext *cx, JSObject *obj, uint32 index, Value *rval, JSBool strict)
+    {
+        jsid id;
+        if (!IndexToId(cx, index, &id))
+            return false;
+        return obj_deleteProperty(cx, obj, id, rval, strict);
+    }
+
+    static JSBool
     obj_enumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op,
                   Value *statep, jsid *idp)
     {
         JSObject *tarray = getTypedArray(obj);
         JS_ASSERT(tarray);
 
         /*
          * Iteration is "length" (if JSENUMERATE_INIT_ALL), then [0, length).
@@ -1713,22 +1844,29 @@ Class js::ArrayBufferClass = {
     NULL,           /* call        */
     NULL,           /* construct   */
     NULL,           /* xdrObject   */
     NULL,           /* hasInstance */
     ArrayBuffer::obj_trace,
     JS_NULL_CLASS_EXT,
     {
         ArrayBuffer::obj_lookupProperty,
+        ArrayBuffer::obj_lookupElement,
         ArrayBuffer::obj_defineProperty,
+        ArrayBuffer::obj_defineElement,
         ArrayBuffer::obj_getProperty,
+        ArrayBuffer::obj_getElement,
         ArrayBuffer::obj_setProperty,
+        ArrayBuffer::obj_setElement,
         ArrayBuffer::obj_getAttributes,
+        ArrayBuffer::obj_getElementAttributes,
         ArrayBuffer::obj_setAttributes,
+        ArrayBuffer::obj_setElementAttributes,
         ArrayBuffer::obj_deleteProperty,
+        ArrayBuffer::obj_deleteElement,
         ArrayBuffer::obj_enumerate,
         ArrayBuffer::obj_typeOf,
         NULL,       /* thisObject      */
         NULL,       /* clear           */
     }
 };
 
 JSPropertySpec ArrayBuffer::jsprops[] = {
@@ -1804,22 +1942,29 @@ JSFunctionSpec _typedArray::jsfuncs[] = 
     NULL,           /* call        */                                          \
     NULL,           /* construct   */                                          \
     NULL,           /* xdrObject   */                                          \
     NULL,           /* hasInstance */                                          \
     _typedArray::obj_trace,           /* trace       */                                          \
     JS_NULL_CLASS_EXT,                                                         \
     {                                                                          \
         _typedArray::obj_lookupProperty,                                       \
+        _typedArray::obj_lookupElement,                                        \
         _typedArray::obj_defineProperty,                                       \
+        _typedArray::obj_defineElement,                                        \
         _typedArray::obj_getProperty,                                          \
+        _typedArray::obj_getElement,                                           \
         _typedArray::obj_setProperty,                                          \
+        _typedArray::obj_setElement,                                           \
         _typedArray::obj_getAttributes,                                        \
+        _typedArray::obj_getElementAttributes,                                 \
         _typedArray::obj_setAttributes,                                        \
+        _typedArray::obj_setElementAttributes,                                 \
         _typedArray::obj_deleteProperty,                                       \
+        _typedArray::obj_deleteElement,                                        \
         _typedArray::obj_enumerate,                                            \
         _typedArray::obj_typeOf,                                               \
         NULL,       /* thisObject      */                                      \
         NULL,       /* clear           */                                      \
     }                                                                          \
 }
 
 template<class ArrayType>
--- a/js/src/jstypedarray.h
+++ b/js/src/jstypedarray.h
@@ -74,35 +74,58 @@ struct JS_FRIEND_API(ArrayBuffer) {
     static void
     obj_trace(JSTracer *trc, JSObject *obj);
 
     static JSBool
     obj_lookupProperty(JSContext *cx, JSObject *obj, jsid id,
                        JSObject **objp, JSProperty **propp);
 
     static JSBool
+    obj_lookupElement(JSContext *cx, JSObject *obj, uint32 index,
+                      JSObject **objp, JSProperty **propp);
+
+    static JSBool
     obj_defineProperty(JSContext *cx, JSObject *obj, jsid id, const Value *v,
                        PropertyOp getter, StrictPropertyOp setter, uintN attrs);
 
     static JSBool
+    obj_defineElement(JSContext *cx, JSObject *obj, uint32 index, const Value *v,
+                      PropertyOp getter, StrictPropertyOp setter, uintN attrs);
+
+    static JSBool
     obj_getProperty(JSContext *cx, JSObject *obj, JSObject *receiver, jsid id, Value *vp);
 
     static JSBool
+    obj_getElement(JSContext *cx, JSObject *obj, JSObject *receiver, uint32 index, Value *vp);
+
+    static JSBool
     obj_setProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp, JSBool strict);
 
     static JSBool
+    obj_setElement(JSContext *cx, JSObject *obj, uint32 index, Value *vp, JSBool strict);
+
+    static JSBool
     obj_getAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp);
 
     static JSBool
+    obj_getElementAttributes(JSContext *cx, JSObject *obj, uint32 index, uintN *attrsp);
+
+    static JSBool
     obj_setAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp);
 
     static JSBool
+    obj_setElementAttributes(JSContext *cx, JSObject *obj, uint32 index, uintN *attrsp);
+
+    static JSBool