Merge last green changeset of mozilla-inbound to mozilla-central
authorEd Morley <bmo@edmorley.co.uk>
Wed, 16 Nov 2011 11:02:43 +0000
changeset 80342 30161b298513513dba7fc9dfcfcd915fd244ba46
parent 80321 d51bd1645a2ff60806622ce7529e93301b69f336 (current diff)
parent 80341 94b2b53b2db60e1ee05c375c09faa0218ffc3fcc (diff)
child 80354 9b12fa716210edfc0fe1516a5c6192eddb15a303
child 105330 7c70058ad7b7503b674d110cd91209605fa80bfe
push id21485
push userbmo@edmorley.co.uk
push dateWed, 16 Nov 2011 11:04:25 +0000
treeherdermozilla-central@30161b298513 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone11.0a1
first release with
nightly linux32
30161b298513 / 11.0a1 / 20111117030939 / files
nightly linux64
30161b298513 / 11.0a1 / 20111117030939 / files
nightly mac
30161b298513 / 11.0a1 / 20111117030939 / files
nightly win32
30161b298513 / 11.0a1 / 20111117030939 / files
nightly win64
30161b298513 / 11.0a1 / 20111116030946 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge last green changeset of mozilla-inbound to mozilla-central
content/base/public/nsContentUtils.h
toolkit/mozapps/extensions/XPIProvider.jsm
--- a/browser/base/content/aboutSyncTabs.js
+++ b/browser/base/content/aboutSyncTabs.js
@@ -132,17 +132,16 @@ let RemoteTabViewer = {
     let uri = Weave.Utils.makeURI(item.getAttribute("url"));
     let title = item.getAttribute("title");
     PlacesUIUtils.showBookmarkDialog({ action: "add"
                                      , type: "bookmark"
                                      , uri: uri
                                      , title: title
                                      , hiddenRows: [ "description"
                                                    , "location"
-                                                   , "folderPicker"
                                                    , "loadInSidebar"
                                                    , "keyword" ]
                                      }, window.top);
   },
 
   bookmarkSelectedTabs: function() {
     let items = this._tabsList.selectedItems;
     let URIs = [];
--- a/browser/base/content/browser-places.js
+++ b/browser/base/content/browser-places.js
@@ -381,17 +381,16 @@ var PlacesCommandHook = {
     if (itemId == -1) {
       PlacesUIUtils.showBookmarkDialog({ action: "add"
                                        , type: "bookmark"
                                        , uri: linkURI
                                        , title: aTitle
                                        , hiddenRows: [ "description"
                                                      , "location"
                                                      , "loadInSidebar"
-                                                     , "folderPicker"
                                                      , "keyword" ]
                                        }, window);
     }
     else {
       PlacesUIUtils.showBookmarkDialog({ action: "edit"
                                        , type: "bookmark"
                                        , itemId: itemId
                                        }, window);
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -3158,17 +3158,16 @@ var bookmarksButtonObserver = {
     try {
       PlacesUIUtils.showBookmarkDialog({ action: "add"
                                        , type: "bookmark"
                                        , uri: makeURI(url)
                                        , title: name
                                        , hiddenRows: [ "description"
                                                      , "location"
                                                      , "loadInSidebar"
-                                                     , "folderPicker"
                                                      , "keyword" ]
                                        }, window);
     } catch(ex) { }
   },
 
   onDragOver: function (aEvent)
   {
     browserDragAndDrop.dragOver(aEvent);
@@ -5787,17 +5786,16 @@ function contentAreaClick(event, isPanel
       // the title that should be used for the sidebar panel.
       PlacesUIUtils.showBookmarkDialog({ action: "add"
                                        , type: "bookmark"
                                        , uri: makeURI(href)
                                        , title: linkNode.getAttribute("title")
                                        , loadBookmarkInSidebar: true
                                        , hiddenRows: [ "description"
                                                      , "location"
-                                                     , "folderPicker"
                                                      , "keyword" ]
                                        }, window);
       event.preventDefault();
       return true;
     }
   }
 
   handleLinkClick(event, href, linkNode);
@@ -6834,18 +6832,19 @@ function AddKeywordForSearchField() {
                                    , type: "bookmark"
                                    , uri: makeURI(spec)
                                    , title: title
                                    , description: description
                                    , keyword: ""
                                    , postData: postData
                                    , charSet: charset
                                    , hiddenRows: [ "location"
-                                                 , "loadInSidebar"
-                                                 , "folderPicker" ]
+                                                 , "description"
+                                                 , "tags"
+                                                 , "loadInSidebar" ]
                                    }, window);
 }
 
 function SwitchDocumentDirection(aWindow) {
   aWindow.document.dir = (aWindow.document.dir == "ltr" ? "rtl" : "ltr");
   for (var run = 0; run < aWindow.frames.length; run++)
     SwitchDocumentDirection(aWindow.frames[run]);
 }
