Merge services-central and mozilla-central
authorPhilipp von Weitershausen <philipp@weitershausen.de>
Thu, 08 Sep 2011 15:32:54 -0700
changeset 78063 41a6dc9025cb67e258aa2cb9f2238d4a9ae98873
parent 78062 05c913f50c3e967da2acdcceb13013795627114c (current diff)
parent 78051 817c2b9dc11d7d39d91cd1f376e673cb87dc9b77 (diff)
child 78080 b57d50c6c0469330e0a4c9c460203c644f64f820
child 78563 42cd2123ad10059497fc1dcf88a1ac6dfcf5def7
child 112067 ab38a3d96333092b9356bb53cc2b03297cf22c8e
push id78
push userclegnitto@mozilla.com
push dateFri, 16 Dec 2011 17:32:24 +0000
treeherdermozilla-release@79d24e644fdd [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone9.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge 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