Merge services-central and mozilla-central
authorPhilipp von Weitershausen <philipp@weitershausen.de>
Thu, 08 Sep 2011 15:32:54 -0700
changeset 76752 41a6dc9025cb67e258aa2cb9f2238d4a9ae98873
parent 76751 05c913f50c3e967da2acdcceb13013795627114c (current diff)
parent 76740 817c2b9dc11d7d39d91cd1f376e673cb87dc9b77 (diff)
child 76769 b57d50c6c0469330e0a4c9c460203c644f64f820
child 77252 42cd2123ad10059497fc1dcf88a1ac6dfcf5def7
push id3
push userfelipc@gmail.com
push dateFri, 30 Sep 2011 20:09:13 +0000
milestone9.0a1
Merge services-central and mozilla-central
extensions/spellcheck/tests/Makefile.in
extensions/spellcheck/tests/chrome/Makefile.in
extensions/spellcheck/tests/chrome/base/Makefile.in
extensions/spellcheck/tests/chrome/base/base_utf.aff
extensions/spellcheck/tests/chrome/base/base_utf.dic
extensions/spellcheck/tests/chrome/map/Makefile.in
extensions/spellcheck/tests/chrome/map/maputf.aff
extensions/spellcheck/tests/chrome/map/maputf.dic
extensions/spellcheck/tests/chrome/test_add_remove_dictionaries.xul
js/src/jsapi-tests/testGCChunkAlloc.cpp
services/sync/tests/unit/test_errorhandler.js
--- 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
@@ -316,18 +316,20 @@ nsContextMenu.prototype = {
                   !this.onTextInput && top.gBidiUI);
   },
 
   initSpellingItems: function() {
     var canSpell = InlineSpellCheckerUI.canSpellCheck;
     var onMisspelling = InlineSpellCheckerUI.overMisspelling;
     this.showItem("spell-check-enabled", canSpell);
     this.showItem("spell-separator", canSpell || this.onEditableArea);
-    document.getElementById("spell-check-enabled")
-            .setAttribute("checked", canSpell && InlineSpellCheckerUI.enabled);
+    if (canSpell) {
+      document.getElementById("spell-check-enabled")
+              .setAttribute("checked", InlineSpellCheckerUI.enabled);
+    }
 
     this.showItem("spell-add-to-dictionary", onMisspelling);
 
     // suggestion list
     this.showItem("spell-suggestions-separator", onMisspelling);
     if (onMisspelling) {
       var suggestionsSeparator =
         document.getElementById("spell-add-to-dictionary");
@@ -1029,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;
@@ -1055,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/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -4034,21 +4034,24 @@
       <handler event="mouseout">
         var anonid = event.originalTarget.getAttribute("anonid");
         if (anonid == "close-button")
           this.mOverCloseButton = false;
       </handler>
       <handler event="dragstart" phase="capturing">
         this.style.MozUserFocus = '';
       </handler>
-      <handler event="mousedown">
+      <handler event="mousedown" phase="capturing">
       <![CDATA[
         if (this.selected) {
           this.style.MozUserFocus = 'ignore';
           this.clientTop; // just using this to flush style updates
+        } else if (this.mOverCloseButton) {
+          // Prevent tabbox.xml from selecting the tab.
+          event.stopPropagation();
         }
       ]]>
       </handler>
       <handler event="mouseup">
         this.style.MozUserFocus = '';
       </handler>
     </handlers>
   </binding>
--- 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/components/wintaskbar/WindowsJumpLists.jsm
+++ b/browser/components/wintaskbar/WindowsJumpLists.jsm
@@ -17,16 +17,17 @@
  * The Initial Developer of the Original Code is
  * the Mozilla Foundation.
  * Portions created by the Initial Developer are Copyright (C) 2009
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *   Jim Mathies <jmathies@mozilla.com> (Original author)
  *   Marco Bonardo <mak77@bonardo.net>
+ *   Brian R. Bondy <netzen@gmail.com>
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either the GNU General Public License Version 2 or later (the "GPL"), or
  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  * in which case the provisions of the GPL or the LGPL are applicable instead
  * of those above. If you wish to allow use of your version of this file only
  * under the terms of either the GPL or the LGPL, and not to allow others to
  * use your version of this file under the terms of the MPL, indicate your
@@ -326,17 +327,17 @@ var WinTaskbarJumpList =
 
   _buildTasks: function WTBJL__buildTasks() {
     var items = Cc["@mozilla.org/array;1"].
                 createInstance(Ci.nsIMutableArray);
     this._tasks.forEach(function (task) {
       if ((this._shuttingDown && !task.close) || (!this._shuttingDown && !task.open))
         return;
       var item = this._getHandlerAppItem(task.title, task.description,
-                                         task.args, task.iconIndex);
+                                         task.args, task.iconIndex, null);
       items.appendElement(item, false);
     }, this);
     
     if (items.length > 0)
       this._builder.addListToBuild(this._builder.JUMPLIST_CATEGORY_TASKS, items);
   },
 
   _buildCustom: function WTBJL__buildCustom(title, items) {
@@ -369,17 +370,19 @@ var WinTaskbarJumpList =
           delete this._pendingStatements[LIST_TYPE.FREQUENT];
           // The are no more results, build the list.
           this._buildCustom(_getString("taskbar.frequent.label"), items);
           this._commitBuild();
           return;
         }
 
         let title = aResult.title || aResult.uri;
-        let shortcut = this._getHandlerAppItem(title, title, aResult.uri, 1);
+        let faviconPageUri = Services.io.newURI(aResult.uri, null, null);
+        let shortcut = this._getHandlerAppItem(title, title, aResult.uri, 1, 
+                                               faviconPageUri);
         items.appendElement(shortcut, false);
         this._frequentHashList.push(aResult.uri);
       },
       this
     );
   },
 
   _buildRecent: function WTBJL__buildRecent() {
@@ -412,33 +415,37 @@ var WinTaskbarJumpList =
 
         // Do not add items to recent that have already been added to frequent.
         if (this._frequentHashList &&
             this._frequentHashList.indexOf(aResult.uri) != -1) {
           return;
         }
 
         let title = aResult.title || aResult.uri;
-        let shortcut = this._getHandlerAppItem(title, title, aResult.uri, 1);
+        let faviconPageUri = Services.io.newURI(aResult.uri, null, null);
+        let shortcut = this._getHandlerAppItem(title, title, aResult.uri, 1,
+                                               faviconPageUri);
         items.appendElement(shortcut, false);
         count++;
       },
       this
     );
   },
 
   _deleteActiveJumpList: function WTBJL__deleteAJL() {
     this._builder.deleteActiveList();
   },
 
   /**
    * Jump list item creation helpers
    */
 
-  _getHandlerAppItem: function WTBJL__getHandlerAppItem(name, description, args, icon) {
+  _getHandlerAppItem: function WTBJL__getHandlerAppItem(name, description, 
+                                                        args, iconIndex, 
+                                                        faviconPageUri) {
     var file = Services.dirsvc.get("XCurProcD", Ci.nsILocalFile);
 
     // XXX where can we grab this from in the build? Do we need to?
     file.append("firefox.exe");
 
     var handlerApp = Cc["@mozilla.org/uriloader/local-handler-app;1"].
                      createInstance(Ci.nsILocalHandlerApp);
     handlerApp.executable = file;
@@ -446,17 +453,18 @@ var WinTaskbarJumpList =
     if (name && name.length != 0)
       handlerApp.name = name;
     handlerApp.detailedDescription = description;
     handlerApp.appendParameter(args);
 
     var item = Cc["@mozilla.org/windows-jumplistshortcut;1"].
                createInstance(Ci.nsIJumpListShortcut);
     item.app = handlerApp;
-    item.iconIndex = icon;
+    item.iconIndex = iconIndex;
+    item.faviconPageUri = faviconPageUri;
     return item;
   },
 
   _getSeparatorItem: function WTBJL__getSeparatorItem() {
     var item = Cc["@mozilla.org/windows-jumplistseparator;1"].
                createInstance(Ci.nsIJumpListSeparator);
     return item;
   },
--- 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/locales/en-US/searchplugins/list.txt
+++ b/browser/locales/en-US/searchplugins/list.txt
@@ -1,6 +1,7 @@
 amazondotcom
 bing
 eBay
 google
+twitter
 wikipedia
 yahoo
new file mode 100644
--- /dev/null
+++ b/browser/locales/en-US/searchplugins/twitter.xml
@@ -0,0 +1,11 @@
+<SearchPlugin xmlns="http://www.mozilla.org/2006/browser/search/">
+<ShortName>Twitter</ShortName>
+<Description>Realtime Twitter Search</Description>
+<InputEncoding>UTF-8</InputEncoding>
+<Image width="16" height="16">data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/v7+D/7+/j/+/v5g/v7+YP7+/mD+/v5I/v7+KP///wD///8A////AP///wD///8A////AP///wD+/v4H/v7+UPbv4pHgx47B1K9Y3tWwWN7Ur1je3sKCx+rbuKj+/v5n/v7+GP///wD///8A////AP///wD+/v4Y+fbweM2ycMe2iB7/vI0f/8STIf/KlyL/zJki/8yZIv/LmCL/0ahK5/Hp1JH+/v4Y////AP///wD///8A7OTTaquHN+CujkXPs5ZTv6N6G/+2iB7/xpUh/8yZIv/MmSL/zJki/8yZIv/Kmy738OjUi////wD///8A////AMKtfY7w6+Ef////AP///wD///8A3sqbp8iWIf/MmSL/zJki/8yZIv/MmSL/y5gi/8mePO7+/v4w////AP///wD///8A////AP///wD+/v4H/v7+V9CtWN3KmCL/zJki/8yZIv/MmSL/zJki/8yZIv/JlyH/5tSqp/7+/mD+/v4/////AP///wD///8A+PXvJtGyZdXNnS/3y5gi/8qYIv/LmCL/zJki/8yZIv/MmSL/y5gi/82iPO7LqVfe0byMmf///wD///8A/v7+D/Do1JHKmy73ypci/8KSIP+/jyD/xpQh/8uYIv/MmSL/zJki/8qYIv+/jyD/rIEd/9nKqH7///8A////APPu4TzAlSz3wZEg/7mLH/+sgR3/uZdGz7mLH//JlyH/zJki/8yZIv/GlSH/to0r9eXbxD/Vx6dg////AP7+/h/p38WhtIsq9al/HP+kfyjuybaKgf///wCzjzjlwJAg/8qYIv/JlyH/u4wf/8CkYrn///8A////AP///wDj2sRMnHUa/7meYa7Vx6dg////AP///wD///8A2MmnYK6DHf++jiD/vo4g/62CHf/k2sQ/////AP///wD///8A8OvhH/f07w////8A////AP///wD///8A////AP///wC/p3Cfpnwc/66GKvPg1LZ8////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////ANXHp2DJtoqByLWKgf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A//8AAP//AADgPwAAwA8AAIAHAAB4BwAA+AMAAPAAAADgAQAA4AMAAMEDAADPhwAA/48AAP/nAAD//wAA//8AAA==</Image>
+<SearchForm>https://twitter.com/search/</SearchForm>
+<Url type="text/html" method="GET" template="https://twitter.com/search/{searchTerms}">
+  <Param name="partner" value="Firefox"/>
+  <Param name="source" value="desktop-search"/>
+</Url>
+</SearchPlugin>
--- 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/autoconf/mozconfig-find
+++ b/build/autoconf/mozconfig-find
@@ -35,18 +35,20 @@
 # 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 *****
 
 # mozconfigfind - Loads options from .mozconfig onto configure's
 #    command-line. The .mozconfig file is searched for in the 
 #    order:
-#       if $MOZCONFIG is set, use that.
-#       Otherwise, use $TOPSRCDIR/.mozconfig
+#       If $MOZCONFIG is set, use that.
+#       If one of $TOPSRCDIR/.mozconfig or $TOPSRCDIR/mozconfig exists, use it.
+#       If both exist, or if various legacy locations contain a mozconfig, error.
+#       Otherwise, use the default build options.
 #
 topsrcdir=$1
 
 abspath() {
   if uname -s | grep -q MINGW; then
     # We have no way to figure out whether we're in gmake or pymake right
     # now. gmake gives us Unix-style paths while pymake gives us Windows-style
     # paths, so attempt to handle both.
@@ -71,30 +73,35 @@ if [ -n "$MOZCONFIG" ] && ! [ -f "$MOZCO
   exit 1
 fi
 
 if [ -n "$MOZ_MYCONFIG" ]; then
   echo "Your environment currently has the MOZ_MYCONFIG variable set to \"$MOZ_MYCONFIG\". MOZ_MYCONFIG is no longer supported. Please use MOZCONFIG instead."
   exit 1
 fi
 
+if [ -z "$MOZCONFIG" ] && [ -f "$topsrcdir/.mozconfig" ] && [ -f "$topsrcdir/mozconfig" ]; then
+  echo "Both \$topsrcdir/.mozconfig and \$topsrcdir/mozconfig are supported, but you must choose only one. Please remove the other."
+  exit 1
+fi
+
 for _config in "$MOZCONFIG" \
-               "$topsrcdir/.mozconfig"
+               "$topsrcdir/.mozconfig" \
+               "$topsrcdir/mozconfig"
 do
   if test -f "$_config"; then
     echo `abspath $_config`
     exit 0
   fi
 done
 
 # We used to support a number of other implicit .mozconfig locations. We now
 # detect if we were about to use any of these locations and issue an error if we
 # find any.
-for _config in "$topsrcdir/mozconfig" \
-               "$topsrcdir/mozconfig.sh" \
+for _config in "$topsrcdir/mozconfig.sh" \
                "$topsrcdir/myconfig.sh" \
                "$HOME/.mozconfig" \
                "$HOME/.mozconfig.sh" \
                "$HOME/.mozmyconfig.sh"
 do
   if test -f "$_config"; then
     echo "You currently have a mozconfig at \"$_config\". This implicit location is no longer supported. Please move it to $topsrcdir/.mozconfig or specify it explicitly via \$MOZCONFIG.";
     exit 1
--- 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/config/optimizejars.py
+++ b/config/optimizejars.py
@@ -298,16 +298,17 @@ def optimizejar(jar, outjar, inlog = Non
 
     if inlog is None:
         dirend.cdir_offset = out_offset
 
     if dups_found > 0:
         print("WARNING: Found %d duplicate files taking %d bytes"%(dups_found, dupe_bytes))
 
     dirend.cdir_size = len(cdir_data)
+    dirend.disk_entries = dirend.cdir_entries
     dirend_data = dirend.pack()
     assert_true(size_of(cdir_end) == len(dirend_data), "Failed to serialize directory end correctly. Serialized size;%d, expected:%d"%(len(dirend_data), size_of(cdir_end)));
 
     outfd.seek(dirend.cdir_offset)
     outfd.write(cdir_data)
     outfd.write(dirend_data)
 
     # for ordered jars the central directory is written in the begining of the file, so a second central-directory
--- a/content/base/public/nsContentUtils.h
+++ b/content/base/public/nsContentUtils.h
@@ -78,16 +78,17 @@ static fp_except_t oldmask = fpsetmask(~
 #include "nsReadableUtils.h"
 #include "mozilla/AutoRestore.h"
 #include "nsINode.h"
 #include "nsHashtable.h"
 #include "nsIDOMNode.h"
 #include "nsHtml5Parser.h"
 #include "nsIFragmentContentSink.h"
 #include "nsMathUtils.h"
+#include "mozilla/TimeStamp.h"
 
 struct nsNativeKeyEvent; // Don't include nsINativeKeyBindings.h here: it will force strange compilation error!
 
 class nsIDOMScriptObjectFactory;
 class nsIXPConnect;
 class nsIContent;
 class nsIDOMKeyEvent;
 class nsIDocument;
@@ -184,16 +185,17 @@ struct nsShortcutCandidate {
   PRUint32 mCharCode;
   PRBool   mIgnoreShift;
 };
 
 class nsContentUtils
 {
   friend class nsAutoScriptBlockerSuppressNodeRemoved;
   typedef mozilla::dom::Element Element;
+  typedef mozilla::TimeDuration TimeDuration;
 
 public:
   static nsresult Init();
 
   /**
    * Get a JSContext from the document's scope object.
    */
   static JSContext* GetContextFromDocument(nsIDocument *aDocument);
@@ -1715,16 +1717,23 @@ public:
 
   /**
    * Returns PR_TRUE if key input is restricted in DOM full-screen mode
    * to non-alpha-numeric key codes only. This mirrors the
    * "full-screen-api.key-input-restricted" pref.
    */
   static PRBool IsFullScreenKeyInputRestricted();
 
+  /**
+   * Returns the time limit on handling user input before
+   * nsEventStateManager::IsHandlingUserInput() stops returning PR_TRUE.
+   * This enables us to detect long running user-generated event handlers.
+   */
+  static TimeDuration HandlingUserInputTimeout();
+
   static void GetShiftText(nsAString& text);
   static void GetControlText(nsAString& text);
   static void GetMetaText(nsAString& text);
   static void GetAltText(nsAString& text);
   static void GetModifierSeparatorText(nsAString& text);
 
   /**
    * Returns if aContent has a tabbable subdocument.
@@ -1882,16 +1891,17 @@ private:
 
   static nsIInterfaceRequestor* sSameOriginChecker;
 
   static PRBool sIsHandlingKeyBoardEvent;
   static PRBool sAllowXULXBL_for_file;
   static PRBool sIsFullScreenApiEnabled;
   static PRBool sTrustedFullScreenOnly;
   static PRBool sFullScreenKeyInputRestricted;
+  static PRUint32 sHandlingInputTimeout;
 
   static nsHtml5Parser* sHTMLFragmentParser;
   static nsIParser* sXMLFragmentParser;
   static nsIFragmentContentSink* sXMLFragmentSink;
 
   static nsString* sShiftText;
   static nsString* sControlText;
   static nsString* sMetaText;
--- 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/nsContentUtils.cpp
+++ b/content/base/src/nsContentUtils.cpp
@@ -196,16 +196,17 @@ static NS_DEFINE_CID(kXTFServiceCID, NS_
 #include "nsChannelPolicy.h"
 #include "nsIContentSecurityPolicy.h"
 #include "nsContentDLF.h"
 #ifdef MOZ_MEDIA
 #include "nsHTMLMediaElement.h"
 #endif
 #include "nsDOMTouchEvent.h"
 #include "nsIScriptElement.h"
+#include "prdtoa.h"
 
 #include "mozilla/Preferences.h"
 
 using namespace mozilla::dom;
 using namespace mozilla::layers;
 using namespace mozilla;
 
 const char kLoadAsData[] = "loadAsData";
@@ -261,16 +262,18 @@ nsString* nsContentUtils::sMetaText = ns
 nsString* nsContentUtils::sAltText = nsnull;
 nsString* nsContentUtils::sModifierSeparator = nsnull;
 
 PRBool nsContentUtils::sInitialized = PR_FALSE;
 PRBool nsContentUtils::sIsFullScreenApiEnabled = PR_FALSE;
 PRBool nsContentUtils::sTrustedFullScreenOnly = PR_TRUE;
 PRBool nsContentUtils::sFullScreenKeyInputRestricted = PR_TRUE;
 
+PRUint32 nsContentUtils::sHandlingInputTimeout = 1000;
+
 nsHtml5Parser* nsContentUtils::sHTMLFragmentParser = nsnull;
 nsIParser* nsContentUtils::sXMLFragmentParser = nsnull;
 nsIFragmentContentSink* nsContentUtils::sXMLFragmentSink = nsnull;
 
 static PLDHashTable sEventListenerManagersHash;
 
 class EventListenerManagerMapEntry : public PLDHashEntryHdr
 {
@@ -314,16 +317,23 @@ EventListenerManagerHashClearEntry(PLDHa
 class nsSameOriginChecker : public nsIChannelEventSink,
                             public nsIInterfaceRequestor
 {
   NS_DECL_ISUPPORTS
   NS_DECL_NSICHANNELEVENTSINK
   NS_DECL_NSIINTERFACEREQUESTOR
 };
 
+/* static */
+TimeDuration
+nsContentUtils::HandlingUserInputTimeout()
+{
+  return TimeDuration::FromMilliseconds(sHandlingInputTimeout);
+}
+
 // static
 nsresult
 nsContentUtils::Init()
 {
   if (sInitialized) {
     NS_WARNING("Init() called twice");
 
     return NS_OK;
@@ -392,16 +402,20 @@ nsContentUtils::Init()
                                "full-screen-api.enabled");
 
   Preferences::AddBoolVarCache(&sTrustedFullScreenOnly,
                                "full-screen-api.allow-trusted-requests-only");
 
   Preferences::AddBoolVarCache(&sFullScreenKeyInputRestricted,
                                "full-screen-api.key-input-restricted");
 
+  Preferences::AddUintVarCache(&sHandlingInputTimeout,
+                               "dom.event.handling-user-input-time-limit",
+                               1000);
+
   sInitialized = PR_TRUE;
 
   return NS_OK;
 }
 
 void
 nsContentUtils::GetShiftText(nsAString& text)
 {
--- 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/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();
--- a/content/events/src/nsEventStateManager.cpp
+++ b/content/events/src/nsEventStateManager.cpp
@@ -170,16 +170,18 @@ static nsITimerCallback* gUserInteractio
 // Pixel scroll accumulation for synthetic line scrolls
 static nscoord gPixelScrollDeltaX = 0;
 static nscoord gPixelScrollDeltaY = 0;
 static PRUint32 gPixelScrollDeltaTimeout = 0;
 
 static nscoord
 GetScrollableLineHeight(nsIFrame* aTargetFrame);
 
+TimeStamp nsEventStateManager::sHandlingInputStart;
+
 static inline PRBool
 IsMouseEventReal(nsEvent* aEvent)
 {
   NS_ABORT_IF_FALSE(NS_IS_MOUSE_EVENT_STRUCT(aEvent), "Not a mouse event");
   // Return true if not synthesized.
   return static_cast<nsMouseEvent*>(aEvent)->reason == nsMouseEvent::eReal;
 }
 
--- a/content/events/src/nsEventStateManager.h
+++ b/content/events/src/nsEventStateManager.h
@@ -52,16 +52,18 @@
 #include "nsIFrameLoader.h"
 #include "nsIFrame.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsIMarkupDocumentViewer.h"
 #include "nsIScrollableFrame.h"
 #include "nsFocusManager.h"
 #include "nsIDocument.h"
 #include "nsEventStates.h"
+#include "mozilla/TimeStamp.h"
+#include "nsContentUtils.h"
 
 class nsIPresShell;
 class nsIDocShell;
 class nsIDocShellTreeNode;
 class nsIDocShellTreeItem;
 class imgIContainer;
 class nsDOMDataTransfer;
 
@@ -75,16 +77,20 @@ class TabParent;
  * Event listener manager
  */
 
 class nsEventStateManager : public nsSupportsWeakReference,
                             public nsIObserver
 {
   friend class nsMouseWheelTransaction;
 public:
+
+  typedef mozilla::TimeStamp TimeStamp;
+  typedef mozilla::TimeDuration TimeDuration;
+
   nsEventStateManager();
   virtual ~nsEventStateManager();
 
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_NSIOBSERVER
 
   nsresult Init();
   nsresult Shutdown();
@@ -164,34 +170,48 @@ public:
 
   nsresult SetCursor(PRInt32 aCursor, imgIContainer* aContainer,
                      PRBool aHaveHotspot, float aHotspotX, float aHotspotY,
                      nsIWidget* aWidget, PRBool aLockCursor); 
 
   static void StartHandlingUserInput()
   {
     ++sUserInputEventDepth;
+    if (sUserInputEventDepth == 1) {
+      sHandlingInputStart = TimeStamp::Now();
+    }
   }
 
   static void StopHandlingUserInput()
   {
     --sUserInputEventDepth;
+    if (sUserInputEventDepth == 0) {
+      sHandlingInputStart = TimeStamp();
+    }
   }
 
   static PRBool IsHandlingUserInput()
   {
-    return sUserInputEventDepth > 0;
+    if (sUserInputEventDepth <= 0) {
+      return PR_FALSE;
+    }
+    TimeDuration timeout = nsContentUtils::HandlingUserInputTimeout();
+    return timeout <= TimeDuration(0) ||
+           (TimeStamp::Now() - sHandlingInputStart) <= timeout;
   }
 
   /**
    * Returns true if the current code is being executed as a result of user input.
    * This includes timers or anything else that is initiated from user input.
    * However, mouse hover events are not counted as user input, nor are
    * page load events. If this method is called from asynchronously executed code,
-   * such as during layout reflows, it will return false.
+   * such as during layout reflows, it will return false. If more time has elapsed
+   * since the user input than is specified by the
+   * dom.event.handling-user-input-time-limit pref (default 1 second), this
+   * function also returns false.
    */
   NS_IMETHOD_(PRBool) IsHandlingUserInputExternal() { return IsHandlingUserInput(); }
   
   nsPresContext* GetPresContext() { return mPresContext; }
 
   NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsEventStateManager,
                                            nsIObserver)
 
@@ -502,16 +522,18 @@ private:
   nsCOMPtr<nsIDocument> mDocument;   // Doesn't necessarily need to be owner
 
   PRUint32 mLClickCount;
   PRUint32 mMClickCount;
   PRUint32 mRClickCount;
 
   PRPackedBool m_haveShutdown;
 
+  // Time at which we began handling user input.
+  static TimeStamp sHandlingInputStart;
 
 public:
   static nsresult UpdateUserActivityTimer(void);
   // Array for accesskey support
   nsCOMArray<nsIContent> mAccessKeys;
 
   // Unlocks pixel scrolling
   PRPackedBool mLastLineScrollConsumedX;
--- 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/test/test_fullscreen-api.html
+++ b/content/html/content/test/test_fullscreen-api.html
@@ -1,15 +1,16 @@
  <!DOCTYPE HTML>
 <html>
 <head>
   <title>Test for Bug 545812</title>
   <script type="application/javascript" src="/MochiKit/packed.js"></script>
   <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+  <script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
 </head>
 <body>
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=545812">Mozilla Bug 545812</a>
 <p id="display"></p>
 <div id="content" style="display: none">
 
 </div>
 <pre id="test">
@@ -33,16 +34,33 @@ function run() {
   document.addEventListener("mozfullscreenchange",
     function(){ok(false, "Should never receive a mozfullscreenchange event in the main window.");},
     false);
 
   // Ensure the full-screen api is enabled, and will be disabled on test exit.
   prevEnabled = SpecialPowers.getBoolPref("full-screen-api.enabled");
   SpecialPowers.setBoolPref("full-screen-api.enabled", true);
 
+  // Test requesting full-screen mode in a long-running user-generated event handler.
+  // The request in the key handler should not be granted.
+  window.addEventListener("keypress", keyHandler, false);
+  synthesizeKey("VK_A", {});
+}
+
+function keyHandler(event) {
+  window.removeEventListener("keypress", keyHandler, false);
+  
+  // Busy loop until 2s has passed. We should then be past the 1 second threshold, and so
+  // our request for full-screen mode should be rejected.
+  var end = (new Date()).getTime() + 2000;
+  while ((new Date()).getTime() < end) {
+    ; // Wait...
+  }
+  document.body.mozRequestFullScreen();
+
   prevTrusted = SpecialPowers.getBoolPref("full-screen-api.allow-trusted-requests-only");
 
   // Request full-screen from a non trusted context (this script isn't a user
   // generated event!). We should not receive a "mozfullscreenchange" event.
   SpecialPowers.setBoolPref("full-screen-api.allow-trusted-requests-only", true);
   document.body.mozRequestFullScreen();
 
   // Disable the requirement for trusted contexts only, so the tests are easier
--- 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/content/smil/nsSMILAnimationController.cpp
+++ b/content/smil/nsSMILAnimationController.cpp
@@ -587,17 +587,17 @@ nsSMILAnimationController::DoMilestoneSa
       nsSMILTimeContainer* container = elem->GetTimeContainer();
       if (!container)
         // The container may be nsnull if the element has been detached from its
         // parent since registering a milestone.
         continue;
 
       nsSMILTimeValue containerTimeValue =
         container->ParentToContainerTime(sampleTime);
-      if (!containerTimeValue.IsResolved())
+      if (!containerTimeValue.IsDefinite())
         continue;
 
       // Clamp the converted container time to non-negative values.
       nsSMILTime containerTime = NS_MAX<nsSMILTime>(0, containerTimeValue.GetMillis());
 
       if (nextMilestone.mIsEnd) {
         elem->TimedElement().SampleEndAt(containerTime);
       } else {
--- a/content/smil/nsSMILAnimationFunction.cpp
+++ b/content/smil/nsSMILAnimationFunction.cpp
@@ -247,18 +247,17 @@ nsSMILAnimationFunction::ComposeResult(c
   // Check that we have the right number of keySplines and keyTimes
   CheckValueListDependentAttrs(values.Length());
   if (mErrorFlags != 0)
     return;
 
   // If this interval is active, we must have a non-negative mSampleTime
   NS_ABORT_IF_FALSE(mSampleTime >= 0 || !mIsActive,
       "Negative sample time for active animation");
-  NS_ABORT_IF_FALSE(mSimpleDuration.IsResolved() ||
-      mSimpleDuration.IsIndefinite() || mLastValue,
+  NS_ABORT_IF_FALSE(mSimpleDuration.IsResolved() || mLastValue,
       "Unresolved simple duration for active or frozen animation");
 
   // If we want to add but don't have a base value then just fail outright.
   // This can happen when we skipped getting the base value because there's an
   // animation function in the sandwich that should replace it but that function
   // failed unexpectedly.
   PRBool isAdditive = IsAdditive();
   if (isAdditive && aResult.IsNull())
@@ -403,17 +402,17 @@ nsSMILAnimationFunction::InterpolateResu
 
   // Get the normalised progress through the simple duration.
   //
   // If we have an indefinite simple duration, just set the progress to be
   // 0 which will give us the expected behaviour of the animation being fixed at
   // its starting point.
   double simpleProgress = 0.0;
 
-  if (mSimpleDuration.IsResolved()) {
+  if (mSimpleDuration.IsDefinite()) {
     nsSMILTime dur = mSimpleDuration.GetMillis();
 
     NS_ABORT_IF_FALSE(dur >= 0, "Simple duration should not be negative");
     NS_ABORT_IF_FALSE(mSampleTime >= 0, "Sample time should not be negative");
 
     if (mSampleTime >= dur || mSampleTime < 0) {
       NS_ERROR("Animation sampled outside interval");
       return NS_ERROR_FAILURE;
--- a/content/smil/nsSMILInterval.cpp
+++ b/content/smil/nsSMILInterval.cpp
@@ -105,18 +105,18 @@ nsSMILInterval::End()
   NS_ABORT_IF_FALSE(mBegin && mEnd,
       "Requesting End() on un-initialized interval.");
   return mEnd;
 }
 
 void
 nsSMILInterval::SetBegin(nsSMILInstanceTime& aBegin)
 {
-  NS_ABORT_IF_FALSE(aBegin.Time().IsResolved(),
-      "Attempting to set unresolved begin time on interval");
+  NS_ABORT_IF_FALSE(aBegin.Time().IsDefinite(),
+      "Attempting to set unresolved or indefinite begin time on interval");
   NS_ABORT_IF_FALSE(!mBeginFixed,
       "Attempting to set begin time but the begin point is fixed");
   // Check that we're not making an instance time dependent on itself. Such an
   // arrangement does not make intuitive sense and should be detected when
   // creating or updating intervals.
   NS_ABORT_IF_FALSE(!mBegin || aBegin.GetBaseTime() != mBegin,
       "Attempting to make self-dependent instance time");
 
--- a/content/smil/nsSMILTimeContainer.cpp
+++ b/content/smil/nsSMILTimeContainer.cpp
@@ -256,17 +256,17 @@ PRBool
 nsSMILTimeContainer::GetNextMilestoneInParentTime(
     nsSMILMilestone& aNextMilestone) const
 {
   if (mMilestoneEntries.IsEmpty())
     return PR_FALSE;
 
   nsSMILTimeValue parentTime =
     ContainerToParentTime(mMilestoneEntries.Top().mMilestone.mTime);
-  if (!parentTime.IsResolved())
+  if (!parentTime.IsDefinite())
     return PR_FALSE;
 
   aNextMilestone = nsSMILMilestone(parentTime.GetMillis(),
                                    mMilestoneEntries.Top().mMilestone.mIsEnd);
 
   return PR_TRUE;
 }
 
@@ -274,17 +274,17 @@ PRBool
 nsSMILTimeContainer::PopMilestoneElementsAtMilestone(
       const nsSMILMilestone& aMilestone,
       AnimElemArray& aMatchedElements)
 {
   if (mMilestoneEntries.IsEmpty())
     return PR_FALSE;
 
   nsSMILTimeValue containerTime = ParentToContainerTime(aMilestone.mTime);
-  if (!containerTime.IsResolved())
+  if (!containerTime.IsDefinite())
     return PR_FALSE;
 
   nsSMILMilestone containerMilestone(containerTime.GetMillis(),
                                      aMilestone.mIsEnd);
 
   NS_ABORT_IF_FALSE(mMilestoneEntries.Top().mMilestone >= containerMilestone,
       "Trying to pop off earliest times but we have earlier ones that were "
       "overlooked");
--- a/content/smil/nsSMILTimeValue.cpp
+++ b/content/smil/nsSMILTimeValue.cpp
@@ -48,22 +48,22 @@ Cmp(PRInt64 aA, PRInt64 aB)
   return aA == aB ? 0 : (aA > aB ? 1 : -1);
 }
 
 PRInt8
 nsSMILTimeValue::CompareTo(const nsSMILTimeValue& aOther) const
 {
   PRInt8 result;
 
-  if (mState == STATE_RESOLVED) {
-    result = (aOther.mState == STATE_RESOLVED)
+  if (mState == STATE_DEFINITE) {
+    result = (aOther.mState == STATE_DEFINITE)
            ? Cmp(mMilliseconds, aOther.mMilliseconds)
            : -1;
   } else if (mState == STATE_INDEFINITE) {
-    if (aOther.mState == STATE_RESOLVED)
+    if (aOther.mState == STATE_DEFINITE)
       result = 1;
     else if (aOther.mState == STATE_INDEFINITE)
       result = 0;
     else
       result = -1;
   } else {
     result = (aOther.mState != STATE_UNRESOLVED) ? 1 : 0;
   }
--- a/content/smil/nsSMILTimeValue.h
+++ b/content/smil/nsSMILTimeValue.h
@@ -61,61 +61,45 @@
  * nsSMILTimeValueSpec -- a component of a begin or end attribute, such as the
  *                        '5s' or 'a.end+2m' in begin="5s; a.end+2m". Acts as
  *                        a broker between an nsSMILTimedElement and its
  *                        nsSMILInstanceTimes by generating new instance times
  *                        and handling changes to existing times.
  *
  * Objects of this class may be in one of three states:
  *
- * 1) The time is resolved and has a millisecond value
- * 2) The time is indefinite
- * 3) The time in unresolved
- *
- * There is considerable chance for confusion with regards to the indefinite
- * state. Is it resolved? We adopt the convention that it is NOT resolved (but
- * nor is it unresolved). This simplifies implementation as you can then write:
- *
- * if (time.IsResolved())
- *    x = time.GetMillis()
- *
- * instead of:
- *
- * if (time.IsResolved() && !time.IsIndefinite())
- *    x = time.GetMillis()
- *
- * Testing if a time is unresolved becomes more complicated but this is tested
- * much less often.
+ * 1) The time is resolved and has a definite millisecond value
+ * 2) The time is resolved and indefinite
+ * 3) The time is unresolved
  *
  * In summary:
  *
- * State         |  GetMillis         |  IsResolved        |  IsIndefinite
- * --------------+--------------------+--------------------+-------------------
- * Resolved      |  The millisecond   |  PR_TRUE           |  PR_FALSE
- *               |  time              |                    |
- * --------------+--------------------+--------------------+-------------------
- * Indefinite    |  LL_MAXINT         |  PR_FALSE          |  PR_TRUE
- * --------------+--------------------+--------------------+-------------------
- * Unresolved    |  LL_MAXINT         |  PR_FALSE          |  PR_FALSE
+ * State      | GetMillis       | IsDefinite | IsIndefinite | IsResolved
+ * -----------+-----------------+------------+--------------+------------
+ * Definite   | nsSMILTimeValue | PR_TRUE    | PR_FALSE     | PR_TRUE
+ * -----------+-----------------+------------+--------------+------------
+ * Indefinite | --              | PR_FALSE   | PR_TRUE      | PR_TRUE
+ * -----------+-----------------+------------+--------------+------------
+ * Unresolved | --              | PR_FALSE   | PR_FALSE     | PR_FALSE
  *
  */
 
 class nsSMILTimeValue
 {
 public:
   // Creates an unresolved time value
   nsSMILTimeValue()
   : mMilliseconds(kUnresolvedMillis),
     mState(STATE_UNRESOLVED)
   { }
 
   // Creates a resolved time value
   explicit nsSMILTimeValue(nsSMILTime aMillis)
   : mMilliseconds(aMillis),
-    mState(STATE_RESOLVED)
+    mState(STATE_DEFINITE)
   { }
 
   // Named constructor to create an indefinite time value
   static nsSMILTimeValue Indefinite()
   {
     nsSMILTimeValue value;
     value.SetIndefinite();
     return value;
@@ -123,34 +107,35 @@ public:
 
   PRBool IsIndefinite() const { return mState == STATE_INDEFINITE; }
   void SetIndefinite()
   {
     mState = STATE_INDEFINITE;
     mMilliseconds = kUnresolvedMillis;
   }
 
-  PRBool IsResolved() const { return mState == STATE_RESOLVED; }
+  PRBool IsResolved() const { return mState != STATE_UNRESOLVED; }
   void SetUnresolved()
   {
     mState = STATE_UNRESOLVED;
     mMilliseconds = kUnresolvedMillis;
   }
 
+  PRBool IsDefinite() const { return mState == STATE_DEFINITE; }
   nsSMILTime GetMillis() const
   {
-    NS_ABORT_IF_FALSE(mState == STATE_RESOLVED,
-       "GetMillis() called for unresolved time");
+    NS_ABORT_IF_FALSE(mState == STATE_DEFINITE,
+       "GetMillis() called for unresolved or indefinite time");
 
-    return mState == STATE_RESOLVED ? mMilliseconds : kUnresolvedMillis;
+    return mState == STATE_DEFINITE ? mMilliseconds : kUnresolvedMillis;
   }
 
   void SetMillis(nsSMILTime aMillis)
   {
-    mState = STATE_RESOLVED;
+    mState = STATE_DEFINITE;
     mMilliseconds = aMillis;
   }
 
   PRInt8 CompareTo(const nsSMILTimeValue& aOther) const;
 
   PRBool operator==(const nsSMILTimeValue& aOther) const
   { return CompareTo(aOther) == 0; }
 
@@ -167,17 +152,17 @@ public:
   { return CompareTo(aOther) <= 0; }
 
   PRBool operator>=(const nsSMILTimeValue& aOther) const
   { return CompareTo(aOther) >= 0; }
 
 private:
   static nsSMILTime kUnresolvedMillis;
 
-  nsSMILTime        mMilliseconds;
+  nsSMILTime mMilliseconds;
   enum {
-    STATE_RESOLVED,
+    STATE_DEFINITE,
     STATE_INDEFINITE,
     STATE_UNRESOLVED
   } mState;
 };
 
 #endif // NS_SMILTIMEVALUE_H_
--- a/content/smil/nsSMILTimeValueSpec.cpp
+++ b/content/smil/nsSMILTimeValueSpec.cpp
@@ -177,17 +177,17 @@ nsSMILTimeValueSpec::HandleNewInterval(n
                                        const nsSMILTimeContainer* aSrcContainer)
 {
   const nsSMILInstanceTime& baseInstance = mParams.mSyncBegin
     ? *aInterval.Begin() : *aInterval.End();
   nsSMILTimeValue newTime =
     ConvertBetweenTimeContainers(baseInstance.Time(), aSrcContainer);
 
   // Apply offset
-  if (newTime.IsResolved()) {
+  if (newTime.IsDefinite()) {
     newTime.SetMillis(newTime.GetMillis() + mParams.mOffset.GetMillis());
   }
 
   // Create the instance time and register it with the interval
   nsRefPtr<nsSMILInstanceTime> newInstance =
     new nsSMILInstanceTime(newTime, nsSMILInstanceTime::SOURCE_SYNCBASE, this,
                            &aInterval);
   mOwner->AddInstanceTime(newInstance, mIsBegin);
@@ -213,17 +213,17 @@ nsSMILTimeValueSpec::HandleChangedInstan
   // time of an active or postactive interval) we just ignore the change.
   if (aInstanceTimeToUpdate.IsFixedTime())
     return;
 
   nsSMILTimeValue updatedTime =
     ConvertBetweenTimeContainers(aBaseTime.Time(), aSrcContainer);
 
   // Apply offset
-  if (updatedTime.IsResolved()) {
+  if (updatedTime.IsDefinite()) {
     updatedTime.SetMillis(updatedTime.GetMillis() +
                           mParams.mOffset.GetMillis());
   }
 
   // The timed element that owns the instance time does the updating so it can
   // re-sort its array of instance times more efficiently
   if (aInstanceTimeToUpdate.Time() != updatedTime || aObjectChanged) {
     mOwner->UpdateInstanceTime(&aInstanceTimeToUpdate, updatedTime, mIsBegin);
@@ -504,17 +504,17 @@ nsSMILTimeValueSpec::CheckAccessKeyEvent
 
 nsSMILTimeValue
 nsSMILTimeValueSpec::ConvertBetweenTimeContainers(
     const nsSMILTimeValue& aSrcTime,
     const nsSMILTimeContainer* aSrcContainer)
 {
   // If the source time is either indefinite or unresolved the result is going
   // to be the same
-  if (!aSrcTime.IsResolved())
+  if (!aSrcTime.IsDefinite())
     return aSrcTime;
 
   // Convert from source time container to our parent time container
   const nsSMILTimeContainer* dstContainer = mOwner->GetTimeContainer();
   if (dstContainer == aSrcContainer)
     return aSrcTime;
 
   // If one of the elements is not attached to a time container then we can't do
@@ -525,13 +525,13 @@ nsSMILTimeValueSpec::ConvertBetweenTimeC
   nsSMILTimeValue docTime =
     aSrcContainer->ContainerToParentTime(aSrcTime.GetMillis());
 
   if (docTime.IsIndefinite())
     // This will happen if the source container is paused and we have a future
     // time. Just return the indefinite time.
     return docTime;
 
-   NS_ABORT_IF_FALSE(docTime.IsResolved(),
-       "ContainerToParentTime gave us an unresolved time");
+  NS_ABORT_IF_FALSE(docTime.IsDefinite(),
+    "ContainerToParentTime gave us an unresolved or indefinite time");
 
   return dstContainer->ParentToContainerTime(docTime.GetMillis());
 }
--- a/content/smil/nsSMILTimedElement.cpp
+++ b/content/smil/nsSMILTimedElement.cpp
@@ -913,31 +913,31 @@ nsSMILTimedElement::SetSimpleDuration(co
   rv = nsSMILParserUtils::ParseClockValue(aDurSpec, &duration,
           nsSMILParserUtils::kClockValueAllowIndefinite, &isMedia);
 
   if (NS_FAILED(rv)) {
     mSimpleDur.SetIndefinite();
     return NS_ERROR_FAILURE;
   }
 
-  if (duration.IsResolved() && duration.GetMillis() == 0L) {
+  if (duration.IsDefinite() && duration.GetMillis() == 0L) {
     mSimpleDur.SetIndefinite();
     return NS_ERROR_FAILURE;
   }
 
   //
   // SVG-specific: "For SVG's animation elements, if "media" is specified, the
   // attribute will be ignored." (SVG 1.1, section 19.2.6)
   //
   if (isMedia)
     duration.SetIndefinite();
 
   // mSimpleDur should never be unresolved. ParseClockValue will either set
   // duration to resolved/indefinite/media or will return a failure code.
-  NS_ASSERTION(duration.IsResolved() || duration.IsIndefinite(),
+  NS_ABORT_IF_FALSE(duration.IsResolved(),
     "Setting unresolved simple duration");
 
   mSimpleDur = duration;
   UpdateCurrentInterval();
 
   return NS_OK;
 }
 
@@ -956,17 +956,17 @@ nsSMILTimedElement::SetMin(const nsAStri
   nsresult rv;
 
   rv = nsSMILParserUtils::ParseClockValue(aMinSpec, &duration, 0, &isMedia);
 
   if (isMedia) {
     duration.SetMillis(0L);
   }
 
-  if (NS_FAILED(rv) || !duration.IsResolved()) {
+  if (NS_FAILED(rv) || !duration.IsDefinite()) {
     mMin.SetMillis(0L);
     return NS_ERROR_FAILURE;
   }
 
   if (duration.GetMillis() < 0L) {
     mMin.SetMillis(0L);
     return NS_ERROR_FAILURE;
   }
@@ -992,22 +992,22 @@ nsSMILTimedElement::SetMax(const nsAStri
   nsresult rv;
 
   rv = nsSMILParserUtils::ParseClockValue(aMaxSpec, &duration,
           nsSMILParserUtils::kClockValueAllowIndefinite, &isMedia);
 
   if (isMedia)
     duration.SetIndefinite();
 
-  if (NS_FAILED(rv) || (!duration.IsResolved() && !duration.IsIndefinite())) {
+  if (NS_FAILED(rv) || !duration.IsResolved()) {
     mMax.SetIndefinite();
     return NS_ERROR_FAILURE;
   }
 
-  if (duration.IsResolved() && duration.GetMillis() <= 0L) {
+  if (duration.IsDefinite() && duration.GetMillis() <= 0L) {
     mMax.SetIndefinite();
     return NS_ERROR_FAILURE;
   }
 
   mMax = duration;
   UpdateCurrentInterval();
 
   return NS_OK;
@@ -1069,17 +1069,17 @@ nsresult
 nsSMILTimedElement::SetRepeatDur(const nsAString& aRepeatDurSpec)
 {
   nsresult rv;
   nsSMILTimeValue duration;
 
   rv = nsSMILParserUtils::ParseClockValue(aRepeatDurSpec, &duration,
           nsSMILParserUtils::kClockValueAllowIndefinite);
 
-  if (NS_FAILED(rv) || (!duration.IsResolved() && !duration.IsIndefinite())) {
+  if (NS_FAILED(rv) || !duration.IsResolved()) {
     mRepeatDur.SetUnresolved();
     return NS_ERROR_FAILURE;
   }
 
   mRepeatDur = duration;
   UpdateCurrentInterval();
 
   return NS_OK;
@@ -1603,18 +1603,18 @@ nsSMILTimedElement::FilterInstanceTimes(
 // http://www.w3.org/TR/2001/REC-smil-animation-20010904/#Timing-BeginEnd-LC-Start
 //
 PRBool
 nsSMILTimedElement::GetNextInterval(const nsSMILInterval* aPrevInterval,
                                     const nsSMILInterval* aReplacedInterval,
                                     const nsSMILInstanceTime* aFixedBeginTime,
                                     nsSMILInterval& aResult) const
 {
-  NS_ABORT_IF_FALSE(!aFixedBeginTime || aFixedBeginTime->Time().IsResolved(),
-      "Unresolved begin time specified for interval start");
+  NS_ABORT_IF_FALSE(!aFixedBeginTime || aFixedBeginTime->Time().IsDefinite(),
+      "Unresolved or indefinite begin time specified for interval start");
   static const nsSMILTimeValue zeroTime(0L);
 
   if (mRestartMode == RESTART_NEVER && aPrevInterval)
     return PR_FALSE;
 
   // Calc starting point
   nsSMILTimeValue beginAfter;
   PRBool prevIntervalWasZeroDur = PR_FALSE;
@@ -1650,23 +1650,23 @@ nsSMILTimedElement::GetNextInterval(cons
       // If we're updating the current interval then skip any begin time that is
       // dependent on the current interval's begin time. e.g.
       //   <animate id="a" begin="b.begin; a.begin+2s"...
       // If b's interval disappears whilst 'a' is in the waiting state the begin
       // time at "a.begin+2s" should be skipped since 'a' never begun.
       do {
         tempBegin =
           GetNextGreaterOrEqual(mBeginInstances, beginAfter, beginPos);
-        if (!tempBegin || !tempBegin->Time().IsResolved()) {
+        if (!tempBegin || !tempBegin->Time().IsDefinite()) {
           return PR_FALSE;
         }
       } while (aReplacedInterval &&
                tempBegin->GetBaseTime() == aReplacedInterval->Begin());
     }
-    NS_ABORT_IF_FALSE(tempBegin && tempBegin->Time().IsResolved() &&
+    NS_ABORT_IF_FALSE(tempBegin && tempBegin->Time().IsDefinite() &&
         tempBegin->Time() >= beginAfter,
         "Got a bad begin time while fetching next interval");
 
     // Calculate end time
     {
       PRInt32 endPos = 0;
       // As above with begin times, avoid creating self-referential loops
       // between instance times by checking that the newly found end instance
@@ -1683,25 +1683,24 @@ nsSMILTimedElement::GetNextInterval(cons
           prevIntervalWasZeroDur) {
         tempEnd = GetNextGreater(mEndInstances, tempBegin->Time(), endPos);
       }
 
       // If all the ends are before the beginning we have a bad interval UNLESS:
       // a) We never had any end attribute to begin with (and hence we should
       //    just use the active duration after allowing for the possibility of
       //    an end instance provided by a DOM call), OR
-      // b) We have no resolved (not incl. indefinite) end instances
-      //    (SMIL only says "if the instance list is empty"--but if we have
-      //    indefinite/unresolved instance times then there must be a good
-      //    reason we haven't used them (since they'll be >= tempBegin) such as
-      //    avoiding creating a self-referential loop. In any case, the interval
-      //    should be allowed to be open.), OR
+      // b) We have no definite end instances (SMIL only says "if the instance
+      //    list is empty"--but if we have indefinite/unresolved instance times
+      //    then there must be a good reason we haven't used them (since they
+      //    will be >= tempBegin) such as avoiding creating a self-referential
+      //    loop. In any case, the interval should be allowed to be open.), OR
       // c) We have end events which leave the interval open-ended.
       PRBool openEndedIntervalOk = mEndSpecs.IsEmpty() ||
-                                   !HaveResolvedEndTimes() ||
+                                   !HaveDefiniteEndTimes() ||
                                    EndHasEventConditions();
       if (!tempEnd && !openEndedIntervalOk)
         return PR_FALSE; // Bad interval
 
       nsSMILTimeValue intervalEnd = tempEnd
                                   ? tempEnd->Time() : nsSMILTimeValue();
       nsSMILTimeValue activeEnd = CalcActiveEnd(tempBegin->Time(), intervalEnd);
 
@@ -1709,17 +1708,17 @@ nsSMILTimedElement::GetNextInterval(cons
         tempEnd = new nsSMILInstanceTime(activeEnd);
       }
     }
     NS_ABORT_IF_FALSE(tempEnd, "Failed to get end point for next interval");
 
     // If we get two zero-length intervals in a row we will potentially have an
     // infinite loop so we break it here by searching for the next begin time
     // greater than tempEnd on the next time around.
-    if (tempEnd->Time().IsResolved() && tempBegin->Time() == tempEnd->Time()) {
+    if (tempEnd->Time().IsDefinite() && tempBegin->Time() == tempEnd->Time()) {
       if (prevIntervalWasZeroDur) {
         beginAfter.SetMillis(tempEnd->Time().GetMillis() + 1);
         prevIntervalWasZeroDur = PR_FALSE;
         continue;
       }
       prevIntervalWasZeroDur = PR_TRUE;
     }
 
@@ -1776,79 +1775,79 @@ nsSMILTimedElement::GetNextGreaterOrEqua
  * @see SMILANIM 3.3.4
  */
 nsSMILTimeValue
 nsSMILTimedElement::CalcActiveEnd(const nsSMILTimeValue& aBegin,
                                   const nsSMILTimeValue& aEnd) const
 {
   nsSMILTimeValue result;
 
-  NS_ABORT_IF_FALSE(mSimpleDur.IsResolved() || mSimpleDur.IsIndefinite(),
+  NS_ABORT_IF_FALSE(mSimpleDur.IsResolved(),
     "Unresolved simple duration in CalcActiveEnd");
-  NS_ABORT_IF_FALSE(aBegin.IsResolved(),
-    "Unresolved begin time in CalcActiveEnd");
+  NS_ABORT_IF_FALSE(aBegin.IsDefinite(),
+    "Indefinite or unresolved begin time in CalcActiveEnd");
 
   if (mRepeatDur.IsIndefinite()) {
     result.SetIndefinite();
   } else {
     result = GetRepeatDuration();
   }
 
-  if (aEnd.IsResolved()) {
+  if (aEnd.IsDefinite()) {
     nsSMILTime activeDur = aEnd.GetMillis() - aBegin.GetMillis();
 
-    if (result.IsResolved()) {
+    if (result.IsDefinite()) {
       result.SetMillis(NS_MIN(result.GetMillis(), activeDur));
     } else {
       result.SetMillis(activeDur);
     }
   }
 
   result = ApplyMinAndMax(result);
 
-  if (result.IsResolved()) {
+  if (result.IsDefinite()) {
     nsSMILTime activeEnd = result.GetMillis() + aBegin.GetMillis();
     result.SetMillis(activeEnd);
   }
 
   return result;
 }
 
 nsSMILTimeValue
 nsSMILTimedElement::GetRepeatDuration() const
 {
   nsSMILTimeValue result;
 
-  if (mRepeatCount.IsDefinite() && mRepeatDur.IsResolved()) {
-    if (mSimpleDur.IsResolved()) {
+  if (mRepeatCount.IsDefinite() && mRepeatDur.IsDefinite()) {
+    if (mSimpleDur.IsDefinite()) {
       nsSMILTime activeDur =
         nsSMILTime(mRepeatCount * double(mSimpleDur.GetMillis()));
       result.SetMillis(NS_MIN(activeDur, mRepeatDur.GetMillis()));
     } else {
       result = mRepeatDur;
     }
-  } else if (mRepeatCount.IsDefinite() && mSimpleDur.IsResolved()) {
+  } else if (mRepeatCount.IsDefinite() && mSimpleDur.IsDefinite()) {
     nsSMILTime activeDur =
       nsSMILTime(mRepeatCount * double(mSimpleDur.GetMillis()));
     result.SetMillis(activeDur);
-  } else if (mRepeatDur.IsResolved()) {
+  } else if (mRepeatDur.IsDefinite()) {
     result = mRepeatDur;
   } else if (mRepeatCount.IsIndefinite()) {
     result.SetIndefinite();
   } else {
     result = mSimpleDur;
   }
 
   return result;
 }
 
 nsSMILTimeValue
 nsSMILTimedElement::ApplyMinAndMax(const nsSMILTimeValue& aDuration) const
 {
-  if (!aDuration.IsResolved() && !aDuration.IsIndefinite()) {
+  if (!aDuration.IsResolved()) {
     return aDuration;
   }
 
   if (mMax < mMin) {
     return aDuration;
   }
 
   nsSMILTimeValue result;
@@ -1866,17 +1865,17 @@ nsSMILTimedElement::ApplyMinAndMax(const
 }
 
 nsSMILTime
 nsSMILTimedElement::ActiveTimeToSimpleTime(nsSMILTime aActiveTime,
                                            PRUint32& aRepeatIteration)
 {
   nsSMILTime result;
 
-  NS_ASSERTION(mSimpleDur.IsResolved() || mSimpleDur.IsIndefinite(),
+  NS_ASSERTION(mSimpleDur.IsResolved(),
       "Unresolved simple duration in ActiveTimeToSimpleTime");
   NS_ASSERTION(aActiveTime >= 0, "Expecting non-negative active time");
   // Note that a negative aActiveTime will give us a negative value for
   // aRepeatIteration, which is bad because aRepeatIteration is unsigned
 
   if (mSimpleDur.IsIndefinite() || mSimpleDur.GetMillis() == 0L) {
     aRepeatIteration = 0;
     result = aActiveTime;
@@ -2030,17 +2029,17 @@ void
 nsSMILTimedElement::SampleFillValue()
 {
   if (mFillMode != FILL_FREEZE || !mClient)
     return;
 
   const nsSMILInterval* prevInterval = GetPreviousInterval();
   NS_ABORT_IF_FALSE(prevInterval,
       "Attempting to sample fill value but there is no previous interval");
-  NS_ABORT_IF_FALSE(prevInterval->End()->Time().IsResolved() &&
+  NS_ABORT_IF_FALSE(prevInterval->End()->Time().IsDefinite() &&
       prevInterval->End()->IsFixedTime(),
       "Attempting to sample fill value but the endpoint of the previous "
       "interval is not resolved and fixed");
 
   nsSMILTime activeTime = prevInterval->End()->Time().GetMillis() -
                           prevInterval->Begin()->Time().GetMillis();
 
   PRUint32 repeatIteration;
@@ -2131,33 +2130,33 @@ nsSMILTimedElement::GetNextMilestone(nsS
     aNextMilestone.mIsEnd = PR_FALSE;
     aNextMilestone.mTime = mCurrentInterval->Begin()->Time().GetMillis();
     return PR_TRUE;
 
   case STATE_ACTIVE:
     {
       // Work out what comes next: the interval end or the next repeat iteration
       nsSMILTimeValue nextRepeat;
-      if (mSeekState == SEEK_NOT_SEEKING && mSimpleDur.IsResolved()) {
+      if (mSeekState == SEEK_NOT_SEEKING && mSimpleDur.IsDefinite()) {
         nextRepeat.SetMillis(mCurrentInterval->Begin()->Time().GetMillis() +
             (mCurrentRepeatIteration + 1) * mSimpleDur.GetMillis());
       }
       nsSMILTimeValue nextMilestone =
         NS_MIN(mCurrentInterval->End()->Time(), nextRepeat);
 
       // Check for an early end before that time
       nsSMILInstanceTime* earlyEnd = CheckForEarlyEnd(nextMilestone);
       if (earlyEnd) {
         aNextMilestone.mIsEnd = PR_TRUE;
         aNextMilestone.mTime = earlyEnd->Time().GetMillis();
         return PR_TRUE;
       }
 
       // Apply the previously calculated milestone
-      if (nextMilestone.IsResolved()) {
+      if (nextMilestone.IsDefinite()) {
         aNextMilestone.mIsEnd = nextMilestone != nextRepeat;
         aNextMilestone.mTime = nextMilestone.GetMillis();
         return PR_TRUE;
       }
 
       return PR_FALSE;
     }
 
@@ -2249,24 +2248,24 @@ const nsSMILInterval*
 nsSMILTimedElement::GetPreviousInterval() const
 {
   return mOldIntervals.IsEmpty()
     ? nsnull
     : mOldIntervals[mOldIntervals.Length()-1].get();
 }
 
 PRBool
-nsSMILTimedElement::HaveResolvedEndTimes() const
+nsSMILTimedElement::HaveDefiniteEndTimes() const
 {
   if (mEndInstances.IsEmpty())
     return PR_FALSE;
 
-  // mEndInstances is sorted so if the first time is not resolved then none of
+  // mEndInstances is sorted so if the first time is not definite then none of
   // them are
-  return mEndInstances[0]->Time().IsResolved();
+  return mEndInstances[0]->Time().IsDefinite();
 }
 
 PRBool
 nsSMILTimedElement::EndHasEventConditions() const
 {
   for (PRUint32 i = 0; i < mEndSpecs.Length(); ++i) {
     if (mEndSpecs[i]->IsEventBased())
       return PR_TRUE;
--- a/content/smil/nsSMILTimedElement.h
+++ b/content/smil/nsSMILTimedElement.h
@@ -520,17 +520,17 @@ protected:
   void              NotifyChangedInterval(nsSMILInterval* aInterval,
                                           PRBool aBeginObjectChanged,
                                           PRBool aEndObjectChanged);
 
   void              FireTimeEventAsync(PRUint32 aMsg, PRInt32 aDetail);
   const nsSMILInstanceTime* GetEffectiveBeginInstance() const;
   const nsSMILInterval* GetPreviousInterval() const;
   PRBool            HasPlayed() const { return !mOldIntervals.IsEmpty(); }
-  PRBool            HaveResolvedEndTimes() const;
+  PRBool            HaveDefiniteEndTimes() const;
   PRBool            EndHasEventConditions() const;
 
   // Reset the current interval by first passing ownership to a temporary
   // variable so that if Unlink() results in us receiving a callback,
   // mCurrentInterval will be nsnull and we will be in a consistent state.
   void ResetCurrentInterval()
   {
     if (mCurrentInterval) {
--- a/content/svg/content/src/SVGMotionSMILAnimationFunction.cpp
+++ b/content/svg/content/src/SVGMotionSMILAnimationFunction.cpp
@@ -378,16 +378,28 @@ SVGMotionSMILAnimationFunction::
 {
   // Call superclass method.
   nsSMILAnimationFunction::CheckValueListDependentAttrs(aNumValues);
 
   // Added behavior: Do checks specific to keyPoints.
   CheckKeyPoints();
 }
 
+PRBool
+SVGMotionSMILAnimationFunction::IsToAnimation() const
+{
+  // Rely on inherited method, but not if we have an <mpath> child or a |path|
+  // attribute, because they'll override any 'to' attr we might have.
+  // NOTE: We can't rely on mPathSourceType, because it might not have been
+  // set to a useful value yet (or it might be stale).
+  return !GetFirstMpathChild(&mAnimationElement->AsElement()) &&
+    !HasAttr(nsGkAtoms::path) &&
+    nsSMILAnimationFunction::IsToAnimation();
+}
+
 void
 SVGMotionSMILAnimationFunction::CheckKeyPoints()
 {
   if (!HasAttr(nsGkAtoms::keyPoints))
     return;
 
   // attribute is ignored for calcMode="paced" (even if it's got errors)
   if (GetCalcMode() == CALC_PACED) {
@@ -480,20 +492,9 @@ SVGMotionSMILAnimationFunction::SetRotat
 void
 SVGMotionSMILAnimationFunction::UnsetRotate()
 {
   mRotateAngle = 0.0f; // default value
   mRotateType = eRotateType_Explicit;
   mHasChanged = PR_TRUE;
 }
 
-PRBool
-SVGMotionSMILAnimationFunction::TreatSingleValueAsStatic() const
-{
-  // <animateMotion> has two more ways that we could be just sampling a single
-  // value -- via path attribute and the <mpath> element, with a path
-  // description that just includes a single "move" command.
-  return (mPathSourceType == ePathSourceType_ValuesAttr ||
-          mPathSourceType == ePathSourceType_PathAttr ||
-          mPathSourceType == ePathSourceType_Mpath);
-}
-
 } // namespace mozilla
--- a/content/svg/content/src/SVGMotionSMILAnimationFunction.h
+++ b/content/svg/content/src/SVGMotionSMILAnimationFunction.h
@@ -80,17 +80,18 @@ protected:
     ePathSourceType_PathAttr,
     ePathSourceType_Mpath
   };
 
   NS_OVERRIDE virtual nsSMILCalcMode GetCalcMode() const;
   NS_OVERRIDE virtual nsresult GetValues(const nsISMILAttr& aSMILAttr,
                                          nsSMILValueArray& aResult);
   NS_OVERRIDE virtual void CheckValueListDependentAttrs(PRUint32 aNumValues);
-  NS_OVERRIDE virtual PRBool TreatSingleValueAsStatic() const;
+
+  NS_OVERRIDE virtual PRBool IsToAnimation() const;
 
   void     CheckKeyPoints();
   nsresult SetKeyPoints(const nsAString& aKeyPoints, nsAttrValue& aResult);
   void     UnsetKeyPoints();
   nsresult SetRotate(const nsAString& aRotate, nsAttrValue& aResult);
   void     UnsetRotate();
 
   // Helpers for GetValues
--- a/content/svg/content/src/nsSVGAnimationElement.cpp
+++ b/content/svg/content/src/nsSVGAnimationElement.cpp
@@ -211,17 +211,17 @@ nsSVGAnimationElement::GetTargetElement(
 
 /* float getStartTime() raises( DOMException ); */
 NS_IMETHODIMP
 nsSVGAnimationElement::GetStartTime(float* retval)
 {
   FlushAnimations();
 
   nsSMILTimeValue startTime = mTimedElement.GetStartTime();
-  if (!startTime.IsResolved())
+  if (!startTime.IsDefinite())
     return NS_ERROR_DOM_INVALID_STATE_ERR;
 
   *retval = float(double(startTime.GetMillis()) / PR_MSEC_PER_SEC);
 
   return NS_OK;
 }
 
 /* float getCurrentTime(); */
@@ -241,17 +241,17 @@ nsSVGAnimationElement::GetCurrentTime(fl
 
 /* float getSimpleDuration() raises( DOMException ); */
 NS_IMETHODIMP
 nsSVGAnimationElement::GetSimpleDuration(float* retval)
 {
   // Not necessary to call FlushAnimations() for this
 
   nsSMILTimeValue simpleDur = mTimedElement.GetSimpleDuration();
-  if (!simpleDur.IsResolved()) {
+  if (!simpleDur.IsDefinite()) {
     *retval = 0.f;
     return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
   }
 
   *retval = float(double(simpleDur.GetMillis()) / PR_MSEC_PER_SEC);
   return NS_OK;
 }
 
--- a/content/svg/content/src/nsSVGFilters.cpp
+++ b/content/svg/content/src/nsSVGFilters.cpp
@@ -5430,17 +5430,17 @@ nsSVGFEImageElement::LoadSVGImage(PRBool
   nsAutoString href;
   mStringAttributes[HREF].GetAnimValue(href, this);
   href.Trim(" \t\n\r");
 
   if (baseURI && !href.IsEmpty())
     NS_MakeAbsoluteURI(href, href, baseURI);
 
   // Make sure we don't get in a recursive death-spiral
-  nsIDocument* doc = GetOurDocument();
+  nsIDocument* doc = GetOwnerDoc();
   if (doc) {
     nsCOMPtr<nsIURI> hrefAsURI;
     if (NS_SUCCEEDED(StringToURI(href, doc, getter_AddRefs(hrefAsURI)))) {
       PRBool isEqual;
       if (NS_SUCCEEDED(hrefAsURI->Equals(baseURI, &isEqual)) && isEqual) {
         // Image URI matches our URI exactly! Bail out.
         return NS_OK;
       }
--- a/content/xbl/crashtests/crashtests.list
+++ b/content/xbl/crashtests/crashtests.list
@@ -26,12 +26,12 @@ load 421997-1.xhtml
 load 432813-1.xhtml
 load 454820-1.html
 load 460665-1.xhtml
 load 463511-1.xhtml
 load 464863-1.xhtml
 load 472260-1.xhtml
 load 477878-1.html
 load 492978-1.xul
-load 493123-1.xhtml
+asserts-if(Android,2) load 493123-1.xhtml
 load 495354-1.xhtml
 load 507628-1.xhtml
 load 507991-1.xhtml
--- a/docshell/base/crashtests/crashtests.list
+++ b/docshell/base/crashtests/crashtests.list
@@ -1,13 +1,13 @@
 load 40929-1.html
 load 369126-1.html
 load 403574-1.xhtml
 load 430124-1.html
 load 430628-1.html
 load 432114-1.html
 load 432114-2.html
-load 436900-1.html
-asserts(0-2) load 436900-2.html # bug 566159
+asserts-if(Android,2) load 436900-1.html
+asserts(0-3) load 436900-2.html # bug 566159
 load 500328-1.html
 load 514779-1.xhtml
 load 614499-1.html
 load 678872-1.html
--- 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/crashtests/crashtests.list
+++ b/dom/base/crashtests/crashtests.list
@@ -1,9 +1,9 @@
-load 90613-1.html
+asserts-if(Android,1) load 90613-1.html
 load 244933-1.html
 load 275912-1.html
 load 327571-1.html
 load 327695-1.html
 load 329481-1.xhtml
 load 338674-1.xhtml
 load 346381-1.html
 load 359432-1.xhtml
@@ -16,16 +16,16 @@ load 375399-1.html
 load 404869-1.xul
 load 417852-1.html
 load 462947.html
 load 439206-1.html
 load 473284.xul
 load 499006-1.html
 load 499006-2.html
 load 502617.html
-asserts(1) load 504224.html # bug 564098
+asserts(1-2) load 504224.html # bug 564098
 load 603531.html
 load 601247.html
 load 609560-1.xhtml
 load 612018-1.html
 load 637116.html
 load 666869.html
 load 675621-1.html
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -521,16 +521,17 @@ static const char kDOMStringBundleURL[] 
   nsIXPCScriptable::WANT_FINALIZE |                                           \
   nsIXPCScriptable::WANT_EQUALITY |                                           \
   nsIXPCScriptable::WANT_ENUMERATE |                                          \
   nsIXPCScriptable::DONT_ENUM_QUERY_INTERFACE |                               \
   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
@@ -660,17 +661,18 @@ static nsDOMClassInfoData sClassInfoData
                            (DOM_DEFAULT_SCRIPTABLE_FLAGS &
                             ~nsIXPCScriptable::ALLOW_PROP_MODS_TO_PROTOTYPE))
 
   NS_DEFINE_CLASSINFO_DATA(CaretPosition, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 
   NS_DEFINE_CLASSINFO_DATA(Navigator, nsNavigatorSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS |
-                           nsIXPCScriptable::WANT_PRECREATE)
+                           nsIXPCScriptable::WANT_PRECREATE |
+                           nsIXPCScriptable::WANT_NEWRESOLVE)
   NS_DEFINE_CLASSINFO_DATA(Plugin, nsPluginSH,
                            ARRAY_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(PluginArray, nsPluginArraySH,
                            ARRAY_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(MimeType, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(MimeTypeArray, nsMimeTypeArraySH,
                            ARRAY_SCRIPTABLE_FLAGS)
@@ -2009,33 +2011,35 @@ CutPrefix(const char *aName) {
 
   return aName;
 }
 
 // static
 nsresult
 nsDOMClassInfo::RegisterClassName(PRInt32 aClassInfoID)
 {
-  nsScriptNameSpaceManager *nameSpaceManager = nsJSRuntime::GetNameSpaceManager();
+  nsScriptNameSpaceManager *nameSpaceManager =
+    nsJSRuntime::GetNameSpaceManager();
   NS_ENSURE_TRUE(nameSpaceManager, NS_ERROR_NOT_INITIALIZED);
 
   nameSpaceManager->RegisterClassName(sClassInfoData[aClassInfoID].mName,
                                       aClassInfoID,
                                       sClassInfoData[aClassInfoID].mChromeOnly,
                                       sClassInfoData[aClassInfoID].mDisabled,
                                       &sClassInfoData[aClassInfoID].mNameUTF16);
 
   return NS_OK;
 }
 
 // static
 nsresult
 nsDOMClassInfo::RegisterClassProtos(PRInt32 aClassInfoID)
 {
-  nsScriptNameSpaceManager *nameSpaceManager = nsJSRuntime::GetNameSpaceManager();
+  nsScriptNameSpaceManager *nameSpaceManager =
+    nsJSRuntime::GetNameSpaceManager();
   NS_ENSURE_TRUE(nameSpaceManager, NS_ERROR_NOT_INITIALIZED);
   PRBool found_old;
 
   const nsIID *primary_iid = sClassInfoData[aClassInfoID].mProtoChainInterface;
 
   if (!primary_iid || primary_iid == &NS_GET_IID(nsISupports)) {
     return NS_OK;
   }
@@ -2077,17 +2081,18 @@ nsDOMClassInfo::RegisterClassProtos(PRIn
 
   return NS_OK;
 }
 
 // static
 nsresult
 nsDOMClassInfo::RegisterExternalClasses()
 {
-  nsScriptNameSpaceManager *nameSpaceManager = nsJSRuntime::GetNameSpaceManager();
+  nsScriptNameSpaceManager *nameSpaceManager =
+    nsJSRuntime::GetNameSpaceManager();
   NS_ENSURE_TRUE(nameSpaceManager, NS_ERROR_NOT_INITIALIZED);
 
   nsCOMPtr<nsIComponentRegistrar> registrar;
   nsresult rv = NS_GetComponentRegistrar(getter_AddRefs(registrar));
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsCOMPtr<nsICategoryManager> cm =
     do_GetService(NS_CATEGORYMANAGER_CONTRACTID, &rv);
@@ -5526,17 +5531,18 @@ private:
     return nameStruct;
   }
 
   static nsresult GetNameStruct(const nsAString& aName,
                                 const nsGlobalNameStruct **aNameStruct)
   {
     *aNameStruct = nsnull;
 
-    nsScriptNameSpaceManager *nameSpaceManager = nsJSRuntime::GetNameSpaceManager();
+    nsScriptNameSpaceManager *nameSpaceManager =
+      nsJSRuntime::GetNameSpaceManager();
     if (!nameSpaceManager) {
       NS_ERROR("Can't get namespace manager.");
       return NS_ERROR_UNEXPECTED;
     }
 
     nameSpaceManager->LookupName(aName, aNameStruct);
 
     // Return NS_OK here, aName just isn't a DOM class but nothing failed.
@@ -5734,17 +5740,18 @@ nsDOMConstructor::HasInstance(nsIXPConne
   NS_ENSURE_TRUE(class_name_struct, NS_ERROR_FAILURE);
 
   if (name_struct == class_name_struct) {
     *bp = JS_TRUE;
 
     return NS_OK;
   }
 
-  nsScriptNameSpaceManager *nameSpaceManager = nsJSRuntime::GetNameSpaceManager();
+  nsScriptNameSpaceManager *nameSpaceManager =
+    nsJSRuntime::GetNameSpaceManager();
   NS_ASSERTION(nameSpaceManager, "Can't get namespace manager?");
 
   const nsIID *class_iid;
   if (class_name_struct->mType == nsGlobalNameStruct::eTypeInterface ||
       class_name_struct->mType == nsGlobalNameStruct::eTypeClassProto) {
     class_iid = &class_name_struct->mIID;
   } else if (class_name_struct->mType == nsGlobalNameStruct::eTypeClassConstructor) {
     class_iid =
@@ -6087,17 +6094,18 @@ ResolvePrototype(nsIXPConnect *aXPConnec
 
 // static
 nsresult
 nsWindowSH::GlobalResolve(nsGlobalWindow *aWin, JSContext *cx,
                           JSObject *obj, jsid id, PRBool *did_resolve)
 {
   *did_resolve = PR_FALSE;
 
-  nsScriptNameSpaceManager *nameSpaceManager = nsJSRuntime::GetNameSpaceManager();
+  nsScriptNameSpaceManager *nameSpaceManager =
+    nsJSRuntime::GetNameSpaceManager();
   NS_ENSURE_TRUE(nameSpaceManager, NS_ERROR_NOT_INITIALIZED);
 
   nsDependentJSString name(id);
 
   const nsGlobalNameStruct *name_struct = nsnull;
   const PRUnichar *class_name = nsnull;
 
   nameSpaceManager->LookupName(name, &name_struct, &class_name);
@@ -6373,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);
@@ -7015,16 +7034,87 @@ nsLocationSH::PreCreate(nsISupports *nat
     return NS_ERROR_UNEXPECTED;
   }
 
   *parentObj = sgo->GetGlobalJSObject();
   return NS_OK;
 }
 
 // DOM Navigator helper
+
+NS_IMETHODIMP
+nsNavigatorSH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
+                          JSObject *obj, jsid id, PRUint32 flags,
+                          JSObject **objp, PRBool *_retval)
+{
+  if (!JSID_IS_STRING(id) || (flags & JSRESOLVE_ASSIGNING)) {
+    return NS_OK;
+  }
+
+  nsScriptNameSpaceManager *nameSpaceManager =
+    nsJSRuntime::GetNameSpaceManager();
+  NS_ENSURE_TRUE(nameSpaceManager, NS_ERROR_NOT_INITIALIZED);
+
+  nsDependentJSString name(id);
+
+  const nsGlobalNameStruct *name_struct = nsnull;
+
+  nameSpaceManager->LookupNavigatorName(name, &name_struct);
+
+  if (!name_struct) {
+    return NS_OK;
+  }
+  NS_ASSERTION(name_struct->mType == nsGlobalNameStruct::eTypeNavigatorProperty,
+               "unexpected type");
+
+  nsresult rv = NS_OK;
+
+  nsCOMPtr<nsISupports> native(do_CreateInstance(name_struct->mCID, &rv));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  jsval prop_val = JSVAL_VOID; // Property value.
+
+  nsCOMPtr<nsIDOMGlobalPropertyInitializer> gpi(do_QueryInterface(native));
+
+  if (gpi) {
+    JSObject *global = JS_GetGlobalForObject(cx, obj);
+
+    nsISupports *globalNative = XPConnect()->GetNativeOfWrapper(cx, global);
+    nsCOMPtr<nsIDOMWindow> window = do_QueryInterface(globalNative);
+
+    if (!window) {
+      return NS_ERROR_UNEXPECTED;
+    }
+
+    rv = gpi->Init(window, &prop_val);
+    NS_ENSURE_SUCCESS(rv, rv);
+  }
+
+  if (JSVAL_IS_PRIMITIVE(prop_val)) {
+    nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
+    rv = WrapNative(cx, obj, native, PR_TRUE, &prop_val,
+                    getter_AddRefs(holder));
+
+    NS_ENSURE_SUCCESS(rv, rv);
+  }
+
+  if (!JS_WrapValue(cx, &prop_val)) {
+    return NS_ERROR_UNEXPECTED;
+  }
+
+  JSBool ok = ::JS_DefinePropertyById(cx, obj, id, prop_val, nsnull, nsnull,
+                                      JSPROP_ENUMERATE);
+
+  *_retval = PR_TRUE;
+  *objp = obj;
+
+  return ok ? NS_OK : NS_ERROR_FAILURE;
+}
+
+// static
 nsresult
 nsNavigatorSH::PreCreate(nsISupports *nativeObj, JSContext *cx,
                          JSObject *globalObj, JSObject **parentObj)
 {
   // window.navigator is persisted across document transitions if
   // we're loading a page from the same origin. Because of that we
   // need to parent the navigator wrapper at the outer window to avoid
   // holding on to the inner window where the navigator was initially
--- a/dom/base/nsDOMClassInfo.h
+++ b/dom/base/nsDOMClassInfo.h
@@ -476,16 +476,19 @@ protected:
 
   virtual ~nsNavigatorSH()
   {
   }
 
 public:
   NS_IMETHOD PreCreate(nsISupports *nativeObj, JSContext *cx,
                        JSObject *globalObj, JSObject **parentObj);
+  NS_IMETHOD NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
+                        JSObject *obj, jsid id, PRUint32 flags,
+                        JSObject **objp, PRBool *_retval);
 
   static nsIClassInfo *doCreate(nsDOMClassInfoData* aData)
   {
     return new nsNavigatorSH(aData);
   }
 };
 
 
--- a/dom/base/nsGlobalWindow.h
+++ b/dom/base/nsGlobalWindow.h
@@ -532,16 +532,20 @@ public:
                                     const nsAString &aPopupWindowName,
                                     const nsAString &aPopupWindowFeatures);
 
   virtual PRUint32 GetSerial() {
     return mSerial;
   }
 
   static nsGlobalWindow* GetOuterWindowWithId(PRUint64 aWindowID) {
+    if (!sWindowsById) {
+      return nsnull;
+    }
+
     nsGlobalWindow* outerWindow = sWindowsById->Get(aWindowID);
     return outerWindow && !outerWindow->IsInnerWindow() ? outerWindow : nsnull;
   }
 
   static nsGlobalWindow* GetInnerWindowWithId(PRUint64 aInnerWindowID) {
     if (!sWindowsById) {
       return nsnull;
     }
--- a/dom/base/nsIScriptNameSpaceManager.h
+++ b/dom/base/nsIScriptNameSpaceManager.h
@@ -46,16 +46,19 @@
 
 #define JAVASCRIPT_GLOBAL_PROPERTY_CATEGORY \
   "JavaScript-global-property"
 
 // a global property that is only accessible to privileged script 
 #define JAVASCRIPT_GLOBAL_PRIVILEGED_PROPERTY_CATEGORY \
   "JavaScript-global-privileged-property"
 
+#define JAVASCRIPT_NAVIGATOR_PROPERTY_CATEGORY \
+  "JavaScript-navigator-property"
+
 #define JAVASCRIPT_GLOBAL_STATIC_NAMESET_CATEGORY \
   "JavaScript-global-static-nameset"
 
 #define JAVASCRIPT_GLOBAL_DYNAMIC_NAMESET_CATEGORY \
   "JavaScript-global-dynamic-nameset"
 
 #define JAVASCRIPT_DOM_CLASS \
   "JavaScript-DOM-class"
--- a/dom/base/nsScriptNameSpaceManager.cpp
+++ b/dom/base/nsScriptNameSpaceManager.cpp
@@ -143,28 +143,29 @@ nsScriptNameSpaceManager::nsScriptNameSp
   MOZ_COUNT_CTOR(nsScriptNameSpaceManager);
 }
 
 nsScriptNameSpaceManager::~nsScriptNameSpaceManager()
 {
   if (mIsInitialized) {
     // Destroy the hash
     PL_DHashTableFinish(&mGlobalNames);
+    PL_DHashTableFinish(&mNavigatorNames);
   }
   MOZ_COUNT_DTOR(nsScriptNameSpaceManager);
 }
 
 nsGlobalNameStruct *
-nsScriptNameSpaceManager::AddToHash(const char *aKey,
+nsScriptNameSpaceManager::AddToHash(PLDHashTable *aTable, const char *aKey,
                                     const PRUnichar **aClassName)
 {
   NS_ConvertASCIItoUTF16 key(aKey);
   GlobalNameMapEntry *entry =
     static_cast<GlobalNameMapEntry *>
-               (PL_DHashTableOperate(&mGlobalNames, &key, PL_DHASH_ADD));
+               (PL_DHashTableOperate(aTable, &key, PL_DHASH_ADD));
 
   if (!entry) {
     return nsnull;
   }
 
   if (aClassName) {
     *aClassName = entry->mKey.get();
   }
@@ -366,17 +367,17 @@ nsScriptNameSpaceManager::RegisterExtern
 
 nsresult
 nsScriptNameSpaceManager::RegisterInterface(const char* aIfName,
                                             const nsIID *aIfIID,
                                             PRBool* aFoundOld)
 {
   *aFoundOld = PR_FALSE;
 
-  nsGlobalNameStruct *s = AddToHash(aIfName);
+  nsGlobalNameStruct *s = AddToHash(&mGlobalNames, aIfName);
   NS_ENSURE_TRUE(s, NS_ERROR_OUT_OF_MEMORY);
 
   if (s->mType != nsGlobalNameStruct::eTypeNotInitialized) {
     *aFoundOld = PR_TRUE;
 
     return NS_OK;
   }
 
@@ -403,16 +404,25 @@ nsScriptNameSpaceManager::Init()
     GlobalNameHashInitEntry
   };
 
   mIsInitialized = PL_DHashTableInit(&mGlobalNames, &hash_table_ops, nsnull,
                                      sizeof(GlobalNameMapEntry), 
                                      GLOBALNAME_HASHTABLE_INITIAL_SIZE);
   NS_ENSURE_TRUE(mIsInitialized, NS_ERROR_OUT_OF_MEMORY);
 
+  mIsInitialized = PL_DHashTableInit(&mNavigatorNames, &hash_table_ops, nsnull,
+                                     sizeof(GlobalNameMapEntry), 
+                                     GLOBALNAME_HASHTABLE_INITIAL_SIZE);
+  if (!mIsInitialized) {
+    PL_DHashTableFinish(&mGlobalNames);
+
+    return NS_ERROR_OUT_OF_MEMORY;
+  }
+
   nsresult rv = NS_OK;
 
   rv = FillHashWithDOMInterfaces();
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsCOMPtr<nsICategoryManager> cm =
     do_GetService(NS_CATEGORYMANAGER_CONTRACTID, &rv);
   NS_ENSURE_SUCCESS(rv, rv);
@@ -427,16 +437,19 @@ nsScriptNameSpaceManager::Init()
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = FillHash(cm, JAVASCRIPT_GLOBAL_STATIC_NAMESET_CATEGORY);
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = FillHash(cm, JAVASCRIPT_GLOBAL_DYNAMIC_NAMESET_CATEGORY);
   NS_ENSURE_SUCCESS(rv, rv);
 
+  rv = FillHash(cm, JAVASCRIPT_NAVIGATOR_PROPERTY_CATEGORY);
+  NS_ENSURE_SUCCESS(rv, rv);
+
   // Initial filling of the has table has been done.
   // Now, listen for changes.
   nsCOMPtr<nsIObserverService> serv = 
     do_GetService(NS_OBSERVERSERVICE_CONTRACTID);
 
   if (serv) {
     serv->AddObserver(this, NS_XPCOM_CATEGORY_ENTRY_ADDED_OBSERVER_ID, PR_TRUE);
   }
@@ -505,27 +518,46 @@ nsScriptNameSpaceManager::LookupName(con
       *aClassName = nsnull;
     }
   }
 
   return NS_OK;
 }
 
 nsresult
+nsScriptNameSpaceManager::LookupNavigatorName(const nsAString& aName,
+                                              const nsGlobalNameStruct **aNameStruct)
+{
+  GlobalNameMapEntry *entry =
+    static_cast<GlobalNameMapEntry *>
+               (PL_DHashTableOperate(&mNavigatorNames, &aName,
+                                     PL_DHASH_LOOKUP));
+
+  if (PL_DHASH_ENTRY_IS_BUSY(entry) &&
+      !((&entry->mGlobalName)->mDisabled)) {
+    *aNameStruct = &entry->mGlobalName;
+  } else {
+    *aNameStruct = nsnull;
+  }
+
+  return NS_OK;
+}
+
+nsresult
 nsScriptNameSpaceManager::RegisterClassName(const char *aClassName,
                                             PRInt32 aDOMClassInfoID,
                                             PRBool aPrivileged,
                                             PRBool aDisabled,
                                             const PRUnichar **aResult)
 {
   if (!nsCRT::IsAscii(aClassName)) {
     NS_ERROR("Trying to register a non-ASCII class name");
     return NS_OK;
   }
-  nsGlobalNameStruct *s = AddToHash(aClassName, aResult);
+  nsGlobalNameStruct *s = AddToHash(&mGlobalNames, aClassName, aResult);
   NS_ENSURE_TRUE(s, NS_ERROR_OUT_OF_MEMORY);
 
   if (s->mType == nsGlobalNameStruct::eTypeClassConstructor) {
     return NS_OK;
   }
 
   // If a external constructor is already defined with aClassName we
   // won't overwrite it.
@@ -550,17 +582,17 @@ nsresult
 nsScriptNameSpaceManager::RegisterClassProto(const char *aClassName,
                                              const nsIID *aConstructorProtoIID,
                                              PRBool *aFoundOld)
 {
   NS_ENSURE_ARG_POINTER(aConstructorProtoIID);
 
   *aFoundOld = PR_FALSE;
 
-  nsGlobalNameStruct *s = AddToHash(aClassName);
+  nsGlobalNameStruct *s = AddToHash(&mGlobalNames, aClassName);
   NS_ENSURE_TRUE(s, NS_ERROR_OUT_OF_MEMORY);
 
   if (s->mType != nsGlobalNameStruct::eTypeNotInitialized &&
       s->mType != nsGlobalNameStruct::eTypeInterface) {
     *aFoundOld = PR_TRUE;
 
     return NS_OK;
   }
@@ -570,17 +602,17 @@ nsScriptNameSpaceManager::RegisterClassP
 
   return NS_OK;
 }
 
 nsresult
 nsScriptNameSpaceManager::RegisterExternalClassName(const char *aClassName,
                                                     nsCID& aCID)
 {
-  nsGlobalNameStruct *s = AddToHash(aClassName);
+  nsGlobalNameStruct *s = AddToHash(&mGlobalNames, aClassName);
   NS_ENSURE_TRUE(s, NS_ERROR_OUT_OF_MEMORY);
 
   // If an external constructor is already defined with aClassName we
   // won't overwrite it.
 
   if (s->mType == nsGlobalNameStruct::eTypeExternalConstructor) {
     return NS_OK;
   }
@@ -600,17 +632,17 @@ nsScriptNameSpaceManager::RegisterDOMCID
                                             nsDOMClassInfoExternalConstructorFnc aConstructorFptr,
                                             const nsIID *aProtoChainInterface,
                                             const nsIID **aInterfaces,
                                             PRUint32 aScriptableFlags,
                                             PRBool aHasClassInterface,
                                             const nsCID *aConstructorCID)
 {
   const PRUnichar* className;
-  nsGlobalNameStruct *s = AddToHash(aName, &className);
+  nsGlobalNameStruct *s = AddToHash(&mGlobalNames, aName, &className);
   NS_ENSURE_TRUE(s, NS_ERROR_OUT_OF_MEMORY);
 
   // If an external constructor is already defined with aClassName we
   // won't overwrite it.
 
   if (s->mType == nsGlobalNameStruct::eTypeClassConstructor ||
       s->mType == nsGlobalNameStruct::eTypeExternalClassInfo) {
     return NS_OK;
@@ -652,16 +684,18 @@ nsScriptNameSpaceManager::AddCategoryEnt
   // Observe() but this way, we have only one place to update and this is
   // not performance sensitive.
   nsGlobalNameStruct::nametype type;
   if (strcmp(aCategory, JAVASCRIPT_GLOBAL_CONSTRUCTOR_CATEGORY) == 0) {
     type = nsGlobalNameStruct::eTypeExternalConstructor;
   } else if (strcmp(aCategory, JAVASCRIPT_GLOBAL_PROPERTY_CATEGORY) == 0 ||
              strcmp(aCategory, JAVASCRIPT_GLOBAL_PRIVILEGED_PROPERTY_CATEGORY) == 0) {
     type = nsGlobalNameStruct::eTypeProperty;
+  } else if (strcmp(aCategory, JAVASCRIPT_NAVIGATOR_PROPERTY_CATEGORY) == 0) {
+    type = nsGlobalNameStruct::eTypeNavigatorProperty;
   } else if (strcmp(aCategory, JAVASCRIPT_GLOBAL_STATIC_NAMESET_CATEGORY) == 0) {
     type = nsGlobalNameStruct::eTypeStaticNameSet;
   } else if (strcmp(aCategory, JAVASCRIPT_GLOBAL_DYNAMIC_NAMESET_CATEGORY) == 0) {
     type = nsGlobalNameStruct::eTypeDynamicNameSet;
   } else {
     return NS_OK;
   }
 
@@ -699,17 +733,17 @@ nsScriptNameSpaceManager::AddCategoryEnt
   nsMemory::Free(cidPtr);
 
   if (type == nsGlobalNameStruct::eTypeExternalConstructor) {
     nsXPIDLCString constructorProto;
     rv = aCategoryManager->GetCategoryEntry(JAVASCRIPT_GLOBAL_CONSTRUCTOR_PROTO_ALIAS_CATEGORY,
                                             categoryEntry.get(),
                                             getter_Copies(constructorProto));
     if (NS_SUCCEEDED(rv)) {
-      nsGlobalNameStruct *s = AddToHash(categoryEntry.get());
+      nsGlobalNameStruct *s = AddToHash(&mGlobalNames, categoryEntry.get());
       NS_ENSURE_TRUE(s, NS_ERROR_OUT_OF_MEMORY);
 
       if (s->mType == nsGlobalNameStruct::eTypeNotInitialized) {
         s->mAlias = new nsGlobalNameStruct::ConstructorAlias;
         s->mType = nsGlobalNameStruct::eTypeExternalConstructorAlias;
         s->mChromeOnly = PR_FALSE;
         s->mAlias->mCID = cid;
         AppendASCIItoUTF16(constructorProto, s->mAlias->mProtoName);
@@ -717,17 +751,24 @@ nsScriptNameSpaceManager::AddCategoryEnt
       } else {
         NS_WARNING("Global script name not overwritten!");
       }
 
       return NS_OK;
     }
   }
 
-  nsGlobalNameStruct *s = AddToHash(categoryEntry.get());
+  PLDHashTable *table;
+  if (type == nsGlobalNameStruct::eTypeNavigatorProperty) {
+    table = &mNavigatorNames;
+  } else {
+    table = &mGlobalNames;
+  }
+
+  nsGlobalNameStruct *s = AddToHash(table, categoryEntry.get());
   NS_ENSURE_TRUE(s, NS_ERROR_OUT_OF_MEMORY);
 
   if (s->mType == nsGlobalNameStruct::eTypeNotInitialized) {
     s->mType = type;
     s->mCID = cid;
     s->mChromeOnly =
       strcmp(aCategory, JAVASCRIPT_GLOBAL_PRIVILEGED_PROPERTY_CATEGORY) == 0;
   } else {
--- a/dom/base/nsScriptNameSpaceManager.h
+++ b/dom/base/nsScriptNameSpaceManager.h
@@ -70,16 +70,17 @@ struct nsGlobalNameStruct
     nsString mProtoName;
     nsGlobalNameStruct* mProto;    
   };
 
   enum nametype {
     eTypeNotInitialized,
     eTypeInterface,
     eTypeProperty,
+    eTypeNavigatorProperty,
     eTypeExternalConstructor,
     eTypeStaticNameSet,
     eTypeDynamicNameSet,
     eTypeClassConstructor,
     eTypeClassProto,
     eTypeExternalClassInfoCreator,
     eTypeExternalClassInfo,
     eTypeExternalConstructorAlias
@@ -123,16 +124,22 @@ public:
   // Returns a nsGlobalNameStruct for aName, or null if one is not
   // found. The returned nsGlobalNameStruct is only guaranteed to be
   // valid until the next call to any of the methods in this class.
   // It also returns a pointer to the string buffer of the classname
   // in the nsGlobalNameStruct.
   nsresult LookupName(const nsAString& aName,
                       const nsGlobalNameStruct **aNameStruct,
                       const PRUnichar **aClassName = nsnull);
+  // Returns a nsGlobalNameStruct for the navigator property aName, or
+  // null if one is not found. The returned nsGlobalNameStruct is only
+  // guaranteed to be valid until the next call to any of the methods
+  // in this class.
+  nsresult LookupNavigatorName(const nsAString& aName,
+                               const nsGlobalNameStruct **aNameStruct);
 
   nsresult RegisterClassName(const char *aClassName,
                              PRInt32 aDOMClassInfoID,
                              PRBool aPrivileged,
                              PRBool aDisabled,
                              const PRUnichar **aResult);
 
   nsresult RegisterClassProto(const char *aClassName,
@@ -156,17 +163,17 @@ public:
 
   nsGlobalNameStruct* GetConstructorProto(const nsGlobalNameStruct* aStruct);
 
 protected:
   // Adds a new entry to the hash and returns the nsGlobalNameStruct
   // that aKey will be mapped to. If mType in the returned
   // nsGlobalNameStruct is != eTypeNotInitialized, an entry for aKey
   // already existed.
-  nsGlobalNameStruct *AddToHash(const char *aKey,
+  nsGlobalNameStruct *AddToHash(PLDHashTable *aTable, const char *aKey,
                                 const PRUnichar **aClassName = nsnull);
 
   nsresult FillHash(nsICategoryManager *aCategoryManager,
                     const char *aCategory);
   nsresult FillHashWithDOMInterfaces();
   nsresult RegisterInterface(const char* aIfName,
                              const nsIID *aIfIID,
                              PRBool* aFoundOld);
@@ -179,16 +186,15 @@ protected:
    * @aCategoryManager Instance of the category manager service.
    * @aCategory        Category where the entry comes from.
    * @aEntry           The entry that should be added.
    */
   nsresult AddCategoryEntryToHash(nsICategoryManager* aCategoryManager,
                                   const char* aCategory,
                                   nsISupports* aEntry);
 
-  // Inline PLDHashTable, init with PL_DHashTableInit() and delete
-  // with PL_DHashTableFinish().
   PLDHashTable mGlobalNames;
+  PLDHashTable mNavigatorNames;
 
   PRPackedBool mIsInitialized;
 };
 
 #endif /* nsScriptNameSpaceManager_h__ */
--- 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/plugins/ipc/PluginInstanceChild.cpp
+++ b/dom/plugins/ipc/PluginInstanceChild.cpp
@@ -980,17 +980,17 @@ PluginInstanceChild::AnswerNPP_SetWindow
     mWsInfo.colormap = aWindow.colormap;
     if (!XVisualIDToInfo(mWsInfo.display, aWindow.visualID,
                          &mWsInfo.visual, &mWsInfo.depth))
         return false;
 
 #ifdef MOZ_WIDGET_GTK2
     if (gtk_check_version(2,18,7) != NULL) { // older
         if (aWindow.type == NPWindowTypeWindow) {
-            GdkWindow* socket_window = gdk_window_lookup(aWindow.window);
+            GdkWindow* socket_window = gdk_window_lookup(static_cast<GdkNativeWindow>(aWindow.window));
             if (socket_window) {
                 // A GdkWindow for the socket already exists.  Need to
                 // workaround https://bugzilla.gnome.org/show_bug.cgi?id=607061
                 // See wrap_gtk_plug_embedded in PluginModuleChild.cpp.
                 g_object_set_data(G_OBJECT(socket_window),
                                   "moz-existed-before-set-window",
                                   GUINT_TO_POINTER(1));
             }
@@ -1034,17 +1034,17 @@ PluginInstanceChild::AnswerNPP_SetWindow
               aWindow.height == 0) {
             // Skip SetWindow call for hidden QuickTime plugins
             return true;
           }
 
           if (!CreatePluginWindow())
               return false;
 
-          ReparentPluginWindow((HWND)aWindow.window);
+          ReparentPluginWindow(reinterpret_cast<HWND>(aWindow.window));
           SizePluginWindow(aWindow.width, aWindow.height);
 
           mWindow.window = (void*)mPluginWindowHWND;
           mWindow.x = aWindow.x;
           mWindow.y = aWindow.y;
           mWindow.width = aWindow.width;
           mWindow.height = aWindow.height;
           mWindow.type = aWindow.type;
--- a/dom/plugins/ipc/PluginInstanceParent.cpp
+++ b/dom/plugins/ipc/PluginInstanceParent.cpp
@@ -599,17 +599,17 @@ PluginInstanceParent::RecvShow(const NPR
     return true;
 }
 
 nsresult
 PluginInstanceParent::AsyncSetWindow(NPWindow* aWindow)
 {
     NPRemoteWindow window;
     mWindowType = aWindow->type;
-    window.window = reinterpret_cast<uintptr_t>(aWindow->window);
+    window.window = reinterpret_cast<uint64_t>(aWindow->window);
     window.x = aWindow->x;
     window.y = aWindow->y;
     window.width = aWindow->width;
     window.height = aWindow->height;
     window.clipRect = aWindow->clipRect;
     window.type = aWindow->type;
     if (!SendAsyncSetWindow(gfxPlatform::GetPlatform()->ScreenReferenceSurface()->GetType(),
                             window))
@@ -906,25 +906,25 @@ PluginInstanceParent::NPP_SetWindow(cons
         // SharedSurfaceSetWindow will take care of NPRemoteWindow.
         if (!SharedSurfaceSetWindow(aWindow, window)) {
           return NPERR_OUT_OF_MEMORY_ERROR;
         }
     }
     else {
         SubclassPluginWindow(reinterpret_cast<HWND>(aWindow->window));
 
-        window.window = reinterpret_cast<uintptr_t>(aWindow->window);
+        window.window = reinterpret_cast<uint64_t>(aWindow->window);
         window.x = aWindow->x;
         window.y = aWindow->y;
         window.width = aWindow->width;
         window.height = aWindow->height;
         window.type = aWindow->type;
     }
 #else
-    window.window = reinterpret_cast<unsigned long>(aWindow->window);
+    window.window = reinterpret_cast<uint64_t>(aWindow->window);
     window.x = aWindow->x;
     window.y = aWindow->y;
     window.width = aWindow->width;
     window.height = aWindow->height;
     window.clipRect = aWindow->clipRect; // MacOS specific
     window.type = aWindow->type;
 #endif
 
--- a/dom/plugins/ipc/PluginMessageUtils.h
+++ b/dom/plugins/ipc/PluginMessageUtils.h
@@ -105,17 +105,17 @@ struct IPCByteRange
 };  
 
 typedef std::vector<IPCByteRange> IPCByteRanges;
 
 typedef nsCString Buffer;
 
 struct NPRemoteWindow
 {
-  unsigned long window;
+  uint64_t window;
   int32_t x;
   int32_t y;
   uint32_t width;
   uint32_t height;
   NPRect clipRect;
   NPWindowType type;
 #if defined(MOZ_X11) && defined(XP_UNIX) && !defined(XP_MACOSX)
   VisualID visualID;
@@ -358,17 +358,17 @@ struct ParamTraits<NPWindowType>
 
 template <>
 struct ParamTraits<mozilla::plugins::NPRemoteWindow>
 {
   typedef mozilla::plugins::NPRemoteWindow paramType;
 
   static void Write(Message* aMsg, const paramType& aParam)
   {
-    aMsg->WriteULong(aParam.window);
+    aMsg->WriteUInt64(aParam.window);
     WriteParam(aMsg, aParam.x);
     WriteParam(aMsg, aParam.y);
     WriteParam(aMsg, aParam.width);
     WriteParam(aMsg, aParam.height);
     WriteParam(aMsg, aParam.clipRect);
     WriteParam(aMsg, aParam.type);
 #if defined(MOZ_X11) && defined(XP_UNIX) && !defined(XP_MACOSX)
     aMsg->WriteULong(aParam.visualID);
@@ -376,22 +376,22 @@ struct ParamTraits<mozilla::plugins::NPR
 #endif
 #if defined(XP_WIN)
     WriteParam(aMsg, aParam.surfaceHandle);
 #endif
   }
 
   static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
   {
-    unsigned long window;
+    uint64_t window;
     int32_t x, y;
     uint32_t width, height;
     NPRect clipRect;
     NPWindowType type;
-    if (!(aMsg->ReadULong(aIter, &window) &&
+    if (!(aMsg->ReadUInt64(aIter, &window) &&
           ReadParam(aMsg, aIter, &x) &&
           ReadParam(aMsg, aIter, &y) &&
           ReadParam(aMsg, aIter, &width) &&
           ReadParam(aMsg, aIter, &height) &&
           ReadParam(aMsg, aIter, &clipRect) &&
           ReadParam(aMsg, aIter, &type)))
       return false;
 
--- a/dom/tests/mochitest/bugs/Makefile.in
+++ b/dom/tests/mochitest/bugs/Makefile.in
@@ -132,19 +132,21 @@ include $(topsrcdir)/config/rules.mk
 		test_bug593174.html \
 		file_bug593174_1.html \
 		file_bug593174_2.html \
 		test_bug612267.html \
 		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)
 
--- a/dom/tests/mochitest/bugs/test_bug597809.html
+++ b/dom/tests/mochitest/bugs/test_bug597809.html
@@ -13,24 +13,21 @@ https://bugzilla.mozilla.org/show_bug.cg
 <p id="display"></p>
 <pre id="test">
 <script type="application/javascript">
 
 /** Test for Bug 597809 **/
 
 SimpleTest.waitForExplicitFinish();
 
-netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
-var cm = Components.classes["@mozilla.org/categorymanager;1"]
-                   .getService(Components.interfaces.nsICategoryManager);
-cm.addCategoryEntry("JavaScript-global-property", "testSNSM", "@mozilla.org/embedcomp/prompt-service;1",
+SpecialPowers.addCategoryEntry("JavaScript-global-property", "testSNSM", "@mozilla.org/embedcomp/prompt-service;1",
                     false, true);
 
 SimpleTest.executeSoon(function () {
-  ok(window.testSNSM, "testSNSM should returns an object");
+  ok(window.testSNSM, "testSNSM should return an object");
   SimpleTest.finish();
 });
 
 
 </script>
 </pre>
 </body>
 </html>
new file mode 100644
--- /dev/null
+++ b/dom/tests/mochitest/bugs/test_bug641552.html
@@ -0,0 +1,42 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=641552
+-->
+<head>
+  <title>Test for Bug 641552</title>
+  <script type="application/javascript" src="/MochiKit/packed.js"></script>
+  <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=641552">Mozilla Bug 641552</a>
+<p id="display"></p>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 641552 **/
+
+SimpleTest.waitForExplicitFinish();
+
+SpecialPowers.addCategoryEntry("JavaScript-global-property", "randomname", "@mozilla.org/embedcomp/prompt-service;1",
+                    false, true);
+
+SpecialPowers.addCategoryEntry("JavaScript-navigator-property", "randomname1", "@mozilla.org/embedcomp/prompt-service;1",
+                    false, true);
+
+SpecialPowers.addCategoryEntry("JavaScript-navigator-property", "randomname2", "@mozilla.org/embedcomp/prompt-service;1",
+                    false, true);
+
+SimpleTest.executeSoon(function () {
+  ok(window.randomname, "window.randomname should return an object");
+  is(typeof(window.navigator.randomname1), 'object', "navigator.randomname1 should return an object");
+  is(typeof(window.navigator.randomname2), 'object', "navigator.randomname1 should return an object");
+  SimpleTest.finish();
+});
+
+
+</script>
+</pre>
+</body>
+</html>
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/editor/composer/src/crashtests/crashtests.list
+++ b/editor/composer/src/crashtests/crashtests.list
@@ -1,6 +1,6 @@
-load 351236-1.html
+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/composer/src/nsEditorSpellCheck.cpp
+++ b/editor/composer/src/nsEditorSpellCheck.cpp
@@ -49,22 +49,18 @@
 #include "nsISpellChecker.h"
 #include "nsISelection.h"
 #include "nsIDOMRange.h"
 #include "nsIEditor.h"
 #include "nsIHTMLEditor.h"
 
 #include "nsIComponentManager.h"
 #include "nsIContentPrefService.h"
-#include "nsIObserverService.h"
 #include "nsServiceManagerUtils.h"
 #include "nsIChromeRegistry.h"
-#include "nsIPrivateBrowsingService.h"
-#include "nsIContentURIGrouper.h"
-#include "nsNetCID.h"
 #include "nsString.h"
 #include "nsReadableUtils.h"
 #include "nsITextServicesFilter.h"
 #include "nsUnicharUtils.h"
 #include "mozilla/Services.h"
 #include "mozilla/Preferences.h"
 
 using namespace mozilla;
@@ -82,26 +78,21 @@ class UpdateDictionnaryHolder {
       if (mSpellCheck) {
         mSpellCheck->EndUpdateDictionary();
       }
     }
 };
 
 #define CPS_PREF_NAME NS_LITERAL_STRING("spellcheck.lang")
 
-class LastDictionary : public nsIObserver, public nsSupportsWeakReference {
+class LastDictionary {
 public:
-  NS_DECL_ISUPPORTS
-  NS_DECL_NSIOBSERVER
-
-  LastDictionary();
-
   /**
    * Store current dictionary for editor document url. Use content pref
-   * service. Or, if in private mode, store this information in memory.
+   * service.
    */
   NS_IMETHOD StoreCurrentDictionary(nsIEditor* aEditor, const nsAString& aDictionary);
 
   /**
    * Get last stored current dictionary for editor document url.
    */
   NS_IMETHOD FetchLastDictionary(nsIEditor* aEditor, nsAString& aDictionary);
 
@@ -110,36 +101,18 @@ public:
    */
   NS_IMETHOD ClearCurrentDictionary(nsIEditor* aEditor);
 
   /**
    * get uri of editor's document.
    *
    */
   static nsresult GetDocumentURI(nsIEditor* aEditor, nsIURI * *aURI);
-
-  PRBool mInPrivateBrowsing;
-
-  // During private browsing, dictionaries are stored in memory
-  nsDataHashtable<nsStringHashKey, nsString> mMemoryStorage;
 };
 
-NS_IMPL_ISUPPORTS2(LastDictionary, nsIObserver, nsISupportsWeakReference)
-
-LastDictionary::LastDictionary():
-  mInPrivateBrowsing(PR_FALSE)
-{  
-  nsCOMPtr<nsIPrivateBrowsingService> pbService =
-    do_GetService(NS_PRIVATE_BROWSING_SERVICE_CONTRACTID);
-  if (pbService) {
-    pbService->GetPrivateBrowsingEnabled(&mInPrivateBrowsing);
-    mMemoryStorage.Init();
-  }
-}
-
 // static
 nsresult
 LastDictionary::GetDocumentURI(nsIEditor* aEditor, nsIURI * *aURI)
 {
   NS_ENSURE_ARG_POINTER(aEditor);
   NS_ENSURE_ARG_POINTER(aURI);
 
   nsCOMPtr<nsIDOMDocument> domDoc;
@@ -163,31 +136,16 @@ LastDictionary::FetchLastDictionary(nsIE
   NS_ENSURE_ARG_POINTER(aEditor);
 
   nsresult rv;
 
   nsCOMPtr<nsIURI> docUri;
   rv = GetDocumentURI(aEditor, getter_AddRefs(docUri));
   NS_ENSURE_SUCCESS(rv, rv);
 
-  if (mInPrivateBrowsing) {
-    nsCOMPtr<nsIContentURIGrouper> hostnameGrouperService =
-      do_GetService(NS_HOSTNAME_GROUPER_SERVICE_CONTRACTID);
-    NS_ENSURE_TRUE(hostnameGrouperService, NS_ERROR_NOT_AVAILABLE);
-    nsString group;
-    hostnameGrouperService->Group(docUri, group);
-    nsAutoString lastDict;
-    if (mMemoryStorage.Get(group, &lastDict)) {
-      aDictionary.Assign(lastDict);
-    } else {
-      aDictionary.Truncate();
-    }
-    return NS_OK;
-  }
-
   nsCOMPtr<nsIContentPrefService> contentPrefService =
     do_GetService(NS_CONTENT_PREF_SERVICE_CONTRACTID);
   NS_ENSURE_TRUE(contentPrefService, NS_ERROR_NOT_AVAILABLE);
 
   nsCOMPtr<nsIWritableVariant> uri = do_CreateInstance(NS_VARIANT_CONTRACTID);
   NS_ENSURE_TRUE(uri, NS_ERROR_OUT_OF_MEMORY);
   uri->SetAsISupports(docUri);
 
@@ -209,30 +167,16 @@ LastDictionary::StoreCurrentDictionary(n
   NS_ENSURE_ARG_POINTER(aEditor);
 
   nsresult rv;
 
   nsCOMPtr<nsIURI> docUri;
   rv = GetDocumentURI(aEditor, getter_AddRefs(docUri));
   NS_ENSURE_SUCCESS(rv, rv);
 
- if (mInPrivateBrowsing) {
-    nsCOMPtr<nsIContentURIGrouper> hostnameGrouperService =
-      do_GetService(NS_HOSTNAME_GROUPER_SERVICE_CONTRACTID);
-    NS_ENSURE_TRUE(hostnameGrouperService, NS_ERROR_NOT_AVAILABLE);
-    nsString group;
-    hostnameGrouperService->Group(docUri, group);
-
-    if (mMemoryStorage.Put(group, nsString(aDictionary))) {
-      return NS_OK;
-    } else {
-      return NS_ERROR_FAILURE;
-    }
-  }
-
   nsCOMPtr<nsIWritableVariant> uri = do_CreateInstance(NS_VARIANT_CONTRACTID);
   NS_ENSURE_TRUE(uri, NS_ERROR_OUT_OF_MEMORY);
   uri->SetAsISupports(docUri);
 
   nsCOMPtr<nsIWritableVariant> prefValue = do_CreateInstance(NS_VARIANT_CONTRACTID);
   NS_ENSURE_TRUE(prefValue, NS_ERROR_OUT_OF_MEMORY);
   prefValue->SetAsAString(aDictionary);
 
@@ -249,55 +193,27 @@ LastDictionary::ClearCurrentDictionary(n
   NS_ENSURE_ARG_POINTER(aEditor);
 
   nsresult rv;
 
   nsCOMPtr<nsIURI> docUri;
   rv = GetDocumentURI(aEditor, getter_AddRefs(docUri));
   NS_ENSURE_SUCCESS(rv, rv);
 
-  nsCOMPtr<nsIContentURIGrouper> hostnameGrouperService =
-      do_GetService(NS_HOSTNAME_GROUPER_SERVICE_CONTRACTID);
-  NS_ENSURE_TRUE(hostnameGrouperService, NS_ERROR_NOT_AVAILABLE);
-
-  nsString group;
-  hostnameGrouperService->Group(docUri, group);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  if (mMemoryStorage.IsInitialized()) {
-    mMemoryStorage.Remove(group);
-  }
-
   nsCOMPtr<nsIWritableVariant> uri = do_CreateInstance(NS_VARIANT_CONTRACTID);
   NS_ENSURE_TRUE(uri, NS_ERROR_OUT_OF_MEMORY);
   uri->SetAsISupports(docUri);
 
   nsCOMPtr<nsIContentPrefService> contentPrefService =
     do_GetService(NS_CONTENT_PREF_SERVICE_CONTRACTID);
   NS_ENSURE_TRUE(contentPrefService, NS_ERROR_NOT_INITIALIZED);
 
   return contentPrefService->RemovePref(uri, CPS_PREF_NAME);
 }
 
-NS_IMETHODIMP
-LastDictionary::Observe(nsISupports *aSubject, char const *aTopic, PRUnichar const *aData)
-{
-  if (strcmp(aTopic, NS_PRIVATE_BROWSING_SWITCH_TOPIC) == 0) {
-    if (NS_LITERAL_STRING(NS_PRIVATE_BROWSING_ENTER).Equals(aData)) {
-      mInPrivateBrowsing = PR_TRUE;
-    } else if (NS_LITERAL_STRING(NS_PRIVATE_BROWSING_LEAVE).Equals(aData)) {
-      mInPrivateBrowsing = PR_FALSE;
-      if (mMemoryStorage.IsInitialized()) {
-        mMemoryStorage.Clear();
-      }
-    }
-  } 
-  return NS_OK;
-}
-
 LastDictionary* nsEditorSpellCheck::gDictionaryStore = nsnull;
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsEditorSpellCheck)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsEditorSpellCheck)
 
 NS_INTERFACE_MAP_BEGIN(nsEditorSpellCheck)
   NS_INTERFACE_MAP_ENTRY(nsIEditorSpellCheck)
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIEditorSpellCheck)
@@ -353,24 +269,16 @@ nsEditorSpellCheck::InitSpellChecker(nsI
 {
   NS_ENSURE_TRUE(aEditor, NS_ERROR_NULL_POINTER);
   mEditor = aEditor;
 
   nsresult rv;
 
   if (!gDictionaryStore) {
     gDictionaryStore = new LastDictionary();
-    if (gDictionaryStore) {
-      NS_ADDREF(gDictionaryStore);
-      nsCOMPtr<nsIObserverService> observerService =
-        mozilla::services::GetObserverService();
-      if (observerService) {
-        observerService->AddObserver(gDictionaryStore, NS_PRIVATE_BROWSING_SWITCH_TOPIC, PR_TRUE);
-      }
-    }
   }
 
 
   // We can spell check with any editor type
   nsCOMPtr<nsITextServicesDocument>tsDoc =
      do_CreateInstance("@mozilla.org/textservices/textservicesdocument;1", &rv);
   NS_ENSURE_SUCCESS(rv, rv);
 
@@ -645,24 +553,16 @@ nsEditorSpellCheck::SetCurrentDictionary
 
     // Also store it in as a preference. It will be used as a default value
     // when everything else fails.
     Preferences::SetString("spellchecker.dictionary", aDictionary);
   }
   return mSpellChecker->SetCurrentDictionary(aDictionary);
 }
 
-NS_IMETHODIMP
-nsEditorSpellCheck::GetSpellChecker(nsISpellChecker **aSpellChecker)
-{
-  *aSpellChecker = mSpellChecker;
-  NS_IF_ADDREF(*aSpellChecker);
-  return NS_OK;
-}
-
 NS_IMETHODIMP    
 nsEditorSpellCheck::UninitSpellChecker()
 {
   NS_ENSURE_TRUE(mSpellChecker, NS_ERROR_NOT_INITIALIZED);
 
   // Cleanup - kill the spell checker
   DeleteSuggestedWordList();
   mDictionaryList.Clear();
@@ -821,27 +721,31 @@ nsEditorSpellCheck::UpdateCurrentDiction
   // lang attribute, we try to get a dictionary. First try, en-US. If it does
   // not work, pick the first one.
   if (mPreferredLang.IsEmpty()) {
     nsAutoString currentDictionary;
     rv = GetCurrentDictionary(currentDictionary);
     if (NS_FAILED(rv) || currentDictionary.IsEmpty()) {
       rv = SetCurrentDictionary(NS_LITERAL_STRING("en-US"));
       if (NS_FAILED(rv)) {
-        mSpellChecker->CheckCurrentDictionary();
+        nsTArray<nsString> dictList;
+        rv = mSpellChecker->GetDictionaryList(&dictList);
+        if (NS_SUCCEEDED(rv) && dictList.Length() > 0) {
+          SetCurrentDictionary(dictList[0]);
+        }
       }
     }
   }
 
   // If an error was thrown while setting the dictionary, just
   // fail silently so that the spellchecker dialog is allowed to come
   // up. The user can manually reset the language to their choice on
   // the dialog if it is wrong.
 
   DeleteSuggestedWordList();
 
   return NS_OK;
 }
 
 void 
 nsEditorSpellCheck::ShutDown() {
-  NS_IF_RELEASE(gDictionaryStore);
+  delete gDictionaryStore;
 }
--- a/editor/composer/src/nsEditorSpellCheck.h
+++ b/editor/composer/src/nsEditorSpellCheck.h
@@ -38,17 +38,16 @@
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef nsEditorSpellCheck_h___
 #define nsEditorSpellCheck_h___
 
 
 #include "nsIEditorSpellCheck.h"
 #include "nsISpellChecker.h"
-#include "nsIObserver.h"
 #include "nsIURI.h"
 #include "nsWeakReference.h"
 #include "nsCOMPtr.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsDataHashtable.h"
 
 #define NS_EDITORSPELLCHECK_CID                     \
 { /* {75656ad9-bd13-4c5d-939a-ec6351eea0cc} */        \
--- a/editor/idl/nsIEditorSpellCheck.idl
+++ b/editor/idl/nsIEditorSpellCheck.idl
@@ -35,30 +35,21 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
  
 #include "nsISupports.idl"
 
 interface nsIEditor;
 interface nsITextServicesFilter;
-%{C++
-#include "nsISpellChecker.h"
-%}
-[ptr] native nsISpellChecker(nsISpellChecker);
 
-[scriptable, uuid(334946c3-0e93-4aac-b662-e1b56f95d68b)]
+[scriptable, uuid(af84da62-588f-409f-847d-feecc991bd93)]
 interface nsIEditorSpellCheck : nsISupports
 {
 
-  /**
-   * Get the spell checker used by this editor.
-   */
-  [noscript] readonly attribute nsISpellChecker spellChecker;
-
  /**
    * Returns true if we can enable spellchecking. If there are no available
    * dictionaries, this will return false.
    */
   boolean       canSpellCheck();
 
   /**
    * Turns on the spell checker for the given editor. enableSelectionChecking
--- a/editor/libeditor/base/Makefile.in
+++ b/editor/libeditor/base/Makefile.in
@@ -89,10 +89,9 @@ FORCE_STATIC_LIB = 1
 
 include $(topsrcdir)/config/rules.mk
 
 INCLUDES	+= \
 		-I$(topsrcdir)/editor/libeditor/text \
 		-I$(topsrcdir)/content/base/src \
 		-I$(topsrcdir)/content/events/src \
 		-I$(topsrcdir)/layout/style \
-		-I$(topsrcdir)/extensions/spellcheck/src \
 		$(NULL)
--- a/editor/libeditor/base/crashtests/crashtests.list
+++ b/editor/libeditor/base/crashtests/crashtests.list
@@ -1,10 +1,10 @@
 load 336104.html
 load 382527-1.html
 load 402172-1.html
 load 407079-1.html
 load 407256-1.html
 load 430624-1.html
 load 459613.html
 load 475132-1.xhtml
-load 633709.xhtml
-asserts(6) load 636074-1.html # Bug 439258, charged to the wrong test due to bug 635550
+asserts-if(Android,6) load 633709.xhtml
+asserts-if(!Android,6) load 636074-1.html # Bug 439258, charged to the wrong test due to bug 635550
--- a/editor/libeditor/base/nsEditor.cpp
+++ b/editor/libeditor/base/nsEditor.cpp
@@ -19,17 +19,16 @@
  * Portions created by the Initial Developer are Copyright (C) 1998
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *   Pierre Phaneuf <pp@ludusdesign.com>
  *   Daniel Glazman <glazman@netscape.com>
  *   Masayuki Nakano <masayuki@d-toybox.com>
  *   Mats Palmgren <matspal@gmail.com>
- *   Jesper Kristensen <mail@jesperkristensen.dk>
  *
  * 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
@@ -44,21 +43,16 @@
 #include "nsIDOMDocument.h"
 #include "nsIDOMHTMLElement.h"
 #include "nsIDOMNSHTMLElement.h"
 #include "nsIDOMNSEvent.h"
 #include "nsIMEStateManager.h"
 #include "nsFocusManager.h"
 #include "nsUnicharUtils.h"
 #include "nsReadableUtils.h"
-#include "nsIObserverService.h"
-#include "mozilla/Services.h"
-#include "mozISpellCheckingEngine.h"
-#include "nsIEditorSpellCheck.h"
-#include "mozInlineSpellChecker.h"
 
 #include "nsIDOMText.h"
 #include "nsIDOMElement.h"
 #include "nsIDOMAttr.h"
 #include "nsIDOMNode.h"
 #include "nsIDOMDocumentFragment.h"
 #include "nsIDOMNamedNodeMap.h"
 #include "nsIDOMNodeList.h"
@@ -208,17 +202,16 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mEventListener)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsEditor)
  NS_INTERFACE_MAP_ENTRY(nsIPhonetic)
  NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
  NS_INTERFACE_MAP_ENTRY(nsIEditorIMESupport)
  NS_INTERFACE_MAP_ENTRY(nsIEditor)
- NS_INTERFACE_MAP_ENTRY(nsIObserver)
  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIEditor)
 NS_INTERFACE_MAP_END
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsEditor)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsEditor)
 
 
 NS_IMETHODIMP
@@ -302,23 +295,16 @@ nsEditor::PostCreate()
 
     // nuke the modification count, so the doc appears unmodified
     // do this before we notify listeners
     ResetModificationCount();
 
     // update the UI with our state
     NotifyDocumentListeners(eDocumentCreated);
     NotifyDocumentListeners(eDocumentStateChanged);
-
-    nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
-    if (obs) {
-      obs->AddObserver(this,
-                       SPELLCHECK_DICTIONARY_UPDATE_NOTIFICATION,
-                       PR_FALSE);
-    }
   }
 
   // update nsTextStateManager and caret if we have focus
   nsCOMPtr<nsIContent> focusedContent = GetFocusedContent();
   if (focusedContent) {
     nsCOMPtr<nsIPresShell> ps = GetPresShell();
     NS_ASSERTION(ps, "no pres shell even though we have focus");
     NS_ENSURE_TRUE(ps, NS_ERROR_UNEXPECTED);
@@ -421,22 +407,16 @@ nsEditor::GetDesiredSpellCheckState()
 }
 
 NS_IMETHODIMP
 nsEditor::PreDestroy(PRBool aDestroyingFrames)
 {
   if (mDidPreDestroy)
     return NS_OK;
 
-  nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
-  if (obs) {
-    obs->RemoveObserver(this,
-                        SPELLCHECK_DICTIONARY_UPDATE_NOTIFICATION);
-  }
-
   // Let spellchecker clean up its observers etc. It is important not to
   // actually free the spellchecker here, since the spellchecker could have
   // caused flush notifications, which could have gotten here if a textbox
   // is being removed. Setting the spellchecker to NULL could free the
   // object that is still in use! It will be freed when the editor is
   // destroyed.
   if (mInlineSpellChecker)
     mInlineSpellChecker->Cleanup(aDestroyingFrames);
@@ -1298,23 +1278,16 @@ NS_IMETHODIMP nsEditor::GetInlineSpellCh
 
   if (mDidPreDestroy) {
     // Don't allow people to get or create the spell checker once the editor
     // is going away.
     *aInlineSpellChecker = nsnull;
     return autoCreate ? NS_ERROR_NOT_AVAILABLE : NS_OK;
   }
 
-  // We don't want to show the spell checking UI if there are no spell check dictionaries available.
-  PRBool canSpell = mozInlineSpellChecker::CanEnableInlineSpellChecking();
-  if (!canSpell) {
-    *aInlineSpellChecker = nsnull;
-    return NS_ERROR_FAILURE;
-  }
-
   nsresult rv;
   if (!mInlineSpellChecker && autoCreate) {
     mInlineSpellChecker = do_CreateInstance(MOZ_INLINESPELLCHECKER_CONTRACTID, &rv);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   if (mInlineSpellChecker) {
     rv = mInlineSpellChecker->Init(this);
@@ -1323,59 +1296,27 @@ NS_IMETHODIMP nsEditor::GetInlineSpellCh
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   NS_IF_ADDREF(*aInlineSpellChecker = mInlineSpellChecker);
 
   return NS_OK;
 }
 
-NS_IMETHODIMP nsEditor::Observe(nsISupports* aSubj, const char *aTopic,
-                                const PRUnichar *aData)
-{
-  NS_ASSERTION(!strcmp(aTopic,
-                       SPELLCHECK_DICTIONARY_UPDATE_NOTIFICATION),
-               "Unexpected observer topic");
-
-  // When mozInlineSpellChecker::CanEnableInlineSpellChecking changes
-  SyncRealTimeSpell();
-
-  // When nsIEditorSpellCheck::GetCurrentDictionary changes
-  if (mInlineSpellChecker) {
-    // if the current dictionary is no longer available, find another one
-    nsCOMPtr<nsIEditorSpellCheck> editorSpellCheck;
-    mInlineSpellChecker->GetSpellChecker(getter_AddRefs(editorSpellCheck));
-    if (editorSpellCheck) {
-      nsCOMPtr<nsISpellChecker> spellChecker;
-      editorSpellCheck->GetSpellChecker(getter_AddRefs(spellChecker));
-      spellChecker->CheckCurrentDictionary();
-    }
-
-    // update the inline spell checker to reflect the new current dictionary
-    mInlineSpellChecker->SpellCheckRange(nsnull); // causes recheck
-  }
-
-  return NS_OK;
-}
-
 NS_IMETHODIMP nsEditor::SyncRealTimeSpell()
 {
   NS_TIME_FUNCTION;
 
   PRBool enable = GetDesiredSpellCheckState();
 
-  // Initializes mInlineSpellChecker
   nsCOMPtr<nsIInlineSpellChecker> spellChecker;
   GetInlineSpellChecker(enable, getter_AddRefs(spellChecker));
 
-  if (mInlineSpellChecker) {
-    // We might have a mInlineSpellChecker even if there are no dictionaries
-    // available since we don't destroy the mInlineSpellChecker when the last
-    // dictionariy is removed, but in that case spellChecker is null
-    mInlineSpellChecker->SetEnableRealTimeSpell(enable && spellChecker);
+  if (spellChecker) {
+    spellChecker->SetEnableRealTimeSpell(enable);
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP nsEditor::SetSpellcheckUserOverride(PRBool enable)
 {
   mSpellcheckCheckboxState = enable ? eTriTrue : eTriFalse;
--- a/editor/libeditor/base/nsEditor.h
+++ b/editor/libeditor/base/nsEditor.h
@@ -61,17 +61,16 @@
 #include "nsIDOMElement.h"
 #include "nsSelectionState.h"
 #include "nsIEditorSpellCheck.h"
 #include "nsIInlineSpellChecker.h"
 #include "nsIDOMEventTarget.h"
 #include "nsStubMutationObserver.h"
 #include "nsIViewManager.h"
 #include "nsCycleCollectionParticipant.h"
-#include "nsIObserver.h"
 
 class nsIDOMCharacterData;
 class nsIDOMRange;
 class nsIPresShell;
 class ChangeAttributeTxn;
 class CreateElementTxn;
 class InsertElementTxn;
 class DeleteElementTxn;
@@ -96,17 +95,16 @@ class nsIDOMNSEvent;
 /** implementation of an editor object.  it will be the controller/focal point 
  *  for the main editor services. i.e. the GUIManager, publishing, transaction 
  *  manager, event interfaces. the idea for the event interfaces is to have them 
  *  delegate the actual commands to the editor independent of the XPFE implementation.
  */
 class nsEditor : public nsIEditor,
                  public nsIEditorIMESupport,
                  public nsSupportsWeakReference,
-                 public nsIObserver,
                  public nsIPhonetic
 {
 public:
 
   enum IterDirection
   {
     kIterForward,
     kIterBackward
@@ -150,19 +148,16 @@ public:
   already_AddRefed<nsIPresShell> GetPresShell();
   void NotifyEditorObservers();
 
   /* ------------ nsIEditor methods -------------- */
   NS_DECL_NSIEDITOR
   /* ------------ nsIEditorIMESupport methods -------------- */
   NS_DECL_NSIEDITORIMESUPPORT
   
-  /* ------------ nsIObserver methods -------------- */
-  NS_DECL_NSIOBSERVER
-
   // nsIPhonetic
   NS_DECL_NSIPHONETIC
 
 public:
 
   
   NS_IMETHOD InsertTextImpl(const nsAString& aStringToInsert, 
                                nsCOMPtr<nsIDOMNode> *aInOutNode, 
--- 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/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/txtsvc/public/nsISpellChecker.h
+++ b/editor/txtsvc/public/nsISpellChecker.h
@@ -39,19 +39,19 @@
 #define nsISpellChecker_h__
 
 #include "nsISupports.h"
 #include "nsTArray.h"
 
 #define NS_SPELLCHECKER_CONTRACTID "@mozilla.org/spellchecker;1"
 
 #define NS_ISPELLCHECKER_IID                    \
-{ /* 27bff957-b486-40ae-9f5d-af0cdd211868 */    \
-0x27bff957, 0xb486, 0x40ae, \
-  { 0x9f, 0x5d, 0xaf, 0x0c, 0xdd, 0x21, 0x18, 0x68 } }
+{ /* E75AC48C-E948-452E-8DB3-30FEE29FE3D2 */    \
+0xe75ac48c, 0xe948, 0x452e, \
+  { 0x8d, 0xb3, 0x30, 0xfe, 0xe2, 0x9f, 0xe3, 0xd2 } }
 
 class nsITextServicesDocument;
 class nsString;
 
 /**
  * A generic interface for a spelling checker.
  */
 class nsISpellChecker  : public nsISupports{
@@ -141,20 +141,14 @@ public:
 
   /**
    * Tells the spellchecker to use a specific dictionary.
    * @param aDictionary a string that is in the list returned
    * by GetDictionaryList() or an empty string. If aDictionary is 
    * empty string, spellchecker will be disabled.
    */
   NS_IMETHOD SetCurrentDictionary(const nsAString &aDictionary) = 0;
-
-  /**
-   * Call this on any change in installed dictionaries to ensure that the spell
-   * checker is not using a current dictionary which is no longer available.
-   */
-  NS_IMETHOD CheckCurrentDictionary() = 0;
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsISpellChecker, NS_ISPELLCHECKER_IID)
 
 #endif // nsISpellChecker_h__
 
--- 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="11"/>
+              android:targetSdkVersion="5"/>
 
     <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/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/extensions/spellcheck/Makefile.in
+++ b/extensions/spellcheck/Makefile.in
@@ -39,13 +39,9 @@ topsrcdir	= @top_srcdir@
 srcdir		= @srcdir@
 VPATH		= @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
 MODULE		= spellchecker
 DIRS		= idl locales hunspell src
 
-ifdef ENABLE_TESTS
-DIRS		+= tests
-endif
-
 include $(topsrcdir)/config/rules.mk
--- a/extensions/spellcheck/hunspell/src/Makefile.in
+++ b/extensions/spellcheck/hunspell/src/Makefile.in
@@ -66,13 +66,11 @@ CPPSRCS         += affentry.cpp \
 
 # This variable is referenced in configure.in.  Make sure to change that file
 # too if you need to change this variable.
 DEFINES = -DHUNSPELL_STATIC
 endif
 
 include $(topsrcdir)/config/rules.mk
 
-INCLUDES        += -I$(topsrcdir)/extensions/spellcheck/src
-
 ifdef MOZ_NATIVE_HUNSPELL
 CXXFLAGS += $(MOZ_HUNSPELL_CFLAGS)
 endif
--- a/extensions/spellcheck/hunspell/src/mozHunspell.cpp
+++ b/extensions/spellcheck/hunspell/src/mozHunspell.cpp
@@ -36,17 +36,16 @@
  *                 Varga Daniel
  *                 Chris Halls
  *                 Rene Engelhard
  *                 Bram Moolenaar
  *                 Dafydd Jones
  *                 Harri Pitkanen
  *                 Andras Timar
  *                 Tor Lillqvist
- *                 Jesper Kristensen (mail@jesperkristensen.dk)
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either the GNU General Public License Version 2 or later (the "GPL"), or
  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  * in which case the provisions of the GPL or the LGPL are applicable instead
  * of those above. If you wish to allow use of your version of this file only
  * under the terms of either the GPL or the LGPL, and not to allow others to
  * use your version of this file under the terms of the MPL, indicate your
@@ -66,18 +65,16 @@
 #include "nsIFile.h"
 #include "nsDirectoryServiceUtils.h"
 #include "nsDirectoryServiceDefs.h"
 #include "mozISpellI18NManager.h"
 #include "nsICharsetConverterManager.h"
 #include "nsUnicharUtilCIID.h"
 #include "nsUnicharUtils.h"
 #include "nsCRT.h"
-#include "mozInlineSpellChecker.h"
-#include "mozilla/Services.h"
 #include <stdlib.h>
 #include "nsIMemoryReporter.h"
 
 static NS_DEFINE_CID(kCharsetConverterManagerCID, NS_ICHARSETCONVERTERMANAGER_CID);
 static NS_DEFINE_CID(kUnicharUtilCID, NS_UNICHARUTIL_CID);
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(mozHunspell)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(mozHunspell)
@@ -120,17 +117,18 @@ NS_MEMORY_REPORTER_IMPLEMENT(Hunspell,
 nsresult
 mozHunspell::Init()
 {
   if (!mDictionaries.Init())
     return NS_ERROR_OUT_OF_MEMORY;
 
   LoadDictionaryList();
 
-  nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
+  nsCOMPtr<nsIObserverService> obs =
+    do_GetService("@mozilla.org/observer-service;1");
   if (obs) {
     obs->AddObserver(this, "profile-do-change", PR_TRUE);
   }
 
   mHunspellReporter = new NS_MEMORY_REPORTER_NAME(Hunspell);
   NS_RegisterMemoryReporter(mHunspellReporter);
 
   return NS_OK;
@@ -144,58 +142,60 @@ mozHunspell::~mozHunspell()
   NS_UnregisterMemoryReporter(mHunspellReporter);
 }
 
 /* attribute wstring dictionary; */
 NS_IMETHODIMP mozHunspell::GetDictionary(PRUnichar **aDictionary)
 {
   NS_ENSURE_ARG_POINTER(aDictionary);
 
+  if (mDictionary.IsEmpty())
+    return NS_ERROR_NOT_INITIALIZED;
+
   *aDictionary = ToNewUnicode(mDictionary);
   return *aDictionary ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
 }
 
 /* set the Dictionary.
  * This also Loads the dictionary and initializes the converter using the dictionaries converter
  */
 NS_IMETHODIMP mozHunspell::SetDictionary(const PRUnichar *aDictionary)
 {
   NS_ENSURE_ARG_POINTER(aDictionary);
 
+  if (mDictionary.Equals(aDictionary))
+    return NS_OK;
+
   nsIFile* affFile = mDictionaries.GetWeak(nsDependentString(aDictionary));
   if (!affFile)
     return NS_ERROR_FILE_NOT_FOUND;
 
   nsCAutoString dictFileName, affFileName;
 
   // XXX This isn't really good. nsIFile->NativePath isn't safe for all
   // character sets on Windows.
   // A better way would be to QI to nsILocalFile, and get a filehandle
   // from there. Only problem is that hunspell wants a path
 
   nsresult rv = affFile->GetNativePath(affFileName);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  if (mAffixFileName.Equals(affFileName.get()))
-    return NS_OK;
-
   dictFileName = affFileName;
   PRInt32 dotPos = dictFileName.RFindChar('.');
   if (dotPos == -1)
     return NS_ERROR_FAILURE;
 
   dictFileName.SetLength(dotPos);
   dictFileName.AppendLiteral(".dic");
 
   // SetDictionary can be called multiple times, so we might have a
   // valid mHunspell instance which needs cleaned up.
   delete mHunspell;
 
   mDictionary = aDictionary;
-  mAffixFileName = affFileName;
 
   mHunspell = new Hunspell(affFileName.get(),
                          dictFileName.get());
   if (!mHunspell)
     return NS_ERROR_OUT_OF_MEMORY;
 
   nsCOMPtr<nsICharsetConverterManager> ccm =
     do_GetService(NS_CHARSETCONVERTERMANAGER_CONTRACTID, &rv);
@@ -217,23 +217,16 @@ NS_IMETHODIMP mozHunspell::SetDictionary
   if (pos == -1)
     pos = mDictionary.FindChar('_');
 
   if (pos == -1)
     mLanguage.Assign(mDictionary);
   else
     mLanguage = Substring(mDictionary, 0, pos);
 
-  nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
-  if (obs) {
-    obs->NotifyObservers(nsnull,
-                         SPELLCHECK_DICTIONARY_UPDATE_NOTIFICATION,
-                         nsnull);
-  }
-
   return NS_OK;
 }
 
 /* readonly attribute wstring language; */
 NS_IMETHODIMP mozHunspell::GetLanguage(PRUnichar **aLanguage)
 {
   NS_ENSURE_ARG_POINTER(aLanguage);
 
@@ -335,37 +328,28 @@ NS_IMETHODIMP mozHunspell::GetDictionary
   }
 
   *aDictionaries = ans.dics;
   *aCount = ans.count;
 
   return NS_OK;
 }
 
-static PLDHashOperator
-FindFirstString(const nsAString& aString, nsIFile* aFile, void* aClosure)
-{
-  nsAString *dic = (nsAString*) aClosure;
-  dic->Assign(aString);
-  return PL_DHASH_STOP;
-}
-
 void
 mozHunspell::LoadDictionaryList()
 {
   mDictionaries.Clear();
 
   nsresult rv;
 
   nsCOMPtr<nsIProperties> dirSvc =
     do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID);
   if (!dirSvc)
     return;
 
-  // find built in dictionaries
   nsCOMPtr<nsIFile> dictDir;
   rv = dirSvc->Get(DICTIONARY_SEARCH_DIRECTORY,
                    NS_GET_IID(nsIFile), getter_AddRefs(dictDir));
   if (NS_SUCCEEDED(rv)) {
     LoadDictionariesFromDir(dictDir);
   }
   else {
     // try to load gredir/dictionaries
@@ -383,77 +367,31 @@ mozHunspell::LoadDictionaryList()
                      NS_GET_IID(nsIFile), getter_AddRefs(appDir));
     PRBool equals;
     if (NS_SUCCEEDED(rv) && NS_SUCCEEDED(appDir->Equals(greDir, &equals)) && !equals) {
       appDir->AppendNative(NS_LITERAL_CSTRING("dictionaries"));
       LoadDictionariesFromDir(appDir);
     }
   }
 
-  // find dictionaries from extensions requiring restart
   nsCOMPtr<nsISimpleEnumerator> dictDirs;
   rv = dirSvc->Get(DICTIONARY_SEARCH_DIRECTORY_LIST,
                    NS_GET_IID(nsISimpleEnumerator), getter_AddRefs(dictDirs));
   if (NS_FAILED(rv))
     return;
 
   PRBool hasMore;
   while (NS_SUCCEEDED(dictDirs->HasMoreElements(&hasMore)) && hasMore) {
     nsCOMPtr<nsISupports> elem;
     dictDirs->GetNext(getter_AddRefs(elem));
 
     dictDir = do_QueryInterface(elem);
     if (dictDir)
       LoadDictionariesFromDir(dictDir);
   }
-
-  // find dictionaries from restartless extensions
-  for (PRUint32 i = 0; i < mDynamicDirectories.Count(); i++) {
-    LoadDictionariesFromDir(mDynamicDirectories[i]);
-  }
-
-  // Now we have finished updating the list of dictionaries, update the current
-  // dictionary and any editors which may use it.
-  mozInlineSpellChecker::UpdateCanEnableInlineSpellChecking();
-
-  // If the current dictionary has gone, try to replace it with another
-  // dictionary of the same language
-  if (!mDictionary.IsEmpty()) {
-    rv = SetDictionary(mDictionary.get());
-    if (NS_SUCCEEDED(rv))
-      return;
-  }
-
-  // If we didn't find a dictionary equal to the current dictionary or we had
-  // no current dictionary, just pick an arbitrary dictionary.
-  nsAutoString firstDictionary;
-  mDictionaries.EnumerateRead(FindFirstString, &firstDictionary);
-  if (!firstDictionary.IsEmpty()) {
-    rv = SetDictionary(firstDictionary.get());
-    if (NS_SUCCEEDED(rv))
-      return;
-  }
-
-  // If there are no dictionaries, set no current dictionary
-  if (!mDictionary.IsEmpty()) {
-    delete mHunspell;
-    mHunspell = nsnull;
-    mDictionary.AssignLiteral("");
-    mAffixFileName.AssignLiteral("");
-    mLanguage.AssignLiteral("");
-    mDecoder = nsnull;
-    mEncoder = nsnull;
-
-    nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
-    if (obs) {
-      obs->NotifyObservers(nsnull,
-                           SPELLCHECK_DICTIONARY_UPDATE_NOTIFICATION,
-                           nsnull);
-    }
-  }
 }
 
 NS_IMETHODIMP
 mozHunspell::LoadDictionariesFromDir(nsIFile* aDir)
 {
   nsresult rv;
 
   PRBool check = PR_FALSE;
@@ -599,24 +537,8 @@ mozHunspell::Observe(nsISupports* aSubj,
 {
   NS_ASSERTION(!strcmp(aTopic, "profile-do-change"),
                "Unexpected observer topic");
 
   LoadDictionaryList();
 
   return NS_OK;
 }
-
-/* void addDirectory(in nsIFile dir); */
-NS_IMETHODIMP mozHunspell::AddDirectory(nsIFile *aDir)
-{
-  mDynamicDirectories.AppendObject(aDir);
-  LoadDictionaryList();
-  return NS_OK;
-}
-
-/* void removeDirectory(in nsIFile dir); */
-NS_IMETHODIMP mozHunspell::RemoveDirectory(nsIFile *aDir)
-{
-  mDynamicDirectories.RemoveObject(aDir);
-  LoadDictionaryList();
-  return NS_OK;
-}
--- a/extensions/spellcheck/hunspell/src/mozHunspell.h
+++ b/extensions/spellcheck/hunspell/src/mozHunspell.h
@@ -36,17 +36,16 @@
  *                 Varga Daniel
  *                 Chris Halls
  *                 Rene Engelhard
  *                 Bram Moolenaar
  *                 Dafydd Jones
  *                 Harri Pitkanen
  *                 Andras Timar
  *                 Tor Lillqvist
- *                 Jesper Kristensen (mail@jesperkristensen.dk)
  * 
  * Alternatively, the contents of this file may be used under the terms of
  * either the GNU General Public License Version 2 or later (the "GPL"), or
  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  * in which case the provisions of the GPL or the LGPL are applicable instead
  * of those above. If you wish to allow use of your version of this file only
  * under the terms of either the GPL or the LGPL, and not to allow others to
  * use your version of this file under the terms of the MPL, indicate your
@@ -60,17 +59,16 @@
 #ifndef mozHunspell_h__
 #define mozHunspell_h__
 
 #include <hunspell.hxx>
 #include "mozISpellCheckingEngine.h"
 #include "mozIPersonalDictionary.h"
 #include "nsString.h"
 #include "nsCOMPtr.h"
-#include "nsCOMArray.h"
 #include "nsIObserver.h"
 #include "nsIUnicodeEncoder.h"
 #include "nsIUnicodeDecoder.h"
 #include "nsInterfaceHashtable.h"
 #include "nsWeakReference.h"
 #include "nsCycleCollectionParticipant.h"
 
 #define MOZ_HUNSPELL_CONTRACTID "@mozilla.org/spellchecker/engine;1"
@@ -106,19 +104,15 @@ protected:
   nsCOMPtr<mozIPersonalDictionary> mPersonalDictionary;
   nsCOMPtr<nsIUnicodeEncoder>      mEncoder; 
   nsCOMPtr<nsIUnicodeDecoder>      mDecoder; 
 
   // Hashtable matches dictionary name to .aff file
   nsInterfaceHashtable<nsStringHashKey, nsIFile> mDictionaries;
   nsString  mDictionary;
   nsString  mLanguage;
-  nsCString mAffixFileName;
-
-  // dynamic dirs used to search for dictionaries
-  nsCOMArray<nsIFile> mDynamicDirectories;
 
   Hunspell  *mHunspell;
 
   nsIMemoryReporter* mHunspellReporter;
 };
 
 #endif
--- a/extensions/spellcheck/idl/mozISpellCheckingEngine.idl
+++ b/extensions/spellcheck/idl/mozISpellCheckingEngine.idl
@@ -15,17 +15,16 @@
  * The Original Code is mozilla.org code.
  *
  * The Initial Developer of the Original Code is
  * David Einstein.
  * Portions created by the Initial Developer are Copyright (C) 2001
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
- *   Jesper Kristensen <mail@jesperkristensen.dk>
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either the GNU General Public License Version 2 or later (the "GPL"), or
  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  * in which case the provisions of the GPL or the LGPL are applicable instead
  * of those above. If you wish to allow use of your version of this file only
  * under the terms of either the GPL or the LGPL, and not to allow others to
  * use your version of this file under the terms of the MPL, indicate your
@@ -36,41 +35,30 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsISupports.idl"
 
 interface nsIFile;
 interface mozIPersonalDictionary;
 
-[scriptable, uuid(8ba643a4-7ddc-4662-b976-7ec123843f10)]
+[scriptable, uuid(6eb307d6-3567-481a-971a-feb666b8ae72)]
 
 /**
  * This interface represents a SpellChecker.
  */
 
 interface mozISpellCheckingEngine : nsISupports {
   /**
    * The name of the current dictionary
-   *
-   * Whenever getDictionaryList is not empty, this attribute contains a value
-   * from that list. Whenever getDictionaryList is empty, this attribute
-   * contains the empty string. Setting this attribute to a value not in
-   * getDictionaryList will throw NS_ERROR_FILE_NOT_FOUND.
-   *
-   * The spellcheck engine will send a notification with
-   * "spellcheck-dictionary-update" as topic when this changes.
    */
   attribute wstring dictionary;
 
   /**
    * The language this spellchecker is using when checking
-   *
-   * The spellcheck engine will send a notification with
-   * "spellcheck-dictionary-update" as topic when this changes.
    */
   readonly attribute wstring language;
 
   /**
    * Does the engine provide its own personal dictionary?
    */
   readonly attribute boolean providesPersonalDictionary;
 
@@ -96,45 +84,26 @@ interface mozISpellCheckingEngine : nsIS
 
   /**
    * Get the list of dictionaries
    */
   void getDictionaryList([array, size_is(count)] out wstring dictionaries, out PRUint32 count);
 
   /**
    * check a word
-   *
-   * The spellcheck engine will send a notification with
-   * "spellcheck-dictionary-update" as topic when this changes.
    */
   boolean check(in wstring word);
 
   /**
    * get a list of suggestions for a misspelled word
-   *
-   * The spellcheck engine will send a notification with
-   * "spellcheck-dictionary-update" as topic when this changes.
    */
   void suggest(in wstring word,[array, size_is(count)] out wstring suggestions, out PRUint32 count);
 
   /**
    * Load dictionaries from the specified dir
    */
   void loadDictionariesFromDir(in nsIFile dir);
-
-  /**
-   * Add dictionaries from a directory to the spell checker
-   */
-  void addDirectory(in nsIFile dir);
-
-  /**
-   * Remove dictionaries from a directory from the spell checker
-   */
-  void removeDirectory(in nsIFile dir);
 };
 
 %{C++
 #define DICTIONARY_SEARCH_DIRECTORY "DictD"
 #define DICTIONARY_SEARCH_DIRECTORY_LIST "DictDL"
-
-#define SPELLCHECK_DICTIONARY_UPDATE_NOTIFICATION \
-  "spellcheck-dictionary-update"
 %}
--- a/extensions/spellcheck/src/mozInlineSpellChecker.cpp
+++ b/extensions/spellcheck/src/mozInlineSpellChecker.cpp
@@ -595,19 +595,19 @@ nsresult mozInlineSpellChecker::Cleanup(
 //    This function can be called to see if it seems likely that we can enable
 //    spellchecking before actually creating the InlineSpellChecking objects.
 //
 //    The problem is that we can't get the dictionary list without actually
 //    creating a whole bunch of spellchecking objects. This function tries to
 //    do that and caches the result so we don't have to keep allocating those
 //    objects if there are no dictionaries or spellchecking.
 //
-//    Whenever dictionaries are added or removed at runtime, this value must be
-//    updated before an observer notification is sent out about the change, to
-//    avoid editors getting a wrong cached result.
+//    This caching will prevent adding dictionaries at runtime if we start out
+//    with no dictionaries! Installing dictionaries as extensions will require
+//    a restart anyway, so it shouldn't be a problem.
 
 PRBool // static
 mozInlineSpellChecker::CanEnableInlineSpellChecking()
 {
   nsresult rv;
   if (gCanEnableSpellChecking == SpellCheck_Uninitialized) {
     gCanEnableSpellChecking = SpellCheck_NotAvailable;
 
@@ -620,22 +620,16 @@ mozInlineSpellChecker::CanEnableInlineSp
     NS_ENSURE_SUCCESS(rv, PR_FALSE);
 
     if (canSpellCheck)
       gCanEnableSpellChecking = SpellCheck_Available;
   }
   return (gCanEnableSpellChecking == SpellCheck_Available);
 }
 
-void // static
-mozInlineSpellChecker::UpdateCanEnableInlineSpellChecking()
-{
-  gCanEnableSpellChecking = SpellCheck_Uninitialized;
-}
-
 // mozInlineSpellChecker::RegisterEventListeners
 //
 //    The inline spell checker listens to mouse events and keyboard navigation+ //    events.
 
 nsresult
 mozInlineSpellChecker::RegisterEventListeners()
 {
   nsCOMPtr<nsIEditor> editor (do_QueryReferent(mEditor));
--- a/extensions/spellcheck/src/mozInlineSpellChecker.h
+++ b/extensions/spellcheck/src/mozInlineSpellChecker.h
@@ -224,20 +224,18 @@ private:
 public:
 
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_NSIEDITACTIONLISTENER
   NS_DECL_NSIINLINESPELLCHECKER
   NS_DECL_NSIDOMEVENTLISTENER
   NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(mozInlineSpellChecker, nsIDOMEventListener)
 
-  // returns true if there are any spell checking dictionaries available
+  // returns true if it looks likely that we can enable real-time spell checking
   static PRBool CanEnableInlineSpellChecking();
-  // update the cached value whenever the list of available dictionaries changes
-  static void UpdateCanEnableInlineSpellChecking();
 
   nsresult Blur(nsIDOMEvent* aEvent);
   nsresult MouseClick(nsIDOMEvent* aMouseEvent);
   nsresult KeyPress(nsIDOMEvent* aKeyEvent);
 
   mozInlineSpellChecker();
   virtual ~mozInlineSpellChecker();
 
--- a/extensions/spellcheck/src/mozSpellChecker.cpp
+++ b/extensions/spellcheck/src/mozSpellChecker.cpp
@@ -13,17 +13,16 @@
  *
  * The Original Code is Mozilla Spellchecker Component.
  *
  * The Initial Developer of the Original Code is David Einstein.
  * Portions created by the Initial Developer are Copyright (C) 2001
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s): David Einstein Deinst@world.std.com
- *   Jesper Kristensen <mail@jesperkristensen.dk>
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either the GNU General Public License Version 2 or later (the "GPL"), or
  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  * in which case the provisions of the GPL or the LGPL are applicable instead
  * of those above. If you wish to allow use of your version of this file only
  * under the terms of either the GPL or the LGPL, and not to allow others to
  * use your version of this file under the terms of the MPL, indicate your
@@ -73,16 +72,19 @@ mozSpellChecker::~mozSpellChecker()
 }
 
 nsresult 
 mozSpellChecker::Init()
 {
   mPersonalDictionary = do_GetService("@mozilla.org/spellchecker/personaldictionary;1");
   
   mSpellCheckingEngine = nsnull;
+  mCurrentEngineContractId = nsnull;
+  mDictionariesMap.Init();
+  InitSpellCheckDictionaryMap();
 
   return NS_OK;
 } 
 
 NS_IMETHODIMP 
 mozSpellChecker::SetDocument(nsITextServicesDocument *aDoc, PRBool aFromStartofDoc)
 {
   mTsDoc = aDoc;
@@ -300,55 +302,45 @@ mozSpellChecker::GetPersonalDictionary(n
   nsAutoString word;
   while (NS_SUCCEEDED(words->HasMore(&hasMore)) && hasMore) {
     words->GetNext(word);
     aWordList->AppendElement(word);
   }
   return NS_OK;
 }
 
+struct AppendNewStruct
+{
+  nsTArray<nsString> *dictionaryList;
+  PRBool failed;
+};
+
+static PLDHashOperator
+AppendNewString(const nsAString& aString, nsCString*, void* aClosure)
+{
+  AppendNewStruct *ans = (AppendNewStruct*) aClosure;
+
+  if (!ans->dictionaryList->AppendElement(aString))
+  {
+    ans->failed = PR_TRUE;
+    return PL_DHASH_STOP;
+  }
+
+  return PL_DHASH_NEXT;
+}
+
 NS_IMETHODIMP 
 mozSpellChecker::GetDictionaryList(nsTArray<nsString> *aDictionaryList)
 {
-  nsresult rv;
-
-  // For catching duplicates
-  nsClassHashtable<nsStringHashKey, nsCString> dictionaries;
-  dictionaries.Init();
-
-  nsCOMArray<mozISpellCheckingEngine> spellCheckingEngines;
-  rv = GetEngineList(&spellCheckingEngines);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  for (PRUint32 i = 0; i < spellCheckingEngines.Count(); i++) {
-    nsCOMPtr<mozISpellCheckingEngine> engine = spellCheckingEngines[i];
+  AppendNewStruct ans = {aDictionaryList, PR_FALSE};
 
-    PRUint32 count = 0;
-    PRUnichar **words = NULL;
-    engine->GetDictionaryList(&words, &count);
-    for (PRUint32 k = 0; k < count; k++) {
-      nsAutoString dictName;
-
-      dictName.Assign(words[k]);
+  mDictionariesMap.EnumerateRead(AppendNewString, &ans);
 
-      // Skip duplicate dictionaries. Only take the first one
-      // for each name.
-      if (dictionaries.Get(dictName, NULL))
-        continue;
-
-      dictionaries.Put(dictName, NULL);
-
-      if (!aDictionaryList->AppendElement(dictName)) {
-        NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(count, words);
-        return NS_ERROR_OUT_OF_MEMORY;
-      }
-    }
-
-    NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(count, words);
-  }
+  if (ans.failed)
+    return NS_ERROR_OUT_OF_MEMORY;
 
   return NS_OK;
 }
 
 NS_IMETHODIMP 
 mozSpellChecker::GetCurrentDictionary(nsAString &aDictionary)
 {
   nsXPIDLString dictname;
@@ -359,97 +351,54 @@ mozSpellChecker::GetCurrentDictionary(ns
   mSpellCheckingEngine->GetDictionary(getter_Copies(dictname));
   aDictionary = dictname;
   return NS_OK;
 }
 
 NS_IMETHODIMP 
 mozSpellChecker::SetCurrentDictionary(const nsAString &aDictionary)
 {
-  mSpellCheckingEngine = nsnull;
+  nsresult rv;
+  nsCString *contractId;
 
   if (aDictionary.IsEmpty()) {
+    mCurrentEngineContractId = nsnull;
+    mSpellCheckingEngine = nsnull;
     return NS_OK;
   }
 
-  nsresult rv;
-  nsCOMArray<mozISpellCheckingEngine> spellCheckingEngines;
-  rv = GetEngineList(&spellCheckingEngines);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  for (PRUint32 i = 0; i < spellCheckingEngines.Count(); i++) {
-    nsCOMPtr<mozISpellCheckingEngine> engine = spellCheckingEngines[i];
+  if (!mDictionariesMap.Get(aDictionary, &contractId)){
+    NS_WARNING("Dictionary not found");
+    return NS_ERROR_NOT_AVAILABLE;
+  }
 
-    rv = engine->SetDictionary(PromiseFlatString(aDictionary).get());
-    if (NS_SUCCEEDED(rv)) {
-      mSpellCheckingEngine = engine;
+  if (!mCurrentEngineContractId || !mCurrentEngineContractId->Equals(*contractId)){
+    mSpellCheckingEngine = do_GetService(contractId->get(), &rv);
+    if (NS_FAILED(rv))
+      return rv;
 
-      nsCOMPtr<mozIPersonalDictionary> personalDictionary = do_GetService("@mozilla.org/spellchecker/personaldictionary;1");
-      mSpellCheckingEngine->SetPersonalDictionary(personalDictionary.get());
-
-      return NS_OK;
-    }
+    mCurrentEngineContractId = contractId;
   }
 
-  // We could not find any engine with the requested dictionary
-  return NS_ERROR_NOT_AVAILABLE;
-}
-
-NS_IMETHODIMP 
-mozSpellChecker::CheckCurrentDictionary()
-{
-  // Check if the current engine has any dictionaries available. If not,
-  // the last dictionary has just been uninstalled, and we need to stop using
-  // the engine.
-  if (mSpellCheckingEngine) {
-    nsXPIDLString dictname;
-
-    mSpellCheckingEngine->GetDictionary(getter_Copies(dictname));
-
-    // We still have a dictionary, so keep using that.
-    if (!dictname.IsEmpty()) {
-      return NS_OK;
-    }
-
-    // Our current dictionary has gone, so we cannot use the engine anymore.
-    mSpellCheckingEngine = nsnull;
+  nsresult res;
+  res = mSpellCheckingEngine->SetDictionary(PromiseFlatString(aDictionary).get());
+  if(NS_FAILED(res)){
+    NS_WARNING("Dictionary load failed");
+    return res;
   }
 
-  // We have no current engine. Pick one.
-  nsresult rv;
-  nsCOMArray<mozISpellCheckingEngine> spellCheckingEngines;
-  rv = GetEngineList(&spellCheckingEngines);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  for (PRUint32 i = 0; i < spellCheckingEngines.Count(); i++) {
-    nsCOMPtr<mozISpellCheckingEngine> engine = spellCheckingEngines[i];
-
-    nsXPIDLString dictname;
-
-    engine->GetDictionary(getter_Copies(dictname));
-
-    if (!dictname.IsEmpty()) {
-      mSpellCheckingEngine = engine;
+  mSpellCheckingEngine->SetPersonalDictionary(mPersonalDictionary);
 
-      nsCOMPtr<mozIPersonalDictionary> personalDictionary = do_GetService("@mozilla.org/spellchecker/personaldictionary;1");
-      mSpellCheckingEngine->SetPersonalDictionary(personalDictionary.get());
-
-      nsXPIDLString language;
-      nsresult rv;
-      nsCOMPtr<mozISpellI18NManager> serv = do_GetService("@mozilla.org/spellchecker/i18nmanager;1", &rv);
-      if(serv && NS_SUCCEEDED(rv)) {
-        serv->GetUtil(language.get(), getter_AddRefs(mConverter));
-      }
-
-      return NS_OK;
-    }
+  nsXPIDLString language;
+  
+  nsCOMPtr<mozISpellI18NManager> serv(do_GetService("@mozilla.org/spellchecker/i18nmanager;1", &res));
+  if(serv && NS_SUCCEEDED(res)){
+    res = serv->GetUtil(language.get(),getter_AddRefs(mConverter));
   }
-
-  // There are no dictionaries available
-  return NS_OK;
+  return res;
 }
 
 nsresult
 mozSpellChecker::SetupDoc(PRInt32 *outBlockOffset)
 {
   nsresult  rv;
 
   nsITextServicesDocument::TSDBlockSelectionStatus blockStatus;
@@ -523,20 +472,21 @@ mozSpellChecker::GetCurrentBlockIndex(ns
   } while (NS_SUCCEEDED(result) && !isDone);
   
   *outBlockIndex = blockIndex;
 
   return result;
 }
 
 nsresult
-mozSpellChecker::GetEngineList(nsCOMArray<mozISpellCheckingEngine>* aSpellCheckingEngines)
+mozSpellChecker::InitSpellCheckDictionaryMap()
 {
   nsresult rv;
   PRBool hasMoreEngines;
+  nsTArray<nsCString> contractIds;
 
   nsCOMPtr<nsICategoryManager> catMgr = do_GetService(NS_CATEGORYMANAGER_CONTRACTID);
   if (!catMgr)
     return NS_ERROR_NULL_POINTER;
 
   nsCOMPtr<nsISimpleEnumerator> catEntries;
 
   // Get contract IDs of registrated external spell-check engines and
@@ -553,29 +503,57 @@ mozSpellChecker::GetEngineList(nsCOMArra
     if (NS_FAILED(rv))
       return rv;
 
     nsCString contractId;
     rv = entry->GetData(contractId);
     if (NS_FAILED(rv))
       return rv;
 
+    contractIds.AppendElement(contractId);
+  }
+
+  contractIds.AppendElement(NS_LITERAL_CSTRING(DEFAULT_SPELL_CHECKER));
+
+  // Retrieve dictionaries from all available spellcheckers and
+  // fill mDictionariesMap hash (only the first dictionary with the
+  // each name is used).
+  for (PRUint32 i=0;i < contractIds.Length();i++){
+    PRUint32 count,k;
+    PRUnichar **words;
+
+    const nsCString& contractId = contractIds[i];
+
     // Try to load spellchecker engine. Ignore errors silently
     // except for the last one (HunSpell).
     nsCOMPtr<mozISpellCheckingEngine> engine =
       do_GetService(contractId.get(), &rv);
-    if (NS_SUCCEEDED(rv)) {
-      aSpellCheckingEngines->AppendObject(engine);
+    if (NS_FAILED(rv)){
+      // Fail if not succeeded to load HunSpell. Ignore errors
+      // for external spellcheck engines.
+      if (i==contractIds.Length()-1){
+        return rv;
+      }
+
+      continue;
     }
-  }
+
+    engine->GetDictionaryList(&words,&count);
+    for(k=0;k<count;k++){
+      nsAutoString dictName;
 
-  // Try to load HunSpell spellchecker engine.
-  nsCOMPtr<mozISpellCheckingEngine> engine =
-    do_GetService(DEFAULT_SPELL_CHECKER, &rv);
-  if (NS_FAILED(rv)) {
-    // Fail if not succeeded to load HunSpell. Ignore errors
-    // for external spellcheck engines.
-    return rv;
+      dictName.Assign(words[k]);
+
+      nsCString dictCName = NS_ConvertUTF16toUTF8(dictName);
+
+      // Skip duplicate dictionaries. Only take the first one
+      // for each name.
+      if (mDictionariesMap.Get(dictName, NULL))
+        continue;
+
+      mDictionariesMap.Put(dictName, new nsCString(contractId));
+    }
+
+    NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(count, words);
   }
-  aSpellCheckingEngines->AppendObject(engine);
 
   return NS_OK;
 }
--- a/extensions/spellcheck/src/mozSpellChecker.h
+++ b/extensions/spellcheck/src/mozSpellChecker.h
@@ -15,17 +15,16 @@
  * The Original Code is Mozilla Spellchecker Component.
  *
  * The Initial Developer of the Original Code is
  * David Einstein.
  * Portions created by the Initial Developer are Copyright (C) 2001
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s): David Einstein Deinst@world.std.com
- *   Jesper Kristensen <mail@jesperkristensen.dk>
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either the GNU General Public License Version 2 or later (the "GPL"), or
  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  * in which case the provisions of the GPL or the LGPL are applicable instead
  * of those above. If you wish to allow use of your version of this file only
  * under the terms of either the GPL or the LGPL, and not to allow others to
  * use your version of this file under the terms of the MPL, indicate your
@@ -35,17 +34,16 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef mozSpellChecker_h__
 #define mozSpellChecker_h__
 
 #include "nsCOMPtr.h"
-#include "nsCOMArray.h"
 #include "nsISpellChecker.h"
 #include "nsString.h"
 #include "nsITextServicesDocument.h"
 #include "mozIPersonalDictionary.h"
 #include "mozISpellCheckingEngine.h"
 #include "nsClassHashtable.h"
 #include "nsVoidArray.h"
 #include "nsTArray.h"
@@ -72,25 +70,29 @@ public:
 
   NS_IMETHOD AddWordToPersonalDictionary(const nsAString &aWord);
   NS_IMETHOD RemoveWordFromPersonalDictionary(const nsAString &aWord);
   NS_IMETHOD GetPersonalDictionary(nsTArray<nsString> *aWordList);
 
   NS_IMETHOD GetDictionaryList(nsTArray<nsString> *aDictionaryList);
   NS_IMETHOD GetCurrentDictionary(nsAString &aDictionary);
   NS_IMETHOD SetCurrentDictionary(const nsAString &aDictionary);
-  NS_IMETHOD CheckCurrentDictionary();
 
 protected:
   nsCOMPtr<mozISpellI18NUtil> mConverter;
   nsCOMPtr<nsITextServicesDocument> mTsDoc;
   nsCOMPtr<mozIPersonalDictionary> mPersonalDictionary;
 
+  // Hastable maps directory name to the spellchecker contract ID
+  nsClassHashtable<nsStringHashKey, nsCString> mDictionariesMap;
+
+  nsString mDictionaryName;
+  nsCString *mCurrentEngineContractId;
   nsCOMPtr<mozISpellCheckingEngine>  mSpellCheckingEngine;
   PRBool mFromStart;
 
   nsresult SetupDoc(PRInt32 *outBlockOffset);
 
   nsresult GetCurrentBlockIndex(nsITextServicesDocument *aDoc, PRInt32 *outBlockIndex);
 
-  nsresult GetEngineList(nsCOMArray<mozISpellCheckingEngine> *aDictionaryList);
+  nsresult InitSpellCheckDictionaryMap();
 };
 #endif // mozSpellChecker_h__
--- a/extensions/spellcheck/src/mozSpellCheckerFactory.cpp
+++ b/extensions/spellcheck/src/mozSpellCheckerFactory.cpp
@@ -54,17 +54,49 @@ 0x8227F019, 0xAFC7, 0x461e,             
 0x9fe5d975, 0x9bd, 0x44aa,                      \
 { 0xa0, 0x1a, 0x66, 0x40, 0x2e, 0xa2, 0x86, 0x57} }
 
 NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(mozHunspell, Init)
 NS_GENERIC_FACTORY_CONSTRUCTOR(mozHunspellDirProvider)
 NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(mozSpellChecker, Init)
 NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(mozPersonalDictionary, Init)
 NS_GENERIC_FACTORY_CONSTRUCTOR(mozSpellI18NManager)
-NS_GENERIC_FACTORY_CONSTRUCTOR(mozInlineSpellChecker)
+
+// This special constructor for the inline spell checker asks the inline
+// spell checker if we can create spell checking objects at all (ie, if there
+// are any dictionaries loaded) before trying to create one. The static
+// CanEnableInlineSpellChecking caches the value so this will be faster (we
+// have to run this code for every edit box we create, as well as for every
+// right click in those edit boxes).
+static nsresult
+mozInlineSpellCheckerConstructor(nsISupports *aOuter, REFNSIID aIID,
+                                 void **aResult)
+{
+  if (! mozInlineSpellChecker::CanEnableInlineSpellChecking())
+    return NS_ERROR_FAILURE;
+
+  nsresult rv;
+
+  *aResult = NULL;
+  if (NULL != aOuter) {
+    rv = NS_ERROR_NO_AGGREGATION;
+    return rv;
+  }
+
+  mozInlineSpellChecker* inst = new mozInlineSpellChecker();
+  if (NULL == inst) {
+    rv = NS_ERROR_OUT_OF_MEMORY;
+    return rv;
+  }
+  NS_ADDREF(inst);
+  rv = inst->QueryInterface(aIID, aResult);
+  NS_RELEASE(inst);
+
+  return rv;
+}
 
 NS_DEFINE_NAMED_CID(MOZ_HUNSPELL_CID);
 NS_DEFINE_NAMED_CID(HUNSPELLDIRPROVIDER_CID);
 NS_DEFINE_NAMED_CID(NS_SPELLCHECKER_CID);
 NS_DEFINE_NAMED_CID(MOZ_PERSONALDICTIONARY_CID);
 NS_DEFINE_NAMED_CID(MOZ_SPELLI18NMANAGER_CID);
 NS_DEFINE_NAMED_CID(MOZ_INLINESPELLCHECKER_CID);
 
deleted file mode 100644
--- a/extensions/spellcheck/tests/Makefile.in
+++ /dev/null
@@ -1,48 +0,0 @@
-#
-# ***** 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
-# Netscape Communications Corporation.
-# Portions created by the Initial Developer are Copyright (C) 1998
-# 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  = extensions/spellcheck/tests
-
-include $(DEPTH)/config/autoconf.mk
-
-DIRS		= chrome
-
-include $(topsrcdir)/config/rules.mk
deleted file mode 100644
--- a/extensions/spellcheck/tests/chrome/Makefile.in
+++ /dev/null
@@ -1,54 +0,0 @@
-#
-# ***** 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
-# Netscape Communications Corporation.
-# Portions created by the Initial Developer are Copyright (C) 1998
-# 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  = extensions/spellcheck/tests/chrome
-
-include $(DEPTH)/config/autoconf.mk
-
-DIRS = base map
-
-include $(topsrcdir)/config/rules.mk
-
-_TEST_FILES = 	test_add_remove_dictionaries.xul \
-				$(NULL)
-
-libs:: $(_TEST_FILES)
-	$(INSTALL) $^ $(DEPTH)/_tests/testing/mochitest/chrome/$(relativesrcdir)
deleted file mode 100644
--- a/extensions/spellcheck/tests/chrome/base/Makefile.in
+++ /dev/null
@@ -1,52 +0,0 @@
-#
-# ***** 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
-# Netscape Communications Corporation.
-# Portions created by the Initial Developer are Copyright (C) 1998
-# 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  = extensions/spellcheck/tests/chrome/base
-
-include $(DEPTH)/config/autoconf.mk
-include $(topsrcdir)/config/rules.mk
-
-_TEST_FILES = 	base_utf.dic \
-				base_utf.aff \
-				$(NULL)
-
-libs:: $(_TEST_FILES)
-	$(INSTALL) $^ $(DEPTH)/_tests/testing/mochitest/chrome/$(relativesrcdir)
deleted file mode 100644
--- a/extensions/spellcheck/tests/chrome/base/base_utf.aff
+++ /dev/null
@@ -1,198 +0,0 @@
-# OpenOffice.org’s en_US.aff file
-# with Unicode apostrophe: ’
-
-SET UTF-8
-TRY esianrtolcdugmphbyfvkwzESIANRTOLCDUGMPHBYFVKWZ'
-
-MAXNGRAMSUGS 1
-WORDCHARS .'’
-
-PFX A Y 1
-PFX A   0     re         .
-
-PFX I Y 1
-PFX I   0     in         .
-
-PFX U Y 1
-PFX U   0     un         .
-
-PFX C Y 1
-PFX C   0     de          .
-
-PFX E Y 1
-PFX E   0     dis         .
-
-PFX F Y 1
-PFX F   0     con         .
-
-PFX K Y 1
-PFX K   0     pro         .
-
-SFX V N 2
-SFX V   e     ive        e
-SFX V   0     ive        [^e]
-
-SFX N Y 3
-SFX N   e     ion        e
-SFX N   y     ication    y 
-SFX N   0     en         [^ey] 
-
-SFX X Y 3
-SFX X   e     ions       e
-SFX X   y     ications   y
-SFX X   0     ens        [^ey]
-
-SFX H N 2
-SFX H   y     ieth       y
-SFX H   0     th         [^y] 
-
-SFX Y Y 1
-SFX Y   0     ly         .
-
-SFX G Y 2
-SFX G   e     ing        e
-SFX G   0     ing        [^e] 
-
-SFX J Y 2
-SFX J   e     ings       e
-SFX J   0     ings       [^e]
-
-SFX D Y 4
-SFX D   0     d          e
-SFX D   y     ied        [^aeiou]y
-SFX D   0     ed         [^ey]
-SFX D   0     ed         [aeiou]y
-
-SFX T N 4
-SFX T   0     st         e
-SFX T   y     iest       [^aeiou]y
-SFX T   0     est        [aeiou]y
-SFX T   0     est        [^ey]
-
-SFX R Y 4
-SFX R   0     r          e
-SFX R   y     ier        [^aeiou]y
-SFX R   0     er         [aeiou]y
-SFX R   0     er         [^ey]
-
-SFX Z Y 4
-SFX Z   0     rs         e
-SFX Z   y     iers       [^aeiou]y
-SFX Z   0     ers        [aeiou]y
-SFX Z   0     ers        [^ey]
-
-SFX S Y 4
-SFX S   y     ies        [^aeiou]y
-SFX S   0     s          [aeiou]y
-SFX S   0     es         [sxzh]
-SFX S   0     s          [^sxzhy]
-
-SFX P Y 3
-SFX P   y     iness      [^aeiou]y
-SFX P   0     ness       [aeiou]y
-SFX P   0     ness       [^y]
-
-SFX M Y 1
-SFX M   0     's         .
-
-SFX B Y 3
-SFX B   0     able       [^aeiou]
-SFX B   0     able       ee
-SFX B   e     able       [^aeiou]e
-
-SFX L Y 1
-SFX L   0     ment       .
-
-REP 88
-REP a ei
-REP ei a
-REP a ey
-REP ey a
-REP ai ie
-REP ie ai
-REP are air
-REP are ear
-REP are eir
-REP air are
-REP air ere
-REP ere air
-REP ere ear
-REP ere eir
-REP ear are
-REP ear air
-REP ear ere
-REP eir are
-REP eir ere
-REP ch te
-REP te ch
-REP ch ti
-REP ti ch
-REP ch tu
-REP tu ch
-REP ch s
-REP s ch
-REP ch k
-REP k ch
-REP f ph
-REP ph f
-REP gh f
-REP f gh
-REP i igh
-REP igh i
-REP i uy
-REP uy i
-REP i ee
-REP ee i
-REP j di
-REP di j
-REP j gg
-REP gg j
-REP j ge
-REP ge j
-REP s ti
-REP ti s
-REP s ci
-REP ci s
-REP k cc
-REP cc k
-REP k qu
-REP qu k
-REP kw qu
-REP o eau
-REP eau o
-REP o ew
-REP ew o
-REP oo ew
-REP ew oo
-REP ew ui
-REP ui ew
-REP oo ui
-REP ui oo
-REP ew u
-REP u ew
-REP oo u
-REP u oo
-REP u oe
-REP oe u
-REP u ieu
-REP ieu u
-REP ue ew
-REP ew ue
-REP uff ough
-REP oo ieu
-REP ieu oo
-REP ier ear
-REP ear ier
-REP ear air
-REP air ear
-REP w qu
-REP qu w
-REP z ss
-REP ss z
-REP shun tion
-REP shun sion
-REP shun cion
-McDonalds’sá/w
-McDonald’sszá/g3)	st:McDonald’s	po:noun_prs	is:TRANS
-McDonald’sszal/g4)	st:McDonald’s	po:noun_prs	is:INSTR
-McDonald’ssal/w
deleted file mode 100644
--- a/extensions/spellcheck/tests/chrome/base/base_utf.dic
+++ /dev/null
@@ -1,29 +0,0 @@
-28
-created/U
-create/XKVNGADS
-imply/GNSDX
-natural/PUY
-like/USPBY
-convey/BDGS
-look/GZRDS
-text
-hello
-said
-sawyer
-NASA
-rotten
-day
-tomorrow
-seven
-FAQ/SM
-can’t
-doesn’t
-etc
-won’t
-lip
-text
-horrifying
-speech
-suggest
-uncreate/V
-Hunspell
deleted file mode 100644
--- a/extensions/spellcheck/tests/chrome/map/Makefile.in
+++ /dev/null
@@ -1,52 +0,0 @@
-#
-# ***** 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
-# Netscape Communications Corporation.
-# Portions created by the Initial Developer are Copyright (C) 1998
-# 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  = extensions/spellcheck/tests/chrome/map
-
-include $(DEPTH)/config/autoconf.mk
-include $(topsrcdir)/config/rules.mk
-
-_TEST_FILES = 	maputf.dic \
-				maputf.aff \
-				$(NULL)
-
-libs:: $(_TEST_FILES)
-	$(INSTALL) $^ $(DEPTH)/_tests/testing/mochitest/chrome/$(relativesrcdir)
deleted file mode 100644
--- a/extensions/spellcheck/tests/chrome/map/maputf.aff
+++ /dev/null
@@ -1,11 +0,0 @@
-# With MAP suggestion, Hunspell can add missing accents to a word.
-
-SET UTF-8
-
-# switch off ngram suggestion for testing
-MAXNGRAMSUGS 0
-
-MAP 3
-MAP uúü
-MAP öóo
-MAP ß(ss)
deleted file mode 100644
--- a/extensions/spellcheck/tests/chrome/map/maputf.dic
+++ /dev/null
@@ -1,4 +0,0 @@
-3
-Frühstück
-tükörfúró
-groß
deleted file mode 100644
--- a/extensions/spellcheck/tests/chrome/test_add_remove_dictionaries.xul
+++ /dev/null
@@ -1,110 +0,0 @@
-<?xml version="1.0"?>
-<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
-
-<window title="Add and remove dictionaries test"
-        xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
-        onload="RunTest();">
-  <title>Add and remove dictionaries test</title>
-
-  <script type="application/javascript"
-          src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
-
-  <script type="application/javascript">
-  <![CDATA[
-SimpleTest.waitForExplicitFinish();
-
-function getMisspelledWords(editor) {
-  return editor.selectionController.getSelection(Components.interfaces.nsISelectionController.SELECTION_SPELLCHECK).toString();
-}
-
-function getDictionaryList(editor) {
-  var spellchecker = editor.getInlineSpellChecker(true).spellChecker;
-  var o1 = {};
-  spellchecker.GetDictionaryList(o1, {});
-  return o1.value;
-}
-
-function getCurrentDictionary(editor) {
-  var spellchecker = editor.getInlineSpellChecker(true).spellChecker;
-  return spellchecker.GetCurrentDictionary();
-}
-
-function setCurrentDictionary(editor, dictionary) {
-  var spellchecker = editor.getInlineSpellChecker(true).spellChecker;
-  spellchecker.SetCurrentDictionary(dictionary);
-}
-
-function RunTest() {
-  var editor = document.getElementById('textbox').editor;
-
-  var dir = Components.classes["@mozilla.org/file/directory_service;1"].
-            getService(Components.interfaces.nsIProperties).
-            get("CurWorkD", Components.interfaces.nsIFile);
-  dir.append("chrome");
-  dir.append("extensions");
-  dir.append("spellcheck");
-  dir.append("tests");
-  dir.append("chrome");
-
-  var hunspell = Components
-    .classes["@mozilla.org/spellchecker/engine;1"]
-    .getService(Components.interfaces.mozISpellCheckingEngine);
-
-  // install base dictionary
-  var base = dir.clone();
-  base.append("base");
-  ok(base.exists());
-  hunspell.addDirectory(base);
-
-  // install map dictionary
-  var map = dir.clone();
-  map.append("map");
-  ok(map.exists());
-  hunspell.addDirectory(map);
-
-  // test that base and map dictionaries are available
-  var dicts = getDictionaryList(editor);
-  isnot(dicts.indexOf("base_utf"), -1, "base is available");
-  isnot(dicts.indexOf("maputf"), -1, "map is available");
-
-  // select base dictionary
-  setCurrentDictionary(editor, "base_utf");
-
-  SimpleTest.executeSoon(function() {
-    // test that base dictionary is in use
-    is(getMisspelledWords(editor), "Frühstück" + "qwertyu", "base misspellings");
-    is(getCurrentDictionary(editor), "base_utf", "current dictionary");
-
-    // select map dictionary
-    setCurrentDictionary(editor, "maputf");
-
-    SimpleTest.executeSoon(function() {
-      // test that map dictionary is in use
-      is(getMisspelledWords(editor), "created" + "imply" + "tomorrow" + "qwertyu", "map misspellings");
-      is(getCurrentDictionary(editor), "maputf", "current dictionary");
-
-      // uninstall map dictionary
-      hunspell.removeDirectory(map);
-
-      SimpleTest.executeSoon(function() {
-        // test that map dictionary is not in use
-        isnot(getMisspelledWords(editor), "created" + "imply" + "tomorrow" + "qwertyu", "map misspellings");
-        isnot(getCurrentDictionary(editor), "maputf", "current dictionary");
-
-        // test that base dictionary is available and map dictionary is unavailable
-        var dicts = getDictionaryList(editor);
-        isnot(dicts.indexOf("base_utf"), -1, "base is available");
-        is(dicts.indexOf("maputf"), -1, "map is unavailable");
-
-        // uninstall base dictionary
-        hunspell.removeDirectory(base);
-
-        SimpleTest.finish();
-      });
-    });
-  });
-}
-  ]]>
-  </script>
-  <textbox id="textbox" spellcheck="true" value="created imply Frühstück tomorrow qwertyu"/>
-</window>
--- a/gfx/thebes/GLContext.cpp
+++ b/gfx/thebes/GLContext.cpp
@@ -431,17 +431,16 @@ static const char *sExtensionNames[] = {
     "GL_IMG_read_format",
     "GL_EXT_read_format_bgra",
     "GL_APPLE_client_storage",
     "GL_ARB_texture_non_power_of_two",
     "GL_ARB_pixel_buffer_object",
     "GL_ARB_ES2_compatibility",
     "GL_OES_texture_float",
     "GL_ARB_texture_float",
-    "GL_EXT_unpack_subimage",
     NULL
 };
 
 void
 GLContext::InitExtensions()
 {
     MakeCurrent();
     const GLubyte *extensions = fGetString(LOCAL_GL_EXTENSIONS);
@@ -1835,27 +1834,19 @@ GLContext::TexImage2D(GLenum target, GLi
                       GLint pixelsize, GLint border, GLenum format, 
                       GLenum type, const GLvoid *pixels)
 {
     fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, 
                  NS_MIN(GetAddressAlignment((ptrdiff_t)pixels),
                         GetAddressAlignment((ptrdiff_t)stride)));
 
 #ifndef USE_GLES2
-    bool useUnpackRowLength = true;
+    fPixelStorei(LOCAL_GL_UNPACK_ROW_LENGTH, stride/pixelsize);
 #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
-
-    if (useUnpackRowLength)
-        fPixelStorei(LOCAL_GL_UNPACK_ROW_LENGTH, stride/pixelsize);
-    else if (stride != width * pixelsize) {
+    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,
                     height,
@@ -1877,29 +1868,31 @@ GLContext::TexImage2D(GLenum target, GLi
                            row);
 
             row += stride;
         }
 
         fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, 4);
         return;
     }
+#endif
 
     fTexImage2D(target,
                 level,
                 internalformat,
                 width,
                 height,
                 border,
                 format,
                 type,
                 pixels);
 
-    if (useUnpackRowLength)
-        fPixelStorei(LOCAL_GL_UNPACK_ROW_LENGTH, 0);
+#ifndef USE_GLES2
+    fPixelStorei(LOCAL_GL_UNPACK_ROW_LENGTH, 0);
+#endif
     fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, 4);
 }
 
 void
 GLContext::TexSubImage2D(GLenum target, GLint level, 
                          GLint xoffset, GLint yoffset, 
                          GLsizei width, GLsizei height, GLsizei stride,
                          GLint pixelsize, GLenum format, 
--- a/gfx/thebes/GLContext.h
+++ b/gfx/thebes/GLContext.h
@@ -975,17 +975,16 @@ public:
         IMG_read_format,
         EXT_read_format_bgra,
         APPLE_client_storage,
         ARB_texture_non_power_of_two,
         ARB_pixel_buffer_object,
         ARB_ES2_compatibility,
         OES_texture_float,
         ARB_texture_float,
-        EXT_unpack_subimage,
         Extensions_Max
     };
 
     PRBool IsExtensionSupported(GLExtensions aKnownExtension) {
         return mAvailableExtensions[aKnownExtension];
     }
 
     // for unknown extensions
--- 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/glue/GeckoChildProcessHost.cpp
+++ b/ipc/glue/GeckoChildProcessHost.cpp
@@ -150,30 +150,30 @@ void GetPathToBinary(FilePath& exePath)
     NS_ASSERTION(directoryService, "Expected XPCOM to be available");
     if (directoryService) {
       nsCOMPtr<nsIFile> greDir;
       nsresult rv = directoryService->Get(NS_GRE_DIR, NS_GET_IID(nsIFile), getter_AddRefs(greDir));
       if (NS_SUCCEEDED(rv)) {
         nsCString path;
         greDir->GetNativePath(path);
         exePath = FilePath(path.get());
+#ifdef OS_MACOSX
+        // We need to use an App Bundle on OS X so that we can hide
+        // the dock icon. See Bug 557225.
+        exePath = exePath.AppendASCII(MOZ_CHILD_PROCESS_BUNDLE);
+#endif
       }
     }
   }
+
   if (exePath.empty()) {
     exePath = FilePath(CommandLine::ForCurrentProcess()->argv()[0]);
     exePath = exePath.DirName();
   }
 
-#ifdef OS_MACOSX
-  // We need to use an App Bundle on OS X so that we can hide
-  // the dock icon. See Bug 557225
-  exePath = exePath.AppendASCII(MOZ_CHILD_PROCESS_BUNDLE);
-#endif
-
   exePath = exePath.AppendASCII(MOZ_CHILD_PROCESS_NAME);
 #endif
 }
 
 #ifdef XP_MACOSX
 class AutoCFTypeObject {
 public:
   AutoCFTypeObject(CFTypeRef object)
--- a/js/src/assembler/assembler/SparcAssembler.h
+++ b/js/src/assembler/assembler/SparcAssembler.h
@@ -1111,29 +1111,34 @@ namespace JSC {
             ASSERT(from.m_offset != -1);
             void *where = (void *)((intptr_t)code + from.m_offset);
             relinkJump(where, to);
         }
 
         static void relinkCall(void* from, void* to)
         {
             js::JaegerSpew(js::JSpew_Insns,
-                           ISPFX "##linkCall ((from=%p)) ((to=%p))\n",
+                           ISPFX "##relinkCall ((from=%p)) ((to=%p))\n",
                            from, to);
 
-            int disp = ((int)to - (int)from)/4;
-            *(uint32_t *)((int)from) &= 0x40000000;
-            *(uint32_t *)((int)from) |= disp & 0x3fffffff;
-            ExecutableAllocator::cacheFlush(from, 4);
+            void * where= (void *)((intptr_t)from - 20);
+            patchPointerInternal(where, (int)to);
+            ExecutableAllocator::cacheFlush(where, 8);
         }
 
         static void linkCall(void* code, JmpSrc where, void* to)
         {
             void *from = (void *)((intptr_t)code + where.m_offset);
-            relinkCall(from, to);
+            js::JaegerSpew(js::JSpew_Insns,
+                           ISPFX "##linkCall ((from=%p)) ((to=%p))\n",
+                           from, to);
+            int disp = ((int)to - (int)from)/4;
+            *(uint32_t *)((int)from) &= 0x40000000;
+            *(uint32_t *)((int)from) |= disp & 0x3fffffff;
+            ExecutableAllocator::cacheFlush(from, 4);
         }
 
         static void linkPointer(void* code, JmpDst where, void* value)
         {
             js::JaegerSpew(js::JSpew_Insns,
                            ISPFX "##linkPointer     ((%p + %#x)) points to ((%p))\n",
                            code, where.m_offset, value);
 
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/basic/bug684348.js
@@ -0,0 +1,4 @@
+var x = Proxy.create({ fix: function() { return []; } });
+Object.__proto__ = x;
+Object.freeze(x);
+quit();
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/basic/bug684796.js
@@ -0,0 +1,2 @@
+if (typeof mjitdatastats == "function")
+    mjitdatastats();
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);
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/jaeger/bug684084.js
@@ -0,0 +1,7 @@
+// |jit-test| error: TypeError
+function Integer( value, exception ) {
+  try {  } catch ( e ) {  }
+  new (value = this)( this.value );
+  if ( Math.floor(value) != value || isNaN(value) ) {  }
+}
+new Integer( 3, false );
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/jaeger/bug684576.js
@@ -0,0 +1,10 @@
+// |jit-test| error: TypeError
+function f0(p0,p1) {
+    var v3;
+    do {
+        p1 > v3
+        v3=1.7
+    } while (((p0[p1][5]==1)||(p0[p1][5]==2)||(p0[p1][5] == 3)) + 0 > p0);
+    + (v3(f0));
+}
+f0(4105,8307);
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/jaeger/closure-01.js
@@ -0,0 +1,18 @@
+
+/* Non-reentrant call on an inner and outer closure. */
+
+function foo() {
+  var x = 0;
+  function bar() {
+    var y = 0;
+    function baz() {
+      return ++x + ++y;
+    }
+    return baz;
+  }
+  return bar();
+}
+
+var a = foo();
+var b = foo();
+assertEq(a() + a() + b() + b(), 12);
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/jaeger/closure-02.js
@@ -0,0 +1,14 @@
+
+/* Non-reentrant closure used in an invoke session. */
+
+var last = null;
+
+var a = [1,2,3,4,5,6,7,8];
+var b = a.map(function(x) {
+    x++;
+    var res = last ? last() : 0;
+    last = function() { return x; };
+    return res;
+  });
+
+assertEq("" + b, "0,2,3,4,5,6,7,8");
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/jaeger/closure-03.js
@@ -0,0 +1,15 @@
+
+/* Recovering non-reentrant information on singletons after a GC. */
+
+function foo(a) {
+  return function() {
+    gc();
+    var n = 0;
+    for (var i = 0; i < 20; i++)
+      n = a++;
+    assertEq(n, 29);
+  };
+}
+var a = foo(10);
+var b = foo(20);
+a();
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/jaeger/closure-04.js
@@ -0,0 +1,23 @@
+test();
+function test() {
+  var catch1, catch2, catch3, finally1, finally2, finally3;
+  function gen() {
+    yield 1;
+    try {
+      try {
+        try {
+          yield 1;
+        } finally {
+          test();
+        }
+      } catch (e) {
+        finally2 = true;
+      }
+    } catch (e) {    }
+  }
+  iter = gen();
+  iter.next();
+  iter.next();
+  iter.close();
+  gc();
+} 
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/jaeger/closure-05.js
@@ -0,0 +1,17 @@
+var gTestcases = new Array();
+var gTc = gTestcases.length;
+function TestCase(n, d, e, a) {
+  gTestcases[gTc++] = this;
+}
+new TestCase("SECTION", "with MyObject, eval should return square of ");
+test();
+function test() {
+  for (gTc = 0; gTc < gTestcases.length; gTc++) {
+    var MYOBJECT = (function isPrototypeOf(message) {
+        delete input;
+      })();
+    with({}) {
+      gTestcases[gTc].actual = eval("");
+    }
+  }
+} 
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/jaeger/loops/bug684621.js
@@ -0,0 +1,15 @@
+function runRichards() {
+    queue = new Packet;
+    Packet(queue, ID_DEVICE_A, KIND_DEVICE);
+    new Packet;
+}
+var ID_DEVICE_A = 4;
+var KIND_DEVICE = 0;
+Packet = function (queue) {
+    this.link = null
+    if (queue == null) return;
+    var peek, next = queue;
+    while ((peek = next.link) != null)
+    ID_HANDLER_B
+};
+runRichards()
--- 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/jsanalyze.cpp
+++ b/js/src/jsanalyze.cpp
@@ -337,17 +337,17 @@ ScriptAnalysis::analyzeBytecode(JSContex
     for (unsigned i = LOCAL_LIMIT; i < script->nfixed; i++)
         setLocal(i, LOCAL_USE_BEFORE_DEF);
 
     /*
      * If the script is in debug mode, JS_SetFrameReturnValue can be called at
      * any safe point.
      */
     if (cx->compartment->debugMode())
-        usesRval = true;
+        usesReturnValue_ = true;
 
     isInlineable = true;
     if (script->nClosedArgs || script->nClosedVars || script->nfixed >= LOCAL_LIMIT ||
         (script->hasFunction && script->function()->isHeavyweight()) ||
         script->usesEval || script->usesArguments || cx->compartment->debugMode()) {
         isInlineable = false;
     }
 
@@ -493,51 +493,65 @@ ScriptAnalysis::analyzeBytecode(JSContex
 
           case JSOP_RETURN:
           case JSOP_STOP:
             numReturnSites_++;
             break;
 
           case JSOP_SETRVAL:
           case JSOP_POPV:
-            usesRval = true;
+            usesReturnValue_ = true;
             isInlineable = false;
             break;
 
           case JSOP_NAME:
           case JSOP_CALLNAME:
           case JSOP_BINDNAME:
           case JSOP_SETNAME:
           case JSOP_DELNAME:
           case JSOP_QNAMEPART:
           case JSOP_QNAMECONST:
             checkAliasedName(cx, pc);
-            usesScope = true;
+            usesScopeChain_ = true;
             isInlineable = false;
             break;
 
           case JSOP_DEFFUN:
           case JSOP_DEFVAR:
           case JSOP_DEFCONST:
           case JSOP_SETCONST:
             checkAliasedName(cx, pc);
-            /* FALLTHROUGH */
+            extendsScope_ = true;
+            isInlineable = canTrackVars = false;
+            break;
 
-          case JSOP_ENTERWITH:
+          case JSOP_EVAL:
+            extendsScope_ = true;
             isInlineable = canTrackVars = false;
             break;
 
+          case JSOP_ENTERWITH:
+            addsScopeObjects_ = true;
+            isInlineable = canTrackVars = false;
+            break;
+
+          case JSOP_ENTERBLOCK:
+          case JSOP_LEAVEBLOCK:
+            addsScopeObjects_ = true;
+            isInlineable = false;
+            break;
+
           case JSOP_THIS:
-            usesThis = true;
+            usesThisValue_ = true;
             break;
 
           case JSOP_CALL:
           case JSOP_NEW:
             /* Only consider potentially inlineable calls here. */
-            hasCalls = true;
+            hasFunctionCalls_ = true;
             break;
 
           case JSOP_TABLESWITCH:
           case JSOP_TABLESWITCHX: {
             isInlineable = canTrackVars = false;
             jsbytecode *pc2 = pc;
             unsigned jmplen = (op == JSOP_TABLESWITCH) ? JUMP_OFFSET_LEN : JUMPX_OFFSET_LEN;
             unsigned defaultOffset = offset + GetJumpOffset(pc, pc2);
@@ -712,30 +726,27 @@ ScriptAnalysis::analyzeBytecode(JSContex
           case JSOP_ARGINC:
           case JSOP_ARGDEC:
             modifiesArguments_ = true;
             isInlineable = false;
             break;
 
           /* Additional opcodes which can be compiled but which can't be inlined. */
           case JSOP_ARGUMENTS:
-          case JSOP_EVAL:
           case JSOP_THROW:
           case JSOP_EXCEPTION:
           case JSOP_DEFLOCALFUN:
           case JSOP_DEFLOCALFUN_FC:
           case JSOP_LAMBDA:
           case JSOP_LAMBDA_FC:
           case JSOP_GETFCSLOT:
           case JSOP_CALLFCSLOT:
           case JSOP_ARGSUB:
           case JSOP_ARGCNT:
           case JSOP_DEBUGGER:
-          case JSOP_ENTERBLOCK:
-          case JSOP_LEAVEBLOCK:
           case JSOP_FUNCALL:
           case JSOP_FUNAPPLY:
             isInlineable = false;
             break;
 
           default:
             break;
         }
--- a/js/src/jsanalyze.h
+++ b/js/src/jsanalyze.h
@@ -881,25 +881,28 @@ class ScriptAnalysis
     /* Which analyses have been performed. */
     bool ranBytecode_;
     bool ranSSA_;
     bool ranLifetimes_;
     bool ranInference_;
 
     /* --------- Bytecode analysis --------- */
 
-    bool usesRval;
-    bool usesScope;
-    bool usesThis;
-    bool hasCalls;
-    bool canTrackVars;
-    bool isInlineable;
+    bool usesReturnValue_:1;
+    bool usesScopeChain_:1;
+    bool usesThisValue_:1;
+    bool hasFunctionCalls_:1;
+    bool modifiesArguments_:1;
+    bool extendsScope_:1;
+    bool addsScopeObjects_:1;
+    bool localsAliasStack_:1;
+    bool isInlineable:1;
+    bool canTrackVars:1;
+
     uint32 numReturnSites_;
-    bool modifiesArguments_;
-    bool localsAliasStack_;
 
     /* Offsets at which each local becomes unconditionally defined, or a value below. */
     uint32 *definedLocals;
 
     static const uint32 LOCAL_USE_BEFORE_DEF = uint32(-1);
     static const uint32 LOCAL_CONDITIONALLY_DEFINED = uint32(-2);
 
     /* --------- Lifetime analysis --------- */
@@ -923,32 +926,41 @@ class ScriptAnalysis
     /* Analyze the effect of invoking 'new' on script. */
     void analyzeTypesNew(JSContext *cx);
 
     bool OOM() { return outOfMemory; }
     bool failed() { return hadFailure; }
     bool inlineable(uint32 argc) { return isInlineable && argc == script->function()->nargs; }
 
     /* Whether there are POPV/SETRVAL bytecodes which can write to the frame's rval. */
-    bool usesReturnValue() const { return usesRval; }
+    bool usesReturnValue() const { return usesReturnValue_; }
 
     /* Whether there are NAME bytecodes which can access the frame's scope chain. */
-    bool usesScopeChain() const { return usesScope; }
+    bool usesScopeChain() const { return usesScopeChain_; }
 
-    bool usesThisValue() const { return usesThis; }
-    bool hasFunctionCalls() const { return hasCalls; }
+    bool usesThisValue() const { return usesThisValue_; }
+    bool hasFunctionCalls() const { return hasFunctionCalls_; }
     uint32 numReturnSites() const { return numReturnSites_; }
 
     /*
      * True if all named formal arguments are not modified. If the arguments
      * object cannot escape, the arguments are never modified within the script.
      */
     bool modifiesArguments() { return modifiesArguments_; }
 
     /*
+     * True if the script may extend declarations in its top level scope with
+     * dynamic fun/var declarations or through eval.
+     */
+    bool extendsScope() { return extendsScope_; }
+
+    /* True if the script may add block or with objects to its scope chain. */
+    bool addsScopeObjects() { return addsScopeObjects_; }
+
+    /*
      * True if there are any LOCAL opcodes aliasing values on the stack (above
      * script->nfixed).
      */
     bool localsAliasStack() { return localsAliasStack_; }
 
     /* Accessors for bytecode information. */
 
     Bytecode& getCode(uint32 offset) {
@@ -1163,16 +1175,31 @@ class ScriptAnalysis
     bool trackSlot(uint32 slot) { return !slotEscapes(slot) && canTrackVars; }
 
     const LifetimeVariable & liveness(uint32 slot) {
         JS_ASSERT(script->compartment()->activeAnalysis);
         JS_ASSERT(!slotEscapes(slot));
         return lifetimes[slot];
     }
 
+    /*
+     * If a NAME or similar opcode is definitely accessing a particular slot
+     * of a script this one is nested in, get that script/slot.
+     */
+    struct NameAccess {
+        JSScript *script;
+        types::TypeScriptNesting *nesting;
+        uint32 slot;
+
+        /* Decompose the slot above. */
+        bool arg;
+        uint32 index;
+    };
+    NameAccess resolveNameAccess(JSContext *cx, jsid id, bool addDependency = false);
+
     void printSSA(JSContext *cx);
     void printTypes(JSContext *cx);
 
     void clearAllocations();
 
   private:
     void setOOM(JSContext *cx) {
         if (!outOfMemory)
--- a/js/src/jsapi-tests/Makefile.in
+++ b/js/src/jsapi-tests/Makefile.in
@@ -60,17 +60,17 @@ CPPSRCS = \
   testDebugger.cpp \
   testDeepFreeze.cpp \
   testDefineGetterSetterNonEnumerable.cpp \
   testDefineProperty.cpp \
   testExtendedEq.cpp \
   testExternalStrings.cpp \
   testFuncCallback.cpp \
   testFunctionProperties.cpp \
-  testGCChunkAlloc.cpp \
+  testGCOutOfMemory.cpp \
   testGetPropertyDefault.cpp \
   testIndexToString.cpp \
   testIntString.cpp \
   testIntern.cpp \
   testLookup.cpp \
   testLooselyEqual.cpp \
   testNewObject.cpp \
   testOps.cpp \
rename from js/src/jsapi-tests/testGCChunkAlloc.cpp
rename to js/src/jsapi-tests/testGCOutOfMemory.cpp
--- a/js/src/jsapi-tests/testGCChunkAlloc.cpp
+++ b/js/src/jsapi-tests/testGCOutOfMemory.cpp
@@ -5,127 +5,64 @@
  * http://creativecommons.org/licenses/publicdomain/
  * Contributor: Igor Bukanov
  */
 
 #include "tests.h"
 #include "jsgcchunk.h"
 #include "jscntxt.h"
 
-/* We allow to allocate 2 (system/user) chunks. */
-
-static const int SYSTEM  = 0;
-static const int USER    = 1;
-static const int N_POOLS = 2;
-
-class CustomGCChunkAllocator: public js::GCChunkAllocator {
-  public:
-    CustomGCChunkAllocator() { pool[SYSTEM] = NULL; pool[USER] = NULL; }
-    void *pool[N_POOLS];
-    
-  private:
-
-    virtual void *doAlloc() {
-        if (!pool[SYSTEM] && !pool[USER])
-            return NULL;
-        void *chunk = NULL;
-        if (pool[SYSTEM]) {
-            chunk = pool[SYSTEM];
-            pool[SYSTEM] = NULL;
-        } else {
-            chunk = pool[USER];
-            pool[USER] = NULL;
-        }
-        return chunk;
-    }
-        
-    virtual void doFree(void *chunk) {
-        JS_ASSERT(!pool[SYSTEM] || !pool[USER]);
-        if (!pool[SYSTEM]) {
-            pool[SYSTEM] = chunk;
-        } else {
-            pool[USER] = chunk;
-        }
-    }
-};
-
-static CustomGCChunkAllocator customGCChunkAllocator;
-
 static unsigned errorCount = 0;
 
 static void
 ErrorCounter(JSContext *cx, const char *message, JSErrorReport *report)
 {
     ++errorCount;
 }
 
-BEGIN_TEST(testGCChunkAlloc)
+BEGIN_TEST(testGCOutOfMemory)
 {
     JS_SetErrorReporter(cx, ErrorCounter);
 
     jsvalRoot root(cx);
 
     /*
-     * We loop until out-of-memory happens during the chunk allocation. But
-     * we have to disable the jit since it cannot tolerate OOM during the
-     * chunk allocation.
+     * We loop until we get out-of-memory. We have to disable the jit since it
+     * ignores the runtime allocation limits during execution.
      */
     JS_ToggleOptions(cx, JSOPTION_JIT);
 
     static const char source[] =
         "var max = 0; (function() {"
         "    var array = [];"
         "    for (; ; ++max)"
         "        array.push({});"
+        "    array = []; array.push(0);"
         "})();";
     JSBool ok = JS_EvaluateScript(cx, global, source, strlen(source), "", 1,
                                   root.addr());
 
     /* Check that we get OOM. */
     CHECK(!ok);
     CHECK(!JS_IsExceptionPending(cx));
     CHECK_EQUAL(errorCount, 1);
-    CHECK(!customGCChunkAllocator.pool[SYSTEM]);
-    CHECK(!customGCChunkAllocator.pool[USER]);
     JS_GC(cx);
     JS_ToggleOptions(cx, JSOPTION_JIT);
     EVAL("(function() {"
          "    var array = [];"
-         "    for (var i = max >> 1; i != 0;) {"
+         "    for (var i = max >> 2; i != 0;) {"
          "        --i;"
          "        array.push({});"
          "    }"
          "})();", root.addr());
     CHECK_EQUAL(errorCount, 1);
     return true;
 }
 
 virtual JSRuntime * createRuntime() {
-    /*
-     * To test failure of chunk allocation allow to use GC twice the memory
-     * the single chunk contains.
-     */
-    JSRuntime *rt = JS_NewRuntime(2 * js::GC_CHUNK_SIZE);
-    if (!rt)
-        return NULL;
-
-    customGCChunkAllocator.pool[SYSTEM] = js::AllocGCChunk();
-    customGCChunkAllocator.pool[USER] = js::AllocGCChunk();
-    JS_ASSERT(customGCChunkAllocator.pool[SYSTEM]);
-    JS_ASSERT(customGCChunkAllocator.pool[USER]);
-
-    rt->setCustomGCChunkAllocator(&customGCChunkAllocator);
-    return rt;
+    return JS_NewRuntime(256 * 1024);
 }
 
 virtual void destroyRuntime() {
     JS_DestroyRuntime(rt);
-
-    /* We should get the initial chunk back at this point. */
-    JS_ASSERT(customGCChunkAllocator.pool[SYSTEM]);
-    JS_ASSERT(customGCChunkAllocator.pool[USER]);
-    js::FreeGCChunk(customGCChunkAllocator.pool[SYSTEM]);
-    js::FreeGCChunk(customGCChunkAllocator.pool[USER]);
-    customGCChunkAllocator.pool[SYSTEM] = NULL;
-    customGCChunkAllocator.pool[USER] = NULL;
 }
 
-END_TEST(testGCChunkAlloc)
+END_TEST(testGCOutOfMemory)
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -633,18 +633,17 @@ JS_IsBuiltinFunctionConstructor(JSFuncti
 /*
  * Has a new runtime ever been created?  This flag is used to detect unsafe
  * changes to js_CStringsAreUTF8 after a runtime has been created, and to
  * control things that should happen only once across all runtimes.
  */
 static JSBool js_NewRuntimeWasCalled = JS_FALSE;
 
 JSRuntime::JSRuntime()
-  : gcChunkAllocator(&defaultGCChunkAllocator),
-    trustedPrincipals_(NULL)
+  : trustedPrincipals_(NULL)
 {
     /* Initialize infallibly first, so we can goto bad and JS_DestroyRuntime. */
     JS_INIT_CLIST(&contextList);
     JS_INIT_CLIST(&debuggerList);
 }
 
 bool
 JSRuntime::init(uint32 maxbytes)
--- 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
--- 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          */
     }
 };
 
@@ -1831,20 +1907,21 @@ js_MergeSort(void *src, size_t nel, size
         memcpy(src, tmp, nel * elsize);
 
     return JS_TRUE;
 }
 
 struct CompareArgs
 {
     JSContext          *context;
-    InvokeSessionGuard session;
-
-    CompareArgs(JSContext *cx)
-      : context(cx)
+    InvokeArgsGuard    args;
+    Value              fval;
+
+    CompareArgs(JSContext *cx, Value fval)
+      : context(cx), fval(fval)
     {}
 };
 
 static JS_REQUIRES_STACK JSBool
 sort_compare(void *arg, const void *a, const void *b, int *result)
 {
     const Value *av = (const Value *)a, *bv = (const Value *)b;
     CompareArgs *ca = (CompareArgs *) arg;
@@ -1855,25 +1932,31 @@ sort_compare(void *arg, const void *a, c
      * come here.
      */
     JS_ASSERT(!av->isMagic() && !av->isUndefined());
     JS_ASSERT(!av->isMagic() && !bv->isUndefined());
 
     if (!JS_CHECK_OPERATION_LIMIT(cx))
         return JS_FALSE;
 
-    InvokeSessionGuard &session = ca->session;
-    session[0] = *av;
-    session[1] = *bv;
-
-    if (!session.invoke(cx))
+    InvokeArgsGuard &args = ca->args;
+    if (!args.pushed() && !cx->stack.pushInvokeArgs(cx, 2, &args))
+        return JS_FALSE;
+        
+    args.calleeHasBeenReset();
+    args.calleev() = ca->fval;
+    args.thisv() = UndefinedValue();
+    args[0] = *av;
+    args[1] = *bv;
+
+    if (!Invoke(cx, args))
         return JS_FALSE;
 
     jsdouble cmp;
-    if (!ToNumber(cx, session.rval(), &cmp))
+    if (!ToNumber(cx, args.rval(), &cmp))
         return JS_FALSE;
 
     /* Clamp cmp to -1, 0, 1. */
     *result = 0;
     if (!JSDOUBLE_IS_NaN(cmp) && cmp != 0)
         *result = cmp > 0 ? 1 : -1;
 
     /*
@@ -2100,20 +2183,17 @@ js::array_sort(JSContext *cx, uintN argc
                  * not call JS_CHECK_OPERATION_LIMIT in the loop.
                  */
                 i = 0;
                 do {
                     vec[i] = vec[2 * i + 1];
                 } while (++i != newlen);
             }
         } else {
-            CompareArgs ca(cx);
-            if (!ca.session.start(cx, fval, UndefinedValue(), 2))
-                return false;
-
+            CompareArgs ca(cx, fval);
             if (!js_MergeSort(vec, size_t(newlen), sizeof(Value),
                               comparator_stack_cast(sort_compare),
                               &ca, mergesort_tmp,
                               JS_SORTING_VALUES)) {
                 return false;
             }
         }
 
@@ -2957,52 +3037,55 @@ array_extra(JSContext *cx, ArrayExtraMod
     Value thisv = (argc > 1 && !REDUCE_MODE(mode)) ? argv[1] : UndefinedValue();
 
     /*
      * For all but REDUCE, we call with 3 args (value, index, array). REDUCE
      * requires 4 args (accum, value, index, array).
      */
     argc = 3 + REDUCE_MODE(mode);
 
-    InvokeSessionGuard session;
-    if (!session.start(cx, ObjectValue(*callable), thisv, argc))
-        return JS_FALSE;
-
     MUST_FLOW_THROUGH("out");
     JSBool ok = JS_TRUE;
     JSBool cond;
 
     Value objv = ObjectValue(*obj);
     AutoValueRooter tvr(cx);
+    InvokeArgsGuard args;
     for (jsuint i = start; i != end; i += step) {
         JSBool hole;
         ok = JS_CHECK_OPERATION_LIMIT(cx) &&
              GetElement(cx, obj, i, &hole, tvr.addr());
         if (!ok)
             goto out;
         if (hole)
             continue;
 
+        if (!args.pushed() && !cx->stack.pushInvokeArgs(cx, argc, &args))
+            return false;
+
         /*
          * Push callable and 'this', then args. We must do this for every
          * iteration around the loop since Invoke clobbers its arguments.
          */
+        args.calleeHasBeenReset();
+        args.calleev() = ObjectValue(*callable);
+        args.thisv() = thisv;
         uintN argi = 0;
         if (REDUCE_MODE(mode))
-            session[argi++] = *vp;
-        session[argi++] = tvr.value();
-        session[argi++] = Int32Value(i);
-        session[argi]   = objv;
+            args[argi++] = *vp;
+        args[argi++] = tvr.value();
+        args[argi++] = Int32Value(i);
+        args[argi]   = objv;
 
         /* Do the call. */
-        ok = session.invoke(cx);
+        ok = Invoke(cx, args);
         if (!ok)
             break;
 
-        const Value &rval = session.rval();
+        const Value &rval = args.rval();
 
         if (mode > MAP)
             cond = js_ValueToBoolean(rval);
 #ifdef __GNUC__ /* quell GCC overwarning */
         else
             cond = JS_FALSE;
 #endif
 
--- 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
@@ -507,24 +507,16 @@ struct JSRuntime {
   private:
     /*
      * Malloc counter to measure memory pressure for GC scheduling. It runs
      * from gcMaxMallocBytes down to zero.
      */
     volatile ptrdiff_t  gcMallocBytes;
 
   public:
-    js::GCChunkAllocator    *gcChunkAllocator;
-
-    void setCustomGCChunkAllocator(js::GCChunkAllocator *allocator) {
-        JS_ASSERT(allocator);
-        JS_ASSERT(state == JSRTS_DOWN);
-        gcChunkAllocator = allocator;
-    }
-
     /*
      * The trace operation and its data argument to trace embedding-specific
      * GC roots.
      */
     JSTraceDataOp       gcExtraRootsTraceOp;
     void                *gcExtraRootsData;
 
     /* Well-known numbers held for use by this runtime's contexts. */
@@ -1095,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()) {
@@ -1491,18 +1483,17 @@ class AutoGCRooter {
         NAMESPACES =   -8, /* js::AutoNamespaceArray */
         XML =          -9, /* js::AutoXMLRooter */
         OBJECT =      -10, /* js::AutoObjectRooter */
         ID =          -11, /* js::AutoIdRooter */
         VALVECTOR =   -12, /* js::AutoValueVector */
         DESCRIPTOR =  -13, /* js::AutoPropertyDescriptorRooter */
         STRING =      -14, /* js::AutoStringRooter */
         IDVECTOR =    -15, /* js::AutoIdVector */
-        OBJVECTOR =   -16, /* js::AutoObjectVector */
-        TYPE =        -17  /* js::types::AutoTypeRooter */
+        OBJVECTOR =   -16  /* js::AutoObjectVector */
     };
 
     private:
     /* No copy or assignment semantics. */
     AutoGCRooter(AutoGCRooter &ida);
     void operator=(AutoGCRooter &ida);
 };
 
--- a/js/src/jscompartment.cpp
+++ b/js/src/jscompartment.cpp
@@ -580,57 +580,73 @@ JSCompartment::sweep(JSContext *cx, uint
                 ScriptTryDestroyCode(cx, script, true, releaseInterval, counter);
                 ScriptTryDestroyCode(cx, script, false, releaseInterval, counter);
             }
         }
     }
 
 #endif
 
-    if (!activeAnalysis) {
+#ifdef JS_METHODJIT
+    if (types.inferenceEnabled)
+        mjit::ClearAllFrames(this);
+#endif
+
+    if (activeAnalysis) {
         /*
-         * Clear the analysis pool, but don't releas its data yet. While
+         * 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);
 
         /*
          * Sweep analysis information and everything depending on it from the
          * compartment, including all remaining mjit code if inference is
          * enabled in the compartment.
          */
         if (types.inferenceEnabled) {
-#ifdef JS_METHODJIT
-            mjit::ClearAllFrames(this);
-#endif
             for (CellIterUnderGC i(this, FINALIZE_SCRIPT); !i.done(); i.next()) {
                 JSScript *script = i.get<JSScript>();
                 if (script->types) {
                     types::TypeScript::Sweep(cx, script);
 
                     /*
                      * On each 1/8 lifetime, release observed types for all scripts.
                      * This is always safe to do when there are no frames for the
                      * compartment on the stack.
                      */
                     if (discardScripts) {
                         script->types->destroy();
                         script->types = NULL;
+                        script->typesPurged = true;
                     }
                 }
             }
         }
 
         types.sweep(cx);
 
         for (CellIterUnderGC i(this, FINALIZE_SCRIPT); !i.done(); i.next()) {
             JSScript *script = i.get<JSScript>();
-            if (script->types)
-                script->types->analysis = NULL;
+            script->clearAnalysis();
         }
 
         /* Reset the analysis pool, releasing all analysis and intermediate type data. */
         JS_FinishArenaPool(&oldPool);
     }
 
     active = false;
 }
--- 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.cpp
+++ b/js/src/jsemit.cpp
@@ -72,24 +72,22 @@
 #include "jsatominlines.h"
 #include "jsobjinlines.h"
 #include "jsscopeinlines.h"
 #include "jsscriptinlines.h"
 
 #include "frontend/ParseMaps-inl.h"
 
 /* Allocation chunk counts, must be powers of two in general. */
-#define BYTECODE_CHUNK  256     /* code allocation increment */
-#define SRCNOTE_CHUNK   64      /* initial srcnote allocation increment */
-#define TRYNOTE_CHUNK   64      /* trynote allocation increment */
+#define BYTECODE_CHUNK_LENGTH  1024    /* initial bytecode chunk length */
+#define SRCNOTE_CHUNK_LENGTH   1024    /* initial srcnote chunk length */
 
 /* Macros to compute byte sizes from typed element counts. */
 #define BYTECODE_SIZE(n)        ((n) * sizeof(jsbytecode))
 #define SRCNOTE_SIZE(n)         ((n) * sizeof(jssrcnote))
-#define TRYNOTE_SIZE(n)         ((n) * sizeof(JSTryNote))
 
 using namespace js;
 using namespace js::gc;
 
 static JSBool
 NewTryNote(JSContext *cx, JSCodeGenerator *cg, JSTryNoteKind kind,
            uintN stackDepth, size_t start, size_t end);
 
@@ -101,22 +99,18 @@ static JSBool
 EmitLeaveBlock(JSContext *cx, JSCodeGenerator *cg, JSOp op, JSObjectBox *box);
 
 void
 JSTreeContext::trace(JSTracer *trc)
 {
     bindings.trace(trc);
 }
 
-JSCodeGenerator::JSCodeGenerator(Parser *parser,
-                                 JSArenaPool *cpool, JSArenaPool *npool,
-                                 uintN lineno)
+JSCodeGenerator::JSCodeGenerator(Parser *parser, uintN lineno)
   : JSTreeContext(parser),
-    codePool(cpool), notePool(npool),
-    codeMark(JS_ARENA_MARK(cpool)), noteMark(JS_ARENA_MARK(npool)),
     atomIndices(parser->context),
     stackDepth(0), maxStackDepth(0),
     ntrynotes(0), lastTryNode(NULL),
     spanDeps(NULL), jumpTargets(NULL), jtFreeList(NULL),
     numSpanDeps(0), numJumpTargets(0), spanDepTodo(0),
     arrayCompDepth(0),
     emitLevel(0),
     constMap(parser->context),
@@ -130,69 +124,72 @@ JSCodeGenerator::JSCodeGenerator(Parser 
     traceIndex(0),
     typesetCount(0)
 {
     flags = TCF_COMPILING;
     memset(&prolog, 0, sizeof prolog);
     memset(&main, 0, sizeof main);
     current = &main;
     firstLine = prolog.currentLine = main.currentLine = lineno;
-    prolog.noteMask = main.noteMask = SRCNOTE_CHUNK - 1;
 }
 
 bool
 JSCodeGenerator::init(JSContext *cx, JSTreeContext::InitBehavior ib)
 {
     roLexdeps.init();
     return JSTreeContext::init(cx, ib) && constMap.init() && atomIndices.ensureMap(cx);
 }
 
 JSCodeGenerator::~JSCodeGenerator()
 {
-    JS_ARENA_RELEASE(codePool, codeMark);
-    JS_ARENA_RELEASE(notePool, noteMark);
-
     JSContext *cx = parser->context;
 
+    cx->free_(prolog.base);
+    cx->free_(prolog.notes);
+    cx->free_(main.base);
+    cx->free_(main.notes);
+
     /* NB: non-null only after OOM. */
     if (spanDeps)
         cx->free_(spanDeps);
 }
 
 static ptrdiff_t
-EmitCheck(JSContext *cx, JSCodeGenerator *cg, JSOp op, ptrdiff_t delta)
+EmitCheck(JSContext *cx, JSCodeGenerator *cg, ptrdiff_t delta)
 {
-    jsbytecode *base, *limit, *next;
-    ptrdiff_t offset, length;
-    size_t incr, size;
-
-    base = CG_BASE(cg);
-    next = CG_NEXT(cg);
-    limit = CG_LIMIT(cg);
-    offset = next - base;
+    jsbytecode *base = CG_BASE(cg);
+    jsbytecode *newbase;
+    jsbytecode *next = CG_NEXT(cg);
+    jsbytecode *limit = CG_LIMIT(cg);
+    ptrdiff_t offset = next - base;
+    size_t minlength = offset + delta;
+
     if (next + delta > limit) {
-        length = offset + delta;
-        length = (length <= BYTECODE_CHUNK)
-                 ? BYTECODE_CHUNK
-                 : JS_BIT(JS_CeilingLog2(length));
-        incr = BYTECODE_SIZE(length);
+        size_t newlength;
         if (!base) {
-            JS_ARENA_ALLOCATE_CAST(base, jsbytecode *, cg->codePool, incr);
+            JS_ASSERT(!next && !limit);
+            newlength = BYTECODE_CHUNK_LENGTH;
+            if (newlength < minlength)     /* make it bigger if necessary */
+                newlength = RoundUpPow2(minlength);
+            newbase = (jsbytecode *) cx->malloc_(BYTECODE_SIZE(newlength));
         } else {
-            size = BYTECODE_SIZE(limit - base);
-            incr -= size;
-            JS_ARENA_GROW_CAST(base, jsbytecode *, cg->codePool, size, incr);
-        }
-        if (!base) {
+            JS_ASSERT(base <= next && next <= limit);
+            newlength = (limit - base) * 2;
+            if (newlength < minlength)     /* make it bigger if necessary */
+                newlength = RoundUpPow2(minlength);
+            newbase = (jsbytecode *) cx->realloc_(base, BYTECODE_SIZE(newlength));
+        }
+        if (!newbase) {
             js_ReportOutOfMemory(cx);
             return -1;
         }
-        CG_BASE(cg) = base;
-        CG_LIMIT(cg) = base + length;
-        CG_NEXT(cg) = base + offset;
+        JS_ASSERT(newlength >= size_t(offset + delta));
+        CG_BASE(cg) = newbase;
+        CG_LIMIT(cg) = newbase + newlength;
+        CG_NEXT(cg) = newbase + offset;
     }
     return offset;
 }
 
 static void
 UpdateDepth(JSContext *cx, JSCodeGenerator *cg, ptrdiff_t target)
 {
     jsbytecode *pc;
@@ -258,61 +255,61 @@ UpdateDecomposeLength(JSCodeGenerator *c
     uintN end = CG_OFFSET(cg);
     JS_ASSERT(uintN(end - start) < 256);
     CG_CODE(cg, start)[-1] = end - start;
 }
 
 ptrdiff_t
 js_Emit1(JSContext *cx, JSCodeGenerator *cg, JSOp op)
 {
-    ptrdiff_t offset = EmitCheck(cx, cg, op, 1);
+    ptrdiff_t offset = EmitCheck(cx, cg, 1);
 
     if (offset >= 0) {
         *CG_NEXT(cg)++ = (jsbytecode)op;
         UpdateDepth(cx, cg, offset);
     }
     return offset;
 }
 
 ptrdiff_t
 js_Emit2(JSContext *cx, JSCodeGenerator *cg, JSOp op, jsbytecode op1)
 {
-    ptrdiff_t offset = EmitCheck(cx, cg, op, 2);
+    ptrdiff_t offset = EmitCheck(cx, cg, 2);
 
     if (offset >= 0) {
         jsbytecode *next = CG_NEXT(cg);
         next[0] = (jsbytecode)op;
         next[1] = op1;
         CG_NEXT(cg) = next + 2;
         UpdateDepth(cx, cg, offset);
     }
     return offset;
 }
 
 ptrdiff_t
 js_Emit3(JSContext *cx, JSCodeGenerator *cg, JSOp op, jsbytecode op1,
          jsbytecode op2)
 {
-    ptrdiff_t offset = EmitCheck(cx, cg, op, 3);
+    ptrdiff_t offset = EmitCheck(cx, cg, 3);
 
     if (offset >= 0) {
         jsbytecode *next = CG_NEXT(cg);
         next[0] = (jsbytecode)op;
         next[1] = op1;
         next[2] = op2;
         CG_NEXT(cg) = next + 3;
         UpdateDepth(cx, cg, offset);
     }
     return offset;
 }
 
 ptrdiff_t
 js_Emit5(JSContext *cx, JSCodeGenerator *cg, JSOp op, uint16 op1, uint16 op2)
 {
-    ptrdiff_t offset = EmitCheck(cx, cg, op, 5);
+    ptrdiff_t offset = EmitCheck(cx, cg, 5);
 
     if (offset >= 0) {
         jsbytecode *next = CG_NEXT(cg);
         next[0] = (jsbytecode)op;
         next[1] = UINT16_HI(op1);
         next[2] = UINT16_LO(op1);
         next[3] = UINT16_HI(op2);
         next[4] = UINT16_LO(op2);
@@ -321,17 +318,17 @@ js_Emit5(JSContext *cx, JSCodeGenerator 
     }
     return offset;
 }
 
 ptrdiff_t
 js_EmitN(JSContext *cx, JSCodeGenerator *cg, JSOp op, size_t extra)
 {
     ptrdiff_t length = 1 + (ptrdiff_t)extra;
-    ptrdiff_t offset = EmitCheck(cx, cg, op, length);
+    ptrdiff_t offset = EmitCheck(cx, cg, length);
 
     if (offset >= 0) {
         jsbytecode *next = CG_NEXT(cg);
         *next = (jsbytecode)op;
         memset(next + 1, 0, BYTECODE_SIZE(extra));
         CG_NEXT(cg) = next + length;
 
         /*
@@ -837,17 +834,16 @@ static JSBool
 OptimizeSpanDeps(JSContext *cx, JSCodeGenerator *cg)
 {
     jsbytecode *pc, *oldpc, *base, *limit, *next;
     JSSpanDep *sd, *sd2, *sdbase, *sdlimit, *sdtop, guard;
     ptrdiff_t offset, growth, delta, top, pivot, span, length, target;
     JSBool done;
     JSOp op;
     uint32 type;
-    size_t size, incr;
     jssrcnote *sn, *snlimit;
     JSSrcNoteSpec *spec;
     uintN i, n, noteIndex;
     JSTryNode *tryNode;
     DebugOnly<int> passes = 0;
 
     base = CG_BASE(cg);
     sdbase = cg->spanDeps;
@@ -967,20 +963,17 @@ OptimizeSpanDeps(JSContext *cx, JSCodeGe
         /*
          * Ensure that we have room for the extended jumps, but don't round up
          * to a power of two -- we're done generating code, so we cut to fit.
          */
         limit = CG_LIMIT(cg);
         length = offset + growth;
         next = base + length;
         if (next > limit) {
-            JS_ASSERT(length > BYTECODE_CHUNK);
-            size = BYTECODE_SIZE(limit - base);
-            incr = BYTECODE_SIZE(length) - size;
-            JS_ARENA_GROW_CAST(base, jsbytecode *, cg->codePool, size, incr);
+            base = (jsbytecode *) cx->realloc_(base, BYTECODE_SIZE(length));
             if (!base) {
                 js_ReportOutOfMemory(cx);
                 return JS_FALSE;
             }
             CG_BASE(cg) = base;
             CG_LIMIT(cg) = next = base + length;
         }
         CG_NEXT(cg) = next;
@@ -1052,17 +1045,17 @@ OptimizeSpanDeps(JSContext *cx, JSCodeGe
 
         /*
          * Don't bother copying the jump offset we're about to reset, but do
          * copy the bytecode at oldpc (which comes just before its immediate
          * jump offset operand), on the next iteration through the loop, by
          * including it in offset's new value.
          */
         offset = sd->before + 1;
-        size = BYTECODE_SIZE(delta - (1 + JUMP_OFFSET_LEN));
+        size_t size = BYTECODE_SIZE(delta - (1 + JUMP_OFFSET_LEN));
         if (size) {
             memmove(pc + 1 + JUMPX_OFFSET_LEN,
                     oldpc + 1 + JUMP_OFFSET_LEN,
                     size);
         }
 
         SET_JUMPX_OFFSET(pc, span);
     }
@@ -1222,17 +1215,16 @@ OptimizeSpanDeps(JSContext *cx, JSCodeGe
   }
 #endif
 
     /*
      * Reset so we optimize at most once -- cg may be used for further code
      * generation of successive, independent, top-level statements.  No jump
      * can span top-level statements, because JS lacks goto.
      */
-    size = SPANDEPS_SIZE(JS_BIT(JS_CeilingLog2(cg->numSpanDeps)));
     cx->free_(cg->spanDeps);
     cg->spanDeps = NULL;
     FreeJumpTargets(cg, cg->jumpTargets);
     cg->jumpTargets = NULL;
     cg->numSpanDeps = cg->numJumpTargets = 0;
     cg->spanDepTodo = CG_OFFSET(cg);
     return JS_TRUE;
 }
@@ -3707,18 +3699,17 @@ EmitSwitch(JSContext *cx, JSCodeGenerato
             if (off < 0)
                 return JS_FALSE;
             pn3->pn_offset = off;
             if (beforeCases) {
                 uintN noteCount, noteCountDelta;
 
                 /* Switch note's second offset is to first JSOP_CASE. */
                 noteCount = CG_NOTE_COUNT(cg);
-                if (!js_SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 1,
-                                         off - top)) {
+                if (!js_SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 1, off - top)) {
                     return JS_FALSE;
                 }
                 noteCountDelta = CG_NOTE_COUNT(cg) - noteCount;
                 if (noteCountDelta != 0)
                     caseNoteIndex += noteCountDelta;
                 beforeCases = JS_FALSE;
             }
         }
@@ -5020,28 +5011,21 @@ js_EmitTree(JSContext *cx, JSCodeGenerat
                 return JS_FALSE;
             break;
         }
 
         JS_ASSERT_IF(pn->pn_funbox->tcflags & TCF_FUN_HEAVYWEIGHT,
                      fun->kind() == JSFUN_INTERPRETED);
 
         /* Generate code for the function's body. */
-        void *cg2mark = JS_ARENA_MARK(cg->codePool);
-        void *cg2space;
-        JS_ARENA_ALLOCATE_TYPE(cg2space, JSCodeGenerator, cg->codePool);
-        if (!cg2space) {
+        JSCodeGenerator *cg2 = cx->new_<JSCodeGenerator>(cg->parser, pn->pn_pos.begin.lineno);
+        if (!cg2) {
             js_ReportOutOfMemory(cx);
             return JS_FALSE;
         }
-        JSCodeGenerator *cg2 =
-            new (cg2space) JSCodeGenerator(cg->parser,
-                                           cg->codePool, cg->notePool,
-                                           pn->pn_pos.begin.lineno);
-
         if (!cg2->init(cx))
             return JS_FALSE;
 
         cg2->flags = pn->pn_funbox->tcflags | TCF_COMPILING | TCF_IN_FUNCTION |
                      (cg->flags & TCF_FUN_MIGHT_ALIAS_LOCALS);
         cg2->bindings.transfer(cx, &pn->pn_funbox->bindings);
 #if JS_HAS_SHARP_VARS
         if (cg2->flags & TCF_HAS_SHARPS) {
@@ -5061,18 +5045,17 @@ js_EmitTree(JSContext *cx, JSCodeGenerat
          */
         JS_ASSERT(cg->staticLevel < JS_BITMASK(16) - 1);
         cg2->staticLevel = cg->staticLevel + 1;
 
         /* We measured the max scope depth when we parsed the function. */
         if (!js_EmitFunctionScript(cx, cg2, pn->pn_body))
             pn = NULL;
 
-        cg2->~JSCodeGenerator();
-        JS_ARENA_RELEASE(cg->codePool, cg2mark);
+        cx->delete_(cg2);
         cg2 = NULL;
         if (!pn)
             return JS_FALSE;
 
         /* Make the function object a literal in the outer script's pool. */
         index = cg->objectList.index(pn->pn_funbox);
 
         /* Emit a bytecode pointing to the closure object in its immediate. */
@@ -7440,41 +7423,42 @@ JS_FRIEND_DATA(JSSrcNoteSpec) js_SrcNote
     {"newline",         0,      0,      0},
     {"setline",         1,      0,      0},
     {"xdelta",          0,      0,      0},
 };
 
 static intN
 AllocSrcNote(JSContext *cx, JSCodeGenerator *cg)
 {
-    intN index;
-    JSArenaPool *pool;
-    size_t size;
-
-    index = CG_NOTE_COUNT(cg);
-    if (((uintN)index & CG_NOTE_MASK(cg)) == 0) {
-        pool = cg->notePool;
-        size = SRCNOTE_SIZE(CG_NOTE_MASK(cg) + 1);
-        if (!CG_NOTES(cg)) {
-            /* Allocate the first note array lazily; leave noteMask alone. */
-            JS_ARENA_ALLOCATE_CAST(CG_NOTES(cg), jssrcnote *, pool, size);
+    jssrcnote *notes = CG_NOTES(cg);
+    jssrcnote *newnotes;
+    uintN index = CG_NOTE_COUNT(cg);
+    uintN max = CG_NOTE_LIMIT(cg);
+
+    if (index == max) {
+        size_t newlength;
+        if (!notes) {
+            JS_ASSERT(!index && !max);
+            newlength = SRCNOTE_CHUNK_LENGTH;
+            newnotes = (jssrcnote *) cx->malloc_(SRCNOTE_SIZE(newlength));
         } else {
-            /* Grow by doubling note array size; update noteMask on success. */
-            JS_ARENA_GROW_CAST(CG_NOTES(cg), jssrcnote *, pool, size, size);
-            if (CG_NOTES(cg))
-                CG_NOTE_MASK(cg) = (CG_NOTE_MASK(cg) << 1) | 1;
-        }
-        if (!CG_NOTES(cg)) {
+            JS_ASSERT(index <= max);
+            newlength = max * 2;
+            newnotes = (jssrcnote *) cx->realloc_(notes, SRCNOTE_SIZE(newlength));
+        }
+        if (!newnotes) {
             js_ReportOutOfMemory(cx);
             return -1;
         }
+        CG_NOTES(cg) = newnotes;
+        CG_NOTE_LIMIT(cg) = newlength;
     }
 
     CG_NOTE_COUNT(cg) = index + 1;
-    return index;
+    return (intN)index;
 }
 
 intN
 js_NewSrcNote(JSContext *cx, JSCodeGenerator *cg, JSSrcNoteType type)
 {
     intN index, n;
     jssrcnote *sn;
     ptrdiff_t offset, delta, xdelta;
@@ -7548,28 +7532,24 @@ js_NewSrcNote3(JSContext *cx, JSCodeGene
             return -1;
     }
     return index;
 }
 
 static JSBool
 GrowSrcNotes(JSContext *cx, JSCodeGenerator *cg)
 {
-    JSArenaPool *pool;
-    size_t size;
-
-    /* Grow by doubling note array size; update noteMask on success. */
-    pool = cg->notePool;
-    size = SRCNOTE_SIZE(CG_NOTE_MASK(cg) + 1);
-    JS_ARENA_GROW_CAST(CG_NOTES(cg), jssrcnote *, pool, size, size);
-    if (!CG_NOTES(cg)) {
+    size_t newlength = CG_NOTE_LIMIT(cg) * 2;
+    jssrcnote *newnotes = (jssrcnote *) cx->realloc_(CG_NOTES(cg), newlength);
+    if (!newnotes) {
         js_ReportOutOfMemory(cx);
         return JS_FALSE;
     }
-    CG_NOTE_MASK(cg) = (CG_NOTE_MASK(cg) << 1) | 1;
+    CG_NOTES(cg) = newnotes;
+    CG_NOTE_LIMIT(cg) = newlength;
     return JS_TRUE;
 }
 
 jssrcnote *
 js_AddToSrcNoteDelta(JSContext *cx, JSCodeGenerator *cg, jssrcnote *sn,
                      ptrdiff_t delta)
 {
     ptrdiff_t base, limit, newdelta, diff;
@@ -7584,17 +7564,17 @@ js_AddToSrcNoteDelta(JSContext *cx, JSCo
 
     base = SN_DELTA(sn);
     limit = SN_IS_XDELTA(sn) ? SN_XDELTA_LIMIT : SN_DELTA_LIMIT;
     newdelta = base + delta;
     if (newdelta < limit) {
         SN_SET_DELTA(sn, newdelta);
     } else {
         index = sn - cg->main.notes;
-        if ((cg->main.noteCount & cg->main.noteMask) == 0) {
+        if (cg->main.noteCount == cg->main.noteLimit) {
             if (!GrowSrcNotes(cx, cg))
                 return NULL;
             sn = cg->main.notes + index;
         }
         diff = cg->main.noteCount - index;
         cg->main.noteCount++;
         memmove(sn + 1, sn, SRCNOTE_SIZE(diff));
         SN_MAKE_XDELTA(sn, delta);
@@ -7659,21 +7639,21 @@ js_SetSrcNoteOffset(JSContext *cx, JSCod
     /* See if the new offset requires three bytes. */
     if (offset > (ptrdiff_t)SN_3BYTE_OFFSET_MASK) {
         /* Maybe this offset was already set to a three-byte value. */
         if (!(*sn & SN_3BYTE_OFFSET_FLAG)) {
             /* Losing, need to insert another two bytes for this offset. */
             index = sn - CG_NOTES(cg);
 
             /*
-             * Simultaneously test to see if the source note array must grow to
-             * accommodate either the first or second byte of additional storage
-             * required by this 3-byte offset.
+             * Test to see if the source note array must grow to accommodate
+             * either the first or second byte of additional storage required
+             * by this 3-byte offset.
              */
-            if (((CG_NOTE_COUNT(cg) + 1) & CG_NOTE_MASK(cg)) <= 1) {
+            if (CG_NOTE_COUNT(cg) + 1 >= CG_NOTE_LIMIT(cg)) {
                 if (!GrowSrcNotes(cx, cg))
                     return JS_FALSE;
                 sn = CG_NOTES(cg) + index;
             }
             CG_NOTE_COUNT(cg) += 2;
 
             diff = CG_NOTE_COUNT(cg) - (index + 3);
             JS_ASSERT(diff >= 0);
--- 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; }
 
@@ -596,28 +596,23 @@ class JSGCConstList {
     bool append(js::Value v) { return list.append(v); }
     size_t length() const { return list.length(); }
     void finish(JSConstArray *array);
 
 };
 
 struct JSCodeGenerator : public JSTreeContext
 {
-    JSArenaPool     *codePool;      /* pointer to thread code arena pool */
-    JSArenaPool     *notePool;      /* pointer to thread srcnote arena pool */
-    void            *codeMark;      /* low watermark in cg->codePool */
-    void            *noteMark;      /* low watermark in cg->notePool */
-
     struct {
         jsbytecode  *base;          /* base of JS bytecode vector */
         jsbytecode  *limit;         /* one byte beyond end of bytecode */
         jsbytecode  *next;          /* pointer to next free bytecode */
         jssrcnote   *notes;         /* source notes, see below */
         uintN       noteCount;      /* number of source notes so far */
-        uintN       noteMask;       /* growth increment for notes */
+        uintN       noteLimit;      /* limit number for source notes in notePool */
         ptrdiff_t   lastNoteOffset; /* code offset for last source note */
         uintN       currentLine;    /* line number for tree-based srcnote gen */
     } prolog, main, *current;
 
     js::OwnedAtomIndexMapPtr atomIndices; /* literals indexed for mapping */
     js::AtomDefnMapPtr roLexdeps;
     uintN           firstLine;      /* first line, for js_NewScriptFromCG */
 
@@ -660,24 +655,17 @@ struct JSCodeGenerator : public JSTreeCo
     /* Vectors of pn_cookie slot values. */
     typedef js::Vector<uint32, 8> SlotVector;
     SlotVector      closedArgs;
     SlotVector      closedVars;
 
     uint16          traceIndex;     /* index for the next JSOP_TRACE instruction */
     uint16          typesetCount;   /* Number of JOF_TYPESET opcodes generated */
 
-    /*
-     * Initialize cg to allocate bytecode space from codePool, source note
-     * space from notePool, and all other arena-allocated temporaries from
-     * parser->context->tempPool.
-     */
-    JSCodeGenerator(js::Parser *parser,
-                    JSArenaPool *codePool, JSArenaPool *notePool,
-                    uintN lineno);
+    JSCodeGenerator(js::Parser *parser, uintN lineno);
     bool init(JSContext *cx, JSTreeContext::InitBehavior ib = USED_AS_CODE_GENERATOR);
 
     JSContext *context() {
         return parser->context;
     }
 
     /*
      * Release cg->codePool, cg->notePool, and parser->context->tempPool to
@@ -685,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.
      *
@@ -756,17 +744,17 @@ struct JSCodeGenerator : public JSTreeCo
 #define CG_BASE(cg)             ((cg)->current->base)
 #define CG_LIMIT(cg)            ((cg)->current->limit)
 #define CG_NEXT(cg)             ((cg)->current->next)
 #define CG_CODE(cg,offset)      (CG_BASE(cg) + (offset))
 #define CG_OFFSET(cg)           (CG_NEXT(cg) - CG_BASE(cg))
 
 #define CG_NOTES(cg)            ((cg)->current->notes)
 #define CG_NOTE_COUNT(cg)       ((cg)->current->noteCount)
-#define CG_NOTE_MASK(cg)        ((cg)->current->noteMask)
+#define CG_NOTE_LIMIT(cg)       ((cg)->current->noteLimit)
 #define CG_LAST_NOTE_OFFSET(cg) ((cg)->current->lastNoteOffset)
 #define CG_CURRENT_LINE(cg)     ((cg)->current->currentLine)
 
 #define CG_PROLOG_BASE(cg)      ((cg)->prolog.base)
 #define CG_PROLOG_LIMIT(cg)     ((cg)->prolog.limit)
 #define CG_PROLOG_NEXT(cg)      ((cg)->prolog.next)
 #define CG_PROLOG_CODE(cg,poff) (CG_PROLOG_BASE(cg) + (poff))
 #define CG_PROLOG_OFFSET(cg)    (CG_PROLOG_NEXT(cg) - CG_PROLOG_BASE(cg))
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -766,16 +766,27 @@ Class js::DeclEnvClass = {
 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();
 
@@ -824,17 +835,17 @@ CreateFunCallObject(JSContext *cx, Stack
     JSObject *scopeChain = &fp->scopeChain();
     JS_ASSERT_IF(scopeChain->isWith() || scopeChain->isBlock() || scopeChain->isCall(),
                  scopeChain->getPrivate() != fp);
 
     /*
      * For a named function expression Call's parent points to an environment
      * object holding function's name.
      */
-    if (JSAtom *lambdaName = (fp->fun()->flags & JSFUN_LAMBDA) ? fp->fun()->atom : NULL) {
+    if (JSAtom *lambdaName = CallObjectLambdaName(fp->fun())) {
         scopeChain = NewDeclEnvObject(cx, fp);
         if (!scopeChain)
             return NULL;
 
         if (!DefineNativeProperty(cx, scopeChain, ATOM_TO_JSID(lambdaName),
                                   ObjectValue(fp->callee()), NULL, NULL,
                                   JSPROP_PERMANENT | JSPROP_READONLY, 0, 0)) {
             return NULL;
@@ -941,16 +952,26 @@ js_PutCallObject(StackFrame *fp)
                 }
 
                 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]);
                 }
             }
+
+            /*
+             * 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();
+            }
         }
 
         /* 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);
@@ -1023,17 +1044,21 @@ SetCallArg(JSContext *cx, JSObject *obj,
     JS_ASSERT((int16) JSID_TO_INT(id) == JSID_TO_INT(id));
     uintN i = (uint16) JSID_TO_INT(id);
 
     if (StackFrame *fp = obj->maybeCallObjStackFrame())
         fp->formalArg(i) = *vp;
     else
         obj->setCallObjArg(i, *vp);
 
-    JSScript *script = obj->getCallObjCalleeFunction()->script();
+    JSFunction *fun = obj->getCallObjCalleeFunction();
+    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)
 {
@@ -1090,17 +1115,21 @@ SetCallVar(JSContext *cx, JSObject *obj,
     }
 #endif
 
     if (StackFrame *fp = obj->maybeCallObjStackFrame())
         fp->varSlot(i) = *vp;
     else
         obj->setCallObjVar(i, *vp);
 
-    JSScript *script = obj->getCallObjCalleeFunction()->script();
+    JSFunction *fun = obj->getCallObjCalleeFunction();
+    JSScript *script = fun->script();
+    if (!script->ensureHasTypes(cx, fun))
+        return false;
+
     TypeScript::SetLocal(cx, script, i, *vp);
 
     return true;
 }
 
 } // namespace js
 
 #if JS_TRACER
@@ -1818,17 +1847,16 @@ fun_toSource(JSContext *cx, uintN argc, 
     vp->setString(str);
     return true;
 }
 #endif
 
 JSBool
 js_fun_call(JSContext *cx, uintN argc, Value *vp)
 {
-    LeaveTrace(cx);
     Value fval = vp[1];
 
     if (!js_IsCallable(fval)) {
         ReportIncompatibleMethod(cx, vp, &FunctionClass);
         return false;
     }
 
     Value *argv = vp + 2;
@@ -1884,18 +1912,16 @@ js_fun_apply(JSContext *cx, uintN argc, 
      * Steps 4-5 (note erratum removing steps originally numbered 5 and 7 in
      * original version of ES5).
      */
     JSObject *aobj = &vp[3].toObject();
     jsuint length;
     if (!js_GetLengthProperty(cx, aobj, &length))
         return false;
 
-    LeaveTrace(cx);
-
     /* Step 6. */
     if (length > StackSpace::ARGS_LENGTH_MAX) {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_TOO_MANY_FUN_APPLY_ARGS);
         return false;
     }
 
     InvokeArgsGuard args;
     if (!cx->stack.pushInvokeArgs(cx, length, &args))
@@ -1993,18 +2019,16 @@ namespace js {
 /* ES5 15.3.4.5.1 and 15.3.4.5.2. */
 JSBool
 CallOrConstructBoundFunction(JSContext *cx, uintN argc, Value *vp)
 {
     JSObject *obj = &vp[0].toObject();
     JS_ASSERT(obj->isFunction());
     JS_ASSERT(obj->isBoundFunction());
 
-    LeaveTrace(cx);
-
     bool constructing = IsConstructing(vp);
 
     /* 15.3.4.5.1 step 1, 15.3.4.5.2 step 3. */
     uintN argslen = obj->getBoundFunctionArgumentCount();
 
     if (argc + argslen > StackSpace::ARGS_LENGTH_MAX) {
         js_ReportAllocationOverflow(cx);
         return false;
@@ -2384,19 +2408,18 @@ js_InitFunctionClass(JSContext *cx, JSOb
 
     JSScript *script = JSScript::NewScript(cx, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, JSVERSION_DEFAULT);
     if (!script)
         return NULL;
     script->noScriptRval = true;
     script->code[0] = JSOP_STOP;
     script->code[1] = SRC_NULL;
     fun->u.i.script = script;
-    fun->getType(cx)->functionScript = script;
+    fun->getType(cx)->interpretedFunction = fun;
     script->hasFunction = true;
-    script->where.fun = fun;
     script->setOwnerObject(fun);
     js_CallNewScriptHook(cx, script, fun);
 
     if (obj->isGlobal()) {
         /* ES5 13.2.3: Construct the unique [[ThrowTypeError]] function object. */
         JSFunction *throwTypeError =
             js_NewFunction(cx, NULL, reinterpret_cast<Native>(ThrowTypeError), 0,
                            0, obj, NULL);
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -233,38 +233,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 {
@@ -529,32 +525,32 @@ Chunk::releaseArena(ArenaHeader *aheader
         rt->gcEmptyChunkListHead = this;
         rt->gcEmptyChunkCount++;
     }
 }
 
 inline Chunk *
 AllocateGCChunk(JSRuntime *rt)
 {
-    Chunk *p = (Chunk *)rt->gcChunkAllocator->alloc();
+    Chunk *p = static_cast<Chunk *>(AllocGCChunk());
 #ifdef MOZ_GCTIMER
     if (p)
         JS_ATOMIC_INCREMENT(&newChunkCount);
 #endif
     return p;
 }
 
 inline void
 ReleaseGCChunk(JSRuntime *rt, Chunk *p)
 {
     JS_ASSERT(p);
 #ifdef MOZ_GCTIMER
     JS_ATOMIC_INCREMENT(&destroyChunkCount);
 #endif
-    rt->gcChunkAllocator->free_(p);
+    FreeGCChunk(p);
 }
 
 /* The caller must hold the GC lock. */
 static Chunk *
 PickChunk(JSContext *cx)
 {
     JSCompartment *comp = cx->compartment;
     JSRuntime *rt = comp->rt;
@@ -1552,19 +1548,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 +1573,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 +1604,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
--- 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/jsgcchunk.cpp
+++ b/js/src/jsgcchunk.cpp
@@ -267,27 +267,25 @@ UnmapPages(void *addr, size_t size)
     JS_ALWAYS_TRUE(munmap(addr, size) == 0);
 #endif
 }
 
 #endif
 
 namespace js {
 
-GCChunkAllocator defaultGCChunkAllocator;
-
 inline void *
 FindChunkStart(void *p)
 {
     jsuword addr = reinterpret_cast<jsuword>(p);
     addr = (addr + GC_CHUNK_MASK) & ~GC_CHUNK_MASK;
     return reinterpret_cast<void *>(addr);
 }
 
-JS_FRIEND_API(void *)
+void *
 AllocGCChunk()
 {
     void *p;
 
 #ifdef JS_GC_HAS_MAP_ALIGN
     p = MapAlignedPages(GC_CHUNK_SIZE, GC_CHUNK_SIZE);
     if (!p)
         return NULL;
@@ -324,17 +322,17 @@ AllocGCChunk()
         }
     }
 #endif /* !JS_GC_HAS_MAP_ALIGN */
 
     JS_ASSERT(!(reinterpret_cast<jsuword>(p) & GC_CHUNK_MASK));
     return p;
 }
 
-JS_FRIEND_API(void)
+void
 FreeGCChunk(void *p)
 {
     JS_ASSERT(p);
     JS_ASSERT(!(reinterpret_cast<jsuword>(p) & GC_CHUNK_MASK));
     UnmapPages(p, GC_CHUNK_SIZE);
 }
 
 } /* namespace js */
--- a/js/src/jsgcchunk.h
+++ b/js/src/jsgcchunk.h
@@ -44,49 +44,17 @@
 #include "jsutil.h"
 
 namespace js {
 
 const size_t GC_CHUNK_SHIFT = 20;
 const size_t GC_CHUNK_SIZE = size_t(1) << GC_CHUNK_SHIFT;
 const size_t GC_CHUNK_MASK = GC_CHUNK_SIZE - 1;
 
-JS_FRIEND_API(void *)
+void *
 AllocGCChunk();
 
-JS_FRIEND_API(void)
+void
 FreeGCChunk(void *p);
 
-class GCChunkAllocator {
-  public:
-    GCChunkAllocator() {}
-    
-    void *alloc() {
-        void *chunk = doAlloc();
-        JS_ASSERT(!(reinterpret_cast<jsuword>(chunk) & GC_CHUNK_MASK));
-        return chunk;
-    }
-
-    void free_(void *chunk) {
-        JS_ASSERT(chunk);
-        JS_ASSERT(!(reinterpret_cast<jsuword>(chunk) & GC_CHUNK_MASK));
-        doFree(chunk);
-    }
-    
-  private:
-    virtual void *doAlloc() {
-        return AllocGCChunk();
-    }
-    
-    virtual void doFree(void *chunk) {
-        FreeGCChunk(chunk);
-    }
-
-    /* No copy or assignment semantics. */
-    GCChunkAllocator(const GCChunkAllocator &);
-    void operator=(const GCChunkAllocator &);
-};
-
-extern GCChunkAllocator defaultGCChunkAllocator;
-
 }
 
 #endif /* jsgchunk_h__ */
--- a/js/src/jsgcinlines.h
+++ b/js/src/jsgcinlines.h
@@ -265,16 +265,17 @@ class CellIterImpl
     uintptr_t thing;
     Cell *cell;
 
   protected:
     CellIterImpl() {
     }
 
     void init(JSCompartment *comp, AllocKind kind) {
+        JS_ASSERT(comp->arenas.isSynchronizedFreeList(kind));
         firstThingOffset = Arena::firstThingOffset(kind);
         thingSize = Arena::thingSize(kind);
         aheader = comp->arenas.getFirstArena(kind);
         firstSpan.initAsEmpty();
         span = &firstSpan;
         thing = span->first;
         next();
     }
@@ -317,17 +318,16 @@ class CellIterImpl
     }
 };
 
 class CellIterUnderGC : public CellIterImpl {
 
   public:
     CellIterUnderGC(JSCompartment *comp, AllocKind kind) {
         JS_ASSERT(comp->rt->gcRunning);
-        comp->arenas.checkEmptyFreeList(kind);
         init(comp, kind);
     }
 };
 
 /*
  * When using the iterator outside the GC the caller must ensure that no GC or
  * allocations of GC things are possible and that the background finalization
  * for the given thing kind is not enabled or is done.
--- a/js/src/jsgcmark.cpp
+++ b/js/src/jsgcmark.cpp
@@ -229,18 +229,18 @@ MarkTypeObject(JSTracer *trc, types::Typ
      * Mark parts of a type object skipped by ScanTypeObject. ScanTypeObject is
      * only used for marking tracers; for tracers with a callback, if we
      * reenter through JS_TraceChildren then MarkChildren will *not* skip these
      * members, and we don't need to handle them here.
      */
     if (IS_GC_MARKING_TRACER(trc)) {
         if (type->singleton)
             MarkObject(trc, *type->singleton, "type_singleton");
-        if (type->functionScript)
-            MarkScript(trc, type->functionScript, "functionScript");
+        if (type->interpretedFunction)
+            MarkObject(trc, *type->interpretedFunction, "type_function");
     }
 }
 
 #if JS_HAS_XML_SUPPORT
 void
 MarkXML(JSTracer *trc, JSXML *xml, const char *name)
 {
     JS_ASSERT(trc);
@@ -410,17 +410,17 @@ MarkKind(JSTracer *trc, void *thing, JSG
         break;
       case JSTRACE_SCRIPT:
         Mark(trc, static_cast<JSScript *>(thing));
         break;
       case JSTRACE_SHAPE:
         Mark(trc, reinterpret_cast<Shape *>(thing));
         break;
       case JSTRACE_TYPE_OBJECT:
-        Mark(trc, reinterpret_cast<types::TypeObject *>(thing));
+        MarkTypeObject(trc, reinterpret_cast<types::TypeObject *>(thing), "type_stack");
         break;
 #if JS_HAS_XML_SUPPORT
       case JSTRACE_XML:
         Mark(trc, static_cast<JSXML *>(thing));
         break;
 #endif
     }
 }
@@ -846,24 +846,25 @@ MarkChildren(JSTracer *trc, JSScript *sc
 
     if (JSScript::isValidOffset(script->constOffset)) {
         JSConstArray *constarray = script->consts();
         MarkValueRange(trc, constarray->length, constarray->vector, "consts");
     }
 
     if (!script->isCachedEval && script->u.object)
         MarkObject(trc, *script->u.object, "object");
-    if (script->hasFunction)
-        MarkObject(trc, *script->function(), "script_fun");
 
     if (IS_GC_MARKING_TRACER(trc) && script->filename)
         js_MarkScriptFilename(script->filename);
 
     script->bindings.trace(trc);
 
+    if (script->types)
+        script->types->trace(trc);
+
 #ifdef JS_METHODJIT
     if (script->jitNormal)
         script->jitNormal->trace(trc);
     if (script->jitCtor)
         script->jitCtor->trace(trc);
 #endif
 }
 
@@ -908,17 +909,17 @@ ScanTypeObject(GCMarker *gcmarker, types
                 PushMarkStack(gcmarker, type->emptyShapes[i]);
         }
     }
 
     if (type->proto)
         PushMarkStack(gcmarker, type->proto);
 
     if (type->newScript) {
-        PushMarkStack(gcmarker, type->newScript->script);
+        PushMarkStack(gcmarker, type->newScript->fun);
         PushMarkStack(gcmarker, type->newScript->shape);
     }
 
     /*
      * Don't need to trace singleton or functionScript, an object with this
      * type must have already been traced and it will also hold a reference
      * on the script (singleton and functionScript types cannot be the newType
      * of another object). Attempts to mark type objects directly must use
@@ -948,22 +949,22 @@ MarkChildren(JSTracer *trc, types::TypeO
 
     if (type->proto)
         MarkObject(trc, *type->proto, "type_proto");
 
     if (type->singleton)
         MarkObject(trc, *type->singleton, "type_singleton");
 
     if (type->newScript) {
-        MarkScript(trc, type->newScript->script, "type_new_script");
+        MarkObject(trc, *type->newScript->fun, "type_new_function");
         MarkShape(trc, type->newScript->shape, "type_new_shape");
     }
 
-    if (type->functionScript)
-        MarkScript(trc, type->functionScript, "functionScript");
+    if (type->interpretedFunction)
+        MarkObject(trc, *type->interpretedFunction, "type_function");
 }
 
 #ifdef JS_HAS_XML_SUPPORT
 void
 MarkChildren(JSTracer *trc, JSXML *xml)
 {
     js_TraceXML(trc, xml);
 }
--- a/js/src/jsgcmark.h
+++ b/js/src/jsgcmark.h
@@ -45,19 +45,16 @@
 #include "jscompartment.h"
 
 #include "jslock.h"
 #include "jstl.h"
 
 namespace js {
 namespace gc {
 
-template<typename T>
-void Mark(JSTracer *trc, T *thing);
-
 void
 MarkString(JSTracer *trc, JSString *str);
 
 void
 MarkString(JSTracer *trc, JSString *str, const char *name);
 
 void
 MarkObject(JSTracer *trc, JSObject &obj, const char *name);
--- 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
@@ -711,42 +711,52 @@ TypeSet::addPropagateThis(JSContext *cx,
     add(cx, ArenaNew<TypeConstraintPropagateThis>(cx->compartment->pool, script, callpc, type));
 }
 
 /* Subset constraint which filters out primitive types. */
 class TypeConstraintFilterPrimitive : public TypeConstraint
 {
 public:
     TypeSet *target;
-
-    /* Primitive types other than null and undefined are passed through. */
-    bool onlyNullVoid;
-
-    TypeConstraintFilterPrimitive(TypeSet *target, bool onlyNullVoid)
-        : TypeConstraint("filter"), target(target), onlyNullVoid(onlyNullVoid)
+    TypeSet::FilterKind filter;
+
+    TypeConstraintFilterPrimitive(TypeSet *target, TypeSet::FilterKind filter)
+        : TypeConstraint("filter"), target(target), filter(filter)
     {}
 
     void newType(JSContext *cx, TypeSet *source, Type type)
     {
-        if (onlyNullVoid) {
+        switch (filter) {
+          case TypeSet::FILTER_ALL_PRIMITIVES:
+            if (type.isPrimitive())
+                return;
+            break;
+
+          case TypeSet::FILTER_NULL_VOID:
             if (type.isPrimitive(JSVAL_TYPE_NULL) || type.isPrimitive(JSVAL_TYPE_UNDEFINED))
                 return;
-        } else if (type.isPrimitive()) {
-            return;
+            break;
+
+          case TypeSet::FILTER_VOID:
+            if (type.isPrimitive(JSVAL_TYPE_UNDEFINED))
+                return;
+            break;
+
+          default:
+            JS_NOT_REACHED("Bad filter");
         }
 
         target->addType(cx, type);
     }
 };
 
 void
-TypeSet::addFilterPrimitives(JSContext *cx, TypeSet *target, bool onlyNullVoid)
-{
-    add(cx, ArenaNew<TypeConstraintFilterPrimitive>(cx->compartment->pool,
-                                                    target, onlyNullVoid));
+TypeSet::addFilterPrimitives(JSContext *cx, TypeSet *target, FilterKind filter)
+{
+    add(cx, ArenaNew<TypeConstraintFilterPrimitive>(cx->compartment->pool, target, filter));
 }
 
 /* If id is a normal slotful 'own' property of an object, get its shape. */
 static inline const Shape *
 GetSingletonShape(JSObject *obj, jsid id)
 {
     const Shape *shape = obj->nativeLookup(id);
     if (shape && shape->hasDefaultGetterOrIsMethod() && shape->slot != SHAPE_INVALID_SLOT)
@@ -1098,17 +1108,17 @@ TypeConstraintCall::newType(JSContext *c
     jsbytecode *pc = callsite->pc;
 
     if (type.isUnknown() || type.isAnyObject()) {
         /* Monitor calls on unknown functions. */
         cx->compartment->types.monitorBytecode(cx, script, pc - script->code);
         return;
     }
 
-    JSScript *callee = NULL;
+    JSFunction *callee = NULL;
 
     if (type.isSingleObject()) {
         JSObject *obj = type.singleObject();
 
         if (!obj->isFunction()) {
             /* Calls on non-functions are dynamically monitored. */
             return;
         }
@@ -1154,69 +1164,67 @@ TypeConstraintCall::newType(JSContext *c
                                        callsite->argumentTypes[i], JSID_VOID);
                     }
                 }
             }
 
             return;
         }
 
-        callee = obj->getFunctionPrivate()->script();
+        callee = obj->getFunctionPrivate();
     } else if (type.isTypeObject()) {
-        callee = type.typeObject()->functionScript;
+        callee = type.typeObject()->interpretedFunction;
         if (!callee)
             return;
     } else {
         /* Calls on non-objects are dynamically monitored. */
         return;
     }
 
-    unsigned nargs = callee->function()->nargs;
-
-    if (!callee->ensureHasTypes(cx))
+    if (!callee->script()->ensureHasTypes(cx, callee))
         return;
 
-    /* Analyze the function if we have not already done so. */
-    if (!callee->ensureRanInference(cx)) {
-        cx->compartment->types.setPendingNukeTypes(cx);
-        return;
-    }
+    unsigned nargs = callee->nargs;
 
     /* Add bindings for the arguments of the call. */
     for (unsigned i = 0; i < callsite->argumentCount && i < nargs; i++) {
         TypeSet *argTypes = callsite->argumentTypes[i];
-        TypeSet *types = TypeScript::ArgTypes(callee, i);
+        TypeSet *types = TypeScript::ArgTypes(callee->script(), i);
         argTypes->addSubsetBarrier(cx, script, pc, types);
     }
 
     /* Add void type for any formals in the callee not supplied at the call site. */
     for (unsigned i = callsite->argumentCount; i < nargs; i++) {
-        TypeSet *types = TypeScript::ArgTypes(callee, i);
+        TypeSet *types = TypeScript::ArgTypes(callee->script(), i);
         types->addType(cx, Type::UndefinedType());
     }
 
+    TypeSet *thisTypes = TypeScript::ThisTypes(callee->script());
+    TypeSet *returnTypes = TypeScript::ReturnTypes(callee->script());
+
     if (callsite->isNew) {
         /*
          * If the script does not return a value then the pushed value is the
          * new object (typical case). Note that we don't model construction of
          * the new value, which is done dynamically; we don't keep track of the
          * possible 'new' types for a given prototype type object.
          */
-        TypeScript::ThisTypes(callee)->addSubset(cx, callsite->returnTypes);
-        TypeScript::ReturnTypes(callee)->addFilterPrimitives(cx, callsite->returnTypes, false);
+        thisTypes->addSubset(cx, callsite->returnTypes);
+        returnTypes->addFilterPrimitives(cx, callsite->returnTypes,
+                                         TypeSet::FILTER_ALL_PRIMITIVES);
     } else {
         /*
          * Add a binding for the return value of the call. We don't add a
          * binding for the receiver object, as this is done with PropagateThis
          * constraints added by the original JSOP_CALL* op. The type sets we
          * manipulate here have lost any correlations between particular types
          * in the 'this' and 'callee' sets, which we want to maintain for
          * polymorphic JSOP_CALLPROP invocations.
          */
-        TypeScript::ReturnTypes(callee)->addSubset(cx, callsite->returnTypes);
+        returnTypes->addSubset(cx, callsite->returnTypes);
     }
 }
 
 void
 TypeConstraintPropagateThis::newType(JSContext *cx, TypeSet *source, Type type)
 {
     if (type.isUnknown() || type.isAnyObject()) {
         /*
@@ -1225,37 +1233,37 @@ TypeConstraintPropagateThis::newType(JSC
          * CALLPROP and CALLELEM, for other calls we are past the type barrier
          * already and a TypeConstraintCall will also monitor the call.
          */
         cx->compartment->types.monitorBytecode(cx, script, callpc - script->code);
         return;
     }
 
     /* Ignore calls to natives, these will be handled by TypeConstraintCall. */
-    JSScript *callee = NULL;
+    JSFunction *callee = NULL;
 
     if (type.isSingleObject()) {
         JSObject *object = type.singleObject();
         if (!object->isFunction() || !object->getFunctionPrivate()->isInterpreted())
             return;
-        callee = object->getFunctionPrivate()->script();
+        callee = object->getFunctionPrivate();
     } else if (type.isTypeObject()) {
         TypeObject *object = type.typeObject();
-        if (!object->isFunction() || !object->functionScript)
+        if (!object->interpretedFunction)
             return;
-        callee = object->functionScript;
+        callee = object->interpretedFunction;
     } else {
         /* Ignore calls to primitives, these will go through a stub. */
         return;
     }
 
-    if (!callee->ensureHasTypes(cx))
+    if (!callee->script()->ensureHasTypes(cx, callee))
         return;
 
-    TypeScript::ThisTypes(callee)->addType(cx, this->type);
+    TypeScript::ThisTypes(callee->script())->addType(cx, this->type);
 }
 
 void
 TypeConstraintArith::newType(JSContext *cx, TypeSet *source, Type type)
 {
     /*
      * We only model a subset of the arithmetic behavior that is actually
      * possible. The following need to be watched for at runtime:
@@ -1618,17 +1626,17 @@ types::MarkArgumentsCreated(JSContext *c
         return;
 
     AutoEnterTypeInference enter(cx);
 
 #ifdef JS_METHODJIT
     mjit::ExpandInlineFrames(cx->compartment);
 #endif
 
-    if (!script->ensureRanBytecode(cx))
+    if (!script->ensureRanAnalysis(cx))
         return;
 
     ScriptAnalysis *analysis = script->analysis();
 
     for (FrameRegsIter iter(cx); !iter.done(); ++iter) {
         StackFrame *fp = iter.fp();
         if (fp->isScriptFrame() && fp->script() == script) {
             /*
@@ -1707,30 +1715,30 @@ public:
         if (source->isOwnProperty(configurable)) {
             updated = true;
             cx->compartment->types.addPendingRecompile(cx, script);
         }
     }
 };
 
 static void
-CheckNewScriptProperties(JSContext *cx, TypeObject *type, JSScript *script);
+CheckNewScriptProperties(JSContext *cx, TypeObject *type, JSFunction *fun);
 
 bool
 TypeSet::isOwnProperty(JSContext *cx, TypeObject *object, bool configurable)
 {
     /*
      * Everywhere compiled code depends on definite properties associated with
      * a type object's newScript, we need to make sure there are constraints
      * in place which will mark those properties as configured should the
      * definite properties be invalidated.
      */
     if (object->flags & OBJECT_FLAG_NEW_SCRIPT_REGENERATE) {
         if (object->newScript) {
-            CheckNewScriptProperties(cx, object, object->newScript->script);
+            CheckNewScriptProperties(cx, object, object->newScript->fun);
         } else {
             JS_ASSERT(object->flags & OBJECT_FLAG_NEW_SCRIPT_CLEARED);
             object->flags &= ~OBJECT_FLAG_NEW_SCRIPT_REGENERATE;
         }
     }
 
     if (isOwnProperty(configurable))
         return true;
@@ -1809,16 +1817,74 @@ TypeSet::getSingleton(JSContext *cx, boo
     if (freeze) {
         add(cx, ArenaNew<TypeConstraintFreeze>(cx->compartment->pool,
                                                cx->compartment->types.compiledScript), false);
     }
 
     return obj;
 }
 
+static inline bool
+TypeHasGlobal(Type type, JSObject *global)
+{
+    if (type.isUnknown() || type.isAnyObject())
+        return false;
+
+    if (type.isSingleObject())
+        return type.singleObject()->getGlobal() == global;
+
+    if (type.isTypeObject())
+        return type.typeObject()->getGlobal() == global;
+
+    JS_ASSERT(type.isPrimitive());
+    return true;
+}
+
+class TypeConstraintFreezeGlobal : public TypeConstraint
+{
+public:
+    JSScript *script;
+    JSObject *global;
+
+    TypeConstraintFreezeGlobal(JSScript *script, JSObject *global)
+        : TypeConstraint("freezeGlobal"), script(script), global(global)
+    {
+        JS_ASSERT(global);
+    }
+
+    void newType(JSContext *cx, TypeSet *source, Type type)
+    {
+        if (!global || TypeHasGlobal(type, global))
+            return;
+
+        global = NULL;
+        cx->compartment->types.addPendingRecompile(cx, script);
+    }
+};
+
+bool
+TypeSet::hasGlobalObject(JSContext *cx, JSObject *global)
+{
+    if (unknownObject())
+        return false;
+
+    unsigned count = getObjectCount();
+    for (unsigned i = 0; i < count; i++) {
+        TypeObjectKey *object = getObject(i);
+        if (object && !TypeHasGlobal(Type::ObjectType(object), global))
+            return false;
+    }
+
+    add(cx, ArenaNew<TypeConstraintFreezeGlobal>(cx->compartment->pool,
+                                                 cx->compartment->types.compiledScript,
+                                                 global), false);
+
+    return true;
+}
+
 /////////////////////////////////////////////////////////////////////
 // TypeCompartment
 /////////////////////////////////////////////////////////////////////
 
 TypeObject types::emptyTypeObject(NULL, false, true);
 
 void
 TypeCompartment::init(JSContext *cx)
@@ -2275,55 +2341,34 @@ ScriptAnalysis::addSingletonTypeBarrier(
     TypeBarrier *barrier =
         ArenaNew<TypeBarrier>(cx->compartment->pool, target, Type::UndefinedType(),
                               singleton, singletonId);
 
     barrier->next = code.typeBarriers;
     code.typeBarriers = barrier;
 }
 
-static void
-PrintScriptTypeCallback(JSContext *cx, void *data, void *thing,
-                        JSGCTraceKind traceKind, size_t thingSize)
-{
-    JS_ASSERT(!data);
-    JS_ASSERT(traceKind == JSTRACE_SCRIPT);
-    JSScript *script = static_cast<JSScript *>(thing);
-    if (script->hasAnalysis() && script->analysis()->ranInference())
-        script->analysis()->printTypes(cx);
-}
-
-#ifdef DEBUG
-static void
-PrintObjectCallback(JSContext *cx, void *data, void *thing,
-                    JSGCTraceKind traceKind, size_t thingSize)
-{
-    JS_ASSERT(traceKind == JSTRACE_OBJECT);
-    TypeObject *object = (TypeObject *) thing;
-    object->print(cx);
-}
-#endif
-
 void
 TypeCompartment::print(JSContext *cx, bool force)
 {
     JSCompartment *compartment = this->compartment();
 
     if (!force && !InferSpewActive(ISpewResult))
         return;
 
-    {
-        AutoUnlockGC unlock(cx->runtime);
-        IterateCells(cx, compartment, gc::FINALIZE_SCRIPT, cx, PrintScriptTypeCallback);
+    for (gc::CellIter i(cx, compartment, gc::FINALIZE_SCRIPT); !i.done(); i.next()) {
+        JSScript *script = i.get<JSScript>();
+        if (script->hasAnalysis() && script->analysis()->ranInference())
+            script->analysis()->printTypes(cx);
     }
 
 #ifdef DEBUG
-    {
-        AutoUnlockGC unlock(cx->runtime);
-        IterateCells(cx, compartment, gc::FINALIZE_TYPE_OBJECT, NULL, PrintObjectCallback);
+    for (gc::CellIter i(cx, compartment, gc::FINALIZE_TYPE_OBJECT); !i.done(); i.next()) {
+        TypeObject *object = i.get<TypeObject>();
+        object->print(cx);
     }
 #endif
 
     printf("Counts: ");
     for (unsigned count = 0; count < TYPE_COUNT_LIMIT; count++) {
         if (count)
             printf("/");
         printf("%u", typeCounts[count]);
@@ -2836,19 +2881,24 @@ TypeObject::setFlags(JSContext *cx, Type
     if ((this->flags & flags) == flags)
         return;
 
     AutoEnterTypeInference enter(cx);
 
     if (singleton) {
         /* Make sure flags are consistent with persistent object state. */
         JS_ASSERT_IF(flags & OBJECT_FLAG_CREATED_ARGUMENTS,
-                     (flags & OBJECT_FLAG_UNINLINEABLE) && functionScript->createdArgs);
-        JS_ASSERT_IF(flags & OBJECT_FLAG_UNINLINEABLE, functionScript->uninlineable);
-        JS_ASSERT_IF(flags & OBJECT_FLAG_ITERATED, singleton->flags & JSObject::ITERATED);
+                     (flags & OBJECT_FLAG_UNINLINEABLE) &&
+                     interpretedFunction->script()->createdArgs);
+        JS_ASSERT_IF(flags & OBJECT_FLAG_UNINLINEABLE,
+                     interpretedFunction->script()->uninlineable);
+        JS_ASSERT_IF(flags & OBJECT_FLAG_REENTRANT_FUNCTION,
+                     interpretedFunction->script()->reentrantOuterFunction);
+        JS_ASSERT_IF(flags & OBJECT_FLAG_ITERATED,
+                     singleton->flags & JSObject::ITERATED);
     }
 
     this->flags |= flags;
 
     InferSpew(ISpewOps, "%s: setFlags %u", TypeObjectString(this), flags);
 
     ObjectStateChange(cx, this, false, false);
 }
@@ -2929,17 +2979,17 @@ TypeObject::clearNewScript(JSContext *cx
      * longer correct state of the object once its initialization is completed.
      * We can't really detect the possibility of this statically, but the new
      * script keeps track of where each property is initialized so we can walk
      * the stack and fix up any such objects.
      */
     for (FrameRegsIter iter(cx); !iter.done(); ++iter) {
         StackFrame *fp = iter.fp();
         if (fp->isScriptFrame() && fp->isConstructing() &&
-            fp->script() == newScript->script && fp->thisValue().isObject() &&
+            fp->fun() == newScript->fun && fp->thisValue().isObject() &&
             !fp->thisValue().toObject().hasLazyType() &&
             fp->thisValue().toObject().type() == this) {
             JSObject *obj = &fp->thisValue().toObject();
             jsbytecode *pc = iter.pc();
 
             /* Whether all identified 'new' properties have been initialized. */
             bool finished = false;
 
@@ -3084,16 +3134,106 @@ GetInitializerType(JSContext *cx, JSScri
 
     JSOp op = JSOp(*pc);
     JS_ASSERT(op == JSOP_NEWARRAY || op == JSOP_NEWOBJECT || op == JSOP_NEWINIT);
 
     bool isArray = (op == JSOP_NEWARRAY || (op == JSOP_NEWINIT && pc[1] == JSProto_Array));
     return TypeScript::InitObject(cx, script, pc, isArray ? JSProto_Array : JSProto_Object);
 }
 
+/*
+ * Detach nesting state for script from its parent, removing it entirely if it
+ * has no children of its own. This happens when walking type information while
+ * initially resolving NAME accesses, thus will not invalidate any compiler
+ * dependencies.
+ */
+static void
+DetachNestingParent(JSScript *script)
+{
+    TypeScriptNesting *nesting = script->nesting();
+
+    if (!nesting || !nesting->parent)
+        return;
+
+    /* Remove from parent's list of children. */
+    JSScript **pscript = &nesting->parent->nesting()->children;
+    while ((*pscript)->nesting() != nesting)
+        pscript = &(*pscript)->nesting()->next;
+    *pscript = nesting->next;
+
+    nesting->parent = NULL;
+
+    /* If this nesting can have no children of its own, destroy it. */
+    if (!script->isOuterFunction)
+        script->clearNesting();
+}
+
+ScriptAnalysis::NameAccess
+ScriptAnalysis::resolveNameAccess(JSContext *cx, jsid id, bool addDependency)
+{
+    JS_ASSERT(cx->typeInferenceEnabled());
+
+    NameAccess access;
+    PodZero(&access);
+
+    if (!JSID_IS_ATOM(id))
+        return access;
+    JSAtom *atom = JSID_TO_ATOM(id);
+
+    JSScript *script = this->script;
+    while (script->hasFunction && script->nesting()) {
+        if (!script->ensureRanInference(cx))
+            return access;
+
+        /*
+         * Don't resolve names in scripts which use 'let' or 'with'. New names
+         * bound here can mask variables of the script itself.
+         *
+         * Also, don't resolve names in scripts which are generators. Frame
+         * balancing works differently for generators and we do not maintain
+         * active frame counts for such scripts.
+         */
+        if (script->analysis()->addsScopeObjects() ||
+            js_GetOpcode(cx, script, script->code) == JSOP_GENERATOR) {
+            return access;
+        }
+
+        /* Check if the script definitely binds the identifier. */
+        uintN index;
+        BindingKind kind = script->bindings.lookup(cx, atom, &index);
+        if (kind == ARGUMENT || kind == VARIABLE) {
+            TypeObject *obj = script->function()->getType(cx);
+
+            if (addDependency) {
+                /*
+                 * Record the dependency which compiled code has on the outer
+                 * function being non-reentrant.
+                 */
+                if (TypeSet::HasObjectFlags(cx, obj, OBJECT_FLAG_REENTRANT_FUNCTION))
+                    return access;
+            }
+
+            access.script = script;
+            access.nesting = script->nesting();
+            access.slot = (kind == ARGUMENT) ? ArgSlot(index) : LocalSlot(script, index);
+            access.arg = (kind == ARGUMENT);
+            access.index = index;
+            return access;
+        } else if (kind != NONE) {
+            return access;
+        }
+
+        if (!script->nesting()->parent)
+            return access;
+        script = script->nesting()->parent;
+    }
+
+    return access;
+}
+
 /* Analyze type information for a single bytecode. */
 bool
 ScriptAnalysis::analyzeTypesBytecode(JSContext *cx, unsigned offset,
                                      TypeInferenceState &state)
 {
     jsbytecode *pc = script->code + offset;
     JSOp op = (JSOp)*pc;
 
@@ -3316,17 +3456,17 @@ ScriptAnalysis::analyzeTypesBytecode(JSC
       case JSOP_GETGNAME:
       case JSOP_CALLGNAME: {
         jsid id;
         if (op == JSOP_GETGLOBAL || op == JSOP_CALLGLOBAL)
             id = GetGlobalId(cx, script, pc);
         else
             id = GetAtomId(cx, script, pc, 0);
 
-        TypeSet *seen = script->analysis()->bytecodeTypes(pc);
+        TypeSet *seen = bytecodeTypes(pc);
         seen->addSubset(cx, &pushed[0]);
 
         /*
          * Normally we rely on lazy standard class initialization to fill in
          * the types of global properties the script can access. In a few cases
          * the method JIT will bypass this, and we need to add the types direclty.
          */
         if (id == ATOM_TO_JSID(cx->runtime->atomState.typeAtoms[JSTYPE_VOID]))
@@ -3346,23 +3486,35 @@ ScriptAnalysis::analyzeTypesBytecode(JSC
 
         if (CheckNextTest(pc))
             pushed[0].addType(cx, Type::UndefinedType());
         break;
       }
 
       case JSOP_NAME:
       case JSOP_CALLNAME: {
+        TypeSet *seen = bytecodeTypes(pc);
+        seen->addSubset(cx, &pushed[0]);
+
         /*
-         * The first value pushed by NAME/CALLNAME must always be added to the
-         * bytecode types, we don't model these opcodes with inference.
+         * Try to resolve this name by walking the function's scope nesting.
+         * If we succeed but the accessed script has had its TypeScript purged
+         * in the past, we still must use a type barrier: the name access can
+         * be on a call object which predated the purge, and whose types might
+         * not be reflected in the reconstructed information.
          */
-        TypeSet *seen = script->analysis()->bytecodeTypes(pc);
-        addTypeBarrier(cx, pc, seen, Type::UnknownType());
-        seen->addSubset(cx, &pushed[0]);
+        jsid id = GetAtomId(cx, script, pc, 0);
+        NameAccess access = resolveNameAccess(cx, id);
+        if (access.script && !access.script->typesPurged) {
+            TypeSet *types = TypeScript::SlotTypes(access.script, access.slot);
+            types->addSubsetBarrier(cx, script, pc, seen);
+        } else {
+            addTypeBarrier(cx, pc, seen, Type::UnknownType());
+        }
+
         if (op == JSOP_CALLNAME) {
             pushed[1].addType(cx, Type::UnknownType());
             pushed[0].addPropagateThis(cx, script, pc, Type::UnknownType());
         }
         break;
       }
 
       case JSOP_BINDGNAME:
@@ -3372,17 +3524,29 @@ ScriptAnalysis::analyzeTypesBytecode(JSC
       case JSOP_SETGNAME: {
         jsid id = GetAtomId(cx, script, pc, 0);
         PropertyAccess(cx, script, pc, script->global()->getType(cx),
                        true, poppedTypes(pc, 0), id);
         poppedTypes(pc, 0)->addSubset(cx, &pushed[0]);
         break;
       }
 
-      case JSOP_SETNAME:
+      case JSOP_SETNAME: {
+        jsid id = GetAtomId(cx, script, pc, 0);
+        NameAccess access = resolveNameAccess(cx, id);
+        if (access.script) {
+            TypeSet *types = TypeScript::SlotTypes(access.script, access.slot);
+            poppedTypes(pc, 0)->addSubset(cx, types);
+        } else {
+            cx->compartment->types.monitorBytecode(cx, script, offset);
+        }
+        poppedTypes(pc, 0)->addSubset(cx, &pushed[0]);
+        break;
+      }
+
       case JSOP_SETCONST:
         cx->compartment->types.monitorBytecode(cx, script, offset);
         poppedTypes(pc, 0)->addSubset(cx, &pushed[0]);
         break;
 
       case JSOP_GETXPROP:
       case JSOP_GETFCSLOT:
       case JSOP_CALLFCSLOT: {
@@ -3491,17 +3655,17 @@ ScriptAnalysis::analyzeTypesBytecode(JSC
         TypeSet *seen = script->analysis()->bytecodeTypes(pc);
 
         poppedTypes(pc, 0)->addGetProperty(cx, script, pc, seen, id);
         if (op == JSOP_CALLPROP)
             poppedTypes(pc, 0)->addCallProperty(cx, script, pc, id);
 
         seen->addSubset(cx, &pushed[0]);
         if (op == JSOP_CALLPROP)
-            poppedTypes(pc, 0)->addFilterPrimitives(cx, &pushed[1], true);
+            poppedTypes(pc, 0)->addFilterPrimitives(cx, &pushed[1], TypeSet::FILTER_NULL_VOID);
         if (CheckNextTest(pc))
             pushed[0].addType(cx, Type::UndefinedType());
         break;
       }
 
       /*
        * We only consider ELEM accesses on integers below. Any element access
        * which is accessing a non-integer property must be monitored.
@@ -3512,17 +3676,17 @@ ScriptAnalysis::analyzeTypesBytecode(JSC
         TypeSet *seen = script->analysis()->bytecodeTypes(pc);
 
         poppedTypes(pc, 1)->addGetProperty(cx, script, pc, seen, JSID_VOID);
         if (op == JSOP_CALLELEM)
             poppedTypes(pc, 1)->addCallProperty(cx, script, pc, JSID_VOID);
 
         seen->addSubset(cx, &pushed[0]);
         if (op == JSOP_CALLELEM)
-            poppedTypes(pc, 1)->addFilterPrimitives(cx, &pushed[1], true);
+            poppedTypes(pc, 1)->addFilterPrimitives(cx, &pushed[1], TypeSet::FILTER_NULL_VOID);
         if (CheckNextTest(pc))
             pushed[0].addType(cx, Type::UndefinedType());
         break;
       }
 
       case JSOP_SETELEM:
       case JSOP_SETHOLE:
         poppedTypes(pc, 1)->addSetElement(cx, script, pc, poppedTypes(pc, 2), poppedTypes(pc, 0));
@@ -3910,16 +4074,56 @@ ScriptAnalysis::analyzeTypes(JSContext *
      * all types in the compartment.
      */
     ranInference_ = true;
 
     /* Make sure the initial type set of all local vars includes void. */
     for (unsigned i = 0; i < script->nfixed; i++)
         TypeScript::LocalTypes(script, i)->addType(cx, Type::UndefinedType());
 
+    TypeScriptNesting *nesting = script->hasFunction ? script->nesting() : NULL;
+    if (nesting && nesting->parent) {
+        /*
+         * Check whether NAME accesses can be resolved in parent scopes, and
+         * detach from the parent if so. Even if outdated activations of this
+         * function are live when the parent is called again, we do not need to
+         * consider this reentrance as no state in the parent will be used.
+         */
+        if (!nesting->parent->ensureRanInference(cx))
+            return;
+
+        bool detached = false;
+
+        /* Don't track for leaf scripts which have no free variables. */
+        if (!usesScopeChain() && !script->isOuterFunction) {
+            DetachNestingParent(script);
+            detached = true;
+        }
+
+        /*
+         * If the names bound by the script are extensible (DEFFUN, EVAL, ...),
+         * don't resolve NAME accesses into the parent.
+         */
+        if (!detached && extendsScope()) {
+            DetachNestingParent(script);
+            detached = true;
+        }
+
+        /*
+         * Don't track for parents which add call objects or are generators,
+         * don't resolve NAME accesses into the parent.
+         */
+        if (!detached &&
+            (nesting->parent->analysis()->addsScopeObjects() ||
+             js_GetOpcode(cx, nesting->parent, nesting->parent->code) == JSOP_GENERATOR)) {
+            DetachNestingParent(script);
+            detached = true;
+        }
+    }
+
     TypeInferenceState state(cx);
 
     unsigned offset = 0;
     while (offset < script->length) {
         Bytecode *code = maybeCode(offset);
 
         jsbytecode *pc = script->code + offset;
         UntrapOpcode untrap(cx, script, pc);
@@ -4118,17 +4322,17 @@ public:
             return;
 
         if (source->baseFlags() || source->getObjectCount() > 1)
             object->clearNewScript(cx);
     }
 };
 
 static bool
-AnalyzeNewScriptProperties(JSContext *cx, TypeObject *type, JSScript *script, JSObject **pbaseobj,
+AnalyzeNewScriptProperties(JSContext *cx, TypeObject *type, JSFunction *fun, JSObject **pbaseobj,
                            Vector<TypeNewScript::Initializer> *initializerList)
 {
     /*
      * When invoking 'new' on the specified script, try to find some properties
      * which will definitely be added to the created object before it has a
      * chance to escape and be accessed elsewhere.
      *
      * Returns true if the entire script was analyzed (pbaseobj has been
@@ -4139,24 +4343,28 @@ AnalyzeNewScriptProperties(JSContext *cx
     if (initializerList->length() > 50) {
         /*
          * Bail out on really long initializer lists (far longer than maximum
          * number of properties we can track), we may be recursing.
          */
         return false;
     }
 
-    if (script->hasClearedGlobal())
-        return false;
-
-    if (!script->ensureRanInference(cx)) {
+    JSScript *script = fun->script();
+    JS_ASSERT(!script->isInnerFunction);
+
+    if (!script->ensureRanAnalysis(cx, fun) || !script->ensureRanInference(cx)) {
         *pbaseobj = NULL;
         cx->compartment->types.setPendingNukeTypes(cx);
         return false;
     }
+
+    if (script->hasClearedGlobal())
+        return false;
+
     ScriptAnalysis *analysis = script->analysis();
 
     /*
      * Offset of the last bytecode which popped 'this' and which we have
      * processed. For simplicity, we scan for places where 'this' is pushed
      * and immediately analyze the place where that pushed value is popped.
      * This runs the risk of doing things out of order, if the script looks
      * something like 'this.f  = (this.g = ...)', so we watch and bail out if
@@ -4324,17 +4532,18 @@ AnalyzeNewScriptProperties(JSContext *cx
             /* Need to definitely be calling Function.call on a specific script. */
             JSObject *funcallObj = funcallTypes->getSingleton(cx, false);
             JSObject *scriptObj = scriptTypes->getSingleton(cx, false);
             if (!funcallObj || !scriptObj || !scriptObj->isFunction() ||
                 !scriptObj->getFunctionPrivate()->isInterpreted()) {
                 return false;
             }
 
-            JSScript *functionScript = scriptObj->getFunctionPrivate()->script();
+            JSFunction *function = scriptObj->getFunctionPrivate();
+            JS_ASSERT(!function->script()->isInnerFunction);
 
             /*
              * Generate constraints to clear definite properties from the type
              * should the Function.call or callee itself change in the future.
              */
             analysis->pushedTypes(calleev.pushedOffset(), 0)->add(cx,
                 ArenaNew<TypeConstraintClearDefiniteSingle>(cx->compartment->pool, type));
             analysis->pushedTypes(calleev.pushedOffset(), 1)->add(cx,
@@ -4342,17 +4551,17 @@ AnalyzeNewScriptProperties(JSContext *cx
 
             TypeNewScript::Initializer pushframe(TypeNewScript::Initializer::FRAME_PUSH, uses->offset);
             if (!initializerList->append(pushframe)) {
                 cx->compartment->types.setPendingNukeTypes(cx);
                 *pbaseobj = NULL;
                 return false;
             }
 
-            if (!AnalyzeNewScriptProperties(cx, type, functionScript,
+            if (!AnalyzeNewScriptProperties(cx, type, function,
                                             pbaseobj, initializerList)) {
                 return false;
             }
 
             TypeNewScript::Initializer popframe(TypeNewScript::Initializer::FRAME_POP, 0);
             if (!initializerList->append(popframe)) {
                 cx->compartment->types.setPendingNukeTypes(cx);
                 *pbaseobj = NULL;
@@ -4374,31 +4583,31 @@ AnalyzeNewScriptProperties(JSContext *cx
 }
 
 /*
  * Either make the newScript information for type when it is constructed
  * by the specified script, or regenerate the constraints for an existing
  * newScript on the type after they were cleared by a GC.
  */
 static void
-CheckNewScriptProperties(JSContext *cx, TypeObject *type, JSScript *script)
-{
-    if (type->unknownProperties())
+CheckNewScriptProperties(JSContext *cx, TypeObject *type, JSFunction *fun)
+{
+    if (type->unknownProperties() || fun->script()->isInnerFunction)
         return;
 
     /* Strawman object to add properties to and watch for duplicates. */
     JSObject *baseobj = NewBuiltinClassInstance(cx, &ObjectClass, gc::FINALIZE_OBJECT16);
     if (!baseobj) {
         if (type->newScript)
             type->clearNewScript(cx);
         return;
     }
 
     Vector<TypeNewScript::Initializer> initializerList(cx);
-    AnalyzeNewScriptProperties(cx, type, script, &baseobj, &initializerList);
+    AnalyzeNewScriptProperties(cx, type, fun, &baseobj, &initializerList);
     if (!baseobj || baseobj->slotSpan() == 0 || !!(type->flags & OBJECT_FLAG_NEW_SCRIPT_CLEARED)) {
         if (type->newScript)
             type->clearNewScript(cx);
         return;
     }
 
     /*
      * If the type already has a new script, we are just regenerating the type
@@ -4435,17 +4644,17 @@ CheckNewScriptProperties(JSContext *cx, 
     size_t numBytes = sizeof(TypeNewScript)
                     + (initializerList.length() * sizeof(TypeNewScript::Initializer));
     type->newScript = (TypeNewScript *) cx->calloc_(numBytes);
     if (!type->newScript) {
         cx->compartment->types.setPendingNukeTypes(cx);
         return;
     }
 
-    type->newScript->script = script;
+    type->newScript->fun = fun;
     type->newScript->allocKind = kind;
     type->newScript->shape = baseobj->lastProperty();
 
     type->newScript->initializerList = (TypeNewScript::Initializer *)
         ((char *) type->newScript + sizeof(TypeNewScript));
     PodCopy(type->newScript->initializerList, initializerList.begin(), initializerList.length());
 }
 
@@ -4685,27 +4894,35 @@ TypeMonitorCallSlow(JSContext *cx, JSObj
 
 static inline bool
 IsAboutToBeFinalized(JSContext *cx, TypeObjectKey *key)
 {
     /* Mask out the low bit indicating whether this is a type or JS object. */
     return !reinterpret_cast<const gc::Cell *>((jsuword) key & ~1)->isMarked();
 }
 
+inline bool
+ScriptIsAboutToBeFinalized(JSContext *cx, JSScript *script, JSFunction *fun)
+{
+    return script->isCachedEval ||
+        (script->u.object && IsAboutToBeFinalized(cx, script->u.object)) ||
+        (fun && IsAboutToBeFinalized(cx, fun));
+}
+
 void
 TypeDynamicResult(JSContext *cx, JSScript *script, jsbytecode *pc, Type type)
 {
     JS_ASSERT(cx->typeInferenceEnabled());
     AutoEnterTypeInference enter(cx);
 
     UntrapOpcode untrap(cx, script, pc);
 
     /* Directly update associated type sets for applicable bytecodes. */
     if (js_CodeSpec[*pc].format & JOF_TYPESET) {
-        if (!script->ensureRanBytecode(cx)) {
+        if (!script->ensureRanAnalysis(cx)) {
             cx->compartment->types.setPendingNukeTypes(cx);
             return;
         }
         TypeSet *types = script->analysis()->bytecodeTypes(pc);
         if (!types->hasType(type)) {
             InferSpew(ISpewOps, "externalType: monitorResult #%u:%05u: %s",
                       script->id(), pc - script->code, TypeString(type));
             types->addType(cx, type);
@@ -4803,31 +5020,264 @@ TypeMonitorResult(JSContext *cx, JSScrip
     UntrapOpcode untrap(cx, script, pc);
 
     /* Allow the non-TYPESET scenario to simplify stubs used in compound opcodes. */
     if (!(js_CodeSpec[*pc].format & JOF_TYPESET))
         return;
 
     AutoEnterTypeInference enter(cx);
 
-    if (!script->ensureRanBytecode(cx)) {
+    if (!script->ensureRanAnalysis(cx)) {
         cx->compartment->types.setPendingNukeTypes(cx);
         return;
     }
 
     Type type = GetValueType(cx, rval);
     TypeSet *types = script->analysis()->bytecodeTypes(pc);
     if (types->hasType(type))
         return;
 
     InferSpew(ISpewOps, "bytecodeType: #%u:%05u: %s",
               script->id(), pc - script->code, TypeString(type));
     types->addType(cx, type);
 }
 
+bool
+TypeScript::SetScope(JSContext *cx, JSScript *script, JSObject *scope)
+{
+    JS_ASSERT(script->types && !script->types->hasScope());
+
+    JSFunction *fun = script->types->function;
+
+    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);
+
+    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();
+
+    if (!cx->typeInferenceEnabled())
+        return true;
+
+    if (!script->isInnerFunction || fun->isNullClosure()) {
+        /*
+         * Outermost functions need nesting information if there are inner
+         * functions directly nested in them.
+         */
+        if (script->isOuterFunction) {
+            script->types->nesting = cx->new_<TypeScriptNesting>();
+            if (!script->types->nesting)
+                return false;
+        }
+        return true;
+    }
+
+    /*
+     * 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();
+
+    /* The isInnerFunction test ensures there is no intervening strict eval call object. */
+    JS_ASSERT(!scope->callIsForEval());
+
+    /* Don't track non-heavyweight parents, NAME ops won't reach into them. */
+    JSFunction *parentFun = scope->getCallObjCalleeFunction();
+    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
+     * analyzing the script's types, which we don't want to do yet. The nesting
+     * info we make here may get pruned if/when we eventually do such analysis.
+     */
+
+    /*
+     * Scopes are set when scripts first execute, and the parent script must
+     * have executed first. It is still possible for the parent script to not
+     * have a scope, however, as we occasionally purge all TypeScripts from the
+     * compartment and there may be inner function objects parented to an
+     * activation of the outer function sticking around. In such cases, treat
+     * the parent's call object as the most recent one, so that it is not
+     * 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();
+    }
+
+    JS_ASSERT(!script->types->nesting);
+
+    /* Construct and link nesting information for the two functions. */
+
+    script->types->nesting = cx->new_<TypeScriptNesting>();
+    if (!script->types->nesting)
+        return false;
+
+    script->nesting()->parent = parent;
+    script->nesting()->next = parent->nesting()->children;
+    parent->nesting()->children = script;
+
+    return true;
+}
+
+TypeScriptNesting::~TypeScriptNesting()
+{
+    /*
+     * Unlink from any parent/child. Nesting info on a script does not keep
+     * either the parent or children live during GC.
+     */
+
+    if (parent) {
+        JSScript **pscript = &parent->nesting()->children;
+        while ((*pscript)->nesting() != this)
+            pscript = &(*pscript)->nesting()->next;
+        *pscript = next;
+    }
+
+    while (children) {
+        TypeScriptNesting *child = children->nesting();
+        children = child->next;
+        child->parent = NULL;
+        child->next = NULL;
+    }
+}
+
+bool
+ClearActiveNesting(JSScript *start)
+{
+    /*
+     * Clear active call information for script and any outer functions
+     * inner to it. Return false if an inner function has frames on the stack.
+     */
+
+    /* Traverse children, then parent, avoiding recursion. */
+    JSScript *script = start;
+    bool traverseChildren = true;
+    while (true) {
+        TypeScriptNesting *nesting = script->nesting();
+        if (nesting->children && traverseChildren) {
+            script = nesting->children;
+            continue;
+        }
+        if (nesting->activeFrames)
+            return false;
+        if (script->isOuterFunction) {
+            nesting->activeCall = NULL;
+            nesting->argArray = NULL;
+            nesting->varArray = NULL;
+        }
+        if (script == start)
+            break;
+        if (nesting->next) {
+            script = nesting->next;
+            traverseChildren = true;
+        } else {
+            script = nesting->parent;
+            traverseChildren = false;
+        }
+    }
+
+    return true;
+}
+
+/*
+ * For the specified scope and script with an outer function, check if the
+ * scope represents a reentrant activation on an inner function of the parent
+ * or any of its transitive parents.
+ */
+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)
+        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.
+         * We don't need to check this in for non-reentrant calls on the outer
+         * function: when we entered any outer function to the immediate parent
+         * we cleared the active call for its transitive children, so a
+         * non-reentrant call on a child is also a non-reentrant call on the
+         * parent.
+         */
+        if (parent->nesting()->parent) {
+            scope = scope->getParent();
+            script = parent;
+            goto restart;
+        }
+    }
+}
+
+void
+NestingPrologue(JSContext *cx, StackFrame *fp)
+{
+    JSScript *script = fp->fun()->script();
+    TypeScriptNesting *nesting = script->nesting();
+
+    if (nesting->parent)
+        CheckNestingParent(cx, &fp->scopeChain(), script);
+
+    if (script->isOuterFunction) {
+        /*
+         * Check the stack has no frames for this activation, any of its inner
+         * functions or any of their transitive inner functions.
+         */
+        if (!ClearActiveNesting(script)) {
+            script->reentrantOuterFunction = true;
+            MarkTypeObjectFlags(cx, fp->fun(), OBJECT_FLAG_REENTRANT_FUNCTION);
+        }
+
+        nesting->activeCall = &fp->callObj();
+        nesting->argArray = fp->formalArgs();
+        nesting->varArray = fp->slots();
+    }
+
+    /* Maintain stack frame count for the function. */
+    nesting->activeFrames++;
+}
+
+void
+NestingEpilogue(StackFrame *fp)
+{
+    JSScript *script = fp->fun()->script();
+    TypeScriptNesting *nesting = script->nesting();
+
+    JS_ASSERT(nesting->activeFrames != 0);
+    nesting->activeFrames--;
+}
+
 } } /* namespace js::types */
 
 /////////////////////////////////////////////////////////////////////
 // TypeScript
 /////////////////////////////////////////////////////////////////////
 
 /*
  * Returns true if we don't expect to compute the correct types for some value
@@ -4901,34 +5351,42 @@ IgnorePushed(const jsbytecode *pc, unsig
         return JSOp(pc[JSOP_GETLOCAL_LENGTH]) == JSOP_POP;
 
       default:
         return false;
     }
 }
 
 bool
-JSScript::makeTypes(JSContext *cx)
+JSScript::makeTypes(JSContext *cx, JSFunction *fun)
 {
     JS_ASSERT(!types);
+    JS_ASSERT(hasFunction == (fun != NULL));
 
     if (!cx->typeInferenceEnabled()) {
         types = (TypeScript *) cx->calloc_(sizeof(TypeScript));
-        return types != NULL;
+        if (!types)
+            return false;
+        new(types) TypeScript(fun);
+        return true;
     }
 
     AutoEnterTypeInference enter(cx);
 
-    unsigned count = TypeScript::NumTypeSets(this);
+    /* Open code for NumTypeSets since the types are not filled in yet. */
+    unsigned count = 2 + (fun ? fun->nargs : 0) + nfixed + nTypeSets;
+
     types = (TypeScript *) cx->calloc_(sizeof(TypeScript) + (sizeof(TypeSet) * count));
     if (!types) {
         cx->compartment->types.setPendingNukeTypes(cx);
         return false;
     }
 
+    new(types) TypeScript(fun);
+
 #ifdef DEBUG
     TypeSet *typeArray = types->typeArray();
     for (unsigned i = 0; i < nTypeSets; i++)
         InferSpew(ISpewOps, "typeSet: %sT%p%s bytecode%u #%u",
                   InferSpewColor(&typeArray[i]), &typeArray[i], InferSpewColorReset(),
                   i, id());
     TypeSet *returnTypes = TypeScript::ReturnTypes(this);
     InferSpew(ISpewOps, "typeSet: %sT%p%s return #%u",
@@ -4977,32 +5435,33 @@ JSScript::makeAnalysis(JSContext *cx)
 
     return true;
 }
 
 bool
 JSScript::typeSetFunction(JSContext *cx, JSFunction *fun, bool singleton)
 {
     hasFunction = true;
-    where.fun = fun;
+    if (fun->isHeavyweight())
+        isHeavyweightFunction = true;
 
     if (!cx->typeInferenceEnabled())
         return true;
 
     if (singleton) {
         if (!fun->setSingletonType(cx))
             return false;
     } else {
         TypeObject *type = cx->compartment->types.newTypeObject(cx, this,
                                                                 JSProto_Function, fun->getProto());
         if (!type)
             return false;
 
         fun->setType(type);
-        type->functionScript = this;
+        type->interpretedFunction = fun;
     }
 
     return true;
 }
 
 #ifdef DEBUG
 
 /* static */ void
@@ -5125,21 +5584,24 @@ JSObject::makeLazyType(JSContext *cx)
         return;
     }
 
     /* Fill in the type according to the state of this object. */
 
     type->singleton = this;
 
     if (isFunction() && getFunctionPrivate() && getFunctionPrivate()->isInterpreted()) {
-        type->functionScript = getFunctionPrivate()->script();
-        if (type->functionScript->uninlineable)
+        type->interpretedFunction = getFunctionPrivate();
+        JSScript *script = type->interpretedFunction->script();
+        if (script->createdArgs)
+            type->flags |= OBJECT_FLAG_CREATED_ARGUMENTS;
+        if (script->uninlineable)
             type->flags |= OBJECT_FLAG_UNINLINEABLE;
-        if (type->functionScript->createdArgs)
-            type->flags |= OBJECT_FLAG_CREATED_ARGUMENTS;
+        if (script->reentrantOuterFunction)
+            type->flags |= OBJECT_FLAG_REENTRANT_FUNCTION;
     }
 
     if (flags & ITERATED)
         type->flags |= OBJECT_FLAG_ITERATED;
 
 #if JS_HAS_XML_SUPPORT
     /*
      * XML objects do not have equality hooks but are treated special by EQ/NE
@@ -5163,17 +5625,17 @@ JSObject::makeLazyType(JSContext *cx)
                 |  OBJECT_FLAG_NON_PACKED_ARRAY
                 |  OBJECT_FLAG_NON_TYPED_ARRAY;
 
     type_ = type;
     flags &= ~LAZY_TYPE;
 }
 
 void
-JSObject::makeNewType(JSContext *cx, JSScript *newScript, bool unknown)
+JSObject::makeNewType(JSContext *cx, JSFunction *fun, bool unknown)
 {
     JS_ASSERT(!newType);
 
     TypeObject *type = cx->compartment->types.newTypeObject(cx, NULL,
                                                             JSProto_Object, this, unknown);
     if (!type)
         return;
 
@@ -5188,18 +5650,18 @@ JSObject::makeNewType(JSContext *cx, JSS
     /*
      * Set the special equality flag for types whose prototype also has the
      * flag set. This is a hack, :XXX: need a real correspondence between
      * types and the possible js::Class of objects with that type.
      */
     if (hasSpecialEquality())
         type->flags |= OBJECT_FLAG_SPECIAL_EQUALITY;
 
-    if (newScript)
-        CheckNewScriptProperties(cx, type, newScript);
+    if (fun)
+        CheckNewScriptProperties(cx, type, fun);
 
 #if JS_HAS_XML_SUPPORT
     /* Special case for XML object equality, see makeLazyType(). */
     if (isXML() && !type->unknownProperties())
         type->flags |= OBJECT_FLAG_UNKNOWN_MASK;
 #endif
 
     if (clasp->ext.equality)
@@ -5515,41 +5977,44 @@ TypeCompartment::~TypeCompartment()
 TypeScript::Sweep(JSContext *cx, JSScript *script)
 {
     JSCompartment *compartment = script->compartment();
     JS_ASSERT(compartment->types.inferenceEnabled);
 
     unsigned num = NumTypeSets(script);
     TypeSet *typeArray = script->types->typeArray();
 
-    if (IsAboutToBeFinalized(cx, script)) {
-        /* Release all memory associated with the persistent type sets. */
-        for (unsigned i = 0; i < num; i++)
-            typeArray[i].clearObjects();
-    } else {
-        /* Remove constraints and references to dead objects from the persistent type sets. */
-        for (unsigned i = 0; i < num; i++)
-            typeArray[i].sweep(cx, compartment);
-    }
+    /* Remove constraints and references to dead objects from the persistent type sets. */
+    for (unsigned i = 0; i < num; i++)
+        typeArray[i].sweep(cx, compartment);
 
     TypeResult **presult = &script->types->dynamicList;
     while (*presult) {
         TypeResult *result = *presult;
         Type type = result->type;
 
         if (!type.isUnknown() && !type.isAnyObject() && type.isObject() &&
             IsAboutToBeFinalized(cx, type.objectKey())) {
             *presult = result->next;
             cx->delete_(result);
         } else {
             presult = &result->next;
         }
     }
 
     /*
+     * If the script has nesting state with a most recent activation, we do not
+     * need either to mark the call object or clear it if not live. Even with
+     * a dead pointer in the nesting, we can't get a spurious match while
+     * testing for reentrancy: if previous activations are still live, they
+     * cannot alias the most recent one, and future activations will overwrite
+     * activeCall on creation.
+     */
+
+    /*
      * Method JIT code depends on the type inference data which is about to
      * be purged, so purge the jitcode as well.
      */
 #ifdef JS_METHODJIT
     mjit::ReleaseScriptCode(cx, script);
 #endif
 }
 
@@ -5557,16 +6022,19 @@ void
 TypeScript::destroy()
 {
     while (dynamicList) {
         TypeResult *next = dynamicList->next;
         Foreground::delete_(dynamicList);
         dynamicList = next;
     }
 
+    if (nesting)
+        Foreground::delete_(nesting);
+
     Foreground::free_(this);
 }
 
 inline size_t
 TypeSet::dynamicSize()
 {
     /* Get the amount of memory allocated from the analysis pool for this set. */
     uint32 count = baseObjectCount();
--- a/js/src/jsinfer.h
+++ b/js/src/jsinfer.h
@@ -50,16 +50,17 @@
 #include "jsvalue.h"
 #include "jshashtable.h"
 
 namespace js {
     class CallArgs;
     namespace analyze {
         class ScriptAnalysis;
     }
+    struct GlobalObject;
 }
 
 namespace js {
 namespace types {
 
 /* Forward declarations. */
 class TypeSet;
 struct TypeCallsite;
@@ -306,47 +307,50 @@ enum {
 
     /* Mask/shift for the number of properties in propertySet */
     OBJECT_FLAG_PROPERTY_COUNT_MASK   = 0xfff0,
     OBJECT_FLAG_PROPERTY_COUNT_SHIFT  = 4,
     OBJECT_FLAG_PROPERTY_COUNT_LIMIT  =
         OBJECT_FLAG_PROPERTY_COUNT_MASK >> OBJECT_FLAG_PROPERTY_COUNT_SHIFT,
 
     /*
-     * Whether any objects this represents are not dense arrays. This also
-     * includes dense arrays whose length property does not fit in an int32.
+     * Some objects are not dense arrays, or are dense arrays whose length
+     * property does not fit in an int32.
      */
-    OBJECT_FLAG_NON_DENSE_ARRAY       = 0x010000,
+    OBJECT_FLAG_NON_DENSE_ARRAY       = 0x0010000,
 
     /* Whether any objects this represents are not packed arrays. */
-    OBJECT_FLAG_NON_PACKED_ARRAY      = 0x020000,
+    OBJECT_FLAG_NON_PACKED_ARRAY      = 0x0020000,
 
     /* Whether any objects this represents are not typed arrays. */
-    OBJECT_FLAG_NON_TYPED_ARRAY       = 0x040000,
+    OBJECT_FLAG_NON_TYPED_ARRAY       = 0x0040000,
 
     /* Whether any represented script has had arguments objects created. */
-    OBJECT_FLAG_CREATED_ARGUMENTS     = 0x080000,
+    OBJECT_FLAG_CREATED_ARGUMENTS     = 0x0080000,
 
     /* Whether any represented script is considered uninlineable. */
-    OBJECT_FLAG_UNINLINEABLE          = 0x100000,
+    OBJECT_FLAG_UNINLINEABLE          = 0x0100000,
 
     /* Whether any objects have an equality hook. */
-    OBJECT_FLAG_SPECIAL_EQUALITY      = 0x200000,
+    OBJECT_FLAG_SPECIAL_EQUALITY      = 0x0200000,
 
     /* Whether any objects have been iterated over. */
-    OBJECT_FLAG_ITERATED              = 0x400000,
+    OBJECT_FLAG_ITERATED              = 0x0400000,
+
+    /* Outer function which has been marked reentrant. */
+    OBJECT_FLAG_REENTRANT_FUNCTION    = 0x0800000,
 
     /* Flags which indicate dynamic properties of represented objects. */
-    OBJECT_FLAG_DYNAMIC_MASK          = 0x7f0000,
+    OBJECT_FLAG_DYNAMIC_MASK          = 0x0ff0000,
 
     /*
      * Whether all properties of this object are considered unknown.
      * If set, all flags in DYNAMIC_MASK will also be set.
      */
-    OBJECT_FLAG_UNKNOWN_PROPERTIES    = 0x800000,
+    OBJECT_FLAG_UNKNOWN_PROPERTIES    = 0x1000000,
 
     /* Mask for objects created with unknown properties. */
     OBJECT_FLAG_UNKNOWN_MASK =
         OBJECT_FLAG_DYNAMIC_MASK
       | OBJECT_FLAG_UNKNOWN_PROPERTIES
       | OBJECT_FLAG_SETS_MARKED_UNKNOWN
 };
 typedef uint32 TypeObjectFlags;
@@ -424,31 +428,37 @@ class TypeSet
     void setDefinite(unsigned slot) {
         JS_ASSERT(slot <= (TYPE_FLAG_DEFINITE_MASK >> TYPE_FLAG_DEFINITE_SHIFT));
         flags |= TYPE_FLAG_DEFINITE_PROPERTY | (slot << TYPE_FLAG_DEFINITE_SHIFT);
     }
 
     bool hasPropagatedProperty() { return !!(flags & TYPE_FLAG_PROPAGATED_PROPERTY); }
     void setPropagatedProperty() { flags |= TYPE_FLAG_PROPAGATED_PROPERTY; }
 
+    enum FilterKind {
+        FILTER_ALL_PRIMITIVES,
+        FILTER_NULL_VOID,
+        FILTER_VOID
+    };
+
     /* Add specific kinds of constraints to this set. */
     inline void add(JSContext *cx, TypeConstraint *constraint, bool callExisting = true);
     void addSubset(JSContext *cx, TypeSet *target);
     void addGetProperty(JSContext *cx, JSScript *script, jsbytecode *pc,
                         TypeSet *target, jsid id);
     void addSetProperty(JSContext *cx, JSScript *script, jsbytecode *pc,
                         TypeSet *target, jsid id);
     void addCallProperty(JSContext *cx, JSScript *script, jsbytecode *pc, jsid id);
     void addSetElement(JSContext *cx, JSScript *script, jsbytecode *pc,
                        TypeSet *objectTypes, TypeSet *valueTypes);
     void addCall(JSContext *cx, TypeCallsite *site);
     void addArith(JSContext *cx, TypeSet *target, TypeSet *other = NULL);
     void addTransformThis(JSContext *cx, JSScript *script, TypeSet *target);
     void addPropagateThis(JSContext *cx, JSScript *script, jsbytecode *pc, Type type);
-    void addFilterPrimitives(JSContext *cx, TypeSet *target, bool onlyNullVoid);
+    void addFilterPrimitives(JSContext *cx, TypeSet *target, FilterKind filter);
     void addSubsetBarrier(JSContext *cx, JSScript *script, jsbytecode *pc, TypeSet *target);
     void addLazyArguments(JSContext *cx, TypeSet *target);
 
     /*
      * Make an type set with the specified debugging name, not embedded in
      * another structure.
      */
     static TypeSet *make(JSContext *cx, const char *name);
@@ -495,16 +505,19 @@ class TypeSet
      * Get the typed array type of all objects in this set. Returns
      * TypedArray::TYPE_MAX if the set contains different array types.
      */
     int getTypedArrayType(JSContext *cx);
 
     /* Get the single value which can appear in this type set, otherwise NULL. */
     JSObject *getSingleton(JSContext *cx, bool freeze = true);
 
+    /* Whether all objects in this set are parented to a particular global. */
+    bool hasGlobalObject(JSContext *cx, JSObject *global);
+
     inline void clearObjects();
 
   private:
     uint32 baseObjectCount() const {
         return (flags & TYPE_FLAG_OBJECT_COUNT_MASK) >> TYPE_FLAG_OBJECT_COUNT_SHIFT;
     }
     inline void setBaseObjectCount(uint32 count);
 };
@@ -639,17 +652,17 @@ struct Property
  * information which could change as the script executes (e.g. a scripted
  * setter is added to a prototype object), and we need to ensure both that the
  * appropriate type constraints are in place when necessary, and that we can
  * remove the definite property information and repair the JS stack if the
  * constraints are violated.
  */
 struct TypeNewScript
 {
-    JSScript *script;
+    JSFunction *fun;
 
     /* Allocation kind to use for newly constructed objects. */
     gc::AllocKind allocKind;
 
     /*
      * Shape to use for newly constructed objects. Reflects all definite
      * properties the object will have.
      */
@@ -771,18 +784,18 @@ struct TypeObject : gc::Cell
      *    or deletion.
      *
      * We establish these by using write barriers on calls to setProperty and
      * defineProperty which are on native properties, and by using the inference
      * analysis to determine the side effects of code which is JIT-compiled.
      */
     Property **propertySet;
 
-    /* If this is an interpreted function, the corresponding script. */
-    JSScript *functionScript;
+    /* If this is an interpreted function, the function object. */
+    JSFunction *interpretedFunction;
 
     inline TypeObject(JSObject *proto, bool isFunction, bool unknown);
 
     bool isFunction() { return !!(flags & OBJECT_FLAG_FUNCTION); }
 
     bool hasAnyFlags(TypeObjectFlags flags) {
         JS_ASSERT((flags & OBJECT_FLAG_DYNAMIC_MASK) == flags);
         return !!(this->flags & flags);
@@ -820,16 +833,22 @@ struct TypeObject : gc::Cell
     inline TypeSet *maybeGetProperty(JSContext *cx, jsid id);
 
     inline unsigned getPropertyCount();
     inline Property *getProperty(unsigned i);
 
     /* Set flags on this object which are implied by the specified key. */
     inline void setFlagsFromKey(JSContext *cx, JSProtoKey kind);
 
+    /*
+     * Get the global object which all objects of this type are parented to,
+     * or NULL if there is none known.
+     */
+    inline JSObject *getGlobal();
+
     /* Helpers */
 
     bool addProperty(JSContext *cx, jsid id, Property **pprop);
     bool addDefiniteProperties(JSContext *cx, JSObject *obj);
     bool matchDefiniteProperties(JSObject *obj);
     void addPrototype(JSContext *cx, TypeObject *proto);
     void addPropertyType(JSContext *cx, jsid id, Type type);
     void addPropertyType(JSContext *cx, jsid id, const Value &value);
@@ -897,29 +916,141 @@ struct TypeCallsite
 
     /* Type set receiving the return value of this call. */
     TypeSet *returnTypes;
 
     inline TypeCallsite(JSContext *cx, JSScript *script, jsbytecode *pc,
                         bool isNew, unsigned argumentCount);
 };
 
+/*
+ * Information attached to outer and inner function scripts nested in one