--- a/browser/base/content/nsContextMenu.js
+++ b/browser/base/content/nsContextMenu.js
@@ -1401,17 +1401,16 @@ nsContextMenu.prototype = {
       PlacesUIUtils.showBookmarkDialog({ action: "add"
                                        , type: "bookmark"
                                        , uri: uri
                                        , title: title
                                        , description: description
                                        , hiddenRows: [ "description"
                                                      , "location"
                                                      , "loadInSidebar"
-                                                     , "folderPicker"
                                                      , "keyword" ]
                                        }, window.top);
     }
     else {
       PlacesUIUtils.showBookmarkDialog({ action: "edit"
                                        , type: "bookmark"
                                        , itemId: itemId
                                        }, window.top);
--- a/browser/components/places/content/bookmarkProperties.js
+++ b/browser/components/places/content/bookmarkProperties.js
@@ -259,18 +259,16 @@ var BookmarkPropertiesPanel = {
 
       if ("description" in dialogInfo)
         this._description = dialogInfo.description;
     }
     else { // edit
       NS_ASSERT("itemId" in dialogInfo);
       this._itemId = dialogInfo.itemId;
       this._title = PlacesUtils.bookmarks.getItemTitle(this._itemId);
-      // Don't show folderPicker when editing
-      this._hiddenRows.push("folderPicker");
       this._readOnly = !!dialogInfo.readOnly;
 
       switch (dialogInfo.type) {
         case "bookmark":
           this._itemType = BOOKMARK_ITEM;
 
           this._uri = PlacesUtils.bookmarks.getBookmarkURI(this._itemId);
           // keyword
--- a/browser/components/places/content/controller.js
+++ b/browser/components/places/content/controller.js
@@ -304,17 +304,16 @@ PlacesController.prototype = {
       break;
     case "placesCmd_createBookmark":
       let node = this._view.selectedNode;
       PlacesUIUtils.showBookmarkDialog({ action: "add"
                                        , type: "bookmark"
                                        , hiddenRows: [ "description"
                                                      , "keyword"
                                                      , "location"
-                                                     , "folderPicker"
                                                      , "loadInSidebar" ]
                                        , uri: NetUtil.newURI(node.uri)
                                        , title: node.title
                                        }, window.top);
       break;
     }
   },
 
@@ -716,16 +715,17 @@ PlacesController.prototype = {
       // the correct title for the node.
       itemId = concreteId;
     }
 
     PlacesUIUtils.showBookmarkDialog({ action: "edit"
                                      , type: itemType
                                      , itemId: itemId
                                      , readOnly: isRootItem
+                                     , hiddenRows: [ "folderPicker" ]
                                      }, window.top);
   },
 
   /**
    * This method can be run on a URI parameter to ensure that it didn't
    * receive a string instead of an nsIURI object.
    */
   _assertURINotString: function PC__assertURINotString(value) {
--- a/browser/components/places/src/PlacesUIUtils.jsm
+++ b/browser/components/places/src/PlacesUIUtils.jsm
@@ -335,39 +335,46 @@ var PlacesUIUtils = {
   /**
    * Shows the bookmark dialog corresponding to the specified info.
    *
    * @param aInfo
    *        Describes the item to be edited/added in the dialog.
    *        See documentation at the top of bookmarkProperties.js
    * @param aWindow
    *        Owner window for the new dialog.
-   * @param aMinimalUI [optional]
-   *        Whether to open the dialog in "minimal ui" mode. Do not pass this
-   *        for new callers.  It'll be removed in a future release.
+   * @param aResizable [optional]
+   *        Whether the dialog is allowed to resize.  Do not pass this for new
+   *        callers since it's deprecated.  It'll be removed in future releases.
    *
    * @see documentation at the top of bookmarkProperties.js
    * @return true if any transaction has been performed, false otherwise.
    */
   showBookmarkDialog:
-  function PUIU_showBookmarkDialog(aInfo, aParentWindow, aMinimalUI) {
+  function PUIU_showBookmarkDialog(aInfo, aParentWindow, aResizable) {
+    // This is a compatibility shim for add-ons.  It will warn in the Error
+    // Console when used.
     if (!aParentWindow) {
       aParentWindow = this._getWindow(null);
     }
 
     // Preserve size attributes differently based on the fact the dialog has
-    // a folder picker or not.
-    let minimalUI = "hiddenRows" in aInfo &&
-                    aInfo.hiddenRows.indexOf("folderPicker") != -1;
-    let dialogURL = aMinimalUI ?
+    // a folder picker or not.  If the picker is visible, the dialog should
+    // be resizable since it may not show enough content for the folders
+    // hierarchy.
+    let hasFolderPicker = !("hiddenRows" in aInfo) ||
+                          aInfo.hiddenRows.indexOf("folderPicker") == -1;
+    let resizable = aResizable !== undefined ? aResizable : hasFolderPicker;
+    // Use a different chrome url, since this allows to persist different sizes,
+    // based on resizability of the dialog.
+    let dialogURL = resizable ?
                     "chrome://browser/content/places/bookmarkProperties2.xul" :
                     "chrome://browser/content/places/bookmarkProperties.xul";
 
     let features =
-      "centerscreen,chrome,modal,resizable=" + (aMinimalUI ? "yes" : "no");
+      "centerscreen,chrome,modal,resizable=" + (resizable ? "yes" : "no");
 
     aParentWindow.openDialog(dialogURL, "",  features, aInfo);
     return ("performed" in aInfo && aInfo.performed);
   },
 
   _getTopBrowserWin: function PUIU__getTopBrowserWin() {
     return Services.wm.getMostRecentWindow("navigator:browser");
   },
--- a/browser/components/sidebar/src/nsSidebar.js
+++ b/browser/components/sidebar/src/nsSidebar.js
@@ -105,19 +105,17 @@ function (aTitle, aContentURL, aCustomiz
       uri = Services.io.newURI(aContentURL, null, null);
     }
     catch(ex) { return; }
 
     win.PlacesUIUtils.showBookmarkDialog({ action: "add"
                                          , type: "bookmark"
                                          , hiddenRows: [ "description"
                                                        , "keyword"
-                                                       , "location"
-                                                       , "folderPicker"
-                                                       , "loadInSidebar" ]
+                                                       , "location" ]
                                          , uri: uri
                                          , title: aTitle
                                          , loadBookmarkInSidebar: true
                                          }, win);
 }
 
 nsSidebar.prototype.validateSearchEngine =
 function (engineURL, iconURL)
--- a/content/base/public/nsContentUtils.h
+++ b/content/base/public/nsContentUtils.h
@@ -1717,20 +1717,20 @@ public:
   /**
    * Returns true if key input is restricted in DOM full-screen mode
    * to non-alpha-numeric key codes only. This mirrors the
    * "full-screen-api.key-input-restricted" pref.
    */
   static bool IsFullScreenKeyInputRestricted();
 
   /**
-   * Returns true if the doctree rooted at aDoc contains any plugins which
-   * we don't control event dispatch for, i.e. do any plugins in this doc tree
-   * receive key events outside of our control? This always returns false
-   * on MacOSX.
+   * Returns true if the doc tree branch which contains aDoc contains any
+   * plugins which we don't control event dispatch for, i.e. do any plugins
+   * in the same tab as this document receive key events outside of our
+   * control? This always returns false on MacOSX.
    */
   static bool HasPluginWithUncontrolledEventDispatch(nsIDocument* aDoc);
 
   /**
    * Returns true if the content is in a document and contains a plugin
    * which we don't control event dispatch for, i.e. do any plugins in this
    * doc tree receive key events outside of our control? This always returns
    * false on MacOSX.
--- a/content/base/src/nsContentUtils.cpp
+++ b/content/base/src/nsContentUtils.cpp
@@ -5871,17 +5871,25 @@ DocTreeContainsWindowedPlugins(nsIDocume
 bool
 nsContentUtils::HasPluginWithUncontrolledEventDispatch(nsIDocument* aDoc)
 {
 #ifdef XP_MACOSX
   // We control dispatch to all mac plugins.
   return false;
 #endif
   bool result = false;
-  DocTreeContainsWindowedPlugins(aDoc, &result);
+  
+  // Find the top of the document's branch, the child of the chrome document.
+  nsIDocument* doc = aDoc;
+  nsIDocument* parent = nsnull;
+  while (doc && (parent = doc->GetParentDocument()) && !IsChromeDoc(parent)) {
+    doc = parent;
+  }
+
+  DocTreeContainsWindowedPlugins(doc, &result);
   return result;
 }
 
 /* static */
 bool
 nsContentUtils::HasPluginWithUncontrolledEventDispatch(nsIContent* aContent)
 {
 #ifdef XP_MACOSX
new file mode 100644
--- /dev/null
+++ b/content/smil/crashtests/691337-1.svg
@@ -0,0 +1,8 @@
+<?xml version="1.0"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100">
+  <rect width="100" height="100" fill="blue">
+    <animate attributeName="fill"
+      begin="999999999999999999999999999999999999999999999999999999999999999999999999999999999"
+      dur="5s" from="blue" to="red" repeatCount="indefinite" additive="sum"/>
+  </rect>
+</svg>
new file mode 100644
--- /dev/null
+++ b/content/smil/crashtests/691337-2.svg
@@ -0,0 +1,11 @@
+<?xml version="1.0"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100">
+  <rect width="100" height="100" fill="blue">
+    <animate attributeName="fill" id="a"
+      begin="4999999999999999" dur="5s" from="blue" to="red"
+      repeatCount="indefinite" additive="sum"/>
+    <animate attributeName="fill"
+      begin="a.begin+4999999999999999"
+      dur="5s" from="blue" to="red" repeatCount="indefinite" additive="sum"/>
+  </rect>
+</svg>
--- a/content/smil/crashtests/crashtests.list
+++ b/content/smil/crashtests/crashtests.list
@@ -38,10 +38,12 @@ load 650732-1.svg
 load 665334-1.svg
 load 669225-1.svg
 load 669225-2.svg
 load 670313-1.svg
 load 678822-1.svg
 load 678847-1.svg
 load 678938-1.svg
 load 690994-1.svg
+load 691337-1.svg
+load 691337-2.svg
 load 697640-1.svg
 load 699325-1.svg
--- a/content/smil/nsSMILParserUtils.cpp
+++ b/content/smil/nsSMILParserUtils.cpp
@@ -725,17 +725,16 @@ nsSMILParserUtils::ParseClockValue(const
 {
   nsSMILTime offset = 0L;
   double component = 0.0;
 
   PRInt8 sign = 0;
   PRUint8 colonCount = 0;
 
   bool started = false;
-  bool isValid = true;
 
   PRInt32 metricMultiplicand = MSEC_PER_SEC;
 
   bool numIsReal = false;
   bool prevNumCouldBeMin = false;
   bool numCouldBeMin = false;
   bool numCouldBeSec = false;
   bool isIndefinite = false;
@@ -754,147 +753,139 @@ nsSMILParserUtils::ParseClockValue(const
         ++start;
         break;
       }
       // else, we haven't started yet, ignore initial whitespace
       ++start;
 
     } else if ((aFlags & kClockValueAllowSign)
                && (*start == '+' || *start == '-')) {
+      // check sign has not already been set
       if (sign != 0) {
-        // sign has already been set
-        isValid = false;
-        break;
+        return NS_ERROR_FAILURE;
       }
 
+      // check sign is not in middle of string
       if (started) {
-        // sign appears in the middle of the string
-        isValid = false;
-        break;
+        return NS_ERROR_FAILURE;
       }
 
       sign = (*start == '+') ? 1 : -1;
       ++start;
     // The NS_IS_DIGIT etc. macros are not locale-specific
     } else if (NS_IS_DIGIT(*start)) {
       prevNumCouldBeMin = numCouldBeMin;
 
       if (!ParseClockComponent(start, end, component, numIsReal, numCouldBeMin,
-                               numCouldBeSec)) {
-        isValid = false;
-        break;
-      }
+                               numCouldBeSec))
+        return NS_ERROR_FAILURE;
 
       started = true;
     } else if (*start == ':') {
       ++colonCount;
 
       // Neither minutes nor hours can be reals
       if (numIsReal) {
-        isValid = false;
-        break;
+        return NS_ERROR_FAILURE;
       }
 
       // Clock value can't start with a ':'
       if (!started) {
-        isValid = false;
-        break;
+        return NS_ERROR_FAILURE;
       }
 
       // Can't have more than two colons
       if (colonCount > 2) {
-        isValid = false;
-        break;
+        return NS_ERROR_FAILURE;
       }
 
       // Multiply the offset by 60 and add the last accumulated component
-      offset = offset * 60 + PRInt64(component);
+      offset = offset * 60 + nsSMILTime(component);
 
       component = 0.0;
       ++start;
     } else if (NS_IS_ALPHA(*start)) {
       if (colonCount > 0) {
-        isValid = false;
-        break;
+        return NS_ERROR_FAILURE;
       }
 
       if ((aFlags & kClockValueAllowIndefinite)
           && ConsumeSubstring(start, end, "indefinite")) {
         // We set a separate flag because we don't know what the state of the
         // passed in time value is and we shouldn't change it in the case of a
         // bad input string (so we can't initialise it to 0ms for example).
         isIndefinite = true;
         if (aResult) {
           aResult->SetIndefinite();
         }
       } else if (aIsMedia && ConsumeSubstring(start, end, "media")) {
         *aIsMedia = true;
       } else if (!ParseMetricMultiplicand(start, end, metricMultiplicand)) {
-        isValid = false;
-        break;
+        return NS_ERROR_FAILURE;
       }
 
       // Nothing must come after the string except whitespace
       break;
     } else {
-      isValid = false;
-      break;
+      return NS_ERROR_FAILURE;
     }
   }
 
   if (!started) {
-    isValid = false;
+    return NS_ERROR_FAILURE;
   }
 
   // Process remainder of string (if any) to ensure it is only trailing
   // whitespace (embedded whitespace is not allowed)
   SkipBeginWsp(start, end);
   if (start != end) {
-    isValid = false;
+    return NS_ERROR_FAILURE;
   }
 
   // No more processing required if the value was "indefinite" or "media".
-  if (isIndefinite || (aIsMedia && *aIsMedia))
+  if (isIndefinite || (aIsMedia && *aIsMedia)) {
     return NS_OK;
+  }
 
   // If there is more than one colon then the previous component must be a
   // correctly formatted minute (i.e. two digits between 00 and 59) and the
   // latest component must be a correctly formatted second (i.e. two digits
   // before the .)
   if (colonCount > 0 && (!prevNumCouldBeMin || !numCouldBeSec)) {
-    isValid = false;
+    return NS_ERROR_FAILURE;
   }
 
-  if (isValid) {
-    // Tack on the last component
-    if (colonCount > 0) {
-      offset = offset * 60 * 1000;
-      component *= 1000;
-      // rounding
-      component = (component >= 0) ? component + 0.5 : component - 0.5;
-      offset += PRInt64(component);
-    } else {
-      component *= metricMultiplicand;
-      // rounding
-      component = (component >= 0) ? component + 0.5 : component - 0.5;
-      offset = PRInt64(component);
-    }
-
-    if (aResult) {
-      nsSMILTime millis = offset;
-
-      if (sign == -1) {
-        millis = -offset;
-      }
-
-      aResult->SetMillis(millis);
-    }
+  // Tack on the last component
+  if (colonCount > 0) {
+    offset = offset * 60 * 1000;
+    component *= 1000;
+    // rounding
+    component = (component >= 0) ? component + 0.5 : component - 0.5;
+    offset += nsSMILTime(component);
+  } else {
+    component *= metricMultiplicand;
+    // rounding
+    component = (component >= 0) ? component + 0.5 : component - 0.5;
+    offset = nsSMILTime(component);
   }
 
-  return (isValid) ? NS_OK : NS_ERROR_FAILURE;
+  // we haven't applied the sign yet so if the result is negative we must have
+  // overflowed
+  if (offset < 0) {
+    return NS_ERROR_FAILURE;
+  }
+
+  if (aResult) {
+    if (sign == -1) {
+      offset = -offset;
+    }
+    aResult->SetMillis(offset);
+  }
+
+  return NS_OK;
 }
 
 PRInt32
 nsSMILParserUtils::CheckForNegativeNumber(const nsAString& aStr)
 {
   PRInt32 absValLocation = -1;
 
   nsAString::const_iterator start, end;
--- a/content/smil/nsSMILTimeValueSpec.cpp
+++ b/content/smil/nsSMILTimeValueSpec.cpp
@@ -43,16 +43,17 @@
 #include "nsSMILInstanceTime.h"
 #include "nsSMILParserUtils.h"
 #include "nsISMILAnimationElement.h"
 #include "nsContentUtils.h"
 #include "nsEventListenerManager.h"
 #include "nsGUIEvent.h"
 #include "nsIDOMTimeEvent.h"
 #include "nsString.h"
+#include <limits>
 
 using namespace mozilla::dom;
 
 //----------------------------------------------------------------------
 // Nested class: EventListener
 
 NS_IMPL_ISUPPORTS1(nsSMILTimeValueSpec::EventListener, nsIDOMEventListener)
 
@@ -177,18 +178,19 @@ nsSMILTimeValueSpec::HandleNewInterval(n
                                        const nsSMILTimeContainer* aSrcContainer)
 {
   const nsSMILInstanceTime& baseInstance = mParams.mSyncBegin
     ? *aInterval.Begin() : *aInterval.End();
   nsSMILTimeValue newTime =
     ConvertBetweenTimeContainers(baseInstance.Time(), aSrcContainer);
 
   // Apply offset
-  if (newTime.IsDefinite()) {
-    newTime.SetMillis(newTime.GetMillis() + mParams.mOffset.GetMillis());
+  if (!ApplyOffset(newTime)) {
+    NS_WARNING("New time overflows nsSMILTime, ignoring");
+    return;
   }
 
   // Create the instance time and register it with the interval
   nsRefPtr<nsSMILInstanceTime> newInstance =
     new nsSMILInstanceTime(newTime, nsSMILInstanceTime::SOURCE_SYNCBASE, this,
                            &aInterval);
   mOwner->AddInstanceTime(newInstance, mIsBegin);
 }
@@ -213,19 +215,19 @@ nsSMILTimeValueSpec::HandleChangedInstan
   // time of an active or postactive interval) we just ignore the change.
   if (aInstanceTimeToUpdate.IsFixedTime())
     return;
 
   nsSMILTimeValue updatedTime =
     ConvertBetweenTimeContainers(aBaseTime.Time(), aSrcContainer);
 
   // Apply offset
-  if (updatedTime.IsDefinite()) {
-    updatedTime.SetMillis(updatedTime.GetMillis() +
-                          mParams.mOffset.GetMillis());
+  if (!ApplyOffset(updatedTime)) {
+    NS_WARNING("Updated time overflows nsSMILTime, ignoring");
+    return;
   }
 
   // The timed element that owns the instance time does the updating so it can
   // re-sort its array of instance times more efficiently
   if (aInstanceTimeToUpdate.Time() != updatedTime || aObjectChanged) {
     mOwner->UpdateInstanceTime(&aInstanceTimeToUpdate, updatedTime, mIsBegin);
   }
 }
@@ -334,17 +336,17 @@ nsSMILTimeValueSpec::RegisterEventListen
 
   if (!mEventListener) {
     mEventListener = new EventListener(this);
   }
 
   nsEventListenerManager* elm = GetEventListenerManager(aTarget);
   if (!elm)
     return;
-  
+
   elm->AddEventListenerByType(mEventListener,
                               nsDependentAtomString(mParams.mEventSymbol),
                               NS_EVENT_FLAG_BUBBLE |
                               NS_PRIV_EVENT_UNTRUSTED_PERMITTED |
                               NS_EVENT_FLAG_SYSTEM_EVENT);
 }
 
 void
@@ -402,17 +404,21 @@ nsSMILTimeValueSpec::HandleEvent(nsIDOME
   nsSMILTimeContainer* container = mOwner->GetTimeContainer();
   if (!container)
     return;
 
   if (!CheckEventDetail(aEvent))
     return;
 
   nsSMILTime currentTime = container->GetCurrentTime();
-  nsSMILTimeValue newTime(currentTime + mParams.mOffset.GetMillis());
+  nsSMILTimeValue newTime(currentTime);
+  if (!ApplyOffset(newTime)) {
+    NS_WARNING("New time generated from event overflows nsSMILTime, ignoring");
+    return;
+  }
 
   nsRefPtr<nsSMILInstanceTime> newInstance =
     new nsSMILInstanceTime(newTime, nsSMILInstanceTime::SOURCE_EVENT);
   mOwner->AddInstanceTime(newInstance, mIsBegin);
 }
 
 bool
 nsSMILTimeValueSpec::CheckEventDetail(nsIDOMEvent *aEvent)
@@ -530,8 +536,26 @@ nsSMILTimeValueSpec::ConvertBetweenTimeC
     // time. Just return the indefinite time.
     return docTime;
 
   NS_ABORT_IF_FALSE(docTime.IsDefinite(),
     "ContainerToParentTime gave us an unresolved or indefinite time");
 
   return dstContainer->ParentToContainerTime(docTime.GetMillis());
 }
+
+bool
+nsSMILTimeValueSpec::ApplyOffset(nsSMILTimeValue& aTime) const
+{
+  // indefinite + offset = indefinite. Likewise for unresolved times.
+  if (!aTime.IsDefinite()) {
+    return true;
+  }
+
+  double resultAsDouble =
+    (double)aTime.GetMillis() + mParams.mOffset.GetMillis();
+  if (resultAsDouble > std::numeric_limits<nsSMILTime>::max() ||
+      resultAsDouble < std::numeric_limits<nsSMILTime>::min()) {
+    return false;
+  }
+  aTime.SetMillis(aTime.GetMillis() + mParams.mOffset.GetMillis());
+  return true;
+}
--- a/content/smil/nsSMILTimeValueSpec.h
+++ b/content/smil/nsSMILTimeValueSpec.h
@@ -97,16 +97,17 @@ protected:
   void UnregisterEventListener(Element* aElement);
   nsEventListenerManager* GetEventListenerManager(Element* aElement);
   void HandleEvent(nsIDOMEvent* aEvent);
   bool CheckEventDetail(nsIDOMEvent* aEvent);
   bool CheckRepeatEventDetail(nsIDOMEvent* aEvent);
   bool CheckAccessKeyEventDetail(nsIDOMEvent* aEvent);
   nsSMILTimeValue ConvertBetweenTimeContainers(const nsSMILTimeValue& aSrcTime,
                                       const nsSMILTimeContainer* aSrcContainer);
+  bool ApplyOffset(nsSMILTimeValue& aTime) const;
 
   nsSMILTimedElement*           mOwner;
   bool                          mIsBegin; // Indicates if *we* are a begin spec,
                                           // not to be confused with
                                           // mParams.mSyncBegin which indicates
                                           // if we're synced with the begin of
                                           // the target.
   nsSMILTimeValueSpecParams     mParams;
--- a/content/smil/nsSMILTimedElement.cpp
+++ b/content/smil/nsSMILTimedElement.cpp
@@ -1883,19 +1883,19 @@ nsSMILTimedElement::ApplyMinAndMax(const
 }
 
 nsSMILTime
 nsSMILTimedElement::ActiveTimeToSimpleTime(nsSMILTime aActiveTime,
                                            PRUint32& aRepeatIteration)
 {
   nsSMILTime result;
 
-  NS_ASSERTION(mSimpleDur.IsResolved(),
+  NS_ABORT_IF_FALSE(mSimpleDur.IsResolved(),
       "Unresolved simple duration in ActiveTimeToSimpleTime");
-  NS_ASSERTION(aActiveTime >= 0, "Expecting non-negative active time");
+  NS_ABORT_IF_FALSE(aActiveTime >= 0, "Expecting non-negative active time");
   // Note that a negative aActiveTime will give us a negative value for
   // aRepeatIteration, which is bad because aRepeatIteration is unsigned
 
   if (mSimpleDur.IsIndefinite() || mSimpleDur.GetMillis() == 0L) {
     aRepeatIteration = 0;
     result = aActiveTime;
   } else {
     result = aActiveTime % mSimpleDur.GetMillis();
--- a/content/smil/test/test_smilDynamicDelayedBeginElement.xhtml
+++ b/content/smil/test/test_smilDynamicDelayedBeginElement.xhtml
@@ -23,17 +23,25 @@ https://bugzilla.mozilla.org/show_bug.cg
 /** Test for Bug 699143 **/
 SimpleTest.waitForExplicitFinish();
 
 // Values for 'width' attr on the <rect> above
 const INITIAL_VAL = "500px"
 const FROM_VAL = "20px";
 const TO_VAL   = "80px";
 
-// Helper function
+// Helper functions
+
+// This function allows 10ms to pass
+function allowTimeToPass() {
+  var initialDate = new Date();
+  while (new Date() - initialDate < 10) {}
+}
+
+// This function returns a newly created <animate> element for use in this test
 function createAnim() {
   var a = document.createElementNS('http://www.w3.org/2000/svg', 'animate');
   a.setAttribute('attributeName', 'width');
   a.setAttribute('from', FROM_VAL);
   a.setAttribute('to',   TO_VAL);
   a.setAttribute('begin', 'indefinite');
   a.setAttribute('dur', '3s');
   a.setAttribute('fill', 'freeze');
@@ -45,23 +53,28 @@ function main() {
   if (!SMILUtil.isSMILEnabled()) {
     ok(false, "SMIL dosn't seem to be enabled");
     SimpleTest.finish();
     return;
   }
 
   // In unpatched Firefox builds, we'll only trigger Bug 699143 if we insert
   // an animation and call beginElement() **after** the document start-time.
-  // Hence, we use executeSoon here to allow some time to pass.
+  // Hence, we use executeSoon here to allow some time to pass.  (And then
+  // we'll use a short busy-loop, for good measure.)
   SimpleTest.executeSoon(runTest);
 }
 
 function runTest() {
   var svg = SMILUtil.getSVGRoot();
 
+  // In case our executeSoon fired immediately, we force a very small amount
+  // of time to pass here, using a 10ms busy-loop.
+  allowTimeToPass();
+
   is(svg.getCurrentTime(), 0,
      "even though we've allowed time to pass, we shouldn't have bothered " +
      "updating the current time, since there aren't any animation elements");
 
   // Insert an animation elem (should affect currentTime but not targeted attr)
   var r = document.getElementById("r");
   var a = createAnim();
   r.appendChild(a);
--- a/gfx/layers/basic/BasicLayers.cpp
+++ b/gfx/layers/basic/BasicLayers.cpp
@@ -38,16 +38,18 @@
 
 #include "gfxSharedImageSurface.h"
 
 #include "mozilla/layers/PLayerChild.h"
 #include "mozilla/layers/PLayersChild.h"
 #include "mozilla/layers/PLayersParent.h"
 #include "mozilla/gfx/2D.h"
 
+#include "mozilla/Types.h"
+
 #include "ipc/ShadowLayerChild.h"
 
 #include "BasicLayers.h"
 #include "ImageLayers.h"
 
 #include "nsTArray.h"
 #include "nsGUIEvent.h"
 #include "gfxContext.h"
@@ -2204,27 +2206,27 @@ public:
   virtual void SyncFrontBufferToBackBuffer();
 
 private:
   BasicShadowLayerManager* BasicManager()
   {
     return static_cast<BasicShadowLayerManager*>(mManager);
   }
 
-  NS_OVERRIDE virtual void
+  virtual void
   PaintBuffer(gfxContext* aContext,
               const nsIntRegion& aRegionToDraw,
               const nsIntRegion& aExtendedRegionToDraw,
               const nsIntRegion& aRegionToInvalidate,
               bool aDidSelfCopy,
               LayerManager::DrawThebesLayerCallback aCallback,
-              void* aCallbackData);
-
-  NS_OVERRIDE virtual already_AddRefed<gfxASurface>
-  CreateBuffer(Buffer::ContentType aType, const nsIntSize& aSize);
+              void* aCallbackData) MOZ_OVERRIDE;
+
+  virtual already_AddRefed<gfxASurface>
+  CreateBuffer(Buffer::ContentType aType, const nsIntSize& aSize) MOZ_OVERRIDE;
 
   void DestroyBackBuffer()
   {
     if (IsSurfaceDescriptorValid(mBackBuffer)) {
       BasicManager()->ShadowLayerForwarder::DestroySharedSurface(&mBackBuffer);
     }
   }
 
--- a/gfx/ots/src/layout.cc
+++ b/gfx/ots/src/layout.cc
@@ -142,17 +142,17 @@ bool ParseFeatureTable(const uint8_t *da
   uint16_t offset_feature_params = 0;
   uint16_t lookup_count = 0;
   if (!subtable.ReadU16(&offset_feature_params) ||
       !subtable.ReadU16(&lookup_count)) {
     return OTS_FAILURE();
   }
 
   const unsigned feature_table_end =
-      2 * static_cast<unsigned>(num_lookups) + 4;
+      2 * static_cast<unsigned>(lookup_count) + 4;
   if (feature_table_end > std::numeric_limits<uint16_t>::max()) {
     return OTS_FAILURE();
   }
   // |offset_feature_params| is generally set to NULL.
   if (offset_feature_params != 0 &&
       (offset_feature_params < feature_table_end ||
        offset_feature_params >= length)) {
     return OTS_FAILURE();
--- a/gfx/qcms/transform.c
+++ b/gfx/qcms/transform.c
@@ -1073,17 +1073,18 @@ qcms_transform* qcms_transform_precacheL
 			}
 		}
 	}
 
 
 	//XXX: qcms_modular_transform_data may return either the src or dest buffer. If so it must not be free-ed
 	if (src && lut != src) {
 		free(src);
-	} else if (dest && lut != src) {
+	}
+	if (dest && lut != dest) {
 		free(dest);
 	}
 
 	if (lut == NULL) {
 		return NULL;
 	}
 	return transform;
 }
--- a/image/test/mochitest/animationPolling.js
+++ b/image/test/mochitest/animationPolling.js
@@ -1,41 +1,36 @@
 var currentTest;
-var gIsImageLoaded = false;
 var gIsRefImageLoaded = false;
 
 function pollForSuccess ()
 {
   if (!currentTest.isTestFinished) {
     if (!currentTest.reusingReferenceImage || (currentTest.reusingReferenceImage
         && gRefImageLoaded)) {
       currentTest.checkImage();
     }
 
     setTimeout(pollForSuccess, currentTest.pollFreq);
   }
 };
 
-function imageLoadCallback()
-{
-  gIsImageLoaded = true;
-}
-
 function referencePoller()
 {
   currentTest.takeReferenceSnapshot();
 }
 
 function reuseImageCallback()
 {
   gIsRefImageLoaded = true;
 }
 
 function failTest ()
-{
+{    imageLoadCallback();
+
   if (currentTest.isTestFinished || currentTest.closeFunc) {
     return;
   }
 
   ok(false, "timing out after " + currentTest.timeout + "ms.  "
      + "Animated image still doesn't look correct, after poll #"
      + currentTest.pollCounter);
   currentTest.wereFailures = true;
@@ -105,25 +100,28 @@ function AnimationTest(pollFreq, timeout
   this.pollCounter = 0;
   this.isTestFinished = false;
   this.numRefsTaken = 0;
   this.blankWaitTime = 0;
 
   this.cleanId = cleanId ? cleanId : '';
   this.xulTest = xulTest ? xulTest : '';
   this.closeFunc = closeFunc ? closeFunc : '';
+};
 
+AnimationTest.prototype.preloadImage = function()
+{
   if (this.srcAttr) {
     this.myImage = new Image();
-    this.myImage.onload = imageLoadCallback;
+    this.myImage.onload = function() { currentTest.continueTest(); };
     this.myImage.src = this.srcAttr;
   } else {
-    gIsImageLoaded = true;
+    this.continueTest();
   }
-}
+};
 
 AnimationTest.prototype.outputDebugInfo = function(message, id, dataUri)
 {
   var debugElement = document.getElementById(this.debugElementId);
   var newDataUriElement = document.createElement("a");
   newDataUriElement.setAttribute("id", id);
   newDataUriElement.setAttribute("href", dataUri);
   newDataUriElement.appendChild(document.createTextNode(message));
@@ -171,34 +169,44 @@ AnimationTest.prototype.takeBlankSnapsho
   var dataString1 = "Initial Blank Snapshot";
   this.outputDebugInfo(dataString1, 'blank1Snap',
                        this.blankSnapshot.toDataURL());
 };
 
 /**
  * Begin the AnimationTest. This will utilize the information provided in the
  * constructor to invoke a mochitest on animated images. It will automatically
- * fail if allowed to run past the timeout.
+ * fail if allowed to run past the timeout. This will attempt to preload an
+ * image, if applicable, and then asynchronously call continueTest(), or if not
+ * applicable, synchronously trigger a call to continueTest().
  */
-AnimationTest.prototype.beginTest = function ()
+AnimationTest.prototype.beginTest = function()
 {
   SimpleTest.waitForExplicitFinish();
 
   currentTest = this;
+  this.preloadImage();
+};
 
-  this.takeReferenceSnapshot();
-
+/**
+ * This is the second part of the test. It is triggered (eventually) from
+ * beginTest() either synchronously or asynchronously, as an image load
+ * callback.
+ */
+AnimationTest.prototype.continueTest = function()
+{
   // In case something goes wrong, fail earlier than mochitest timeout,
   // and with more information.
   setTimeout(failTest, this.timeout);
 
   if (!this.reusingImageAsReference) {
     this.disableDisplay(document.getElementById(this.imageElementId));
   }
 
+  this.takeReferenceSnapshot();
   this.setupPolledImage();
   setTimeout(pollForSuccess, 10);
 };
 
 AnimationTest.prototype.setupPolledImage = function ()
 {
   // Make sure the image is visible
   if (!this.reusingImageAsReference) {
@@ -268,16 +276,17 @@ AnimationTest.prototype.takeReferenceSna
   }
 
   if (this.reusingImageAsReference) {
     // Show reference div, & take a snapshot
     var referenceDiv = document.getElementById(this.imageElementId);
     this.enableDisplay(referenceDiv);
 
     this.referenceSnapshot = snapshotWindow(window, false);
+
     var snapResult = compareSnapshots(this.cleanSnapshot, this.referenceSnapshot,
                                       false);
     if (!snapResult[0]) {
       if (this.blankWaitTime > 2000) {
         // if it took longer than two seconds to load the image, we probably
         // have a problem.
         this.wereFailures = true;
         ok(snapResult[0],
--- a/image/test/mochitest/test_svg_animatedGIF.html
+++ b/image/test/mochitest/test_svg_animatedGIF.html
@@ -35,17 +35,17 @@ https://bugzilla.mozilla.org/show_bug.cg
 <script type="text/javascript;version=1.8">
 
 /** Test for Bug 666446 nsSVGImageFrame/RasterImage**/
 
 const FAILURE_TIMEOUT = 120000; // Fail early after 120 seconds (2 minutes)
 
 function main() {
   var animTest = new AnimationTest(20, FAILURE_TIMEOUT, 'referenceDiv',
-      							   'embeddedSVG', 'debug', '', 'src');
+                                   'embeddedSVG', 'debug', '');
   animTest.beginTest();
 }
 
 window.onload = main;
 
 </script>
 </pre>
 </body>
--- a/image/test/mochitest/test_svg_filter_animation.html
+++ b/image/test/mochitest/test_svg_filter_animation.html
@@ -25,17 +25,17 @@ Mozilla Bug 666446: lots of animated gif
 <script type="text/javascript;version=1.8">
 
 /** Test for Bug 666446 nsSVGFEImageElement/RasterImage**/
 
 const FAILURE_TIMEOUT = 120000; // Fail early after 120 seconds (2 minutes)
 
 function main() {
   var animTest = new AnimationTest(20, FAILURE_TIMEOUT, 'referenceImage',
-                       'embeddedSVGFilt', 'debug', '', 'src');
+                                   'embeddedSVGFilt', 'debug', '');
   animTest.beginTest();
 }
 
 window.onload = main;
 
 </script>
 </pre>
 </body>
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -718,16 +718,18 @@ JSRuntime::JSRuntime()
 #endif
     thousandsSeparator(0),
     decimalSeparator(0),
     numGrouping(0),
     anynameObject(NULL),
     functionNamespaceObject(NULL),
 #ifdef JS_THREADSAFE
     interruptCounter(0),
+#else
+    threadData(thisFromCtor()),
 #endif
     trustedPrincipals_(NULL),
     shapeGen(0),
     wrapObjectCallback(NULL),
     preWrapObjectCallback(NULL),
     inOOMReport(0)
 {
     /* Initialize infallibly first, so we can goto bad and JS_DestroyRuntime. */
--- a/js/src/jscntxt.cpp
+++ b/js/src/jscntxt.cpp
@@ -82,69 +82,78 @@
 #include "jsstr.h"
 #include "jstracer.h"
 
 #ifdef JS_METHODJIT
 # include "assembler/assembler/MacroAssembler.h"
 #endif
 #include "frontend/TokenStream.h"
 #include "frontend/ParseMaps.h"
+#include "yarr/BumpPointerAllocator.h"
 
 #include "jsatominlines.h"
 #include "jscntxtinlines.h"
 #include "jscompartment.h"
 #include "jsobjinlines.h"
 
 using namespace js;
 using namespace js::gc;
 
 namespace js {
 
-ThreadData::ThreadData()
-  : interruptFlags(0),
+ThreadData::ThreadData(JSRuntime *rt)
+  : rt(rt),
+    interruptFlags(0),
 #ifdef JS_THREADSAFE
     requestDepth(0),
 #endif
 #ifdef JS_TRACER
     onTraceCompartment(NULL),
     recordingCompartment(NULL),
     profilingCompartment(NULL),
     maxCodeCacheBytes(DEFAULT_JIT_CACHE_SIZE),
 #endif
     waiveGCQuota(false),
     tempLifoAlloc(TEMP_LIFO_ALLOC_PRIMARY_CHUNK_SIZE),
+    execAlloc(NULL),
+    bumpAlloc(NULL),
     repCache(NULL),
     dtoaState(NULL),
     nativeStackBase(GetNativeStackBase()),
     pendingProxyOperation(NULL),
     interpreterFrames(NULL)
 {
 #ifdef DEBUG
     noGCOrAllocationCheck = 0;
 #endif
 }
 
 ThreadData::~ThreadData()
 {
     JS_ASSERT(!repCache);
 
+    rt->delete_<JSC::ExecutableAllocator>(execAlloc);
+    rt->delete_<WTF::BumpPointerAllocator>(bumpAlloc);
+
     if (dtoaState)
         js_DestroyDtoaState(dtoaState);
 }
 
 bool
 ThreadData::init()
 {
     JS_ASSERT(!repCache);
     return stackSpace.init() && !!(dtoaState = js_NewDtoaState());
 }
 
 void
 ThreadData::triggerOperationCallback(JSRuntime *rt)
 {
+    JS_ASSERT(rt == this->rt);
+
     /*
      * Use JS_ATOMIC_SET and JS_ATOMIC_INCREMENT in the hope that it ensures
      * the write will become immediately visible to other processors polling
      * the flag.  Note that we only care about visibility here, not read/write
      * ordering: this field can only be written with the GC lock held.
      */
     if (interruptFlags)
         return;
@@ -152,33 +161,60 @@ ThreadData::triggerOperationCallback(JSR
 
 #ifdef JS_THREADSAFE
     /* rt->interruptCounter does not reflect suspended threads. */
     if (requestDepth != 0)
         JS_ATOMIC_INCREMENT(&rt->interruptCounter);
 #endif
 }
 
+JSC::ExecutableAllocator *
+ThreadData::createExecutableAllocator(JSContext *cx)
+{
+    JS_ASSERT(!execAlloc);
+    JS_ASSERT(cx->runtime == rt);
+
+    execAlloc = rt->new_<JSC::ExecutableAllocator>();
+    if (!execAlloc)
+        js_ReportOutOfMemory(cx);
+    return execAlloc;
+}
+
+WTF::BumpPointerAllocator *
+ThreadData::createBumpPointerAllocator(JSContext *cx)
+{
+    JS_ASSERT(!bumpAlloc);
+    JS_ASSERT(cx->runtime == rt);
+
+    bumpAlloc = rt->new_<WTF::BumpPointerAllocator>();
+    if (!bumpAlloc)
+        js_ReportOutOfMemory(cx);
+    return bumpAlloc;
+}
+
 RegExpPrivateCache *
-ThreadData::createRegExpPrivateCache(JSRuntime *rt)
+ThreadData::createRegExpPrivateCache(JSContext *cx)
 {
     JS_ASSERT(!repCache);
+    JS_ASSERT(cx->runtime == rt);
+
     RegExpPrivateCache *newCache = rt->new_<RegExpPrivateCache>(rt);
 
     if (!newCache || !newCache->init()) {
+        js_ReportOutOfMemory(cx);
         rt->delete_<RegExpPrivateCache>(newCache);
         return NULL;
     }
 
     repCache = newCache;
     return repCache;
 }
 
 void
-ThreadData::purgeRegExpPrivateCache(JSRuntime *rt)
+ThreadData::purgeRegExpPrivateCache()
 {
     rt->delete_<RegExpPrivateCache>(repCache);
     repCache = NULL;
 }
 
 } /* namespace js */
 
 JSScript *
@@ -218,17 +254,17 @@ js_CurrentThreadAndLockGC(JSRuntime *rt)
          * If thread has no contexts, it might be left over from a previous
          * thread with the same id but a different stack address.
          */
         if (JS_CLIST_IS_EMPTY(&thread->contextList))
             thread->data.nativeStackBase = GetNativeStackBase();
     } else {
         JS_UNLOCK_GC(rt);
 
-        thread = OffTheBooks::new_<JSThread>(id);
+        thread = OffTheBooks::new_<JSThread>(rt, id);
         if (!thread || !thread->init()) {
             Foreground::delete_(thread);
             return NULL;
         }
         JS_LOCK_GC(rt);
         js_WaitForGC(rt);
         if (!rt->threads.relookupOrAdd(p, id, thread)) {
             JS_UNLOCK_GC(rt);
@@ -347,20 +383,20 @@ js_PurgeThreads_PostGlobalSweep(JSContex
 #ifdef JS_THREADSAFE
     for (JSThread::Map::Enum e(cx->runtime->threads);
          !e.empty();
          e.popFront())
     {
         JSThread *thread = e.front().value;
 
         JS_ASSERT(!JS_CLIST_IS_EMPTY(&thread->contextList));
-        thread->data.purgeRegExpPrivateCache(cx->runtime);
+        thread->data.purgeRegExpPrivateCache();
     }
 #else
-    cx->runtime->threadData.purgeRegExpPrivateCache(cx->runtime);
+    cx->runtime->threadData.purgeRegExpPrivateCache();
 #endif
 }
 
 JSContext *
 js_NewContext(JSRuntime *rt, size_t stackChunkSize)
 {
     JS_AbortIfWrongThread(rt);
 
--- a/js/src/jscntxt.h
+++ b/js/src/jscntxt.h
@@ -148,16 +148,18 @@ inline GSNCache *
 GetGSNCache(JSContext *cx);
 
 struct PendingProxyOperation {
     PendingProxyOperation   *next;
     JSObject                *object;
 };
 
 struct ThreadData {
+    JSRuntime           *rt;
+
     /*
      * If non-zero, we were been asked to call the operation callback as soon
      * as possible.  If the thread has an active request, this contributes
      * towards rt->interruptCounter.
      */
     volatile int32      interruptFlags;
 
 #ifdef JS_THREADSAFE
@@ -193,33 +195,55 @@ struct ThreadData {
      */
     bool                waiveGCQuota;
 
     /* Temporary arena pool used while compiling and decompiling. */
     static const size_t TEMP_LIFO_ALLOC_PRIMARY_CHUNK_SIZE = 1 << 12;
     LifoAlloc           tempLifoAlloc;
 
   private:
-    js::RegExpPrivateCache       *repCache;
-
-    js::RegExpPrivateCache *createRegExpPrivateCache(JSRuntime *rt);
+    /*
+     * Both of these allocators are used for regular expression code which is shared at the
+     * thread-data level.
+     */
+    JSC::ExecutableAllocator    *execAlloc;
+    WTF::BumpPointerAllocator   *bumpAlloc;
+    js::RegExpPrivateCache      *repCache;
+
+    JSC::ExecutableAllocator *createExecutableAllocator(JSContext *cx);
+    WTF::BumpPointerAllocator *createBumpPointerAllocator(JSContext *cx);
+    js::RegExpPrivateCache *createRegExpPrivateCache(JSContext *cx);
 
   public:
-    js::RegExpPrivateCache *getRegExpPrivateCache() { return repCache; }
-
-    /* N.B. caller is responsible for reporting OOM. */
-    js::RegExpPrivateCache *getOrCreateRegExpPrivateCache(JSRuntime *rt) {
+    JSC::ExecutableAllocator *getOrCreateExecutableAllocator(JSContext *cx) {
+        if (execAlloc)
+            return execAlloc;
+
+        return createExecutableAllocator(cx);
+    }
+
+    WTF::BumpPointerAllocator *getOrCreateBumpPointerAllocator(JSContext *cx) {
+        if (bumpAlloc)
+            return bumpAlloc;
+
+        return createBumpPointerAllocator(cx);
+    }
+
+    js::RegExpPrivateCache *getRegExpPrivateCache() {
+        return repCache;
+    }
+    js::RegExpPrivateCache *getOrCreateRegExpPrivateCache(JSContext *cx) {
         if (repCache)
             return repCache;
 
-        return createRegExpPrivateCache(rt);
+        return createRegExpPrivateCache(cx);
     }
 
     /* Called at the end of the global GC sweep phase to deallocate repCache memory. */
-    void purgeRegExpPrivateCache(JSRuntime *rt);
+    void purgeRegExpPrivateCache();
 
     /*
      * The GSN cache is per thread since even multi-cx-per-thread embeddings
      * do not interleave js_GetSrcNote calls.
      */
     GSNCache            gsnCache;
 
     /* Property cache for faster call/get/set invocation. */
@@ -235,17 +259,17 @@ struct ThreadData {
     PendingProxyOperation *pendingProxyOperation;
 
     ConservativeGCThreadData conservativeGC;
 
 #ifdef DEBUG
     size_t              noGCOrAllocationCheck;
 #endif
 
-    ThreadData();
+    ThreadData(JSRuntime *rt);
     ~ThreadData();
 
     bool init();
 
     void mark(JSTracer *trc) {
         stackSpace.mark(trc);
     }
 
@@ -292,22 +316,23 @@ struct JSThread {
 
 # ifdef DEBUG
     unsigned            checkRequestDepth;
 # endif
 
     /* Factored out of JSThread for !JS_THREADSAFE embedding in JSRuntime. */
     js::ThreadData      data;
 
-    JSThread(void *id)
+    JSThread(JSRuntime *rt, void *id)
       : id(id),
-        suspendCount(0)
+        suspendCount(0),
 # ifdef DEBUG
-      , checkRequestDepth(0)
+        checkRequestDepth(0),
 # endif
+        data(rt)
     {
         JS_INIT_CLIST(&contextList);
     }
 
     ~JSThread() {
         /* The thread must have zero contexts. */
         JS_ASSERT(JS_CLIST_IS_EMPTY(&contextList));
     }
--- a/js/src/jscompartment.cpp
+++ b/js/src/jscompartment.cpp
@@ -83,19 +83,16 @@ JSCompartment::JSCompartment(JSRuntime *
     traceMonitor_(NULL),
 #endif
     data(NULL),
     active(false),
     hasDebugModeCodeToDrop(false),
 #ifdef JS_METHODJIT
     jaegerCompartment_(NULL),
 #endif
-#if ENABLE_YARR_JIT
-    regExpAllocator(NULL),
-#endif
     propertyTree(thisForCtor()),
     emptyArgumentsShape(NULL),
     emptyBlockShape(NULL),
     emptyCallShape(NULL),
     emptyDeclEnvShape(NULL),
     emptyEnumeratorShape(NULL),
     emptyWithShape(NULL),
     initialRegExpShape(NULL),
@@ -105,20 +102,16 @@ JSCompartment::JSCompartment(JSRuntime *
     breakpointSites(rt),
     watchpointMap(NULL)
 {
     PodArrayZero(evalCache);
 }
 
 JSCompartment::~JSCompartment()
 {
-#if ENABLE_YARR_JIT
-    Foreground::delete_(regExpAllocator);
-#endif
-
 #ifdef JS_METHODJIT
     Foreground::delete_(jaegerCompartment_);
 #endif
 
 #ifdef JS_TRACER
     Foreground::delete_(traceMonitor_);
 #endif
 
@@ -138,20 +131,16 @@ JSCompartment::init(JSContext *cx)
     types.init(cx);
 
     if (!crossCompartmentWrappers.init())
         return false;
 
     if (!scriptFilenameTable.init())
         return false;
 
-    regExpAllocator = rt->new_<WTF::BumpPointerAllocator>();
-    if (!regExpAllocator)
-        return false;
-
     if (!backEdgeTable.init())
         return false;
 
     return debuggees.init() && breakpointSites.init();
 }
 
 #ifdef JS_METHODJIT
 bool
--- a/js/src/jscompartment.h
+++ b/js/src/jscompartment.h
@@ -48,19 +48,16 @@
 #include "jsobj.h"
 #include "vm/GlobalObject.h"
 
 #ifdef _MSC_VER
 #pragma warning(push)
 #pragma warning(disable:4251) /* Silence warning about JS_FRIEND_API and data members. */
 #endif
 
-namespace JSC { class ExecutableAllocator; }
-namespace WTF { class BumpPointerAllocator; }
-
 namespace js {
 
 /* Holds the number of recording attemps for an address. */
 typedef HashMap<jsbytecode*,
                 size_t,
                 DefaultHasher<jsbytecode*>,
                 SystemAllocPolicy> RecordAttemptMap;
 
@@ -468,17 +465,16 @@ struct JS_FRIEND_API(JSCompartment) {
         JS_ASSERT(jaegerCompartment_);
         return jaegerCompartment_;
     }
 
     bool ensureJaegerCompartmentExists(JSContext *cx);
 
     void getMjitCodeStats(size_t& method, size_t& regexp, size_t& unused) const;
 #endif
-    WTF::BumpPointerAllocator    *regExpAllocator;
 
     /*
      * Shared scope property tree, and arena-pool for allocating its nodes.
      */
     js::PropertyTree             propertyTree;
 
 #ifdef DEBUG
     /* Property metering. */
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -2395,46 +2395,42 @@ ReleaseObservedTypes(JSContext *cx)
 
 static void
 DecommitFreePages(JSContext *cx)
 {
     JSRuntime *rt = cx->runtime;
 
     for (GCChunkSet::Range r(rt->gcChunkSet.all()); !r.empty(); r.popFront()) {
         Chunk *chunk = r.front();
-        while (chunk) {
-            ArenaHeader *aheader = static_cast<ArenaHeader*>(chunk->info.freeArenasHead);
-
-            /*
-             * In the non-failure case, the list will be gone at the end of
-             * the loop. In the case where we fail, we relink all failed
-             * decommits into a new list on freeArenasHead.
-             */
-            chunk->info.freeArenasHead = NULL;
-
-            while (aheader) {
-                /* Store aside everything we will need after decommit. */
-                ArenaHeader *next = aheader->next;
-
-                bool success = DecommitMemory(aheader, ArenaSize);
-                if (!success) {
-                    aheader->next = chunk->info.freeArenasHead;
-                    chunk->info.freeArenasHead = aheader;
-                    continue;
-                }
-
-                size_t arenaOffset = Chunk::arenaIndex(reinterpret_cast<uintptr_t>(aheader));
-                chunk->decommittedArenas.set(arenaOffset);
-                --chunk->info.numArenasFreeCommitted;
-                --rt->gcNumFreeArenas;
-
-                aheader = next;
+        ArenaHeader *aheader = chunk->info.freeArenasHead;
+
+        /*
+         * In the non-failure case, the list will be gone at the end of
+         * the loop. In the case where we fail, we relink all failed
+         * decommits into a new list on freeArenasHead.
+         */
+        chunk->info.freeArenasHead = NULL;
+
+        while (aheader) {
+            /* Store aside everything we will need after decommit. */
+            ArenaHeader *next = aheader->next;
+
+            bool success = DecommitMemory(aheader, ArenaSize);
+            if (!success) {
+                aheader->next = chunk->info.freeArenasHead;
+                chunk->info.freeArenasHead = aheader;
+                continue;
             }
 
-            chunk = chunk->info.next;
+            size_t arenaIndex = Chunk::arenaIndex(aheader->arenaAddress());
+            chunk->decommittedArenas.set(arenaIndex);
+            --chunk->info.numArenasFreeCommitted;
+            --rt->gcNumFreeArenas;
+
+            aheader = next;
         }
     }
 }
 
 static void
 SweepCompartments(JSContext *cx, JSGCInvocationKind gckind)
 {
     JSRuntime *rt = cx->runtime;
--- a/js/src/jsprvtd.h
+++ b/js/src/jsprvtd.h
@@ -264,16 +264,28 @@ class TypeSet;
 struct TypeCallsite;
 struct TypeObject;
 struct TypeCompartment;
 
 } /* namespace types */
 
 } /* namespace js */
 
+namespace JSC {
+
+class ExecutableAllocator;
+
+} /* namespace JSC */
+
+namespace WTF {
+
+class BumpPointerAllocator;
+
+} /* namespace WTF */
+
 } /* export "C++" */
 
 #else
 
 typedef struct JSAtom JSAtom;
 
 #endif  /* __cplusplus */
 
--- a/js/src/jswrapper.h
+++ b/js/src/jswrapper.h
@@ -37,16 +37,18 @@
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef jswrapper_h___
 #define jswrapper_h___
 
+#include "mozilla/Types.h"
+
 #include "jsapi.h"
 #include "jsproxy.h"
 
 namespace js {
 
 /* No-op wrapper handler base class. */
 class JS_FRIEND_API(Wrapper) : public ProxyHandler
 {
@@ -57,47 +59,47 @@ class JS_FRIEND_API(Wrapper) : public Pr
     explicit Wrapper(uintN flags);
 
     typedef enum { PermitObjectAccess, PermitPropertyAccess, DenyAccess } Permission;
 
     virtual ~Wrapper();
 
     /* ES5 Harmony fundamental wrapper traps. */
     virtual bool getPropertyDescriptor(JSContext *cx, JSObject *wrapper, jsid id, bool set,
-                                       PropertyDescriptor *desc);
+                                       PropertyDescriptor *desc) MOZ_OVERRIDE;
     virtual bool getOwnPropertyDescriptor(JSContext *cx, JSObject *wrapper, jsid id, bool set,
-                                          PropertyDescriptor *desc);
+                                          PropertyDescriptor *desc) MOZ_OVERRIDE;
     virtual bool defineProperty(JSContext *cx, JSObject *wrapper, jsid id,
-                                PropertyDescriptor *desc);
-    virtual bool getOwnPropertyNames(JSContext *cx, JSObject *wrapper, AutoIdVector &props);
-    virtual bool delete_(JSContext *cx, JSObject *wrapper, jsid id, bool *bp);
-    virtual bool enumerate(JSContext *cx, JSObject *wrapper, AutoIdVector &props);
-    virtual bool fix(JSContext *cx, JSObject *wrapper, Value *vp);
+                                PropertyDescriptor *desc) MOZ_OVERRIDE;
+    virtual bool getOwnPropertyNames(JSContext *cx, JSObject *wrapper, AutoIdVector &props) MOZ_OVERRIDE;
+    virtual bool delete_(JSContext *cx, JSObject *wrapper, jsid id, bool *bp) MOZ_OVERRIDE;
+    virtual bool enumerate(JSContext *cx, JSObject *wrapper, AutoIdVector &props) MOZ_OVERRIDE;
+    virtual bool fix(JSContext *cx, JSObject *wrapper, Value *vp) MOZ_OVERRIDE;
 
     /* ES5 Harmony derived wrapper traps. */
-    virtual bool has(JSContext *cx, JSObject *wrapper, jsid id, bool *bp);
-    virtual bool hasOwn(JSContext *cx, JSObject *wrapper, jsid id, bool *bp);
-    virtual bool get(JSContext *cx, JSObject *wrapper, JSObject *receiver, jsid id, Value *vp);
+    virtual bool has(JSContext *cx, JSObject *wrapper, jsid id, bool *bp) MOZ_OVERRIDE;
+    virtual bool hasOwn(JSContext *cx, JSObject *wrapper, jsid id, bool *bp) MOZ_OVERRIDE;
+    virtual bool get(JSContext *cx, JSObject *wrapper, JSObject *receiver, jsid id, Value *vp) MOZ_OVERRIDE;
     virtual bool set(JSContext *cx, JSObject *wrapper, JSObject *receiver, jsid id, bool strict,
-                     Value *vp);
-    virtual bool keys(JSContext *cx, JSObject *wrapper, AutoIdVector &props);
-    virtual bool iterate(JSContext *cx, JSObject *wrapper, uintN flags, Value *vp);
+                     Value *vp) MOZ_OVERRIDE;
+    virtual bool keys(JSContext *cx, JSObject *wrapper, AutoIdVector &props) MOZ_OVERRIDE;
+    virtual bool iterate(JSContext *cx, JSObject *wrapper, uintN flags, Value *vp) MOZ_OVERRIDE;
 
     /* Spidermonkey extensions. */
-    virtual bool call(JSContext *cx, JSObject *wrapper, uintN argc, Value *vp);
-    virtual bool construct(JSContext *cx, JSObject *wrapper, uintN argc, Value *argv, Value *rval);
-    virtual bool nativeCall(JSContext *cx, JSObject *wrapper, Class *clasp, Native native, CallArgs args);
-    virtual bool hasInstance(JSContext *cx, JSObject *wrapper, const Value *vp, bool *bp);
-    virtual JSType typeOf(JSContext *cx, JSObject *proxy);
-    virtual bool objectClassIs(JSObject *obj, ESClassValue classValue, JSContext *cx);
-    virtual JSString *obj_toString(JSContext *cx, JSObject *wrapper);
-    virtual JSString *fun_toString(JSContext *cx, JSObject *wrapper, uintN indent);
-    virtual bool defaultValue(JSContext *cx, JSObject *wrapper, JSType hint, Value *vp);
+    virtual bool call(JSContext *cx, JSObject *wrapper, uintN argc, Value *vp) MOZ_OVERRIDE;
+    virtual bool construct(JSContext *cx, JSObject *wrapper, uintN argc, Value *argv, Value *rval) MOZ_OVERRIDE;
+    virtual bool nativeCall(JSContext *cx, JSObject *wrapper, Class *clasp, Native native, CallArgs args) MOZ_OVERRIDE;
+    virtual bool hasInstance(JSContext *cx, JSObject *wrapper, const Value *vp, bool *bp) MOZ_OVERRIDE;
+    virtual JSType typeOf(JSContext *cx, JSObject *proxy) MOZ_OVERRIDE;
+    virtual bool objectClassIs(JSObject *obj, ESClassValue classValue, JSContext *cx) MOZ_OVERRIDE;
+    virtual JSString *obj_toString(JSContext *cx, JSObject *wrapper) MOZ_OVERRIDE;
+    virtual JSString *fun_toString(JSContext *cx, JSObject *wrapper, uintN indent) MOZ_OVERRIDE;
+    virtual bool defaultValue(JSContext *cx, JSObject *wrapper, JSType hint, Value *vp) MOZ_OVERRIDE;
 
-    virtual void trace(JSTracer *trc, JSObject *wrapper);
+    virtual void trace(JSTracer *trc, JSObject *wrapper) MOZ_OVERRIDE;
 
     /* Policy enforcement traps. */
     enum Action { GET, SET, CALL };
     virtual bool enter(JSContext *cx, JSObject *wrapper, jsid id, Action act, bool *bp);
     virtual void leave(JSContext *cx, JSObject *wrapper);
 
     static Wrapper singleton;
 
@@ -120,44 +122,44 @@ class JS_FRIEND_API(CrossCompartmentWrap
 {
   public:
     CrossCompartmentWrapper(uintN flags);
 
     virtual ~CrossCompartmentWrapper();
 
     /* ES5 Harmony fundamental wrapper traps. */
     virtual bool getPropertyDescriptor(JSContext *cx, JSObject *wrapper, jsid id, bool set,
-                                       PropertyDescriptor *desc);
+                                       PropertyDescriptor *desc) MOZ_OVERRIDE;
     virtual bool getOwnPropertyDescriptor(JSContext *cx, JSObject *wrapper, jsid id, bool set,
-                                          PropertyDescriptor *desc);
+                                          PropertyDescriptor *desc) MOZ_OVERRIDE;
     virtual bool defineProperty(JSContext *cx, JSObject *wrapper, jsid id,
-                                PropertyDescriptor *desc);
-    virtual bool getOwnPropertyNames(JSContext *cx, JSObject *wrapper, AutoIdVector &props);
-    virtual bool delete_(JSContext *cx, JSObject *wrapper, jsid id, bool *bp);
-    virtual bool enumerate(JSContext *cx, JSObject *wrapper, AutoIdVector &props);
+                                PropertyDescriptor *desc) MOZ_OVERRIDE;
+    virtual bool getOwnPropertyNames(JSContext *cx, JSObject *wrapper, AutoIdVector &props) MOZ_OVERRIDE;
+    virtual bool delete_(JSContext *cx, JSObject *wrapper, jsid id, bool *bp) MOZ_OVERRIDE;
+    virtual bool enumerate(JSContext *cx, JSObject *wrapper, AutoIdVector &props) MOZ_OVERRIDE;
 
     /* ES5 Harmony derived wrapper traps. */
-    virtual bool has(JSContext *cx, JSObject *wrapper, jsid id, bool *bp);
-    virtual bool hasOwn(JSContext *cx, JSObject *wrapper, jsid id, bool *bp);
-    virtual bool get(JSContext *cx, JSObject *wrapper, JSObject *receiver, jsid id, Value *vp);
+    virtual bool has(JSContext *cx, JSObject *wrapper, jsid id, bool *bp) MOZ_OVERRIDE;
+    virtual bool hasOwn(JSContext *cx, JSObject *wrapper, jsid id, bool *bp) MOZ_OVERRIDE;
+    virtual bool get(JSContext *cx, JSObject *wrapper, JSObject *receiver, jsid id, Value *vp) MOZ_OVERRIDE;
     virtual bool set(JSContext *cx, JSObject *wrapper, JSObject *receiver, jsid id, bool strict,
-                     Value *vp);
-    virtual bool keys(JSContext *cx, JSObject *wrapper, AutoIdVector &props);
-    virtual bool iterate(JSContext *cx, JSObject *wrapper, uintN flags, Value *vp);
+                     Value *vp) MOZ_OVERRIDE;
+    virtual bool keys(JSContext *cx, JSObject *wrapper, AutoIdVector &props) MOZ_OVERRIDE;
+    virtual bool iterate(JSContext *cx, JSObject *wrapper, uintN flags, Value *vp) MOZ_OVERRIDE;
 
     /* Spidermonkey extensions. */
-    virtual bool call(JSContext *cx, JSObject *wrapper, uintN argc, Value *vp);
-    virtual bool construct(JSContext *cx, JSObject *wrapper, uintN argc, Value *argv, Value *rval);
-    virtual bool nativeCall(JSContext *cx, JSObject *wrapper, Class *clasp, Native native, CallArgs args);
-    virtual bool hasInstance(JSContext *cx, JSObject *wrapper, const Value *vp, bool *bp);
-    virtual JSString *obj_toString(JSContext *cx, JSObject *wrapper);
-    virtual JSString *fun_toString(JSContext *cx, JSObject *wrapper, uintN indent);
-    virtual bool defaultValue(JSContext *cx, JSObject *wrapper, JSType hint, Value *vp);
+    virtual bool call(JSContext *cx, JSObject *wrapper, uintN argc, Value *vp) MOZ_OVERRIDE;
+    virtual bool construct(JSContext *cx, JSObject *wrapper, uintN argc, Value *argv, Value *rval) MOZ_OVERRIDE;
+    virtual bool nativeCall(JSContext *cx, JSObject *wrapper, Class *clasp, Native native, CallArgs args) MOZ_OVERRIDE;
+    virtual bool hasInstance(JSContext *cx, JSObject *wrapper, const Value *vp, bool *bp) MOZ_OVERRIDE;
+    virtual JSString *obj_toString(JSContext *cx, JSObject *wrapper) MOZ_OVERRIDE;
+    virtual JSString *fun_toString(JSContext *cx, JSObject *wrapper, uintN indent) MOZ_OVERRIDE;
+    virtual bool defaultValue(JSContext *cx, JSObject *wrapper, JSType hint, Value *vp) MOZ_OVERRIDE;
 
-    virtual void trace(JSTracer *trc, JSObject *wrapper);
+    virtual void trace(JSTracer *trc, JSObject *wrapper) MOZ_OVERRIDE;
 
     static CrossCompartmentWrapper singleton;
 };
 
 /*
  * Base class for security wrappers. A security wrapper is potentially hiding
  * all or part of some wrapped object thus SecurityWrapper defaults to denying
  * access to the wrappee. This is the opposite of Wrapper which tries to be
@@ -167,18 +169,18 @@ class JS_FRIEND_API(CrossCompartmentWrap
  * access, relying on derived SecurityWrapper to block access when necessary.
  */
 template <class Base>
 class JS_FRIEND_API(SecurityWrapper) : public Base
 {
   public:
     SecurityWrapper(uintN flags);
 
-    virtual bool nativeCall(JSContext *cx, JSObject *wrapper, Class *clasp, Native native, CallArgs args);
-    virtual bool objectClassIs(JSObject *obj, ESClassValue classValue, JSContext *cx);
+    virtual bool nativeCall(JSContext *cx, JSObject *wrapper, Class *clasp, Native native, CallArgs args) MOZ_OVERRIDE;
+    virtual bool objectClassIs(JSObject *obj, ESClassValue classValue, JSContext *cx) MOZ_OVERRIDE;
 };
 
 typedef SecurityWrapper<Wrapper> SameCompartmentSecurityWrapper;
 typedef SecurityWrapper<CrossCompartmentWrapper> CrossCompartmentSecurityWrapper;
 
 /*
  * A hacky class that lets a friend force a fake frame. We must already be
  * in the compartment of |target| when we enter the forced frame.
--- a/js/src/vm/RegExpObject-inl.h
+++ b/js/src/vm/RegExpObject-inl.h
@@ -243,17 +243,17 @@ RegExpObject::setSticky(bool enabled)
     setSlot(STICKY_FLAG_SLOT, BooleanValue(enabled));
 }
 
 /* RegExpPrivate inlines. */
 
 inline RegExpPrivateCache *
 detail::RegExpPrivate::getOrCreateCache(JSContext *cx)
 {
-    if (RegExpPrivateCache *cache = cx->threadData()->getOrCreateRegExpPrivateCache(cx->runtime))
+    if (RegExpPrivateCache *cache = cx->threadData()->getOrCreateRegExpPrivateCache(cx))
         return cache;
 
     js_ReportOutOfMemory(cx);
     return NULL;
 }
 
 inline bool
 detail::RegExpPrivate::cacheLookup(JSContext *cx, JSAtom *atom, RegExpFlag flags,
@@ -374,28 +374,37 @@ detail::RegExpPrivateCode::compile(JSCon
     /*
      * The YARR JIT compiler attempts to compile the parsed pattern. If
      * it cannot, it informs us via |codeBlock.isFallBack()|, in which
      * case we have to bytecode compile it.
      */
 
 #ifdef JS_METHODJIT
     if (isJITRuntimeEnabled(cx) && !yarrPattern.m_containsBackreferences) {
-        if (!cx->compartment->ensureJaegerCompartmentExists(cx))
+        JSC::ExecutableAllocator *execAlloc = cx->threadData()->getOrCreateExecutableAllocator(cx);
+        if (!execAlloc) {
+            js_ReportOutOfMemory(cx);
             return false;
+        }
 
-        JSGlobalData globalData(cx->compartment->jaegerCompartment()->execAlloc());
+        JSGlobalData globalData(execAlloc);
         jitCompile(yarrPattern, &globalData, codeBlock);
         if (!codeBlock.isFallBack())
             return true;
     }
 #endif
 
+    WTF::BumpPointerAllocator *bumpAlloc = cx->threadData()->getOrCreateBumpPointerAllocator(cx);
+    if (!bumpAlloc) {
+        js_ReportOutOfMemory(cx);
+        return false;
+    }
+
     codeBlock.setFallBack(true);
-    byteCode = byteCompile(yarrPattern, cx->compartment->regExpAllocator).get();
+    byteCode = byteCompile(yarrPattern, bumpAlloc).get();
     return true;
 #else /* !defined(ENABLE_YARR_JIT) */
     int error = 0;
     compiled = jsRegExpCompile(pattern.chars(), pattern.length(),
                   ignoreCase() ? JSRegExpIgnoreCase : JSRegExpDoNotIgnoreCase,
                   multiline() ? JSRegExpMultiline : JSRegExpSingleLine,
                   parenCount, &error);
     if (error) {
--- a/js/xpconnect/src/XPCJSRuntime.cpp
+++ b/js/xpconnect/src/XPCJSRuntime.cpp
@@ -2018,18 +2018,18 @@ public:
                           "all compartments' 'gc-heap/arena-unused' numbers.",
                           callback, closure);
 
         ReportMemoryPercentage(NS_LITERAL_CSTRING("js-gc-heap-unused-fraction"),
                                nsIMemoryReporter::KIND_OTHER,
                                data.gcHeapUnusedPercentage,
                                "Fraction of the garbage-collected JavaScript heap that is unused. "
                                "Computed as ('js-gc-heap-chunk-clean-unused' + "
-                               "'js-gc-heap-chunk-dirty-unused' + 'js-gc-heap-arena-unused') / "
-                               "'js-gc-heap'.",
+                               "'js-gc-heap-chunk-dirty-unused' + 'js-gc-heap-decommitted' + "
+                               "'js-gc-heap-arena-unused') / 'js-gc-heap'.",
                                callback, closure);
 
         ReportMemoryBytes(NS_LITERAL_CSTRING("js-total-objects"),
                           nsIMemoryReporter::KIND_OTHER, data.totalObjects,
                           "Memory used for all object-related data.  This is the sum of all "
                           "compartments' 'gc-heap/objects-non-function', "
                           "'gc-heap/objects-function' and 'object-slots' numbers.",
                           callback, closure);
--- a/layout/reftests/text/reftest.list
+++ b/layout/reftests/text/reftest.list
@@ -94,46 +94,46 @@ random-if(!winWidget) == arial-bold-lam-
 != auto-hyphenation-1.html auto-hyphenation-1-notref.html
 == auto-hyphenation-1a.html auto-hyphenation-1-ref.html
 == auto-hyphenation-2.html auto-hyphenation-2-ref.html
 == auto-hyphenation-3.html auto-hyphenation-3-ref.html
 == auto-hyphenation-4.html auto-hyphenation-4-ref.html
 == auto-hyphenation-5.html auto-hyphenation-5-ref.html
 == auto-hyphenation-6.html auto-hyphenation-6-ref.html
 == auto-hyphenation-7.html auto-hyphenation-7-ref.html
-# Android ships only the en-US hyphenation dictionary
-skip-if(Android) == auto-hyphenation-af-1.html auto-hyphenation-af-1-ref.html
-skip-if(Android) == auto-hyphenation-bg-1.html auto-hyphenation-bg-1-ref.html
-skip-if(Android) == auto-hyphenation-ca-1.html auto-hyphenation-ca-1-ref.html
-skip-if(Android) == auto-hyphenation-cy-1.html auto-hyphenation-cy-1-ref.html
-skip-if(Android) == auto-hyphenation-da-1.html auto-hyphenation-da-1-ref.html
-skip-if(Android) == auto-hyphenation-de-1901-1.html auto-hyphenation-de-1901-1-ref.html
-skip-if(Android) == auto-hyphenation-de-1996-1.html auto-hyphenation-de-1996-1-ref.html
-skip-if(Android) != auto-hyphenation-de-1901-1.html auto-hyphenation-de-1996-1.html
-skip-if(Android) == auto-hyphenation-de-ch-1.html auto-hyphenation-de-ch-1-ref.html
-skip-if(Android) == auto-hyphenation-eo-1.html auto-hyphenation-eo-1-ref.html
-skip-if(Android) == auto-hyphenation-es-1.html auto-hyphenation-es-1-ref.html
-skip-if(Android) == auto-hyphenation-et-1.html auto-hyphenation-et-1-ref.html
-skip-if(Android) == auto-hyphenation-fi-1.html auto-hyphenation-fi-1-ref.html
-skip-if(Android) == auto-hyphenation-fr-1.html auto-hyphenation-fr-1-ref.html
-skip-if(Android) == auto-hyphenation-gl-1.html auto-hyphenation-gl-1-ref.html
-skip-if(Android) == auto-hyphenation-hr-1.html auto-hyphenation-hr-1-ref.html
-skip-if(Android) == auto-hyphenation-hsb-1.html auto-hyphenation-hsb-1-ref.html
-skip-if(Android) == auto-hyphenation-hu-1.html auto-hyphenation-hu-1-ref.html
-skip-if(Android) == auto-hyphenation-ia-1.html auto-hyphenation-ia-1-ref.html
-skip-if(Android) == auto-hyphenation-is-1.html auto-hyphenation-is-1-ref.html
-skip-if(Android) == auto-hyphenation-it-1.html auto-hyphenation-it-1-ref.html
-skip-if(Android) == auto-hyphenation-kmr-1.html auto-hyphenation-kmr-1-ref.html
-skip-if(Android) == auto-hyphenation-la-1.html auto-hyphenation-la-1-ref.html
-skip-if(Android) == auto-hyphenation-lt-1.html auto-hyphenation-lt-1-ref.html
-skip-if(Android) == auto-hyphenation-mn-1.html auto-hyphenation-mn-1-ref.html
-skip-if(Android) == auto-hyphenation-nb-1.html auto-hyphenation-nb-1-ref.html
-skip-if(Android) == auto-hyphenation-nl-1.html auto-hyphenation-nl-1-ref.html
-skip-if(Android) == auto-hyphenation-nn-1.html auto-hyphenation-nn-1-ref.html
-skip-if(Android) == auto-hyphenation-pt-1.html auto-hyphenation-pt-1-ref.html
-skip-if(Android) == auto-hyphenation-ru-1.html auto-hyphenation-ru-1-ref.html
-skip-if(Android) == auto-hyphenation-sh-1.html auto-hyphenation-sh-1-ref.html
-skip-if(Android) == auto-hyphenation-sl-1.html auto-hyphenation-sl-1-ref.html
-skip-if(Android) == auto-hyphenation-sr-1.html auto-hyphenation-sr-1-ref.html
-skip-if(Android) == auto-hyphenation-sv-1.html auto-hyphenation-sv-1-ref.html # test swedish patterns
-skip-if(Android) != auto-hyphenation-sv-1.html auto-hyphenation-sv-1-notref.html # verify swedish != english
-skip-if(Android) == auto-hyphenation-tr-1.html auto-hyphenation-tr-1-ref.html
-skip-if(Android) == auto-hyphenation-uk-1.html auto-hyphenation-uk-1-ref.html
+== auto-hyphenation-af-1.html auto-hyphenation-af-1-ref.html
+== auto-hyphenation-bg-1.html auto-hyphenation-bg-1-ref.html
+== auto-hyphenation-ca-1.html auto-hyphenation-ca-1-ref.html
+== auto-hyphenation-cy-1.html auto-hyphenation-cy-1-ref.html
+== auto-hyphenation-da-1.html auto-hyphenation-da-1-ref.html
+== auto-hyphenation-de-1901-1.html auto-hyphenation-de-1901-1-ref.html
+== auto-hyphenation-de-1996-1.html auto-hyphenation-de-1996-1-ref.html
+!= auto-hyphenation-de-1901-1.html auto-hyphenation-de-1996-1.html
+== auto-hyphenation-de-ch-1.html auto-hyphenation-de-ch-1-ref.html
+== auto-hyphenation-eo-1.html auto-hyphenation-eo-1-ref.html
+== auto-hyphenation-es-1.html auto-hyphenation-es-1-ref.html
+== auto-hyphenation-et-1.html auto-hyphenation-et-1-ref.html
+== auto-hyphenation-fi-1.html auto-hyphenation-fi-1-ref.html
+== auto-hyphenation-fr-1.html auto-hyphenation-fr-1-ref.html
+== auto-hyphenation-gl-1.html auto-hyphenation-gl-1-ref.html
+== auto-hyphenation-hr-1.html auto-hyphenation-hr-1-ref.html
+== auto-hyphenation-hsb-1.html auto-hyphenation-hsb-1-ref.html
+== auto-hyphenation-hu-1.html auto-hyphenation-hu-1-ref.html
+== auto-hyphenation-ia-1.html auto-hyphenation-ia-1-ref.html
+== auto-hyphenation-is-1.html auto-hyphenation-is-1-ref.html
+== auto-hyphenation-it-1.html auto-hyphenation-it-1-ref.html
+== auto-hyphenation-kmr-1.html auto-hyphenation-kmr-1-ref.html
+== auto-hyphenation-la-1.html auto-hyphenation-la-1-ref.html
+== auto-hyphenation-lt-1.html auto-hyphenation-lt-1-ref.html
+== auto-hyphenation-mn-1.html auto-hyphenation-mn-1-ref.html
+== auto-hyphenation-nb-1.html auto-hyphenation-nb-1-ref.html
+== auto-hyphenation-nl-1.html auto-hyphenation-nl-1-ref.html
+== auto-hyphenation-nn-1.html auto-hyphenation-nn-1-ref.html
+== auto-hyphenation-pt-1.html auto-hyphenation-pt-1-ref.html
+== auto-hyphenation-ru-1.html auto-hyphenation-ru-1-ref.html
+== auto-hyphenation-sh-1.html auto-hyphenation-sh-1-ref.html
+== auto-hyphenation-sl-1.html auto-hyphenation-sl-1-ref.html
+== auto-hyphenation-sr-1.html auto-hyphenation-sr-1-ref.html
+== auto-hyphenation-sv-1.html auto-hyphenation-sv-1-ref.html # test swedish patterns
+!= auto-hyphenation-sv-1.html auto-hyphenation-sv-1-notref.html # verify swedish != english
+== auto-hyphenation-tr-1.html auto-hyphenation-tr-1-ref.html
+== auto-hyphenation-uk-1.html auto-hyphenation-uk-1-ref.html
+
--- a/mfbt/Types.h
+++ b/mfbt/Types.h
@@ -74,28 +74,65 @@
 #define MOZ_EXPORT_API(type_)  JS_EXPORT_API(type_)
 #define MOZ_IMPORT_API(type_)  JS_IMPORT_API(type_)
 
 /*
  * mfbt definitions need to see export declarations when built, but
  * other code needs to see import declarations when using mfbt.
  */
 #if defined(IMPL_MFBT)
-# define MFBT_API(type_)       MOZ_EXPORT_API(type_)
+#  define MFBT_API(type_)       MOZ_EXPORT_API(type_)
 #else
-# define MFBT_API(type_)       MOZ_IMPORT_API(type_)
+#  define MFBT_API(type_)       MOZ_IMPORT_API(type_)
 #endif
 
 
 #define MOZ_BEGIN_EXTERN_C     JS_BEGIN_EXTERN_C
 #define MOZ_END_EXTERN_C       JS_END_EXTERN_C
 
 #ifdef __cplusplus
 
 /*
+ * g++ requires -std=c++0x or -std=gnu++0x to support C++11 functionality
+ * without warnings (functionality used by the macros below).  These modes are
+ * detectable by checking whether __GXX_EXPERIMENTAL_CXX0X__ is defined or, more
+ * standardly, by checking whether __cplusplus has a C++11 or greater value.
+ * Current versions of g++ do not correctly set __cplusplus, so we check both
+ * for forward compatibility.
+ */
+#if defined(__clang__)
+#  if __clang_major__ >= 3
+#    define MOZ_HAVE_CXX11_DELETE
+#    define MOZ_HAVE_CXX11_OVERRIDE
+#  elif __clang_major__ == 2
+#    if __clang_minor__ >= 9
+#      define MOZ_HAVE_CXX11_DELETE
+#    endif
+#  endif
+#elif defined(__GNUC__)
+#  if defined(__GXX_EXPERIMENTAL_CXX0X__) || __cplusplus >= 201103L
+#    if __GNUC__ > 4
+#      define MOZ_HAVE_CXX11_DELETE
+#      define MOZ_HAVE_CXX11_OVERRIDE
+#    elif __GNUC__ == 4
+#      if __GNUC_MINOR__ >= 7
+#        define MOZ_HAVE_CXX11_OVERRIDE
+#      endif
+#      if __GNUC_MINOR__ >= 4
+#        define MOZ_HAVE_CXX11_DELETE
+#      endif
+#    endif
+#  endif
+#elif defined(_MSC_VER)
+#  if _MSC_VER >= 1400
+#    define MOZ_HAVE_CXX11_OVERRIDE
+#  endif
+#endif
+
+/*
  * MOZ_DELETE, specified immediately prior to the ';' terminating an undefined-
  * method declaration, attempts to delete that method from the corresponding
  * class.  An attempt to use the method will always produce an error *at compile
  * time* (instead of sometimes as late as link time) when this macro can be
  * implemented.  For example, you can use MOZ_DELETE to produce classes with no
  * implicit copy constructor or assignment operator:
  *
  *   struct NonCopyable
@@ -107,30 +144,58 @@
  *
  * If MOZ_DELETE can't be implemented for the current compiler, use of the
  * annotated method will still cause an error, but the error might occur at link
  * time in some cases rather than at compile time.
  *
  * MOZ_DELETE relies on C++11 functionality not universally implemented.  As a
  * backstop, method declarations using MOZ_DELETE should be private.
  */
-#if defined(__clang__) && (__clang_major__ >= 3 || (__clang_major__ == 2 && __clang_minor__ >= 9))
-# define MOZ_DELETE            = delete
-#elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 4))
- /*
-  * g++ >= 4.4 requires -std=c++0x or -std=gnu++0x to support deleted functions
-  * without warnings.  These modes are detectable by the experimental macro used
-  * below or, more standardly, by checking whether __cplusplus has a C++11 or
-  * greater value.  Current versions of g++ do not correctly set __cplusplus, so
-  * we check both for forward compatibility.
-  */
-# if defined(__GXX_EXPERIMENTAL_CXX0X__) || __cplusplus >= 201103L
-#  define MOZ_DELETE           = delete
-# else
-#  define MOZ_DELETE           /* = delete */
-# endif
+#if defined(MOZ_HAVE_CXX11_DELETE)
+#  define MOZ_DELETE            = delete
 #else
-# define MOZ_DELETE            /* no = delete support, or unknown support */
+#  define MOZ_DELETE            /* no support */
+#endif
+
+/*
+ * MOZ_OVERRIDE explicitly indicates that a virtual member function in a class
+ * overrides a member function of a base class, rather than potentially being a
+ * new member function.  MOZ_OVERRIDE should be placed immediately before the
+ * ';' terminating the member function's declaration, or before '= 0;' if the
+ * member function is pure.  If the member function is defined in the class
+ * definition, it should appear before the opening brace of the function body.
+ *
+ *   class Base
+ *   {
+ *     public:
+ *       virtual void f() = 0;
+ *   };
+ *   class Derived1 : public Base
+ *   {
+ *     public:
+ *       virtual void f() MOZ_OVERRIDE;
+ *   };
+ *   class Derived2 : public Base
+ *   {
+ *     public:
+ *       virtual void f() MOZ_OVERRIDE = 0;
+ *   };
+ *   class Derived3 : public Base
+ *   {
+ *     public:
+ *       virtual void f() MOZ_OVERRIDE { }
+ *   };
+ *
+ * In compilers supporting C++11 override controls, MOZ_OVERRIDE *requires* that
+ * the function marked with it override a member function of a base class: it
+ * is a compile error if it does not.  Otherwise MOZ_OVERRIDE does not affect
+ * semantics and merely documents the override relationship to the reader (but
+ * of course must still be used correctly to not break C++11 compilers).
+ */
+#if defined(MOZ_HAVE_CXX11_OVERRIDE)
+#  define MOZ_OVERRIDE          override
+#else
+#  define MOZ_OVERRIDE          /* no support */
 #endif
 
 #endif /* __cplusplus */
 
 #endif  /* mozilla_Types_h_ */
--- a/mfbt/Util.h
+++ b/mfbt/Util.h
@@ -64,77 +64,73 @@ JS_Assert(const char *s, const char *fil
 MOZ_END_EXTERN_C
 
 /*
  * MOZ_ASSERT() is a "strong" assertion of state, like libc's
  * assert().  If a MOZ_ASSERT() fails in a debug build, the process in
  * which it fails will stop running in a loud and dramatic way.
  */
 #ifdef DEBUG
-
-# define MOZ_ASSERT(expr_)                                      \
-    ((expr_) ? (void)0 : JS_Assert(#expr_, __FILE__, __LINE__))
-
+#  define MOZ_ASSERT(expr_)                                      \
+     ((expr_) ? (void)0 : JS_Assert(#expr_, __FILE__, __LINE__))
 #else
-
-# define MOZ_ASSERT(expr_) ((void)0)
-
+#  define MOZ_ASSERT(expr_) ((void)0)
 #endif  /* DEBUG */
 
 /*
  * MOZ_INLINE is a macro which expands to tell the compiler that the method
  * decorated with it should be inlined.  This macro is usable from C and C++
  * code, even though C89 does not support the |inline| keyword.  The compiler
  * may ignore this directive if it chooses.
  */
 #ifndef MOZ_INLINE
-# if defined __cplusplus
-#  define MOZ_INLINE          inline
-# elif defined _MSC_VER
-#  define MOZ_INLINE          __inline
-# elif defined __GNUC__
-#  define MOZ_INLINE          __inline__
-# else
-#  define MOZ_INLINE          inline
-# endif
+#  if defined __cplusplus
+#    define MOZ_INLINE          inline
+#  elif defined _MSC_VER
+#    define MOZ_INLINE          __inline
+#  elif defined __GNUC__
+#    define MOZ_INLINE          __inline__
+#  else
+#    define MOZ_INLINE          inline
+#  endif
 #endif
 
 /*
  * MOZ_ALWAYS_INLINE is a macro which expands to tell the compiler that the
  * method decorated with it must be inlined, even if the compiler thinks
  * otherwise.  This is only a (much) stronger version of the MOZ_INLINE hint:
  * compilers are not guaranteed to respect it (although they're much more likely
  * to do so).
  */
 #ifndef MOZ_ALWAYS_INLINE
-# if defined DEBUG
-#  define MOZ_ALWAYS_INLINE   MOZ_INLINE
-# elif defined _MSC_VER
-#  define MOZ_ALWAYS_INLINE   __forceinline
-# elif defined __GNUC__
-#  define MOZ_ALWAYS_INLINE   __attribute__((always_inline)) MOZ_INLINE
-# else
-#  define MOZ_ALWAYS_INLINE   MOZ_INLINE
-# endif
+#  if defined DEBUG
+#    define MOZ_ALWAYS_INLINE   MOZ_INLINE
+#  elif defined _MSC_VER
+#    define MOZ_ALWAYS_INLINE   __forceinline
+#  elif defined __GNUC__
+#    define MOZ_ALWAYS_INLINE   __attribute__((always_inline)) MOZ_INLINE
+#  else
+#    define MOZ_ALWAYS_INLINE   MOZ_INLINE
+#  endif
 #endif
 
 /*
  * MOZ_NEVER_INLINE is a macro which expands to tell the compiler that the
  * method decorated with it must never be inlined, even if the compiler would
  * otherwise choose to inline the method.  Compilers aren't absolutely
  * guaranteed to support this, but most do.
  */
 #ifndef MOZ_NEVER_INLINE
-# if defined _MSC_VER
-#  define MOZ_NEVER_INLINE __declspec(noinline)
-# elif defined __GNUC__
-#  define MOZ_NEVER_INLINE __attribute__((noinline))
-# else
-#  define MOZ_NEVER_INLINE
-# endif
+#  if defined _MSC_VER
+#    define MOZ_NEVER_INLINE __declspec(noinline)
+#  elif defined __GNUC__
+#    define MOZ_NEVER_INLINE __attribute__((noinline))
+#  else
+#    define MOZ_NEVER_INLINE
+#  endif
 #endif
 
 #ifdef __cplusplus
 
 namespace mozilla {
 
 /**
  * DebugOnly contains a value of type T, but only in debug builds.  In
@@ -219,28 +215,24 @@ public:
  * For instance,
  *
  *   MOZ_ALIGNED_DECL(char arr[2], 8);
  *
  * will declare a two-character array |arr| aligned to 8 bytes.
  */
 
 #if defined(__GNUC__)
-#define MOZ_ALIGNED_DECL(_type, _align) \
-  _type __attribute__((aligned(_align)))
-
+#  define MOZ_ALIGNED_DECL(_type, _align) \
+     _type __attribute__((aligned(_align)))
 #elif defined(_MSC_VER)
-#define MOZ_ALIGNED_DECL(_type, _align) \
-  __declspec(align(_align)) _type
-
+#  define MOZ_ALIGNED_DECL(_type, _align) \
+     __declspec(align(_align)) _type
 #else
-
-#warning "We don't know how to align variables on this compiler."
-#define MOZ_ALIGNED_DECL(_type, _align) _type
-
+#  warning "We don't know how to align variables on this compiler."
+#  define MOZ_ALIGNED_DECL(_type, _align) _type
 #endif
 
 /*
  * AlignedElem<N> is a structure whose alignment is guaranteed to be at least N bytes.
  *
  * We support 1, 2, 4, 8, and 16-bit alignment.
  */
 template<size_t align>
--- a/toolkit/components/build/nsToolkitCompsCID.h
+++ b/toolkit/components/build/nsToolkitCompsCID.h
@@ -155,19 +155,19 @@
 // {59648a91-5a60-4122-8ff2-54b839c84aed}
 #define NS_PARENTALCONTROLSSERVICE_CID \
 { 0x580530e5, 0x118c, 0x4bc7, { 0xab, 0x88, 0xbc, 0x2c, 0xd2, 0xb9, 0x72, 0x23 } }
 
 // {e7f70966-9a37-48d7-8aeb-35998f31090e}
 #define NS_TYPEAHEADFIND_CID \
 { 0xe7f70966, 0x9a37, 0x48d7, { 0x8a, 0xeb, 0x35, 0x99, 0x8f, 0x31, 0x09, 0x0e} }
 
-// {5edc87c2-6960-44e5-8431-bdfbb56f6aff}
+// {51464459-4e46-4f31-8745-4acfa7c1e2f2}
 #define NS_URLCLASSIFIERPREFIXSET_CID \
-{ 0x5edc87c2, 0x6960, 0x44e5, { 0x84, 0x31, 0xbd, 0xfb, 0xb5, 0x6f, 0x6a, 0xff} }
+{ 0x51464459, 0x4e46, 0x4f31, { 0x87, 0x45, 0x4a, 0xcf, 0xa7, 0xc1, 0xe2, 0xf2} }
 
 // {5eb7c3c1-ec1f-4007-87cc-eefb37d68ce6}
 #define NS_URLCLASSIFIERDBSERVICE_CID \
 { 0x5eb7c3c1, 0xec1f, 0x4007, { 0x87, 0xcc, 0xee, 0xfb, 0x37, 0xd6, 0x8c, 0xe6} }
 
 // {c2be6dc0-ef1e-4abd-86a2-4f864ddc57f6}
 #define NS_URLCLASSIFIERSTREAMUPDATER_CID \
 { 0xc2be6dc0, 0xef1e, 0x4abd, { 0x86, 0xa2, 0x4f, 0x86, 0x4d, 0xdc, 0x57, 0xf6} }
--- a/toolkit/components/url-classifier/nsIUrlClassifierPrefixSet.idl
+++ b/toolkit/components/url-classifier/nsIUrlClassifierPrefixSet.idl
@@ -36,24 +36,24 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsISupports.idl"
 #include "nsIFile.idl"
 
 interface nsIArray;
 
-[scriptable, uuid(5edc87c2-6960-44e5-8431-bdfbb56f6aff)]
+[scriptable, uuid(51464459-4e46-4f31-8745-4acfa7c1e2f2)]
 interface nsIUrlClassifierPrefixSet : nsISupports
 {
   void setPrefixes([const, array, size_is(aLength)] in unsigned long aPrefixes,
                    in unsigned long aLength);
   void addPrefixes([const, array, size_is(aLength)] in unsigned long aPrefixes,
                    in unsigned long aLength);
   boolean contains(in unsigned long aPrefix);
   boolean probe(in unsigned long aPrefix, in unsigned long aKey,
                 inout boolean aReady);
-  PRUint32 sizeOfIncludingThis(in boolean aCountMe);
+  PRUint32 sizeOfIncludingThis();
   PRUint32 getKey();
   boolean isEmpty();
   void loadFromFile(in nsIFile aFile);
   void storeToFile(in nsIFile aFile);
 };
--- a/toolkit/components/url-classifier/nsUrlClassifierDBService.cpp
+++ b/toolkit/components/url-classifier/nsUrlClassifierDBService.cpp
@@ -3648,17 +3648,17 @@ nsUrlClassifierDBServiceWorker::LoadPref
   }
   if (!exists || NS_FAILED(rv)) {
     LOG(("no (usable) stored PrefixSet found, constructing from store"));
     ConstructPrefixSet();
   }
 
 #ifdef DEBUG
   PRUint32 size = 0;
-  rv = mPrefixSet->SizeOfIncludingThis(true, &size);
+  rv = mPrefixSet->SizeOfIncludingThis(&size);
   LOG(("SB tree done, size = %d bytes\n", size));
   NS_ENSURE_SUCCESS(rv, rv);
 #endif
 #if defined(PR_LOGGING)
   if (LOG_ENABLED()) {
     PRIntervalTime clockEnd = PR_IntervalNow();
     LOG(("Loading took %dms\n",
          PR_IntervalToMilliseconds(clockEnd - clockStart)));
--- a/toolkit/components/url-classifier/nsUrlClassifierPrefixSet.cpp
+++ b/toolkit/components/url-classifier/nsUrlClassifierPrefixSet.cpp
@@ -122,17 +122,17 @@ nsPrefixSetReporter::GetUnits(PRInt32 * 
   *aUnits = nsIMemoryReporter::UNITS_BYTES;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsPrefixSetReporter::GetAmount(PRInt64 * aAmount)
 {
   PRUint32 size;
-  nsresult rv = mParent->SizeOfIncludingThis(true, &size);
+  nsresult rv = mParent->SizeOfIncludingThis(&size);
   *aAmount = size;
   return rv;
 }
 
 NS_IMETHODIMP
 nsPrefixSetReporter::GetDescription(nsACString & aDescription)
 {
   aDescription.Assign(NS_LITERAL_CSTRING("Memory used by a PrefixSet for "
@@ -322,25 +322,21 @@ nsUrlClassifierPrefixSet::Contains(PRUin
   if (diff == 0) {
     *aFound = true;
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsUrlClassifierPrefixSet::SizeOfIncludingThis(bool aCountMe, PRUint32 * aSize)
+nsUrlClassifierPrefixSet::SizeOfIncludingThis(PRUint32 * aSize)
 {
   MutexAutoLock lock(mPrefixSetLock);
-  if (aCountMe) {
-    size_t usable = moz_malloc_usable_size(this);
-    *aSize = (PRUint32)(usable ? usable : sizeof(*this));
-  } else {
-    *aSize = 0;
-  }
+  size_t usable = moz_malloc_usable_size(this);
+  *aSize = (PRUint32)(usable ? usable : sizeof(*this));
   *aSize += mDeltas.SizeOf();
   *aSize += mIndexPrefixes.SizeOf();
   *aSize += mIndexStarts.SizeOf();
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsUrlClassifierPrefixSet::IsEmpty(bool * aEmpty)
--- a/toolkit/components/url-classifier/nsUrlClassifierPrefixSet.h
+++ b/toolkit/components/url-classifier/nsUrlClassifierPrefixSet.h
@@ -67,17 +67,17 @@ public:
   // Does the PrefixSet contain this prefix? not thread-safe
   NS_IMETHOD Contains(PRUint32 aPrefix, bool* aFound);
   // Do a lookup in the PrefixSet
   // if aReady is set, we will block until there are any entries
   // if not set, we will return in aReady whether we were ready or not
   NS_IMETHOD Probe(PRUint32 aPrefix, PRUint32 aKey, bool* aReady, bool* aFound);
   // Return the estimated size of the set on disk and in memory,
   // in bytes
-  NS_IMETHOD SizeOfIncludingThis(bool aCountMe, PRUint32* aSize);
+  NS_IMETHOD SizeOfIncludingThis(PRUint32* aSize);
   NS_IMETHOD IsEmpty(bool * aEmpty);
   NS_IMETHOD LoadFromFile(nsIFile* aFile);
   NS_IMETHOD StoreToFile(nsIFile* aFile);
   // Return a key that is used to randomize the collisions in the prefixes
   NS_IMETHOD GetKey(PRUint32* aKey);
 
   NS_DECL_ISUPPORTS
 
--- a/toolkit/mozapps/extensions/XPIProvider.jsm
+++ b/toolkit/mozapps/extensions/XPIProvider.jsm
@@ -1767,17 +1767,17 @@ var XPIProvider = {
       // This *must* be modal as it has to block startup.
       var features = "chrome,centerscreen,dialog,titlebar,modal";
       var ww = Cc["@mozilla.org/embedcomp/window-watcher;1"].
                getService(Ci.nsIWindowWatcher);
       ww.openWindow(null, URI_EXTENSION_UPDATE_DIALOG, "", features, variant);
     }
 
     // Ensure any changes to the add-ons list are flushed to disk
-    XPIDatabase.writeAddonsList([]);
+    XPIDatabase.writeAddonsList();
     Services.prefs.setBoolPref(PREF_PENDING_OPERATIONS, false);
   },
 
   /**
    * Adds a list of currently active add-ons to the next crash report.
    */
   addAddonsToCrashReporter: function XPI_addAddonsToCrashReporter() {
     if (!("nsICrashReporter" in Ci) ||
@@ -3042,18 +3042,18 @@ var XPIProvider = {
       ERROR("Error during startup file checks, rolling back any database " +
             "changes", e);
       XPIDatabase.rollbackTransaction();
     }
 
     // Check that the add-ons list still exists
     let addonsList = FileUtils.getFile(KEY_PROFILEDIR, [FILE_XPI_ADDONS_LIST],
                                        true);
-    if (!addonsList.exists()) {
-      LOG("Add-ons list is missing, recreating");
+    if (addonsList.exists() == (state.length == 0)) {
+      LOG("Add-ons list is invalid, rebuilding");
       XPIDatabase.writeAddonsList();
     }
 
     return false;
   },
 
   /**
    * Called to test whether this provider supports installing a particular
@@ -5490,59 +5490,82 @@ var XPIDatabase = {
     // startup when the only references are internal.
     this.addonCache = [];
   },
 
   /**
    * Writes out the XPI add-ons list for the platform to read.
    */
   writeAddonsList: function XPIDB_writeAddonsList() {
-    LOG("Writing add-ons list");
     Services.appinfo.invalidateCachesOnRestart();
+
     let addonsList = FileUtils.getFile(KEY_PROFILEDIR, [FILE_XPI_ADDONS_LIST],
                                        true);
+    if (!this.connection) {
+      try {
+        addonsList.remove(false);
+        LOG("Deleted add-ons list");
+      }
+      catch (e) {
+      }
+
+      Services.prefs.clearUserPref(PREF_EM_ENABLED_ADDONS);
+      return;
+    }
 
     let enabledAddons = [];
     let text = "[ExtensionDirs]\r\n";
     let count = 0;
-    let stmt;
-
-    if (this.connection) {
-      stmt = this.getStatement("getActiveAddons");
-
-      for (let row in resultRows(stmt)) {
-        text += "Extension" + (count++) + "=" + row.descriptor + "\r\n";
-        enabledAddons.push(row.id + ":" + row.version);
-      }
-    }
+    let fullCount = 0;
+
+    let stmt = this.getStatement("getActiveAddons");
+
+    for (let row in resultRows(stmt)) {
+      text += "Extension" + (count++) + "=" + row.descriptor + "\r\n";
+      enabledAddons.push(row.id + ":" + row.version);
+    }
+    fullCount += count;
 
     // The selected skin may come from an inactive theme (the default theme
     // when a lightweight theme is applied for example)
     text += "\r\n[ThemeDirs]\r\n";
 
-    if (this.connection) {
-      if (Prefs.getBoolPref(PREF_EM_DSS_ENABLED)) {
-        stmt = this.getStatement("getThemes");
-      }
-      else {
-        stmt = this.getStatement("getActiveTheme");
-        stmt.params.internalName = XPIProvider.selectedSkin;
-      }
+    if (Prefs.getBoolPref(PREF_EM_DSS_ENABLED)) {
+      stmt = this.getStatement("getThemes");
+    }
+    else {
+      stmt = this.getStatement("getActiveTheme");
+      stmt.params.internalName = XPIProvider.selectedSkin;
+    }
+
+    if (stmt) {
       count = 0;
       for (let row in resultRows(stmt)) {
         text += "Extension" + (count++) + "=" + row.descriptor + "\r\n";
         enabledAddons.push(row.id + ":" + row.version);
       }
-    }
-
-    var fos = FileUtils.openSafeFileOutputStream(addonsList);
-    fos.write(text, text.length);
-    FileUtils.closeSafeFileOutputStream(fos);
-
-    Services.prefs.setCharPref(PREF_EM_ENABLED_ADDONS, enabledAddons.join(","));
+      fullCount += count;
+    }
+
+    if (fullCount > 0) {
+      LOG("Writing add-ons list");
+      var fos = FileUtils.openSafeFileOutputStream(addonsList);
+      fos.write(text, text.length);
+      FileUtils.closeSafeFileOutputStream(fos);
+
+      Services.prefs.setCharPref(PREF_EM_ENABLED_ADDONS, enabledAddons.join(","));
+    }
+    else {
+      if (addonsList.exists()) {
+        LOG("Deleting add-ons list");
+        addonsList.remove(false);
+      }
+
+      Services.prefs.clearUserPref(PREF_EM_ENABLED_ADDONS);
+    }
   }
 };
 
 function getHashStringForCrypto(aCrypto) {
   // return the two-digit hexadecimal code for a byte
   function toHexString(charCode)
     ("0" + charCode.toString(16)).slice(-2);
 
--- a/toolkit/mozapps/extensions/test/xpcshell/test_bootstrap.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_bootstrap.js
@@ -124,16 +124,19 @@ function run_test() {
   testserver.start(4444);
 
   startupManager();
 
   let file = gProfD.clone();
   file.append("extensions.sqlite");
   do_check_false(file.exists());
 
+  file.leafName = "extensions.ini";
+  do_check_false(file.exists());
+
   run_test_1();
 }
 
 // Tests that installing doesn't require a restart
 function run_test_1() {
   prepare_test({ }, [
     "onNewInstall"
   ]);
@@ -170,16 +173,19 @@ function run_test_1() {
   });
 }
 
 function check_test_1() {
   let file = gProfD.clone();
   file.append("extensions.sqlite");
   do_check_true(file.exists());
 
+  file.leafName = "extensions.ini";
+  do_check_false(file.exists());
+
   AddonManager.getAllInstalls(function(installs) {
     // There should be no active installs now since the install completed and
     // doesn't require a restart.
     do_check_eq(installs.length, 0);
 
     AddonManager.getAddonByID("bootstrap1@tests.mozilla.org", function(b1) {
       do_check_neq(b1, null);
       do_check_eq(b1.version, "1.0");
@@ -250,16 +256,20 @@ function run_test_3() {
   do_check_eq(getActiveVersion(), 0);
   do_check_eq(getShutdownReason(), ADDON_DISABLE);
   startupManager(false);
   do_check_eq(getInstalledVersion(), 1);
   do_check_eq(getActiveVersion(), 0);
   do_check_eq(getShutdownReason(), ADDON_DISABLE);
   do_check_not_in_crash_annotation("bootstrap1@tests.mozilla.org", "1.0");
 
+  let file = gProfD.clone();
+  file.append("extensions.ini");
+  do_check_false(file.exists());
+
   AddonManager.getAddonByID("bootstrap1@tests.mozilla.org", function(b1) {
     do_check_neq(b1, null);
     do_check_eq(b1.version, "1.0");
     do_check_false(b1.appDisabled);
     do_check_true(b1.userDisabled);
     do_check_false(b1.isActive);
 
     run_test_4();
--- a/toolkit/mozapps/extensions/test/xpcshell/test_startup.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_startup.js
@@ -131,16 +131,19 @@ function run_test() {
   check_startup_changes(AddonManager.STARTUP_CHANGE_UNINSTALLED, []);
   check_startup_changes(AddonManager.STARTUP_CHANGE_DISABLED, []);
   check_startup_changes(AddonManager.STARTUP_CHANGE_ENABLED, []);
 
   let file = gProfD.clone();
   file.append("extensions.sqlite");
   do_check_false(file.exists());
 
+  file.leafName = "extensions.ini";
+  do_check_false(file.exists());
+
   AddonManager.getAddonsByIDs(["addon1@tests.mozilla.org",
                                "addon2@tests.mozilla.org",
                                "addon3@tests.mozilla.org",
                                "addon4@tests.mozilla.org",
                                "addon5@tests.mozilla.org",
                                "addon6@tests.mozilla.org",
                                "addon7@tests.mozilla.org"],
                                function([a1, a2, a3, a4, a5, a6, a7]) {
@@ -186,16 +189,19 @@ function run_test_1() {
   check_startup_changes(AddonManager.STARTUP_CHANGE_DISABLED, []);
   check_startup_changes(AddonManager.STARTUP_CHANGE_ENABLED, []);
   do_check_true(gCachePurged);
 
   let file = gProfD.clone();
   file.append("extensions.sqlite");
   do_check_true(file.exists());
 
+  file.leafName = "extensions.ini";
+  do_check_true(file.exists());
+
   AddonManager.getAddonsByIDs(["addon1@tests.mozilla.org",
                                "addon2@tests.mozilla.org",
                                "addon3@tests.mozilla.org",
                                "addon4@tests.mozilla.org",
                                "addon5@tests.mozilla.org",
                                "addon6@tests.mozilla.org",
                                "addon7@tests.mozilla.org"],
                                function([a1, a2, a3, a4, a5, a6, a7]) {
@@ -287,16 +293,20 @@ function run_test_2() {
   restartManager();
   check_startup_changes(AddonManager.STARTUP_CHANGE_INSTALLED, []);
   check_startup_changes(AddonManager.STARTUP_CHANGE_CHANGED, ["addon2@tests.mozilla.org"]);
   check_startup_changes(AddonManager.STARTUP_CHANGE_UNINSTALLED, ["addon3@tests.mozilla.org"]);
   check_startup_changes(AddonManager.STARTUP_CHANGE_DISABLED, []);
   check_startup_changes(AddonManager.STARTUP_CHANGE_ENABLED, []);
   do_check_true(gCachePurged);
 
+  var file = gProfD.clone();
+  file.append("extensions.ini");
+  do_check_true(file.exists());
+
   AddonManager.getAddonsByIDs(["addon1@tests.mozilla.org",
                                "addon2@tests.mozilla.org",
                                "addon3@tests.mozilla.org",
                                "addon4@tests.mozilla.org",
                                "addon5@tests.mozilla.org"],
                                function([a1, a2, a3, a4, a5]) {
 
     do_check_neq(a1, null);
--- a/toolkit/mozapps/installer/packager.mk
+++ b/toolkit/mozapps/installer/packager.mk
@@ -265,17 +265,17 @@ JARSIGNER ?= echo
 
 DIST_FILES = \
   resources.arsc \
   AndroidManifest.xml \
   chrome \
   components \
   defaults \
   modules \
-  hyphenation/hyph_en_US.dic \
+  hyphenation \
   res \
   lib \
   lib.id \
   libmozalloc.so \
   libnspr4.so \
   libplc4.so \
   libplds4.so \
   libmozsqlite3.so \
--- a/widget/public/nsIGfxInfo.idl
+++ b/widget/public/nsIGfxInfo.idl
@@ -143,10 +143,13 @@ interface nsIGfxInfo : nsISupports
    * WebGL info; valid params are "full-renderer", "vendor", "renderer", "version",
    * "shading_language_version", "extensions".  These return info from
    * underlying GL impl that's used to implement WebGL.
    */
   DOMString getWebGLParameter(in DOMString aParam);
 
   // only useful on X11
   [noscript, notxpcom] void GetData();
+
+  [implicit_jscontext]
+  jsval getInfo();
 };
 
--- a/widget/src/xpwidgets/GfxInfoBase.cpp
+++ b/widget/src/xpwidgets/GfxInfoBase.cpp
@@ -858,8 +858,68 @@ NS_IMETHODIMP GfxInfoBase::GetFailures(P
         NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(i, (*failures));
         return NS_ERROR_OUT_OF_MEMORY;
       }
     }
   }
 
   return NS_OK;
 }
+
+nsTArray<GfxInfoCollectorBase*> *sCollectors;
+
+static void
+InitCollectors()
+{
+  if (!sCollectors)
+    sCollectors = new nsTArray<GfxInfoCollectorBase*>;
+}
+
+nsresult GfxInfoBase::GetInfo(JSContext* aCx, jsval* aResult)
+{
+  InitCollectors();
+  InfoObject obj(aCx);
+
+  for (PRUint32 i = 0; i < sCollectors->Length(); i++) {
+    (*sCollectors)[i]->GetInfo(obj);
+  }
+
+  // Some example property definitions
+  // obj.DefineProperty("wordCacheSize", gfxTextRunWordCache::Count());
+  // obj.DefineProperty("renderer", mRendererIDsString);
+  // obj.DefineProperty("five", 5);
+
+  if (!obj.mOk) {
+    return NS_ERROR_FAILURE;
+  }
+
+  *aResult = OBJECT_TO_JSVAL(obj.mObj);
+  return NS_OK;
+}
+
+void
+GfxInfoBase::AddCollector(GfxInfoCollectorBase* collector)
+{
+  InitCollectors();
+  sCollectors->AppendElement(collector);
+}
+
+void
+GfxInfoBase::RemoveCollector(GfxInfoCollectorBase* collector)
+{
+  InitCollectors();
+  for (PRUint32 i = 0; i < sCollectors->Length(); i++) {
+    if ((*sCollectors)[i] == collector) {
+      sCollectors->RemoveElementAt(i);
+      break;
+    }
+  }
+}
+
+GfxInfoCollectorBase::GfxInfoCollectorBase()
+{
+  GfxInfoBase::AddCollector(this);
+}
+
+GfxInfoCollectorBase::~GfxInfoCollectorBase()
+{
+  GfxInfoBase::RemoveCollector(this);
+}
--- a/widget/src/xpwidgets/GfxInfoBase.h
+++ b/widget/src/xpwidgets/GfxInfoBase.h
@@ -42,16 +42,17 @@
 
 #include "nsIGfxInfo.h"
 #include "nsCOMPtr.h"
 #include "nsIObserver.h"
 #include "nsWeakReference.h"
 #include "GfxDriverInfo.h"
 #include "nsTArray.h"
 #include "nsString.h"
+#include "GfxInfoCollector.h"
 
 namespace mozilla {
 namespace widget {  
 
 class GfxInfoBase : public nsIGfxInfo,
                     public nsIObserver,
                     public nsSupportsWeakReference
 {
@@ -70,16 +71,17 @@ public:
   // using GfxInfoBase::GetWebGLParameter;
   // to import the relevant methods into their namespace.
   NS_SCRIPTABLE NS_IMETHOD GetFeatureStatus(PRInt32 aFeature, PRInt32 *_retval NS_OUTPARAM);
   NS_SCRIPTABLE NS_IMETHOD GetFeatureSuggestedDriverVersion(PRInt32 aFeature, nsAString & _retval NS_OUTPARAM);
   NS_SCRIPTABLE NS_IMETHOD GetWebGLParameter(const nsAString & aParam, nsAString & _retval NS_OUTPARAM);
 
   NS_SCRIPTABLE NS_IMETHOD GetFailures(PRUint32 *failureCount NS_OUTPARAM, char ***failures NS_OUTPARAM);
   NS_IMETHOD_(void) LogFailure(const nsACString &failure);
+  NS_SCRIPTABLE NS_IMETHOD GetInfo(JSContext*, jsval*);
 
   // Initialization function. If you override this, you must call this class's
   // version of Init first.
   // We need Init to be called separately from the constructor so we can
   // register as an observer after all derived classes have been constructed
   // and we know we have a non-zero refcount.
   // Ideally, Init() would be void-return, but the rules of
   // NS_GENERIC_FACTORY_CONSTRUCTOR_INIT require it be nsresult return.
@@ -87,16 +89,20 @@ public:
   
   // Gets the driver info table. Used by GfxInfoBase to check for general cases
   // (while subclasses check for more specific ones).
   virtual const GfxDriverInfo* GetGfxDriverInfo() = 0;
 
   // only useful on X11
   NS_IMETHOD_(void) GetData() { }
 
+  static void AddCollector(GfxInfoCollectorBase* collector);
+  static void RemoveCollector(GfxInfoCollectorBase* collector);
+
+
 protected:
 
   virtual nsresult GetFeatureStatusImpl(PRInt32 aFeature, PRInt32* aStatus,
                                         nsAString& aSuggestedDriverVersion,
                                         GfxDriverInfo* aDriverInfo = nsnull,
                                         OperatingSystem* aOS = nsnull);
 
 private:
new file mode 100644
--- /dev/null
+++ b/widget/src/xpwidgets/GfxInfoCollector.h
@@ -0,0 +1,149 @@
+/* vim: se cin sw=2 ts=2 et : */
+/* -*- 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 mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * 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 ***** */
+
+#ifndef __mozilla_widget_GfxInfoCollector_h__
+#define __mozilla_widget_GfxInfoCollector_h__
+
+#include "jsapi.h"
+
+namespace mozilla {
+namespace widget {
+
+
+/* this is handy wrapper around JSAPI to make it more pleasant to use.
+ * We collect the JSAPI errors and so that callers don't need to */
+class InfoObject
+{
+  friend class GfxInfoBase;
+
+  public:
+  void DefineProperty(const char *name, int value)
+  {
+    if (!mOk)
+      return;
+
+    mOk = JS_DefineProperty(mCx, mObj, name, INT_TO_JSVAL(value), NULL, NULL, JSPROP_ENUMERATE);
+  }
+
+  void DefineProperty(const char *name, nsAString &value)
+  {
+    if (!mOk)
+      return;
+
+    const nsPromiseFlatString &flat = PromiseFlatString(value);
+    JSString *string = JS_NewUCStringCopyN(mCx, static_cast<const jschar*>(flat.get()), flat.Length());
+    if (!string)
+      mOk = JS_FALSE;
+
+    if (!mOk)
+      return;
+
+    mOk = JS_DefineProperty(mCx, mObj, name, STRING_TO_JSVAL(string), NULL, NULL, JSPROP_ENUMERATE);
+  }
+
+  private:
+  // We need to ensure that this object lives on the stack so that GC sees it properly
+  InfoObject(JSContext *aCx) : mCx(aCx), mOk(JS_TRUE)
+  {
+    mObj = JS_NewObject(mCx, NULL, NULL, NULL);
+    if (!mObj)
+      mOk = JS_FALSE;
+  }
+  InfoObject(InfoObject&);
+
+  JSContext *mCx;
+  JSObject *mObj;
+  JSBool mOk;
+};
+
+/*
+
+   Here's an example usage:
+
+   class Foo {
+   Foo::Foo() : mInfoCollector(this, &Foo::GetAweseomeness) {}
+
+   void GetAwesomeness(InfoObject &obj) {
+     obj.DefineProperty("awesome", mAwesome);
+   }
+
+   int mAwesome;
+
+   GfxInfoCollector<Foo> mInfoCollector;
+   }
+
+   This will define a property on the object
+   returned from calling getInfo() on a
+   GfxInfo object. e.g.
+
+       gfxInfo = Cc["@mozilla.org/gfx/info;1"].getService(Ci.nsIGfxInfo);
+       info = gfxInfo.getInfo();
+       if (info.awesome)
+          alert(info.awesome);
+
+*/
+
+class GfxInfoCollectorBase
+{
+  public:
+  GfxInfoCollectorBase();
+  virtual void GetInfo(InfoObject &obj) = 0;
+  virtual ~GfxInfoCollectorBase();
+};
+
+template<class T>
+class GfxInfoCollector : public GfxInfoCollectorBase
+{
+  public:
+  GfxInfoCollector(T* aPointer, void (T::*aFunc)(InfoObject &obj)) : mPointer(aPointer), mFunc(aFunc) {
+  }
+  virtual void GetInfo(InfoObject &obj) {
+    (mPointer->*mFunc)(obj);
+  }
+
+  protected:
+  T* mPointer;
+  void (T::*mFunc)(InfoObject &obj);
+
+};
+
+}
+}
+
+#endif
--- a/widget/src/xpwidgets/Makefile.in
+++ b/widget/src/xpwidgets/Makefile.in
@@ -41,16 +41,19 @@ srcdir		= @srcdir@
 VPATH		= @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
 MODULE		= widget
 LIBRARY_NAME	= xpwidgets_s
 LIBXUL_LIBRARY  = 1
 
+EXPORTS = \
+		GfxInfoCollector.h \
+		$(NULL)
 
 DEFINES += \
   -D_IMPL_NS_WIDGET \
   -DNO_NSPR_10_SUPPORT=1 \
   $(NULL)
 
 CPPSRCS		= \
 		nsBaseAppShell.cpp \
--- a/xpcom/base/nsMemoryReporterManager.cpp
+++ b/xpcom/base/nsMemoryReporterManager.cpp
@@ -308,17 +308,17 @@ static PRInt64 GetHeapAllocated()
 
 static PRInt64 GetHeapCommitted()
 {
     jemalloc_stats_t stats;
     jemalloc_stats(&stats);
     return (PRInt64) stats.committed;
 }
 
-static PRInt64 GetHeapCommittedUnallocatedFraction()
+static PRInt64 GetHeapCommittedFragmentation()
 {
     jemalloc_stats_t stats;
     jemalloc_stats(&stats);
     return (PRInt64) 10000 * (1 - stats.allocated / (double)stats.committed);
 }
 
 static PRInt64 GetHeapDirty()
 {
@@ -334,21 +334,21 @@ NS_MEMORY_REPORTER_IMPLEMENT(HeapCommitt
     GetHeapCommitted,
     "Memory mapped by the heap allocator that is committed, i.e. in physical "
     "memory or paged to disk.  When heap-committed is larger than "
     "heap-allocated, the difference between the two values is likely due to "
     "external fragmentation; that is, the allocator allocated a large block of "
     "memory and is unable to decommit it because a small part of that block is "
     "currently in use.")
 
-NS_MEMORY_REPORTER_IMPLEMENT(HeapCommittedUnallocatedFraction,
-    "heap-committed-unallocated-fraction",
+NS_MEMORY_REPORTER_IMPLEMENT(HeapCommittedFragmentation,
+    "heap-committed-fragmentation",
     KIND_OTHER,
     UNITS_PERCENTAGE,
-    GetHeapCommittedUnallocatedFraction,
+    GetHeapCommittedFragmentation,
     "Fraction of committed bytes which do not correspond to an active "
     "allocation; i.e., 1 - (heap-allocated / heap-committed).  Although the "
     "allocator will waste some space under any circumstances, a large value here "
     "may indicate that the heap is highly fragmented.")
 
 NS_MEMORY_REPORTER_IMPLEMENT(HeapDirty,
     "heap-dirty",
     KIND_OTHER,
@@ -467,17 +467,17 @@ nsMemoryReporterManager::Init()
 #endif
 
 #if defined(XP_WIN) && MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
     REGISTER(Private);
 #endif
 
 #if defined(HAVE_JEMALLOC_STATS)
     REGISTER(HeapCommitted);
-    REGISTER(HeapCommittedUnallocatedFraction);
+    REGISTER(HeapCommittedFragmentation);
     REGISTER(HeapDirty);
 #elif defined(XP_MACOSX) && !defined(MOZ_MEMORY)
     REGISTER(HeapZone0Committed);
     REGISTER(HeapZone0Used);
 #endif
 
     return NS_OK;
 }