Merge services-central with mozilla-central
authorPhilipp von Weitershausen <philipp@weitershausen.de>
Tue, 02 Aug 2011 12:01:42 -0700
changeset 74460 aca5afbed1883d081218aeb1d99c6f6ef5cfa2ba
parent 74459 822ae9ffa97eac490b409f9bb70caa645ad738e8 (current diff)
parent 74451 f21f3fafab5b5224defa1b7e907b63be2135e1d7 (diff)
child 74461 f185f48d35dc966aff08536b6c599319731271a9
child 74839 70994f9acb3a53636e70d1c3ebf109d9cf57ba98
child 76570 0ecd5149132ccd658fa372f95f51c1f244ec2f50
push id235
push userbzbarsky@mozilla.com
push dateTue, 27 Sep 2011 17:13:04 +0000
treeherdermozilla-beta@2d1e082d176a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone8.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge services-central with mozilla-central
--- a/browser/base/content/browser-fullZoom.js
+++ b/browser/base/content/browser-fullZoom.js
@@ -257,17 +257,19 @@ var FullZoom = {
 
     if (Services.contentPrefs.hasCachedPref(aURI, this.name)) {
       let zoomValue = Services.contentPrefs.getPref(aURI, this.name);
       this._applyPrefToSetting(zoomValue, browser);
     } else {
       var self = this;
       Services.contentPrefs.getPref(aURI, this.name, function (aResult) {
         // Check that we're still where we expect to be in case this took a while.
-        if (aURI.equals(browser.currentURI)) {
+        // Null check currentURI, since the window may have been destroyed before
+        // we were called.
+        if (browser.currentURI && aURI.equals(browser.currentURI)) {
           self._applyPrefToSetting(aResult, browser);
         }
       });
     }
   },
 
   // update state of zoom type menu item
 
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -3814,18 +3814,18 @@
           return;
 
 #ifdef XP_MACOSX
         if (event.altKey) {
 #else
         if (event.ctrlKey) {
 #endif
           let dt = event.dataTransfer;
-          let spec = this.tabbrowser.getBrowserForTab(tab).currentURI.spec;
-          dt.setData("text/x-moz-url", spec);
+          let browser = tab.linkedBrowser;
+          dt.setData("text/x-moz-url", browser.currentURI.spec + "\n" + browser.contentTitle);
           let favicon = document.getAnonymousElementByAttribute(tab, "class", "tab-icon-image");
           dt.setDragImage(favicon, 16, 16);
           return;
         }
 
         this.setAttribute("drag", "move");
         this.draggedTab = tab;
         tab.setAttribute("dragged", "true");
--- a/browser/components/places/content/controller.js
+++ b/browser/components/places/content/controller.js
@@ -133,18 +133,17 @@ PlacesController.prototype = {
   ]),
 
   // nsIClipboardOwner
   LosingOwnership: function PC_LosingOwnership (aXferable) {
     this.cutNodes = [];
   },
 
   terminate: function PC_terminate() {
-    if (this._cutNodes.length > 0)
-      this._clearClipboard();
+    this._releaseClipboardOwnership();
   },
 
   supportsCommand: function PC_supportsCommand(aCommand) {
     //LOG("supportsCommand: " + command);
     // Non-Places specific commands that we also support
     switch (aCommand) {
     case "cmd_undo":
     case "cmd_redo":
@@ -1123,24 +1122,30 @@ PlacesController.prototype = {
     // instances should instead be handled as copies (The sources are not
     // available for this instance).
     if (action == "cut" && actionOwner != this.profileName)
       action = "copy";
 
     return action;
   },
 
+  _releaseClipboardOwnership: function PC__releaseClipboardOwnership() {
+    if (this.cutNodes.length > 0) {
+      // This clears the logical clipboard, doesn't remove data.
+      this.clipboard.emptyClipboard(Ci.nsIClipboard.kGlobalClipboard);
+    }
+  },
+
   _clearClipboard: function PC__clearClipboard() {
-    this.clipboard.emptyClipboard(Ci.nsIClipboard.kGlobalClipboard);
-    // Unfortunately just invoking emptyClipboard is not enough, since it
-    // does not act on the native clipboard.
     let xferable = Cc["@mozilla.org/widget/transferable;1"].
                    createInstance(Ci.nsITransferable);
-    // GTK doesn't like empty transferables, so just add an unknown type.
-    xferable.addDataFlavor("text/x-moz-place-empty");
+    // Empty transferables may cause crashes, so just add an unknown type.
+    const TYPE = "text/x-moz-place-empty";
+    xferable.addDataFlavor(TYPE);
+    xferable.setTransferData(TYPE, PlacesUtils.toISupportsString(""), 0);
     this.clipboard.setData(xferable, null, Ci.nsIClipboard.kGlobalClipboard);
   },
 
   _populateClipboard: function PC__populateClipboard(aNodes, aAction) {
     // This order is _important_! It controls how this and other applications
     // select data to be inserted based on type.
     let contents = [
       { type: PlacesUtils.TYPE_X_MOZ_PLACE, entries: [] },
@@ -1190,21 +1195,25 @@ PlacesController.prototype = {
     });
 
     // Track the exected action in the xferable.  This must be the last flavor
     // since it's the least preferred one.
     // Enqueue a unique instance identifier to distinguish operations across
     // concurrent instances of the application.
     addData(PlacesUtils.TYPE_X_MOZ_PLACE_ACTION, aAction + "," + this.profileName);
 
-    if (hasData)
-      this.clipboard.setData(xferable, this, Ci.nsIClipboard.kGlobalClipboard);
+    if (hasData) {
+      this.clipboard.setData(xferable,
+                             this.cutNodes.length > 0 ? this : null,
+                             Ci.nsIClipboard.kGlobalClipboard);
+    }
   },
 
   _cutNodes: [],
+  get cutNodes() this._cutNodes,
   set cutNodes(aNodes) {
     let self = this;
     function updateCutNodes(aValue) {
       self._cutNodes.forEach(function (aNode) {
         self._view.toggleCutNode(aNode, aValue);
       });
     }
 
--- a/browser/components/places/tests/browser/browser_410196_paste_into_tags.js
+++ b/browser/components/places/tests/browser/browser_410196_paste_into_tags.js
@@ -39,29 +39,30 @@ function onLibraryReady() {
   tests.focusTag();
   waitForClipboard(function(aData) !!aData,
                    tests.copyHistNode,
                    onClipboardReady,
                    PlacesUtils.TYPE_X_MOZ_PLACE);
 }
 
 function onClipboardReady() {
-  tests.pasteToTag();
+  tests.focusTag();
+  PlacesOrganizer._places.controller.paste();
   tests.historyNode();
   tests.checkForBookmarkInUI();
 
   gLibrary.close();
 
   // Remove new Places data we created.
   PlacesUtils.tagging.untagURI(NetUtil.newURI(MOZURISPEC), ["foo"]);
   PlacesUtils.tagging.untagURI(NetUtil.newURI(TEST_URL), ["foo"]);
   let tags = PlacesUtils.tagging.getTagsForURI(NetUtil.newURI(TEST_URL));
   is(tags.length, 0, "tags are gone");
   PlacesUtils.bookmarks.removeFolderChildren(PlacesUtils.unfiledBookmarksFolderId);
-  
+
   waitForClearHistory(finish);
 }
 
 let tests = {
 
   makeHistVisit: function() {
     // need to add a history object
     let testURI1 = NetUtil.newURI(MOZURISPEC);
@@ -75,55 +76,44 @@ let tests = {
     // create an initial tag to work with
     let bmId = add_bookmark(NetUtil.newURI(TEST_URL));
     ok(bmId > 0, "A bookmark was added");
     PlacesUtils.tagging.tagURI(NetUtil.newURI(TEST_URL), ["foo"]);
     let tags = PlacesUtils.tagging.getTagsForURI(NetUtil.newURI(TEST_URL));
     is(tags[0], 'foo', "tag is foo");
   },
 
-  focusTag: function (paste){
+  focusTag: function (){
     // focus the new tag
     PlacesOrganizer.selectLeftPaneQuery("Tags");
     let tags = PlacesOrganizer._places.selectedNode;
     tags.containerOpen = true;
     let fooTag = tags.getChild(0);
-    this.tagNode = fooTag;
+    let tagNode = fooTag;
     PlacesOrganizer._places.selectNode(fooTag);
-    is(this.tagNode.title, 'foo', "tagNode title is foo");
+    is(tagNode.title, 'foo', "tagNode title is foo");
     let ip = PlacesOrganizer._places.insertionPoint;
     ok(ip.isTag, "IP is a tag");
-    if (paste) {
-      ok(true, "About to paste");
-      PlacesOrganizer._places.controller.paste();
-    }
   },
 
-  histNode: null,
-
   copyHistNode: function (){
     // focus the history object
     PlacesOrganizer.selectLeftPaneQuery("History");
     let histContainer = PlacesOrganizer._places.selectedNode;
     PlacesUtils.asContainer(histContainer);
     histContainer.containerOpen = true;
     PlacesOrganizer._places.selectNode(histContainer.getChild(0));
-    this.histNode = PlacesOrganizer._content.view.nodeForTreeIndex(0);
-    PlacesOrganizer._content.selectNode(this.histNode);
-    is(this.histNode.uri, MOZURISPEC,
-       "historyNode exists: " + this.histNode.uri);
+    let histNode = PlacesOrganizer._content.view.nodeForTreeIndex(0);
+    PlacesOrganizer._content.selectNode(histNode);
+    is(histNode.uri, MOZURISPEC,
+       "historyNode exists: " + histNode.uri);
     // copy the history node
     PlacesOrganizer._content.controller.copy();
   },
 
-  pasteToTag: function (){
-    // paste history node into tag
-    this.focusTag(true);
-  },
-
   historyNode: function (){
     // re-focus the history again
     PlacesOrganizer.selectLeftPaneQuery("History");
     let histContainer = PlacesOrganizer._places.selectedNode;
     PlacesUtils.asContainer(histContainer);
     histContainer.containerOpen = true;
     PlacesOrganizer._places.selectNode(histContainer.getChild(0));
     let histNode = PlacesOrganizer._content.view.nodeForTreeIndex(0);
@@ -143,18 +133,16 @@ let tests = {
     // is the bookmark visible in the UI?
     // get the Unsorted Bookmarks node
     PlacesOrganizer.selectLeftPaneQuery("UnfiledBookmarks");
     // now we can see what is in the _content tree
     let unsortedNode = PlacesOrganizer._content.view.nodeForTreeIndex(1);
     ok(unsortedNode, "unsortedNode is not null: " + unsortedNode.uri);
     is(unsortedNode.uri, MOZURISPEC, "node uri's are the same");
   },
-
-  tagNode: null,
 };
 
 /**
  * Clears history invoking callback when done.
  */
 function waitForClearHistory(aCallback) {
   const TOPIC_EXPIRATION_FINISHED = "places-expiration-finished";
   let observer = {
--- a/browser/components/sessionstore/src/nsSessionStore.js
+++ b/browser/components/sessionstore/src/nsSessionStore.js
@@ -635,25 +635,26 @@ SessionStoreService.prototype = {
       case "enter":
         this._inPrivateBrowsing = true;
         break;
       case "exit":
         aSubject.QueryInterface(Ci.nsISupportsPRBool);
         let quitting = aSubject.data;
         if (quitting) {
           // save the backed up state with session set to stopped,
-          // otherwise resuming next time would look like a crash
+          // otherwise resuming next time would look like a crash.
+          // Whether we restore the session upon resume will be determined by the
+          // usual startup prefs, so we will have the same behavior regardless of
+          // whether the browser was closed while in normal or private browsing mode.
           if ("_stateBackup" in this) {
             var oState = this._stateBackup;
             oState.session = { state: STATE_STOPPED_STR };
 
             this._saveStateObject(oState);
           }
-          // make sure to restore the non-private session upon resuming
-          this._prefBranch.setBoolPref("sessionstore.resume_session_once", true);
         }
         else
           this._inPrivateBrowsing = false;
         delete this._stateBackup;
         break;
       }
 
       this._clearRestoringWindows();
@@ -1907,17 +1908,25 @@ SessionStoreService.prototype = {
    *        the tab is pinned and should be treated differently for privacy
    */
   _serializeSessionStorage:
     function sss_serializeSessionStorage(aTabData, aHistory, aDocShell, aFullData, aIsPinned) {
     let storageData = {};
     let hasContent = false;
 
     for (let i = 0; i < aHistory.count; i++) {
-      let uri = aHistory.getEntryAtIndex(i, false).URI;
+      let uri;
+      try {
+        uri = aHistory.getEntryAtIndex(i, false).URI;
+      }
+      catch (ex) {
+        // Chances are that this is getEntryAtIndex throwing, as seen in bug 669196.
+        // We've already asserted in _collectTabData, so we won't show that again.
+        continue;
+      }
       // sessionStorage is saved per origin (cf. nsDocShell::GetSessionStorageForURI)
       let domain = uri.spec;
       try {
         if (uri.host)
           domain = uri.prePath;
       }
       catch (ex) { /* this throws for host-less URIs (such as about: or jar:) */ }
       if (storageData[domain] ||
--- a/build/autoconf/mozconfig-find
+++ b/build/autoconf/mozconfig-find
@@ -41,33 +41,27 @@
 #    command-line. The .mozconfig file is searched for in the 
 #    order:
 #       if $MOZCONFIG is set, use that.
 #       Otherwise, use $TOPSRCDIR/.mozconfig
 #       Otherwise, use $HOME/.mozconfig
 #
 topsrcdir=$1
 
-absolute_path() {
-  if [ -n "${1%%/*}" ]; then
-    echo $topsrcdir/$1
-  else
-    echo $1
-  fi
-}
-
-if [ -n "$MOZCONFIG" ]; then
-  MOZCONFIG=`absolute_path "$MOZCONFIG"`
-  if ! [ -f "$MOZCONFIG" ]; then
-    echo "Specified MOZCONFIG \"$MOZCONFIG\" does not exist!"
+for _config in "$MOZCONFIG" \
+               "$MOZ_MYCONFIG"
+do
+  if [ -n "$_config" ] && ! [ -f "$_config" ]; then
+    echo "Specified MOZCONFIG \"$_config\" does not exist!"
     exit 1
   fi
-fi
+done
 
 for _config in "$MOZCONFIG" \
+               "$MOZ_MYCONFIG" \
                "$topsrcdir/.mozconfig" \
                "$topsrcdir/mozconfig" \
                "$topsrcdir/mozconfig.sh" \
                "$topsrcdir/myconfig.sh" \
                "$HOME/.mozconfig" \
                "$HOME/.mozconfig.sh" \
                "$HOME/.mozmyconfig.sh"
 do
--- a/config/rules.mk
+++ b/config/rules.mk
@@ -187,17 +187,17 @@ endif # XPCSHELL_TESTS
 ifdef CPP_UNIT_TESTS
 
 # Compile the tests to $(DIST)/bin.  Make lots of niceties available by default
 # through TestHarness.h, by modifying the list of includes and the libs against
 # which stuff links.
 CPPSRCS += $(CPP_UNIT_TESTS)
 SIMPLE_PROGRAMS += $(CPP_UNIT_TESTS:.cpp=$(BIN_SUFFIX))
 INCLUDES += -I$(DIST)/include/testing
-LIBS += $(XPCOM_GLUE_LDOPTS) $(NSPR_LIBS)
+LIBS += $(XPCOM_GLUE_LDOPTS) $(NSPR_LIBS) $(MOZ_JS_LIBS)
 
 # ...and run them the usual way
 check::
 	@$(EXIT_ON_ERROR) \
 	  for f in $(subst .cpp,$(BIN_SUFFIX),$(CPP_UNIT_TESTS)); do \
 	    XPCOM_DEBUG_BREAK=stack-and-abort $(RUN_TEST_PROGRAM) $(DIST)/bin/$$f; \
 	  done
 
--- a/configure.in
+++ b/configure.in
@@ -1869,20 +1869,21 @@ if test -n "$MOZ_SHARK"; then
     MOZ_PROFILING=1
     AC_DEFINE(MOZ_SHARK)
 fi
 
 dnl ========================================================
 dnl callgrind
 dnl ========================================================
 MOZ_ARG_ENABLE_BOOL(callgrind,
-[  --enable-callgrind      Enable callgrind profiling],
+[  --enable-callgrind      Enable callgrind profiling. Implies --enable-profiling.],
     MOZ_CALLGRIND=1,
     MOZ_CALLGRIND= )
 if test -n "$MOZ_CALLGRIND"; then
+    MOZ_PROFILING=1
     AC_DEFINE(MOZ_CALLGRIND)
 fi
 
 dnl ========================================================
 dnl vtune
 dnl ========================================================
 MOZ_ARG_ENABLE_BOOL(vtune,
 [  --enable-vtune          Enable vtune profiling. Implies --enable-profiling.],
--- a/content/base/public/nsContentUtils.h
+++ b/content/base/public/nsContentUtils.h
@@ -77,16 +77,17 @@ static fp_except_t oldmask = fpsetmask(~
 #include "nsTextFragment.h"
 #include "nsReadableUtils.h"
 #include "mozilla/AutoRestore.h"
 #include "nsINode.h"
 #include "nsHashtable.h"
 #include "nsIDOMNode.h"
 #include "nsAHtml5FragmentParser.h"
 #include "nsIFragmentContentSink.h"
+#include "nsMathUtils.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;
@@ -2030,59 +2031,47 @@ public:
 #if defined(XP_WIN)
 #define DOUBLE_COMPARE(LVAL, OP, RVAL)                                  \
     (!DOUBLE_IS_NaN(LVAL) && !DOUBLE_IS_NaN(RVAL) && (LVAL) OP (RVAL))
 #else
 #define DOUBLE_COMPARE(LVAL, OP, RVAL) ((LVAL) OP (RVAL))
 #endif
 
 /*
- * Check whether a floating point number is finite (not +/-infinity and not a
- * NaN value).
- */
-inline NS_HIDDEN_(PRBool) NS_FloatIsFinite(jsdouble f) {
-#ifdef WIN32
-  return _finite(f);
-#else
-  return finite(f);
-#endif
-}
-
-/*
  * In the following helper macros we exploit the fact that the result of a
  * series of additions will not be finite if any one of the operands in the
  * series is not finite.
  */
 #define NS_ENSURE_FINITE(f, rv)                                               \
-  if (!NS_FloatIsFinite(f)) {                                                 \
+  if (!NS_finite(f)) {                                                        \
     return (rv);                                                              \
   }
 
 #define NS_ENSURE_FINITE2(f1, f2, rv)                                         \
-  if (!NS_FloatIsFinite((f1)+(f2))) {                                         \
+  if (!NS_finite((f1)+(f2))) {                                                \
     return (rv);                                                              \
   }
 
 #define NS_ENSURE_FINITE3(f1, f2, f3, rv)                                     \
-  if (!NS_FloatIsFinite((f1)+(f2)+(f3))) {                                    \
+  if (!NS_finite((f1)+(f2)+(f3))) {                                           \
     return (rv);                                                              \
   }
 
 #define NS_ENSURE_FINITE4(f1, f2, f3, f4, rv)                                 \
-  if (!NS_FloatIsFinite((f1)+(f2)+(f3)+(f4))) {                               \
+  if (!NS_finite((f1)+(f2)+(f3)+(f4))) {                                      \
     return (rv);                                                              \
   }
 
 #define NS_ENSURE_FINITE5(f1, f2, f3, f4, f5, rv)                             \
-  if (!NS_FloatIsFinite((f1)+(f2)+(f3)+(f4)+(f5))) {                          \
+  if (!NS_finite((f1)+(f2)+(f3)+(f4)+(f5))) {                                 \
     return (rv);                                                              \
   }
 
 #define NS_ENSURE_FINITE6(f1, f2, f3, f4, f5, f6, rv)                         \
-  if (!NS_FloatIsFinite((f1)+(f2)+(f3)+(f4)+(f5)+(f6))) {                     \
+  if (!NS_finite((f1)+(f2)+(f3)+(f4)+(f5)+(f6))) {                            \
     return (rv);                                                              \
   }
 
 // Deletes a linked list iteratively to avoid blowing up the stack (bug 460444).
 #define NS_CONTENT_DELETE_LIST_MEMBER(type_, ptr_, member_)                   \
   {                                                                           \
     type_ *cur = (ptr_)->member_;                                             \
     (ptr_)->member_ = nsnull;                                                 \
--- a/content/base/src/nsDocument.cpp
+++ b/content/base/src/nsDocument.cpp
@@ -8396,12 +8396,12 @@ nsIDocument::SizeOf() const
 
   return size;
 }
 
 PRInt64
 nsDocument::SizeOf() const
 {
   PRInt64 size = MemoryReporter::GetBasicSize<nsDocument, nsIDocument>(this);
-  size += mAttrStyleSheet ? mAttrStyleSheet->SizeOf() : 0;
+  size += mAttrStyleSheet ? mAttrStyleSheet->DOMSizeOf() : 0;
   return size;
 }
 
--- a/content/base/src/nsTreeSanitizer.cpp
+++ b/content/base/src/nsTreeSanitizer.cpp
@@ -1190,17 +1190,17 @@ nsTreeSanitizer::SanitizeAttributes(mozi
   PRUint32 ac = aElement->GetAttrCount();
 
   nsresult rv;
 
   for (PRInt32 i = ac - 1; i >= 0; --i) {
     rv = NS_OK;
     const nsAttrName* attrName = aElement->GetAttrNameAt(i);
     PRInt32 attrNs = attrName->NamespaceID();
-    nsIAtom* attrLocal = attrName->Atom();
+    nsIAtom* attrLocal = attrName->LocalName();
 
     if (kNameSpaceID_None == attrNs) {
       if (aAllowStyle && nsGkAtoms::style == attrLocal) {
         nsCOMPtr<nsIURI> baseURI = aElement->GetBaseURI();
         nsIDocument* document = aElement->GetOwnerDoc();
         // Pass the CSS Loader object to the parser, to allow parser error
         // reports to include the outer window ID.
         nsCSSParser parser(document->CSSLoader());
--- a/content/events/src/nsEventStateManager.cpp
+++ b/content/events/src/nsEventStateManager.cpp
@@ -2666,24 +2666,25 @@ nsEventStateManager::ComputeWheelActionF
   if (aMouseEvent->message == NS_MOUSE_PIXEL_SCROLL) {
     if (action == MOUSE_SCROLL_N_LINES || action == MOUSE_SCROLL_PAGE ||
         (aMouseEvent->scrollFlags & nsMouseScrollEvent::kIsMomentum)) {
       action = MOUSE_SCROLL_PIXELS;
     } else {
       // Do not scroll pixels when zooming
       action = -1;
     }
-  } else if (aMouseEvent->scrollFlags & nsMouseScrollEvent::kHasPixels) {
-    if (aUseSystemSettings ||
-        action == MOUSE_SCROLL_N_LINES || action == MOUSE_SCROLL_PAGE ||
-        (aMouseEvent->scrollFlags & nsMouseScrollEvent::kIsMomentum)) {
-      // Don't scroll lines when a pixel scroll event will follow.
-      // Also, don't do history scrolling or zooming for momentum scrolls.
-      action = -1;
-    }
+  } else if (((aMouseEvent->scrollFlags & nsMouseScrollEvent::kHasPixels) &&
+              (aUseSystemSettings ||
+               action == MOUSE_SCROLL_N_LINES || action == MOUSE_SCROLL_PAGE)) ||
+             ((aMouseEvent->scrollFlags & nsMouseScrollEvent::kIsMomentum) &&
+              (action == MOUSE_SCROLL_HISTORY || action == MOUSE_SCROLL_ZOOM))) {
+    // Don't scroll lines or page when a pixel scroll event will follow.
+    // Also, don't do history scrolling or zooming for momentum scrolls,
+    // no matter what's going on with pixel scrolling.
+    action = -1;
   }
 
   return action;
 }
 
 PRInt32
 nsEventStateManager::GetWheelActionFor(nsMouseScrollEvent* aMouseEvent)
 {
--- a/content/events/test/test_bug574663.html
+++ b/content/events/test/test_bug574663.html
@@ -30,17 +30,21 @@ function sendTouchpadScrollMotion(scroll
     'axis': "vertical",
     'delta': direction,
     'hasPixels': true,
     'ctrlKey': ctrl,
     'isMomentum': momentum,
   };
   // first a line scroll
   synthesizeMouseScroll(scrollbox, 10, 10, event, win);
+  // Then a line scroll with hasPixels set to false
+  event.hasPixels = false;
+  synthesizeMouseScroll(scrollbox, 10, 10, event, win);
   // then 5 pixel scrolls
+  event.hasPixels = true;
   event.delta *= 3;
   event.type = "MozMousePixelScroll";
   event.hasPixels = false;
   for (let i = 0; i < 5; ++i) {
     synthesizeMouseScroll(scrollbox, 10, 10, event, win);
   }
 }
 
--- a/content/html/content/src/nsHTMLMediaElement.cpp
+++ b/content/html/content/src/nsHTMLMediaElement.cpp
@@ -2029,16 +2029,21 @@ void nsHTMLMediaElement::Error(PRUint16 
 }
 
 void nsHTMLMediaElement::PlaybackEnded()
 {
   NS_ASSERTION(mDecoder->IsEnded(), "Decoder fired ended, but not in ended state");
   // We changed the state of IsPlaybackEnded which can affect AddRemoveSelfReference
   AddRemoveSelfReference();
 
+  if (mDecoder && mDecoder->IsInfinite()) {
+    LOG(PR_LOG_DEBUG, ("%p, got duration by reaching the end of the stream", this));
+    DispatchAsyncEvent(NS_LITERAL_STRING("durationchange"));
+  }
+
   FireTimeUpdate(PR_FALSE);
   DispatchAsyncEvent(NS_LITERAL_STRING("ended"));
 }
 
 void nsHTMLMediaElement::SeekStarted()
 {
   DispatchAsyncEvent(NS_LITERAL_STRING("seeking"));
   FireTimeUpdate(PR_FALSE);
--- a/content/html/content/src/nsHTMLSelectElement.cpp
+++ b/content/html/content/src/nsHTMLSelectElement.cpp
@@ -682,18 +682,19 @@ nsHTMLSelectElement::Add(nsIDOMHTMLEleme
 NS_IMETHODIMP
 nsHTMLSelectElement::Add(nsIDOMHTMLElement* aElement,
                          nsIVariant* aBefore)
 {
   PRUint16 dataType;
   nsresult rv = aBefore->GetDataType(&dataType);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  // aBefore is omitted or null
-  if (dataType == nsIDataType::VTYPE_EMPTY) {
+  // aBefore is omitted, undefined or null
+  if (dataType == nsIDataType::VTYPE_EMPTY ||
+      dataType == nsIDataType::VTYPE_VOID) {
     return Add(aElement);
   }
 
   nsCOMPtr<nsISupports> supports;
   nsCOMPtr<nsIDOMHTMLElement> beforeElement;
 
   // whether aBefore is nsIDOMHTMLElement...
   if (NS_SUCCEEDED(aBefore->GetAsISupports(getter_AddRefs(supports)))) {
--- a/content/html/content/test/test_bug666200.html
+++ b/content/html/content/test/test_bug666200.html
@@ -17,24 +17,28 @@ https://bugzilla.mozilla.org/show_bug.cg
 <pre id="test">
 <script class="testbody" type="text/javascript">
 /** Test for Bug 666200 **/
 var sel = document.createElement("select");
 var opt1 = new Option();
 var opt2 = new Option();
 var opt3 = new Option();
 var opt4 = new Option();
+var opt5 = new Option();
 opt1.value = 1;
 opt2.value = 2;
 opt3.value = 3;
 opt4.value = 4;
+opt5.value = 5;
 sel.add(opt1);
 sel.add(opt2, 0);
 sel.add(opt3, 1000);
 sel.options.add(opt4, opt3);
+sel.add(opt5, undefined);
 is(sel[0], opt2, "1st item should be 2");
 is(sel[1], opt1, "2nd item should be 1");
 is(sel[2], opt4, "3rd item should be 4");
 is(sel[3], opt3, "4th item should be 3");
+is(sel[4], opt5, "5th item should be 5");
 </script>
 </pre>
 </body>
 </html>
--- a/content/media/nsBuiltinDecoder.cpp
+++ b/content/media/nsBuiltinDecoder.cpp
@@ -78,35 +78,51 @@ void nsBuiltinDecoder::SetVolume(double 
   if (mDecoderStateMachine) {
     mDecoderStateMachine->SetVolume(aVolume);
   }
 }
 
 double nsBuiltinDecoder::GetDuration()
 {
   NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
+  if (mInfiniteStream) {
+    return std::numeric_limits<double>::infinity();
+  }
   if (mDuration >= 0) {
      return static_cast<double>(mDuration) / static_cast<double>(USECS_PER_S);
   }
   return std::numeric_limits<double>::quiet_NaN();
 }
 
+void nsBuiltinDecoder::SetInfinite(PRBool aInfinite)
+{
+  NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
+  mInfiniteStream = aInfinite;
+}
+
+PRBool nsBuiltinDecoder::IsInfinite()
+{
+  NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
+  return mInfiniteStream;
+}
+
 nsBuiltinDecoder::nsBuiltinDecoder() :
   mDecoderPosition(0),
   mPlaybackPosition(0),
   mCurrentTime(0.0),
   mInitialVolume(0.0),
   mRequestedSeekTime(-1.0),
   mDuration(-1),
   mSeekable(PR_TRUE),
   mReentrantMonitor("media.decoder"),
   mPlayState(PLAY_STATE_PAUSED),
   mNextState(PLAY_STATE_PAUSED),
   mResourceLoaded(PR_FALSE),
-  mIgnoreProgressData(PR_FALSE)
+  mIgnoreProgressData(PR_FALSE),
+  mInfiniteStream(PR_FALSE)
 {
   MOZ_COUNT_CTOR(nsBuiltinDecoder);
   NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
 #ifdef PR_LOGGING
   if (!gBuiltinDecoderLog) {
     gBuiltinDecoderLog = PR_NewLogModule("nsBuiltinDecoder");
   }
 #endif
@@ -337,16 +353,20 @@ void nsBuiltinDecoder::MetadataLoaded(PR
     ReentrantMonitorAutoEnter mon(mReentrantMonitor);
     mDuration = mDecoderStateMachine ? mDecoderStateMachine->GetDuration() : -1;
     // Duration has changed so we should recompute playback rate
     UpdatePlaybackRate();
 
     notifyElement = mNextState != PLAY_STATE_SEEKING;
   }
 
+  if (mDuration == -1) {
+    SetInfinite(PR_TRUE);
+  }
+
   if (mElement && notifyElement) {
     // Make sure the element and the frame (if any) are told about
     // our new size.
     Invalidate();
     mElement->MetadataLoaded(aChannels, aRate);
   }
 
   if (!mResourceLoaded) {
@@ -456,16 +476,22 @@ void nsBuiltinDecoder::PlaybackEnded()
 
   PlaybackPositionChanged();
   ChangeState(PLAY_STATE_ENDED);
 
   if (mElement)  {
     UpdateReadyStateForData();
     mElement->PlaybackEnded();
   }
+
+  // This must be called after |mElement->PlaybackEnded()| call above, in order
+  // to fire the required durationchange.
+  if (IsInfinite()) {
+    SetInfinite(PR_FALSE);
+  }
 }
 
 NS_IMETHODIMP nsBuiltinDecoder::Observe(nsISupports *aSubjet,
                                         const char *aTopic,
                                         const PRUnichar *someData)
 {
   NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
   if (strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID) == 0) {
@@ -786,17 +812,17 @@ void nsBuiltinDecoder::DurationChanged()
 {
   NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
   ReentrantMonitorAutoEnter mon(mReentrantMonitor);
   PRInt64 oldDuration = mDuration;
   mDuration = mDecoderStateMachine ? mDecoderStateMachine->GetDuration() : -1;
   // Duration has changed so we should recompute playback rate
   UpdatePlaybackRate();
 
-  if (mElement && oldDuration != mDuration) {
+  if (mElement && oldDuration != mDuration && !IsInfinite()) {
     LOG(PR_LOG_DEBUG, ("%p duration changed to %lld", this, mDuration));
     mElement->DispatchEvent(NS_LITERAL_STRING("durationchange"));
   }
 }
 
 void nsBuiltinDecoder::SetDuration(double aDuration)
 {
   NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
--- a/content/media/nsBuiltinDecoder.h
+++ b/content/media/nsBuiltinDecoder.h
@@ -390,16 +390,19 @@ class nsBuiltinDecoder : public nsMediaD
   virtual nsresult Seek(double aTime);
 
   virtual nsresult PlaybackRateChanged();
 
   virtual void Pause();
   virtual void SetVolume(double aVolume);
   virtual double GetDuration();
 
+  virtual void SetInfinite(PRBool aInfinite);
+  virtual PRBool IsInfinite();
+
   virtual nsMediaStream* GetCurrentStream();
   virtual already_AddRefed<nsIPrincipal> GetCurrentPrincipal();
 
   virtual void NotifySuspendedStatusChanged();
   virtual void NotifyBytesDownloaded();
   virtual void NotifyDownloadEnded(nsresult aStatus);
   // Called by the decode thread to keep track of the number of bytes read
   // from the resource.
@@ -683,11 +686,14 @@ public:
   PRPackedBool mResourceLoaded;
 
   // True when seeking or otherwise moving the play position around in
   // such a manner that progress event data is inaccurate. This is set
   // during seek and duration operations to prevent the progress indicator
   // from jumping around. Read/Write from any thread. Must have decode monitor
   // locked before accessing.
   PRPackedBool mIgnoreProgressData;
+
+  // PR_TRUE if the stream is infinite (e.g. a webradio).
+  PRPackedBool mInfiniteStream;
 };
 
 #endif
--- a/content/media/nsBuiltinDecoderReader.h
+++ b/content/media/nsBuiltinDecoderReader.h
@@ -471,16 +471,19 @@ public:
                                PRInt64 aStartTime) = 0;
 
   class VideoQueueMemoryFunctor : public nsDequeFunctor {
   public:
     VideoQueueMemoryFunctor() : mResult(0) {}
 
     virtual void* operator()(void* anObject) {
       const VideoData* v = static_cast<const VideoData*>(anObject);
+      if (!v->mImage) {
+        return nsnull;
+      }
       NS_ASSERTION(v->mImage->GetFormat() == mozilla::layers::Image::PLANAR_YCBCR,
                    "Wrong format?");
       mozilla::layers::PlanarYCbCrImage* vi = static_cast<mozilla::layers::PlanarYCbCrImage*>(v->mImage.get());
 
       mResult += vi->GetDataSize();
       return nsnull;
     }
 
--- a/content/media/nsMediaDecoder.h
+++ b/content/media/nsMediaDecoder.h
@@ -107,16 +107,29 @@ public:
   // Called by the element when the playback rate has been changed.
   // Adjust the speed of the playback, optionally with pitch correction,
   // when this is called.
   virtual nsresult PlaybackRateChanged() = 0;
 
   // Return the duration of the video in seconds.
   virtual double GetDuration() = 0;
 
+  // A media stream is assumed to be infinite if the metadata doesn't
+  // contain the duration, and range requests are not supported, and
+  // no headers give a hint of a possible duration (Content-Length,
+  // Content-Duration, and variants), and we cannot seek in the media
+  // stream to determine the duration.
+  //
+  // When the media stream ends, we can know the duration, thus the stream is
+  // no longer considered to be infinite.
+  virtual void SetInfinite(PRBool aInfinite) = 0;
+
+  // Return true if the stream is infinite (see SetInfinite).
+  virtual PRBool IsInfinite() = 0;
+
   // Pause video playback.
   virtual void Pause() = 0;
 
   // Set the audio volume. It should be a value from 0 to 1.0.
   virtual void SetVolume(double aVolume) = 0;
 
   // Start playback of a video. 'Load' must have previously been
   // called.
--- a/content/media/nsMediaStream.cpp
+++ b/content/media/nsMediaStream.cpp
@@ -220,16 +220,18 @@ nsMediaChannelStream::OnStartRequest(nsI
         rv = hc->GetResponseHeader(NS_LITERAL_CSTRING("X-Content-Duration"), durationText);
       }
 
       if (NS_SUCCEEDED(rv)) {
         double duration = durationText.ToDouble(&ec);
         if (ec == NS_OK && duration >= 0) {
           mDecoder->SetDuration(duration);
         }
+      } else {
+        mDecoder->SetInfinite(PR_TRUE);
       }
     }
 
     if (mOffset > 0 && responseStatus == HTTP_OK_CODE) {
       // If we get an OK response but we were seeking, we have to assume
       // that seeking doesn't work. We also need to tell the cache that
       // it's getting data for the start of the stream.
       mCacheStream.NotifyDataStarted(0);
@@ -251,16 +253,20 @@ nsMediaChannelStream::OnStartRequest(nsI
     // XXX we probably should examine the Content-Range header in case
     // the server gave us a range which is not quite what we asked for
 
     // If we get an HTTP_OK_CODE response to our byte range request,
     // and the server isn't sending Accept-Ranges:bytes then we don't
     // support seeking.
     seekable =
       responseStatus == HTTP_PARTIAL_RESPONSE_CODE || acceptsRanges;
+
+    if (seekable) {
+      mDecoder->SetInfinite(PR_FALSE);
+    }
   }
   mDecoder->SetSeekable(seekable);
   mCacheStream.SetSeekable(seekable);
 
   nsCOMPtr<nsICachingChannel> cc = do_QueryInterface(aRequest);
   if (cc) {
     PRBool fromCache = PR_FALSE;
     rv = cc->IsFromCache(&fromCache);
--- a/content/media/test/test_contentDuration3.html
+++ b/content/media/test/test_contentDuration3.html
@@ -8,17 +8,17 @@
 </head>
 <body onunload="mediaTestCleanup();">
 <pre id="test">
 <script class="testbody" type="text/javascript">
 
 function on_metadataloaded() {
   var v = document.getElementById('v');
   var d = Math.round(v.duration*1000);
-  ok(d.toString() == "NaN", "Checking duration: " + d);
+  ok(d.toString() == "Infinity", "Checking duration: " + d);
   SimpleTest.finish();
 }
 
 SimpleTest.waitForExplicitFinish();
 </script>
 </pre>
 <video id='v'
        src='contentDuration3.sjs'
--- a/content/media/test/test_contentDuration4.html
+++ b/content/media/test/test_contentDuration4.html
@@ -8,17 +8,17 @@
 </head>
 <body onunload="mediaTestCleanup();">
 <pre id="test">
 <script class="testbody" type="text/javascript">
 
 function on_metadataloaded() {
   var v = document.getElementById('v');
   var d = Math.round(v.duration*1000);
-  ok(d.toString() == "NaN", "Checking duration: " + d);
+  ok(d.toString() == "Infinity", "Checking duration: " + d);
   SimpleTest.finish();
 }
 
 SimpleTest.waitForExplicitFinish();
 </script>
 </pre>
 <video id='v'
        src='contentDuration4.sjs'
--- a/content/media/test/test_contentDuration5.html
+++ b/content/media/test/test_contentDuration5.html
@@ -8,17 +8,17 @@
 </head>
 <body onunload="mediaTestCleanup();">
 <pre id="test">
 <script class="testbody" type="text/javascript">
 
 function on_metadataloaded() {
   var v = document.getElementById('v');
   var d = Math.round(v.duration*1000);
-  ok(d.toString() == "NaN", "Checking duration: " + d);
+  ok(d.toString() == "Infinity", "Checking duration: " + d);
   SimpleTest.finish();
 }
 
 SimpleTest.waitForExplicitFinish();
 </script>
 </pre>
 <video id='v'
        src='contentDuration5.sjs'
--- a/content/media/test/test_contentDuration6.html
+++ b/content/media/test/test_contentDuration6.html
@@ -8,17 +8,17 @@
 </head>
 <body onunload="mediaTestCleanup();">
 <pre id="test">
 <script class="testbody" type="text/javascript">
 
 function on_metadataloaded() {
   var v = document.getElementById('v');
   var d = Math.round(v.duration*1000);
-  ok(d.toString() == "NaN", "Checking duration: " + d);
+  ok(d.toString() == "Infinity", "Checking duration: " + d);
   SimpleTest.finish();
 }
 
 SimpleTest.waitForExplicitFinish();
 </script>
 </pre>
 <video id='v'
        src='contentDuration6.sjs'
--- a/content/svg/content/src/DOMSVGLength.cpp
+++ b/content/svg/content/src/DOMSVGLength.cpp
@@ -37,16 +37,17 @@
 #include "DOMSVGLength.h"
 #include "DOMSVGLengthList.h"
 #include "DOMSVGAnimatedLengthList.h"
 #include "SVGLength.h"
 #include "SVGAnimatedLengthList.h"
 #include "nsSVGElement.h"
 #include "nsIDOMSVGLength.h"
 #include "nsDOMError.h"
+#include "nsMathUtils.h"
 
 // See the architecture comment in DOMSVGAnimatedLengthList.h.
 
 namespace mozilla {
 
 // We could use NS_IMPL_CYCLE_COLLECTION_1, except that in Unlink() we need to
 // clear our list's weak ref to us to be safe. (The other option would be to
 // not unlink and rely on the breaking of the other edges in the cycle, as
@@ -124,17 +125,17 @@ DOMSVGLength::GetValue(float* aValue)
 {
 #ifdef MOZ_SMIL
   if (mIsAnimValItem && HasOwner()) {
     Element()->FlushAnimations(); // May make HasOwner() == PR_FALSE
   }
 #endif
   if (HasOwner()) {
     *aValue = InternalItem().GetValueInUserUnits(Element(), Axis());
-    if (NS_FloatIsFinite(*aValue)) {
+    if (NS_finite(*aValue)) {
       return NS_OK;
     }
   } else if (mUnit == nsIDOMSVGLength::SVG_LENGTHTYPE_NUMBER ||
              mUnit == nsIDOMSVGLength::SVG_LENGTHTYPE_PX) {
     *aValue = mValue;
     return NS_OK;
   }
   // else [SVGWG issue] Can't convert this length's value to user units
--- a/content/svg/content/src/DOMSVGPoint.h
+++ b/content/svg/content/src/DOMSVGPoint.h
@@ -38,16 +38,17 @@
 #define MOZILLA_DOMSVGPOINT_H__
 
 #include "nsIDOMSVGPoint.h"
 #include "DOMSVGPointList.h"
 #include "SVGPoint.h"
 #include "gfxPoint.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsAutoPtr.h"
+#include "nsMathUtils.h"
 
 class nsSVGElement;
 
 // We make DOMSVGPoint a pseudo-interface to allow us to QI to it in order to
 // check that the objects that scripts pass to DOMSVGPointList methods are
 // our *native* point objects.
 //
 // {d6b6c440-af8d-40ee-856b-02a317cab275}
@@ -123,17 +124,17 @@ public:
   DOMSVGPoint(const gfxPoint &aPt)
     : mList(nsnull)
     , mListIndex(0)
     , mIsReadonly(PR_FALSE)
     , mIsAnimValItem(PR_FALSE)
   {
     mPt.mX = float(aPt.x);
     mPt.mY = float(aPt.y);
-    NS_ASSERTION(NS_FloatIsFinite(mPt.mX) && NS_FloatIsFinite(mPt.mX),
+    NS_ASSERTION(NS_finite(mPt.mX) && NS_finite(mPt.mX),
                  "DOMSVGPoint coords are not finite");
   }
 
 
   ~DOMSVGPoint() {
     // Our mList's weak ref to us must be nulled out when we die. If GC has
     // unlinked us using the cycle collector code, then that has already
     // happened, and mList is null.
--- a/content/svg/content/src/SVGLength.cpp
+++ b/content/svg/content/src/SVGLength.cpp
@@ -34,19 +34,19 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "SVGLength.h"
 #include "nsSVGElement.h"
 #include "nsSVGSVGElement.h"
 #include "nsString.h"
 #include "nsSVGUtils.h"
-#include "nsContentUtils.h"
 #include "nsTextFormatter.h"
 #include "prdtoa.h"
+#include "nsMathUtils.h"
 #include <limits>
 
 namespace mozilla {
 
 // Declare some helpers defined below:
 static void GetUnitString(nsAString& unit, PRUint16 unitType);
 static PRUint16 GetUnitTypeForString(const char* unitStr);
 
@@ -73,17 +73,17 @@ SVGLength::SetValueFromString(const nsAS
   NS_ConvertUTF16toUTF8 value(aValue);
   const char *str = value.get();
 
   while (*str != '\0' && IsSVGWhitespace(*str)) {
     ++str;
   }
   char *unit;
   tmpValue = float(PR_strtod(str, &unit));
-  if (unit != str && NS_FloatIsFinite(tmpValue)) {
+  if (unit != str && NS_finite(tmpValue)) {
     char *theRest = unit;
     if (*unit != '\0' && !IsSVGWhitespace(*unit)) {
       while (*theRest != '\0' && !IsSVGWhitespace(*theRest)) {
         ++theRest;
       }
       nsCAutoString unitStr(unit, theRest - unit);
       tmpUnit = GetUnitTypeForString(unitStr.get());
       if (tmpUnit == nsIDOMSVGLength::SVG_LENGTHTYPE_UNKNOWN) {
@@ -167,27 +167,27 @@ SVGLength::GetValueInSpecifiedUnit(PRUin
   // succeed if aElement is non-null (although that's not sufficent to
   // guarantee success).
 
   float userUnitsPerCurrentUnit = GetUserUnitsPerUnit(aElement, aAxis);
   float userUnitsPerNewUnit =
     SVGLength(0.0f, aUnit).GetUserUnitsPerUnit(aElement, aAxis);
 
   NS_ASSERTION(userUnitsPerCurrentUnit >= 0 ||
-               !NS_FloatIsFinite(userUnitsPerCurrentUnit),
+               !NS_finite(userUnitsPerCurrentUnit),
                "bad userUnitsPerCurrentUnit");
   NS_ASSERTION(userUnitsPerNewUnit >= 0 ||
-               !NS_FloatIsFinite(userUnitsPerNewUnit),
+               !NS_finite(userUnitsPerNewUnit),
                "bad userUnitsPerNewUnit");
 
   float value = mValue * userUnitsPerCurrentUnit / userUnitsPerNewUnit;
 
   // userUnitsPerCurrentUnit could be infinity, or userUnitsPerNewUnit could
   // be zero.
-  if (NS_FloatIsFinite(value)) {
+  if (NS_finite(value)) {
     return value;
   }
   return std::numeric_limits<float>::quiet_NaN();
 }
 
 #define INCHES_PER_MM_FLOAT float(0.0393700787)
 #define INCHES_PER_CM_FLOAT float(0.393700787)
 
--- a/content/svg/content/src/SVGLength.h
+++ b/content/svg/content/src/SVGLength.h
@@ -35,17 +35,17 @@
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef MOZILLA_SVGLENGTH_H__
 #define MOZILLA_SVGLENGTH_H__
 
 #include "nsIDOMSVGLength.h"
 #include "nsIContent.h"
 #include "nsAString.h"
-#include "nsContentUtils.h"
+#include "nsMathUtils.h"
 
 class nsSVGElement;
 
 namespace mozilla {
 
 /**
  * This SVGLength class is currently used for SVGLength *list* attributes only.
  * The class that is currently used for <length> attributes is nsSVGLength2.
@@ -147,17 +147,17 @@ public:
    * converted to this length's current unit, in which case it returns PR_FALSE
    * (and the length is left unchanged).
    */
   PRBool SetFromUserUnitValue(float aUserUnitValue,
                               nsSVGElement *aElement,
                               PRUint8 aAxis) {
     float uuPerUnit = GetUserUnitsPerUnit(aElement, aAxis);
     float value = aUserUnitValue / uuPerUnit;
-    if (uuPerUnit > 0 && NS_FloatIsFinite(value)) {
+    if (uuPerUnit > 0 && NS_finite(value)) {
       mValue = value;
       NS_ASSERTION(IsValid(), "Set invalid SVGLength");
       return PR_TRUE;
     }
     return PR_FALSE;
   }
 
   /**
@@ -174,17 +174,17 @@ public:
    * Convert this length's value to the unit specified.
    *
    * This method returns PR_TRUE, unless it isn't possible to convert the
    * length to the specified unit. In that case the length is left unchanged
    * and this method returns PR_FALSE.
    */
   PRBool ConvertToUnit(PRUint32 aUnit, nsSVGElement *aElement, PRUint8 aAxis) {
     float val = GetValueInSpecifiedUnit(aUnit, aElement, aAxis);
-    if (NS_FloatIsFinite(val)) {
+    if (NS_finite(val)) {
       mValue = val;
       mUnit = aUnit;
       NS_ASSERTION(IsValid(), "Set invalid SVGLength");
       return PR_TRUE;
     }
     return PR_FALSE;
   }
 
@@ -196,17 +196,17 @@ public:
     return unit > nsIDOMSVGLength::SVG_LENGTHTYPE_UNKNOWN &&
            unit <= nsIDOMSVGLength::SVG_LENGTHTYPE_PC;
   }
 
 private:
 
 #ifdef DEBUG
   PRBool IsValid() const {
-    return NS_FloatIsFinite(mValue) && IsValidUnitType(mUnit);
+    return NS_finite(mValue) && IsValidUnitType(mUnit);
   }
 #endif
 
   /**
    * Returns the number of user units per current unit.
    *
    * This method returns numeric_limits<float>::quiet_NaN() if the conversion
    * factor between the length's current unit and user units is undefined (see
--- a/content/svg/content/src/SVGLengthListSMILType.cpp
+++ b/content/svg/content/src/SVGLengthListSMILType.cpp
@@ -32,16 +32,17 @@
  * 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 ***** */
 
 #include "SVGLengthListSMILType.h"
 #include "nsSMILValue.h"
 #include "SVGLengthList.h"
+#include "nsMathUtils.h"
 #include <math.h>
 
 namespace mozilla {
 
 /*static*/ SVGLengthListSMILType SVGLengthListSMILType::sSingleton;
 
 //----------------------------------------------------------------------
 // nsISMILType implementation
@@ -247,17 +248,17 @@ SVGLengthListSMILType::ComputeDistance(c
     total += f * f;
   }
   for (; i < to.Length(); ++i) {
     double t = to[i].GetValueInUserUnits(to.Element(), to.Axis());
     total += t * t;
   }
 
   float distance = sqrt(total);
-  if (!NS_FloatIsFinite(distance)) {
+  if (!NS_finite(distance)) {
     return NS_ERROR_FAILURE;
   }
   aDistance = distance;
   return NS_OK;
 }
 
 nsresult
 SVGLengthListSMILType::Interpolate(const nsSMILValue& aStartVal,
--- a/content/svg/content/src/SVGNumberList.cpp
+++ b/content/svg/content/src/SVGNumberList.cpp
@@ -34,23 +34,23 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "SVGNumberList.h"
 #include "SVGAnimatedNumberList.h"
 #include "nsSVGElement.h"
 #include "nsISVGValueUtils.h"
 #include "nsDOMError.h"
-#include "nsContentUtils.h"
 #include "nsString.h"
 #include "nsSVGUtils.h"
 #include "string.h"
 #include "prdtoa.h"
 #include "nsTextFormatter.h"
 #include "nsCharSeparatedTokenizer.h"
+#include "nsMathUtils.h"
 
 namespace mozilla {
 
 nsresult
 SVGNumberList::CopyFrom(const SVGNumberList& rhs)
 {
   if (!mNumbers.SetCapacity(rhs.Length())) {
     // Yes, we do want fallible alloc here
@@ -93,17 +93,17 @@ SVGNumberList::SetValueFromString(const 
   while (tokenizer.hasMoreTokens()) {
     CopyUTF16toUTF8(tokenizer.nextToken(), str); // NS_ConvertUTF16toUTF8
     const char *token = str.get();
     if (token == '\0') {
       return NS_ERROR_DOM_SYNTAX_ERR; // nothing between commas
     }
     char *end;
     float num = float(PR_strtod(token, &end));
-    if (*end != '\0' || !NS_FloatIsFinite(num)) {
+    if (*end != '\0' || !NS_finite(num)) {
       return NS_ERROR_DOM_SYNTAX_ERR;
     }
     temp.AppendItem(num);
   }
   if (tokenizer.lastTokenEndedWithSeparator()) {
     return NS_ERROR_DOM_SYNTAX_ERR; // trailing comma
   }
   return CopyFrom(temp);
--- a/content/svg/content/src/SVGNumberListSMILType.cpp
+++ b/content/svg/content/src/SVGNumberListSMILType.cpp
@@ -32,16 +32,17 @@
  * 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 ***** */
 
 #include "SVGNumberListSMILType.h"
 #include "nsSMILValue.h"
 #include "SVGNumberList.h"
+#include "nsMathUtils.h"
 #include <math.h>
 
 /* The "identity" number list for a given number list attribute (the effective
  * number list that is used if an attribute value is not specified) varies
  * widely for different number list attributes, and can depend on the value of
  * other attributes on the same element:
  *
  * http://www.w3.org/TR/SVG11/filters.html#feColorMatrixValuesAttribute
@@ -180,17 +181,17 @@ SVGNumberListSMILType::ComputeDistance(c
 
   double total = 0.0;
 
   for (PRUint32 i = 0; i < to.Length(); ++i) {
     double delta = to[i] - from[i];
     total += delta * delta;
   }
   double distance = sqrt(total);
-  if (!NS_FloatIsFinite(distance)) {
+  if (!NS_finite(distance)) {
     return NS_ERROR_FAILURE;
   }
   aDistance = distance;
 
   return NS_OK;
 }
 
 nsresult
--- a/content/svg/content/src/SVGPoint.h
+++ b/content/svg/content/src/SVGPoint.h
@@ -33,18 +33,18 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef MOZILLA_SVGPOINT_H__
 #define MOZILLA_SVGPOINT_H__
 
 #include "nsDebug.h"
-#include "nsContentUtils.h"
 #include "gfxPoint.h"
+#include "nsMathUtils.h"
 
 namespace mozilla {
 
 /**
  * This class is currently used for point list attributes.
  *
  * The DOM wrapper class for this class is DOMSVGPoint.
  */
@@ -88,17 +88,17 @@ public:
   }
 
   operator gfxPoint() const {
     return gfxPoint(mX, mY);
   }
 
 #ifdef DEBUG
   PRBool IsValid() const {
-    return NS_FloatIsFinite(mX) && NS_FloatIsFinite(mY);
+    return NS_finite(mX) && NS_finite(mY);
   }
 #endif
 
   float mX;
   float mY;
 };
 
 inline SVGPoint operator+(const SVGPoint& aP1,
--- a/content/svg/content/src/SVGPointList.cpp
+++ b/content/svg/content/src/SVGPointList.cpp
@@ -34,23 +34,23 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "SVGPointList.h"
 #include "SVGAnimatedPointList.h"
 #include "nsSVGElement.h"
 #include "nsISVGValueUtils.h"
 #include "nsDOMError.h"
-#include "nsContentUtils.h"
 #include "nsString.h"
 #include "nsSVGUtils.h"
 #include "string.h"
 #include "prdtoa.h"
 #include "nsTextFormatter.h"
 #include "nsCharSeparatedTokenizer.h"
+#include "nsMathUtils.h"
 
 namespace mozilla {
 
 nsresult
 SVGPointList::CopyFrom(const SVGPointList& rhs)
 {
   if (!SetCapacity(rhs.Length())) {
     // Yes, we do want fallible alloc here
@@ -108,17 +108,17 @@ SVGPointList::SetValueFromString(const n
     CopyUTF16toUTF8(tokenizer.nextToken(), str1);
     const char *token1 = str1.get();
     if (*token1 == '\0') {
       rv = NS_ERROR_DOM_SYNTAX_ERR;
       break;
     }
     char *end;
     float x = float(PR_strtod(token1, &end));
-    if (end == token1 || !NS_FloatIsFinite(x)) {
+    if (end == token1 || !NS_finite(x)) {
       rv = NS_ERROR_DOM_SYNTAX_ERR;
       break;
     }
     const char *token2;
     if (*end == '-') {
       // It's possible for the token to be 10-30 which has
       // no separator but needs to be parsed as 10, -30
       token2 = end;
@@ -131,17 +131,17 @@ SVGPointList::SetValueFromString(const n
       token2 = str2.get();
       if (*token2 == '\0') {
         rv = NS_ERROR_DOM_SYNTAX_ERR;
         break;
       }
     }
 
     float y = float(PR_strtod(token2, &end));
-    if (*end != '\0' || !NS_FloatIsFinite(y)) {
+    if (*end != '\0' || !NS_finite(y)) {
       rv = NS_ERROR_DOM_SYNTAX_ERR;
       break;
     }
 
     temp.AppendItem(SVGPoint(x, y));
   }
   if (tokenizer.lastTokenEndedWithSeparator()) {
     rv = NS_ERROR_DOM_SYNTAX_ERR; // trailing comma
--- a/content/svg/content/src/SVGPointListSMILType.cpp
+++ b/content/svg/content/src/SVGPointListSMILType.cpp
@@ -165,17 +165,17 @@ SVGPointListSMILType::ComputeDistance(co
   double total = 0.0;
 
   for (PRUint32 i = 0; i < to.Length(); ++i) {
     double dx = to[i].mX - from[i].mX;
     double dy = to[i].mY - from[i].mY;
     total += dx * dx + dy * dy;
   }
   double distance = sqrt(total);
-  if (!NS_FloatIsFinite(distance)) {
+  if (!NS_finite(distance)) {
     return NS_ERROR_FAILURE;
   }
   aDistance = distance;
 
   return NS_OK;
 }
 
 nsresult
--- a/content/svg/content/src/nsSVGAngle.cpp
+++ b/content/svg/content/src/nsSVGAngle.cpp
@@ -34,16 +34,17 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsSVGAngle.h"
 #include "prdtoa.h"
 #include "nsTextFormatter.h"
 #include "nsSVGUtils.h"
 #include "nsSVGMarkerElement.h"
+#include "nsMathUtils.h"
 #ifdef MOZ_SMIL
 #include "nsSMILValue.h"
 #include "SVGOrientSMILType.h"
 #endif // MOZ_SMIL
 
 using namespace mozilla;
 
 /**
@@ -220,17 +221,17 @@ GetValueFromString(const nsAString &aVal
   NS_ConvertUTF16toUTF8 value(aValueAsString);
   const char *str = value.get();
 
   if (NS_IsAsciiWhitespace(*str))
     return NS_ERROR_DOM_SYNTAX_ERR;
   
   char *rest;
   *aValue = float(PR_strtod(str, &rest));
-  if (rest != str && NS_FloatIsFinite(*aValue)) {
+  if (rest != str && NS_finite(*aValue)) {
     *aUnitType = GetUnitTypeForString(rest);
     if (IsValidUnitType(*aUnitType)) {
       return NS_OK;
     }
   }
   
   return NS_ERROR_DOM_SYNTAX_ERR;
 }
--- a/content/svg/content/src/nsSVGDataParser.cpp
+++ b/content/svg/content/src/nsSVGDataParser.cpp
@@ -44,19 +44,19 @@
   *
   *   A subclass should implement a Match method which gets invoked from the
   *   Parse method.  The Parse method can be overridden, as required.
   *
   */
 
 
 #include "nsSVGDataParser.h"
-#include "nsContentUtils.h"
 #include "prdtoa.h"
 #include "nsSVGUtils.h"
+#include "nsMathUtils.h"
 #include <stdlib.h>
 #include <math.h>
 
 //----------------------------------------------------------------------
 // public interface
 
 nsresult
 nsSVGDataParser::Parse(const nsAString &aValue)
@@ -140,17 +140,17 @@ nsresult nsSVGDataParser::MatchNonNegati
 
   if (NS_FAILED(rv)) {
     RewindTo(pos);
     ENSURE_MATCHED(MatchIntegerConst());
   }
 
   char* end;
   *aX = float(PR_strtod(pos, &end));
-  if (pos != end && NS_FloatIsFinite(*aX)) {
+  if (pos != end && NS_finite(*aX)) {
     return NS_OK;
   }
   
   return NS_ERROR_FAILURE;
 }
 
 PRBool nsSVGDataParser::IsTokenNonNegativeNumberStarter()
 {
@@ -176,17 +176,17 @@ nsresult nsSVGDataParser::MatchNumber(fl
   }
 
   char* end;
   /* PR_strtod is not particularily fast. We only need a float and not a double so
    * we could probably use something faster here if needed. The CSS parser uses
    * nsCSSScanner::ParseNumber() instead of PR_strtod. See bug 516396 for some
    * additional info. */
   *aX = float(PR_strtod(pos, &end));
-  if (pos != end && NS_FloatIsFinite(*aX)) {
+  if (pos != end && NS_finite(*aX)) {
     return NS_OK;
   }
   
   return NS_ERROR_FAILURE;
 }
 
 PRBool nsSVGDataParser::IsTokenNumberStarter()
 {
--- a/content/svg/content/src/nsSVGIntegerPair.cpp
+++ b/content/svg/content/src/nsSVGIntegerPair.cpp
@@ -33,16 +33,17 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsSVGIntegerPair.h"
 #include "nsSVGUtils.h"
 #include "nsCharSeparatedTokenizer.h"
 #include "nsDOMError.h"
+#include "nsMathUtils.h"
 #ifdef MOZ_SMIL
 #include "nsSMILValue.h"
 #include "SVGIntegerPairSMILType.h"
 #endif // MOZ_SMIL
 
 using namespace mozilla;
 
 NS_SVG_VAL_IMPL_CYCLE_COLLECTION(nsSVGIntegerPair::DOMAnimatedInteger, mSVGElement)
@@ -76,17 +77,17 @@ ParseIntegerOptionalInteger(const nsAStr
     NS_ConvertUTF16toUTF8 utf8Token(tokenizer.nextToken());
     const char *token = utf8Token.get();
     if (*token == '\0') {
       return NS_ERROR_DOM_SYNTAX_ERR; // empty string (e.g. two commas in a row)
     }
 
     char *end;
     aValues[i] = strtol(token, &end, 10);
-    if (*end != '\0' || !NS_FloatIsFinite(aValues[i])) {
+    if (*end != '\0' || !NS_finite(aValues[i])) {
       return NS_ERROR_DOM_SYNTAX_ERR; // parse error
     }
   }
   if (i == 1) {
     aValues[1] = aValues[0];
   }
 
   if (i == 0                    ||                // Too few values.
--- a/content/svg/content/src/nsSVGLength2.cpp
+++ b/content/svg/content/src/nsSVGLength2.cpp
@@ -38,16 +38,17 @@
 
 #include "nsSVGLength2.h"
 #include "prdtoa.h"
 #include "nsTextFormatter.h"
 #include "nsSVGSVGElement.h"
 #include "nsIFrame.h"
 #include "nsSVGIntegrationUtils.h"
 #include "nsSVGAttrTearoffTable.h"
+#include "nsMathUtils.h"
 #ifdef MOZ_SMIL
 #include "nsSMILValue.h"
 #include "nsSMILFloatType.h"
 #endif // MOZ_SMIL
 
 NS_SVG_VAL_IMPL_CYCLE_COLLECTION(nsSVGLength2::DOMBaseVal, mSVGElement)
 
 NS_SVG_VAL_IMPL_CYCLE_COLLECTION(nsSVGLength2::DOMAnimVal, mSVGElement)
@@ -170,17 +171,17 @@ GetValueFromString(const nsAString &aVal
   NS_ConvertUTF16toUTF8 value(aValueAsString);
   const char *str = value.get();
 
   if (NS_IsAsciiWhitespace(*str))
     return NS_ERROR_DOM_SYNTAX_ERR;
   
   char *rest;
   *aValue = float(PR_strtod(str, &rest));
-  if (rest != str && NS_FloatIsFinite(*aValue)) {
+  if (rest != str && NS_finite(*aValue)) {
     *aUnitType = GetUnitTypeForString(rest);
     if (IsValidUnitType(*aUnitType)) {
       return NS_OK;
     }
   }
   
   return NS_ERROR_DOM_SYNTAX_ERR;
 }
--- a/content/svg/content/src/nsSVGNumber2.cpp
+++ b/content/svg/content/src/nsSVGNumber2.cpp
@@ -33,16 +33,17 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsSVGNumber2.h"
 #include "nsSVGUtils.h"
 #include "nsTextFormatter.h"
 #include "prdtoa.h"
+#include "nsMathUtils.h"
 #ifdef MOZ_SMIL
 #include "nsSMILValue.h"
 #include "nsSMILFloatType.h"
 #endif // MOZ_SMIL
 
 class DOMSVGNumber : public nsIDOMSVGNumber
 {
 public:
@@ -94,17 +95,17 @@ GetValueFromString(const nsAString &aVal
   NS_ConvertUTF16toUTF8 value(aValueAsString);
   const char *str = value.get();
 
   if (NS_IsAsciiWhitespace(*str))
     return NS_ERROR_DOM_SYNTAX_ERR;
   
   char *rest;
   *aValue = float(PR_strtod(str, &rest));
-  if (rest == str || !NS_FloatIsFinite(*aValue)) {
+  if (rest == str || !NS_finite(*aValue)) {
     return NS_ERROR_DOM_SYNTAX_ERR;
   }
   if (*rest == '%' && aPercentagesAllowed) {
     *aValue /= 100;
     ++rest;
   }
   if (*rest == '\0') {
     return NS_OK;
--- a/content/svg/content/src/nsSVGNumberPair.cpp
+++ b/content/svg/content/src/nsSVGNumberPair.cpp
@@ -34,16 +34,17 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsSVGNumberPair.h"
 #include "nsSVGUtils.h"
 #include "nsCharSeparatedTokenizer.h"
 #include "prdtoa.h"
 #include "nsDOMError.h"
+#include "nsMathUtils.h"
 #ifdef MOZ_SMIL
 #include "nsSMILValue.h"
 #include "SVGNumberPairSMILType.h"
 #endif // MOZ_SMIL
 
 using namespace mozilla;
 
 NS_SVG_VAL_IMPL_CYCLE_COLLECTION(nsSVGNumberPair::DOMAnimatedNumber, mSVGElement)
@@ -77,17 +78,17 @@ ParseNumberOptionalNumber(const nsAStrin
     NS_ConvertUTF16toUTF8 utf8Token(tokenizer.nextToken());
     const char *token = utf8Token.get();
     if (*token == '\0') {
       return NS_ERROR_DOM_SYNTAX_ERR; // empty string (e.g. two commas in a row)
     }
 
     char *end;
     aValues[i] = float(PR_strtod(token, &end));
-    if (*end != '\0' || !NS_FloatIsFinite(aValues[i])) {
+    if (*end != '\0' || !NS_finite(aValues[i])) {
       return NS_ERROR_DOM_SYNTAX_ERR; // parse error
     }
   }
   if (i == 1) {
     aValues[1] = aValues[0];
   }
 
   if (i == 0 ||                                   // Too few values.
--- a/content/svg/content/src/nsSVGTransformSMILAttr.cpp
+++ b/content/svg/content/src/nsSVGTransformSMILAttr.cpp
@@ -45,16 +45,17 @@
 #include "nsSVGMatrix.h"
 #include "nsSMILValue.h"
 #include "nsSMILNullType.h"
 #include "nsISMILAnimationElement.h"
 #include "nsSVGElement.h"
 #include "nsISVGValue.h"
 #include "prdtoa.h"
 #include "prlog.h"
+#include "nsMathUtils.h"
 
 nsresult
 nsSVGTransformSMILAttr::ValueFromString(const nsAString& aStr,
                                      const nsISMILAnimationElement* aSrcElement,
                                      nsSMILValue& aValue,
                                      PRBool& aPreventCachingOfSandwich) const
 {
   NS_ENSURE_TRUE(aSrcElement, NS_ERROR_FAILURE);
@@ -230,17 +231,17 @@ nsSVGTransformSMILAttr::ParseParameterLi
   SkipWsp(start, end);
 
   int numArgsFound = 0;
 
   while (start != end) {
     char const *arg = start.get();
     char *argend;
     float f = float(PR_strtod(arg, &argend));
-    if (arg == argend || argend > end.get() || !NS_FloatIsFinite(f))
+    if (arg == argend || argend > end.get() || !NS_finite(f))
       return -1;
 
     if (numArgsFound < aNVars) {
       aVars[numArgsFound] = f;
     }
 
     start.advance(argend - arg);
     numArgsFound++;
--- a/content/svg/content/src/nsSVGViewBox.cpp
+++ b/content/svg/content/src/nsSVGViewBox.cpp
@@ -36,16 +36,17 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsSVGViewBox.h"
 #include "nsSVGUtils.h"
 #include "prdtoa.h"
 #include "nsTextFormatter.h"
 #include "nsCharSeparatedTokenizer.h"
+#include "nsMathUtils.h"
 #ifdef MOZ_SMIL
 #include "nsSMILValue.h"
 #include "SVGViewBoxSMILType.h"
 #endif // MOZ_SMIL
 
 #define NUM_VIEWBOX_COMPONENTS 4
 using namespace mozilla;
 
@@ -151,17 +152,17 @@ ToSVGViewBoxRect(const nsAString& aStr, 
     NS_ConvertUTF16toUTF8 utf8Token(tokenizer.nextToken());
     const char *token = utf8Token.get();
     if (*token == '\0') {
       return NS_ERROR_DOM_SYNTAX_ERR; // empty string (e.g. two commas in a row)
     }
 
     char *end;
     vals[i] = float(PR_strtod(token, &end));
-    if (*end != '\0' || !NS_FloatIsFinite(vals[i])) {
+    if (*end != '\0' || !NS_finite(vals[i])) {
       return NS_ERROR_DOM_SYNTAX_ERR; // parse error
     }
   }
 
   if (i != NUM_VIEWBOX_COMPONENTS ||              // Too few values.
       tokenizer.hasMoreTokens() ||                // Too many values.
       tokenizer.lastTokenEndedWithSeparator()) {  // Trailing comma.
     return NS_ERROR_DOM_SYNTAX_ERR;
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -9346,22 +9346,24 @@ nsDocShell::ScrollToAnchor(nsACString & 
         // Tell the shell it's at an anchor, without scrolling.
         shell->GoToAnchor(EmptyString(), PR_FALSE);
         
         // An empty anchor was found, but if it's a load from history,
         // we don't have to jump to the top of the page. Scrollbar 
         // position will be restored by the caller, based on positions
         // stored in session history.
         if (aLoadType == LOAD_HISTORY || aLoadType == LOAD_RELOAD_NORMAL)
-            return rv;
-        //An empty anchor. Scroll to the top of the page.
-        rv = SetCurScrollPosEx(0, 0);
-    }
-
-    return rv;
+            return NS_OK;
+        // An empty anchor. Scroll to the top of the page.  Ignore the
+        // return value; failure to scroll here (e.g. if there is no
+        // root scrollframe) is not grounds for canceling the load!
+        SetCurScrollPosEx(0, 0);
+    }
+
+    return NS_OK;
 }
 
 void
 nsDocShell::SetupReferrerFromChannel(nsIChannel * aChannel)
 {
     nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(aChannel));
     if (httpChannel) {
         nsCOMPtr<nsIURI> referrer;
--- a/docshell/shistory/src/nsSHistory.cpp
+++ b/docshell/shistory/src/nsSHistory.cpp
@@ -1279,16 +1279,19 @@ nsSHistory::RemoveDuplicate(PRInt32 aInd
       mListRoot = txToKeep;
     }
     if (mRootDocShell) {
       static_cast<nsDocShell*>(mRootDocShell)->HistoryTransactionRemoved(aIndex);
     }
     if (mIndex > aIndex) {
       mIndex = mIndex - 1;
     }
+    if (mRequestedIndex > aIndex) {
+      mRequestedIndex = mRequestedIndex - 1;
+    }
     --mLength;
     return PR_TRUE;
   }
   return PR_FALSE;
 }
 
 NS_IMETHODIMP_(void)
 nsSHistory::RemoveEntries(nsTArray<PRUint64>& aIDs, PRInt32 aStartIndex)
--- a/docshell/test/Makefile.in
+++ b/docshell/test/Makefile.in
@@ -113,16 +113,17 @@ include $(topsrcdir)/config/rules.mk
 		file_bug662170.html \
 		test_bug570341.html \
 		bug570341_recordevents.html \
 		test_bug668513.html \
 		bug668513_redirect.html \
 		bug668513_redirect.html^headers^ \
 		test_bug669671.html \
 		file_bug669671.sjs \
+		test_bug675587.html \
 		$(NULL)
 
 ifeq ($(MOZ_WIDGET_TOOLKIT),cocoa)
 _TEST_FILES += \
 		test_bug511449.html \
 		file_bug511449.html \
 		$(NULL)
 endif
--- a/docshell/test/browser/Makefile.in
+++ b/docshell/test/browser/Makefile.in
@@ -57,12 +57,14 @@ include $(topsrcdir)/config/rules.mk
 		browser_bug503832.js \
 		browser_loadDisallowInherit.js \
 		file_bug503832.html \
 		browser_bug554155.js \
 		browser_bug655273.js \
 		browser_bug655270.js \
 		file_bug655270.html \
 		favicon_bug655270.ico \
+		browser_bug670318.js \
+		file_bug670318.html \
 		$(NULL)
 
 libs:: $(_BROWSER_TEST_FILES)
 	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/browser/$(relativesrcdir)
new file mode 100644
--- /dev/null
+++ b/docshell/test/browser/browser_bug670318.js
@@ -0,0 +1,59 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Test for Bug 670318
+ *
+ * When LoadEntry() is called on a browser that has multiple duplicate history
+ * entries, history.index can end up out of range (>= history.count).
+ */
+
+const URL = "http://mochi.test:8888/browser/docshell/test/browser/file_bug670318.html";
+
+function test() {
+  waitForExplicitFinish();
+
+  let count = 0, historyListenerRemoved = false;
+
+  let listener = {
+    OnHistoryNewEntry: function (aNewURI) {
+      if (aNewURI.spec == URL && 5 == ++count) {
+        browser.addEventListener("load", function onLoad() {
+          browser.removeEventListener("load", onLoad, true);
+
+          ok(history.index < history.count, "history.index is valid");
+          finish();
+        }, true);
+
+        history.removeSHistoryListener(listener);
+        historyListenerRemoved = true;
+
+        executeSoon(function () BrowserReload());
+      }
+
+      return true;
+    },
+
+    OnHistoryReload: function () true,
+    OnHistoryGoBack: function () true,
+    OnHistoryGoForward: function () true,
+    OnHistoryGotoIndex: function () true,
+    OnHistoryPurge: function () true,
+
+    QueryInterface: XPCOMUtils.generateQI([Ci.nsISHistoryListener,
+                                           Ci.nsISupportsWeakReference])
+  };
+
+  let tab = gBrowser.loadOneTab(URL, {inBackground: false});
+  let browser = tab.linkedBrowser;
+  let history = browser.sessionHistory;
+
+  history.addSHistoryListener(listener);
+
+  registerCleanupFunction(function () {
+    gBrowser.removeTab(tab);
+
+    if (!historyListenerRemoved)
+      history.removeSHistoryListener(listener);
+  });
+}
new file mode 100644
--- /dev/null
+++ b/docshell/test/browser/file_bug670318.html
@@ -0,0 +1,23 @@
+<html><head>
+<meta http-equiv="content-type" content="text/html; charset=UTF-8">
+<script>
+function load() {
+  function next() {
+    if (count < 5)
+      iframe.src = 'data:text/html,iframe ' + (++count);
+  }
+
+  var count = 0;
+  var iframe = document.createElement('iframe');
+  iframe.onload = function () { setTimeout(next, 0) };
+  document.body.appendChild(iframe);
+
+  setTimeout(next, 0);
+}
+</script>
+</head>
+
+<body onload="load()">
+Testcase
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/docshell/test/test_bug675587.html
@@ -0,0 +1,35 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=675587
+-->
+<head>
+  <title>Test for Bug 675587</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=675587">Mozilla Bug 675587</a>
+<p id="display">
+  <iframe src="data:text/html,<script>location.hash='';</script>#hash"></iframe>
+</p>
+<div id="content" style="display: none">
+  
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 675587 **/
+SimpleTest.waitForExplicitFinish();
+addLoadEvent(function() {
+  is(window.frames[0].location.href,
+     "data:text/html,<script>location.hash='';</" + "script>#",
+     "Should have the right href");
+  SimpleTest.finish();
+});
+
+</script>
+</pre>
+</body>
+</html>
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -193,17 +193,16 @@
 // XBL related includes.
 #include "nsIXBLService.h"
 #include "nsXBLBinding.h"
 #include "nsBindingManager.h"
 #include "nsIFrame.h"
 #include "nsIPresShell.h"
 #include "nsIDOMElement.h"
 #include "nsIDOMCSSStyleDeclaration.h"
-#include "nsStyleSet.h"
 #include "nsStyleContext.h"
 #include "nsAutoPtr.h"
 #include "nsMemory.h"
 
 // Tranformiix
 #include "nsIDOMXPathEvaluator.h"
 #include "nsIXSLTProcessor.h"
 #include "nsIXSLTProcessorPrivate.h"
--- a/dom/indexedDB/IDBObjectStore.cpp
+++ b/dom/indexedDB/IDBObjectStore.cpp
@@ -237,20 +237,17 @@ private:
   nsCString mContinueQuery;
   nsCString mContinueToQuery;
   Key mRangeKey;
 };
 
 class CreateIndexHelper : public AsyncConnectionHelper
 {
 public:
-  CreateIndexHelper(IDBTransaction* aTransaction,
-                    IDBIndex* aIndex)
-  : AsyncConnectionHelper(aTransaction, nsnull), mIndex(aIndex)
-  { }
+  CreateIndexHelper(IDBTransaction* aTransaction, IDBIndex* aIndex);
 
   nsresult DoDatabaseWork(mozIStorageConnection* aConnection);
 
   nsresult OnSuccess()
   {
     return NS_OK;
   }
 
@@ -263,20 +260,27 @@ public:
   {
     mIndex = nsnull;
     AsyncConnectionHelper::ReleaseMainThreadObjects();
   }
 
 private:
   nsresult InsertDataFromObjectStore(mozIStorageConnection* aConnection);
 
+  static void DestroyTLSEntry(void* aPtr);
+
+  static PRUintn sTLSIndex;
+
   // In-params.
   nsRefPtr<IDBIndex> mIndex;
 };
 
+static const PRUintn BAD_TLS_INDEX = (PRUint32)-1;
+PRUintn CreateIndexHelper::sTLSIndex = BAD_TLS_INDEX;
+
 class DeleteIndexHelper : public AsyncConnectionHelper
 {
 public:
   DeleteIndexHelper(IDBTransaction* aTransaction,
                     const nsAString& aName,
                     IDBObjectStore* aObjectStore)
   : AsyncConnectionHelper(aTransaction, nsnull), mName(aName),
     mObjectStore(aObjectStore)
@@ -586,36 +590,28 @@ IDBObjectStore::GetJSValFromKey(const Ke
   return NS_ERROR_DOM_INDEXEDDB_DATA_ERR;
 }
 
 // static
 nsresult
 IDBObjectStore::GetKeyPathValueFromStructuredData(const PRUint8* aData,
                                                   PRUint32 aDataLength,
                                                   const nsAString& aKeyPath,
-                                                  JSContext** aCx,
+                                                  JSContext* aCx,
                                                   Key& aValue)
 {
   NS_ASSERTION(aData, "Null pointer!");
   NS_ASSERTION(aDataLength, "Empty data!");
   NS_ASSERTION(!aKeyPath.IsEmpty(), "Empty keyPath!");
   NS_ASSERTION(aCx, "Null pointer!");
 
-  nsresult rv;
-
-  if (!*aCx) {
-    rv = nsContentUtils::ThreadJSContextStack()->GetSafeJSContext(aCx);
-    NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
-  }
-  JSContext*& cx = *aCx;
-
-  JSAutoRequest ar(cx);
+  JSAutoRequest ar(aCx);
 
   jsval clone;
-  if (!JS_ReadStructuredClone(cx, reinterpret_cast<const uint64*>(aData),
+  if (!JS_ReadStructuredClone(aCx, reinterpret_cast<const uint64*>(aData),
                               aDataLength, JS_STRUCTURED_CLONE_VERSION,
                               &clone, NULL, NULL)) {
     return NS_ERROR_DOM_DATA_CLONE_ERR;
   }
 
   if (JSVAL_IS_PRIMITIVE(clone)) {
     // This isn't an object, so just leave the key unset.
     aValue = Key::UNSETKEY;
@@ -624,20 +620,20 @@ IDBObjectStore::GetKeyPathValueFromStruc
 
   JSObject* obj = JSVAL_TO_OBJECT(clone);
 
   const jschar* keyPathChars =
     reinterpret_cast<const jschar*>(aKeyPath.BeginReading());
   const size_t keyPathLen = aKeyPath.Length();
 
   jsval keyVal;
-  JSBool ok = JS_GetUCProperty(cx, obj, keyPathChars, keyPathLen, &keyVal);
+  JSBool ok = JS_GetUCProperty(aCx, obj, keyPathChars, keyPathLen, &keyVal);
   NS_ENSURE_TRUE(ok, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
-  rv = GetKeyFromJSVal(keyVal, *aCx, aValue);
+  nsresult rv = GetKeyFromJSVal(keyVal, aCx, aValue);
   if (NS_FAILED(rv)) {
     // If the object doesn't have a value that we can use for our index then we
     // leave it unset.
     aValue = Key::UNSETKEY;
   }
 
   return NS_OK;
 }
@@ -2199,16 +2195,103 @@ OpenCursorHelper::GetSuccessResult(JSCon
                       mCloneBuffer);
   NS_ENSURE_TRUE(cursor, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   NS_ASSERTION(!mCloneBuffer.data(), "Should have swapped!");
 
   return WrapNative(aCx, cursor, aVal);
 }
 
+class ThreadLocalJSRuntime
+{
+  JSRuntime* mRuntime;
+  JSContext* mContext;
+  JSObject* mGlobal;
+
+  static JSClass sGlobalClass;
+  static const unsigned sRuntimeHeapSize = 64 * 1024;  // should be enough for anyone
+
+  ThreadLocalJSRuntime()
+  : mRuntime(NULL), mContext(NULL), mGlobal(NULL)
+  {
+      MOZ_COUNT_CTOR(ThreadLocalJSRuntime);
+  }
+
+  nsresult Init()
+  {
+    mRuntime = JS_NewRuntime(sRuntimeHeapSize);
+    NS_ENSURE_TRUE(mRuntime, NS_ERROR_OUT_OF_MEMORY);
+
+    mContext = JS_NewContext(mRuntime, 0);
+    NS_ENSURE_TRUE(mContext, NS_ERROR_OUT_OF_MEMORY);
+
+    JSAutoRequest ar(mContext);
+
+    mGlobal = JS_NewCompartmentAndGlobalObject(mContext, &sGlobalClass, NULL);
+    NS_ENSURE_TRUE(mGlobal, NS_ERROR_OUT_OF_MEMORY);
+
+    JS_SetGlobalObject(mContext, mGlobal);
+    return NS_OK;
+  }
+
+ public:
+  static ThreadLocalJSRuntime *Create()
+  {
+    ThreadLocalJSRuntime *entry = new ThreadLocalJSRuntime();
+    NS_ENSURE_TRUE(entry, nsnull);
+
+    if (NS_FAILED(entry->Init())) {
+      delete entry;
+      return nsnull;
+    }
+
+    return entry;
+  }
+
+  JSContext *Context() const
+  {
+    return mContext;
+  }
+
+  ~ThreadLocalJSRuntime()
+  {
+    MOZ_COUNT_DTOR(ThreadLocalJSRuntime);
+
+    if (mContext) {
+      JS_DestroyContext(mContext);
+    }
+
+    if (mRuntime) {
+      JS_DestroyRuntime(mRuntime);
+    }
+  }
+};
+
+JSClass ThreadLocalJSRuntime::sGlobalClass = {
+  "IndexedDBTransactionThreadGlobal",
+  JSCLASS_GLOBAL_FLAGS,
+  JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
+  JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub
+};
+
+CreateIndexHelper::CreateIndexHelper(IDBTransaction* aTransaction,
+                                     IDBIndex* aIndex)
+  : AsyncConnectionHelper(aTransaction, nsnull), mIndex(aIndex)
+{
+  if (sTLSIndex == BAD_TLS_INDEX) {
+    PR_NewThreadPrivateIndex(&sTLSIndex, DestroyTLSEntry);
+  }
+}
+
+void
+CreateIndexHelper::DestroyTLSEntry(void* aPtr)
+{
+  delete reinterpret_cast<ThreadLocalJSRuntime *>(aPtr);
+}
+
 nsresult
 CreateIndexHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
 {
   // Insert the data into the database.
   nsCOMPtr<mozIStorageStatement> stmt =
     mTransaction->GetCachedStatement(
     "INSERT INTO object_store_index (id, name, key_path, unique_index, "
       "object_store_id, object_store_autoincrement) "
@@ -2329,21 +2412,32 @@ CreateIndexHelper::InsertDataFromObjectS
       NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
     }
 
     const PRUint8* data;
     PRUint32 dataLength;
     rv = stmt->GetSharedBlob(1, &dataLength, &data);
     NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
+    NS_ENSURE_TRUE(sTLSIndex != BAD_TLS_INDEX, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+
+    ThreadLocalJSRuntime* tlsEntry =
+      reinterpret_cast<ThreadLocalJSRuntime*>(PR_GetThreadPrivate(sTLSIndex));
+
+    if (!tlsEntry) {
+      tlsEntry = ThreadLocalJSRuntime::Create();
+      NS_ENSURE_TRUE(tlsEntry, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+
+      PR_SetThreadPrivate(sTLSIndex, tlsEntry);
+    }
+
     Key key;
-    JSContext* cx = nsnull;
     rv = IDBObjectStore::GetKeyPathValueFromStructuredData(data, dataLength,
                                                            mIndex->KeyPath(),
-                                                           &cx, key);
+                                                           tlsEntry->Context(), key);
     NS_ENSURE_SUCCESS(rv, rv);
 
     if (key.IsUnset()) {
       continue;
     }
 
     NS_NAMED_LITERAL_CSTRING(value, "value");
     if (key.IsInt()) {
--- a/dom/indexedDB/IDBObjectStore.h
+++ b/dom/indexedDB/IDBObjectStore.h
@@ -85,17 +85,17 @@ public:
   GetJSValFromKey(const Key& aKey,
                   JSContext* aCx,
                   jsval* aKeyVal);
 
   static nsresult
   GetKeyPathValueFromStructuredData(const PRUint8* aData,
                                     PRUint32 aDataLength,
                                     const nsAString& aKeyPath,
-                                    JSContext** aCx,
+                                    JSContext* aCx,
                                     Key& aValue);
 
   static nsresult
   GetIndexUpdateInfo(ObjectStoreInfo* aObjectStoreInfo,
                      JSContext* aCx,
                      jsval aObject,
                      nsTArray<IndexUpdateInfo>& aUpdateInfoArray);
 
--- a/dom/plugins/base/nsPluginHost.cpp
+++ b/dom/plugins/base/nsPluginHost.cpp
@@ -1062,17 +1062,16 @@ nsPluginHost::InstantiateEmbeddedPlugin(
   nsRefPtr<nsNPAPIPluginInstance> instance;
   rv = aOwner->GetInstance(getter_AddRefs(instance));
   // if we have a failure error, it means we found a plugin for the mimetype,
   // but we had a problem with the entry point
   if (rv == NS_ERROR_FAILURE)
     return rv;
 
   if (instance) {
-    instance->Start();
     aOwner->CreateWidget();
 
     // If we've got a native window, the let the plugin know about it.
     aOwner->SetWindow();
 
     // create an initial stream with data
     // don't make the stream if it's a java applet or we don't have SRC or DATA attribute
     PRBool havedata = PR_FALSE;
@@ -1121,17 +1120,16 @@ nsresult nsPluginHost::InstantiateFullPa
   if (NS_OK == rv) {
     nsRefPtr<nsNPAPIPluginInstance> instance;
     aOwner->GetInstance(getter_AddRefs(instance));
 
     NPWindow* win = nsnull;
     aOwner->GetWindow(win);
 
     if (win && instance) {
-      instance->Start();
       aOwner->CreateWidget();
 
       // If we've got a native window, the let the plugin know about it.
       aOwner->SetWindow();
 
       rv = NewFullPagePluginStream(aURI, instance.get(), aStreamListener);
 
       // If we've got a native window, the let the plugin know about it.
--- a/dom/plugins/base/nsPluginStreamListenerPeer.cpp
+++ b/dom/plugins/base/nsPluginStreamListenerPeer.cpp
@@ -653,17 +653,16 @@ nsPluginStreamListenerPeer::OnStartReque
     mOwner->GetWindow(window);
     if (!mPluginInstance && window) {
       nsRefPtr<nsPluginHost> pluginHost = dont_AddRef(nsPluginHost::GetInst());
       rv = pluginHost->SetUpPluginInstance(aContentType.get(), aURL, mOwner);
       if (NS_SUCCEEDED(rv)) {
         mOwner->GetInstance(getter_AddRefs(pluginInstRefPtr));
         mPluginInstance = pluginInstRefPtr.get();
         if (mPluginInstance) {
-          mPluginInstance->Start();
           mOwner->CreateWidget();
           // If we've got a native window, the let the plugin know about it.
           mOwner->SetWindow();
         }
       }
     }
   }
   
--- a/dom/plugins/ipc/PluginInstanceChild.cpp
+++ b/dom/plugins/ipc/PluginInstanceChild.cpp
@@ -1284,20 +1284,16 @@ PluginInstanceChild::PluginWindowProcInt
       self->CallPluginFocusChange(true);
 
     // Prevent lockups due to plugins making rpc calls when the parent
     // is making a synchronous SendMessage call to the child window. Add
     // more messages as needed.
     if ((InSendMessageEx(NULL)&(ISMEX_REPLIED|ISMEX_SEND)) == ISMEX_SEND) {
         switch(message) {
             case WM_KILLFOCUS:
-            case WM_MOUSEHWHEEL:
-            case WM_MOUSEWHEEL:
-            case WM_HSCROLL:
-            case WM_VSCROLL:
             ReplyMessage(0);
             break;
         }
     }
 
     if (message == WM_KILLFOCUS)
       self->CallPluginFocusChange(false);
 
--- a/dom/src/storage/nsDOMStorage.cpp
+++ b/dom/src/storage/nsDOMStorage.cpp
@@ -1083,17 +1083,17 @@ class ItemCounterState
 {
  public:
   ItemCounterState(PRBool aIsCallerSecure)
   : mIsCallerSecure(aIsCallerSecure), mCount(0)
   {
   }
 
   PRBool mIsCallerSecure;
-  PRBool mCount;
+  PRUint32 mCount;
  private:
   ItemCounterState(); // Not to be implemented
 };
 
 static PLDHashOperator
 ItemCounter(nsSessionStorageEntry* aEntry, void* userArg)
 {
   ItemCounterState *state = (ItemCounterState *)userArg;
--- a/dom/workers/RuntimeService.cpp
+++ b/dom/workers/RuntimeService.cpp
@@ -39,41 +39,45 @@
 #include "RuntimeService.h"
 
 #include "nsIDOMChromeWindow.h"
 #include "nsIDocument.h"
 #include "nsIEffectiveTLDService.h"
 #include "nsIObserverService.h"
 #include "nsIPrincipal.h"
 #include "nsIJSContextStack.h"
+#include "nsIMemoryReporter.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsISupportsPriority.h"
 #include "nsITimer.h"
 #include "nsPIDOMWindow.h"
 
+#include "jsprf.h"
 #include "mozilla/Preferences.h"
 #include "nsContentUtils.h"
 #include "nsDOMJSUtils.h"
 #include "nsGlobalWindow.h"
 #include "nsNetUtil.h"
 #include "nsServiceManagerUtils.h"
 #include "nsThreadUtils.h"
 #include "nsXPCOM.h"
 #include "nsXPCOMPrivate.h"
+#include "xpcpublic.h"
 
 #include "Events.h"
 #include "EventTarget.h"
 #include "Worker.h"
 #include "WorkerPrivate.h"
 
 USING_WORKERS_NAMESPACE
 
 using mozilla::MutexAutoLock;
 using mozilla::MutexAutoUnlock;
 using mozilla::Preferences;
+using namespace mozilla::xpconnect::memory;
 
 // The size of the worker runtime heaps in bytes.
 #define WORKER_RUNTIME_HEAPSIZE 32 * 1024 * 1024
 
 // The size of the C stack in bytes.
 #define WORKER_CONTEXT_NATIVE_STACK_LIMIT sizeof(size_t) * 32 * 1024
 
 // The maximum number of threads to use for workers, overridable via pref.
@@ -280,16 +284,80 @@ CreateJSContextForWorker(WorkerPrivate* 
 
   if (aWorkerPrivate->IsChromeWorker()) {
     JS_SetVersion(workerCx, JSVERSION_LATEST);
   }
 
   return workerCx;
 }
 
+class WorkerMemoryReporter : public nsIMemoryMultiReporter
+{
+  JSRuntime* mRuntime;
+  nsCString mPathPrefix;
+
+public:
+  NS_DECL_ISUPPORTS
+
+  WorkerMemoryReporter(WorkerPrivate* aWorkerPrivate, JSRuntime* aRuntime)
+  : mRuntime(aRuntime)
+  {
+    NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
+
+    nsCString escapedDomain(aWorkerPrivate->Domain());
+    escapedDomain.ReplaceChar('/', '\\');
+
+    NS_ConvertUTF16toUTF8 escapedURL(aWorkerPrivate->ScriptURL());
+    escapedURL.ReplaceChar('/', '\\');
+
+    // 64bit address plus '0x' plus null terminator.
+    char address[21];
+    JSUint32 addressSize =
+      JS_snprintf(address, sizeof(address), "0x%llx", aWorkerPrivate);
+    if (addressSize == JSUint32(-1)) {
+      NS_WARNING("JS_snprintf failed!");
+      address[0] = '\0';
+      addressSize = 0;
+    }
+
+    mPathPrefix = NS_LITERAL_CSTRING("explicit/dom/workers(") +
+                  escapedDomain + NS_LITERAL_CSTRING(")/worker(") +
+                  escapedURL + NS_LITERAL_CSTRING(", ") +
+                  nsDependentCString(address, addressSize) +
+                  NS_LITERAL_CSTRING(")/");
+  }
+
+  NS_IMETHOD
+  CollectReports(nsIMemoryMultiReporterCallback* aCallback,
+                 nsISupports* aClosure)
+  {
+    AssertIsOnMainThread();
+
+    JS_TriggerAllOperationCallbacks(mRuntime);
+
+    IterateData data;
+    if (!CollectCompartmentStatsForRuntime(mRuntime, &data)) {
+      return NS_ERROR_FAILURE;
+    }
+
+    for (CompartmentStats *stats = data.compartmentStatsVector.begin();
+         stats != data.compartmentStatsVector.end();
+         ++stats)
+    {
+      ReportCompartmentStats(*stats, mPathPrefix, aCallback, aClosure);
+    }
+
+    ReportJSStackSizeForRuntime(mRuntime, mPathPrefix, aCallback, aClosure);
+
+    return NS_OK;
+  }
+};
+
+NS_IMPL_THREADSAFE_ISUPPORTS1(WorkerMemoryReporter, nsIMemoryMultiReporter)
+
 class WorkerThreadRunnable : public nsRunnable
 {
   WorkerPrivate* mWorkerPrivate;
 
 public:
   WorkerThreadRunnable(WorkerPrivate* aWorkerPrivate)
   : mWorkerPrivate(aWorkerPrivate)
   {
@@ -306,22 +374,33 @@ public:
 
     JSContext* cx = CreateJSContextForWorker(workerPrivate);
     if (!cx) {
       // XXX need to fire an error at parent.
       NS_ERROR("Failed to create runtime and context!");
       return NS_ERROR_FAILURE;
     }
 
-    {
-      JSAutoRequest ar(cx);
-      workerPrivate->DoRunLoop(cx);
+    JSRuntime* rt = JS_GetRuntime(cx);
+
+    nsRefPtr<WorkerMemoryReporter> reporter =
+      new WorkerMemoryReporter(workerPrivate, rt);
+    if (NS_FAILED(NS_RegisterMemoryMultiReporter(reporter))) {
+      NS_WARNING("Failed to register memory reporter!");
+      reporter = nsnull;
     }
 
-    JSRuntime* rt = JS_GetRuntime(cx);
+    workerPrivate->DoRunLoop(cx);
+
+    if (reporter) {
+      if (NS_FAILED(NS_UnregisterMemoryMultiReporter(reporter))) {
+        NS_WARNING("Failed to unregister memory reporter!");
+      }
+      reporter = nsnull;
+    }
 
     // XXX Bug 666963 - CTypes can create another JSContext for use with
     // closures, and then it holds that context in a reserved slot on the CType
     // prototype object. We have to destroy that context before we can destroy
     // the runtime, and we also have to make sure that it isn't the last context
     // to be destroyed (otherwise it will assert). To accomplish this we create
     // an unused dummy context, destroy our real context, and then destroy the
     // dummy. Once this bug is resolved we can remove this nastiness and simply
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -2037,28 +2037,32 @@ WorkerPrivate::DoRunLoop(JSContext* aCx)
 
       while (!mControlQueue.Pop(event) && !mQueue.Pop(event)) {
         mCondVar.Wait();
       }
 
       {
         MutexAutoUnlock unlock(mMutex);
 
+        JSAutoRequest ar(aCx);
+
 #ifdef EXTRA_GC
         // Find GC bugs...
         JS_GC(aCx);
 #endif
 
         event->Run();
         NS_RELEASE(event);
       }
 
       currentStatus = mStatus;
     }
 
+    JSAutoRequest ar(aCx);
+
 #ifdef EXTRA_GC
     // Find GC bugs...
     JS_GC(aCx);
 #endif
 
     if (currentStatus != Running && !HasActiveFeatures()) {
       // If the close handler has finished and all features are done then we can
       // kill this thread.
@@ -2088,16 +2092,18 @@ WorkerPrivate::DoRunLoop(JSContext* aCx)
   NS_NOTREACHED("Shouldn't get here!");
 }
 
 bool
 WorkerPrivate::OperationCallback(JSContext* aCx)
 {
   AssertIsOnWorkerThread();
 
+  JS_YieldRequest(aCx);
+
   bool mayContinue = true;
 
   for (;;) {
     // Run all control events now.
     for (;;) {
       nsIRunnable* event;
       {
         MutexAutoLock lock(mMutex);
@@ -2121,16 +2127,18 @@ WorkerPrivate::OperationCallback(JSConte
     JS_FlushCaches(aCx);
     JS_GC(aCx);
 
     while ((mayContinue = MayContinueRunning())) {
       MutexAutoLock lock(mMutex);
       if (!mControlQueue.IsEmpty()) {
         break;
       }
+
+      JSAutoSuspendRequest asr(aCx);
       mCondVar.Wait(PR_MillisecondsToInterval(RemainingRunTimeMS()));
     }
   }
 
   if (!mayContinue) {
     // We want only uncatchable exceptions here.
     NS_ASSERTION(!JS_IsExceptionPending(aCx),
                  "Should not have an exception set here!");
@@ -2475,16 +2483,17 @@ WorkerPrivate::RunSyncLoop(JSContext* aC
   SyncQueue* syncQueue = mSyncQueues[aSyncLoopKey].get();
 
   for (;;) {
     nsIRunnable* event;
     {
       MutexAutoLock lock(mMutex);
 
       while (!mControlQueue.Pop(event) && !syncQueue->mQueue.Pop(event)) {
+        JSAutoSuspendRequest asr(aCx);
         mCondVar.Wait();
       }
     }
 
 #ifdef EXTRA_GC
     // Find GC bugs...
     JS_GC(mJSContext);
 #endif
--- a/editor/idl/nsIURIRefObject.idl
+++ b/editor/idl/nsIURIRefObject.idl
@@ -30,19 +30,16 @@
  * 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 ***** */
 
-#ifndef nsIURIRefObject_h__
-#define nsIURIRefObject_h__
-
 #include "nsISupports.idl"
 #include "domstubs.idl"
 
 interface nsIDOMNode;
 
 /** A class which can represent any node which points to an
   * external URI, e.g. <a>, <img>, <script> etc,
   * and has the capability to rewrite URLs to be
@@ -71,11 +68,8 @@ interface nsIURIRefObject  : nsISupports
    *
    * @param aOldPat  Old pattern to be replaced, e.g. file:///a/b/
    * @param aNewPat  New pattern to be replaced, e.g. http://mypage.aol.com/
    * @param aMakeRel Rewrite links as relative vs. absolute
    */
   void RewriteAllURIs(in DOMString aOldPat, in DOMString aNewPat,
                       in boolean aMakeRel);
 };
-
-#endif /* nsIURIRefObject_h__ */
-
--- a/embedding/android/GeckoApp.java
+++ b/embedding/android/GeckoApp.java
@@ -388,24 +388,27 @@ abstract public class GeckoApp
         // without going through onDestroy.
         //
         // We might also get an onRestart after this; not sure what
         // that would mean for Gecko if we were to kill it here.
         // Instead, what we should do here is save prefs, session,
         // etc., and generally mark the profile as 'clean', and then
         // dirty it again if we get an onResume.
 
+
         GeckoAppShell.sendEventToGecko(new GeckoEvent(GeckoEvent.ACTIVITY_STOPPING));
         super.onStop();
+        GeckoAppShell.putChildInBackground();
     }
 
     @Override
     public void onRestart()
     {
         Log.i("GeckoApp", "restart");
+        GeckoAppShell.putChildInForeground();
         super.onRestart();
     }
 
     @Override
     public void onStart()
     {
         Log.i("GeckoApp", "start");
         super.onStart();
@@ -663,17 +666,17 @@ abstract public class GeckoApp
 
     private SynchronousQueue<String> mFilePickerResult = new SynchronousQueue();
     public String showFilePicker(String aMimeType) {
         Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
         intent.addCategory(Intent.CATEGORY_OPENABLE);
         intent.setType(aMimeType);
         GeckoApp.this.
             startActivityForResult(
-                Intent.createChooser(intent,"choose a file"),
+                Intent.createChooser(intent, getString(R.string.choose_file)),
                 FILE_PICKER_REQUEST);
         String filePickerResult = "";
         try {
             filePickerResult = mFilePickerResult.take();
         } catch (InterruptedException e) {
             Log.i("GeckoApp", "showing file picker ",  e);
         }
 
--- a/embedding/android/GeckoAppShell.java
+++ b/embedding/android/GeckoAppShell.java
@@ -1160,16 +1160,62 @@ public class GeckoAppShell
                 result[idx] = color;
             }
             appearance.recycle();
         }
 
         return result;
     }
 
+    public static void putChildInBackground() {
+        try {
+            File cgroupFile = new File("/proc" + android.os.Process.myPid() + "/cgroup");
+            BufferedReader br = new BufferedReader(new FileReader(cgroupFile));
+            String[] cpuLine = br.readLine().split("/");
+            br.close();
+            final String backgroundGroup = cpuLine.length == 2 ? cpuLine[1] : "";
+            GeckoProcessesVisitor visitor = new GeckoProcessesVisitor() {
+                public boolean callback(int pid) {
+                    if (pid != android.os.Process.myPid()) {
+                        try {
+                            FileOutputStream fos = new FileOutputStream(
+                                new File("/dev/cpuctl/" + backgroundGroup +"/tasks"));
+                            fos.write(new Integer(pid).toString().getBytes());
+                            fos.close();
+                        } catch(Exception e) {
+                            Log.e("GeckoAppShell", "error putting child in the background", e);
+                        }
+                    }
+                    return true;
+                }
+            };
+            EnumerateGeckoProcesses(visitor);
+        } catch (Exception e) {
+            Log.e("GeckoInputStream", "error reading cgroup", e);
+        }
+    }
+
+    public static void putChildInForeground() {
+        GeckoProcessesVisitor visitor = new GeckoProcessesVisitor() {
+            public boolean callback(int pid) {
+                if (pid != android.os.Process.myPid()) {
+                    try {
+                        FileOutputStream fos = new FileOutputStream(new File("/dev/cpuctl/tasks"));
+                        fos.write(new Integer(pid).toString().getBytes());
+                        fos.close();
+                    } catch(Exception e) {
+                        Log.e("GeckoAppShell", "error putting child in the foreground", e);
+                    }
+                }
+                return true;
+            }
+        };   
+        EnumerateGeckoProcesses(visitor);
+    }
+
     public static void killAnyZombies() {
         GeckoProcessesVisitor visitor = new GeckoProcessesVisitor() {
             public boolean callback(int pid) {
                 if (pid != android.os.Process.myPid())
                     android.os.Process.killProcess(pid);
                 return true;
             }
         };
--- a/embedding/android/locales/en-US/android_strings.dtd
+++ b/embedding/android/locales/en-US/android_strings.dtd
@@ -14,8 +14,10 @@
 <!ENTITY  crash_close_label "Close">
 <!ENTITY  crash_restart_label "Restart &brandShortName;">
 <!ENTITY  sending_crash_report "Sending crash report\u2026">
 <!ENTITY  exit_label "Exit">
 <!ENTITY  continue_label "Continue">
 
 <!ENTITY  launcher_shortcuts_title "&brandShortName; Web Apps">
 <!ENTITY  launcher_shortcuts_empty "No web apps were found">
+
+<!ENTITY choose_file "Choose File">
--- a/embedding/android/strings.xml.in
+++ b/embedding/android/strings.xml.in
@@ -19,9 +19,11 @@
   <string name="crash_close_label">&crash_close_label;</string>
   <string name="crash_restart_label">&crash_restart_label;</string>
   <string name="sending_crash_report">&sending_crash_report;</string>
   <string name="exit_label">&exit_label;</string>
   <string name="continue_label">&continue_label;</string>
 
   <string name="launcher_shortcuts_title">&launcher_shortcuts_title;</string>
   <string name="launcher_shortcuts_empty">&launcher_shortcuts_empty;</string>
+  
+  <string name="choose_file">&choose_file;</string>
 </resources>
--- a/intl/lwbrk/public/nsILineBreaker.h
+++ b/intl/lwbrk/public/nsILineBreaker.h
@@ -60,19 +60,19 @@ public:
 
   // Call this on a word with whitespace at either end. We will apply JISx4501
   // rules to find breaks inside the word. aBreakBefore is set to the break-
   // before status of each character; aBreakBefore[0] will always be false
   // because we never return a break before the first character.
   // aLength is the length of the aText array and also the length of the aBreakBefore
   // output array.
   virtual void GetJISx4051Breaks(const PRUnichar* aText, PRUint32 aLength,
-                                 PRPackedBool* aBreakBefore) = 0;
+                                 PRUint8* aBreakBefore) = 0;
   virtual void GetJISx4051Breaks(const PRUint8* aText, PRUint32 aLength,
-                                 PRPackedBool* aBreakBefore) = 0;
+                                 PRUint8* aBreakBefore) = 0;
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsILineBreaker, NS_ILINEBREAKER_IID)
 
 static inline PRBool
 NS_IsSpace(PRUnichar u)
 {
   return u == 0x0020 ||                  // SPACE
--- a/intl/lwbrk/src/nsCarbonBreaker.cpp
+++ b/intl/lwbrk/src/nsCarbonBreaker.cpp
@@ -37,22 +37,22 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsComplexBreaker.h"
 #include <Carbon/Carbon.h>
 
 void
 NS_GetComplexLineBreaks(const PRUnichar* aText, PRUint32 aLength,
-                        PRPackedBool* aBreakBefore)
+                        PRUint8* aBreakBefore)
 {
   NS_ASSERTION(aText, "aText shouldn't be null");
   TextBreakLocatorRef breakLocator;
 
-  memset(aBreakBefore, PR_FALSE, aLength * sizeof(PRPackedBool));
+  memset(aBreakBefore, PR_FALSE, aLength * sizeof(PRUint8));
 
   OSStatus status = UCCreateTextBreakLocator(NULL, 0, kUCTextBreakLineMask, &breakLocator);
 
   if (status != noErr)
     return;
      
   for (UniCharArrayOffset position = 0; position < aLength;) {
     UniCharArrayOffset offset;
--- a/intl/lwbrk/src/nsComplexBreaker.h
+++ b/intl/lwbrk/src/nsComplexBreaker.h
@@ -42,11 +42,11 @@
 
 /**
  * Find line break opportunities in aText[] of aLength characters,
  * filling boolean values indicating line break opportunities for
  * corresponding charactersin aBreakBefore[] on return.
  */
 void
 NS_GetComplexLineBreaks(const PRUnichar* aText, PRUint32 aLength,
-                        PRPackedBool* aBreakBefore);
+                        PRUint8* aBreakBefore);
 
 #endif  /* nsComplexBreaker_h__ */
--- a/intl/lwbrk/src/nsJISx4501LineBreaker.cpp
+++ b/intl/lwbrk/src/nsJISx4501LineBreaker.cpp
@@ -781,17 +781,17 @@ nsJISx4051LineBreaker::WordMove(const PR
   }
   for (end = aPos + 1; end < PRInt32(aLen) && !NS_IsSpace(aText[end]); ++end) {
     if (IS_CJK_CHAR(aText[end]) || NS_NeedsPlatformNativeHandling(aText[end])) {
       textNeedsJISx4051 = PR_TRUE;
     }
   }
 
   PRInt32 ret;
-  nsAutoTArray<PRPackedBool, 2000> breakState;
+  nsAutoTArray<PRUint8, 2000> breakState;
   if (!textNeedsJISx4051 || !breakState.AppendElements(end - begin)) {
     // No complex text character, do not try to do complex line break.
     // (This is required for serializers. See Bug #344816.)
     // Also fall back to this when out of memory.
     if (aDirection < 0) {
       ret = (begin == PRInt32(aPos)) ? begin - 1 : begin;
     } else {
       ret = end;
@@ -828,17 +828,17 @@ nsJISx4051LineBreaker::Prev(const PRUnic
                "Bad position passed to nsJISx4051LineBreaker::Prev");
 
   PRInt32 prevPos = WordMove(aText, aLen, aPos, -1);
   return prevPos > 0 ? prevPos : NS_LINEBREAKER_NEED_MORE_TEXT;
 }
 
 void
 nsJISx4051LineBreaker::GetJISx4051Breaks(const PRUnichar* aChars, PRUint32 aLength,
-                                         PRPackedBool* aBreakBefore)
+                                         PRUint8* aBreakBefore)
 {
   PRUint32 cur;
   PRInt8 lastClass = CLASS_NONE;
   ContextState state(aChars, aLength);
 
   for (cur = 0; cur < aLength; ++cur, state.AdvanceIndex()) {
     PRUnichar ch = aChars[cur];
     PRInt8 cl;
@@ -885,17 +885,17 @@ nsJISx4051LineBreaker::GetJISx4051Breaks
 
       cur = end - 1;
     }
   }
 }
 
 void
 nsJISx4051LineBreaker::GetJISx4051Breaks(const PRUint8* aChars, PRUint32 aLength,
-                                         PRPackedBool* aBreakBefore)
+                                         PRUint8* aBreakBefore)
 {
   PRUint32 cur;
   PRInt8 lastClass = CLASS_NONE;
   ContextState state(aChars, aLength);
 
   for (cur = 0; cur < aLength; ++cur, state.AdvanceIndex()) {
     PRUnichar ch = aChars[cur];
     PRInt8 cl;
--- a/intl/lwbrk/src/nsJISx4501LineBreaker.h
+++ b/intl/lwbrk/src/nsJISx4501LineBreaker.h
@@ -48,18 +48,18 @@ public:
   nsJISx4051LineBreaker();
   virtual ~nsJISx4051LineBreaker();
 
   PRInt32 Next( const PRUnichar* aText, PRUint32 aLen, PRUint32 aPos);
 
   PRInt32 Prev( const PRUnichar* aText, PRUint32 aLen, PRUint32 aPos);
 
   virtual void GetJISx4051Breaks(const PRUnichar* aText, PRUint32 aLength,
-                                 PRPackedBool* aBreakBefore);
+                                 PRUint8* aBreakBefore);
   virtual void GetJISx4051Breaks(const PRUint8* aText, PRUint32 aLength,
-                                 PRPackedBool* aBreakBefore);
+                                 PRUint8* aBreakBefore);
 
 private:
   PRInt32 WordMove(const PRUnichar* aText, PRUint32 aLen, PRUint32 aPos,
                    PRInt8 aDirection);
 };
 
 #endif  /* nsJISx4501LineBreaker_h__ */
--- a/intl/lwbrk/src/nsPangoBreaker.cpp
+++ b/intl/lwbrk/src/nsPangoBreaker.cpp
@@ -40,21 +40,21 @@
 
 #include <pango/pango-break.h>
 #include "nsUTF8Utils.h"
 #include "nsString.h"
 #include "nsTArray.h"
 
 void
 NS_GetComplexLineBreaks(const PRUnichar* aText, PRUint32 aLength,
-                        PRPackedBool* aBreakBefore)
+                        PRUint8* aBreakBefore)
 {
   NS_ASSERTION(aText, "aText shouldn't be null");
 
-  memset(aBreakBefore, PR_FALSE, aLength * sizeof(PRPackedBool));
+  memset(aBreakBefore, PR_FALSE, aLength * sizeof(PRUint8));
 
   nsAutoTArray<PangoLogAttr, 2000> attrBuffer;
   if (!attrBuffer.AppendElements(aLength + 1))
     return;
 
   NS_ConvertUTF16toUTF8 aUTF8(aText, aLength);
 
   const gchar* p = aUTF8.Data();
--- a/intl/lwbrk/src/nsRuleBreaker.cpp
+++ b/intl/lwbrk/src/nsRuleBreaker.cpp
@@ -38,16 +38,16 @@
 
 #include "nsComplexBreaker.h"
 
 #define TH_UNICODE
 #include "rulebrk.h"
 
 void
 NS_GetComplexLineBreaks(const PRUnichar* aText, PRUint32 aLength,
-                        PRPackedBool* aBreakBefore)
+                        PRUint8* aBreakBefore)
 {
   NS_ASSERTION(aText, "aText shouldn't be null");
 
   for (PRUint32 i = 0; i < aLength; i++)
     aBreakBefore[i] = (0 == TrbWordBreakPos(aText, i, aText + i, aLength - i));
 }
 
--- a/intl/lwbrk/src/nsUniscribeBreaker.cpp
+++ b/intl/lwbrk/src/nsUniscribeBreaker.cpp
@@ -46,17 +46,17 @@
 #include <usp10.h>
 
 #include "nsUTF8Utils.h"
 #include "nsString.h"
 #include "nsTArray.h"
 
 void
 NS_GetComplexLineBreaks(const PRUnichar* aText, PRUint32 aLength,
-                        PRPackedBool* aBreakBefore)
+                        PRUint8* aBreakBefore)
 {
   NS_ASSERTION(aText, "aText shouldn't be null"); 
 
   int outItems = 0;
   HRESULT result;
   nsAutoTArray<SCRIPT_ITEM, 64> items;
 
   memset(aBreakBefore, PR_FALSE, aLength);
--- a/js/src/Makefile.in
+++ b/js/src/Makefile.in
@@ -1014,17 +1014,17 @@ host_jsoplengen.$(OBJ_SUFFIX): jsopcode.
 
 # Force auto-header generation before compiling any source that may use them
 $(patsubst %.cc,%.$(OBJ_SUFFIX),$(CPPSRCS:%.cpp=%.$(OBJ_SUFFIX))): $(CURDIR)/jsautokw.h $(CURDIR)/jsautooplen.h
 
 ifdef MOZ_ETW
 ETWProvider.h ETWProvider.rc ETWProvider.mof: ETWProvider.man
 	$(MC) -um -mof $^
 
-$(CPPSRCS:%.cpp=%.$(OBJ_SUFFIX)): ETWProvider.h
+jsprobes.$(OBJ_SUFFIX): ETWProvider.h
 
 ETWProvider.res: ETWProvider.rc
 	$(RC) -r -i "$(SDKDIR)Include" $^
 
 export:: ETWProvider.res
 
 install:: ETWProvider.mof ETWProvider.man
 	$(SYSINSTALL) $^ $(DESTDIR)$(bindir)
--- a/js/src/config/rules.mk
+++ b/js/src/config/rules.mk
@@ -187,17 +187,17 @@ endif # XPCSHELL_TESTS
 ifdef CPP_UNIT_TESTS
 
 # Compile the tests to $(DIST)/bin.  Make lots of niceties available by default
 # through TestHarness.h, by modifying the list of includes and the libs against
 # which stuff links.
 CPPSRCS += $(CPP_UNIT_TESTS)
 SIMPLE_PROGRAMS += $(CPP_UNIT_TESTS:.cpp=$(BIN_SUFFIX))
 INCLUDES += -I$(DIST)/include/testing
-LIBS += $(XPCOM_GLUE_LDOPTS) $(NSPR_LIBS)
+LIBS += $(XPCOM_GLUE_LDOPTS) $(NSPR_LIBS) $(MOZ_JS_LIBS)
 
 # ...and run them the usual way
 check::
 	@$(EXIT_ON_ERROR) \
 	  for f in $(subst .cpp,$(BIN_SUFFIX),$(CPP_UNIT_TESTS)); do \
 	    XPCOM_DEBUG_BREAK=stack-and-abort $(RUN_TEST_PROGRAM) $(DIST)/bin/$$f; \
 	  done
 
--- a/js/src/configure.in
+++ b/js/src/configure.in
@@ -5036,20 +5036,21 @@ if test -n "$MOZ_SHARK"; then
     MOZ_PROFILING=1
     AC_DEFINE(MOZ_SHARK)
 fi
 
 dnl ========================================================
 dnl callgrind
 dnl ========================================================
 MOZ_ARG_ENABLE_BOOL(callgrind,
-[  --enable-callgrind      Enable callgrind profiling],
+[  --enable-callgrind      Enable callgrind profiling. Implies --enable-profiling.],
     MOZ_CALLGRIND=1,
     MOZ_CALLGRIND= )
 if test -n "$MOZ_CALLGRIND"; then
+    MOZ_PROFILING=1
     AC_DEFINE(MOZ_CALLGRIND)
 fi
 
 dnl ========================================================
 dnl vtune
 dnl ========================================================
 MOZ_ARG_ENABLE_BOOL(vtune,
 [  --enable-vtune          Enable vtune profiling. Implies --enable-profiling.],
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -741,19 +741,16 @@ JSRuntime::~JSRuntime()
         JS_DESTROY_LOCK(debuggerLock);
 #endif
 }
 
 JS_PUBLIC_API(JSRuntime *)
 JS_NewRuntime(uint32 maxbytes)
 {
     if (!js_NewRuntimeWasCalled) {
-#ifdef MOZ_ETW
-        EventRegisterMozillaSpiderMonkey();
-#endif
 #ifdef DEBUG
         /*
          * This code asserts that the numbers associated with the error names
          * in jsmsg.def are monotonically increasing.  It uses values for the
          * error names enumerated in jscntxt.c.  It's not a compile-time check
          * but it's better than nothing.
          */
         int errorNumber = 0;
@@ -784,40 +781,40 @@ JS_NewRuntime(uint32 maxbytes)
         return NULL;
 
     JSRuntime *rt = new (mem) JSRuntime();
     if (!rt->init(maxbytes)) {
         JS_DestroyRuntime(rt);
         return NULL;
     }
 
+    Probes::createRuntime(rt);
     return rt;
 }
 
 JS_PUBLIC_API(void)
 JS_DestroyRuntime(JSRuntime *rt)
 {
+    Probes::destroyRuntime(rt);
     Foreground::delete_(rt);
 }
 
 JS_PUBLIC_API(void)
 JS_ShutDown(void)
 {
+    Probes::shutdown();
+
 #ifdef MOZ_TRACEVIS
     StopTraceVis();
 #endif
 
 #ifdef JS_THREADSAFE
     js_CleanupLocks();
 #endif
     PRMJ_NowShutdown();
-
-#ifdef MOZ_ETW
-    EventUnregisterMozillaSpiderMonkey();
-#endif
 }
 
 JS_PUBLIC_API(void *)
 JS_GetRuntimePrivate(JSRuntime *rt)
 {
     return rt->data;
 }
 
--- a/js/src/jshashtable.h
+++ b/js/src/jshashtable.h
@@ -40,16 +40,17 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef jshashtable_h_
 #define jshashtable_h_
 
 #include "jsalloc.h"
 #include "jstl.h"
+#include "jsutil.h"
 
 namespace js {
 
 /* Integral types for all hash functions. */
 typedef uint32 HashNumber;
 
 /*****************************************************************************/
 
@@ -72,17 +73,19 @@ class HashTableEntry {
 
     static bool isLiveHash(HashNumber hash)
     {
         return hash > sRemovedKey;
     }
 
   public:
     HashTableEntry() : keyHash(0), t() {}
+    HashTableEntry(MoveRef<HashTableEntry> rhs) : keyHash(rhs->keyHash), t(Move(rhs->t)) { }
     void operator=(const HashTableEntry &rhs) { keyHash = rhs.keyHash; t = rhs.t; }
+    void operator=(MoveRef<HashTableEntry> rhs) { keyHash = rhs->keyHash; t = Move(rhs->t); }
 
     NonConstT t;
 
     bool isFree() const           { return keyHash == sFreeKey; }
     void setFree()                { keyHash = sFreeKey; t = T(); }
     bool isRemoved() const        { return keyHash == sRemovedKey; }
     void setRemoved()             { keyHash = sRemovedKey; t = T(); }
     bool isLive() const           { return isLiveHash(keyHash); }
@@ -547,17 +550,17 @@ class HashTable : private AllocPolicy
         removedCount = 0;
         gen++;
         table = newTable;
 
         /* Copy only live entries, leaving removed ones behind. */
         for (Entry *src = oldTable, *end = src + oldCap; src != end; ++src) {
             if (src->isLive()) {
                 src->unsetCollision();
-                findFreeEntry(src->getKeyHash()) = *src;
+                findFreeEntry(src->getKeyHash()) = Move(*src);
             }
         }
 
         destroyTable(*this, oldTable, oldCap);
         return true;
     }
 
     void remove(Entry &e)
@@ -876,16 +879,22 @@ class HashMapEntry
     void operator=(const HashMapEntry &rhs) {
         const_cast<Key &>(key) = rhs.key;
         value = rhs.value;
     }
 
   public:
     HashMapEntry() : key(), value() {}
     HashMapEntry(const Key &k, const Value &v) : key(k), value(v) {}
+    HashMapEntry(MoveRef<HashMapEntry> rhs) 
+      : key(Move(rhs->key)), value(Move(rhs->value)) { }
+    void operator=(MoveRef<HashMapEntry> rhs) {
+        const_cast<Key &>(key) = Move(rhs->key);
+        value = Move(rhs->value);
+    }
 
     const Key key;
     Value value;
 };
 
 namespace tl {
 
 template <class T>
@@ -1014,16 +1023,25 @@ class HashMap
         Entry *pentry;
         if (!impl.add(p, &pentry))
             return false;
         const_cast<Key &>(pentry->key) = k;
         pentry->value = v;
         return true;
     }
 
+    bool add(AddPtr &p, const Key &k, MoveRef<Value> v) {
+        Entry *pentry;
+        if (!impl.add(p, &pentry))
+            return false;
+        const_cast<Key &>(pentry->key) = k;
+        pentry->value = v;
+        return true;
+    }
+
     bool add(AddPtr &p, const Key &k) {
         Entry *pentry;
         if (!impl.add(p, &pentry))
             return false;
         const_cast<Key &>(pentry->key) = k;
         return true;
     }
 
--- a/js/src/jsprobes.cpp
+++ b/js/src/jsprobes.cpp
@@ -28,16 +28,24 @@
  * 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 ***** */
 
+#ifdef MOZ_ETW
+#include "jswin.h"
+#include <evntprov.h>
+
+/* Generated from ETWProvider.man */
+#include "ETWProvider.h"
+#endif
+
 #include "jsapi.h"
 #include "jsutil.h"
 #include "jsatom.h"
 #include "jscntxt.h"
 #include "jsdbgapi.h"
 #include "jsfun.h"
 #include "jsinterp.h"
 #include "jsobj.h"
@@ -175,8 +183,248 @@ Probes::startProfiling()
 
 void
 Probes::stopProfiling()
 {
 #if defined(MOZ_SHARK) && defined(__APPLE__)
     Shark::Stop();
 #endif
 }
+
+
+#ifdef MOZ_ETW
+/*
+ * ETW (Event Tracing for Windows)
+ *
+ * These are here rather than in the .h file to avoid having to include
+ * windows.h in a header.
+ */
+bool
+Probes::ETWCallTrackingActive(JSContext *cx)
+{
+    return MCGEN_ENABLE_CHECK(MozillaSpiderMonkey_Context, EvtFunctionEntry);
+}
+
+bool
+Probes::ETWCreateRuntime(JSRuntime *rt)
+{
+    static bool registered = false;
+    if (!registered) {
+        EventRegisterMozillaSpiderMonkey();
+        registered = true;
+    }
+    return true;
+}
+
+bool
+Probes::ETWDestroyRuntime(JSRuntime *rt)
+{
+    return true;
+}
+
+bool
+Probes::ETWShutdown()
+{
+    EventUnregisterMozillaSpiderMonkey();
+    return true;
+}
+
+bool
+Probes::ETWEnterJSFun(JSContext *cx, JSFunction *fun, JSScript *script, int counter)
+{
+    int lineno = script ? script->lineno : -1;
+    JSAutoByteString bytes;
+    return (EventWriteEvtFunctionEntry(ScriptFilename(script), lineno,
+                                       ObjectClassname((JSObject *)fun),
+                                       FunctionName(cx, fun, &bytes)) == ERROR_SUCCESS);
+}
+
+bool
+Probes::ETWExitJSFun(JSContext *cx, JSFunction *fun, JSScript *script, int counter)
+{
+    int lineno = script ? script->lineno : -1;
+    JSAutoByteString bytes;
+    return (EventWriteEvtFunctionExit(ScriptFilename(script), lineno,
+                                      ObjectClassname((JSObject *)fun),
+                                      FunctionName(cx, fun, &bytes)) == ERROR_SUCCESS);
+}
+
+bool
+Probes::ETWCreateObject(JSContext *cx, JSObject *obj)
+{
+    int lineno;
+    const char * script_filename;
+    current_location(cx, &lineno, &script_filename);
+
+    return EventWriteEvtObjectCreate(script_filename, lineno,
+                                     ObjectClassname(obj), reinterpret_cast<JSUint64>(obj),
+                                     obj ? obj->slotsAndStructSize() : 0) == ERROR_SUCCESS;
+}
+
+bool
+Probes::ETWFinalizeObject(JSObject *obj)
+{
+    return EventWriteEvtObjectFinalize(ObjectClassname(obj),
+                                       reinterpret_cast<JSUint64>(obj)) == ERROR_SUCCESS;
+}
+
+bool
+Probes::ETWResizeObject(JSContext *cx, JSObject *obj, size_t oldSize, size_t newSize)
+{
+    int lineno;
+    const char *script_filename;
+    current_location(cx, &lineno, &script_filename);
+
+    return EventWriteEvtObjectResize(script_filename, lineno,
+                                     ObjectClassname(obj), reinterpret_cast<JSUint64>(obj),
+                                     oldSize, newSize) == ERROR_SUCCESS;
+}
+
+bool
+Probes::ETWCreateString(JSContext *cx, JSString *string, size_t length)
+{
+    int lineno;
+    const char *script_filename;
+    current_location(cx, &lineno, &script_filename);
+
+    return EventWriteEvtStringCreate(script_filename, lineno,
+                                     reinterpret_cast<JSUint64>(string), length) == ERROR_SUCCESS;
+}
+
+bool
+Probes::ETWFinalizeString(JSString *string)
+{
+    return EventWriteEvtStringFinalize(reinterpret_cast<JSUint64>(string), string->length()) == ERROR_SUCCESS;
+}
+
+bool
+Probes::ETWCompileScriptBegin(const char *filename, int lineno)
+{
+    return EventWriteEvtScriptCompileBegin(filename, lineno) == ERROR_SUCCESS;
+}
+
+bool
+Probes::ETWCompileScriptEnd(const char *filename, int lineno)
+{
+    return EventWriteEvtScriptCompileEnd(filename, lineno) == ERROR_SUCCESS;
+}
+
+bool
+Probes::ETWCalloutBegin(JSContext *cx, JSFunction *fun)
+{
+    const char *script_filename;
+    int lineno;
+    JSAutoByteString bytes;
+    current_location(cx, &lineno, &script_filename);
+
+    return EventWriteEvtCalloutBegin(script_filename,
+                                     lineno,
+                                     ObjectClassname((JSObject *)fun),
+                                     FunctionName(cx, fun, &bytes)) == ERROR_SUCCESS;
+}
+
+bool
+Probes::ETWCalloutEnd(JSContext *cx, JSFunction *fun)
+{
+        const char *script_filename;
+        int lineno;
+        JSAutoByteString bytes;
+        current_location(cx, &lineno, &script_filename);
+
+        return EventWriteEvtCalloutEnd(script_filename,
+                                       lineno,
+                                       ObjectClassname((JSObject *)fun),
+                                       FunctionName(cx, fun, &bytes)) == ERROR_SUCCESS;
+}
+
+bool
+Probes::ETWAcquireMemory(JSContext *cx, void *address, size_t nbytes)
+{
+    return EventWriteEvtMemoryAcquire(reinterpret_cast<JSUint64>(cx->compartment),
+                                      reinterpret_cast<JSUint64>(address),
+                                      nbytes) == ERROR_SUCCESS;
+}
+
+bool
+Probes::ETWReleaseMemory(JSContext *cx, void *address, size_t nbytes)
+{
+    return EventWriteEvtMemoryRelease(reinterpret_cast<JSUint64>(cx->compartment),
+                                      reinterpret_cast<JSUint64>(address),
+                                      nbytes) == ERROR_SUCCESS;
+}
+
+bool
+Probes::ETWGCStart(JSCompartment *compartment)
+{
+    return EventWriteEvtGCStart(reinterpret_cast<JSUint64>(compartment)) == ERROR_SUCCESS;
+}
+
+bool
+Probes::ETWGCEnd(JSCompartment *compartment)
+{
+    return EventWriteEvtGCEnd(reinterpret_cast<JSUint64>(compartment)) == ERROR_SUCCESS;
+}
+
+bool
+Probes::ETWGCStartMarkPhase(JSCompartment *compartment)
+{
+    return EventWriteEvtGCStartMarkPhase(reinterpret_cast<JSUint64>(compartment)) == ERROR_SUCCESS;
+}
+
+bool
+Probes::ETWGCEndMarkPhase(JSCompartment *compartment)
+{
+    return EventWriteEvtGCEndMarkPhase(reinterpret_cast<JSUint64>(compartment)) == ERROR_SUCCESS;
+}
+
+bool
+Probes::ETWGCStartSweepPhase(JSCompartment *compartment)
+{
+    return EventWriteEvtGCStartSweepPhase(reinterpret_cast<JSUint64>(compartment)) == ERROR_SUCCESS;
+}
+
+bool
+Probes::ETWGCEndSweepPhase(JSCompartment *compartment)
+{
+    return EventWriteEvtGCEndSweepPhase(reinterpret_cast<JSUint64>(compartment)) == ERROR_SUCCESS;
+}
+
+bool
+Probes::ETWCustomMark(JSString *string)
+{
+    const jschar *chars = string->getCharsZ(NULL);
+    return !chars || EventWriteEvtCustomString(chars) == ERROR_SUCCESS;
+}
+
+bool
+Probes::ETWCustomMark(const char *string)
+{
+    return EventWriteEvtCustomANSIString(string) == ERROR_SUCCESS;
+}
+
+bool
+Probes::ETWCustomMark(int marker)
+{
+    return EventWriteEvtCustomInt(marker) == ERROR_SUCCESS;
+}
+
+bool
+Probes::ETWStartExecution(JSContext *cx, JSScript *script)
+{
+    int lineno = script ? script->lineno : -1;
+    return EventWriteEvtExecuteStart(ScriptFilename(script), lineno) == ERROR_SUCCESS;
+}
+
+bool
+Probes::ETWStopExecution(JSContext *cx, JSScript *script)
+{
+    int lineno = script ? script->lineno : -1;
+    return EventWriteEvtExecuteDone(ScriptFilename(script), lineno) == ERROR_SUCCESS;
+}
+
+bool
+Probes::ETWResizeHeap(JSCompartment *compartment, size_t oldSize, size_t newSize)
+{
+    return EventWriteEvtHeapResize(reinterpret_cast<JSUint64>(compartment),
+                                   oldSize, newSize) == ERROR_SUCCESS;
+}
+
+#endif
--- a/js/src/jsprobes.h
+++ b/js/src/jsprobes.h
@@ -39,24 +39,16 @@
 #ifdef INCLUDE_MOZILLA_DTRACE
 #include "javascript-trace.h"
 #endif
 #include "jspubtd.h"
 #include "jsprvtd.h"
 
 namespace js {
 
-#ifdef MOZ_ETW
-#include "jswin.h"
-#include <evntprov.h>
-
-/* Generated from ETWProvider.man */
-#include "ETWProvider.h"
-#endif
-
 class Probes {
     static bool ProfilingActive;
     static bool controlProfilers(JSContext *cx, bool toState);
 
     static const char nullName[];
     static const char anonymousName[];
 
     static const char *FunctionName(JSContext *cx, const JSFunction *fun, JSAutoByteString* bytes)
@@ -94,16 +86,20 @@ class Probes {
     static const char *FunctionClassname(const JSFunction *fun);
     static const char *ScriptFilename(JSScript *script);
     static int FunctionLineNumber(JSContext *cx, const JSFunction *fun);
 
     static void enterJSFunImpl(JSContext *cx, JSFunction *fun, JSScript *script);
     static void handleFunctionReturn(JSContext *cx, JSFunction *fun, JSScript *script);
     static void finalizeObjectImpl(JSObject *obj);
   public:
+    static bool createRuntime(JSRuntime *rt);
+    static bool destroyRuntime(JSRuntime *rt);
+    static bool shutdown();
+
     /*
      * Pause/resume whatever profiling mechanism is currently compiled
      * in, if applicable. This will not affect things like dtrace.
      *
      * Do not mix calls to these APIs with calls to the individual
      * profilers' pase/resume functions, because only overall state is
      * tracked, not the state of each profiler.
      *
@@ -171,31 +167,97 @@ class Probes {
     static bool GCEndSweepPhase(JSCompartment *compartment);
 
     static bool CustomMark(JSString *string);
     static bool CustomMark(const char *string);
     static bool CustomMark(int marker);
 
     static bool startProfiling();
     static void stopProfiling();
+
+#ifdef MOZ_ETW
+    // ETW Handlers
+    static bool ETWCreateRuntime(JSRuntime *rt);
+    static bool ETWDestroyRuntime(JSRuntime *rt);
+    static bool ETWShutdown();
+    static bool ETWCallTrackingActive(JSContext *cx);
+    static bool ETWEnterJSFun(JSContext *cx, JSFunction *fun, JSScript *script, int counter);
+    static bool ETWExitJSFun(JSContext *cx, JSFunction *fun, JSScript *script, int counter);
+    static bool ETWCreateObject(JSContext *cx, JSObject *obj);
+    static bool ETWFinalizeObject(JSObject *obj);
+    static bool ETWResizeObject(JSContext *cx, JSObject *obj, size_t oldSize, size_t newSize);
+    static bool ETWCreateString(JSContext *cx, JSString *string, size_t length);
+    static bool ETWFinalizeString(JSString *string);
+    static bool ETWCompileScriptBegin(const char *filename, int lineno);
+    static bool ETWCompileScriptEnd(const char *filename, int lineno);
+    static bool ETWCalloutBegin(JSContext *cx, JSFunction *fun);
+    static bool ETWCalloutEnd(JSContext *cx, JSFunction *fun);
+    static bool ETWAcquireMemory(JSContext *cx, void *address, size_t nbytes);
+    static bool ETWReleaseMemory(JSContext *cx, void *address, size_t nbytes);
+    static bool ETWGCStart(JSCompartment *compartment);
+    static bool ETWGCEnd(JSCompartment *compartment);
+    static bool ETWGCStartMarkPhase(JSCompartment *compartment);
+    static bool ETWGCEndMarkPhase(JSCompartment *compartment);
+    static bool ETWGCStartSweepPhase(JSCompartment *compartment);
+    static bool ETWGCEndSweepPhase(JSCompartment *compartment);
+    static bool ETWCustomMark(JSString *string);
+    static bool ETWCustomMark(const char *string);
+    static bool ETWCustomMark(int marker);
+    static bool ETWStartExecution(JSContext *cx, JSScript *script);
+    static bool ETWStopExecution(JSContext *cx, JSScript *script);
+    static bool ETWResizeHeap(JSCompartment *compartment, size_t oldSize, size_t newSize);
+#endif
 };
 
 inline bool
+Probes::createRuntime(JSRuntime *rt)
+{
+    bool ok = true;
+#ifdef MOZ_ETW
+    if (!ETWCreateRuntime(rt))
+        ok = false;
+#endif
+    return ok;
+}
+
+inline bool
+Probes::destroyRuntime(JSRuntime *rt)
+{
+    bool ok = true;
+#ifdef MOZ_ETW
+    if (!ETWDestroyRuntime(rt))
+        ok = false;
+#endif
+    return ok;
+}
+
+inline bool
+Probes::shutdown()
+{
+    bool ok = true;
+#ifdef MOZ_ETW
+    if (!ETWShutdown())
+        ok = false;
+#endif
+    return ok;
+}
+
+inline bool
 Probes::callTrackingActive(JSContext *cx)
 {
 #ifdef INCLUDE_MOZILLA_DTRACE
     if (JAVASCRIPT_FUNCTION_ENTRY_ENABLED() || JAVASCRIPT_FUNCTION_RETURN_ENABLED())
         return true;
 #endif
 #ifdef MOZ_TRACE_JSCALLS
     if (cx->functionCallback)
         return true;
 #endif
 #ifdef MOZ_ETW
-    if (ProfilingActive && MCGEN_ENABLE_CHECK(MozillaSpiderMonkey_Context, EvtFunctionEntry))
+    if (ProfilingActive && ETWCallTrackingActive(cx))
         return true;
 #endif
     return false;
 }
 
 extern inline JS_FRIEND_API(JSBool)
 js_PauseProfilers(JSContext *cx, uintN argc, jsval *vp)
 {
@@ -220,25 +282,18 @@ Probes::enterJSFun(JSContext *cx, JSFunc
 #ifdef INCLUDE_MOZILLA_DTRACE
     if (JAVASCRIPT_FUNCTION_ENTRY_ENABLED())
         enterJSFunImpl(cx, fun, script);
 #endif
 #ifdef MOZ_TRACE_JSCALLS
     cx->doFunctionCallback(fun, script, counter);
 #endif
 #ifdef MOZ_ETW
-    if (ProfilingActive) {
-        JSScript* script = fun ? FUN_SCRIPT(fun) : NULL;
-        int lineno = script ? script->lineno : -1;
-        JSAutoByteString bytes;
-        if (EventWriteEvtFunctionEntry(ScriptFilename(script), lineno,
-                                       ObjectClassname((JSObject *)fun),
-                                       FunctionName(cx, fun, &bytes)) != ERROR_SUCCESS)
-            ok = false;
-    }
+    if (ProfilingActive && !ETWEnterJSFun(cx, fun, script, counter))
+        ok = false;
 #endif
 
     return ok;
 }
 
 inline bool
 Probes::exitJSFun(JSContext *cx, JSFunction *fun, JSScript *script, int counter)
 {
@@ -249,64 +304,48 @@ Probes::exitJSFun(JSContext *cx, JSFunct
         handleFunctionReturn(cx, fun, script);
 #endif
 #ifdef MOZ_TRACE_JSCALLS
     if (counter > 0)
         counter = -counter;
     cx->doFunctionCallback(fun, script, counter);
 #endif
 #ifdef MOZ_ETW
-    if (ProfilingActive) {
-        JSScript* script = fun ? FUN_SCRIPT(fun) : NULL;
-        int lineno = script ? script->lineno : -1;
-        JSAutoByteString bytes;
-        if (EventWriteEvtFunctionExit(ScriptFilename(script), lineno,
-                                      ObjectClassname((JSObject *)fun),
-                                      FunctionName(cx, fun, &bytes)) != ERROR_SUCCESS)
-            ok = false;
-    }
+    if (ProfilingActive && !ETWExitJSFun(cx, fun, script, counter))
+        ok = false;
 #endif
 
     return ok;
 }
 
 inline bool
 Probes::resizeHeap(JSCompartment *compartment, size_t oldSize, size_t newSize)
 {
     bool ok = true;
 
 #ifdef MOZ_ETW
-    if (ProfilingActive)
-        if (EventWriteEvtHeapResize(reinterpret_cast<JSUint64>(compartment), oldSize, newSize) != ERROR_SUCCESS)
-            ok = false;
+    if (ProfilingActive && !ETWResizeHeap(compartment, oldSize, newSize))
+        ok = false;
 #endif
 
     return ok;
 }
 
 inline bool
 Probes::createObject(JSContext *cx, JSObject *obj)
 {
     bool ok = true;
 
 #ifdef INCLUDE_MOZILLA_DTRACE
     if (JAVASCRIPT_OBJECT_CREATE_ENABLED())
         JAVASCRIPT_OBJECT_CREATE(ObjectClassname(obj), (uintptr_t)obj);
 #endif
 #ifdef MOZ_ETW
-    if (ProfilingActive) {
-        int lineno;
-        const char * script_filename;
-        current_location(cx, &lineno, &script_filename);
-
-        if (EventWriteEvtObjectCreate(script_filename, lineno,
-                                      ObjectClassname(obj), reinterpret_cast<JSUint64>(obj),
-                                      obj ? obj->slotsAndStructSize() : 0) != ERROR_SUCCESS)
-            ok = false;
-    }
+    if (ProfilingActive && !ETWCreateObject(cx, obj))
+        ok = false;
 #endif
 
     return ok;
 }
 
 inline bool
 Probes::finalizeObject(JSObject *obj)
 {
@@ -316,351 +355,288 @@ Probes::finalizeObject(JSObject *obj)
     if (JAVASCRIPT_OBJECT_FINALIZE_ENABLED()) {
         Class *clasp = obj->getClass();
 
         /* the first arg is NULL - reserved for future use (filename?) */
         JAVASCRIPT_OBJECT_FINALIZE(NULL, (char *)clasp->name, (uintptr_t)obj);
     }
 #endif
 #ifdef MOZ_ETW
-    if (ProfilingActive)
-        if (EventWriteEvtObjectFinalize(ObjectClassname(obj),
-                                        reinterpret_cast<JSUint64>(obj)) != ERROR_SUCCESS)
-            ok = false;
+    if (ProfilingActive && !ETWFinalizeObject(obj))
+        ok = false;
 #endif
 
     return ok;
 }
 
 inline bool
 Probes::resizeObject(JSContext *cx, JSObject *obj, size_t oldSize, size_t newSize)
 {
     bool ok = true;
 
 #ifdef MOZ_ETW
-    if (ProfilingActive) {
-        int lineno;
-        const char *script_filename;
-        current_location(cx, &lineno, &script_filename);
-
-        if (EventWriteEvtObjectResize(script_filename, lineno,
-                                      ObjectClassname(obj), reinterpret_cast<JSUint64>(obj),
-                                      oldSize, newSize) != ERROR_SUCCESS)
-            ok = false;
-    }
+    if (ProfilingActive && !ETWResizeObject(cx, obj, oldSize, newSize))
+        ok = false;
 #endif
 
     return ok;
 }
 
 inline bool
 Probes::createString(JSContext *cx, JSString *string, size_t length)
 {
     bool ok = true;
 
 #ifdef MOZ_ETW
-    if (ProfilingActive) {
-        int lineno;
-        const char *script_filename;
-        current_location(cx, &lineno, &script_filename);
-
-        if (EventWriteEvtStringCreate(script_filename, lineno,
-                                      reinterpret_cast<JSUint64>(string), length) != ERROR_SUCCESS)
-            ok = 0;
-    }
+    if (ProfilingActive && !ETWCreateString(cx, string, length))
+        ok = false;
 #endif
 
     return ok;
 }
 
 inline bool
 Probes::finalizeString(JSString *string)
 {
     bool ok = true;
 
 #ifdef MOZ_ETW
-    if (ProfilingActive)
-        if (EventWriteEvtStringFinalize(reinterpret_cast<JSUint64>(string), string->length()) != ERROR_SUCCESS)
-            ok = false;
+    if (ProfilingActive && !ETWFinalizeString(string))
+        ok = false;
 #endif
 
     return ok;
 }
 
 inline bool
 Probes::compileScriptBegin(JSContext *cx, const char *filename, int lineno)
 {
     bool ok = true;
 
 #ifdef MOZ_ETW
-    if (ProfilingActive)
-        if (EventWriteEvtScriptCompileBegin(filename, lineno) != ERROR_SUCCESS)
-            ok = false;
+    if (ProfilingActive && !ETWCompileScriptBegin(filename, lineno))
+        ok = false;
 #endif
 
     return ok;
 }
 
 inline bool
 Probes::compileScriptEnd(JSContext *cx, JSScript *script, const char *filename, int lineno)
 {
     bool ok = true;
 
 #ifdef MOZ_ETW
-    if (ProfilingActive)
-        if (EventWriteEvtScriptCompileEnd(filename, lineno) != ERROR_SUCCESS)
-            ok = false;
+    if (ProfilingActive && !ETWCompileScriptEnd(filename, lineno))
+        ok = false;
 #endif
 
     return ok;
 }
 
 inline bool
 Probes::calloutBegin(JSContext *cx, JSFunction *fun)
 {
     bool ok = true;
 
 #ifdef MOZ_ETW
-    if (ProfilingActive) {
-        const char *script_filename;
-        int lineno;
-        JSAutoByteString bytes;
-        current_location(cx, &lineno, &script_filename);
-
-        if (EventWriteEvtCalloutBegin(script_filename,
-                                      lineno,
-                                      ObjectClassname((JSObject *)fun),
-                                      FunctionName(cx, fun, &bytes)) != ERROR_SUCCESS)
-            ok = false;
-    }
+    if (ProfilingActive && !ETWCalloutBegin(cx, fun))
+        ok = false;
 #endif
 
     return ok;
 }
 
 inline bool
 Probes::calloutEnd(JSContext *cx, JSFunction *fun)
 {
     bool ok = true;
 
 #ifdef MOZ_ETW
-    if (ProfilingActive) {
-        const char *script_filename;
-        int lineno;
-        JSAutoByteString bytes;
-        current_location(cx, &lineno, &script_filename);
-
-        if (EventWriteEvtCalloutEnd(script_filename,
-                                    lineno,
-                                    ObjectClassname((JSObject *)fun),
-                                    FunctionName(cx, fun, &bytes)) != ERROR_SUCCESS)
-            ok = false;
-    }
+    if (ProfilingActive && !ETWCalloutEnd(cx, fun))
+        ok = false;
 #endif
 
     return ok;
 }
 
 inline bool
 Probes::acquireMemory(JSContext *cx, void *address, size_t nbytes)
 {
     bool ok = true;
 
 #ifdef MOZ_ETW
-    if (ProfilingActive)
-        if (EventWriteEvtMemoryAcquire(reinterpret_cast<JSUint64>(cx->compartment),
-                                       reinterpret_cast<JSUint64>(address),
-                                       nbytes) != ERROR_SUCCESS)
-            ok = false;
+    if (ProfilingActive && !ETWAcquireMemory(cx, address, nbytes))
+        ok = false;
 #endif
 
     return ok;
 }
 
 inline bool
 Probes::releaseMemory(JSContext *cx, void *address, size_t nbytes)
 {
     bool ok = true;
 
 #ifdef MOZ_ETW
-    if (ProfilingActive)
-        if (EventWriteEvtMemoryRelease(reinterpret_cast<JSUint64>(cx->compartment),
-                                       reinterpret_cast<JSUint64>(address),
-                                       nbytes) != ERROR_SUCCESS)
-            ok = false;
+    if (ProfilingActive && !ETWReleaseMemory(cx, address, nbytes))
+        ok = false;
 #endif
 
     return ok;
 }
 
 inline bool
 Probes::GCStart(JSCompartment *compartment)
 {
     bool ok = true;
 
 #ifdef MOZ_ETW
-    if (ProfilingActive)
-        if (EventWriteEvtGCStart(reinterpret_cast<JSUint64>(compartment)) != ERROR_SUCCESS)
-            ok = false;
+    if (ProfilingActive && !ETWGCStart(compartment))
+        ok = false;
 #endif
 
     return ok;
 }
 
 inline bool
 Probes::GCEnd(JSCompartment *compartment)
 {
     bool ok = true;
 
 #ifdef MOZ_ETW
-    if (ProfilingActive)
-        if (EventWriteEvtGCEnd(reinterpret_cast<JSUint64>(compartment)) != ERROR_SUCCESS)
-            ok = false;
+    if (ProfilingActive && !ETWGCEnd(compartment))
+        ok = false;
 #endif
 
     return ok;
 }
 
 inline bool
 Probes::GCStartMarkPhase(JSCompartment *compartment)
 {
     bool ok = true;
 
 #ifdef MOZ_ETW
-    if (ProfilingActive)
-        if (EventWriteEvtGCStartMarkPhase(reinterpret_cast<JSUint64>(compartment)) != ERROR_SUCCESS)
-            ok = false;
+    if (ProfilingActive && !ETWGCStartMarkPhase(compartment))
+        ok = false;
 #endif
 
     return ok;
 }
 
 inline bool
 Probes::GCEndMarkPhase(JSCompartment *compartment)
 {
     bool ok = true;
 
 #ifdef MOZ_ETW
-    if (ProfilingActive)
-        if (EventWriteEvtGCEndMarkPhase(reinterpret_cast<JSUint64>(compartment)) != ERROR_SUCCESS)
-            ok = false;
+    if (ProfilingActive && !ETWGCEndMarkPhase(compartment))
+        ok = false;
 #endif
 
     return ok;
 }
 
 inline bool
 Probes::GCStartSweepPhase(JSCompartment *compartment)
 {
     bool ok = true;
 
 #ifdef MOZ_ETW
-    if (ProfilingActive)
-        if (EventWriteEvtGCStartSweepPhase(reinterpret_cast<JSUint64>(compartment)) != ERROR_SUCCESS)
-            ok = false;
+    if (ProfilingActive && !ETWGCStartSweepPhase(compartment))
+        ok = false;
 #endif
 
     return ok;
 }
 
 inline bool
 Probes::GCEndSweepPhase(JSCompartment *compartment)
 {
     bool ok = true;
 
 #ifdef MOZ_ETW
-    if (ProfilingActive)
-        if (EventWriteEvtGCEndSweepPhase(reinterpret_cast<JSUint64>(compartment)) != ERROR_SUCCESS)
-            ok = false;
+    if (ProfilingActive && !ETWGCEndSweepPhase(compartment))
+        ok = false;
 #endif
 
     return ok;
 }
 
 inline bool
 Probes::CustomMark(JSString *string)
 {
     bool ok = true;
 
 #ifdef MOZ_ETW
-    if (ProfilingActive) {
-        const jschar *chars = string->getCharsZ(NULL);
-        if (!chars || EventWriteEvtCustomString(chars) != ERROR_SUCCESS)
-            ok = false;
-    }
+    if (ProfilingActive && !ETWCustomMark(string))
+        ok = false;
 #endif
 
     return ok;
 }
 
 inline bool
 Probes::CustomMark(const char *string)
 {
     bool ok = true;
 
 #ifdef MOZ_ETW
-    if (ProfilingActive)
-        if (EventWriteEvtCustomANSIString(string) != ERROR_SUCCESS)
-            ok = false;
+    if (ProfilingActive && !ETWCustomMark(string))
+        ok = false;
 #endif
 
     return ok;
 }
 
 inline bool
 Probes::CustomMark(int marker)
 {
     bool ok = true;
 
 #ifdef MOZ_ETW
-    if (ProfilingActive)
-        if (EventWriteEvtCustomInt(marker) != ERROR_SUCCESS)
-            ok = false;
+    if (ProfilingActive && !ETWCustomMark(marker))
+        ok = false;
 #endif
 
     return ok;
 }
 
 inline bool
 Probes::startExecution(JSContext *cx, JSScript *script)
 {
     bool ok = true;
 
 #ifdef INCLUDE_MOZILLA_DTRACE
     if (JAVASCRIPT_EXECUTE_START_ENABLED())
         JAVASCRIPT_EXECUTE_START((script->filename ? (char *)script->filename : nullName),
                                  script->lineno);
 #endif
 #ifdef MOZ_ETW
-    if (ProfilingActive) {
-        int lineno = script ? script->lineno : -1;
-        if (EventWriteEvtExecuteStart(ScriptFilename(script), lineno) != ERROR_SUCCESS)
-            ok = false;
-    }
+    if (ProfilingActive && !ETWStartExecution(cx, script))
+        ok = false;
 #endif
 
     return ok;
 }
 
 inline bool
 Probes::stopExecution(JSContext *cx, JSScript *script)
 {
     bool ok = true;
 
 #ifdef INCLUDE_MOZILLA_DTRACE
     if (JAVASCRIPT_EXECUTE_DONE_ENABLED())
         JAVASCRIPT_EXECUTE_DONE((script->filename ? (char *)script->filename : nullName),
                                 script->lineno);
 #endif
 #ifdef MOZ_ETW
-    if (ProfilingActive) {
-        int lineno = script ? script->lineno : -1;
-        if (EventWriteEvtExecuteDone(ScriptFilename(script), lineno) != ERROR_SUCCESS)
-            ok = false;
-    }
+    if (ProfilingActive && !ETWStopExecution(cx, script))
+        ok = false;
 #endif
 
     return ok;
 }
 
 struct AutoFunctionCallProbe {
     JSContext * const cx;
     JSFunction *fun;
--- a/js/src/jsutil.h
+++ b/js/src/jsutil.h
@@ -688,13 +688,128 @@ PodEqual(T *one, T *two, size_t len)
  * Ordinarily, a function taking a JSContext* 'cx' paremter reports errors on
  * the context. In some cases, functions optionally report and indicate this by
  * taking a nullable 'maybecx' parameter. In some cases, though, a function
  * always needs a 'cx', but optionally reports. This option is presented by the
  * MaybeReportError.
  */
 enum MaybeReportError { REPORT_ERROR = true, DONT_REPORT_ERROR = false };
 
+/*
+ * "Move" References
+ *
+ * Some types can be copied much more efficiently if we know the original's
+ * value need not be preserved --- that is, if we are doing a "move", not a
+ * "copy". For example, if we have:
+ *
+ *   Vector<T> u;
+ *   Vector<T> v(u);
+ * 
+ * the constructor for v must apply a copy constructor to each element of u ---
+ * taking time linear in the length of u. However, if we know we will not need u
+ * any more once v has been initialized, then we could initialize v very
+ * efficiently simply by stealing u's dynamically allocated buffer and giving it
+ * to v --- a constant-time operation, regardless of the size of u.
+ *
+ * Moves often appear in container implementations. For example, when we append
+ * to a vector, we may need to resize its buffer. This entails moving each of
+ * its extant elements from the old, smaller buffer to the new, larger buffer.
+ * But once the elements have been migrated, we're just going to throw away the
+ * old buffer; we don't care if they still have their values. So if the vector's
+ * element type can implement "move" more efficiently than "copy", the vector
+ * resizing should by all means use a "move" operation. Hash tables also need to
+ * be resized.
+ *
+ * The details of the optimization, and whether it's worth applying, vary from
+ * one type to the next. And while some constructor calls are moves, many really
+ * are copies, and can't be optimized this way. So we need:
+ *
+ * 1) a way for a particular invocation of a copy constructor to say that it's
+ *    really a move, and that the value of the original isn't important
+ *    afterwards (althought it must still be safe to destroy); and
+ *
+ * 2) a way for a type (like Vector) to announce that it can be moved more
+ *    efficiently than it can be copied, and provide an implementation of that
+ *    move operation.
+ *
+ * The Move(T &) function takes a reference to a T, and returns an MoveRef<T>
+ * referring to the same value; that's 1). An MoveRef<T> is simply a reference
+ * to a T, annotated to say that a copy constructor applied to it may move that
+ * T, instead of copying it. Finally, a constructor that accepts an MoveRef<T>
+ * should perform a more efficient move, instead of a copy, providing 2).
+ *
+ * So, where we might define a copy constructor for a class C like this:
+ *
+ *   C(const C &rhs) { ... copy rhs to this ... }
+ *
+ * we would declare a move constructor like this:
+ *
+ *   C(MoveRef<C> rhs) { ... move rhs to this ... }
+ *
+ * And where we might perform a copy like this:
+ *
+ *   C c2(c1);
+ *
+ * we would perform a move like this:
+ *
+ *   C c2(Move(c1))
+ * 
+ * Note that MoveRef<T> implicitly converts to T &, so you can pass an
+ * MoveRef<T> to an ordinary copy constructor for a type that doesn't support a
+ * special move constructor, and you'll just get a copy. This means that
+ * templates can use Move whenever they know they won't use the original value
+ * any more, even if they're not sure whether the type at hand has a specialized
+ * move constructor. If it doesn't, the MoveRef<T> will just convert to a T &,
+ * and the ordinary copy constructor will apply.
+ *
+ * A class with a move constructor can also provide a move assignment operator,
+ * which runs this's destructor, and then applies the move constructor to
+ * *this's memory. A typical definition:
+ *
+ *   C &operator=(MoveRef<C> rhs) {
+ *     this->~C();
+ *     new(this) C(rhs);
+ *     return *this;
+ *   }
+ *
+ * With that in place, one can write move assignments like this:
+ *
+ *   c2 = Move(c1);
+ *
+ * This destroys c1, moves c1's value to c2, and leaves c1 in an undefined but
+ * destructible state.
+ *
+ * This header file defines MoveRef and Move in the js namespace. It's up to
+ * individual containers to annotate moves as such, by calling Move; and it's up
+ * to individual types to define move constructors.
+ *
+ * One hint: if you're writing a move constructor where the type has members
+ * that should be moved themselves, it's much nicer to write this:
+ *
+ *   C(MoveRef<C> c) : x(c->x), y(c->y) { }
+ *
+ * than the equivalent:
+ *
+ *   C(MoveRef<C> c) { new(&x) X(c->x); new(&y) Y(c->y); }
+ *
+ * especially since GNU C++ fails to notice that this does indeed initialize x
+ * and y, which may matter if they're const.
+ */
+template<typename T>
+class MoveRef {
+  public:
+    typedef T Referent;
+    explicit MoveRef(T &t) : pointer(&t) { }
+    T &operator*()  const { return *pointer; }
+    T *operator->() const { return  pointer; }
+    operator T &()  const { return *pointer; }
+  private:
+    T *pointer;
+};
+
+template<typename T>
+MoveRef<T> Move(T &t) { return MoveRef<T>(t); }
+
 } /* namespace js */
 
 #endif /* defined(__cplusplus) */
 
 #endif /* jsutil_h___ */
--- a/js/src/jsvector.h
+++ b/js/src/jsvector.h
@@ -39,16 +39,17 @@
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef jsvector_h_
 #define jsvector_h_
 
 #include "jsalloc.h"
 #include "jstl.h"
 #include "jsprvtd.h"
+#include "jsutil.h"
 
 /* Silence dire "bugs in previous versions of MSVC have been fixed" warnings */
 #ifdef _MSC_VER
 #pragma warning(push)
 #pragma warning(disable:4345)
 #endif
 
 namespace js {
@@ -78,16 +79,26 @@ struct VectorImpl
      */
     template <class U>
     static inline void copyConstruct(T *dst, const U *srcbeg, const U *srcend) {
         for (const U *p = srcbeg; p != srcend; ++p, ++dst)
             new(dst) T(*p);
     }
 
     /*
+     * Move-constructs objects in the uninitialized range
+     * [dst, dst+(srcend-srcbeg)) from the range [srcbeg, srcend).
+     */
+    template <class U>
+    static inline void moveConstruct(T *dst, const U *srcbeg, const U *srcend) {
+        for (const U *p = srcbeg; p != srcend; ++p, ++dst)
+            new(dst) T(Move(*p));
+    }
+
+    /*
      * Copy-constructs objects in the uninitialized range [dst, dst+n) from the
      * same object u.
      */
     template <class U>
     static inline void copyConstructN(T *dst, size_t n, const U &u) {
         for (T *end = dst + n; dst != end; ++dst)
             new(dst) T(u);
     }
@@ -99,17 +110,17 @@ struct VectorImpl
      * not overflow.
      */
     static inline bool growTo(Vector<T,N,AP> &v, size_t newcap) {
         JS_ASSERT(!v.usingInlineStorage());
         T *newbuf = reinterpret_cast<T *>(v.malloc_(newcap * sizeof(T)));
         if (!newbuf)
             return false;
         for (T *dst = newbuf, *src = v.beginNoCheck(); src != v.endNoCheck(); ++dst, ++src)
-            new(dst) T(*src);
+            new(dst) T(Move(*src));
         VectorImpl::destroy(v.beginNoCheck(), v.endNoCheck());
         v.free_(v.mBegin);
         v.mBegin = newbuf;
         /* v.mLength is unchanged. */
         v.mCapacity = newcap;
         return true;
     }
 };
@@ -145,16 +156,21 @@ struct VectorImpl<T, N, AP, true>
          * requiring T == U.
          *
          * memcpy(dst, srcbeg, sizeof(T) * (srcend - srcbeg));
          */
         for (const U *p = srcbeg; p != srcend; ++p, ++dst)
             *dst = *p;
     }
 
+    template <class U>
+    static inline void moveConstruct(T *dst, const U *srcbeg, const U *srcend) {
+        copyConstruct(dst, srcbeg, srcend);
+    }
+
     static inline void copyConstructN(T *dst, size_t n, const T &t) {
         for (T *p = dst, *end = dst + n; p != end; ++p)
             *p = t;
     }
 
     static inline bool growTo(Vector<T,N,AP> &v, size_t newcap) {
         JS_ASSERT(!v.usingInlineStorage());
         size_t bytes = sizeof(T) * newcap;
@@ -282,27 +298,29 @@ class Vector : private AllocPolicy
     size_t reserved() const {
         JS_ASSERT(mReserved <= mCapacity);
         JS_ASSERT(mLength <= mReserved);
         return mReserved;
     }
 #endif
 
     /* Append operations guaranteed to succeed due to pre-reserved space. */
-    void internalAppend(const T &t);
+    template <class U> void internalAppend(U t);
     void internalAppendN(const T &t, size_t n);
     template <class U> void internalAppend(const U *begin, size_t length);
     template <class U, size_t O, class BP> void internalAppend(const Vector<U,O,BP> &other);
 
   public:
     static const size_t sMaxInlineStorage = N;
 
     typedef T ElementType;
 
     Vector(AllocPolicy = AllocPolicy());
+    Vector(MoveRef<Vector>); /* Move constructor. */
+    Vector &operator=(MoveRef<Vector>); /* Move assignment. */
     ~Vector();
 
     /* accessors */
 
     const AllocPolicy &allocPolicy() const {
         return *this;
     }
 
@@ -381,18 +399,25 @@ class Vector : private AllocPolicy
     bool resizeUninitialized(size_t newLength);
 
     /* Shorthand for shrinkBy(length()). */
     void clear();
 
     /* Clears and releases any heap-allocated storage. */
     void clearAndFree();
 
-    /* Potentially fallible append operations. */
-    bool append(const T &t);
+    /*
+     * Potentially fallible append operations.
+     *
+     * The function templates that take an unspecified type U require a
+     * const T & or a MoveRef<T>. The MoveRef<T> variants move their
+     * operands into the vector, instead of copying them. If they fail, the
+     * operand is left unmoved.
+     */
+    template <class U> bool append(U t);
     bool appendN(const T &t, size_t n);
     template <class U> bool append(const U *begin, const U *end);
     template <class U> bool append(const U *begin, size_t length);
     template <class U, size_t O, class BP> bool append(const Vector<U,O,BP> &other);
 
     /*
      * Guaranteed-infallible append operations for use upon vectors whose
      * memory has been pre-reserved.
@@ -462,16 +487,61 @@ JS_ALWAYS_INLINE
 Vector<T,N,AllocPolicy>::Vector(AllocPolicy ap)
   : AllocPolicy(ap), mBegin((T *)storage.addr()), mLength(0),
     mCapacity(sInlineCapacity)
 #ifdef DEBUG
   , mReserved(0), entered(false)
 #endif
 {}
 
+/* Move constructor. */
+template <class T, size_t N, class AllocPolicy>
+JS_ALWAYS_INLINE
+Vector<T, N, AllocPolicy>::Vector(MoveRef<Vector> rhs)
+    : AllocPolicy(rhs)
+{
+    mLength = rhs->mLength;
+    mCapacity = rhs->mCapacity;
+#ifdef DEBUG
+    mReserved = rhs->mReserved;
+#endif
+
+    if (rhs->usingInlineStorage()) {
+        /* We can't move the buffer over in this case, so copy elements. */
+        Impl::moveConstruct(mBegin, rhs->beginNoCheck(), rhs->endNoCheck());
+        /*
+         * Leave rhs's mLength, mBegin, mCapacity, and mReserved as they are.
+         * The elements in its in-line storage still need to be destroyed.
+         */
+    } else {
+        /*
+         * Take src's buffer, and turn src into an empty vector using
+         * in-line storage.
+         */
+        mBegin = rhs->mBegin;
+        rhs->mBegin = (T *) rhs->storage.addr();
+        rhs->mCapacity = sInlineCapacity;
+        rhs->mLength = 0;
+#ifdef DEBUG
+        rhs->mReserved = 0;
+#endif
+    }
+}
+
+/* Move assignment. */
+template <class T, size_t N, class AP>
+JS_ALWAYS_INLINE
+Vector<T, N, AP> &
+Vector<T, N, AP>::operator=(MoveRef<Vector> rhs)
+{
+    this->~Vector();
+    new(this) Vector(rhs);
+    return *this;
+}
+
 template <class T, size_t N, class AP>
 JS_ALWAYS_INLINE
 Vector<T,N,AP>::~Vector()
 {
     REENTRANCY_GUARD_ET_AL;
     Impl::destroy(beginNoCheck(), endNoCheck());
     if (!usingInlineStorage())
         this->free_(beginNoCheck());
@@ -542,17 +612,17 @@ Vector<T,N,AP>::convertToHeapStorage(siz
         return false;
 
     /* Allocate buffer. */
     T *newBuf = reinterpret_cast<T *>(this->malloc_(newCap * sizeof(T)));
     if (!newBuf)
         return false;
 
     /* Copy inline elements into heap buffer. */
-    Impl::copyConstruct(newBuf, beginNoCheck(), endNoCheck());
+    Impl::moveConstruct(newBuf, beginNoCheck(), endNoCheck());
     Impl::destroy(beginNoCheck(), endNoCheck());
 
     /* Switch in heap buffer. */
     mBegin = newBuf;
     /* mLength is unchanged. */
     mCapacity = newCap;
     return true;
 }
@@ -567,26 +637,26 @@ Vector<T,N,AP>::growStorageBy(size_t inc
          : growHeapStorageBy(incr);
 }
 
 template <class T, size_t N, class AP>
 inline bool
 Vector<T,N,AP>::reserve(size_t request)
 {
     REENTRANCY_GUARD_ET_AL;
-    if (request <= mCapacity || growStorageBy(request - mLength)) {
+    if (request > mCapacity && !growStorageBy(request - mLength))
+        return false;
+
 #ifdef DEBUG
-        if (request > mReserved)
-            mReserved = request;
-        JS_ASSERT(mLength <= mReserved);
-        JS_ASSERT(mReserved <= mCapacity);
+    if (request > mReserved)
+        mReserved = request;
+    JS_ASSERT(mLength <= mReserved);
+    JS_ASSERT(mReserved <= mCapacity);
 #endif
-        return true;
-    }
-    return false;
+    return true;
 }
 
 template <class T, size_t N, class AP>
 inline void
 Vector<T,N,AP>::shrinkBy(size_t incr)
 {
     REENTRANCY_GUARD_ET_AL;
     JS_ASSERT(incr <= mLength);
@@ -674,34 +744,36 @@ Vector<T,N,AP>::clearAndFree()
     mBegin = (T *)storage.addr();
     mCapacity = sInlineCapacity;
 #ifdef DEBUG
     mReserved = 0;
 #endif
 }
 
 template <class T, size_t N, class AP>
+template <class U>
 JS_ALWAYS_INLINE bool
-Vector<T,N,AP>::append(const T &t)
+Vector<T,N,AP>::append(U t)
 {
     REENTRANCY_GUARD_ET_AL;
     if (mLength == mCapacity && !growStorageBy(1))
         return false;
 
 #ifdef DEBUG
     if (mLength + 1 > mReserved)
         mReserved = mLength + 1;
 #endif
     internalAppend(t);
     return true;
 }
 
 template <class T, size_t N, class AP>
+template <class U>
 JS_ALWAYS_INLINE void
-Vector<T,N,AP>::internalAppend(const T &t)
+Vector<T,N,AP>::internalAppend(U t)
 {
     JS_ASSERT(mLength + 1 <= mReserved);
     JS_ASSERT(mReserved <= mCapacity);
     new(endNoCheck()) T(t);
     ++mLength;
 }
 
 template <class T, size_t N, class AP>
@@ -876,17 +948,17 @@ Vector<T,N,AP>::replaceRawBuffer(T *p, s
         /*
          * We convert to inline storage if possible, even though p might
          * otherwise be acceptable.  Maybe this behaviour should be
          * specifiable with an argument to this function.
          */
         mBegin = (T *)storage.addr();
         mLength = length;
         mCapacity = sInlineCapacity;
-        Impl::copyConstruct(mBegin, p, p + length);
+        Impl::moveConstruct(mBegin, p, p + length);
         Impl::destroy(p, p + length);
         this->free_(p);
     } else {
         mBegin = p;
         mLength = length;
         mCapacity = length;
     }
 #ifdef DEBUG
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -4785,38 +4785,43 @@ Help(JSContext *cx, uintN argc, jsval *v
     int did_header, did_something;
     JSType type;
     JSFunction *fun;
     JSString *str;
 
     fprintf(gOutFile, "%s\n", JS_GetImplementationVersion());
     if (argc == 0) {
         fputs(shell_help_header, gOutFile);
-        for (i = 0; shell_functions[i].name; i++)
+        for (i = 0; i < JS_ARRAY_LENGTH(shell_help_messages); ++i)
             fprintf(gOutFile, "%s\n", shell_help_messages[i]);
     } else {
         did_header = 0;
         jsval *argv = JS_ARGV(cx, vp);
         for (i = 0; i < argc; i++) {
             did_something = 0;
             type = JS_TypeOfValue(cx, argv[i]);
             if (type == JSTYPE_FUNCTION) {
                 fun = JS_ValueToFunction(cx, argv[i]);
                 str = fun->atom;
             } else if (type == JSTYPE_STRING) {
                 str = JSVAL_TO_STRING(argv[i]);
             } else {
                 str = NULL;
             }
             if (str) {
-                JSFlatString *flatStr = JS_FlattenString(cx, str);
-                if (!flatStr)
+                JSAutoByteString funcName(cx, str);
+                if (!funcName)
                     return JS_FALSE;
-                for (j = 0; shell_functions[j].name; j++) {
-                    if (JS_FlatStringEqualsAscii(flatStr, shell_functions[j].name)) {
+                for (j = 0; j < JS_ARRAY_LENGTH(shell_help_messages); ++j) {
+                    /* Help messages are required to be formatted "functionName(..." */
+                    const char *msg = shell_help_messages[j];
+                    const char *p = strchr(msg, '(');
+                    JS_ASSERT(p);
+
+                    if (strncmp(funcName.ptr(), msg, p - msg) == 0) {
                         if (!did_header) {
                             did_header = 1;
                             fputs(shell_help_header, gOutFile);
                         }
                         did_something = 1;
                         fprintf(gOutFile, "%s\n", shell_help_messages[j]);
                         break;
                     }
--- a/js/src/tests/ecma_5/Global/jstests.list
+++ b/js/src/tests/ecma_5/Global/jstests.list
@@ -1,11 +1,11 @@
 url-prefix ../../jsreftest.html?test=ecma_5/Global/
 fails-if(!xulRuntime.shell) script adding-global-var-nonextensible-error.js
-fails-if(!xulRuntime.shell) script cross-global-implicit-this.js
+skip-if(!xulRuntime.shell) script cross-global-implicit-this.js
 script parseInt-01.js
 script parseFloat-01.js
 script eval-01.js
 script eval-02.js
 script eval-inside-with-is-direct.js
 script parenthesized-eval-is-direct.js
 script eval-native-callback-is-indirect.js
 script direct-eval-but-not.js
--- a/js/src/tests/ecma_5/RegExp/jstests.list
+++ b/js/src/tests/ecma_5/RegExp/jstests.list
@@ -6,8 +6,9 @@ script empty-lookahead.js
 script exec.js
 script exec-lastIndex-ToInteger.js
 script regress-576828.js
 script regress-613820-1.js
 script regress-613820-2.js
 script regress-613820-3.js
 silentfail skip-if(!xulRuntime.shell&&(Android||xulRuntime.OS=="WINNT")) script regress-617935.js
 script instance-property-storage-introspection.js
+script regexp-space-character-class.js
new file mode 100644
--- /dev/null
+++ b/js/src/tests/ecma_5/RegExp/regexp-space-character-class.js
@@ -0,0 +1,80 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+* Version: MPL 1.1/GPL 2.0/LGPL 2.1
+*
+* The contents of this file are subject to the Mozilla Public License Version
+* 1.1 (the "License"); you may not use this file except in compliance with
+* the License. You may obtain a copy of the License at
+* http://www.mozilla.org/MPL/
+*
+* 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 JavaScript Engine testing utilities.
+*
+* The Initial Developer of the Original Code is
+* Mozilla Foundation.
+* Portions created by the Initial Developer are Copyright (C) 2008
+* the Initial Developer. All Rights Reserved.
+*
+* Contributor(s): Dave Mandelin
+*
+* Alternatively, the contents of this file may be used under the terms of
+* either the GNU General Public License Version 2 or later (the "GPL"), or
+* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+* in which case the provisions of the GPL or the LGPL are applicable instead
+* of those above. If you wish to allow use of your version of this file only
+* under the terms of either the GPL or the LGPL, and not to allow others to
+* use your version of this file under the terms of the MPL, indicate your
+* decision by deleting the provisions above and replace them with the notice
+* and other provisions required by the GPL or the LGPL. If you do not delete
+* the provisions above, a recipient may use your version of this file under
+* the terms of any one of the MPL, the GPL or the LGPL.
+*
+* ***** END LICENSE BLOCK ***** */
+ 
+var gTestfile = 'regexp-space-character-class.js';
+//-----------------------------------------------------------------------------
+var BUGNUMBER = 514808;
+var summary = 'Correct space character class in regexes';
+var actual = '';
+var expect = '';
+ 
+ 
+//-----------------------------------------------------------------------------
+test();
+//-----------------------------------------------------------------------------
+ 
+function test()
+{
+enterFunc ('test');
+printBugNumber(BUGNUMBER);
+printStatus (summary);
+ 
+var spaces = [ "\u0009", "\u000b", "\u000c", "\u0020", "\u00a0", "\u1680",
+"\u180e", "\u2000", "\u2001", "\u2002", "\u2003", "\u2004",
+"\u2005", "\u2006", "\u2007", "\u2008", "\u2009", "\u200a",
+"\u202f", "\u205f", "\u3000" ];
+var line_terminators = [ "\u2028", "\u2029", "\u000a", "\u000d" ];
+var space_chars = [].concat(spaces, line_terminators);
+ 
+var non_space_chars = [ "\u200b", "\u200c", "\u200d",
+"\ufeff" ];
+ 
+var chars = [].concat(space_chars, non_space_chars);
+var is_space = [].concat(space_chars.map(function(ch) { return true; }),
+non_space_chars.map(function(ch) { return false; }));
+var expect = is_space.join(',');
+ 
+var actual = chars.map(function(ch) { return /\s/.test(ch); }).join(',');
+reportCompare(expect, actual, summary);
+ 
+jit(true);
+var actual = chars.map(function(ch) { return /\s/.test(ch); }).join(',');
+reportCompare(expect, actual, summary);
+jit(false);
+ 
+exitFunc ('test');
+}
--- a/js/src/tests/ecma_5/misc/jstests.list
+++ b/js/src/tests/ecma_5/misc/jstests.list
@@ -10,8 +10,9 @@ script function-definition-eval.js
 skip-if(!xulRuntime.shell) script function-definition-evaluate.js # needs evaluate()
 script future-reserved-words.js
 script builtin-methods-reject-null-undefined-this.js
 script regress-bug632003.js
 script new-with-non-constructor.js
 script error-undefined-message.js
 script regexp-functions-with-undefined.js
 script unnamed-function.js
+script unicode-identifier-1d17.js
new file mode 100644
--- /dev/null
+++ b/js/src/tests/ecma_5/misc/unicode-identifier-1d17.js
@@ -0,0 +1,27 @@
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/licenses/publicdomain/
+ */
+
+
+var BUGNUMBER = 497692;
+var summary = 'Javascript does not treat Unicode 1D17 as valid identifier character';
+
+print(BUGNUMBER + ": " + summary);
+
+/**************
+ * BEGIN TEST *
+ **************/
+
+var o = {}
+try {
+    eval('o.\\u1D17 = 42');
+}
+catch (e) {
+    assertEq('should not fail', true);
+}
+
+assertEq(o['\u1d17'], 42);
+
+if (typeof reportCompare == 'function')
+    reportCompare(true, true);
--- a/js/src/xpconnect/src/xpcjsruntime.cpp
+++ b/js/src/xpconnect/src/xpcjsruntime.cpp
@@ -37,31 +37,33 @@
  * 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 ***** */
 
 /* Per JSRuntime object */
 
 #include "xpcprivate.h"
+#include "xpcpublic.h"
 #include "WrapperFactory.h"
 #include "dom_quickstubs.h"
 
 #include "jsgcchunk.h"
 #include "jsscope.h"
 #include "nsIMemoryReporter.h"
 #include "nsPrintfCString.h"
 #include "mozilla/FunctionTimer.h"
 #include "prsystem.h"
 
 #ifdef MOZ_CRASHREPORTER
 #include "nsExceptionHandler.h"
 #endif
 
 using namespace mozilla;
+using namespace mozilla::xpconnect::memory;
 
 /***************************************************************************/
 
 const char* XPCJSRuntime::mStrings[] = {
     "constructor",          // IDX_CONSTRUCTOR
     "toString",             // IDX_TO_STRING
     "toSource",             // IDX_TO_SOURCE
     "lastResult",           // IDX_LAST_RESULT
@@ -1222,16 +1224,215 @@ XPCJSRuntime::~XPCJSRuntime()
 #ifdef DEBUG_shaver_off
         fprintf(stderr, "nJRSI: destroyed runtime %p\n", (void *)mJSRuntime);
 #endif
     }
 
     XPCPerThreadData::ShutDown();
 }
 
+namespace {
+
+PRInt64
+GetCompartmentScriptsSize(JSCompartment *c)
+{
+    PRInt64 n = 0;
+    for(JSScript *script = (JSScript *)c->scripts.next;
+        &script->links != &c->scripts;
+        script = (JSScript *)script->links.next)
+    {
+        n += script->totalSize();
+    }
+    return n;
+}
+
+#ifdef JS_METHODJIT
+
+PRInt64
+GetCompartmentMjitCodeSize(JSCompartment *c)
+{
+    return c->getMjitCodeSize();
+}
+
+PRInt64
+GetCompartmentMjitDataSize(JSCompartment *c)
+{
+    PRInt64 n = 0;
+    for(JSScript *script = (JSScript *)c->scripts.next;
+        &script->links != &c->scripts;
+        script = (JSScript *)script->links.next)
+    {
+        n += script->jitDataSize();
+    }
+    return n;
+}
+
+#endif  // JS_METHODJIT
+
+#ifdef JS_TRACER
+
+PRInt64
+GetCompartmentTjitCodeSize(JSCompartment *c)
+{
+    if(c->hasTraceMonitor())
+    {
+        size_t total, frag_size, free_size;
+        c->traceMonitor()->getCodeAllocStats(total, frag_size, free_size);
+        return total;
+    }
+    return 0;
+}
+
+PRInt64
+GetCompartmentTjitDataAllocatorsMainSize(JSCompartment *c)
+{
+    return c->hasTraceMonitor()
+         ? c->traceMonitor()->getVMAllocatorsMainSize()
+         : 0;
+}
+
+PRInt64
+GetCompartmentTjitDataAllocatorsReserveSize(JSCompartment *c)
+{
+    return c->hasTraceMonitor()
+         ? c->traceMonitor()->getVMAllocatorsReserveSize()
+         : 0;
+}
+
+#endif  // JS_TRACER
+
+void
+CompartmentCallback(JSContext *cx, void *vdata, JSCompartment *compartment)
+{
+    // Append a new CompartmentStats to the vector.
+    IterateData *data = static_cast<IterateData *>(vdata);
+    CompartmentStats compartmentStats(cx, compartment);
+    data->compartmentStatsVector.infallibleAppend(compartmentStats);
+    CompartmentStats *curr = data->compartmentStatsVector.end() - 1;
+    data->currCompartmentStats = curr;
+
+    // Get the compartment-level numbers.
+    curr->scripts = GetCompartmentScriptsSize(compartment);
+#ifdef JS_METHODJIT
+    curr->mjitCode = GetCompartmentMjitCodeSize(compartment);
+    curr->mjitData = GetCompartmentMjitDataSize(compartment);
+#endif
+#ifdef JS_TRACER
+    curr->tjitCode = GetCompartmentTjitCodeSize(compartment);
+    curr->tjitDataAllocatorsMain = GetCompartmentTjitDataAllocatorsMainSize(compartment);
+    curr->tjitDataAllocatorsReserve = GetCompartmentTjitDataAllocatorsReserveSize(compartment);
+#endif
+}
+
+void
+ArenaCallback(JSContext *cx, void *vdata, js::gc::Arena *arena,
+              size_t traceKind, size_t thingSize)
+{
+    IterateData *data = static_cast<IterateData *>(vdata);
+    data->currCompartmentStats->gcHeapArenaHeaders +=
+        sizeof(js::gc::ArenaHeader);
+    data->currCompartmentStats->gcHeapArenaPadding +=
+        arena->thingsStartOffset(thingSize) - sizeof(js::gc::ArenaHeader);
+    // We don't call the callback on unused things.  So we compute the
+    // unused space like this:  arenaUnused = maxArenaUnused - arenaUsed.
+    // We do this by setting arenaUnused to maxArenaUnused here, and then
+    // subtracting thingSize for every used cell, in CellCallback().
+    data->currCompartmentStats->gcHeapArenaUnused += arena->thingsSpan(thingSize);
+}
+
+void
+CellCallback(JSContext *cx, void *vdata, void *thing, size_t traceKind,
+             size_t thingSize)
+{
+    IterateData *data = static_cast<IterateData *>(vdata);
+    CompartmentStats *curr = data->currCompartmentStats;
+    if(traceKind == JSTRACE_OBJECT)
+    {
+        curr->gcHeapObjects += thingSize;
+        JSObject *obj = static_cast<JSObject *>(thing);
+        if(obj->hasSlotsArray())
+            curr->objectSlots += obj->numSlots() * sizeof(js::Value);
+    }
+    else if(traceKind == JSTRACE_STRING)
+    {
+        curr->gcHeapStrings += thingSize;
+        JSString *str = static_cast<JSString *>(thing);
+        curr->stringChars += str->charsHeapSize();
+    }
+    else if(traceKind == JSTRACE_SHAPE)
+    {
+        curr->gcHeapShapes += thingSize;
+        js::Shape *shape = static_cast<js::Shape *>(thing);
+        if(shape->hasTable())
+            curr->propertyTables += shape->getTable()->sizeOf();
+    }
+    else
+    {
+        JS_ASSERT(traceKind == JSTRACE_XML);
+        curr->gcHeapXml += thingSize;
+    }
+    // Yes, this is a subtraction:  see ArenaCallback() for details.
+    curr->gcHeapArenaUnused -= thingSize;
+}
+
+template <int N>
+inline void
+ReportMemory(const nsACString &path, PRInt32 kind, PRInt32 units,
+             PRInt64 amount, const char (&desc)[N],
+             nsIMemoryMultiReporterCallback *callback, nsISupports *closure)
+{
+    callback->Callback(NS_LITERAL_CSTRING(""), path, kind, units, amount,
+                       NS_LITERAL_CSTRING(desc), closure);
+}
+
+template <int N>
+inline void
+ReportMemoryBytes(const nsACString &path, PRInt32 kind, PRInt64 amount,
+                  const char (&desc)[N],
+                  nsIMemoryMultiReporterCallback *callback,
+                  nsISupports *closure)
+{
+    ReportMemory(path, kind, nsIMemoryReporter::UNITS_BYTES, amount, desc,
+                 callback, closure);
+}
+
+template <int N>
+inline void
+ReportMemoryBytes0(const nsCString &path, PRInt32 kind, PRInt64 amount,
+                   const char (&desc)[N],
+                   nsIMemoryMultiReporterCallback *callback,
+                   nsISupports *closure)
+{
+    if(amount)
+        ReportMemoryBytes(path, kind, amount, desc, callback, closure);
+}
+
+template <int N>
+inline void
+ReportMemoryPercentage(const nsACString &path, PRInt32 kind, PRInt64 amount,
+                       const char (&desc)[N],
+                       nsIMemoryMultiReporterCallback *callback,
+                       nsISupports *closure)
+{
+    ReportMemory(path, kind, nsIMemoryReporter::UNITS_PERCENTAGE, amount, desc,
+                 callback, closure);
+}
+
+template <int N>
+inline const nsCString
+MakeMemoryReporterPath(const nsACString &pathPrefix,
+                       const nsACString &compartmentName,
+                       const char (&reporterName)[N])
+{
+  return pathPrefix + NS_LITERAL_CSTRING("compartment(") + compartmentName +
+         NS_LITERAL_CSTRING(")/") + nsDependentCString(reporterName);
+}
+
+} // anonymous namespace
+
 class XPConnectGCChunkAllocator
     : public js::GCChunkAllocator
 {
 public:
     XPConnectGCChunkAllocator() {}
 
     PRInt64 GetGCChunkBytesInUse() {
         return mNumGCChunksInUse * js::GC_CHUNK_SIZE;
@@ -1278,35 +1479,16 @@ static XPConnectGCChunkAllocator gXPCJSC
 NS_MEMORY_REPORTER_IMPLEMENT(XPConnectJSGCHeap,
     "js-gc-heap",
     KIND_OTHER,
     nsIMemoryReporter::UNITS_BYTES,
     gXPCJSChunkAllocator.GetGCChunkBytesInUse,
     "Memory used by the garbage-collected JavaScript heap.")
 
 static PRInt64
-GetJSStack()
-{
-    JSRuntime *rt = nsXPConnect::GetRuntimeInstance()->GetJSRuntime();
-    PRInt64 n = 0;
-    for (js::ThreadDataIter i(rt); !i.empty(); i.popFront())
-        n += i.threadData()->stackSpace.committedSize();
-    return n;
-}
-
-NS_MEMORY_REPORTER_IMPLEMENT(XPConnectJSStack,
-    "explicit/js/stack",
-    KIND_NONHEAP,
-    nsIMemoryReporter::UNITS_BYTES,
-    GetJSStack,
-    "Memory used for the JavaScript stack.  This is the committed portion "
-    "of the stack; any uncommitted portion is not measured because it "
-    "hardly costs anything.")
-
-static PRInt64
 GetJSSystemCompartmentCount()
 {
     JSRuntime *rt = nsXPConnect::GetRuntimeInstance()->GetJSRuntime();
     size_t n = 0;
     for (size_t i = 0; i < rt->compartments.length(); i++) {
         if (rt->compartments[i]->isSystemCompartment) {
             n++;
         }
@@ -1349,448 +1531,337 @@ NS_MEMORY_REPORTER_IMPLEMENT(XPConnectJS
     KIND_OTHER,
     nsIMemoryReporter::UNITS_COUNT,
     GetJSUserCompartmentCount,
     "The number of JavaScript compartments for user code.  The sum of this "
     "and 'js-compartments-system' might not match the number of "
     "compartments listed under 'js' if a garbage collection occurs at an "
     "inopportune time, but such cases should be rare.")
 
-class XPConnectJSCompartmentsMultiReporter : public nsIMemoryMultiReporter
+namespace mozilla {
+namespace xpconnect {
+namespace memory {
+
+CompartmentStats::CompartmentStats(JSContext *cx, JSCompartment *c)
 {
-private:
-    struct CompartmentStats
-    {
-        CompartmentStats(JSContext *cx, JSCompartment *c) {
-            memset(this, 0, sizeof(*this));
+    memset(this, 0, sizeof(*this));
 
-            if (c == cx->runtime->atomsCompartment) {
-                name = NS_LITERAL_CSTRING("atoms");
-            } else if (c->principals) {
-                if (c->principals->codebase) {
-                    // A hack: replace forward slashes with '\\' so they aren't
-                    // treated as path separators.  Users of the reporters
-                    // (such as about:memory) have to undo this change.
-                    name.Assign(c->principals->codebase);
-                    char* cur = name.BeginWriting();
-                    char* end = name.EndWriting();
-                    for (; cur < end; ++cur) {
-                        if ('/' == *cur) {
-                            *cur = '\\';
-                        }
-                    }
-                    // If it's the system compartment, append the address.
-                    // This means that multiple system compartments (and there
-                    // can be many) can be distinguished.
-                    if (c->isSystemCompartment) {
-                        static const int maxLength = 31;   // ample; 64-bit address max is 18 chars
-                        nsPrintfCString address(maxLength, ", 0x%llx", PRUint64(c));
-                        name.Append(address);
-                    }
-                } else {
-                    name = NS_LITERAL_CSTRING("null-codebase");
-                }
-            } else {
-                name = NS_LITERAL_CSTRING("null-principal");
+    if(c == cx->runtime->atomsCompartment)
+    {
+        name.AssignLiteral("atoms");
+    }
+    else if(c->principals)
+    {
+        if(c->principals->codebase)
+        {
+            // A hack: replace forward slashes with '\\' so they aren't
+            // treated as path separators.  Users of the reporters
+            // (such as about:memory) have to undo this change.
+            name.Assign(c->principals->codebase);
+            name.ReplaceChar('/', '\\');
+
+            // If it's the system compartment, append the address.
+            // This means that multiple system compartments (and there
+            // can be many) can be distinguished.
+            if(c->isSystemCompartment)
+            {
+                // ample; 64-bit address max is 18 chars
+                static const int maxLength = 31;
+                nsPrintfCString address(maxLength, ", 0x%llx", PRUint64(c));
+                name.Append(address);
             }
         }
-
-        nsCString name;
-        PRInt64 gcHeapArenaHeaders;
-        PRInt64 gcHeapArenaPadding;
-        PRInt64 gcHeapArenaUnused;
-
-        PRInt64 gcHeapObjects;
-        PRInt64 gcHeapStrings;
-        PRInt64 gcHeapShapes;
-        PRInt64 gcHeapXml;
-
-        PRInt64 objectSlots;
-        PRInt64 stringChars;
-        PRInt64 propertyTables;
+        else
+        {
+            name.AssignLiteral("null-codebase");
+        }
+    }
+    else
+    {
+        name.AssignLiteral("null-principal");
+    }
+}
 
-        PRInt64 scripts;
-#ifdef JS_METHODJIT
-        PRInt64 mjitCode;
-        PRInt64 mjitData;
-#endif
-#ifdef JS_TRACER
-        PRInt64 tjitCode;
-        PRInt64 tjitDataAllocatorsMain;
-        PRInt64 tjitDataAllocatorsReserve;
-#endif
-    };
-
-    struct IterateData
+JSBool
+CollectCompartmentStatsForRuntime(JSRuntime *rt, IterateData *data)
+{
+    JSContext *cx = JS_NewContext(rt, 0);
+    if(!cx)
     {
-        IterateData(JSRuntime *rt)
-        : compartmentStatsVector()
-        , currCompartmentStats(NULL)
-        {
-            compartmentStatsVector.reserve(rt->compartments.length());
-        }
-
-        js::Vector<CompartmentStats, 0, js::SystemAllocPolicy> compartmentStatsVector;
-        CompartmentStats *currCompartmentStats;
-    };
-
-    static PRInt64
-    GetCompartmentScriptsSize(JSCompartment *c)
-    {
-        PRInt64 n = 0;
-        for (JSScript *script = (JSScript *)c->scripts.next;
-             &script->links != &c->scripts;
-             script = (JSScript *)script->links.next)
-        {
-            n += script->totalSize(); 
-        }
-        return n;
+        NS_ERROR("couldn't create context for memory tracing");
+        return false;
     }
 
-    #ifdef JS_METHODJIT
-
-    static PRInt64
-    GetCompartmentMjitCodeSize(JSCompartment *c)
     {
-        return c->getMjitCodeSize();
-    }
+      JSAutoRequest ar(cx);
 
-    static PRInt64
-    GetCompartmentMjitDataSize(JSCompartment *c)
-    {
-        PRInt64 n = 0;
-        for (JSScript *script = (JSScript *)c->scripts.next;
-             &script->links != &c->scripts;
-             script = (JSScript *)script->links.next)
-        {
-            n += script->jitDataSize(); 
-        }
-        return n;
+      data->compartmentStatsVector.reserve(rt->compartments.length());
+      js::IterateCompartmentsArenasCells(cx, data, CompartmentCallback,
+                                         ArenaCallback, CellCallback);
     }
 
-    #endif  // JS_METHODJIT
+    JS_DestroyContextNoGC(cx);
+    return true;
+}
 
-    #ifdef JS_TRACER
+void
+ReportCompartmentStats(const CompartmentStats &stats,
+                       const nsACString &pathPrefix,
+                       nsIMemoryMultiReporterCallback *callback,
+                       nsISupports *closure)
+{
+    ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats.name,
+                                              "gc-heap/arena-headers"),
+                       JS_GC_HEAP_KIND, stats.gcHeapArenaHeaders,
+    "Memory on the compartment's garbage-collected JavaScript heap, within "
+    "arenas, that is used to hold internal book-keeping information.",
+                       callback, closure);
+
+    ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats.name,
+                                              "gc-heap/arena-padding"),
+                       JS_GC_HEAP_KIND, stats.gcHeapArenaPadding,
+    "Memory on the compartment's garbage-collected JavaScript heap, within "
+    "arenas, that is unused and present only so that other data is aligned. "
+    "This constitutes internal fragmentation.",
+                       callback, closure);
 
-    static PRInt64
-    GetCompartmentTjitCodeSize(JSCompartment *c)
-    {
-        if (c->hasTraceMonitor()) {
-            size_t total, frag_size, free_size;
-            c->traceMonitor()->getCodeAllocStats(total, frag_size, free_size);
-            return total;
-        }
-        return 0;
-    }
+    ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats.name,
+                                              "gc-heap/arena-unused"),
+                       JS_GC_HEAP_KIND, stats.gcHeapArenaUnused,
+    "Memory on the compartment's garbage-collected JavaScript heap, within "
+    "arenas, that could be holding useful data but currently isn't.",
+                       callback, closure);
+
+    ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats.name,
+                                              "gc-heap/objects"),
+                       JS_GC_HEAP_KIND, stats.gcHeapObjects,
+    "Memory on the compartment's garbage-collected JavaScript heap that holds "
+    "objects.",
+                       callback, closure);
 
-    static PRInt64
-    GetCompartmentTjitDataAllocatorsMainSize(JSCompartment *c)
-    {
-        return c->hasTraceMonitor()
-             ? c->traceMonitor()->getVMAllocatorsMainSize()
-             : 0;
-    }
+    ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats.name,
+                                              "gc-heap/strings"),
+                       JS_GC_HEAP_KIND, stats.gcHeapStrings,
+    "Memory on the compartment's garbage-collected JavaScript heap that holds "
+    "string headers.  String headers contain various pieces of information "
+    "about a string, but do not contain (except in the case of very short "
+    "strings) the string characters;  characters in longer strings are counted "
+    "under 'gc-heap/string-chars' instead.",
+                       callback, closure);
+
+    ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats.name,
+                                              "gc-heap/shapes"),
+                       JS_GC_HEAP_KIND, stats.gcHeapShapes,
+    "Memory on the compartment's garbage-collected JavaScript heap that holds "
+    "shapes. A shape is an internal data structure that makes JavaScript "
+    "property accesses fast.",
+                       callback, closure);
 
-    static PRInt64
-    GetCompartmentTjitDataAllocatorsReserveSize(JSCompartment *c)
-    {
-        return c->hasTraceMonitor()
-             ? c->traceMonitor()->getVMAllocatorsReserveSize()
-             : 0;
-    }
+    ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats.name,
+                                              "gc-heap/xml"),
+                       JS_GC_HEAP_KIND, stats.gcHeapXml,
+    "Memory on the compartment's garbage-collected JavaScript heap that holds "
+    "E4X XML objects.",
+                       callback, closure);
 
-    #endif  // JS_TRACER
+    ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats.name,
+                                              "object-slots"),
+                       nsIMemoryReporter::KIND_HEAP, stats.objectSlots,
+    "Memory allocated for the compartment's non-fixed object slot arrays, "
+    "which are used to represent object properties.  Some objects also "
+    "contain a fixed number of slots which are stored on the compartment's "
+    "JavaScript heap; those slots are not counted here, but in "
+    "'gc-heap/objects' instead.",
+                       callback, closure);
+
+    ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats.name,
+                                              "string-chars"),
+                       nsIMemoryReporter::KIND_HEAP, stats.stringChars,
+    "Memory allocated to hold the compartment's string characters.  Sometimes "
+    "more memory is allocated than necessary, to simplify string "
+    "concatenation.  Each string also includes a header which is stored on the "
+    "compartment's JavaScript heap;  that header is not counted here, but in "
+    "'gc-heap/strings' instead.",
+                       callback, closure);
 
-    static void
-    CompartmentCallback(JSContext *cx, void *vdata, JSCompartment *compartment)
-    {
-        // Append a new CompartmentStats to the vector.
-        IterateData *data = static_cast<IterateData *>(vdata);
-        CompartmentStats compartmentStats(cx, compartment);
-        data->compartmentStatsVector.infallibleAppend(compartmentStats);
-        CompartmentStats *curr = data->compartmentStatsVector.end() - 1;
-        data->currCompartmentStats = curr;
+    ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats.name,
+                                              "property-tables"),
+                       nsIMemoryReporter::KIND_HEAP, stats.propertyTables,
+    "Memory allocated for the compartment's property tables.  A property "
+    "table is an internal data structure that makes JavaScript property "
+    "accesses fast.",
+                       callback, closure);
 
-        // Get the compartment-level numbers.
-        curr->scripts = GetCompartmentScriptsSize(compartment);
+    ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats.name,
+                                              "scripts"),
+                       nsIMemoryReporter::KIND_HEAP, stats.scripts,
+    "Memory allocated for the compartment's JSScripts.  A JSScript is created "
+    "for each user-defined function in a script.  One is also created for "
+    "the top-level code in a script.  Each JSScript includes byte-code and "
+    "various other things.",
+                       callback, closure);
+
 #ifdef JS_METHODJIT
-        curr->mjitCode = GetCompartmentMjitCodeSize(compartment);
-        curr->mjitData = GetCompartmentMjitDataSize(compartment);
+    ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats.name,
+                                              "mjit-code"),
+                       nsIMemoryReporter::KIND_NONHEAP, stats.mjitCode,
+    "Memory used by the method JIT to hold the compartment's generated code.",
+                       callback, closure);
+
+    ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats.name,
+                                              "mjit-data"),
+                       nsIMemoryReporter::KIND_HEAP, stats.mjitData,
+    "Memory used by the method JIT for the compartment's compilation data: "
+    "JITScripts, native maps, and inline cache structs.",
+                       callback, closure);
 #endif
 #ifdef JS_TRACER
-        curr->tjitCode = GetCompartmentTjitCodeSize(compartment);
-        curr->tjitDataAllocatorsMain = GetCompartmentTjitDataAllocatorsMainSize(compartment);
-        curr->tjitDataAllocatorsReserve = GetCompartmentTjitDataAllocatorsReserveSize(compartment);
-#endif
-    }
+    ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats.name,
+                                              "tjit-code"),
+                       nsIMemoryReporter::KIND_NONHEAP, stats.tjitCode,
+    "Memory used by the trace JIT to hold the compartment's generated code.",
+                       callback, closure);
 
-    static void
-    ArenaCallback(JSContext *cx, void *vdata, js::gc::Arena *arena,
-                  size_t traceKind, size_t thingSize)
-    {
-        IterateData *data = static_cast<IterateData *>(vdata);
-        data->currCompartmentStats->gcHeapArenaHeaders +=
-            sizeof(js::gc::ArenaHeader);
-        data->currCompartmentStats->gcHeapArenaPadding +=
-            arena->thingsStartOffset(thingSize) - sizeof(js::gc::ArenaHeader);
-        // We don't call the callback on unused things.  So we compute the
-        // unused space like this:  arenaUnused = maxArenaUnused - arenaUsed.
-        // We do this by setting arenaUnused to maxArenaUnused here, and then
-        // subtracting thingSize for every used cell, in CellCallback().
-        data->currCompartmentStats->gcHeapArenaUnused += arena->thingsSpan(thingSize);
-    }
+    ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats.name,
+                                              "tjit-data/allocators-main"),
+                       nsIMemoryReporter::KIND_HEAP,
+                       stats.tjitDataAllocatorsMain,
+    "Memory used by the trace JIT to store the compartment's trace-related "
+    "data.  This data is allocated via the compartment's VMAllocators.",
+                       callback, closure);
+
+    ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats.name,
+                                              "tjit-data/allocators-reserve"),
+                       nsIMemoryReporter::KIND_HEAP,
+                       stats.tjitDataAllocatorsReserve,
+    "Memory used by the trace JIT and held in reserve for the compartment's "
+    "VMAllocators in case of OOM.",
+                       callback, closure);
+#endif
+}
 
-    static void
-    CellCallback(JSContext *cx, void *vdata, void *thing, size_t traceKind,
-                 size_t thingSize)
-    {
-        IterateData *data = static_cast<IterateData *>(vdata);
-        CompartmentStats *curr = data->currCompartmentStats;
-        if (traceKind == JSTRACE_OBJECT) {
-            curr->gcHeapObjects += thingSize;
-            JSObject *obj = static_cast<JSObject *>(thing);
-            if (obj->hasSlotsArray()) {
-                curr->objectSlots += obj->numSlots() * sizeof(js::Value);
-            }
-        } else if (traceKind == JSTRACE_STRING) {
-            curr->gcHeapStrings += thingSize;
-            JSString *str = static_cast<JSString *>(thing);
-            curr->stringChars += str->charsHeapSize();
-        } else if (traceKind == JSTRACE_SHAPE) {
-            curr->gcHeapShapes += thingSize;
-            js::Shape *shape = static_cast<js::Shape *>(thing);
-            if (shape->hasTable()) {
-                curr->propertyTables += shape->getTable()->sizeOf();
-            }
-        } else {
-            JS_ASSERT(traceKind == JSTRACE_XML);
-            curr->gcHeapXml += thingSize;
-        }
-        // Yes, this is a subtraction:  see ArenaCallback() for details.
-        curr->gcHeapArenaUnused -= thingSize;
-    }
+void
+ReportJSStackSizeForRuntime(JSRuntime *rt, const nsACString &pathPrefix,
+                            nsIMemoryMultiReporterCallback *callback,
+                            nsISupports *closure)
+{
+    PRInt64 stackSize = 0;
+    for(js::ThreadDataIter i(rt); !i.empty(); i.popFront())
+        stackSize += i.threadData()->stackSpace.committedSize();
 
+    ReportMemoryBytes(pathPrefix + NS_LITERAL_CSTRING("stack"),
+                      nsIMemoryReporter::KIND_NONHEAP, stackSize,
+    "Memory used for the JavaScript stack.  This is the committed portion "
+    "of the stack; any uncommitted portion is not measured because it "
+    "hardly costs anything.",
+                      callback, closure);
+}
+
+} // namespace memory
+} // namespace xpconnect
+} // namespace mozilla
+
+class XPConnectJSCompartmentsMultiReporter : public nsIMemoryMultiReporter
+{
 public:
     NS_DECL_ISUPPORTS
 
-    XPConnectJSCompartmentsMultiReporter()
-    {
-    }
-
-    nsCString mkPath(const nsACString &compartmentName,
-                     const char* reporterName)
-    {
-        nsCString path(NS_LITERAL_CSTRING("explicit/js/compartment("));
-        path += compartmentName;
-        path += NS_LITERAL_CSTRING(")/");
-        path += nsDependentCString(reporterName);
-        return path;
-    }
-
     NS_IMETHOD CollectReports(nsIMemoryMultiReporterCallback *callback,
                               nsISupports *closure)
     {
         JSRuntime *rt = nsXPConnect::GetRuntimeInstance()->GetJSRuntime();
-        IterateData data(rt);
 
         // In the first step we get all the stats and stash them in a local
         // data structure.  In the second step we pass all the stashed stats to
         // the callback.  Separating these steps is important because the
         // callback may be a JS function, and executing JS while getting these
         // stats seems like a bad idea.
-        {
-            JSContext *cx = JS_NewContext(rt, 0);
-            if (!cx) {
-                NS_ERROR("couldn't create context for memory tracing");
-                return NS_ERROR_FAILURE;
-            }
-            JS_BeginRequest(cx);
-            js::IterateCompartmentsArenasCells(cx, &data, CompartmentCallback, ArenaCallback,
-                                               CellCallback);
-            JS_EndRequest(cx);
-            JS_DestroyContextNoGC(cx);
-        }
-
-        NS_NAMED_LITERAL_CSTRING(p, "");
+        IterateData data;
+        if(!CollectCompartmentStatsForRuntime(rt, &data))
+            return NS_ERROR_FAILURE;
 
         PRInt64 gcHeapChunkTotal = gXPCJSChunkAllocator.GetGCChunkBytesInUse();
         // This is initialized to gcHeapChunkTotal, and then we subtract used
         // space from it each time around the loop.
         PRInt64 gcHeapChunkUnused = gcHeapChunkTotal;
         PRInt64 gcHeapArenaUnused = 0;
 
-        #define BYTES(path, kind, amount, desc) \
-            callback->Callback(p, path, kind, nsIMemoryReporter::UNITS_BYTES, \
-                               amount, NS_LITERAL_CSTRING(desc), closure)
-
-        #define BYTES0(path, kind, amount, desc) \
-            do { \
-                if (amount != 0) \
-                    BYTES(path, kind, amount, desc); \
-            } while (0)
-
-        #define PERCENTAGE(path, kind, amount, desc) \
-            callback->Callback(p, path, kind, nsIMemoryReporter::UNITS_PERCENTAGE, \
-                               amount, NS_LITERAL_CSTRING(desc), closure);
+        NS_NAMED_LITERAL_CSTRING(pathPrefix, "explicit/js/");
 
         // This is the second step (see above).
-        for (CompartmentStats *stats = data.compartmentStatsVector.begin();
-             stats != data.compartmentStatsVector.end();
-             ++stats)
+        for(CompartmentStats *stats = data.compartmentStatsVector.begin();
+            stats != data.compartmentStatsVector.end();
+            ++stats)
         {
-            nsCString &name = stats->name;
-
             gcHeapChunkUnused -=
                 stats->gcHeapArenaHeaders + stats->gcHeapArenaPadding +
                 stats->gcHeapArenaUnused +
                 stats->gcHeapObjects + stats->gcHeapStrings +
                 stats->gcHeapShapes + stats->gcHeapXml;
 
             gcHeapArenaUnused += stats->gcHeapArenaUnused;
 
-            BYTES0(mkPath(name, "gc-heap/arena-headers"),
-               JS_GC_HEAP_KIND, stats->gcHeapArenaHeaders,
-    "Memory on the compartment's garbage-collected JavaScript heap, within "
-    "arenas, that is used to hold internal book-keeping information.");
-
-            BYTES0(mkPath(name, "gc-heap/arena-padding"),
-               JS_GC_HEAP_KIND, stats->gcHeapArenaPadding,
-    "Memory on the compartment's garbage-collected JavaScript heap, within "
-    "arenas, that is unused and present only so that other data is aligned. "
-    "This constitutes internal fragmentation.");
-
-            BYTES0(mkPath(name, "gc-heap/arena-unused"),
-               JS_GC_HEAP_KIND, stats->gcHeapArenaUnused,
-    "Memory on the compartment's garbage-collected JavaScript heap, within "
-    "arenas, that could be holding useful data but currently isn't.");
-
-            BYTES0(mkPath(name, "gc-heap/objects"),
-               JS_GC_HEAP_KIND, stats->gcHeapObjects,
-    "Memory on the compartment's garbage-collected JavaScript heap that holds "
-    "objects.");
-
-            BYTES0(mkPath(name, "gc-heap/strings"),
-               JS_GC_HEAP_KIND, stats->gcHeapStrings,
-    "Memory on the compartment's garbage-collected JavaScript heap that holds "
-    "string headers.  String headers contain various pieces of information "
-    "about a string, but do not contain (except in the case of very short "
-    "strings) the string characters;  characters in longer strings are counted "
-    "under 'gc-heap/string-chars' instead.");
-
-            BYTES0(mkPath(name, "gc-heap/shapes"),
-               JS_GC_HEAP_KIND, stats->gcHeapShapes,
-    "Memory on the compartment's garbage-collected JavaScript heap that holds "
-    "shapes. A shape is an internal data structure that makes JavaScript "
-    "property accesses fast.");
-
-            BYTES0(mkPath(name, "gc-heap/xml"),
-               JS_GC_HEAP_KIND, stats->gcHeapXml,
-    "Memory on the compartment's garbage-collected JavaScript heap that holds "
-    "E4X XML objects.");
-
-            BYTES0(mkPath(name, "object-slots"),
-               nsIMemoryReporter::KIND_HEAP, stats->objectSlots,
-    "Memory allocated for the compartment's non-fixed object slot arrays, "
-    "which are used to represent object properties.  Some objects also "
-    "contain a fixed number of slots which are stored on the compartment's "
-    "JavaScript heap; those slots are not counted here, but in "
-    "'gc-heap/objects' instead.");
-
-            BYTES0(mkPath(name, "string-chars"),
-               nsIMemoryReporter::KIND_HEAP, stats->stringChars,
-    "Memory allocated to hold the compartment's string characters.  Sometimes "
-    "more memory is allocated than necessary, to simplify string "
-    "concatenation.  Each string also includes a header which is stored on the "
-    "compartment's JavaScript heap;  that header is not counted here, but in "
-    "'gc-heap/strings' instead.");
-
-            BYTES0(mkPath(name, "property-tables"),
-               nsIMemoryReporter::KIND_HEAP, stats->propertyTables,
-    "Memory allocated for the compartment's property tables.  A property "
-    "table is an internal data structure that makes JavaScript property "
-    "accesses fast.");
-
-            BYTES0(mkPath(name, "scripts"),
-               nsIMemoryReporter::KIND_HEAP, stats->scripts,
-    "Memory allocated for the compartment's JSScripts.  A JSScript is created "
-    "for each user-defined function in a script.  One is also created for "
-    "the top-level code in a script.  Each JSScript includes byte-code and "
-    "various other things.");
-
-#ifdef JS_METHODJIT
-            BYTES0(mkPath(name, "mjit-code"),
-               nsIMemoryReporter::KIND_NONHEAP, stats->mjitCode,
-    "Memory used by the method JIT to hold the compartment's generated code.");
-
-            BYTES0(mkPath(name, "mjit-data"),
-               nsIMemoryReporter::KIND_HEAP, stats->mjitData,
-    "Memory used by the method JIT for the compartment's compilation data: "
-    "JITScripts, native maps, and inline cache structs.");
-#endif
-#ifdef JS_TRACER
-            BYTES0(mkPath(name, "tjit-code"),
-               nsIMemoryReporter::KIND_NONHEAP, stats->tjitCode,
-    "Memory used by the trace JIT to hold the compartment's generated code.");
-
-            BYTES0(mkPath(name, "tjit-data/allocators-main"),
-               nsIMemoryReporter::KIND_HEAP, stats->tjitDataAllocatorsMain,
-    "Memory used by the trace JIT to store the compartment's trace-related "
-    "data.  This data is allocated via the compartment's VMAllocators.");
-
-            BYTES0(mkPath(name, "tjit-data/allocators-reserve"),
-               nsIMemoryReporter::KIND_HEAP, stats->tjitDataAllocatorsReserve,
-    "Memory used by the trace JIT and held in reserve for the compartment's "
-    "VMAllocators in case of OOM.");
-#endif
+            ReportCompartmentStats(*stats, pathPrefix, callback, closure);
         }
 
         JS_ASSERT(gcHeapChunkTotal % js::GC_CHUNK_SIZE == 0);
         size_t numChunks = gcHeapChunkTotal / js::GC_CHUNK_SIZE;
         PRInt64 perChunkAdmin =
             sizeof(js::gc::Chunk) - (sizeof(js::gc::Arena) * js::gc::ArenasPerChunk);
         PRInt64 gcHeapChunkAdmin = numChunks * perChunkAdmin;
         gcHeapChunkUnused -= gcHeapChunkAdmin;
 
         // Why 10000x?  100x because it's a percentage, and another 100x
         // because nsIMemoryReporter requires that for percentage amounts so
         // they can be fractional.
         PRInt64 gcHeapUnusedPercentage =
             (gcHeapChunkUnused + gcHeapArenaUnused) * 10000 /
             gXPCJSChunkAllocator.GetGCChunkBytesInUse();
 
-        BYTES(NS_LITERAL_CSTRING("explicit/js/gc-heap-chunk-unused"),
-           JS_GC_HEAP_KIND, gcHeapChunkUnused,
+        ReportMemoryBytes(pathPrefix +
+                          NS_LITERAL_CSTRING("gc-heap-chunk-unused"),
+                          JS_GC_HEAP_KIND, gcHeapChunkUnused,
     "Memory on the garbage-collected JavaScript heap, within chunks, that "
-    "could be holding useful data but currently isn't.");
+    "could be holding useful data but currently isn't.",
+                          callback, closure);
 
-        BYTES(NS_LITERAL_CSTRING("js-gc-heap-chunk-unused"),
-           nsIMemoryReporter::KIND_OTHER, gcHeapChunkUnused,
+        ReportMemoryBytes(NS_LITERAL_CSTRING("js-gc-heap-chunk-unused"),
+                          nsIMemoryReporter::KIND_OTHER, gcHeapChunkUnused,
     "The same as 'explicit/js/gc-heap-chunk-unused'.  Shown here for "
-    "easy comparison with 'js-gc-heap' and 'js-gc-heap-arena-unused'.");
+    "easy comparison with 'js-gc-heap' and 'js-gc-heap-arena-unused'.",
+                          callback, closure);
 
-        BYTES(NS_LITERAL_CSTRING("explicit/js/gc-heap-chunk-admin"),
-           JS_GC_HEAP_KIND, gcHeapChunkAdmin,
+        ReportMemoryBytes(pathPrefix +
+                          NS_LITERAL_CSTRING("gc-heap-chunk-admin"),
+                          JS_GC_HEAP_KIND, gcHeapChunkAdmin,
     "Memory on the garbage-collected JavaScript heap, within chunks, that is "
-    "used to hold internal book-keeping information.");
+    "used to hold internal book-keeping information.",
+                          callback, closure);
 
-        BYTES(NS_LITERAL_CSTRING("js-gc-heap-arena-unused"),
-           nsIMemoryReporter::KIND_OTHER, gcHeapArenaUnused,
+        ReportMemoryBytes(NS_LITERAL_CSTRING("js-gc-heap-arena-unused"),
+                          nsIMemoryReporter::KIND_OTHER, gcHeapArenaUnused,
     "Memory on the garbage-collected JavaScript heap, within arenas, that "
     "could be holding useful data but currently isn't.  This is the sum of "
-    "all compartments' 'gc-heap/arena-unused' numbers.");
+    "all compartments' 'gc-heap/arena-unused' numbers.",
+                          callback, closure);
 
-        PERCENTAGE(NS_LITERAL_CSTRING("js-gc-heap-unused-fraction"),
-           nsIMemoryReporter::KIND_OTHER, gcHeapUnusedPercentage,
+        ReportMemoryPercentage(NS_LITERAL_CSTRING("js-gc-heap-unused-fraction"),
+                               nsIMemoryReporter::KIND_OTHER,
+                               gcHeapUnusedPercentage,
     "Fraction of the garbage-collected JavaScript heap that is unused. "
     "Computed as ('js-gc-heap-chunk-unused' + 'js-gc-heap-arena-unused') / "
-    "'js-gc-heap'.");
+    "'js-gc-heap'.",
+                               callback, closure);
+
+        ReportJSStackSizeForRuntime(rt, pathPrefix, callback, closure);
 
         return NS_OK;
     }
 };
+
 NS_IMPL_THREADSAFE_ISUPPORTS1(
   XPConnectJSCompartmentsMultiReporter
 , nsIMemoryMultiReporter
 )
 
 #ifdef MOZ_CRASHREPORTER
 static JSBool
 DiagnosticMemoryCallback(void *ptr, size_t size)
@@ -1863,17 +1934,16 @@ XPCJSRuntime::XPCJSRuntime(nsXPConnect* 
         if (!mWatchdogWakeup)
             NS_RUNTIMEABORT("JS_NEW_CONDVAR failed.");
 
         mJSRuntime->setActivityCallback(ActivityCallback, this);
 
         mJSRuntime->setCustomGCChunkAllocator(&gXPCJSChunkAllocator);
 
         NS_RegisterMemoryReporter(new NS_MEMORY_REPORTER_NAME(XPConnectJSGCHeap));
-        NS_RegisterMemoryReporter(new NS_MEMORY_REPORTER_NAME(XPConnectJSStack));
         NS_RegisterMemoryReporter(new NS_MEMORY_REPORTER_NAME(XPConnectJSSystemCompartmentCount));
         NS_RegisterMemoryReporter(new NS_MEMORY_REPORTER_NAME(XPConnectJSUserCompartmentCount));
         NS_RegisterMemoryMultiReporter(new XPConnectJSCompartmentsMultiReporter);
     }
 
     if(!JS_DHashTableInit(&mJSHolders, JS_DHashGetStubOps(), nsnull,
                           sizeof(ObjectHolder), 512))
         mJSHolders.ops = nsnull;
--- a/js/src/xpconnect/src/xpcpublic.h
+++ b/js/src/xpconnect/src/xpcpublic.h
@@ -38,20 +38,22 @@
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef xpcpublic_h
 #define xpcpublic_h
 
 #include "jsapi.h"
 #include "jsobj.h"
 #include "jsgc.h"
+#include "jspubtd.h"
 
 #include "nsISupports.h"
 #include "nsIPrincipal.h"
 #include "nsWrapperCache.h"
+#include "nsStringGlue.h"
 
 class nsIPrincipal;
 
 static const uint32 XPC_GC_COLOR_BLACK = 0;
 static const uint32 XPC_GC_COLOR_GRAY = 1;
 
 nsresult
 xpc_CreateGlobalObject(JSContext *cx, JSClass *clasp,
@@ -178,9 +180,72 @@ xpc_UnmarkGrayObject(JSObject *obj)
 inline JSObject*
 nsWrapperCache::GetWrapper() const
 {
   JSObject* obj = GetWrapperPreserveColor();
   xpc_UnmarkGrayObject(obj);
   return obj;
 }
 
+class nsIMemoryMultiReporterCallback;
+
+namespace mozilla {
+namespace xpconnect {
+namespace memory {
+
+struct CompartmentStats
+{
+    CompartmentStats(JSContext *cx, JSCompartment *c);
+
+    nsCString name;
+    PRInt64 gcHeapArenaHeaders;
+    PRInt64 gcHeapArenaPadding;
+    PRInt64 gcHeapArenaUnused;
+
+    PRInt64 gcHeapObjects;
+    PRInt64 gcHeapStrings;
+    PRInt64 gcHeapShapes;
+    PRInt64 gcHeapXml;
+
+    PRInt64 objectSlots;
+    PRInt64 stringChars;
+    PRInt64 propertyTables;
+
+    PRInt64 scripts;
+#ifdef JS_METHODJIT
+    PRInt64 mjitCode;
+    PRInt64 mjitData;
 #endif
+#ifdef JS_TRACER
+    PRInt64 tjitCode;
+    PRInt64 tjitDataAllocatorsMain;
+    PRInt64 tjitDataAllocatorsReserve;
+#endif
+};
+
+struct IterateData
+{
+    IterateData()
+    : compartmentStatsVector(), currCompartmentStats(NULL) { }
+
+    js::Vector<CompartmentStats, 0, js::SystemAllocPolicy> compartmentStatsVector;
+    CompartmentStats *currCompartmentStats;
+};
+
+JSBool
+CollectCompartmentStatsForRuntime(JSRuntime *rt, IterateData *data);
+
+void
+ReportCompartmentStats(const CompartmentStats &stats,
+                       const nsACString &pathPrefix,
+                       nsIMemoryMultiReporterCallback *callback,
+                       nsISupports *closure);
+
+void
+ReportJSStackSizeForRuntime(JSRuntime *rt, const nsACString &pathPrefix,
+                            nsIMemoryMultiReporterCallback *callback,
+                            nsISupports *closure);
+
+} // namespace memory
+} // namespace xpconnect
+} // namespace mozilla
+
+#endif
new file mode 100644
--- /dev/null
+++ b/layout/base/crashtests/675246-1.xhtml
@@ -0,0 +1,8 @@
+<html xmlns="http://www.w3.org/1999/xhtml" class="reftest-print">
+<style><![CDATA[
+ tfoot::after { content: "m"; position: fixed;}
+]]>
+</style>
+<td></td>
+<tfoot style="page-break-before: always;"></tfoot>
+</html>
--- a/layout/base/crashtests/crashtests.list
+++ b/layout/base/crashtests/crashtests.list
@@ -337,8 +337,9 @@ load 650475.xhtml
 load 650489.xhtml
 load 653133-1.html
 load 663295.html
 load 663662-1.html
 load 663662-2.html
 load 665837.html
 load 668941.xhtml
 load 670226.html
+asserts(2) load 675246-1.xhtml # Bug 675713
--- a/layout/base/nsCSSFrameConstructor.cpp
+++ b/layout/base/nsCSSFrameConstructor.cpp
@@ -723,17 +723,18 @@ public:
 
   // A boolean to indicate whether we have a "pending" popupgroup.  That is, we
   // have already created the FrameConstructionItem for the root popupgroup but
   // we have not yet created the relevant frame.
   PRPackedBool              mHavePendingPopupgroup;
 
   // If false (which is the default) then call SetPrimaryFrame() as needed
   // during frame construction.  If true, don't make any SetPrimaryFrame()
-  // calls.  The mCreatingExtraFrames == PR_TRUE mode is meant to be used for
+  // calls, except for generated content which doesn't have a primary frame
+  // yet.  The mCreatingExtraFrames == PR_TRUE mode is meant to be used for
   // construction of random "extra" frames for elements via normal frame
   // construction APIs (e.g. replication of things across pages in paginated
   // mode).
   PRPackedBool              mCreatingExtraFrames;
 
   nsCOMArray<nsIContent>    mGeneratedTextNodesWithInitializer;
 
   TreeMatchContext          mTreeMatchContext;
@@ -3805,17 +3806,24 @@ nsCSSFrameConstructor::ConstructFrameFro
     // childItems is empty!
     newFrame->SetInitialChildList(nsnull, childItems);
   }
 
   NS_ASSERTION(newFrame->IsFrameOfType(nsIFrame::eLineParticipant) ==
                ((bits & FCDATA_IS_LINE_PARTICIPANT) != 0),
                "Incorrectly set FCDATA_IS_LINE_PARTICIPANT bits");
 
-  if (!aState.mCreatingExtraFrames && !(bits & FCDATA_SKIP_FRAMESET)) {
+  // Even if mCreatingExtraFrames is set, we may need to SetPrimaryFrame for
+  // generated content that doesn't have one yet.  Note that we have to examine
+  // the frame bit, because by this point mIsGeneratedContent has been cleared
+  // on aItem.
+  if ((!aState.mCreatingExtraFrames ||
+       ((primaryFrame->GetStateBits() & NS_FRAME_GENERATED_CONTENT) &&
+        !aItem.mContent->GetPrimaryFrame())) &&
+       !(bits & FCDATA_SKIP_FRAMESET)) {
     aItem.mContent->SetPrimaryFrame(primaryFrame);
   }
 
   return NS_OK;
 }
 
 // after the node has been constructed and initialized create any
 // anonymous content a node needs.
--- a/layout/base/nsPresShell.cpp
+++ b/layout/base/nsPresShell.cpp
@@ -1427,29 +1427,41 @@ public:
   {
     PresShell *aShell = static_cast<PresShell*>(aEntry->GetKey());
     PRUint32 *val = (PRUint32*)userArg;
     *val += aShell->EstimateMemoryUsed();
     *val += aShell->mPresContext->EstimateMemoryUsed();
     return PL_DHASH_NEXT;
   }
 
+  static PLDHashOperator StyleSizeEnumerator(PresShellPtrKey *aEntry,
+                                             void *userArg)
+  {
+    PresShell *aShell = static_cast<PresShell*>(aEntry->GetKey());
+    PRUint32 *val = (PRUint32*)userArg;
+    *val += aShell->StyleSet()->SizeOf();
+    return PL_DHASH_NEXT;
+  }
+
   static PRUint32
   EstimateShellsMemory(nsTHashtable<PresShellPtrKey>::Enumerator aEnumerator)
   {
     PRUint32 result = 0;
     sLiveShells->EnumerateEntries(aEnumerator, &result);
     return result;
   }
-                  
-                                  
+
   static PRInt64 SizeOfLayoutMemoryReporter() {
     return EstimateShellsMemory(LiveShellSizeEnumerator);
   }
 
+  static PRInt64 SizeOfStyleMemoryReporter() {
+    return EstimateShellsMemory(StyleSizeEnumerator);
+  }
+
 protected:
   void QueryIsActive();
   nsresult UpdateImageLockingState();
 };
 
 class nsAutoCauseReflowNotifier
 {
 public:
@@ -1649,22 +1661,29 @@ NS_NewPresShell(nsIPresShell** aInstance
   NS_ADDREF(*aInstancePtrResult);
   return NS_OK;
 }
 
 nsTHashtable<PresShell::PresShellPtrKey> *nsIPresShell::sLiveShells = 0;
 static PRBool sSynthMouseMove = PR_TRUE;
 
 NS_MEMORY_REPORTER_IMPLEMENT(LayoutPresShell,
-    "explicit/layout/all",
+    "explicit/layout/arenas",
     KIND_HEAP,
     UNITS_BYTES,
     PresShell::SizeOfLayoutMemoryReporter,
     "Memory used by layout PresShell, PresContext, and other related areas.")
 
+NS_MEMORY_REPORTER_IMPLEMENT(LayoutStyle,
+    "explicit/layout/styledata",
+    KIND_HEAP,
+    UNITS_BYTES,
+    PresShell::SizeOfStyleMemoryReporter,
+    "Memory used by the style system.")
+
 PresShell::PresShell()
   : mMouseLocation(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE)
 {
   mSelection = nsnull;
 #ifdef MOZ_REFLOW_PERF
   mReflowCountMgr = new ReflowCountMgr();
   mReflowCountMgr->SetPresContext(mPresContext);
   mReflowCountMgr->SetPresShell(this);
@@ -1683,16 +1702,17 @@ PresShell::PresShell()
   mRenderFlags = 0;
   mXResolution = 1.0;
   mYResolution = 1.0;
   mViewportOverridden = PR_FALSE;
 
   static bool registeredReporter = false;
   if (!registeredReporter) {
     NS_RegisterMemoryReporter(new NS_MEMORY_REPORTER_NAME(LayoutPresShell));
+    NS_RegisterMemoryReporter(new NS_MEMORY_REPORTER_NAME(LayoutStyle));
     Preferences::AddBoolVarCache(&sSynthMouseMove,
                                  "layout.reflow.synthMouseMove", PR_TRUE);
     registeredReporter = true;
   }
 
   new (this) nsFrameManager();
 
   sLiveShells->PutEntry(this);
--- a/layout/forms/nsFormControlFrame.cpp
+++ b/layout/forms/nsFormControlFrame.cpp
@@ -182,17 +182,17 @@ nsFormControlFrame::GetFormProperty(nsIA
 
 // static
 nsRect
 nsFormControlFrame::GetUsableScreenRect(nsPresContext* aPresContext)
 {
   nsRect screen;
 
   nsDeviceContext *context = aPresContext->DeviceContext();
-  PRBool dropdownCanOverlapOSBar = PR_FALSE;
+  PRInt32 dropdownCanOverlapOSBar = PR_FALSE;
   nsILookAndFeel *lookAndFeel = aPresContext->LookAndFeel();
   lookAndFeel->GetMetric(nsILookAndFeel::eMetric_MenusCanOverlapOSBar,
                          dropdownCanOverlapOSBar);
   if ( dropdownCanOverlapOSBar )
     context->GetRect(screen);
   else
     context->GetClientRect(screen);
 
--- a/layout/generic/nsBlockReflowContext.cpp
+++ b/layout/generic/nsBlockReflowContext.cpp
@@ -114,17 +114,17 @@ nsBlockReflowContext::ComputeCollapsedTo
     // iterate not just through the lines of 'block' but also its
     // overflow lines and the normal and overflow lines of its next in
     // flows. Note that this will traverse some frames more than once:
     // for example, if A contains B and A->nextinflow contains
     // B->nextinflow, we'll traverse B->nextinflow twice. But this is
     // OK because our traversal is idempotent.
     for (nsBlockFrame* block = static_cast<nsBlockFrame*>(frame);
          block; block = static_cast<nsBlockFrame*>(block->GetNextInFlow())) {
-      for (PRBool overflowLines = PR_FALSE; overflowLines <= PR_TRUE; ++overflowLines) {
+      for (PRIntn overflowLines = PR_FALSE; overflowLines <= PR_TRUE; ++overflowLines) {
         nsBlockFrame::line_iterator line;
         nsBlockFrame::line_iterator line_end;
         PRBool anyLines = PR_TRUE;
         if (overflowLines) {
           nsLineList* lines = block->GetOverflowLines();
           if (!lines) {
             anyLines = PR_FALSE;
           } else {
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -198,22 +198,22 @@ PRBool nsFrame::GetShowEventTargetFrameB
 /**
  * Note: the log module is created during library initialization which
  * means that you cannot perform logging before then.
  */
 static PRLogModuleInfo* gLogModule;
 
 static PRLogModuleInfo* gStyleVerifyTreeLogModuleInfo;
 
-static PRBool gStyleVerifyTreeEnable = PRBool(0x55);
+static PRUint32 gStyleVerifyTreeEnable = 0x55;
 
 PRBool
 nsFrame::GetVerifyStyleTreeEnable()
 {
-  if (gStyleVerifyTreeEnable == PRBool(0x55)) {
+  if (gStyleVerifyTreeEnable == 0x55) {
     if (nsnull == gStyleVerifyTreeLogModuleInfo) {
       gStyleVerifyTreeLogModuleInfo = PR_NewLogModule("styleverifytree");
       gStyleVerifyTreeEnable = 0 != gStyleVerifyTreeLogModuleInfo->level;
     }
   }
   return gStyleVerifyTreeEnable;
 }
 
--- a/layout/generic/nsGfxScrollFrame.cpp
+++ b/layout/generic/nsGfxScrollFrame.cpp
@@ -1458,17 +1458,17 @@ nsGfxScrollFrameInner::nsGfxScrollFrameI
   , mVerticalOverflow(PR_FALSE)
   , mPostedReflowCallback(PR_FALSE)
   , mMayHaveDirtyFixedChildren(PR_FALSE)
   , mUpdateScrollbarAttributes(PR_FALSE)
   , mCollapsedResizer(PR_FALSE)
   , mShouldBuildLayer(PR_FALSE)
 {
   // lookup if we're allowed to overlap the content from the look&feel object
-  PRBool canOverlap;
+  PRInt32 canOverlap;
   nsPresContext* presContext = mOuter->PresContext();
   presContext->LookAndFeel()->
     GetMetric(nsILookAndFeel::eMetric_ScrollbarsCanOverlapContent, canOverlap);
   mScrollbarsCanOverlapContent = canOverlap;
   mScrollingActive = IsAlwaysActive();
 }
 
 nsGfxScrollFrameInner::~nsGfxScrollFrameInner()
--- a/layout/generic/nsTextRunTransformations.cpp
+++ b/layout/generic/nsTextRunTransformations.cpp
@@ -83,17 +83,17 @@ nsTransformedTextRun::SetCapitalization(
     memset(mCapitalize.Elements(), 0, GetLength()*sizeof(PRPackedBool));
   }
   memcpy(mCapitalize.Elements() + aStart, aCapitalization, aLength*sizeof(PRPackedBool));
   mNeedsRebuild = PR_TRUE;
 }
 
 PRBool
 nsTransformedTextRun::SetPotentialLineBreaks(PRUint32 aStart, PRUint32 aLength,
-                                             PRPackedBool* aBreakBefore,
+                                             PRUint8* aBreakBefore,
                                              gfxContext* aRefContext)
 {
   PRBool changed = gfxTextRun::SetPotentialLineBreaks(aStart, aLength,
       aBreakBefore, aRefContext);
   if (changed) {
     mNeedsRebuild = PR_TRUE;
   }
   return changed;
@@ -259,17 +259,17 @@ nsFontVariantTextRunFactory::RebuildText
 
   nsCaseTransformTextRunFactory uppercaseFactory(nsnull, PR_TRUE);
 
   aTextRun->ResetGlyphRuns();
 
   PRUint32 runStart = 0;
   PRBool runIsLowercase = PR_FALSE;
   nsAutoTArray<nsStyleContext*,50> styleArray;
-  nsAutoTArray<PRPackedBool,50> canBreakBeforeArray;
+  nsAutoTArray<PRUint8,50> canBreakBeforeArray;
 
   PRUint32 i;
   for (i = 0; i <= length; ++i) {
     PRBool isLowercase = PR_FALSE;
     if (i < length) {
       // Characters that aren't the start of a cluster are ignored here. They
       // get added to whatever lowercase/non-lowercase run we're in.
       if (!inner->IsClusterStart(i)) {
@@ -333,17 +333,17 @@ nsCaseTransformTextRunFactory::RebuildTe
 {
   PRUint32 length = aTextRun->GetLength();
   const PRUnichar* str = aTextRun->GetTextUnicode();
   nsRefPtr<nsStyleContext>* styles = aTextRun->mStyles.Elements();
 
   nsAutoString convertedString;
   nsAutoTArray<PRPackedBool,50> charsToMergeArray;
   nsAutoTArray<nsStyleContext*,50> styleArray;
-  nsAutoTArray<PRPackedBool,50> canBreakBeforeArray;
+  nsAutoTArray<PRUint8,50> canBreakBeforeArray;
   PRUint32 extraCharsCount = 0;
 
   PRUint32 i;
   for (i = 0; i < length; ++i) {
     PRUnichar ch = str[i];
 
     charsToMergeArray.AppendElement(PR_FALSE);
     styleArray.AppendElement(styles[i]);
--- a/layout/generic/nsTextRunTransformations.h
+++ b/layout/generic/nsTextRunTransformations.h
@@ -112,17 +112,17 @@ public:
       delete mFactory;
     }
   }
   
   void SetCapitalization(PRUint32 aStart, PRUint32 aLength,
                          PRPackedBool* aCapitalization,
                          gfxContext* aRefContext);
   virtual PRBool SetPotentialLineBreaks(PRUint32 aStart, PRUint32 aLength,
-                                        PRPackedBool* aBreakBefore,
+                                        PRUint8* aBreakBefore,
                                         gfxContext* aRefContext);
   /**
    * Called after SetCapitalization and SetPotentialLineBreaks
    * are done and before we request any data from the textrun. Also always
    * called after a Create.
    */
   void FinishSettingProperties(gfxContext* aRefContext)
   {
--- a/layout/style/AnimationCommon.cpp
+++ b/layout/style/AnimationCommon.cpp
@@ -121,16 +121,22 @@ CommonAnimationManager::HasAttributeDepe
 }
 
 /* virtual */ PRBool
 CommonAnimationManager::MediumFeaturesChanged(nsPresContext* aPresContext)
 {
   return PR_FALSE;
 }
 
+/* virtual */ PRInt64
+CommonAnimationManager::SizeOf() const
+{
+  return sizeof(*this);
+}
+
 /* static */ PRBool
 CommonAnimationManager::ExtractComputedValueForTransition(
                           nsCSSProperty aProperty,
                           nsStyleContext* aStyleContext,
                           nsStyleAnimation::Value& aComputedValue)
 {
   PRBool result =
     nsStyleAnimation::ExtractComputedValue(aProperty, aStyleContext,
--- a/layout/style/AnimationCommon.h
+++ b/layout/style/AnimationCommon.h
@@ -66,16 +66,17 @@ public:
   NS_DECL_ISUPPORTS
 
   // nsIStyleRuleProcessor (parts)
   virtual nsRestyleHint HasStateDependentStyle(StateRuleProcessorData* aData);
   virtual PRBool HasDocumentStateDependentStyle(StateRuleProcessorData* aData);
   virtual nsRestyleHint
     HasAttributeDependentStyle(AttributeRuleProcessorData* aData);
   virtual PRBool MediumFeaturesChanged(nsPresContext* aPresContext);
+  virtual PRInt64 SizeOf() const;
 
   /**
    * Notify the manager that the pres context is going away.
    */
   void Disconnect();
 
   static PRBool ExtractComputedValueForTransition(
                   nsCSSProperty aProperty,
--- a/layout/style/nsCSSRuleProcessor.cpp
+++ b/layout/style/nsCSSRuleProcessor.cpp
@@ -2449,16 +2449,24 @@ nsCSSRuleProcessor::MediumFeaturesChange
   // enabled).  And if there's nothing cached, it doesn't matter if
   // anything changed.  See bug 448281.
   if (old) {
     RefreshRuleCascade(aPresContext);
   }
   return (old != mRuleCascades);
 }
 
+/* virtual */ PRInt64
+nsCSSRuleProcessor::SizeOf() const
+{
+  size_t n = sizeof(*this);
+
+  return n;
+}
+
 // Append all the currently-active font face rules to aArray.  Return
 // true for success and false for failure.
 PRBool
 nsCSSRuleProcessor::AppendFontFaceRules(
                               nsPresContext *aPresContext,
                               nsTArray<nsFontFaceRuleContainer>& aArray)
 {
   RuleCascadeData* cascade = GetRuleCascade(aPresContext);
--- a/layout/style/nsCSSRuleProcessor.h
+++ b/layout/style/nsCSSRuleProcessor.h
@@ -131,16 +131,18 @@ public:
 
   virtual PRBool HasDocumentStateDependentStyle(StateRuleProcessorData* aData);
 
   virtual nsRestyleHint
     HasAttributeDependentStyle(AttributeRuleProcessorData* aData);
 
   virtual PRBool MediumFeaturesChanged(nsPresContext* aPresContext);
 
+  virtual PRInt64 SizeOf() const;
+
   // Append all the currently-active font face rules to aArray.  Return
   // true for success and false for failure.
   PRBool AppendFontFaceRules(nsPresContext* aPresContext,
                              nsTArray<nsFontFaceRuleContainer>& aArray);
 
   PRBool AppendKeyframesRules(nsPresContext* aPresContext,
                               nsTArray<nsCSSKeyframesRule*>& aArray);
 
--- a/layout/style/nsHTMLCSSStyleSheet.h
+++ b/layout/style/nsHTMLCSSStyleSheet.h
@@ -79,16 +79,17 @@ public:
 #ifdef MOZ_XUL
   virtual void RulesMatching(XULTreeRuleProcessorData* aData);
 #endif
   virtual nsRestyleHint HasStateDependentStyle(StateRuleProcessorData* aData);
   virtual PRBool HasDocumentStateDependentStyle(StateRuleProcessorData* aData);
   virtual nsRestyleHint
     HasAttributeDependentStyle(AttributeRuleProcessorData* aData);
   virtual PRBool MediumFeaturesChanged(nsPresContext* aPresContext);
+  virtual PRInt64 SizeOf() const { return sizeof(*this); }
 
 private: 
   // These are not supported and are not implemented! 
   nsHTMLCSSStyleSheet(const nsHTMLCSSStyleSheet& aCopy); 
   nsHTMLCSSStyleSheet& operator=(const nsHTMLCSSStyleSheet& aCopy); 
 
 protected:
   nsCOMPtr<nsIURI> mURL;
--- a/layout/style/nsHTMLStyleSheet.cpp
+++ b/layout/style/nsHTMLStyleSheet.cpp
@@ -306,16 +306,21 @@ nsHTMLStyleSheet::HasAttributeDependentS
 }
 
 /* virtual */ PRBool
 nsHTMLStyleSheet::MediumFeaturesChanged(nsPresContext* aPresContext)
 {
   return PR_FALSE;
 }
 
+/* virtual */ PRInt64
+nsHTMLStyleSheet::SizeOf() const
+{
+  return 0; // nsHTMLStyleSheets are charged to the DOM, not layout
+}
 
 /* virtual */ void
 nsHTMLStyleSheet::RulesMatching(PseudoElementRuleProcessorData* aData)
 {
 }
 
 /* virtual */ void
 nsHTMLStyleSheet::RulesMatching(AnonBoxRuleProcessorData* aData)
@@ -541,17 +546,17 @@ GetHashEntryAttributesSize(PLDHashTable*
 
   NS_ASSERTION(entry->mAttributes, "entry->mAttributes should not be null!");
   size += entry->mAttributes->SizeOf();
 
   return PL_DHASH_NEXT;
 }
 
 PRInt64
-nsHTMLStyleSheet::SizeOf() const
+nsHTMLStyleSheet::DOMSizeOf() const
 {
   PRInt64 size = sizeof(*this);
 
   size += mLinkRule ? sizeof(*mLinkRule.get()) : 0;
   size += mVisitedRule ? sizeof(*mVisitedRule.get()) : 0;
   size += mActiveRule ? sizeof(*mActiveRule.get()) : 0;
   size += mTableQuirkColorRule ? sizeof(*mTableQuirkColorRule.get()) : 0;
   size += mTableTHRule ? sizeof(*mTableTHRule.get()) : 0;
--- a/layout/style/nsHTMLStyleSheet.h
+++ b/layout/style/nsHTMLStyleSheet.h
@@ -84,30 +84,30 @@ public:
 #ifdef MOZ_XUL
   virtual void RulesMatching(XULTreeRuleProcessorData* aData);
 #endif
   virtual nsRestyleHint HasStateDependentStyle(StateRuleProcessorData* aData);
   virtual PRBool HasDocumentStateDependentStyle(StateRuleProcessorData* aData);
   virtual nsRestyleHint
     HasAttributeDependentStyle(AttributeRuleProcessorData* aData);
   virtual PRBool MediumFeaturesChanged(nsPresContext* aPresContext);
+  virtual PRInt64 SizeOf() const;
 
   nsresult Init(nsIURI* aURL, nsIDocument* aDocument);
   void Reset(nsIURI* aURL);
   nsresult SetLinkColor(nscolor aColor);
   nsresult SetActiveLinkColor(nscolor aColor);
   nsresult SetVisitedLinkColor(nscolor aColor);
 
   // Mapped Attribute management methods
   already_AddRefed<nsMappedAttributes>
     UniqueMappedAttributes(nsMappedAttributes* aMapped);
   void DropMappedAttributes(nsMappedAttributes* aMapped);
 
-  PRInt64 SizeOf() const;
-
+  PRInt64 DOMSizeOf() const;
 private: 
   // These are not supported and are not implemented! 
   nsHTMLStyleSheet(const nsHTMLStyleSheet& aCopy); 
   nsHTMLStyleSheet& operator=(const nsHTMLStyleSheet& aCopy); 
 
   ~nsHTMLStyleSheet();
 
   class HTMLColorRule;
--- a/layout/style/nsIStyleRuleProcessor.h
+++ b/layout/style/nsIStyleRuleProcessor.h
@@ -56,20 +56,20 @@ struct AnonBoxRuleProcessorData;
 #ifdef MOZ_XUL
 struct XULTreeRuleProcessorData;
 #endif
 struct StateRuleProcessorData;
 struct AttributeRuleProcessorData;
 class nsPresContext;
 
 // IID for the nsIStyleRuleProcessor interface
-// {b8e44bbe-aaac-4125-8ab2-0f42802e14ad}
+// {32612c0e-3d34-4a6f-89d9-464f6811ac13}
 #define NS_ISTYLE_RULE_PROCESSOR_IID     \
-{ 0xb8e44bbe, 0xaaac, 0x4125, \
- { 0x8a, 0xb2, 0x0f, 0x42, 0x80, 0x2e, 0x14, 0xad } }
+{ 0x32612c0e, 0x3d34, 0x4a6f, \
+  {0x89, 0xd9, 0x46, 0x4f, 0x68, 0x11, 0xac, 0x13} }
 
 
 /* The style rule processor interface is a mechanism to separate the matching
  * of style rules from style sheet instances.
  * Simple style sheets can and will act as their own processor. 
  * Sheets where rule ordering interlaces between multiple sheets, will need to 
  * share a single rule processor between them (CSS sheets do this for cascading order)
  *
@@ -149,14 +149,20 @@ public:
     HasAttributeDependentStyle(AttributeRuleProcessorData* aData) = 0;
 
   /**
    * Do any processing that needs to happen as a result of a change in
    * the characteristics of the medium, and return whether this rule
    * processor's rules have changed (e.g., because of media queries).
    */
   virtual PRBool MediumFeaturesChanged(nsPresContext* aPresContext) = 0;
+
+  /**
+   * Report the size of this style rule processor to about:memory.  A
+   * processor may return 0.
+   */
+  virtual PRInt64 SizeOf() const = 0;
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsIStyleRuleProcessor,
                               NS_ISTYLE_RULE_PROCESSOR_IID)
 
 #endif /* nsIStyleRuleProcessor_h___ */
--- a/layout/style/nsStyleSet.cpp
+++ b/layout/style/nsStyleSet.cpp
@@ -93,16 +93,30 @@ nsStyleSet::nsStyleSet()
     mBatching(0),
     mInShutdown(PR_FALSE),
     mAuthorStyleDisabled(PR_FALSE),
     mInReconstruct(PR_FALSE),
     mDirty(0)
 {
 }
 
+size_t
+nsStyleSet::SizeOf() const
+{
+  size_t n = sizeof(*this);
+
+  for (int i = 0; i < eSheetTypeCount; i++) {
+    if (mRuleProcessors[i]) {
+      n += mRuleProcessors[i]->SizeOf();
+    }
+  }
+
+  return n;
+}
+
 nsresult
 nsStyleSet::Init(nsPresContext *aPresContext)
 {
   mFirstLineRule = new nsEmptyStyleRule;
   mFirstLetterRule = new nsEmptyStyleRule;
   if (!mFirstLineRule || !mFirstLetterRule) {
     return NS_ERROR_OUT_OF_MEMORY;
   }
--- a/layout/style/nsStyleSet.h
+++ b/layout/style/nsStyleSet.h
@@ -78,16 +78,18 @@ class nsEmptyStyleRule : public nsIStyle
 // then handed off to the PresShell.  Only the PresShell should delete a
 // style set.
 
 class nsStyleSet
 {
  public:
   nsStyleSet();
 
+  size_t SizeOf() const;
+
   // Initialize the object.  You must check the return code and not use
   // the nsStyleSet if Init() fails.
 
   nsresult Init(nsPresContext *aPresContext);
 
   // For getting the cached default data in case we hit out-of-memory.
   // To be used only by nsRuleNode.
   nsCachedStyleData* DefaultStyleData() { return &mDefaultStyleData; }
--- a/layout/xul/base/src/nsMenuPopupFrame.cpp
+++ b/layout/xul/base/src/nsMenuPopupFrame.cpp
@@ -143,17 +143,17 @@ nsMenuPopupFrame::Init(nsIContent*      
 {
   nsresult rv = nsBoxFrame::Init(aContent, aParent, aPrevInFlow);
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsPresContext* presContext = PresContext();
 
   // lookup if we're allowed to overlap the OS bar (menubar/taskbar) from the
   // look&feel object
-  PRBool tempBool;
+  PRInt32 tempBool;
   presContext->LookAndFeel()->
     GetMetric(nsILookAndFeel::eMetric_MenusCanOverlapOSBar, tempBool);
   mMenuCanOverlapOSBar = tempBool;
 
   rv = CreatePopupViewForFrame();
   NS_ENSURE_SUCCESS(rv, rv);
 
   // XXX Hack. The popup's view should float above all other views,
--- a/layout/xul/base/src/nsXULPopupManager.cpp
+++ b/layout/xul/base/src/nsXULPopupManager.cpp
@@ -2085,17 +2085,17 @@ nsXULPopupManager::IsValidMenuItem(nsPre
   if (ns == kNameSpaceID_XUL) {
     if (tag != nsGkAtoms::menu && tag != nsGkAtoms::menuitem)
       return PR_FALSE;
   }
   else if (ns != kNameSpaceID_XHTML || !aOnPopup || tag != nsGkAtoms::option) {
     return PR_FALSE;
   }
 
-  PRBool skipNavigatingDisabledMenuItem = PR_TRUE;
+  PRInt32 skipNavigatingDisabledMenuItem = PR_TRUE;
   if (aOnPopup) {
     aPresContext->LookAndFeel()->
       GetMetric(nsILookAndFeel::eMetric_SkipNavigatingDisabledMenuItem,
                 skipNavigatingDisabledMenuItem);
   }
 
   return !(skipNavigatingDisabledMenuItem &&
            aContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::disabled,
--- a/mobile/chrome/content/browser.js
+++ b/mobile/chrome/content/browser.js
@@ -2726,18 +2726,18 @@ Tab.prototype = {
       } else if (!validW && !validH) {
         viewportW = this.useFallbackWidth ? kFallbackBrowserWidth : kDefaultBrowserWidth;
         viewportH = kDefaultBrowserWidth * (screenH / screenW);
       }
     }
 
     // Make sure the viewport height is not shorter than the window when
     // the page is zoomed out to show its full width.
-    let minScale = this.clampZoomLevel(this.getPageZoomLevel());
-    viewportH = Math.max(viewportH, screenH / minScale);
+    if (viewportH * this.clampZoomLevel(this.getPageZoomLevel()) < screenH)
+      viewportH = Math.max(viewportH, screenH * (browser.contentDocumentWidth / screenW));
 
     if (browser.contentWindowWidth != viewportW || browser.contentWindowHeight != viewportH)
       browser.setWindowSize(viewportW, viewportH);
   },
 
   restoreViewportPosition: function restoreViewportPosition(aOldWidth, aNewWidth) {
     let browser = this._browser;
 
@@ -2860,23 +2860,20 @@ Tab.prototype = {
       this._browser = null;
       this._loading = false;
 
       Elements.browsers.removeChild(notification);
     }
   },
 
   clampZoomLevel: function clampZoomLevel(aScale) {
-    let md = this.metadata;
-    if (!this.allowZoom)
-      return (md && md.defaultZoom) ? md.defaultZoom : this.getPageZoomLevel();
-
     let browser = this._browser;
     let bounded = Util.clamp(aScale, ZoomManager.MIN, ZoomManager.MAX);
 
+    let md = this.metadata;
     if (md && md.minZoom)
       bounded = Math.max(bounded, md.minZoom);
     if (md && md.maxZoom)
       bounded = Math.min(bounded, md.maxZoom);
 
     bounded = Math.max(bounded, this.getPageZoomLevel());
 
     let rounded = Math.round(bounded * kBrowserViewZoomLevelPrecision) / kBrowserViewZoomLevelPrecision;
--- a/mobile/chrome/content/common-ui.js
+++ b/mobile/chrome/content/common-ui.js
@@ -1269,82 +1269,84 @@ var SelectionHelper = {
 
     this._end.customDragger = {
       isDraggable: function isDraggable(target, content) { return { x: true, y: false }; },
       dragStart: function dragStart(cx, cy, target, scroller) {},
       dragStop: function dragStop(dx, dy, scroller) { return false; },
       dragMove: function dragMove(dx, dy, scroller) { return false; }
     };
 
-    this._start.addEventListener("TapDown", this, true);
     this._start.addEventListener("TapUp", this, true);
-
-    this._end.addEventListener("TapDown", this, true);
     this._end.addEventListener("TapUp", this, true);
 
     messageManager.addMessageListener("Browser:SelectionRange", this);
     messageManager.addMessageListener("Browser:SelectionCopied", this);
 
     this.popupState.target.messageManager.sendAsyncMessage("Browser:SelectionStart", { x: this.popupState.x, y: this.popupState.y });
 
-    BrowserUI.pushPopup(this, [this._start, this._end]);
-
     // Hide the selection handles
+    window.addEventListener("TapDown", this, true);
     window.addEventListener("resize", this, true);
     window.addEventListener("keypress", this, true);
     Elements.browsers.addEventListener("URLChanged", this, true);
     Elements.browsers.addEventListener("SizeChanged", this, true);
     Elements.browsers.addEventListener("ZoomChanged", this, true);
 
     let event = document.createEvent("Events");
     event.initEvent("CancelTouchSequence", true, false);
     this.popupState.target.dispatchEvent(event);
 
     return true;
   },
 
-  hide: function sh_hide() {
+  hide: function sh_hide(aEvent) {
     if (this._start.hidden)
       return;
 
+    let pos = this.popupState.target.transformClientToBrowser(aEvent.clientX || 0, aEvent.clientY || 0);
+    let json = {
+      x: pos.x,
+      y: pos.y
+    };
+
     try {
-      this.popupState.target.messageManager.sendAsyncMessage("Browser:SelectionEnd", {});
+      this.popupState.target.messageManager.sendAsyncMessage("Browser:SelectionEnd", json);
     } catch (e) {
       Cu.reportError(e);
     }
 
     this.popupState = null;
 
     this._start.hidden = true;
     this._end.hidden = true;
 
-    this._start.removeEventListener("TapDown", this, true);
     this._start.removeEventListener("TapUp", this, true);
-
-    this._end.removeEventListener("TapDown", this, true);
     this._end.removeEventListener("TapUp", this, true);
 
     messageManager.removeMessageListener("Browser:SelectionRange", this);
 
+    window.removeEventListener("TapDown", this, true);
     window.removeEventListener("resize", this, true);
     window.removeEventListener("keypress", this, true);
     Elements.browsers.removeEventListener("URLChanged", this, true);
     Elements.browsers.removeEventListener("SizeChanged", this, true);
     Elements.browsers.removeEventListener("ZoomChanged", this, true);
-
-    BrowserUI.popPopup(this);
   },
 
   handleEvent: function handleEvent(aEvent) {
     switch (aEvent.type) {
       case "TapDown":
-        this.target = aEvent.target;
-        this.deltaX = (aEvent.clientX - this.target.left);
-        this.deltaY = (aEvent.clientY - this.target.top);
-        window.addEventListener("TapMove", this, true);
+        if (aEvent.target == this._start || aEvent.target == this._end) {
+          this.target = aEvent.target;
+          this.deltaX = (aEvent.clientX - this.target.left);
+          this.deltaY = (aEvent.clientY - this.target.top);
+          window.addEventListener("TapMove", this, true);
+        } else {
+          this.hide(aEvent);
+        }
         break;
       case "TapUp":
         window.removeEventListener("TapMove", this, true);
         this.target = null;
         this.deltaX = -1;
         this.deltaY = -1;
         break;
       case "TapMove":
@@ -1362,17 +1364,17 @@ var SelectionHelper = {
           this.popupState.target.messageManager.sendAsyncMessage("Browser:SelectionMove", json);
         }
         break;
       case "resize":
       case "keypress":
       case "URLChanged":
       case "SizeChanged":
       case "ZoomChanged":
-        this.hide();
+        this.hide(aEvent);
         break;
     }
   },
 
   receiveMessage: function sh_receiveMessage(aMessage) {
     let json = aMessage.json;
     switch (aMessage.name) {
       case "Browser:SelectionRange": {
--- a/mobile/chrome/content/content.js
+++ b/mobile/chrome/content/content.js
@@ -1329,45 +1329,44 @@ var TouchEventHandler = {
 
 TouchEventHandler.init();
 
 var SelectionHandler = {
   cache: {},
   selectedText: "",
   contentWindow: null,
   
-  init: function() {
+  init: function sh_init() {
     addMessageListener("Browser:SelectionStart", this);
     addMessageListener("Browser:SelectionEnd", this);
     addMessageListener("Browser:SelectionMove", this);
   },
 
-  receiveMessage: function(aMessage) {
+  receiveMessage: function sh_receiveMessage(aMessage) {
     let scrollOffset = ContentScroll.getScrollOffset(content);
     let utils = Util.getWindowUtils(content);
     let json = aMessage.json;
 
     switch (aMessage.name) {
       case "Browser:SelectionStart": {
         this.selectedText = "";
 
         // if this is an iframe, dig down to find the document that was clicked
         let x = json.x;
         let y = json.y;
-        let offsetX = 0;
-        let offsetY = 0;
+        let offset = scrollOffset;
         let elem = utils.elementFromPoint(x, y, true, false);
         while (elem && (elem instanceof HTMLIFrameElement || elem instanceof HTMLFrameElement)) {
           // adjust client coordinates' origin to be top left of iframe viewport
           let rect = elem.getBoundingClientRect();
           scrollOffset = ContentScroll.getScrollOffset(elem.ownerDocument.defaultView);
-          offsetX += rect.left;
+          offset.x += rect.left;
           x -= rect.left;
 
-          offsetY += rect.top + scrollOffset.y;
+          offset.y += rect.top + scrollOffset.y;
           y -= rect.top + scrollOffset.y;
           utils = elem.contentDocument.defaultView.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils);
           elem = utils.elementFromPoint(x, y, true, false);
         }
         let contentWindow = elem.ownerDocument.defaultView;
         let currentDocShell = contentWindow.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIWebNavigation).QueryInterface(Ci.nsIDocShell);
 
         // Position the caret using a fake mouse click
@@ -1397,73 +1396,106 @@ var SelectionHandler = {
         this.selectedText = selection.toString().trim();
 
         // If the range didn't have any text, let's bail
         if (!this.selectedText.length) {
           selection.collapseToStart();
           return;
         }
 
-        this.cache = { start: {}, end: {} };
-        let rects = range.getClientRects();
-        for (let i=0; i<rects.length; i++) {
-          if (i == 0) {
-            this.cache.start.x = rects[i].left + offsetX;
-            this.cache.start.y = rects[i].bottom + offsetY;
-          }
-          this.cache.end.x = rects[i].right + offsetX;
-          this.cache.end.y = rects[i].bottom + offsetY;
+        this.cache = this._extractFromRange(range, offset);
+
+        let tap = { x: json.x - this.cache.offset.x, y: json.y - this.cache.offset.y };
+        pointInSelection = (tap.x > this.cache.rect.left && tap.x < this.cache.rect.right) && (tap.y > this.cache.rect.top && tap.y < this.cache.rect.bottom);
+        if (!pointInSelection) {
+          selection.collapseToStart();
+          return;
         }
 
         this.contentWindow = contentWindow;
+
         sendAsyncMessage("Browser:SelectionRange", this.cache);
         break;
       }
 
       case "Browser:SelectionEnd": {
+        let tap = { x: json.x - this.cache.offset.x, y: json.y - this.cache.offset.y };
+        pointInSelection = (tap.x > this.cache.rect.left && tap.x < this.cache.rect.right) && (tap.y > this.cache.rect.top && tap.y < this.cache.rect.bottom);
+
         try {
           // The selection might already be gone
           if (this.contentWindow)
             this.contentWindow.getSelection().collapseToStart();
           this.contentWindow = null;
         } catch(e) {}
 
-        if (this.selectedText.length) {
+        if (pointInSelection && this.selectedText.length) {
           let clipboard = Cc["@mozilla.org/widget/clipboardhelper;1"].getService(Ci.nsIClipboardHelper);
           clipboard.copyString(this.selectedText);
           sendAsyncMessage("Browser:SelectionCopied", { succeeded: true });
         } else {
           sendAsyncMessage("Browser:SelectionCopied", { succeeded: false });
         }
         break;
       }
 
       case "Browser:SelectionMove":
         if (!this.contentWindow)
           return;
+
         // Hack to avoid setting focus in a textbox [Bugs 654352 & 667243]
         let elemUnder = elementFromPoint(json.x - scrollOffset.x, json.y - scrollOffset.y);
         if (elemUnder && elemUnder instanceof Ci.nsIDOMHTMLInputElement || elemUnder instanceof Ci.nsIDOMHTMLTextAreaElement)
           return;
 
+        // Limit the selection to the initial content window (don't leave or enter iframes)
+        if (elemUnder && elemUnder.ownerDocument.defaultView != this.contentWindow)
+          return;
+
         if (json.type == "end") {
           this.cache.end.x = json.x - scrollOffset.x;
           this.cache.end.y = json.y - scrollOffset.y;
           utils.sendMouseEventToWindow("mousedown", this.cache.end.x, this.cache.end.y, 0, 1, Ci.nsIDOMNSEvent.SHIFT_MASK, true);
           utils.sendMouseEventToWindow("mouseup", this.cache.end.x, this.cache.end.y, 0, 1, Ci.nsIDOMNSEvent.SHIFT_MASK, true);
         } else {
           this.cache.start.x = json.x - scrollOffset.x;
           this.cache.start.y = json.y - scrollOffset.y;
           utils.sendMouseEventToWindow("mousedown", this.cache.start.x, this.cache.start.y, 0, 1, 0, true);
           // Don't cause a click. A mousedown is enough to move the caret
           //utils.sendMouseEventToWindow("mouseup", this.cache.start.x, this.cache.start.y, 0, 1, 0, true);
           utils.sendMouseEventToWindow("mousedown", this.cache.end.x, this.cache.end.y, 0, 1, Ci.nsIDOMNSEvent.SHIFT_MASK, true);
           utils.sendMouseEventToWindow("mouseup", this.cache.end.x, this.cache.end.y, 0, 1, Ci.nsIDOMNSEvent.SHIFT_MASK, true);
         }
 
         // Cache the selected text since the selection might be gone by the time we get the "end" message
-        this.selectedText = this.contentWindow.getSelection().toString().trim();
+        let selection = this.contentWindow.getSelection()
+        this.selectedText = selection.toString().trim();
+
+        // Update the rect we use to test when finishing the clipboard operation
+        let range = selection.getRangeAt(0).QueryInterface(Ci.nsIDOMNSRange);
+        this.cache.rect = this._extractFromRange(range, this.cache.offset).rect;
         break;
     }
+  },
+
+  _extractFromRange: function sh_extractFromRange(aRange, aOffset) {
+    let cache = { start: {}, end: {}, rect: { left: Number.MAX_VALUE, top: Number.MAX_VALUE, right: 0, bottom: 0 } };
+    let rects = aRange.getClientRects();
+    for (let i=0; i<rects.length; i++) {
+      if (i == 0) {
+        cache.start.x = rects[i].left + aOffset.x;
+        cache.start.y = rects[i].bottom + aOffset.y;
+      }
+      cache.end.x = rects[i].right + aOffset.x;
+      cache.end.y = rects[i].bottom + aOffset.y;
+    }
+    cache.rect = aRange.getBoundingClientRect();
+    cache.rect.left += aOffset.x;
+    cache.rect.top += aOffset.y;
+    cache.rect.right += aOffset.x;
+    cache.rect.bottom += aOffset.y;
+    cache.offset = aOffset;
+
+    return cache;
   }
 };
 
 SelectionHandler.init();
--- a/mobile/themes/core/gingerbread/platform.css
+++ b/mobile/themes/core/gingerbread/platform.css
@@ -732,17 +732,17 @@ dialog {
   }
   
   /* This will affect the prefs screen, but not the awesome screen */
   #panel-controls {
     -moz-box-orient: vertical !important;
     -moz-box-align: start;
   }
   
-  .panel-row-button {
+  #panel-controls > .panel-row-button {
     -moz-box-orient: horizontal;
     -moz-box-flex: 0;
     min-width: @tablet_panel_controls@ !important;
   }
 
   #panel-controls .toolbarbutton-text {
     display: -moz-box !important;
     -moz-box-flex: 1;
--- a/mobile/themes/core/platform.css
+++ b/mobile/themes/core/platform.css
@@ -745,17 +745,17 @@ dialog {
   }
   
   /* This will affect the prefs screen, but not the awesome screen */
   #panel-controls {
     -moz-box-orient: vertical !important;
     -moz-box-align: start;
   }
   
-  .panel-row-button {
+  #panel-controls > .panel-row-button {
     -moz-box-orient: horizontal;
     -moz-box-flex: 0;
     min-width: @tablet_panel_controls@ !important;
   }
 
   #panel-controls .toolbarbutton-text {
     display: -moz-box !important;
     -moz-box-flex: 1;
--- a/netwerk/test/unit/test_URIs.js
+++ b/netwerk/test/unit/test_URIs.js
@@ -522,17 +522,31 @@ var gTests = [
     nsIURL:  true, nsINestedURI: false },
   { spec:    "http://a/b/c/d;p?q",
     relativeURI: "g;x=1/../y",
     scheme:  "http",
     prePath: "http://a",
     path:    "/b/c/y",
     ref:     "",
     nsIURL:  true, nsINestedURI: false },
-
+  // protocol-relative http://tools.ietf.org/html/rfc3986#section-4.2
+  { spec:    "http://www2.example.com/",
+    relativeURI: "//www3.example2.com/bar",
+    scheme:  "http",
+    prePath: "http://www3.example2.com",
+    path:    "/bar",
+    ref:     "",
+    nsIURL:  true, nsINestedURI: false },
+  { spec:    "https://www2.example.com/",
+    relativeURI: "//www3.example2.com/bar",
+    scheme:  "https",
+    prePath: "https://www3.example2.com",
+    path:    "/bar",
+    ref:     "",
+    nsIURL:  true, nsINestedURI: false },
 ];
 
 var gHashSuffixes = [
   "#",
   "#myRef",
   "#myRef?a=b",
   "#myRef#",
   "#myRef#x:yz"
--- a/startupcache/StartupCache.cpp
+++ b/startupcache/StartupCache.cpp
@@ -505,17 +505,17 @@ StartupCacheDebugOutputStream::CheckRefe
   nsCOMPtr<nsIClassInfo> classInfo = do_QueryInterface(aObject);
   if (!classInfo) {
     NS_ERROR("aObject must implement nsIClassInfo");
     return PR_FALSE;
   }
   
   PRUint32 flags;
   rv = classInfo->GetFlags(&flags);
-  NS_ENSURE_SUCCESS(rv, rv);
+  NS_ENSURE_SUCCESS(rv, PR_FALSE);
   if (flags & nsIClassInfo::SINGLETON)
     return PR_TRUE;
   
   nsISupportsHashKey* key = mObjectMap->GetEntry(aObject);
   if (key) {
     NS_ERROR("non-singleton aObject is referenced multiple times in this" 
                   "serialization, we don't support that.");
     return PR_FALSE;
--- a/toolkit/components/places/PlacesDBUtils.jsm
+++ b/toolkit/components/places/PlacesDBUtils.jsm
@@ -109,16 +109,17 @@ let PlacesDBUtils = {
    *        Scope for the callback.
    */
   maintenanceOnIdle: function PDBU_maintenanceOnIdle(aCallback, aScope)
   {
     let tasks = new Tasks([
       this.checkIntegrity
     , this.checkCoherence
     , this._refreshUI
+    , this._telemetry
     ]);
     tasks.callback = aCallback;
     tasks.scope = aScope;
     this._executeTasks(tasks);
   },
 
   /**
    * Executes integrity check, common and advanced maintenance tasks (like
@@ -825,17 +826,160 @@ let PlacesDBUtils = {
 
     stmt.params.type = "trigger";
     while (stmt.executeStep()) {
       tasks.log("Trigger " + stmt.getString(0));
     }
     stmt.finalize();
 
     PlacesDBUtils._executeTasks(tasks);
-  }
+  },
+
+  /**
+   * Collects telemetry data.
+   *
+   * @param [optional] aTasks
+   *        Tasks object to execute.
+   */
+  _telemetry: function PDBU__telemetry(aTasks)
+  {
+    let tasks = new Tasks(aTasks);
+
+    // Hash of telemetry probes.  Each one uses the historygram name as key,
+    // and may be either a database query or an helper function.
+    let probes = {
+      PLACES_PAGES_COUNT: "SELECT count(*) FROM moz_places",
+
+      PLACES_BOOKMARKS_COUNT: "SELECT count(*) FROM moz_bookmarks b "
+                            + "JOIN moz_bookmarks t ON t.id = b.parent "
+                            + "AND t.parent <> :tags_folder "
+                            + "WHERE b.type = :type_bookmark ",
+
+      PLACES_TAGS_COUNT: "SELECT count(*) FROM moz_bookmarks "
+                       + "WHERE parent = :tags_folder ",
+
+      PLACES_FOLDERS_COUNT: "SELECT count(*) FROM moz_bookmarks "
+                          + "WHERE TYPE = :type_folder "
+                          + "AND parent NOT IN (0, :places_root, :tags_folder) ",
+
+      PLACES_KEYWORDS_COUNT: "SELECT count(*) FROM moz_keywords ",
+
+      PLACES_SORTED_BOOKMARKS_PERC: "SELECT ROUND(( "
+                                  +   "SELECT count(*) FROM moz_bookmarks b "
+                                  +   "JOIN moz_bookmarks t ON t.id = b.parent "
+                                  +   "AND t.parent <> :tags_folder AND t.parent > :places_root "
+                                  +   "WHERE b.type  = :type_bookmark "
+                                  +   ") * 100 / ( "
+                                  +   "SELECT count(*) FROM moz_bookmarks b "
+                                  +   "JOIN moz_bookmarks t ON t.id = b.parent "
+                                  +   "AND t.parent <> :tags_folder "
+                                  +   "WHERE b.type = :type_bookmark "
+                                  + ")) ",
+
+      PLACES_TAGGED_BOOKMARKS_PERC: "SELECT ROUND(( "
+                                  +   "SELECT count(*) FROM moz_bookmarks b "
+                                  +   "JOIN moz_bookmarks t ON t.id = b.parent "
+                                  +   "AND t.parent = :tags_folder "
+                                  +   ") * 100 / ( "
+                                  +   "SELECT count(*) FROM moz_bookmarks b "
+                                  +   "JOIN moz_bookmarks t ON t.id = b.parent "
+                                  +   "AND t.parent <> :tags_folder "
+                                  +   "WHERE b.type = :type_bookmark "
+                                  + ")) ",
+
+      PLACES_DATABASE_FILESIZE_MB: function () {
+        let DBFile = Services.dirsvc.get("ProfD", Ci.nsILocalFile);
+        DBFile.append("places.sqlite");
+        try {
+          return parseInt(DBFile.fileSize / 1024);
+        } catch (ex) {
+          return 0;
+        }
+      },
+
+      PLACES_DATABASE_JOURNALSIZE_MB: function () {
+        let DBFile = Services.dirsvc.get("ProfD", Ci.nsILocalFile);
+        DBFile.append("places.sqlite-wal");
+        try {
+          return parseInt(DBFile.fileSize / 1024);
+        } catch (ex) {
+          return 0;
+        }
+      },
+
+      PLACES_DATABASE_PAGESIZE_B: "PRAGMA page_size",
+
+      PLACES_DATABASE_SIZE_PER_PAGE_B: function() {
+        // Cannot use the filesize here, due to chunked growth.
+        let stmt = DBConn.createStatement("PRAGMA page_size");
+        stmt.executeStep();
+        let pageSize = stmt.row.page_size;
+        stmt.finalize();
+        stmt = DBConn.createStatement("PRAGMA page_count");
+        stmt.executeStep();
+        let pageCount = stmt.row.page_count;
+        stmt.finalize();
+        stmt = DBConn.createStatement("SELECT count(*) AS c FROM moz_places");
+        stmt.executeStep();
+        let count = stmt.row.c;
+        stmt.finalize();
+        return Math.round((pageSize * pageCount) / count);
+      }
+    };
+
+    let params = {
+      tags_folder: PlacesUtils.tagsFolderId,
+      type_folder: PlacesUtils.bookmarks.TYPE_FOLDER,
+      type_bookmark: PlacesUtils.bookmarks.TYPE_BOOKMARK,
+      places_root: PlacesUtils.placesRootId
+    };
+
+    for (let probename in probes) {
+      let probe = probes[probename];
+      let histogram = Services.telemetry.getHistogramById(probename);
+      if (typeof probe == "string") {
+        // Run it as a query.
+        let stmt = DBConn.createAsyncStatement(probe);
+        for (param in params) {
+          if (probe.indexOf(":" + param) > 0) {
+            stmt.params[param] = params[param];
+          }
+        }
+
+        try {
+          stmt.executeAsync({
+            handleError: PlacesDBUtils._handleError,
+            handleResult: function (aResultSet) {
+              let row = aResultSet.getNextRow();
+              try {
+                histogram.add(row.getResultByIndex(0));
+              } catch (ex) {
+                Components.utils.reportError("Unable to report telemetry.");
+              }
+            },
+            handleCompletion: function () {}
+          });
+        }
+        finally{
+          stmt.finalize();
+        }
+      }
+      else {
+        // Execute it as a function.
+        try {
+          histogram.add(probe());
+        } catch (ex) {
+          Components.utils.reportError("Unable to report telemetry.");
+        }
+      }
+    }
+
+    PlacesDBUtils._executeTasks(tasks);
+  },
+
 };
 
 /**
  * LIFO tasks stack.
  *
  * @param [optional] aTasks
  *        Array of tasks or another Tasks object to clone.
  */
--- a/toolkit/components/places/PlacesUtils.jsm
+++ b/toolkit/components/places/PlacesUtils.jsm
@@ -2347,19 +2347,22 @@ PlacesAggregatedTransaction.prototype = 
  */
 
 function PlacesCreateFolderTransaction(aName, aContainer, aIndex, aAnnotations,
                                        aChildItemsTransactions)
 {
   this._name = aName;
   this._container = aContainer;
   this._index = typeof(aIndex) == "number" ? aIndex : -1;
-  this._annotations = aAnnotations;
   this._id = null;
-  this.childTransactions = aChildItemsTransactions || [];
+  // Copy the array to decouple it from its prototype, which otherwise keeps
+  // alive its associated global object.
+  this._annotations = aAnnotations ? Array.slice(aAnnotations) : [];
+  this.childTransactions = aChildItemsTransactions ?
+                             Array.slice(aChildItemsTransactions) : [];
 }
 
 PlacesCreateFolderTransaction.prototype = {
   __proto__: BaseTransaction.prototype,
 
   // childItemsTransaction support
   get container() this._container,
   set container(val) this._container = val,
@@ -2434,18 +2437,20 @@ function PlacesCreateBookmarkTransaction
                                          aKeyword, aAnnotations,
                                          aChildTransactions)
 {
   this._uri = aURI;
   this._container = aContainer;
   this._index = typeof(aIndex) == "number" ? aIndex : -1;
   this._title = aTitle;
   this._keyword = aKeyword;
-  this._annotations = aAnnotations;
-  this.childTransactions = aChildTransactions || [];
+  // Copy the array to decouple it from its prototype, which otherwise keeps
+  // alive its associated global object.
+  this._annotations = aAnnotations ? Array.slice(aAnnotations) : [];
+  this.childTransactions = aChildTransactions ? Array.slice(aChildTransactions) : [];
 }
 
 PlacesCreateBookmarkTransaction.prototype = {
   __proto__: BaseTransaction.prototype,
 
   // childItemsTransactions support for the create-folder transaction
   get container() this._container,
   set container(val) this._container = val,
@@ -2556,17 +2561,19 @@ PlacesCreateSeparatorTransaction.prototy
 function PlacesCreateLivemarkTransaction(aFeedURI, aSiteURI, aName, aContainer,
                                          aIndex, aAnnotations)
 {
   this._feedURI = aFeedURI;
   this._siteURI = aSiteURI;
   this._name = aName;
   this._container = aContainer;
   this._index = typeof(aIndex) == "number" ? aIndex : -1;
-  this._annotations = aAnnotations;
+  // Copy the array to decouple it from its prototype, which otherwise keeps
+  // alive its associated global object.
+  this._annotations = aAnnotations ? Array.slice(aAnnotations) : [];
 }
 
 PlacesCreateLivemarkTransaction.prototype = {
   __proto__: BaseTransaction.prototype,
 
   // childItemsTransaction support
   get container() this._container,
   set container(val) this._container = val,
@@ -3305,18 +3312,20 @@ PlacesSortFolderByNameTransaction.protot
  *        the URL to tag.
  * @param aTags
  *        Array of tags to set for the given URL.
  */
 
 function PlacesTagURITransaction(aURI, aTags)
 {
   this._uri = aURI;
-  this._tags = aTags;
   this._unfiledItemId = -1;
+  // Copy the array to decouple it from its prototype, which otherwise keeps
+  // alive its associated global object.
+  this._tags = Array.slice(aTags);
 }
 
 PlacesTagURITransaction.prototype = {
   __proto__: BaseTransaction.prototype,
 
   doTransaction: function TUTXN_doTransaction()
   {
     if (PlacesUtils.getMostRecentBookmarkForURI(this._uri) == -1) {
@@ -3359,21 +3368,24 @@ PlacesTagURITransaction.prototype = {
  *        Array of tags to unset. pass null to remove all tags from the given
  *        url.
  */
 
 function PlacesUntagURITransaction(aURI, aTags)
 {
   this._uri = aURI;
   if (aTags) {    
+    // Copy the array to decouple it from its prototype, which otherwise keeps
+    // alive its associated global object.
+    this._tags = Array.slice(aTags);
+
     // Within this transaction, we cannot rely on tags given by itemId
     // since the tag containers may be gone after we call untagURI.
     // Thus, we convert each tag given by its itemId to name.
-    this._tags = aTags;
-    for (let i = 0; i < aTags.length; ++i) {
+    for (let i = 0; i < this._tags.length; ++i) {
       if (typeof(this._tags[i]) == "number")
         this._tags[i] = PlacesUtils.bookmarks.getItemTitle(this._tags[i]);
     }
   }
   else {
     this._tags = PlacesUtils.tagging.getTagsForURI(this._uri);
   }
 }
--- a/toolkit/components/places/nsPlacesAutoComplete.js
+++ b/toolkit/components/places/nsPlacesAutoComplete.js
@@ -33,16 +33,17 @@
  * 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 ***** */
 
 Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
+Components.utils.import("resource://gre/modules/Services.jsm");
 
 ////////////////////////////////////////////////////////////////////////////////
 //// Constants
 
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 const Cr = Components.results;
 
@@ -469,16 +470,17 @@ nsPlacesAutoComplete.prototype = {
     // reason to run the query).
     let {query, tokens} =
       this._getSearch(this._getUnfilteredSearchTokens(this._currentSearchString));
     let queries = tokens.length ?
       [this._getBoundKeywordQuery(tokens), this._getBoundAdaptiveQuery(), this._getBoundOpenPagesQuery(tokens), query] :
       [this._getBoundAdaptiveQuery(), this._getBoundOpenPagesQuery(tokens), query];
 
     // Start executing our queries.
+    this._telemetryStartTime = Date.now();
     this._executeQueries(queries);
 
     // Set up our persistent state for the duration of the search.
     this._searchTokens = tokens;
     this._usedPlaces = {};
   },
 
   stopSearch: function PAC_stopSearch()
@@ -721,16 +723,29 @@ nsPlacesAutoComplete.prototype = {
   {
     let result = this._result;
     let resultCode = result.matchCount ? "RESULT_SUCCESS" : "RESULT_NOMATCH";
     if (aSearchOngoing)
       resultCode += "_ONGOING";
     result.setSearchResult(Ci.nsIAutoCompleteResult[resultCode]);
     result.setDefaultIndex(result.matchCount ? 0 : -1);
     this._listener.onSearchResult(this, result);
+    if (this._telemetryStartTime) {
+      let elapsed = Date.now() - this._telemetryStartTime;
+      if (elapsed > 50) {
+        try {
+          Services.telemetry
+                  .getHistogramById("PLACES_AUTOCOMPLETE_1ST_RESULT_TIME_MS")
+                  .add(elapsed);
+        } catch (ex) {
+          Components.utils.reportError("Unable to report telemetry.");
+        }
+      }
+      this._telemetryStartTime = null;
+    }
   },
 
   /**
    * Loads the preferences that we care about.
    *
    * @param [optional] aRegisterObserver
    *        Indicates if the preference observer should be added or not.  The
    *        default value is false.
--- a/toolkit/components/places/nsPlacesExpiration.js
+++ b/toolkit/components/places/nsPlacesExpiration.js
@@ -664,25 +664,48 @@ nsPlacesExpiration.prototype = {
   },
 
   handleError: function PEX_handleError(aError)
   {
     Cu.reportError("Async statement execution returned with '" +
                    aError.result + "', '" + aError.message + "'");
   },
 
+  // Number of expiration steps needed to reach a CLEAN status.
+  _telemetrySteps: 1,
   handleCompletion: function PEX_handleCompletion(aReason)
   {
     if (aReason == Ci.mozIStorageStatementCallback.REASON_FINISHED) {
       if ("_expectedResultsCount" in this) {
         // Adapt the aggressivity of steps based on the status of history.
         // A dirty history will return all the entries we are expecting bringing
         // our countdown to zero, while a clean one will not.
+        let oldStatus = this.status;
         this.status = this._expectedResultsCount == 0 ? STATUS.DIRTY
                                                       : STATUS.CLEAN;
+
+        // Collect or send telemetry data.
+        if (this.status == STATUS.DIRTY) {
+          this._telemetrySteps++;
+        }
+        else {
+          // Avoid reporting the common cases where the database is clean, or
+          // a single step is needed.
+          if (oldStatus == STATUS.DIRTY) {
+            try {
+              Services.telemetry
+                      .getHistogramById("PLACES_EXPIRATION_STEPS_TO_CLEAN")
+                      .add(this._telemetrySteps);
+            } catch (ex) {
+              Components.utils.reportError("Unable to report telemetry.");
+            }
+          }
+          this._telemetrySteps = 1;
+        }
+
         delete this._expectedResultsCount;
       }
 
       // Dispatch a notification that expiration has finished.
       Services.obs.notifyObservers(null, TOPIC_EXPIRATION_FINISHED, null);
     }
   },
 
new file mode 100644
--- /dev/null
+++ b/toolkit/components/places/tests/unit/test_telemetry.js
@@ -0,0 +1,120 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Tests common Places telemetry probes by faking the telemetry service.
+
+Components.utils.import("resource://gre/modules/PlacesDBUtils.jsm");
+
+let histograms = {
+  PLACES_PAGES_COUNT: function (val) do_check_eq(val, 1),
+  PLACES_BOOKMARKS_COUNT: function (val) do_check_eq(val, 1),
+  PLACES_TAGS_COUNT: function (val) do_check_eq(val, 1),
+  PLACES_FOLDERS_COUNT: function (val) do_check_eq(val, 1),
+  PLACES_KEYWORDS_COUNT: function (val) do_check_eq(val, 1),
+  PLACES_SORTED_BOOKMARKS_PERC: function (val) do_check_eq(val, 100),
+  PLACES_TAGGED_BOOKMARKS_PERC: function (val) do_check_eq(val, 100),
+  PLACES_DATABASE_FILESIZE_MB: function (val) do_check_true(val > 0),
+  PLACES_DATABASE_JOURNALSIZE_MB: function (val) do_check_true(val > 0),
+  PLACES_DATABASE_PAGESIZE_B: function (val) do_check_eq(val, 32768),
+  PLACES_DATABASE_SIZE_PER_PAGE_B: function (val) do_check_true(val > 0),
+  PLACES_EXPIRATION_STEPS_TO_CLEAN: function (val) do_check_true(val > 1),
+  //PLACES_AUTOCOMPLETE_1ST_RESULT_TIME_MS:  function (val) do_check_true(val > 1),
+}
+
+// This sucks, but due to nsITelemetry using [implicit_jscontext], it's
+// impossible to implement it in js, so no fancy service factory replacements.
+// This mock implements only the telemetry methods used by Places.
+XPCOMUtils.defineLazyGetter(Services, "telemetry", function () {
+  return {
+    getHistogramById: function FT_getHistogramById(id) {
+      if (id in histograms) {
+        return {
+          add: function FH_add(val) {
+            do_log_info("Testing probe " + id);
+            histograms[id](val);
+            delete histograms[id];
+            if (Object.keys(histograms).length == 0)
+              do_test_finished();
+          }
+        };
+      }
+
+      return {
+        add: function FH_add(val) {
+          do_log_info("Unknown probe " + id);
+        }
+      };
+    },
+  };
+});
+
+function run_test() {
+  do_test_pending();
+
+  // Put some trash in the database.
+  const URI = NetUtil.newURI("http://moz.org/");
+
+  let folderId = PlacesUtils.bookmarks.createFolder(PlacesUtils.unfiledBookmarksFolderId,
+                                                    "moz test",
+                                                    PlacesUtils.bookmarks.DEFAULT_INDEX);
+  let itemId = PlacesUtils.bookmarks.insertBookmark(folderId,
+                                                    uri,
+                                                    PlacesUtils.bookmarks.DEFAULT_INDEX,
+                                                    "moz test");
+  PlacesUtils.tagging.tagURI(uri, ["tag"]);
+  PlacesUtils.bookmarks.setKeywordForBookmark(itemId, "keyword");
+
+  // Test generic database probes.
+  PlacesDBUtils._telemetry();
+
+  waitForAsyncUpdates(continue_test);
+}
+
+function continue_test() {
+  // Test expiration probes.
+  for (let i = 0; i < 2; i++) {
+    PlacesUtils.history.addVisit(NetUtil.newURI("http://" +  i + ".moz.org/"),
+                                 Date.now(), null,
+                                 PlacesUtils.history.TRANSITION_TYPED, false, 0);
+  }
+  Services.prefs.setIntPref("places.history.expiration.max_pages", 0);
+  let expire = Cc["@mozilla.org/places/expiration;1"].getService(Ci.nsIObserver);
+  expire.observe(null, "places-debug-start-expiration", 1);
+  expire.observe(null, "places-debug-start-expiration", -1);
+
+  // Test autocomplete probes.
+  /*
+  // This is useful for manual testing by changing the minimum time for
+  // autocomplete telemetry to 0, but there is no way to artificially delay
+  // autocomplete by more than 50ms in a realiable way.
+  Services.prefs.setIntPref("browser.urlbar.search.sources", 3);
+  Services.prefs.setIntPref("browser.urlbar.default.behavior", 0);
+  function AutoCompleteInput(aSearches) {
+    this.searches = aSearches;
+  }
+  AutoCompleteInput.prototype = {
+    timeout: 10,
+    textValue: "",
+    searchParam: "",
+    popupOpen: false,
+    minResultsForPopup: 0,
+    invalidate: function() {},
+    disableAutoComplete: false,
+    completeDefaultIndex: false,
+    get popup() { return this; },
+    onSearchBegin: function() {},
+    onSearchComplete: function() {},
+    setSelectedIndex: function() {},
+    get searchCount() { return this.searches.length; },
+    getSearchAt: function(aIndex) this.searches[aIndex],
+    QueryInterface: XPCOMUtils.generateQI([
+      Ci.nsIAutoCompleteInput,
+      Ci.nsIAutoCompletePopup,
+    ])
+  };
+  let controller = Cc["@mozilla.org/autocomplete/controller;1"].
+                   getService(Ci.nsIAutoCompleteController);
+  controller.input = new AutoCompleteInput(["history"]);
+  controller.startSearch("moz");
+  */
+}
--- a/toolkit/components/places/tests/unit/xpcshell.ini
+++ b/toolkit/components/places/tests/unit/xpcshell.ini
@@ -87,8 +87,9 @@ tail =
 [test_sql_guid_functions.js]
 [test_tag_autocomplete_search.js]
 [test_tagging.js]
 [test_update_frecency_after_delete.js]
 [test_utils_backups_create.js]
 [test_utils_getURLsForContainerNode.js]
 [test_utils_setAnnotationsFor.js]
 [test_PlacesUtils_asyncGetBookmarkIds.js]
+[test_telemetry.js]
--- a/toolkit/components/telemetry/Telemetry.cpp
+++ b/toolkit/components/telemetry/Telemetry.cpp
@@ -172,17 +172,17 @@ ReflectHistogramSnapshot(JSContext *cx, 
   h->SnapshotSample(&ss);
   JSObject *counts_array;
   JSObject *rarray;
   jsval static_histogram = h->flags() && Histogram::kUmaTargetedHistogramFlag ? JSVAL_TRUE : JSVAL_FALSE;
   const size_t count = h->bucket_count();
   if (!(JS_DefineProperty(cx, obj, "min", INT_TO_JSVAL(h->declared_min()), NULL, NULL, JSPROP_ENUMERATE)
         && JS_DefineProperty(cx, obj, "max", INT_TO_JSVAL(h->declared_max()), NULL, NULL, JSPROP_ENUMERATE)
         && JS_DefineProperty(cx, obj, "histogram_type", INT_TO_JSVAL(h->histogram_type()), NULL, NULL, JSPROP_ENUMERATE)
-        && JS_DefineProperty(cx, obj, "sum", INT_TO_JSVAL(ss.sum()), NULL, NULL, JSPROP_ENUMERATE)
+        && JS_DefineProperty(cx, obj, "sum", DOUBLE_TO_JSVAL(ss.sum()), NULL, NULL, JSPROP_ENUMERATE)
         && (rarray = JS_NewArrayObject(cx, count, NULL))
         && JS_DefineProperty(cx, obj, "ranges", OBJECT_TO_JSVAL(rarray), NULL, NULL, JSPROP_ENUMERATE)
         && FillRanges(cx, rarray, h)
         && (counts_array = JS_NewArrayObject(cx, count, NULL))
         && JS_DefineProperty(cx, obj, "counts", OBJECT_TO_JSVAL(counts_array), NULL, NULL, JSPROP_ENUMERATE)
         && JS_DefineProperty(cx, obj, "static", static_histogram, NULL, NULL, JSPROP_ENUMERATE)
         )) {
     return JS_FALSE;
--- a/toolkit/components/telemetry/Telemetry.h
+++ b/toolkit/components/telemetry/Telemetry.h
@@ -67,17 +67,17 @@ class AutoTimer {
 public:
   AutoTimer(MOZILLA_GUARD_OBJECT_NOTIFIER_ONLY_PARAM)
     : start(TimeStamp::Now())
   {
     MOZILLA_GUARD_OBJECT_NOTIFIER_INIT;
   }
 
   ~AutoTimer() {
-    Accumulate(id, (TimeStamp::Now() - start).ToMilliseconds());
+    Accumulate(id, static_cast<PRUint32>((TimeStamp::Now() - start).ToMilliseconds()));
   }
 
 private:
   const TimeStamp start;
   MOZILLA_DECL_USE_GUARD_OBJECT_NOTIFIER
 };
 } // namespace Telemetry
 } // namespace mozilla
--- a/toolkit/components/telemetry/TelemetryHistograms.h
+++ b/toolkit/components/telemetry/TelemetryHistograms.h
@@ -135,8 +135,25 @@ HISTOGRAM(MOZ_SQLITE_COOKIES_SYNC, 1, 10
 HISTOGRAM(MOZ_SQLITE_URLCLASSIFIER_SYNC, 1, 10000, 10, EXPONENTIAL, "Time spent on SQLite fsync() (ms)")
 HISTOGRAM(MOZ_SQLITE_OTHER_SYNC, 1, 10000, 10, EXPONENTIAL, "Time spent on SQLite fsync() (ms)")
 HISTOGRAM(STARTUP_MEASUREMENT_ERRORS, 1, 3, 4, LINEAR, "Flags errors in startup calculation()")
 HISTOGRAM(NETWORK_DISK_CACHE_OPEN, 1, 10000, 10, EXPONENTIAL, "Time spent opening disk cache (ms)")
 HISTOGRAM(NETWORK_DISK_CACHE_TRASHRENAME, 1, 10000, 10, EXPONENTIAL, "Time spent renaming bad Cache to Cache.Trash (ms)")
 HISTOGRAM(NETWORK_DISK_CACHE_DELETEDIR, 1, 10000, 10, EXPONENTIAL, "Time spent deleting disk cache (ms)")
 HISTOGRAM(MOZ_SQLITE_MAIN_THREAD_WAIT_MS, 1, 3000, 10, EXPONENTIAL, "Time spent waiting on SQLite IO on main thread (ms)")
 HISTOGRAM(MOZ_SQLITE_OTHER_THREAD_WAIT_MS, 1, 3000, 10, EXPONENTIAL, "Time spent waiting on SQLite IO off main thread (ms)")
+
+/**
+ * Places telemetry.
+ */
+HISTOGRAM(PLACES_PAGES_COUNT, 1000, 150000, 20, EXPONENTIAL, "PLACES: Number of unique pages")
+HISTOGRAM(PLACES_BOOKMARKS_COUNT, 100, 8000, 15, EXPONENTIAL, "PLACES: Number of bookmarks")
+HISTOGRAM(PLACES_TAGS_COUNT, 1, 200, 10, EXPONENTIAL, "PLACES: Number of tags")
+HISTOGRAM(PLACES_FOLDERS_COUNT, 1, 200, 10, EXPONENTIAL, "PLACES: Number of folders")
+HISTOGRAM(PLACES_KEYWORDS_COUNT, 1, 200, 10, EXPONENTIAL, "PLACES: Number of keywords")
+HISTOGRAM(PLACES_SORTED_BOOKMARKS_PERC, 1, 100, 10, LINEAR, "PLACES: Percentage of bookmarks organized in folders")
+HISTOGRAM(PLACES_TAGGED_BOOKMARKS_PERC, 1, 100, 10, LINEAR, "PLACES: Percentage of tagged bookmarks")
+HISTOGRAM(PLACES_DATABASE_FILESIZE_MB, 5, 200, 10, EXPONENTIAL, "PLACES: Database filesize (MB)")
+HISTOGRAM(PLACES_DATABASE_JOURNALSIZE_MB, 1, 50, 10, EXPONENTIAL, "PLACES: Database journal size (MB)")
+HISTOGRAM(PLACES_DATABASE_PAGESIZE_B, 1024, 32768, 10, EXPONENTIAL, "PLACES: Database page size (bytes)")
+HISTOGRAM(PLACES_DATABASE_SIZE_PER_PAGE_B, 500, 10240, 20, EXPONENTIAL, "PLACES: Average size of a place in the database (bytes)")
+HISTOGRAM(PLACES_EXPIRATION_STEPS_TO_CLEAN, 1, 10, 10, LINEAR, "PLACES: Expiration steps to cleanup the database")
+HISTOGRAM(PLACES_AUTOCOMPLETE_1ST_RESULT_TIME_MS, 50, 500, 10, EXPONENTIAL, "PLACES: Time for first autocomplete result if > 50ms (ms)")
--- a/toolkit/components/telemetry/tests/unit/test_nsITelemetry.js
+++ b/toolkit/components/telemetry/tests/unit/test_nsITelemetry.js
@@ -1,14 +1,15 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 const Cu = Components.utils;
+const INT_MAX = 0x7FFFFFFF;
 
 const Telemetry = Cc["@mozilla.org/base/telemetry;1"].getService(Ci.nsITelemetry);
 Cu.import("resource://gre/modules/Services.jsm");
 
 function test_histogram(histogram_type, name, min, max, bucket_count) {
   var h = Telemetry.newHistogram(name, min, max, bucket_count, histogram_type);
   
   var r = h.snapshot().ranges;
@@ -101,17 +102,17 @@ function test_privateMode() {
   h.add(1);
   do_check_neq(uneval(orig), uneval(h.snapshot()));
 }
 
 function run_test()
 {
   let kinds = [Telemetry.HISTOGRAM_EXPONENTIAL, Telemetry.HISTOGRAM_LINEAR]
   for each (let histogram_type in kinds) {
-    let [min, max, bucket_count] = [1, 10000, 10]
+    let [min, max, bucket_count] = [1, INT_MAX - 1, 10]
     test_histogram(histogram_type, "test::"+histogram_type, min, max, bucket_count);
     
     const nh = Telemetry.newHistogram;
     expect_fail(function () nh("test::min", 0, max, bucket_count, histogram_type));
     expect_fail(function () nh("test::bucket_count", min, max, 1, histogram_type));
   }
 
   test_boolean_histogram();
--- a/toolkit/content/widgets/videocontrols.xml
+++ b/toolkit/content/widgets/videocontrols.xml
@@ -303,17 +303,16 @@
                                "loadstart", "timeupdate", "progress",
                                "playing", "waiting", "canplay", "canplaythrough",
                                "seeking", "seeked", "emptied", "loadedmetadata",
                                "error", "suspend", "stalled"],
 
                 firstFrameShown : false,
                 timeUpdateCount : 0,
                 maxCurrentTimeSeen : 0,
-                lastDurationSeen : NaN,
                 isAudioOnly : false,
 
                 setupStatusFader : function(immediate) {
                     var show = false;
                     if (this.video.seeking ||
                         this.video.error ||
                         this.video.networkState == this.video.NETWORK_NO_SOURCE ||
                         (this.video.networkState == this.video.NETWORK_LOADING &&
@@ -543,17 +542,17 @@
                     }
                 },
 
                 terminateEventListeners : function () {
                     for each (var event in this.videoEvents)
                         this.video.removeEventListener(event, this, false);
                     this.log("--- videocontrols terminated ---");
                 },
-                
+
                 formatTime : function(aTime) {
                     // Format the duration as "h:mm:ss" or "m:ss"
                     aTime = Math.round(aTime / 1000);
                     let hours = Math.floor(aTime / 3600);
                     let mins  = Math.floor((aTime % 3600) / 60);
                     let secs  = Math.floor(aTime % 60);
                     let timeString;
                     if (secs < 10)
@@ -564,25 +563,24 @@
                         timeString = hours + ":" + mins + ":" + secs;
                     } else {
                         timeString = mins + ":" + secs;
                     }
                     return timeString;
                 },
 
                 showDuration : function (duration) {
-                    if (isNaN(duration))
+                    let isInfinite = (duration == Infinity);
+                    this.log("Duration is " + duration + "ms.\n");
+
+                    if (isNaN(duration) || isInfinite)
                         duration = this.maxCurrentTimeSeen;
-                    if (duration == this.lastDurationSeen)
-                        return;
-                    this.lastDurationSeen = duration;
-                    this.log("Duration is " + duration + "ms");
 
                     // Format the duration as "h:mm:ss" or "m:ss"
-                    let timeString = this.formatTime(duration);
+                    let timeString = isInfinite ? "" : this.formatTime(duration);
                     this.durationLabel.setAttribute("value", timeString);
 
                     // "durationValue" property is used by scale binding to
                     // generate accessible name.
                     this.scrubber.durationValue = timeString;
 
                     // If the duration is over an hour, thumb should show h:mm:ss instead of mm:ss
                     this.scrubberThumb.showHours = (duration >= 3600000);
@@ -608,18 +606,16 @@
                 },
 
                 showPosition : function(currentTime, duration) {
                     // If the duration is unknown (because the server didn't provide
                     // it, or the video is a stream), then we want to fudge the duration
                     // by using the maximum playback position that's been seen.
                     if (currentTime > this.maxCurrentTimeSeen)
                         this.maxCurrentTimeSeen = currentTime;
-                    if (isNaN(duration))
-                      duration = this.maxCurrentTimeSeen;
                     this.showDuration(duration);
 
                     this.log("time update @ " + currentTime + "ms of " + duration + "ms");
 
                     this.positionLabel.setAttribute("value", this.formatTime(currentTime));
                     this.scrubber.value = currentTime;
                 },
 
--- a/toolkit/crashreporter/google-breakpad/src/common/mac/macho_id.cc
+++ b/toolkit/crashreporter/google-breakpad/src/common/mac/macho_id.cc
@@ -32,17 +32,16 @@
 // See macho_id.h for documentation
 //
 // Author: Dan Waylonis
 
 extern "C" {  // necessary for Leopard
   #include <fcntl.h>
   #include <mach-o/loader.h>
   #include <mach-o/swap.h>
-  #include <openssl/sha.h>
   #include <stdio.h>
   #include <stdlib.h>
   #include <string.h>
   #include <sys/time.h>
   #include <sys/types.h>
   #include <unistd.h>
 }
 
@@ -52,17 +51,16 @@ extern "C" {  // necessary for Leopard
 #include "common/mac/macho_utilities.h"
 
 namespace MacFileUtilities {
 
 MachoID::MachoID(const char *path)
    : file_(0), 
      crc_(0), 
      md5_context_(), 
-     sha1_context_(), 
      update_function_(NULL) {
   strlcpy(path_, path, sizeof(path_));
   file_ = open(path, O_RDONLY);
 }
 
 MachoID::~MachoID() {
   if (file_ != -1)
     close(file_);
@@ -115,20 +113,16 @@ void MachoID::UpdateCRC(unsigned char *b
     crc_ = (sum2 << 16) | sum1;
   }
 }
 
 void MachoID::UpdateMD5(unsigned char *bytes, size_t size) {
   MD5Update(&md5_context_, bytes, size);
 }
 
-void MachoID::UpdateSHA1(unsigned char *bytes, size_t size) {
-  SHA_Update(&sha1_context_, bytes, size);
-}
-
 void MachoID::Update(MachoWalker *walker, off_t offset, size_t size) {
   if (!update_function_ || !size)
     return;
 
   // Read up to 4k bytes at a time
   unsigned char buffer[4096];
   size_t buffer_size;
   off_t file_offset = offset;
@@ -228,31 +222,16 @@ bool MachoID::MD5(int cpu_type, unsigned
   MD5Init(&md5_context_);
   if (!walker.WalkHeader(cpu_type))
     return false;
 
   MD5Final(identifier, &md5_context_);
   return true;
 }
 
-bool MachoID::SHA1(int cpu_type, unsigned char identifier[16]) {
-  MachoWalker walker(path_, WalkerCB, this);
-  update_function_ = &MachoID::UpdateSHA1;
-
-  if (SHA_Init(&sha1_context_)) {
-    if (!walker.WalkHeader(cpu_type))
-      return false;
-
-    SHA_Final(identifier, &sha1_context_);
-    return true;
-  }
-
-  return false;
-}
-
 // static
 bool MachoID::WalkerCB(MachoWalker *walker, load_command *cmd, off_t offset,
                        bool swap, void *context) {
   MachoID *macho_id = (MachoID *)context;
 
   if (cmd->cmd == LC_SEGMENT) {
     struct segment_command seg;
 
--- a/toolkit/crashreporter/google-breakpad/src/common/mac/macho_id.h
+++ b/toolkit/crashreporter/google-breakpad/src/common/mac/macho_id.h
@@ -31,17 +31,16 @@
 //
 // Author: Dan Waylonis
 
 #ifndef COMMON_MAC_MACHO_ID_H__
 #define COMMON_MAC_MACHO_ID_H__
 
 #include <limits.h>
 #include <mach-o/loader.h>
-#include <openssl/sha.h>
 
 #include "common/md5.h"
 
 namespace MacFileUtilities {
 
 class MachoWalker;
 
 class MachoID {
@@ -61,40 +60,32 @@ class MachoID {
   // segment(s).
   // Return 0 on error (e.g., if the file is not a mach-o file)
   uint32_t Adler32(int cpu_type);
 
   // For the given |cpu_type|, return the MD5 for the mach-o data segment(s).
   // Return true on success, false otherwise
   bool MD5(int cpu_type, unsigned char identifier[16]);
 
-  // For the given |cpu_type|, return the SHA1 for the mach-o data segment(s).
-  // Return true on success, false otherwise
-  bool SHA1(int cpu_type, unsigned char identifier[16]);
-
  private:
   // Signature of class member function to be called with data read from file
   typedef void (MachoID::*UpdateFunction)(unsigned char *bytes, size_t size);
 
   // Update the CRC value by examining |size| |bytes| and applying the algorithm
   // to each byte.
   void UpdateCRC(unsigned char *bytes, size_t size);
 
   // Update the MD5 value by examining |size| |bytes| and applying the algorithm
   // to each byte.
   void UpdateMD5(unsigned char *bytes, size_t size);
 
-  // Update the SHA1 value by examining |size| |bytes| and applying the
-  // algorithm to each byte.
-  void UpdateSHA1(unsigned char *bytes, size_t size);
-
   // Bottleneck for update routines
   void Update(MachoWalker *walker, off_t offset, size_t size);
 
-  // The callback from the MachoWalker for CRC, MD5, and SHA1
+  // The callback from the MachoWalker for CRC and MD5
   static bool WalkerCB(MachoWalker *walker, load_command *cmd, off_t offset,
                        bool swap, void *context);
 
   // The callback from the MachoWalker for LC_UUID
   static bool UUIDWalkerCB(MachoWalker *walker, load_command *cmd, off_t offset,
                            bool swap, void *context);
 
   // The callback from the MachoWalker for LC_ID_DYLIB
@@ -108,18 +99,15 @@ class MachoID {
   int file_;
 
   // The current crc value
   uint32_t crc_;
 
   // The MD5 context
   MD5Context md5_context_;
 
-  // The SHA1 context
-  SHA_CTX sha1_context_;
-
   // The current update to call from the Update callback
   UpdateFunction update_function_;
 };
 
 }  // namespace MacFileUtilities
 
 #endif  // COMMON_MAC_MACHO_ID_H__
--- a/toolkit/crashreporter/google-breakpad/src/tools/mac/crash_report/on_demand_symbol_supplier.mm
+++ b/toolkit/crashreporter/google-breakpad/src/tools/mac/crash_report/on_demand_symbol_supplier.mm
@@ -247,25 +247,20 @@ bool OnDemandSymbolSupplier::GenerateSym
 
   if (generate_file) {
     NSString *module_str = [[NSFileManager defaultManager]
       stringWithFileSystemRepresentation:module_path.c_str()
                                   length:module_path.length()];
     DumpSymbols dump;
     if (dump.Read(module_str)) {
       if (dump.SetArchitecture(system_info->cpu)) {
-        FILE *file = fopen([symbol_path fileSystemRepresentation],"w");
-        if (file) {
-          dump.WriteSymbolFile(file);
-          fclose(file);
-        } else {
-          printf("Unable to open %s (%d)\n", name.c_str(), errno);
-          result = false;
-        } 
-      } else {
+         std::fstream file([symbol_path fileSystemRepresentation],
+                           std::ios_base::out | std::ios_base::trunc);
+         dump.WriteSymbolFile(file);
+     } else {
         printf("Architecture %s not available for %s\n", 
                system_info->cpu.c_str(), name.c_str());
         result = false;
       }
     } else {
       printf("Unable to open %s\n", [module_str UTF8String]);
       result = false;
     }
--- a/toolkit/library/Makefile.in
+++ b/toolkit/library/Makefile.in
@@ -147,17 +147,16 @@ DEFINES += -DIMPL_XREAPI
 EXTRA_DSO_LDOPTS += $(NSPR_LIBS) $(MOZALLOC_LIB)
 
 ifeq ($(MOZ_WIDGET_TOOLKIT),cocoa)
 CXXFLAGS	+= $(TK_CFLAGS)
 OS_LIBS += \
 	-framework SystemConfiguration \
 	-framework QuickTime \
 	-framework IOKit \
-	-lcrypto \
 	$(TK_LIBS) \
 	$(NULL)
 endif
 
 ifeq ($(OS_ARCH),Darwin)
 ifdef MOZ_SYDNEYAUDIO
 EXTRA_DSO_LDOPTS += \
 	-framework Carbon \
--- a/toolkit/mozapps/extensions/AddonLogging.jsm
+++ b/toolkit/mozapps/extensions/AddonLogging.jsm
@@ -32,24 +32,28 @@
 # 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 *****
 */
 
+"use strict";
+
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 const Cr = Components.results;
 
 const KEY_PROFILEDIR                  = "ProfD";
 const FILE_EXTENSIONS_LOG             = "extensions.log";
 const PREF_LOGGING_ENABLED            = "extensions.logging.enabled";
 
+const LOGGER_FILE_PERM                = parseInt("666", 8);
+
 const NS_PREFBRANCH_PREFCHANGE_TOPIC_ID = "nsPref:changed";
 
 Components.utils.import("resource://gre/modules/FileUtils.jsm");
 Components.utils.import("resource://gre/modules/Services.jsm");
 
 var EXPORTED_SYMBOLS = [ "LogManager" ];
 
 var gDebugLogEnabled = false;
@@ -114,17 +118,17 @@ AddonLogger.prototype = {
     if (gDebugLogEnabled)
       dump("*** " + message + "\n");
 
     try {
       var tstamp = new Date();
       var logfile = FileUtils.getFile(KEY_PROFILEDIR, [FILE_EXTENSIONS_LOG]);
       var stream = Cc["@mozilla.org/network/file-output-stream;1"].
                    createInstance(Ci.nsIFileOutputStream);
-      stream.init(logfile, 0x02 | 0x08 | 0x10, 0666, 0); // write, create, append
+      stream.init(logfile, 0x02 | 0x08 | 0x10, LOGGER_FILE_PERM, 0); // write, create, append
       var writer = Cc["@mozilla.org/intl/converter-output-stream;1"].
                    createInstance(Ci.nsIConverterOutputStream);
       writer.init(stream, "UTF-8", 0, 0x0000);
       writer.writeString(tstamp.toLocaleFormat("%Y-%m-%d %H:%M:%S ") +
                          message + " at " + stack.sourceName + ":" +
                          stack.lineNumber + "\n");
       writer.close();
     }
--- a/toolkit/mozapps/extensions/AddonManager.jsm
+++ b/toolkit/mozapps/extensions/AddonManager.jsm
@@ -32,16 +32,18 @@
 # 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 *****
 */
 
+"use strict";
+
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 const Cr = Components.results;
 
 const PREF_BLOCKLIST_PINGCOUNTVERSION = "extensions.blocklist.pingCountVersion";
 const PREF_EM_UPDATE_ENABLED          = "extensions.update.enabled";
 const PREF_EM_LAST_APP_VERSION        = "extensions.lastAppVersion";
 const PREF_EM_LAST_PLATFORM_VERSION   = "extensions.lastPlatformVersion";
--- a/toolkit/mozapps/extensions/AddonRepository.jsm
+++ b/toolkit/mozapps/extensions/AddonRepository.jsm
@@ -32,16 +32,18 @@
 # 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 *****
 */
 
+"use strict";
+
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 const Cu = Components.utils;
 
 Components.utils.import("resource://gre/modules/FileUtils.jsm");
 Components.utils.import("resource://gre/modules/NetUtil.jsm");
 Components.utils.import("resource://gre/modules/Services.jsm");
 Components.utils.import("resource://gre/modules/AddonManager.jsm");
@@ -1505,17 +1507,17 @@ var AddonDatabase = {
         handleCompletion: function(aReason) {
           if (aReason != Ci.mozIStorageStatementCallback.REASON_FINISHED) {
             ERROR("Error retrieving screenshots from database. Returning empty results");
             aCallback({});
             return;
           }
 
           let returnedAddons = {};
-          for each (addon in addons)
+          for each (let addon in addons)
             returnedAddons[addon.id] = addon;
           aCallback(returnedAddons);
         }
       });
     }
 
     // Begin asynchronous process
     getAllAddons();
--- a/toolkit/mozapps/extensions/AddonUpdateChecker.jsm
+++ b/toolkit/mozapps/extensions/AddonUpdateChecker.jsm
@@ -37,16 +37,18 @@
 # ***** END LICENSE BLOCK *****
 */
 
 /**
  * The AddonUpdateChecker is responsible for retrieving the update information
  * from an add-on's remote update manifest.
  */
 
+"use strict";
+
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 
 var EXPORTED_SYMBOLS = [ "AddonUpdateChecker" ];
 
 const TIMEOUT               = 2 * 60 * 1000;
 const PREFIX_NS_RDF         = "http://www.w3.org/1999/02/22-rdf-syntax-ns#";
 const PREFIX_NS_EM          = "http://www.mozilla.org/2004/em-rdf#";
--- a/toolkit/mozapps/extensions/LightweightThemeManager.jsm
+++ b/toolkit/mozapps/extensions/LightweightThemeManager.jsm
@@ -30,16 +30,18 @@
  * 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 ***** */
 
+"use strict";
+
 var EXPORTED_SYMBOLS = ["LightweightThemeManager"];
 
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 
 Components.utils.import("resource://gre/modules/AddonManager.jsm");
 Components.utils.import("resource://gre/modules/Services.jsm");
 
--- a/toolkit/mozapps/extensions/PluginProvider.jsm
+++ b/toolkit/mozapps/extensions/PluginProvider.jsm
@@ -32,16 +32,18 @@
 # 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 *****
 */
 
+"use strict";
+
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 
 var EXPORTED_SYMBOLS = [];
 
 Components.utils.import("resource://gre/modules/AddonManager.jsm");
 Components.utils.import("resource://gre/modules/Services.jsm");
 
--- a/toolkit/mozapps/extensions/XPIProvider.jsm
+++ b/toolkit/mozapps/extensions/XPIProvider.jsm
@@ -32,16 +32,18 @@
 # 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 *****
 */
 
+"use strict";
+
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 const Cr = Components.results;
 
 var EXPORTED_SYMBOLS = [];
 
 Components.utils.import("resource://gre/modules/Services.jsm");
 Components.utils.import("resource://gre/modules/AddonManager.jsm");
@@ -385,17 +387,17 @@ function findClosestLocale(aLocales) {
   /* If the current locale is English then it will find a match if there is
      a valid match for en-US so no point searching that locale too. */
   if (matchLocales[0].substring(0, 3) != "en-")
     matchLocales.push("en-us");
 
   for each (var locale in matchLocales) {
     var lparts = locale.split("-");
     for each (var localized in aLocales) {
-      for each (found in localized.locales) {
+      for each (let found in localized.locales) {
         found = found.toLowerCase();
         // Exact match is returned immediately
         if (locale == found)
           return localized;
 
         var fparts = found.split("-");
         /* If we have found a possible match and this one isn't any longer
            then we dont need to check further. */
@@ -1895,18 +1897,18 @@ var XPIProvider = {
           LOG("Error removing XPI staging dir " + stagedXPIDir.path, e);
         }
       }
 
       if (!stagingDir || !stagingDir.exists() || !stagingDir.isDirectory())
         return;
 
       let seenFiles = [];
-      entries = stagingDir.directoryEntries
-                          .QueryInterface(Ci.nsIDirectoryEnumerator);
+      let entries = stagingDir.directoryEntries
+                              .QueryInterface(Ci.nsIDirectoryEnumerator);
       while (entries.hasMoreElements()) {
         let stageDirEntry = entries.getNext().QueryInterface(Ci.nsILocalFile);
 
         let id = stageDirEntry.leafName;
         if (!stageDirEntry.isDirectory()) {
           if (id.substring(id.length - 4).toLowerCase() == ".xpi") {
             id = id.substring(0, id.length - 4);
           }
@@ -2773,17 +2775,17 @@ var XPIProvider = {
     knownLocations.forEach(function(aLocation) {
       let addons = XPIDatabase.getAddonsInLocation(aLocation);
       addons.forEach(function(aOldAddon) {
         changed = removeMetadata(aLocation, aOldAddon) || changed;
       }, this);
     }, this);
 
     // Cache the new install location states
-    cache = JSON.stringify(this.getInstallLocationStates());
+    let cache = JSON.stringify(this.getInstallLocationStates());
     Services.prefs.setCharPref(PREF_INSTALL_CACHE, cache);
 
     return changed;
   },
 
   /**
    * Imports the xpinstall permissions from preferences into the permissions
    * manager for the user to change later.
@@ -3686,16 +3688,60 @@ var XPIProvider = {
     // If the add-on is not visible then there is no need to notify listeners.
     if (!aAddon.visible)
       return;
 
     let wrapper = createWrapper(aAddon);
     AddonManagerPrivate.callAddonListeners("onUninstalling", wrapper,
                                            requiresRestart);
 
+    // Reveal the highest priority add-on with the same ID
+    function revealAddon(aAddon) {
+      XPIDatabase.makeAddonVisible(aAddon);
+
+      let wrappedAddon = createWrapper(aAddon);
+      AddonManagerPrivate.callAddonListeners("onInstalling", wrappedAddon, false);
+
+      if (!isAddonDisabled(aAddon) && !XPIProvider.enableRequiresRestart(aAddon)) {
+        aAddon.active = true;
+        XPIDatabase.updateAddonActive(aAddon);
+      }
+
+      if (aAddon.bootstrap) {
+        let file = aAddon._installLocation.getLocationForID(aAddon.id);
+        XPIProvider.callBootstrapMethod(aAddon.id, aAddon.version, file,
+                                        "install", BOOTSTRAP_REASONS.ADDON_INSTALL);
+
+        if (aAddon.active) {
+          XPIProvider.callBootstrapMethod(aAddon.id, aAddon.version, file,
+                                          "startup", BOOTSTRAP_REASONS.ADDON_INSTALL);
+        }
+        else {
+          XPIProvider.unloadBootstrapScope(aAddon.id);
+        }
+      }
+
+      // We always send onInstalled even if a restart is required to enable
+      // the revealed add-on
+      AddonManagerPrivate.callAddonListeners("onInstalled", wrappedAddon);
+    }
+
+    function checkInstallLocation(aPos) {
+      if (aPos < 0)
+        return;
+
+      let location = XPIProvider.installLocations[aPos];
+      XPIDatabase.getAddonInLocation(aAddon.id, location.name, function(aNewAddon) {
+        if (aNewAddon)
+          revealAddon(aNewAddon);
+        else
+          checkInstallLocation(aPos - 1);
+      })
+    }
+
     if (!requiresRestart) {
       if (aAddon.bootstrap) {
         let file = aAddon._installLocation.getLocationForID(aAddon.id);
         if (aAddon.active) {
           this.callBootstrapMethod(aAddon.id, aAddon.version, file, "shutdown",
                                    BOOTSTRAP_REASONS.ADDON_UNINSTALL);
         }
 
@@ -3703,60 +3749,16 @@ var XPIProvider = {
                                  BOOTSTRAP_REASONS.ADDON_UNINSTALL);
         this.unloadBootstrapScope(aAddon.id);
         flushStartupCache();
       }
       aAddon._installLocation.uninstallAddon(aAddon.id);
       XPIDatabase.removeAddonMetadata(aAddon);
       AddonManagerPrivate.callAddonListeners("onUninstalled", wrapper);
 
-      // Reveal the highest priority add-on with the same ID
-      function revealAddon(aAddon) {
-        XPIDatabase.makeAddonVisible(aAddon);
-
-        let wrappedAddon = createWrapper(aAddon);
-        AddonManagerPrivate.callAddonListeners("onInstalling", wrappedAddon, false);
-
-        if (!isAddonDisabled(aAddon) && !XPIProvider.enableRequiresRestart(aAddon)) {
-          aAddon.active = true;
-          XPIDatabase.updateAddonActive(aAddon);
-        }
-
-        if (aAddon.bootstrap) {
-          let file = aAddon._installLocation.getLocationForID(aAddon.id);
-          XPIProvider.callBootstrapMethod(aAddon.id, aAddon.version, file,
-                                          "install", BOOTSTRAP_REASONS.ADDON_INSTALL);
-
-          if (aAddon.active) {
-            XPIProvider.callBootstrapMethod(aAddon.id, aAddon.version, file,
-                                            "startup", BOOTSTRAP_REASONS.ADDON_INSTALL);
-          }
-          else {
-            XPIProvider.unloadBootstrapScope(aAddon.id);
-          }
-        }
-
-        // We always send onInstalled even if a restart is required to enable
-        // the revealed add-on
-        AddonManagerPrivate.callAddonListeners("onInstalled", wrappedAddon);
-      }
-
-      function checkInstallLocation(aPos) {
-        if (aPos < 0)
-          return;
-
-        let location = XPIProvider.installLocations[aPos];
-        XPIDatabase.getAddonInLocation(aAddon.id, location.name, function(aNewAddon) {
-          if (aNewAddon)
-            revealAddon(aNewAddon);
-          else
-            checkInstallLocation(aPos - 1);
-        })
-      }
-
       checkInstallLocation(this.installLocations.length - 1);
     }
 
     // Notify any other providers that a new theme has been enabled
     if (aAddon.type == "theme" && aAddon.active)
       AddonManagerPrivate.notifyAddonChanged(null, aAddon.type, requiresRestart);
   },
 
@@ -5027,36 +5029,38 @@ var XPIDatabase = {
    * @param  aAddon
    *         AddonInternal to add
    * @param  aDescriptor
    *         The file descriptor of the add-on
    */
   addAddonMetadata: function XPIDB_addAddonMetadata(aAddon, aDescriptor) {
     this.beginTransaction();
 
+    var self = this;
+    function insertLocale(aLocale) {
+      let localestmt = self.getStatement("addAddonMetadata_locale");
+      let stringstmt = self.getStatement("addAddonMetadata_strings");
+
+      copyProperties(aLocale, PROP_LOCALE_SINGLE, localestmt.params);
+      executeStatement(localestmt);
+      let row = XPIDatabase.connection.lastInsertRowID;
+
+      PROP_LOCALE_MULTI.forEach(function(aProp) {
+        aLocale[aProp].forEach(function(aStr) {
+          stringstmt.params.locale = row;
+          stringstmt.params.type = aProp;
+          stringstmt.params.value = aStr;
+          executeStatement(stringstmt);
+        });
+      });
+      return row;
+    }
+
     // Any errors in here should rollback the transaction
     try {
-      let localestmt = this.getStatement("addAddonMetadata_locale");
-      let stringstmt = this.getStatement("addAddonMetadata_strings");
-
-      function insertLocale(aLocale) {
-        copyProperties(aLocale, PROP_LOCALE_SINGLE, localestmt.params);
-        executeStatement(localestmt);
-        let row = XPIDatabase.connection.lastInsertRowID;
-
-        PROP_LOCALE_MULTI.forEach(function(aProp) {
-          aLocale[aProp].forEach(function(aStr) {
-            stringstmt.params.locale = row;
-            stringstmt.params.type = aProp;
-            stringstmt.params.value = aStr;
-            executeStatement(stringstmt);
-          });
-        });
-        return row;
-      }
 
       if (aAddon.visible) {
         let stmt = this.getStatement("clearVisibleAddons");
         stmt.params.id = aAddon.id;
         executeStatement(stmt);
       }
 
       let stmt = this.getStatement("addAddonMetadata_addon");
@@ -7507,17 +7511,17 @@ DirectoryInstallLocation.prototype = {
 
       if (!gIDTest.test(id)) {
         LOG("Ignoring file entry whose name is not a valid add-on ID: " +
              entry.path);
         continue;
       }
 
       if (entry.isFile() && !directLoad) {
-        newEntry = this._readDirectoryFromFile(entry);
+        let newEntry = this._readDirectoryFromFile(entry);
         if (!newEntry) {
           LOG("Deleting stale pointer file " + entry.path);
           entry.remove(true);
           continue;
         }
 
         entry = newEntry;
         this._linkedAddons.push(id);
--- a/toolkit/mozapps/extensions/addonManager.js
+++ b/toolkit/mozapps/extensions/addonManager.js
@@ -38,16 +38,18 @@
 */
 
 /**
  * This component serves as integration between the platform and AddonManager.
  * It is responsible for initializing and shutting down the AddonManager as well
  * as passing new installs from webpages to the AddonManager.
  */
 
+"use strict";
+
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 const Cr = Components.results;
 
 const PREF_EM_UPDATE_INTERVAL = "extensions.update.interval";
 
 // The old XPInstall error codes
 const EXECUTION_ERROR   = -203;
@@ -134,28 +136,28 @@ amManager.prototype = {
     let installs = [];
     function buildNextInstall() {
       if (aUris.length == 0) {
         AddonManager.installAddonsFromWebpage(aMimetype, aWindow, aReferer, installs);
         return;
       }
       let uri = aUris.shift();
       AddonManager.getInstallForURL(uri, function(aInstall) {
+        function callCallback(aUri, aStatus) {
+          try {
+            aCallback.onInstallEnded(aUri, aStatus);
+          }
+          catch (e) {
+            Components.utils.reportError(e);
+          }
+        }
+
         if (aInstall) {
           installs.push(aInstall);
           if (aCallback) {
-            function callCallback(aUri, aStatus) {
-              try {
-                aCallback.onInstallEnded(aUri, aStatus);
-              }
-              catch (e) {
-                Components.utils.reportError(e);
-              }
-            }
-
             aInstall.addListener({
               onDownloadCancelled: function(aInstall) {
                 callCallback(uri, USER_CANCELLED);
               },
 
               onDownloadFailed: function(aInstall) {
                 if (aInstall.error == AddonManager.ERROR_CORRUPT_FILE)
                   callCallback(uri, CANT_READ_ARCHIVE);
--- a/toolkit/mozapps/extensions/amContentHandler.js
+++ b/toolkit/mozapps/extensions/amContentHandler.js
@@ -32,16 +32,18 @@
 # 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 *****
 */
 
+"use strict";
+
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 const Cr = Components.results;
 
 const XPI_CONTENT_TYPE = "application/x-xpinstall";
 
 Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
 
--- a/toolkit/mozapps/extensions/amWebInstallListener.js
+++ b/toolkit/mozapps/extensions/amWebInstallListener.js
@@ -39,16 +39,18 @@
 
 /**
  * This is a default implementation of amIWebInstallListener that should work
  * for most applications but can be overriden. It notifies the observer service
  * about blocked installs. For normal installs it pops up an install
  * confirmation when all the add-ons have been downloaded.
  */
 
+"use strict";
+
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 const Cr = Components.results;
 
 Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
 Components.utils.import("resource://gre/modules/AddonManager.jsm");
 Components.utils.import("resource://gre/modules/Services.jsm");
 
--- a/toolkit/mozapps/extensions/content/about.js
+++ b/toolkit/mozapps/extensions/content/about.js
@@ -31,16 +31,18 @@
 # 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 *****
 
+"use strict";
+
 function init() {
   var addon = window.arguments[0];
   var extensionsStrings = document.getElementById("extensionsStrings");
 
   document.documentElement.setAttribute("addontype", addon.type);
 
   if (addon.iconURL) {
     var extensionIcon = document.getElementById("extensionIcon");
--- a/toolkit/mozapps/extensions/content/blocklist.js
+++ b/toolkit/mozapps/extensions/content/blocklist.js
@@ -30,16 +30,18 @@
 # 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 *****
 
+"use strict";
+
 Components.utils.import("resource://gre/modules/Services.jsm");
 
 var gArgs;
 
 function init() {
   var hasHardBlocks = false;
   var hasSoftBlocks = false;
   gArgs = window.arguments[0].wrappedJSObject;
--- a/toolkit/mozapps/extensions/content/eula.js
+++ b/toolkit/mozapps/extensions/content/eula.js
@@ -30,16 +30,18 @@
 # 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 *****
 
+"use strict";
+
 function Startup() {
   var bundle = document.getElementById("extensionsStrings");
   var addon = window.arguments[0].addon;
 
   document.documentElement.setAttribute("addontype", addon.type);
 
   if (addon.iconURL)
     document.getElementById("icon").src = addon.iconURL;
--- a/toolkit/mozapps/extensions/content/extensions-content.js
+++ b/toolkit/mozapps/extensions/content/extensions-content.js
@@ -32,16 +32,18 @@
 # 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 *****
 */
 
+"use strict";
+
 (function(){
 
 let Cc = Components.classes;
 let Ci = Components.interfaces;
 let Cu = Components.utils;
 
 const MSG_INSTALL_ENABLED  = "WebInstallerIsInstallEnabled";
 const MSG_INSTALL_ADDONS   = "WebInstallerInstallAddonsFromWebpage";
--- a/toolkit/mozapps/extensions/content/extensions.js
+++ b/toolkit/mozapps/extensions/content/extensions.js
@@ -30,16 +30,18 @@
  * 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 ***** */
 
+"use strict";
+
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 const Cu = Components.utils;
 
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/PluralForm.jsm");
@@ -220,23 +222,24 @@ var HTML5History = {
     window.history.pushState(aState, document.title);
   },
 
   replaceState: function(aState) {
     window.history.replaceState(aState, document.title);
   },
 
   popState: function() {
-    window.addEventListener("popstate", function(event) {
-      window.removeEventListener("popstate", arguments.callee, true);
+    function onStatePopped(aEvent) {
+      window.removeEventListener("popstate", onStatePopped, true);
       // TODO To ensure we can't go forward again we put an additional entry
       // for the current state into the history. Ideally we would just strip
       // the history but there doesn't seem to be a way to do that. Bug 590661
-      window.history.pushState(event.state, document.title);
-    }, true);
+      window.history.pushState(aEvent.state, document.title);
+    }
+    window.addEventListener("popstate", onStatePopped, true);
     window.history.back();
     gViewController.updateCommand("cmd_back");
     gViewController.updateCommand("cmd_forward");
   }
 };
 
 /**
  * A wrapper around a fake history service
--- a/toolkit/mozapps/extensions/content/list.js
+++ b/toolkit/mozapps/extensions/content/list.js
@@ -70,16 +70,18 @@ const kDialog = "dialog";
  *            focused: true },
  *  cancel: { label: "A Label for the Cancel button" },
  *  ...
  * },
  *
  * result:  The dlgtype of button that was used to dismiss the dialog. 
  */
 
+"use strict";
+
 var gButtons = { };
 
 function init() {
   var de = document.documentElement;
   var items = [];
   if (window.arguments[0] instanceof Components.interfaces.nsIDialogParamBlock) {
     // This is a warning about a blocklisted item the user is trying to install
     var args = window.arguments[0];
--- a/toolkit/mozapps/extensions/content/update.js
+++ b/toolkit/mozapps/extensions/content/update.js
@@ -33,16 +33,18 @@
 # 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 *****
 
 // This UI is only opened from the Extension Manager when the app is upgraded.
 
+"use strict";
+
 const PREF_UPDATE_EXTENSIONS_ENABLED            = "extensions.update.enabled";
 const PREF_XPINSTALL_ENABLED                    = "xpinstall.enabled";
 
 Components.utils.import("resource://gre/modules/Services.jsm");
 Components.utils.import("resource://gre/modules/AddonManager.jsm");
 
 var gUpdateWizard = {
   // When synchronizing app compatibility info this contains all installed
--- a/toolkit/mozapps/extensions/nsBlocklistService.js
+++ b/toolkit/mozapps/extensions/nsBlocklistService.js
@@ -35,16 +35,18 @@
 # 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 *****
 */
 
+"use strict";
+
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 const Cr = Components.results;
 
 Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
 Components.utils.import("resource://gre/modules/FileUtils.jsm");
 Components.utils.import("resource://gre/modules/AddonManager.jsm");
 Components.utils.import("resource://gre/modules/Services.jsm");
@@ -1031,30 +1033,31 @@ Blocklist.prototype = {
           else
             addonList[i].item.softDisabled = true;
         }
 
         if (args.restart)
           restartApp();
 
         Services.obs.notifyObservers(self, "blocklist-updated", "");
-        Services.obs.removeObserver(arguments.callee, "addon-blocklist-closed");
+        Services.obs.removeObserver(applyBlocklistChanges, "addon-blocklist-closed");
       }
 
       Services.obs.addObserver(applyBlocklistChanges, "addon-blocklist-closed", false)
 
+      function blocklistUnloadHandler(event) {
+        if (event.target.location == URI_BLOCKLIST_DIALOG) {
+          applyBlocklistChanges();
+          blocklistWindow.removeEventListener("unload", blocklistUnloadHandler);
+        }
+      }
+
       let blocklistWindow = Services.ww.openWindow(null, URI_BLOCKLIST_DIALOG, "",
                               "chrome,centerscreen,dialog,titlebar", args);
-
-      blocklistWindow.addEventListener("unload", function(event) {
-        if(event.target.location == URI_BLOCKLIST_DIALOG) {
-          applyBlocklistChanges();
-          blocklistWindow.removeEventListener("unload", arguments.callee);
-        }
-      },false)
+      blocklistWindow.addEventListener("unload", blocklistUnloadHandler, false);
     });
   },
 
   classID: Components.ID("{66354bc9-7ed1-4692-ae1d-8da97d6b205e}"),
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver,
                                          Ci.nsIBlocklistService,
                                          Ci.nsITimerCallback]),
 };
--- a/tools/trace-malloc/leaksoup.cpp
+++ b/tools/trace-malloc/leaksoup.cpp
@@ -335,17 +335,17 @@ int main(int argc, char **argv)
                count, num_root_nodes, num_sccs);
 
         for (size_t i = 0; i < count; ++i) {
             nodes[i].reached = PR_FALSE;
         }
 
         // Loop over the sorted nodes twice, first printing the roots
         // and then the non-roots.
-        for (PRBool root_type = PR_TRUE;
+        for (PRInt32 root_type = PR_TRUE;
              root_type == PR_TRUE || root_type == PR_FALSE; --root_type) {
             if (root_type) {
                 printf("\n\n"
                        "<div class=\"root\">\n"
                        "<h1 id=\"root\">Root components</h1>\n");
             } else {
                 printf("\n\n"
                        "<div class=\"nonroot\">\n"
--- a/widget/src/cocoa/TextInputHandler.h
+++ b/widget/src/cocoa/TextInputHandler.h
@@ -1051,17 +1051,17 @@ private:
 };
 
 /**
  * TextInputHandler implements the NSTextInput protocol.
  */
 class TextInputHandler : public IMEInputHandler
 {
 public:
-  static PRBool sLastModifierState;
+  static NSUInteger sLastModifierState;
 
   static CFArrayRef CreateAllKeyboardLayoutList();
   static void DebugPrintAllKeyboardLayouts();
 
   TextInputHandler(nsChildView* aWidget, NSView<mozView> *aNativeView);
   virtual ~TextInputHandler();
 
   /**
--- a/widget/src/cocoa/TextInputHandler.mm
+++ b/widget/src/cocoa/TextInputHandler.mm
@@ -900,17 +900,17 @@ TISInputSourceWrapper::InitKeyPressEvent
 
 
 /******************************************************************************
  *
  *  TextInputHandler implementation (static methods)
  *
  ******************************************************************************/
 
-PRBool TextInputHandler::sLastModifierState = PR_FALSE;
+NSUInteger TextInputHandler::sLastModifierState = 0;
 
 // static
 CFArrayRef
 TextInputHandler::CreateAllKeyboardLayoutList()
 {
   const void* keys[] = { kTISPropertyInputSourceType };
   const void* values[] = { kTISTypeKeyboardLayout };
   CFDictionaryRef filter =
--- a/widget/src/windows/nsWindow.cpp
+++ b/widget/src/windows/nsWindow.cpp
@@ -4246,21 +4246,16 @@ nsWindow::IPCWindowProcHandler(UINT& msg
               !wcscmp(szClass, L"Edit") &&
               !IsOurProcessWindow(focusWnd)) {
             break;
           }
         }
         handled = PR_TRUE;
       }
     break;
-    // Wheel events forwarded from the child.
-    case WM_MOUSEWHEEL:
-    case WM_MOUSEHWHEEL:
-    case WM_HSCROLL:
-    case WM_VSCROLL:
     // Plugins taking or losing focus triggering focus app messages.
     case WM_SETFOCUS:
     case WM_KILLFOCUS:
     // Windowed plugins that pass sys key events to defwndproc generate
     // WM_SYSCOMMAND events to the main window.
     case WM_SYSCOMMAND:
     // Windowed plugins that fire context menu selection events to parent
     // windows.
@@ -5118,16 +5113,23 @@ PRBool nsWindow::ProcessMessage(UINT msg
     break;
 
     case WM_HSCROLL:
     case WM_VSCROLL:
       *aRetValue = 0;
       result = OnScroll(msg, wParam, lParam);
       break;
 
+    case MOZ_WM_HSCROLL:
+    case MOZ_WM_VSCROLL:
+      *aRetValue = 0;
+      OnScrollInternal(GetNativeMessage(msg), wParam, lParam);
+      // Doesn't need to call next wndproc for internal message.
+      return PR_TRUE;
+
     // The WM_ACTIVATE event is fired when a window is raised or lowered,
     // and the loword of wParam specifies which. But we don't want to tell
     // the focus system about this until the WM_SETFOCUS or WM_KILLFOCUS
     // events are fired. Instead, set either the sJustGotActivate or
     // gJustGotDeativate flags and fire the NS_ACTIVATE or NS_DEACTIVATE
     // events once the focus events arrive.
     case WM_ACTIVATE:
       if (mEventCallback) {
@@ -5280,28 +5282,36 @@ PRBool nsWindow::ProcessMessage(UINT msg
                           MOZ_SYSCONTEXT_Y_POS);
         result = PR_TRUE;
       }
     }
     break;
 
   case WM_MOUSEWHEEL:
   case WM_MOUSEHWHEEL:
+    OnMouseWheel(msg, wParam, lParam, aRetValue);
+    // We don't need to call next wndproc WM_MOUSEWHEEL and WM_MOUSEHWHEEL.
+    // We should consume them always.  If the messages would be handled by
+    // our window again, it causes making infinite message loop.
+    return PR_TRUE;
+
+  case MOZ_WM_MOUSEVWHEEL:
+  case MOZ_WM_MOUSEHWHEEL:
     {
+      UINT nativeMessage = GetNativeMessage(msg);
       // If OnMouseWheel returns true, the event was forwarded directly to another
       // mozilla window message handler (ProcessMessage). In this case the return
       // value of the forwarded event is in 'result' which we should return immediately.
       // If OnMouseWheel returns false, OnMouseWheel processed the event internally.
       // 'result' and 'aRetValue' will be set based on what we did with the event, so
       // we should fall through.
-      if (OnMouseWheel(msg, wParam, lParam, result, aRetValue)) {
-        return result;
-      }
-    }
-    break;
+      OnMouseWheelInternal(nativeMessage, wParam, lParam, aRetValue);
+      // Doesn't need to call next wndproc for internal message.
+      return PR_TRUE;
+    }
 
 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
   case WM_DWMCOMPOSITIONCHANGED:
     // First, update the compositor state to latest one. All other methods
     // should use same state as here for consistency painting.
     nsUXThemeData::CheckForCompositor(PR_TRUE);
 
     UpdateNonClientMargins();
@@ -6361,59 +6371,44 @@ nsWindow::ResetRemainingWheelDelta()
   sLastMouseWheelWnd = NULL;
 }
 
 static PRInt32 RoundDelta(double aDelta)
 {
   return aDelta >= 0 ? (PRInt32)NS_floor(aDelta) : (PRInt32)NS_ceil(aDelta);
 }
 
-/*
- * OnMouseWheel - mouse wheel event processing. This was originally embedded
- * within the message case block. If returning true result should be returned
- * immediately (no more processing).
+/**
+ * OnMouseWheelInternal - mouse wheel event processing.
+ * aMessage may be WM_MOUSEWHEEL or WM_MOUSEHWHEEL but this is called when
+ * ProcessMessage() handles MOZ_WM_MOUSEVWHEEL or MOZ_WM_MOUSEHWHEEL.
  */
-PRBool
-nsWindow::OnMouseWheel(UINT aMessage, WPARAM aWParam, LPARAM aLParam,
-                       PRBool& aHandled, LRESULT *aRetValue)
+void
+nsWindow::OnMouseWheelInternal(UINT aMessage, WPARAM aWParam, LPARAM aLParam,
+                               LRESULT *aRetValue)
 {
   InitMouseWheelScrollData();
 
   PRBool isVertical = (aMessage == WM_MOUSEWHEEL);
   if ((isVertical && sMouseWheelScrollLines == 0) ||
       (!isVertical && sMouseWheelScrollChars == 0)) {
     // XXX I think that we should dispatch mouse wheel events even if the
     // operation will not scroll because the wheel operation really happened
     // and web application may want to handle the event for non-scroll action.
     ResetRemainingWheelDelta();
     *aRetValue = isVertical ? TRUE : FALSE; // means we don't process it
-    aHandled = PR_FALSE;
-    return PR_FALSE;
-  }
-
-  // The mousewheel event will be dispatched to the toplevel
-  // window.  We need to give it to the child window.
-  PRBool quit;
-  if (!HandleScrollingPlugins(aMessage, aWParam, aLParam,
-                              aHandled, aRetValue, quit)) {
-    ResetRemainingWheelDelta();
-    return quit; // return immediately if it's not our window
- }
+    return;
+  }
 
   PRInt32 nativeDelta = (short)HIWORD(aWParam);
   if (!nativeDelta) {
     *aRetValue = isVertical ? TRUE : FALSE; // means we don't process it
-    aHandled = PR_FALSE;
     ResetRemainingWheelDelta();
-    return PR_FALSE; // We cannot process this message
-  }
-
-  // The event may go to a plug-in which already dispatched this message.
-  // Then, the event can cause deadlock.  We should unlock the sender here.
-  ::ReplyMessage(isVertical ? 0 : TRUE);
+    return; // We cannot process this message
+  }
 
   PRBool isPageScroll =
     ((isVertical && sMouseWheelScrollLines == WHEEL_PAGESCROLL) ||
      (!isVertical && sMouseWheelScrollChars == WHEEL_PAGESCROLL));
 
   // Discard the remaining delta if current wheel message and last one are
   // received by different window or to scroll different direction or
   // different unit scroll.  Furthermore, if the last event was too old.
@@ -6551,27 +6546,27 @@ nsWindow::OnMouseWheel(UINT aMessage, WP
     scrollEvent.delta =
       RoundDelta((double)nativeDeltaForScroll * orienter / deltaPerUnit);
     PRInt32 recomputedNativeDelta =
       (PRInt32)(scrollEvent.delta * orienter * deltaPerUnit);
     sRemainingDeltaForScroll = nativeDeltaForScroll - recomputedNativeDelta;
   }
 
   if (scrollEvent.delta) {
-    aHandled = DispatchWindowEvent(&scrollEvent);
+    DispatchWindowEvent(&scrollEvent);
     if (mOnDestroyCalled) {
       ResetRemainingWheelDelta();
-      return PR_FALSE;
+      return;
     }
   }
 
   // If the query event failed, we cannot send pixel events.
   if (!dispatchPixelScrollEvent) {
     sRemainingDeltaForPixel = 0;
-    return PR_FALSE;
+    return;
   }
 
   nsMouseScrollEvent pixelEvent(PR_TRUE, NS_MOUSE_PIXEL_SCROLL, this);
   InitEvent(pixelEvent);
   pixelEvent.scrollFlags = nsMouseScrollEvent::kAllowSmoothScroll;
   pixelEvent.scrollFlags |= isVertical ?
     nsMouseScrollEvent::kIsVertical : nsMouseScrollEvent::kIsHorizontal;
   if (actualScrollAction == nsQueryContentEvent::SCROLL_ACTION_PAGE) {
@@ -6591,19 +6586,19 @@ nsWindow::OnMouseWheel(UINT aMessage, WP
   double deltaPerPixel =
     (double)WHEEL_DELTA / computedScrollAmount / pixelsPerUnit;
   pixelEvent.delta =
     RoundDelta((double)nativeDeltaForPixel * orienterForPixel / deltaPerPixel);
   PRInt32 recomputedNativeDelta =
     (PRInt32)(pixelEvent.delta * orienterForPixel * deltaPerPixel);
   sRemainingDeltaForPixel = nativeDeltaForPixel - recomputedNativeDelta;
   if (pixelEvent.delta != 0) {
-    aHandled = DispatchWindowEvent(&pixelEvent);
-  }
-  return PR_FALSE;
+    DispatchWindowEvent(&pixelEvent);
+  }
+  return;
 }
 
 static PRBool
 StringCaseInsensitiveEquals(const PRUnichar* aChars1, const PRUint32 aNumChars1,
                             const PRUnichar* aChars2, const PRUint32 aNumChars2)
 {
   if (aNumChars1 != aNumChars2)
     return PR_FALSE;
@@ -7577,38 +7572,69 @@ static PRBool IsElantechHelperWindow(HWN
       }
     }
     ::CloseHandle(hProcess);
   }
 
   return result;
 }
 
-// Scrolling helper function for handling plugins.  
-// Return value indicates whether the calling function should handle this
-// aHandled indicates whether this was handled at all
-// aQuitProcessing tells whether or not to continue processing the message
-PRBool nsWindow::HandleScrollingPlugins(UINT aMsg, WPARAM aWParam,
-                                        LPARAM aLParam, PRBool& aHandled,
-                                        LRESULT* aRetValue,
-                                        PRBool& aQuitProcessing)
-{
-  // The scroll event will be dispatched to the toplevel
-  // window.  We need to give it to the child window
-  aQuitProcessing = PR_FALSE; // default is to not stop processing
+// static
+UINT
+nsWindow::GetInternalMessage(UINT aNativeMessage)
+{
+  switch (aNativeMessage) {
+    case WM_MOUSEWHEEL:
+      return MOZ_WM_MOUSEVWHEEL;
+    case WM_MOUSEHWHEEL:
+      return MOZ_WM_MOUSEHWHEEL;
+    case WM_VSCROLL:
+      return MOZ_WM_VSCROLL;
+    case WM_HSCROLL:
+      return MOZ_WM_HSCROLL;
+    default:
+      return aNativeMessage;
+  }
+}
+
+// static
+UINT
+nsWindow::GetNativeMessage(UINT aInternalMessage)
+{
+  switch (aInternalMessage) {
+    case MOZ_WM_MOUSEVWHEEL:
+      return WM_MOUSEWHEEL;
+    case MOZ_WM_MOUSEHWHEEL:
+      return WM_MOUSEHWHEEL;
+    case MOZ_WM_VSCROLL:
+      return WM_VSCROLL;
+    case MOZ_WM_HSCROLL:
+      return WM_HSCROLL;
+    default:
+      return aInternalMessage;
+  }
+}
+
+/**
+ * OnMouseWheel() is called when ProcessMessage() handles WM_MOUSEWHEEL,
+ * WM_MOUSEHWHEEL and also OnScroll() tries to emulate mouse wheel action for
+ * WM_VSCROLL or WM_HSCROLL.
+ * So, aMsg may be WM_MOUSEWHEEL, WM_MOUSEHWHEEL, WM_VSCROLL or WM_HSCROLL.
+ */
+void
+nsWindow::OnMouseWheel(UINT aMsg, WPARAM aWParam, LPARAM aLParam,
+                       LRESULT *aRetValue)
+{
+  *aRetValue = (aMsg != WM_MOUSEHWHEEL) ? TRUE : FALSE;
+
   POINT point;
   DWORD dwPoints = ::GetMessagePos();
   point.x = GET_X_LPARAM(dwPoints);
   point.y = GET_Y_LPARAM(dwPoints);
 
-  static PRBool sIsProcessing = PR_FALSE;
-  if (sIsProcessing) {
-    return PR_TRUE;  // the caller should handle this.
-  }
-
   static PRBool sMayBeUsingLogitechMouse = PR_FALSE;
   if (aMsg == WM_MOUSEHWHEEL) {
     // Logitech (Logicool) mouse driver (confirmed with 4.82.11 and MX-1100)
     // always sets 0 to the lParam of WM_MOUSEHWHEEL.  The driver SENDs one
     // message at first time, this time, ::GetMessagePos works fine.
     // Then, we will return 0 (0 means we process it) to the message. Then, the
     // driver will POST the same messages continuously during the wheel tilted.
     // But ::GetMessagePos API always returns (0, 0), even if the actual mouse
@@ -7625,167 +7651,111 @@ PRBool nsWindow::HandleScrollingPlugins(
     // If the WM_MOUSEHWHEEL comes from Logitech's mouse driver, and the
     // ::GetMessagePos isn't correct, probably, we should use ::GetCursorPos
     // instead.
     if (sMayBeUsingLogitechMouse && aLParam == 0 && dwPoints == 0) {
       ::GetCursorPos(&point);
     }
   }
 
-  HWND destWnd = ::WindowFromPoint(point);
-  // Since we receive scroll events for as long as
-  // we are focused, it's entirely possible that there
-  // is another app's window or no window under the
-  // pointer.
-
-  if (sUseElantechPinchHack && IsElantechHelperWindow(destWnd)) {
+  HWND underCursorWnd = ::WindowFromPoint(point);
+  if (!underCursorWnd) {
+    return;
+  }
+
+  if (sUseElantechPinchHack && IsElantechHelperWindow(underCursorWnd)) {
     // The Elantech driver places a window right underneath the cursor
     // when sending a WM_MOUSEWHEEL event to us as part of a pinch-to-zoom
     // gesture.  We detect that here, and search for our window that would
     // be beneath the cursor if that window wasn't there.
-    destWnd = FindOurWindowAtPoint(point);
-  }
-
-  if (!destWnd) {
-    // No window is under the pointer
-    return PR_FALSE; // break, but continue processing
-  }
-
-  nsWindow* destWindow;
-
-  // We don't handle the message if the found window belongs to another
-  // process's top window.  If it belongs window, that is a plug-in's window.
-  // Then, we need to send the message to the plug-in window.
-  if (!IsOurProcessWindow(destWnd)) {
-    HWND ourPluginWnd = FindOurProcessWindow(destWnd);
-    if (!ourPluginWnd) {
-      // Somebody elses window
-      return PR_FALSE; // break, but continue processing
-    }
-    destWindow = GetNSWindowPtr(ourPluginWnd);
-  } else {
-    destWindow = GetNSWindowPtr(destWnd);
-  }
-
-  if (destWindow == this && mWindowType == eWindowType_plugin) {
-    // If this is plug-in window, the message came from the plug-in window.
-    // Then, the message should be processed on the parent window.
-    destWindow = static_cast<nsWindow*>(GetParent());
-    NS_ENSURE_TRUE(destWindow, PR_FALSE); // break, but continue processing
-    destWnd = destWindow->mWnd;
-    NS_ENSURE_TRUE(destWnd, PR_FALSE); // break, but continue processing
-  }
-
-  if (!destWindow || destWindow->mWindowType == eWindowType_plugin) {
-    // Some other app, or a plugin window.
-    // Windows directs scrolling messages to the focused window.
-    // However, Mozilla does not like plugins having focus, so a
-    // Mozilla window (ie, the plugin's parent (us!) has focus.)
-    // Therefore, plugins etc _should_ get first grab at the
-    // message, but this focus vaguary means the plugin misses
-    // out. If the window is a child of ours, forward it on.
-    // Determine if a child by walking the parent list until
-    // we find a parent matching our wndproc.
-    HWND parentWnd = ::GetParent(destWnd);
-    while (parentWnd) {
-      nsWindow* parentWindow = GetNSWindowPtr(parentWnd);
-      if (parentWindow) {
-        // We have a child window - quite possibly a plugin window.
-        // However, not all plugins are created equal - some will handle this 
-        // message themselves, some will forward directly back to us, while 
-        // others will call DefWndProc, which itself still forwards back to us.
-        // So if we have sent it once, we need to handle it ourself.
-
-        // XXX The message shouldn't come from the plugin window at here.
-        // But the message might come from it due to some bugs.  If it happens,
-        // SendMessage causes deadlock.  For safety, we should unlock the
-        // sender here.
-        ::ReplyMessage(aMsg == WM_MOUSEHWHEEL ? TRUE : 0);
-
-        // First time we have seen this message.
-        // Call the child - either it will consume it, or
-        // it will wind it's way back to us,triggering the destWnd case above
-        // either way,when the call returns,we are all done with the message,
-        sIsProcessing = PR_TRUE;
-        ::SendMessageW(destWnd, aMsg, aWParam, aLParam);
-        sIsProcessing = PR_FALSE;
-        aHandled = PR_TRUE;
-        aQuitProcessing = PR_TRUE;
-        return PR_FALSE; // break, and stop processing
+    underCursorWnd = FindOurWindowAtPoint(point);
+    if (!underCursorWnd) {
+      return;
+    }
+  }
+
+  // Handle most cases first.  If the window under mouse cursor is our window
+  // except plugin window (MozillaWindowClass), we should handle the message
+  // on the window.
+  if (IsOurProcessWindow(underCursorWnd)) {
+    nsWindow* destWindow = GetNSWindowPtr(underCursorWnd);
+    if (!destWindow) {
+      NS_WARNING("We're not sure what cause this is.");
+      HWND wnd = ::GetParent(underCursorWnd);
+      for (; wnd; wnd = ::GetParent(wnd)) {
+        destWindow = GetNSWindowPtr(wnd);
+        if (destWindow) {
+          break;
+        }
+      }
+      if (!wnd) {
+        return;
       }
-      parentWnd = ::GetParent(parentWnd);
-    } // while parentWnd
-  }
-  if (destWnd == nsnull)
-    return PR_FALSE;
-  if (destWnd != mWnd) {
-    if (destWindow) {
-      sIsProcessing = PR_TRUE;
-      aHandled = destWindow->ProcessMessage(aMsg, aWParam, aLParam, aRetValue);
-      sIsProcessing = PR_FALSE;
-      aQuitProcessing = PR_TRUE;
-      return PR_FALSE; // break, and stop processing
-    }
-  #ifdef DEBUG
-    else
-      printf("WARNING: couldn't get child window for SCROLL event\n");
-  #endif
-  }
-  return PR_TRUE;  // caller should handle this
-}
-
-PRBool nsWindow::OnScroll(UINT aMsg, WPARAM aWParam, LPARAM aLParam)
+    }
+
+    NS_ASSERTION(destWindow, "destWindow must not be NULL");
+    // If the found window is our plugin window, it means that the message
+    // has been handled by the plugin but not consumed.  We should handle the
+    // message on its parent window.
+    if (destWindow->mWindowType == eWindowType_plugin) {
+      destWindow = destWindow->GetParentWindow(PR_FALSE);
+      NS_ENSURE_TRUE(destWindow, );
+    }
+    UINT internalMessage = GetInternalMessage(aMsg);
+    destWindow->ProcessMessage(internalMessage, aWParam, aLParam, aRetValue);
+    return;
+  }
+
+  // If the window under cursor is not in our process, it means:
+  // 1. The window may be a plugin window (GeckoPluginWindow or its descendant).
+  // 2. The window may be another application's window.
+  HWND pluginWnd = FindOurProcessWindow(underCursorWnd);
+  if (!pluginWnd) {
+    // If there is no plugin window in ancestors of the window under cursor,
+    // the window is for another applications (case 2).
+    // We don't need to handle this message.
+    return;
+  }
+
+  // If we're a plugin window (MozillaWindowClass) and cursor in this window,
+  // the message shouldn't go to plugin's wndproc again.  So, we should handle
+  // it on parent window.
+  if (mWindowType == eWindowType_plugin && pluginWnd == mWnd) {
+    nsWindow* destWindow = GetParentWindow(PR_FALSE);
+    NS_ENSURE_TRUE(destWindow, );
+    UINT internalMessage = GetInternalMessage(aMsg);
+    destWindow->ProcessMessage(internalMessage, aWParam, aLParam, aRetValue);
+    return;
+  }
+
+  // If the window is a part of plugin, we should post the message to it.
+  ::PostMessage(underCursorWnd, aMsg, aWParam, aLParam);
+}
+
+/**
+ * OnScroll() is called when ProcessMessage() handles WM_VSCROLL or WM_HSCROLL.
+ * aMsg may be WM_VSCROLL or WM_HSCROLL.
+ */
+PRBool
+nsWindow::OnScroll(UINT aMsg, WPARAM aWParam, LPARAM aLParam)
 {
   static PRInt8 sMouseWheelEmulation = -1;
   if (sMouseWheelEmulation < 0) {
     PRBool emulate =
       Preferences::GetBool("mousewheel.emulate_at_wm_scroll", PR_FALSE);
     sMouseWheelEmulation = PRInt8(emulate);
   }
 
   if (aLParam || sMouseWheelEmulation) {
     // Scroll message generated by Thinkpad Trackpoint Driver or similar
     // Treat as a mousewheel message and scroll appropriately
-    PRBool quit, result;
     LRESULT retVal;
-
-    if (!HandleScrollingPlugins(aMsg, aWParam, aLParam, result, &retVal, quit))
-      return quit;  // Return if it's not our message or has been dispatched
-
-    nsMouseScrollEvent scrollevent(PR_TRUE, NS_MOUSE_SCROLL, this);
-    scrollevent.scrollFlags = (aMsg == WM_VSCROLL) 
-                              ? nsMouseScrollEvent::kIsVertical
-                              : nsMouseScrollEvent::kIsHorizontal;
-    switch (LOWORD(aWParam))
-    {
-      case SB_PAGEDOWN:
-        scrollevent.scrollFlags |= nsMouseScrollEvent::kIsFullPage;
-      case SB_LINEDOWN:
-        scrollevent.delta = 1;
-        break;
-      case SB_PAGEUP:
-        scrollevent.scrollFlags |= nsMouseScrollEvent::kIsFullPage;
-      case SB_LINEUP:
-        scrollevent.delta = -1;
-        break;
-      default:
-        return PR_FALSE;
-    }
-    // The event may go to a plug-in which already dispatched this message.
-    // Then, the event can cause deadlock.  We should unlock the sender here.
-    ::ReplyMessage(0);
-    scrollevent.isShift   = IS_VK_DOWN(NS_VK_SHIFT);
-    scrollevent.isControl = IS_VK_DOWN(NS_VK_CONTROL);
-    scrollevent.isMeta    = PR_FALSE;
-    scrollevent.isAlt     = IS_VK_DOWN(NS_VK_ALT);
-    InitEvent(scrollevent);
-    if (nsnull != mEventCallback)
-    {
-      DispatchWindowEvent(&scrollevent);
-    }
+    OnMouseWheel(aMsg, aWParam, aLParam, &retVal);
+    // Always consume the scroll message if we try to emulate mouse wheel
+    // action.
     return PR_TRUE;
   }
 
   // Scroll message generated by external application
   nsContentCommandEvent command(PR_TRUE, NS_CONTENT_COMMAND_SCROLL, this);
 
   command.mScroll.mIsHorizontal = (aMsg == WM_HSCROLL);
 
@@ -7813,20 +7783,59 @@ PRBool nsWindow::OnScroll(UINT aMsg, WPA
       break;
     case SB_BOTTOM:   // SB_RIGHT
       command.mScroll.mUnit = nsContentCommandEvent::eCmdScrollUnit_Whole;
       command.mScroll.mAmount = 1;
       break;
     default:
       return PR_FALSE;
   }
+  // XXX If this is a plugin window, we should dispatch the event from
+  //     parent window.
   DispatchWindowEvent(&command);
   return PR_TRUE;
 }
 
+/**
+ * OnScrollInternal() is called when ProcessMessage() handles MOZ_WM_VSCROLL or
+ * MOZ_WM_HSCROLL but aMsg may be WM_VSCROLL or WM_HSCROLL.
+ * These internal messages used only when OnScroll() tries to emulate mouse
+ * wheel action for the WM_VSCROLL or WM_HSCROLL message.
+ */
+void
+nsWindow::OnScrollInternal(UINT aMsg, WPARAM aWParam, LPARAM aLParam)
+{
+  nsMouseScrollEvent scrollevent(PR_TRUE, NS_MOUSE_SCROLL, this);
+  scrollevent.scrollFlags = (aMsg == WM_VSCROLL) 
+                            ? nsMouseScrollEvent::kIsVertical
+                            : nsMouseScrollEvent::kIsHorizontal;
+  switch (LOWORD(aWParam)) {
+    case SB_PAGEDOWN:
+      scrollevent.scrollFlags |= nsMouseScrollEvent::kIsFullPage;
+    case SB_LINEDOWN:
+      scrollevent.delta = 1;
+      break;
+    case SB_PAGEUP:
+      scrollevent.scrollFlags |= nsMouseScrollEvent::kIsFullPage;
+    case SB_LINEUP:
+      scrollevent.delta = -1;
+      break;
+    default:
+      return;
+  }
+  scrollevent.isShift   = IS_VK_DOWN(NS_VK_SHIFT);
+  scrollevent.isControl = IS_VK_DOWN(NS_VK_CONTROL);
+  scrollevent.isMeta    = PR_FALSE;
+  scrollevent.isAlt     = IS_VK_DOWN(NS_VK_ALT);
+  InitEvent(scrollevent);
+  if (mEventCallback) {
+    DispatchWindowEvent(&scrollevent);
+  }
+}
+
 // Can be overriden. Controls auto-erase of background.
 PRBool nsWindow::AutoErase(HDC dc)
 {
   return PR_FALSE;
 }
 
 void
 nsWindow::AllowD3D9Callback(nsWindow *aWindow)
@@ -8384,17 +8393,17 @@ LRESULT CALLBACK nsWindow::MozSpecialMsg
   return ::CallNextHookEx(sMsgFilterHook, code, wParam, lParam);
 }
 
 // Process all mouse messages. Roll up when a click is in a native window
 // that doesn't have an nsIWidget.
 LRESULT CALLBACK nsWindow::MozSpecialMouseProc(int code, WPARAM wParam, LPARAM lParam)
 {
   if (sProcessHook) {
-    switch (wParam) {
+    switch (GetNativeMessage(wParam)) {
       case WM_LBUTTONDOWN:
       case WM_RBUTTONDOWN:
       case WM_MBUTTONDOWN:
       case WM_MOUSEWHEEL:
       case WM_MOUSEHWHEEL:
       {
         MOUSEHOOKSTRUCT* ms = (MOUSEHOOKSTRUCT*)lParam;
         nsIWidget* mozWin = (nsIWidget*)GetNSWindowPtr(ms->hwnd);
@@ -8585,16 +8594,17 @@ nsWindow::EventIsInsideWindow(UINT Msg, 
 }
 
 // Handle events that may cause a popup (combobox, XPMenu, etc) to need to rollup.
 BOOL
 nsWindow::DealWithPopups(HWND inWnd, UINT inMsg, WPARAM inWParam, LPARAM inLParam, LRESULT* outResult)
 {
   if (sRollupListener && sRollupWidget && ::IsWindowVisible(inWnd)) {
 
+    inMsg = GetNativeMessage(inMsg);
     if (inMsg == WM_LBUTTONDOWN || inMsg == WM_RBUTTONDOWN || inMsg == WM_MBUTTONDOWN ||
         inMsg == WM_MOUSEWHEEL || inMsg == WM_MOUSEHWHEEL || inMsg == WM_ACTIVATE ||
         (inMsg == WM_KILLFOCUS && IsDifferentThreadWindow((HWND)inWParam)) ||
         inMsg == WM_NCRBUTTONDOWN ||
         inMsg == WM_MOVING ||
         inMsg == WM_SIZING ||
         inMsg == WM_NCLBUTTONDOWN ||
         inMsg == WM_NCMBUTTONDOWN ||
@@ -8980,17 +8990,17 @@ void nsWindow::InitInputWorkaroundPrefDe
   if (HasRegistryKey(HKEY_CURRENT_USER, L"Software\\Lenovo\\TrackPoint")) {
     sDefaultTrackPointHack = PR_TRUE;
   } else if (HasRegistryKey(HKEY_CURRENT_USER, L"Software\\Lenovo\\UltraNav")) {
     sDefaultTrackPointHack = PR_TRUE;
   } else if (HasRegistryKey(HKEY_CURRENT_USER, L"Software\\Alps\\Apoint\\TrackPoint")) {
     sDefaultTrackPointHack = PR_TRUE;
   } else if ((HasRegistryKey(HKEY_CURRENT_USER, L"Software\\Synaptics\\SynTPEnh\\UltraNavUSB") ||
               HasRegistryKey(HKEY_CURRENT_USER, L"Software\\Synaptics\\SynTPEnh\\UltraNavPS2")) &&
-              elantechDriverVersion != 0 && elantechDriverVersion <= 8) {
+              IsObsoleteSynapticsDriver()) {
     sDefaultTrackPointHack = PR_TRUE;
   }
 
   PRBool useElantechGestureHacks =
     GetInputWorkaroundPref("ui.elantech_gesture_hacks.enabled",
                            elantechDriverVersion != 0);
   sUseElantechSwipeHack = useElantechGestureHacks && elantechDriverVersion <= 7;
   sUseElantechPinchHack = useElantechGestureHacks && elantechDriverVersion <= 8;
--- a/widget/src/windows/nsWindow.h
+++ b/widget/src/windows/nsWindow.h
@@ -370,21 +370,16 @@ protected:
   LRESULT                 ProcessKeyUpMessage(const MSG &aMsg,
                                               PRBool *aEventDispatched);
   LRESULT                 ProcessKeyDownMessage(const MSG &aMsg,
                                                 PRBool *aEventDispatched);
   static PRBool           EventIsInsideWindow(UINT Msg, nsWindow* aWindow);
   // Convert nsEventStatus value to a windows boolean
   static PRBool           ConvertStatus(nsEventStatus aStatus);
   static void             PostSleepWakeNotification(const char* aNotification);
-  PRBool                  HandleScrollingPlugins(UINT aMsg, WPARAM aWParam, 
-                                                 LPARAM aLParam,
-                                                 PRBool& aResult,
-                                                 LRESULT* aRetValue,
-                                                 PRBool& aQuitProcessing);
   PRInt32                 ClientMarginHitTestPoint(PRInt32 mx, PRInt32 my);
   static WORD             GetScanCode(LPARAM aLParam)
   {
     return (aLParam >> 16) & 0xFF;
   }
   static PRBool           IsExtendedScanCode(LPARAM aLParam)
   {
     return (aLParam & 0x1000000) != 0;
@@ -412,28 +407,34 @@ protected:
   LRESULT                 OnKeyUp(const MSG &aMsg,
                                   nsModifierKeyState &aModKeyState,
                                   PRBool *aEventDispatched);
   LRESULT                 OnCharRaw(UINT charCode, UINT aScanCode,
                                     nsModifierKeyState &aModKeyState,
                                     PRUint32 aFlags = 0,
                                     const MSG *aMsg = nsnull,
                                     PRBool *aEventDispatched = nsnull);
-  virtual PRBool          OnScroll(UINT aMsg, WPARAM aWParam, LPARAM aLParam);
+  PRBool                  OnScroll(UINT aMsg, WPARAM aWParam, LPARAM aLParam);
+  void                    OnScrollInternal(UINT aMsg, WPARAM aWParam,
+                                           LPARAM aLParam);
   PRBool                  OnGesture(WPARAM wParam, LPARAM lParam);
 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_WIN7
   PRBool                  OnTouch(WPARAM wParam, LPARAM lParam);
 #endif
   PRBool                  OnHotKey(WPARAM wParam, LPARAM lParam);
   BOOL                    OnInputLangChange(HKL aHKL);
   PRBool                  OnPaint(HDC aDC, PRUint32 aNestingLevel);
   void                    OnWindowPosChanged(WINDOWPOS *wp, PRBool& aResult);
-  PRBool                  OnMouseWheel(UINT aMessage, WPARAM aWParam,
-                                       LPARAM aLParam, PRBool& aHandled,
-                                       LRESULT *aRetValue);
+  static UINT             GetInternalMessage(UINT aNativeMessage);
+  static UINT             GetNativeMessage(UINT aInternalMessage);
+  void                    OnMouseWheel(UINT aMsg, WPARAM aWParam,
+                                       LPARAM aLParam, LRESULT *aRetValue);
+  void                    OnMouseWheelInternal(UINT aMessage, WPARAM aWParam,
+                                               LPARAM aLParam,
+                                               LRESULT *aRetValue);
   void                    OnWindowPosChanging(LPWINDOWPOS& info);
 
   /**
    * Function that registers when the user has been active (used for detecting
    * when the user is idle).
    */
   void                    UserActivity();
 
--- a/widget/src/windows/nsWindowDefs.h
+++ b/widget/src/windows/nsWindowDefs.h
@@ -53,16 +53,22 @@
  * 
  **************************************************************/
 
 // A magic APP message that can be sent to quit, sort of like a QUERYENDSESSION/ENDSESSION,
 // but without the query.
 #define MOZ_WM_APP_QUIT                   (WM_APP+0x0300)
 // Used as a "tracer" event to probe event loop latency.
 #define MOZ_WM_TRACE                      (WM_APP+0x0301)
+// Our internal message for WM_MOUSEWHEEL, WM_MOUSEHWHEEL, WM_VSCROLL and
+// WM_HSCROLL
+#define MOZ_WM_MOUSEVWHEEL                (WM_APP+0x0310)
+#define MOZ_WM_MOUSEHWHEEL                (WM_APP+0x0311)
+#define MOZ_WM_VSCROLL                    (WM_APP+0x0312)
+#define MOZ_WM_HSCROLL                    (WM_APP+0x0313)
 
 // GetWindowsVersion constants
 #define WIN2K_VERSION                     0x500
 #define WINXP_VERSION                     0x501
 #define WIN2K3_VERSION                    0x502
 #define VISTA_VERSION                     0x600
 #define WIN7_VERSION                      0x601
 
--- a/xpcom/ds/nsMathUtils.h
+++ b/xpcom/ds/nsMathUtils.h
@@ -140,16 +140,20 @@ inline NS_HIDDEN_(double) NS_hypot(doubl
     return __builtin_hypot(x, y);
 #elif defined _WIN32
     return _hypot(x, y);
 #else
     return hypot(x, y);
 #endif
 }
 
+/**
+ * Check whether a floating point number is finite (not +/-infinity and not a
+ * NaN value).
+ */
 inline NS_HIDDEN_(bool) NS_finite(double d)
 {
 #ifdef WIN32
     // NOTE: '!!' casts an int to bool without spamming MSVC warning C4800.
     return !!_finite(d);
 #else
     return finite(d);
 #endif
--- a/xpcom/glue/nsTArray.h
+++ b/xpcom/glue/nsTArray.h
@@ -425,16 +425,22 @@ public:
   }
 
   template<typename Allocator>
   nsTArray& operator=(const nsTArray<E, Allocator>& other) {
     ReplaceElementsAt(0, Length(), other.Elements(), other.Length());
     return *this;
   }
 
+  // @return The amount of memory taken used by this nsTArray, not including
+  // sizeof(this)
+  size_t SizeOf() const {
+    return this->Capacity() * sizeof(elem_type) + sizeof(*this->Hdr());
+  }
+
   //
   // Accessor methods
   //
 
   // This method provides direct access to the array elements.
   // @return A pointer to the first element of the array.  If the array is
   // empty, then this pointer must not be dereferenced.
   elem_type* Elements() {
--- a/xpcom/idl-parser/xpidl.py
+++ b/xpcom/idl-parser/xpidl.py
@@ -989,20 +989,19 @@ class IDLParser(object):
     def t_INCLUDE(self, t):
         r'\#include[ \t]+"[^"\n]+"'
         inc, value, end = t.value.split('"')
         t.value = value
         return t
 
     def t_directive(self, t):
         r'\#(?P<directive>[a-zA-Z]+)[^\n]+'
-        print >>sys.stderr, IDLError("Unrecognized directive %s" % t.lexer.lexmatch.group('directive'),
-                                     Location(lexer=self.lexer,
-                                              lineno=self.lexer.lineno,
-                                              lexpos=self.lexer.lexpos))
+        raise IDLError("Unrecognized directive %s" % t.lexer.lexmatch.group('directive'),
+                       Location(lexer=self.lexer, lineno=self.lexer.lineno,
+                                lexpos=self.lexer.lexpos))
 
     def t_newline(self, t):
         r'\n+'
         t.lexer.lineno += len(t.value)
 
     def t_nativeid_NATIVEID(self, t):
         r'[^()\n]+(?=\))'
         t.lexer.begin('INITIAL')