Merge the last PGO-green inbound changeset to m-c.
authorRyan VanderMeulen <ryanvm@gmail.com>
Thu, 02 Aug 2012 22:00:53 -0400
changeset 101276 89dcadd42ec4b68b6e39b71061f04cd8d1aefc25
parent 101275 030feb4315fc1d8401477dd14a2cc57704eeb9dc (current diff)
parent 101266 38b216220e608d9d1613765d3dbde93d1119a33f (diff)
child 101277 6a82b0462271dadc79f584028abb290237e48344
child 101303 73b3b3f828b095d5b260728310f1b160f72b94fc
child 101350 369f4847191837ca58a8dd4af0ae01c2cccd782c
push id12935
push userryanvm@gmail.com
push dateFri, 03 Aug 2012 02:01:42 +0000
treeherdermozilla-inbound@6a82b0462271 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone17.0a1
first release with
nightly linux32
89dcadd42ec4 / 17.0a1 / 20120803030521 / files
nightly linux64
89dcadd42ec4 / 17.0a1 / 20120803030521 / files
nightly mac
89dcadd42ec4 / 17.0a1 / 20120803030521 / files
nightly win32
89dcadd42ec4 / 17.0a1 / 20120803030521 / files
nightly win64
89dcadd42ec4 / 17.0a1 / 20120803030521 / 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 the last PGO-green inbound changeset to m-c.
toolkit/components/maintenanceservice/prefetch.cpp
toolkit/components/maintenanceservice/prefetch.h
--- a/accessible/src/atk/ApplicationAccessibleWrap.cpp
+++ b/accessible/src/atk/ApplicationAccessibleWrap.cpp
@@ -567,17 +567,17 @@ toplevel_event_watcher(GSignalInvocation
       }
 
     }
   }
 
   return TRUE;
 }
 
-bool
+void
 ApplicationAccessibleWrap::Init()
 {
     if (ShouldA11yBeEnabled()) {
         // load and initialize gail library
         nsresult rv = LoadGtkModule(sGail);
         if (NS_SUCCEEDED(rv)) {
             (*sGail.init)();
         }
@@ -610,17 +610,17 @@ ApplicationAccessibleWrap::Init()
               reinterpret_cast<gpointer>(nsIAccessibleEvent::EVENT_SHOW), NULL);
           sToplevel_hide_hook =
             g_signal_add_emission_hook(g_signal_lookup("hide", GTK_TYPE_WINDOW),
               0, toplevel_event_watcher,
               reinterpret_cast<gpointer>(nsIAccessibleEvent::EVENT_HIDE), NULL);
         }
     }
 
-    return ApplicationAccessible::Init();
+    ApplicationAccessible::Init();
 }
 
 void
 ApplicationAccessibleWrap::Unload()
 {
     if (sToplevel_event_hook_added) {
       sToplevel_event_hook_added = false;
       g_signal_remove_emission_hook(g_signal_lookup("show", GTK_TYPE_WINDOW),
--- a/accessible/src/atk/ApplicationAccessibleWrap.h
+++ b/accessible/src/atk/ApplicationAccessibleWrap.h
@@ -18,17 +18,17 @@ public:
   static void Unload();
   static void PreCreate();
 
 public:
   ApplicationAccessibleWrap();
   virtual ~ApplicationAccessibleWrap();
 
   // nsAccessNode
-  virtual bool Init();
+  virtual void Init();
 
   // Accessible
   virtual mozilla::a11y::ENameValueFlag Name(nsString& aName);
   virtual bool AppendChild(Accessible* aChild);
   virtual bool RemoveChild(Accessible* aChild);
 
   /**
    * Return the atk object for app root accessible.
--- a/accessible/src/base/nsAccDocManager.cpp
+++ b/accessible/src/base/nsAccDocManager.cpp
@@ -383,20 +383,17 @@ nsAccDocManager::CreateDocOrRootAccessib
   nsRefPtr<DocAccessible> docAcc = isRootDoc ?
     new RootAccessibleWrap(aDocument, rootElm, presShell) :
     new DocAccessibleWrap(aDocument, rootElm, presShell);
 
   // Cache the document accessible into document cache.
   mDocAccessibleCache.Put(aDocument, docAcc);
 
   // Initialize the document accessible.
-  if (!docAcc->Init()) {
-    docAcc->Shutdown();
-    return nullptr;
-  }
+  docAcc->Init();
   docAcc->SetRoleMapEntry(aria::GetRoleMap(aDocument));
 
   // Bind the document to the tree.
   if (isRootDoc) {
     Accessible* appAcc = nsAccessNode::GetApplicationAccessible();
     if (!appAcc->AppendChild(docAcc)) {
       docAcc->Shutdown();
       return nullptr;
--- a/accessible/src/base/nsAccessNode.cpp
+++ b/accessible/src/base/nsAccessNode.cpp
@@ -91,22 +91,17 @@ nsAccessNode::GetApplicationAccessible()
   if (!gApplicationAccessible) {
     ApplicationAccessibleWrap::PreCreate();
 
     gApplicationAccessible = new ApplicationAccessibleWrap();
 
     // Addref on create. Will Release in ShutdownXPAccessibility()
     NS_ADDREF(gApplicationAccessible);
 
-    nsresult rv = gApplicationAccessible->Init();
-    if (NS_FAILED(rv)) {
-      gApplicationAccessible->Shutdown();
-      NS_RELEASE(gApplicationAccessible);
-      return nullptr;
-    }
+    gApplicationAccessible->Init();
   }
 
   return gApplicationAccessible;
 }
 
 void nsAccessNode::ShutdownXPAccessibility()
 {
   // Called by nsAccessibilityService::Shutdown()
--- a/accessible/src/base/nsTextEquivUtils.cpp
+++ b/accessible/src/base/nsTextEquivUtils.cpp
@@ -6,16 +6,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsTextEquivUtils.h"
 
 #include "Accessible-inl.h"
 #include "AccIterator.h"
 #include "nsAccessibilityService.h"
 #include "nsAccUtils.h"
+#include "nsStyleStructInlines.h"
 
 #include "nsIDOMXULLabeledControlEl.h"
 
 #include "nsArrayUtils.h"
 
 using namespace mozilla::a11y;
 
 #define NS_OK_NO_NAME_CLAUSE_HANDLED \
@@ -121,17 +122,17 @@ nsTextEquivUtils::AppendTextEquivFromTex
     nsIContent *parentContent = aContent->GetParent();
     if (parentContent) {
       nsIFrame *frame = parentContent->GetPrimaryFrame();
       if (frame) {
         // If this text is inside a block level frame (as opposed to span
         // level), we need to add spaces around that block's text, so we don't
         // get words jammed together in final name.
         const nsStyleDisplay* display = frame->GetStyleDisplay();
-        if (display->IsBlockOutside() ||
+        if (display->IsBlockOutsideStyle() ||
             display->mDisplay == NS_STYLE_DISPLAY_TABLE_CELL) {
           isHTMLBlock = true;
           if (!aString->IsEmpty()) {
             aString->Append(PRUnichar(' '));
           }
         }
       }
     }
--- a/accessible/src/generic/Accessible.cpp
+++ b/accessible/src/generic/Accessible.cpp
@@ -190,20 +190,19 @@ Accessible::~Accessible()
 }
 
 void
 Accessible::SetRoleMapEntry(nsRoleMapEntry* aRoleMapEntry)
 {
   mRoleMapEntry = aRoleMapEntry;
 }
 
-bool
+void
 Accessible::Init()
 {
-  return true;
 }
 
 NS_IMETHODIMP
 Accessible::GetDocument(nsIAccessibleDocument** aDocument)
 {
   NS_ENSURE_ARG_POINTER(aDocument);
 
   NS_IF_ADDREF(*aDocument = Document());
--- a/accessible/src/generic/Accessible.h
+++ b/accessible/src/generic/Accessible.h
@@ -124,17 +124,17 @@ public:
   virtual void Shutdown();
 
   //////////////////////////////////////////////////////////////////////////////
   // Public methods
 
   /**
    * Initialize the accessible.
    */
-  virtual bool Init();
+  virtual void Init();
 
   /**
    * Get the description of this accessible.
    */
   virtual void Description(nsString& aDescription);
 
   /**
    * Get the value of this accessible.
--- a/accessible/src/generic/ApplicationAccessible.cpp
+++ b/accessible/src/generic/ApplicationAccessible.cpp
@@ -263,21 +263,20 @@ ApplicationAccessible::GetPlatformVersio
 
   AppendUTF8toUTF16(cversion, aVersion);
   return NS_OK;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsAccessNode public methods
 
-bool
+void
 ApplicationAccessible::Init()
 {
   mAppInfo = do_GetService("@mozilla.org/xre/app-info;1");
-  return true;
 }
 
 void
 ApplicationAccessible::Shutdown()
 {
   mAppInfo = nullptr;
 }
 
--- a/accessible/src/generic/ApplicationAccessible.h
+++ b/accessible/src/generic/ApplicationAccessible.h
@@ -56,17 +56,17 @@ public:
   NS_IMETHOD GetActionName(PRUint8 aIndex, nsAString &aName);
   NS_IMETHOD GetActionDescription(PRUint8 aIndex, nsAString &aDescription);
   NS_IMETHOD DoAction(PRUint8 aIndex);
 
   // nsIAccessibleApplication
   NS_DECL_NSIACCESSIBLEAPPLICATION
 
   // nsAccessNode
-  virtual bool Init();
+  virtual void Init();
   virtual void Shutdown();
   virtual bool IsPrimaryForNode() const;
 
   // Accessible
   virtual GroupPos GroupPosition();
   virtual ENameValueFlag Name(nsString& aName);
   virtual void ApplyARIAState(PRUint64* aState) const;
   virtual void Description(nsString& aDescription);
--- a/accessible/src/generic/DocAccessible.cpp
+++ b/accessible/src/generic/DocAccessible.cpp
@@ -599,37 +599,34 @@ DocAccessible::GetAccessible(nsINode* aN
 #endif
 
   return accessible;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsAccessNode
 
-bool
+void
 DocAccessible::Init()
 {
 #ifdef DEBUG
   if (logging::IsEnabled(logging::eDocCreate))
     logging::DocCreate("document initialize", mDocument, this);
 #endif
 
   // Initialize notification controller.
   mNotificationController = new NotificationController(this, mPresShell);
-  if (!mNotificationController)
-    return false;
 
   // Mark the document accessible as loaded if its DOM document was loaded at
   // this point (this can happen because a11y is started late or DOM document
   // having no container was loaded.
   if (mDocument->GetReadyStateEnum() == nsIDocument::READYSTATE_COMPLETE)
     mLoadState |= eDOMLoaded;
 
   AddEventListeners();
-  return true;
 }
 
 void
 DocAccessible::Shutdown()
 {
   if (!mPresShell) // already shutdown
     return;
 
@@ -1392,22 +1389,17 @@ DocAccessible::BindToDocument(Accessible
   // Put into DOM node cache.
   if (aAccessible->IsPrimaryForNode())
     mNodeToAccessibleMap.Put(aAccessible->GetNode(), aAccessible);
 
   // Put into unique ID cache.
   mAccessibleCache.Put(aAccessible->UniqueID(), aAccessible);
 
   // Initialize the accessible.
-  if (!aAccessible->Init()) {
-    NS_ERROR("Failed to initialize an accessible!");
-
-    UnbindFromDocument(aAccessible);
-    return false;
-  }
+  aAccessible->Init();
 
   aAccessible->SetRoleMapEntry(aRoleMapEntry);
   if (aAccessible->IsElement())
     AddDependentIDsFor(aAccessible);
 
   return true;
 }
 
--- a/accessible/src/generic/DocAccessible.h
+++ b/accessible/src/generic/DocAccessible.h
@@ -66,17 +66,17 @@ public:
   // nsIScrollPositionListener
   virtual void ScrollPositionWillChange(nscoord aX, nscoord aY) {}
   virtual void ScrollPositionDidChange(nscoord aX, nscoord aY);
 
   // nsIDocumentObserver
   NS_DECL_NSIDOCUMENTOBSERVER
 
   // nsAccessNode
-  virtual bool Init();
+  virtual void Init();
   virtual void Shutdown();
   virtual nsIFrame* GetFrame() const;
   virtual nsINode* GetNode() const { return mDocument; }
   virtual nsIDocument* GetDocumentNode() const { return mDocument; }
 
   // Accessible
   virtual mozilla::a11y::ENameValueFlag Name(nsString& aName);
   virtual void Description(nsString& aDescription);
--- a/accessible/src/xul/XULTreeAccessible.cpp
+++ b/accessible/src/xul/XULTreeAccessible.cpp
@@ -1145,24 +1145,21 @@ XULTreeItemAccessible::Name(nsString& aN
 
   GetCellName(mColumn, aName);
   return eNameOK;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // XULTreeItemAccessible: nsAccessNode implementation
 
-bool
+void
 XULTreeItemAccessible::Init()
 {
-  if (!XULTreeItemAccessibleBase::Init())
-    return false;
-
+  XULTreeItemAccessibleBase::Init();
   Name(mCachedName);
-  return true;
 }
 
 void
 XULTreeItemAccessible::Shutdown()
 {
   mColumn = nullptr;
   XULTreeItemAccessibleBase::Shutdown();
 }
--- a/accessible/src/xul/XULTreeAccessible.h
+++ b/accessible/src/xul/XULTreeAccessible.h
@@ -230,17 +230,17 @@ public:
                         nsITreeView* aTreeView, PRInt32 aRow);
 
   // nsISupports and cycle collection
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(XULTreeItemAccessible,
                                            XULTreeItemAccessibleBase)
 
   // nsAccessNode
-  virtual bool Init();
+  virtual void Init();
   virtual void Shutdown();
 
   // Accessible
   virtual ENameValueFlag Name(nsString& aName);
   virtual a11y::role NativeRole();
 
   // XULTreeItemAccessibleBase
   virtual void RowInvalidated(PRInt32 aStartColIdx, PRInt32 aEndColIdx);
--- a/accessible/src/xul/XULTreeGridAccessible.cpp
+++ b/accessible/src/xul/XULTreeGridAccessible.cpp
@@ -774,30 +774,29 @@ XULTreeGridCellAccessible::IsSelected(bo
   NS_ENSURE_SUCCESS(rv, rv);
 
   return selection->IsSelected(mRow, aIsSelected);
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // XULTreeGridCellAccessible: nsAccessNode implementation
 
-bool
+void
 XULTreeGridCellAccessible::Init()
 {
-  if (!LeafAccessible::Init() || !mTreeView)
-    return false;
+  LeafAccessible::Init();
+
+  NS_ASSERTION(mTreeView, "mTreeView is null");
 
   PRInt16 type;
   mColumn->GetType(&type);
   if (type == nsITreeColumn::TYPE_CHECKBOX)
     mTreeView->GetCellValue(mRow, mColumn, mCachedTextEquiv);
   else
     mTreeView->GetCellText(mRow, mColumn, mCachedTextEquiv);
-
-  return true;
 }
 
 bool
 XULTreeGridCellAccessible::IsPrimaryForNode() const
 {
   return false;
 }
 
--- a/accessible/src/xul/XULTreeGridAccessible.h
+++ b/accessible/src/xul/XULTreeGridAccessible.h
@@ -145,17 +145,17 @@ public:
 
   NS_IMETHOD GetActionName(PRUint8 aIndex, nsAString& aName);
   NS_IMETHOD DoAction(PRUint8 aIndex);
 
   // nsIAccessibleTableCell
   NS_DECL_OR_FORWARD_NSIACCESSIBLETABLECELL_WITH_XPCACCESSIBLETABLECELL
 
   // nsAccessNode
-  virtual bool Init();
+  virtual void Init();
   virtual bool IsPrimaryForNode() const;
 
   // Accessible
   virtual void Shutdown();
   virtual ENameValueFlag Name(nsString& aName);
   virtual Accessible* FocusedChild();
   virtual nsresult GetAttributesInternal(nsIPersistentProperties* aAttributes);
   virtual PRInt32 IndexInParent() const;
--- a/b2g/app/nsBrowserApp.cpp
+++ b/b2g/app/nsBrowserApp.cpp
@@ -169,29 +169,22 @@ int main(int argc, char* argv[])
 
   strcpy(++lastSlash, XPCOM_DLL);
 
   int gotCounters;
 #if defined(XP_UNIX)
   struct rusage initialRUsage;
   gotCounters = !getrusage(RUSAGE_SELF, &initialRUsage);
 #elif defined(XP_WIN)
-  // GetProcessIoCounters().ReadOperationCount seems to have little to
-  // do with actual read operations. It reports 0 or 1 at this stage
-  // in the program. Luckily 1 coincides with when prefetch is
-  // enabled. If Windows prefetch didn't happen we can do our own
-  // faster dll preloading.
   IO_COUNTERS ioCounters;
   gotCounters = GetProcessIoCounters(GetCurrentProcess(), &ioCounters);
-  if (gotCounters && !ioCounters.ReadOperationCount)
 #endif
-  {
-      XPCOMGlueEnablePreload();
-  }
 
+  // We do this because of data in bug 771745
+  XPCOMGlueEnablePreload();
 
   rv = XPCOMGlueStartup(exePath);
   if (NS_FAILED(rv)) {
     Output("Couldn't load XPCOM.\n");
     return 255;
   }
   // Reset exePath so that it is the directory name and not the xpcom dll name
   *lastSlash = 0;
--- a/browser/app/nsBrowserApp.cpp
+++ b/browser/app/nsBrowserApp.cpp
@@ -169,48 +169,16 @@ static int do_main(int argc, char* argv[
     int result = XRE_main(argc, argv, appData, 0);
     XRE_FreeAppData(appData);
     return result;
   }
 
   return XRE_main(argc, argv, &sAppData, 0);
 }
 
-#ifdef XP_WIN
-/**
- * Determines if the registry is disabled via the service or not.
- * 
- * @return true if prefetch is disabled
- *         false if prefetch is not disabled or an error occurred.
-*/
-bool IsPrefetchDisabledViaService()
-{
-  // We don't need to return false when we don't have MOZ_MAINTENANCE_SERVICE
-  // defined.  The reason is because another product installed that has it
-  // defined may have cleared our prefetch for us.  There is no known way
-  // to figure out which prefetch files are associated with which apps
-  // because of the prefetch hash.  So we disable all of them that start
-  // with FIREFOX.
-  HKEY baseKey;
-  LONG retCode = RegOpenKeyExW(HKEY_LOCAL_MACHINE, 
-                               L"SOFTWARE\\Mozilla\\MaintenanceService", 0,
-                               KEY_READ | KEY_WOW64_64KEY, &baseKey);
-  if (retCode != ERROR_SUCCESS) {
-    return false;
-  }
-  DWORD disabledValue = 0;
-  DWORD disabledValueSize = sizeof(DWORD);
-  RegQueryValueExW(baseKey, L"FFPrefetchDisabled", 0, NULL,
-                   reinterpret_cast<LPBYTE>(&disabledValue),
-                   &disabledValueSize);
-  RegCloseKey(baseKey);
-  return disabledValue == 1;
-}
-#endif
-
 /* Local implementation of PR_Now, since the executable can't depend on NSPR */
 static PRTime _PR_Now()
 {
 #ifdef XP_WIN
   MOZ_STATIC_ASSERT(sizeof(PRTime) == sizeof(FILETIME), "PRTime must have the same size as FILETIME");
   FILETIME ft;
   GetSystemTimeAsFileTime(&ft);
   PRTime now;
@@ -253,19 +221,18 @@ int main(int argc, char* argv[])
 #if defined(XP_UNIX)
   struct rusage initialRUsage;
   gotCounters = !getrusage(RUSAGE_SELF, &initialRUsage);
 #elif defined(XP_WIN)
   IO_COUNTERS ioCounters;
   gotCounters = GetProcessIoCounters(GetCurrentProcess(), &ioCounters);
 #endif
 
-#if !defined(XP_WIN)
+  // We do this because of data in bug 771745
   XPCOMGlueEnablePreload();
-#endif
 
   rv = XPCOMGlueStartup(exePath);
   if (NS_FAILED(rv)) {
     Output("Couldn't load XPCOM.\n");
     return 255;
   }
   // Reset exePath so that it is the directory name and not the xpcom dll name
   *lastSlash = 0;
--- a/browser/components/shell/src/nsWindowsShellService.cpp
+++ b/browser/components/shell/src/nsWindowsShellService.cpp
@@ -47,21 +47,16 @@
 #define REG_SUCCEEDED(val) \
   (val == ERROR_SUCCESS)
 
 #define REG_FAILED(val) \
   (val != ERROR_SUCCESS)
 
 #define NS_TASKBAR_CONTRACTID "@mozilla.org/windows-taskbar;1"
 
-// We clear the prefetch files one time after the browser is started after
-// 3 minutes.  After this is done once we set a pref so this will never happen
-// again except in updater code.
-#define CLEAR_PREFETCH_TIMEOUT_MS 180000
-
 NS_IMPL_ISUPPORTS2(nsWindowsShellService, nsIWindowsShellService, nsIShellService)
 
 static nsresult
 OpenKeyForReading(HKEY aKeyRoot, const nsAString& aKeyName, HKEY* aKey)
 {
   const nsString &flatName = PromiseFlatString(aKeyName);
 
   DWORD res = ::RegOpenKeyExW(aKeyRoot, flatName.get(), 0, KEY_READ, aKey);
@@ -189,27 +184,16 @@ static SETTING gDDESettings[] = {
   { MAKE_KEY_NAME1("Software\\Classes\\FirefoxURL", SOD) },
 
   // Protocol Handlers
   { MAKE_KEY_NAME1("Software\\Classes\\FTP", SOD) },
   { MAKE_KEY_NAME1("Software\\Classes\\HTTP", SOD) },
   { MAKE_KEY_NAME1("Software\\Classes\\HTTPS", SOD) }
 };
 
-#if defined(MOZ_MAINTENANCE_SERVICE)
-
-#define ONLY_SERVICE_LAUNCHING
-#include "updatehelper.h"
-#include "updatehelper.cpp"
-
-static const char *kPrefetchClearedPref =
-  "app.update.service.lastVersionPrefetchCleared";
-static nsCOMPtr<nsIThread> sThread;
-#endif
-
 nsresult
 GetHelperPath(nsAutoString& aPath)
 {
   nsresult rv;
   nsCOMPtr<nsIProperties> directoryService = 
     do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv);
   NS_ENSURE_SUCCESS(rv, rv);
 
@@ -996,133 +980,22 @@ nsWindowsShellService::SetDesktopBackgro
   NS_ENSURE_SUCCESS(rv, rv);
 
   return regKey->Close();
 }
 
 nsWindowsShellService::nsWindowsShellService() : 
   mCheckedThisSession(false) 
 {
-#if defined(MOZ_MAINTENANCE_SERVICE)
-
-  // Check to make sure the service is installed
-  PRUint32 installed = 0;
-  nsCOMPtr<nsIWindowsRegKey> regKey = 
-    do_CreateInstance("@mozilla.org/windows-registry-key;1");
-  if (!regKey || 
-      NS_FAILED(regKey->Open(nsIWindowsRegKey::ROOT_KEY_LOCAL_MACHINE,
-                             NS_LITERAL_STRING(
-                               "SOFTWARE\\Mozilla\\MaintenanceService"),
-                             nsIWindowsRegKey::ACCESS_READ |
-                             nsIWindowsRegKey::WOW64_64)) ||
-      NS_FAILED(regKey->ReadIntValue(NS_LITERAL_STRING("Installed"), 
-                &installed)) ||
-      !installed) {
-    return;
-  }
-
-  // check to see if we have attempted to do the one time operation of clearing
-  // the prefetch.  We do it once per version upgrade.
-  nsCString lastClearedVer;
-  nsCOMPtr<nsIPrefBranch> prefBranch;
-  nsCOMPtr<nsIPrefService> prefs =
-    do_GetService(NS_PREFSERVICE_CONTRACTID);
-  if (!prefs || 
-      NS_FAILED(prefs->GetBranch(nullptr, getter_AddRefs(prefBranch))) ||
-      (NS_SUCCEEDED(prefBranch->GetCharPref(kPrefetchClearedPref, 
-                                            getter_Copies(lastClearedVer))))) {
-    // If the versions are the same, then bail out early.  We only want to clear
-    // once per version.
-    if (!strcmp(MOZ_APP_VERSION, lastClearedVer.get())) {
-      return;
-    }
-  }
-
-  // In a minute after startup is definitely complete, launch the
-  // service command.
-  mTimer = do_CreateInstance(NS_TIMER_CONTRACTID);
-  if (mTimer) {
-    mTimer->InitWithFuncCallback(
-      nsWindowsShellService::LaunchPrefetchClearCommand, 
-      nullptr, CLEAR_PREFETCH_TIMEOUT_MS, nsITimer::TYPE_ONE_SHOT);
-  }
-#endif
 }
 
 nsWindowsShellService::~nsWindowsShellService()
 {
-#if defined(MOZ_MAINTENANCE_SERVICE)
- if (mTimer) {
-    mTimer->Cancel();
-    mTimer = nullptr;
-  }
-  if (sThread) {
-    sThread->Shutdown();
-    sThread = nullptr;
-  }
-#endif
 }
 
-#if defined(MOZ_MAINTENANCE_SERVICE)
-
-class ClearPrefetchEvent : public nsRunnable {
-public:
-  ClearPrefetchEvent()
-  {
-  }
-
-  NS_IMETHOD Run() 
-  {
-    // Start the service command
-    LPCWSTR updaterServiceArgv[2];
-    updaterServiceArgv[0] = L"MozillaMaintenance";
-    updaterServiceArgv[1] = L"clear-prefetch";
-    // If this command fails, it is not critical as prefetch will be cleared
-    // on the next software update.
-    StartServiceCommand(NS_ARRAY_LENGTH(updaterServiceArgv), 
-                        updaterServiceArgv);
-    return NS_OK;
-  }
-};
-#endif
-
-/**
- * For faster startup we attempt to clear the prefetch if the maintenance
- * service is installed.  Please see the definition of ClearPrefetch()
- * in toolkit/components/maintenanceservice/prefetch.cpp for more info.
- * For now the only application that gets prefetch cleaned is Firefox
- * since we have not done performance checking for other applications.
- * This is done on every update but also there is a one time operation done
- * from within the program for first time installs.
- */ 
-#if defined(MOZ_MAINTENANCE_SERVICE)
-void
-nsWindowsShellService::LaunchPrefetchClearCommand(nsITimer *aTimer, void*)
-{
-  // Make sure we don't call this again from the application, it will be
-  // called on each application update instead.
-  nsCOMPtr<nsIPrefBranch> prefBranch;
-  nsCOMPtr<nsIPrefService> prefs =
-    do_GetService(NS_PREFSERVICE_CONTRACTID);
-  if (prefs) {
-    if (NS_SUCCEEDED(prefs->GetBranch(nullptr, getter_AddRefs(prefBranch)))) {
-      prefBranch->SetCharPref(kPrefetchClearedPref, MOZ_APP_VERSION);
-    }
-  }
-
-  // Starting the sevice can take a bit of time and we don't want to block the 
-  // main thread, so start an event on another thread to handle the operation
-  NS_NewThread(getter_AddRefs(sThread));
-  if (sThread) {
-    nsCOMPtr<nsIRunnable> prefetchEvent = new ClearPrefetchEvent();
-    sThread->Dispatch(prefetchEvent, NS_DISPATCH_NORMAL);
-  }
-}
-#endif
-
 NS_IMETHODIMP
 nsWindowsShellService::OpenApplicationWithURI(nsIFile* aApplication,
                                               const nsACString& aURI)
 {
   nsresult rv;
   nsCOMPtr<nsIProcess> process = 
     do_CreateInstance("@mozilla.org/process/util;1", &rv);
   if (NS_FAILED(rv))
--- a/browser/components/shell/src/nsWindowsShellService.h
+++ b/browser/components/shell/src/nsWindowsShellService.h
@@ -24,16 +24,12 @@ public:
   NS_DECL_NSISHELLSERVICE
   NS_DECL_NSIWINDOWSSHELLSERVICE
 
 protected:
   static nsresult IsDefaultBrowser(bool* aIsDefaultBrowser);
   static bool IsDefaultBrowserVista(bool* aIsDefaultBrowser);
 
 private:
-#if defined(MOZ_MAINTENANCE_SERVICE)
-  static void LaunchPrefetchClearCommand(nsITimer *aTimer, void*);
-  nsCOMPtr<nsITimer> mTimer;
-#endif
   bool      mCheckedThisSession;
 };
 
 #endif // nswindowsshellservice_h____
--- a/build/automationutils.py
+++ b/build/automationutils.py
@@ -421,17 +421,17 @@ def wrapCommand(cmd):
   return cmd
 
 class ShutdownLeakLogger(object):
   """
   Parses the mochitest run log when running a debug build, assigns all leaked
   DOM windows (that are still around after test suite shutdown, despite running
   the GC) to the tests that created them and prints leak statistics.
   """
-  MAX_LEAK_COUNT = 4
+  MAX_LEAK_COUNT = 5
 
   def __init__(self, logger):
     self.logger = logger
     self.tests = []
     self.leakedWindows = {}
     self.leakedDocShells = set()
     self.currentTest = None
     self.seenShutdown = False
--- a/build/mobile/devicemanager.py
+++ b/build/mobile/devicemanager.py
@@ -432,16 +432,18 @@ class DeviceManager:
   @abstractmethod
   def getInfo(self, directive=None):
     """
     Returns information about the device:
     Directive indicates the information you want to get, your choices are:
     os - name of the os
     id - unique id of the device
     uptime - uptime of the device
+    uptimemillis - uptime of the device in milliseconds (NOT supported on all
+                   platforms)
     systime - system time of the device
     screen - screen resolution
     memory - memory stats
     process - list of running processes (same as ps)
     disk - total, free, available bytes on disk
     power - power status (charge, battery temp)
     all - all of them - or call it with no parameters to get all the information
     returns:
--- a/build/mobile/devicemanagerADB.py
+++ b/build/mobile/devicemanagerADB.py
@@ -658,16 +658,18 @@ class DeviceManagerADB(DeviceManager):
   # uptime - uptime of the device
   # systime - system time of the device
   # screen - screen resolution
   # memory - memory stats
   # process - list of running processes (same as ps)
   # disk - total, free, available bytes on disk
   # power - power status (charge, battery temp)
   # all - all of them - or call it with no parameters to get all the information
+  ### Note that uptimemillis is NOT supported, as there is no way to get this
+  ### data from the shell.
   # returns:
   #   success: dict of info strings by directive name
   #   failure: {}
   def getInfo(self, directive="all"):
     ret = {}
     if (directive == "id" or directive == "all"):
       ret["id"] = self.runCmd(["get-serialno"]).stdout.read()
     if (directive == "os" or directive == "all"):
--- a/build/mobile/devicemanagerSUT.py
+++ b/build/mobile/devicemanagerSUT.py
@@ -912,34 +912,35 @@ class DeviceManagerSUT(DeviceManager):
     if (self.debug > 3): print "INFO: rebt- got status back: " + str(status)
     return status
 
   # Returns information about the device:
   # Directive indicates the information you want to get, your choices are:
   # os - name of the os
   # id - unique id of the device
   # uptime - uptime of the device
+  # uptimemillis - uptime of the device in milliseconds
   # systime - system time of the device
   # screen - screen resolution
   # rotation - rotation of the device (in degrees)
   # memory - memory stats
   # process - list of running processes (same as ps)
   # disk - total, free, available bytes on disk
   # power - power status (charge, battery temp)
   # all - all of them - or call it with no parameters to get all the information
   # returns:
   #   success: dict of info strings by directive name
   #   failure: {}
   def getInfo(self, directive=None):
     data = None
     result = {}
     collapseSpaces = re.compile('  +')
 
-    directives = ['os','id','uptime','systime','screen','rotation','memory','process',
-                  'disk','power']
+    directives = ['os','id','uptime','uptimemillis','systime','screen',
+                  'rotation','memory','process','disk','power']
     if (directive in directives):
       directives = [directive]
 
     for d in directives:
       data = self.runCmds([{ 'cmd': 'info ' + d }])
       if (data is None):
         continue
       data = collapseSpaces.sub(' ', data)
--- a/build/mobile/sutagent/android/watcher/WatcherService.java
+++ b/build/mobile/sutagent/android/watcher/WatcherService.java
@@ -45,17 +45,17 @@ import android.widget.Toast;
 
 public class WatcherService extends Service
 {
     String sErrorPrefix = "##Installer Error## ";
     String currentDir = "/";
     String sPingTarget = "";
     long lDelay = 60000;
     long lPeriod = 300000;
-    int nMaxStrikes = 3; // maximum number of tries before we consider network unreachable
+    int nMaxStrikes = 0; // maximum number of tries before we consider network unreachable (0 means don't check)
     boolean bStartSUTAgent = true;
 
     Process    pProc;
     Context myContext = null;
     Timer myTimer = null;
     private PowerManager.WakeLock pwl = null;
     public static final int NOTIFICATION_ID = 1964;
     boolean bInstalling = false;
@@ -106,17 +106,17 @@ public class WatcherService extends Serv
         String sHold = "";
 
         Log.i("Watcher", String.format("Loading settings from %s", sIniFile));
         this.sPingTarget = GetIniData("watcher", "PingTarget", sIniFile, "www.mozilla.org");
         sHold = GetIniData("watcher", "delay", sIniFile, "60000");
         this.lDelay = Long.parseLong(sHold.trim());
         sHold = GetIniData("watcher", "period", sIniFile,"300000");
         this.lPeriod = Long.parseLong(sHold.trim());
-        sHold = GetIniData("watcher", "strikes", sIniFile,"3");
+        sHold = GetIniData("watcher", "strikes", sIniFile,"0");
         this.nMaxStrikes = Integer.parseInt(sHold.trim());
         Log.i("Watcher", String.format("Pinging %s after a delay of %s sec, period of %s sec, max number of failed attempts is %s (if max # of failed attempts is 0, then no checking)",
                                        this.sPingTarget, this.lDelay / 1000.0, this.lPeriod / 1000.0, nMaxStrikes));
 
         sHold = GetIniData("watcher", "StartSUTAgent", sIniFile, "true");
         this.bStartSUTAgent = Boolean.parseBoolean(sHold.trim());
 
         sHold = GetIniData("watcher", "stayon", sIniFile,"0");
--- a/content/base/src/nsDocument.cpp
+++ b/content/base/src/nsDocument.cpp
@@ -8434,18 +8434,17 @@ nsDocument::CreateTouch(nsIDOMWindow* aV
                                       aForce));
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDocument::CreateTouchList(nsIVariant* aPoints,
                             nsIDOMTouchList** aRetVal)
 {
-  nsRefPtr<nsDOMTouchList> retval =
-    new nsDOMTouchList(static_cast<nsIDocument*>(this));
+  nsRefPtr<nsDOMTouchList> retval = new nsDOMTouchList();
   if (aPoints) {
     PRUint16 type;
     aPoints->GetDataType(&type);
     if (type == nsIDataType::VTYPE_INTERFACE ||
         type == nsIDataType::VTYPE_INTERFACE_IS) {
       nsCOMPtr<nsISupports> data;
       aPoints->GetAsISupports(getter_AddRefs(data));
       nsCOMPtr<nsIDOMTouch> point = do_QueryInterface(data);
--- a/content/canvas/src/WebGLContext.cpp
+++ b/content/canvas/src/WebGLContext.cpp
@@ -146,32 +146,34 @@ WebGLContext::WebGLContext()
     mGLMaxTextureUnits = 0;
     mGLMaxTextureSize = 0;
     mGLMaxCubeMapTextureSize = 0;
     mGLMaxTextureImageUnits = 0;
     mGLMaxVertexTextureImageUnits = 0;
     mGLMaxVaryingVectors = 0;
     mGLMaxFragmentUniformVectors = 0;
     mGLMaxVertexUniformVectors = 0;
-    
+
     // See OpenGL ES 2.0.25 spec, 6.2 State Tables, table 6.13
     mPixelStorePackAlignment = 4;
     mPixelStoreUnpackAlignment = 4;
 
     WebGLMemoryMultiReporterWrapper::AddWebGLContext(this);
 
     mAllowRestore = true;
     mContextLossTimerRunning = false;
     mDrawSinceContextLossTimerSet = false;
     mContextRestorer = do_CreateInstance("@mozilla.org/timer;1");
     mContextStatus = ContextStable;
     mContextLostErrorSet = false;
 
     mAlreadyGeneratedWarnings = 0;
     mAlreadyWarnedAboutFakeVertexAttrib0 = false;
+
+    mLastUseIndex = 0;
 }
 
 WebGLContext::~WebGLContext()
 {
     DestroyResourcesAndContext();
     WebGLMemoryMultiReporterWrapper::RemoveWebGLContext(this);
     TerminateContextLossTimer();
     mContextRestorer = nullptr;
@@ -330,17 +332,17 @@ WebGLContext::SetContextOptions(nsIPrope
     mOptions = newOpts;
     return NS_OK;
 }
 
 NS_IMETHODIMP
 WebGLContext::SetDimensions(PRInt32 width, PRInt32 height)
 {
     /*** early success return cases ***/
-  
+
     if (mCanvasElement) {
         mCanvasElement->InvalidateCanvas();
     }
 
     if (gl && mWidth == width && mHeight == height)
         return NS_OK;
 
     // Zero-sized surfaces can cause problems.
@@ -361,21 +363,27 @@ WebGLContext::SetDimensions(PRInt32 widt
         mHeight = gl->OffscreenActualSize().height;
         mResetLayer = true;
 
         gl->ClearSafely();
 
         return NS_OK;
     }
 
-    /*** end of early success return cases ***/
+    /*** End of early success return cases.
+     *** At this point we know that we're not just resizing an existing context,
+     *** we are initializing a new context.
+     ***/
 
-    // At this point we know that the old context is not going to survive, even though we still don't
-    // know if creating the new context will succeed.
-    DestroyResourcesAndContext();
+    // if we exceeded either the global or the per-principal limit for WebGL contexts,
+    // lose the oldest-used context now to free resources. Note that we can't do that
+    // in the WebGLContext constructor as we don't have a canvas element yet there.
+    // Here is the right place to do so, as we are about to create the OpenGL context
+    // and that is what can fail if we already have too many.
+    LoseOldestWebGLContextIfLimitExceeded();
 
     // Get some prefs for some preferred/overriden things
     NS_ENSURE_TRUE(Preferences::GetRootBranch(), NS_ERROR_FAILURE);
 
     bool forceOSMesa =
         Preferences::GetBool("webgl.force_osmesa", false);
 #ifdef XP_WIN
     bool preferEGL =
@@ -624,16 +632,101 @@ WebGLContext::Render(gfxContext *ctx, gf
 
     ctx->NewPath();
     ctx->PixelSnappedRectangleAndSetPattern(gfxRect(0, 0, mWidth, mHeight), pat);
     ctx->Fill();
 
     return NS_OK;
 }
 
+void WebGLContext::LoseOldestWebGLContextIfLimitExceeded()
+{
+#ifdef MOZ_GFX_OPTIMIZE_MOBILE
+    // some mobile devices can't have more than 8 GL contexts overall
+    const size_t kMaxWebGLContextsPerPrincipal = 2;
+    const size_t kMaxWebGLContexts             = 4;
+#else
+    const size_t kMaxWebGLContextsPerPrincipal = 8;
+    const size_t kMaxWebGLContexts             = 16;
+#endif
+    MOZ_ASSERT(kMaxWebGLContextsPerPrincipal < kMaxWebGLContexts);
+
+    // it's important to update the index on a new context before losing old contexts,
+    // otherwise new unused contexts would all have index 0 and we couldn't distinguish older ones
+    // when choosing which one to lose first.
+    UpdateLastUseIndex();
+
+    WebGLMemoryMultiReporterWrapper::ContextsArrayType &contexts
+      = WebGLMemoryMultiReporterWrapper::Contexts();
+
+    // quick exit path, should cover a majority of cases
+    if (contexts.Length() <= kMaxWebGLContextsPerPrincipal) {
+        return;
+    }
+
+    // note that here by "context" we mean "non-lost context". See the check for
+    // IsContextLost() below. Indeed, the point of this function is to maybe lose
+    // some currently non-lost context.
+
+    uint64_t oldestIndex = UINT64_MAX;
+    uint64_t oldestIndexThisPrincipal = UINT64_MAX;
+    const WebGLContext *oldestContext = nsnull;
+    const WebGLContext *oldestContextThisPrincipal = nsnull;
+    size_t numContexts = 0;
+    size_t numContextsThisPrincipal = 0;
+
+    for(size_t i = 0; i < contexts.Length(); ++i) {
+
+        // don't want to lose ourselves.
+        if (contexts[i] == this)
+            continue;
+
+        if (contexts[i]->IsContextLost())
+            continue;
+
+        if (!contexts[i]->GetCanvas()) {
+            // Zombie context: the canvas is already destroyed, but something else
+            // (typically the compositor) is still holding on to the context.
+            // Killing zombies is a no-brainer.
+            const_cast<WebGLContext*>(contexts[i])->LoseContext();
+            continue;
+        }
+
+        numContexts++;
+        if (contexts[i]->mLastUseIndex < oldestIndex) {
+            oldestIndex = contexts[i]->mLastUseIndex;
+            oldestContext = contexts[i];
+        }
+
+        nsIPrincipal *ourPrincipal = GetCanvas()->NodePrincipal();
+        nsIPrincipal *theirPrincipal = contexts[i]->GetCanvas()->NodePrincipal();
+        bool samePrincipal;
+        nsresult rv = ourPrincipal->Equals(theirPrincipal, &samePrincipal);
+        if (NS_SUCCEEDED(rv) && samePrincipal) {
+            numContextsThisPrincipal++;
+            if (contexts[i]->mLastUseIndex < oldestIndexThisPrincipal) {
+                oldestIndexThisPrincipal = contexts[i]->mLastUseIndex;
+                oldestContextThisPrincipal = contexts[i];
+            }
+        }
+    }
+
+    if (numContextsThisPrincipal > kMaxWebGLContextsPerPrincipal) {
+        GenerateWarning("Exceeded %d live WebGL contexts for this principal, losing the "
+                        "least recently used one.", kMaxWebGLContextsPerPrincipal);
+        MOZ_ASSERT(oldestContextThisPrincipal); // if we reach this point, this can't be null
+        const_cast<WebGLContext*>(oldestContextThisPrincipal)->LoseContext();
+    } else if (numContexts > kMaxWebGLContexts) {
+        GenerateWarning("Exceeded %d live WebGL contexts, losing the least recently used one.",
+                        kMaxWebGLContexts);
+        MOZ_ASSERT(oldestContext); // if we reach this point, this can't be null
+        const_cast<WebGLContext*>(oldestContext)->LoseContext();
+    }
+}
+
 NS_IMETHODIMP
 WebGLContext::GetInputStream(const char* aMimeType,
                              const PRUnichar* aEncoderOptions,
                              nsIInputStream **aStream)
 {
     NS_ASSERTION(gl, "GetInputStream on invalid context?");
     if (!gl)
         return NS_ERROR_FAILURE;
@@ -686,16 +779,31 @@ WebGLContext::GetInputStream(const char*
 }
 
 NS_IMETHODIMP
 WebGLContext::GetThebesSurface(gfxASurface **surface)
 {
     return NS_ERROR_NOT_AVAILABLE;
 }
 
+void WebGLContext::UpdateLastUseIndex()
+{
+    static CheckedInt<uint64_t> sIndex = 0;
+
+    sIndex++;
+
+    // should never happen with 64-bit; trying to handle this would be riskier than
+    // not handling it as the handler code would never get exercised.
+    if (!sIndex.isValid()) {
+        NS_RUNTIMEABORT("Can't believe it's been 2^64 transactions already!");
+    }
+
+    mLastUseIndex = sIndex.value();
+}
+
 static PRUint8 gWebGLLayerUserData;
 
 namespace mozilla {
 
 class WebGLContextUserData : public LayerUserData {
 public:
     WebGLContextUserData(nsHTMLCanvasElement *aContent)
     : mContent(aContent) {}
@@ -706,16 +814,18 @@ public:
   static void DidTransactionCallback(void* aData)
   {
     WebGLContextUserData *userdata = static_cast<WebGLContextUserData*>(aData);
     nsHTMLCanvasElement *canvas = userdata->mContent;
     WebGLContext *context = static_cast<WebGLContext*>(canvas->GetContextAtIndex(0));
 
     context->mBackbufferClearingStatus = BackbufferClearingStatus::NotClearedSinceLastPresented;
     canvas->MarkContextClean();
+
+    context->UpdateLastUseIndex();
   }
 
 private:
   nsRefPtr<nsHTMLCanvasElement> mContent;
 };
 
 } // end namespace mozilla
 
--- a/content/canvas/src/WebGLContext.h
+++ b/content/canvas/src/WebGLContext.h
@@ -1356,16 +1356,21 @@ protected:
 
     int mAlreadyGeneratedWarnings;
     bool mAlreadyWarnedAboutFakeVertexAttrib0;
 
     bool ShouldGenerateWarnings() const {
         return mAlreadyGeneratedWarnings < 32;
     }
 
+    uint64_t mLastUseIndex;
+
+    void LoseOldestWebGLContextIfLimitExceeded();
+    void UpdateLastUseIndex();
+
 #ifdef XP_MACOSX
     // see bug 713305. This RAII helper guarantees that we're on the discrete GPU, during its lifetime
     // Debouncing note: we don't want to switch GPUs too frequently, so try to not create and destroy
     // these objects at high frequency. Having WebGLContext's hold one such object seems fine,
     // because WebGLContext objects only go away during GC, which shouldn't happen too frequently.
     // If in the future GC becomes much more frequent, we may have to revisit then (maybe use a timer).
     ForceDiscreteGPUHelperCGL mForceDiscreteGPUHelper;
 #endif
@@ -3169,23 +3174,25 @@ class WebGLMemoryMultiReporterWrapper
     ~WebGLMemoryMultiReporterWrapper();
     static WebGLMemoryMultiReporterWrapper* sUniqueInstance;
 
     // here we store plain pointers, not RefPtrs: we don't want the 
     // WebGLMemoryMultiReporterWrapper unique instance to keep alive all		
     // WebGLContexts ever created.
     typedef nsTArray<const WebGLContext*> ContextsArrayType;
     ContextsArrayType mContexts;
-    
+
     nsCOMPtr<nsIMemoryMultiReporter> mReporter;
 
     static WebGLMemoryMultiReporterWrapper* UniqueInstance();
 
     static ContextsArrayType & Contexts() { return UniqueInstance()->mContexts; }
 
+    friend class WebGLContext;
+
   public:
 
     static void AddWebGLContext(const WebGLContext* c) {
         Contexts().AppendElement(c);
     }
 
     static void RemoveWebGLContext(const WebGLContext* c) {
         ContextsArrayType & contexts = Contexts();
--- a/content/canvas/src/WebGLContextGL.cpp
+++ b/content/canvas/src/WebGLContextGL.cpp
@@ -4499,16 +4499,17 @@ WebGLContext::name##_base(WebGLUniformLo
                                      " (since this uniform is not an array uniform)," \
                                      " got an array of length %d",              \
                                  #name,                                         \
                                  expectedElemSize,                           \
                                  arrayLength);                                  \
     }                                                                           \
                                                                                 \
     uint32_t numElementsToUpload = NS_MIN(info.arraySize, arrayLength/expectedElemSize);     \
+    MakeContextCurrent();                                                       \
     gl->f##name(location, numElementsToUpload, data);    \
 }
 
 #define SIMPLE_MATRIX_METHOD_UNIFORM(name, dim)                                 \
 NS_IMETHODIMP                                                                   \
 WebGLContext::name(nsIWebGLUniformLocation* aLocation, bool aTranspose,         \
                    const JS::Value& aValue, JSContext* aCx)                     \
 {                                                                               \
--- a/content/events/src/nsDOMTouchEvent.cpp
+++ b/content/events/src/nsDOMTouchEvent.cpp
@@ -123,56 +123,52 @@ nsDOMTouch::Equals(nsIDOMTouch* aTouch)
   aTouch->GetRadiusY(&radiusY);
   return mRefPoint != aTouch->mRefPoint ||
          (mForce != force) ||
          (mRotationAngle != orientation) ||
          (mRadius.x != radiusX) || (mRadius.y != radiusY);
 }
 
 // TouchList
+nsDOMTouchList::nsDOMTouchList(nsTArray<nsCOMPtr<nsIDOMTouch> > &aTouches)
+{
+  mPoints.AppendElements(aTouches);
+}
 
 DOMCI_DATA(TouchList, nsDOMTouchList)
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(nsDOMTouchList)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsDOMTouchList)
-  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY(nsISupports)
   NS_INTERFACE_MAP_ENTRY(nsIDOMTouchList)
   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(TouchList)
 NS_INTERFACE_MAP_END
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsDOMTouchList)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSTARRAY_OF_NSCOMPTR(mPoints)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mParent)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
-NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsDOMTouchList)
-  NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
-NS_IMPL_CYCLE_COLLECTION_TRACE_END
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsDOMTouchList)
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSTARRAY(mPoints)
-  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mParent)
-  NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsDOMTouchList)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsDOMTouchList)
 
 NS_IMETHODIMP
 nsDOMTouchList::GetLength(PRUint32* aLength)
 {
   *aLength = mPoints.Length();
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDOMTouchList::Item(PRUint32 aIndex, nsIDOMTouch** aRetVal)
 {
-  NS_IF_ADDREF(*aRetVal = nsDOMTouchList::GetItemAt(aIndex));
+  NS_IF_ADDREF(*aRetVal = mPoints.SafeElementAt(aIndex, nsnull));
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDOMTouchList::IdentifiedTouch(PRInt32 aIdentifier, nsIDOMTouch** aRetVal)
 {
   *aRetVal = nullptr;
   for (PRUint32 i = 0; i < mPoints.Length(); ++i) {
@@ -182,22 +178,16 @@ nsDOMTouchList::IdentifiedTouch(PRInt32 
         aIdentifier == identifier) {
       point.swap(*aRetVal);
       break;
     }
   }
   return NS_OK;
 }
 
-nsIDOMTouch*
-nsDOMTouchList::GetItemAt(PRUint32 aIndex)
-{
-  return mPoints.SafeElementAt(aIndex, nullptr);
-}
-
 // TouchEvent
 
 nsDOMTouchEvent::nsDOMTouchEvent(nsPresContext* aPresContext,
                                  nsTouchEvent* aEvent)
   : nsDOMUIEvent(aPresContext, aEvent ? aEvent :
                                         new nsTouchEvent(false, 0, nullptr))
 {
   if (aEvent) {
@@ -292,21 +282,19 @@ nsDOMTouchEvent::GetTouches(nsIDOMTouchL
     // for touchend events, remove any changed touches from the touches array
     nsTArray<nsCOMPtr<nsIDOMTouch> > unchangedTouches;
     nsTArray<nsCOMPtr<nsIDOMTouch> > touches = touchEvent->touches;
     for (PRUint32 i = 0; i < touches.Length(); ++i) {
       if (!touches[i]->mChanged) {
         unchangedTouches.AppendElement(touches[i]);
       }
     }
-    t = new nsDOMTouchList(static_cast<nsIDOMTouchEvent*>(this),
-                           unchangedTouches);
+    t = new nsDOMTouchList(unchangedTouches);
   } else {
-    t = new nsDOMTouchList(static_cast<nsIDOMTouchEvent*>(this),
-                           touchEvent->touches);
+    t = new nsDOMTouchList(touchEvent->touches);
   }
   mTouches = t;
   return CallQueryInterface(mTouches, aTouches);
 }
 
 NS_IMETHODIMP
 nsDOMTouchEvent::GetTargetTouches(nsIDOMTouchList** aTargetTouches)
 {
@@ -326,18 +314,17 @@ nsDOMTouchEvent::GetTargetTouches(nsIDOM
     if ((mEvent->message != NS_TOUCH_END &&
          mEvent->message != NS_TOUCH_CANCEL) || !touches[i]->mChanged) {
       nsIDOMEventTarget* targetPtr = touches[i]->GetTarget();
       if (targetPtr == mEvent->target) {
         targetTouches.AppendElement(touches[i]);
       }
     }
   }
-  mTargetTouches = new nsDOMTouchList(static_cast<nsIDOMTouchEvent*>(this),
-                                      targetTouches);
+  mTargetTouches = new nsDOMTouchList(targetTouches);
   return CallQueryInterface(mTargetTouches, aTargetTouches);
 }
 
 NS_IMETHODIMP
 nsDOMTouchEvent::GetChangedTouches(nsIDOMTouchList** aChangedTouches)
 {
   NS_ENSURE_ARG_POINTER(aChangedTouches);
   NS_ENSURE_STATE(mEvent);
@@ -349,18 +336,17 @@ nsDOMTouchEvent::GetChangedTouches(nsIDO
   nsTArray<nsCOMPtr<nsIDOMTouch> > changedTouches;
   nsTouchEvent* touchEvent = static_cast<nsTouchEvent*>(mEvent);
   nsTArray<nsCOMPtr<nsIDOMTouch> > touches = touchEvent->touches;
   for (PRUint32 i = 0; i < touches.Length(); ++i) {
     if (touches[i]->mChanged) {
       changedTouches.AppendElement(touches[i]);
     }
   }
-  mChangedTouches = new nsDOMTouchList(static_cast<nsIDOMTouchEvent*>(this),
-                                       changedTouches);
+  mChangedTouches = new nsDOMTouchList(changedTouches);
   return CallQueryInterface(mChangedTouches, aChangedTouches);
 }
 
 NS_IMETHODIMP
 nsDOMTouchEvent::GetAltKey(bool* aAltKey)
 {
   *aAltKey = static_cast<nsInputEvent*>(mEvent)->IsAlt();
   return NS_OK;
--- a/content/events/src/nsDOMTouchEvent.h
+++ b/content/events/src/nsDOMTouchEvent.h
@@ -4,18 +4,16 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 #ifndef nsDOMTouchEvent_h_
 #define nsDOMTouchEvent_h_
 
 #include "nsDOMUIEvent.h"
 #include "nsIDOMTouchEvent.h"
 #include "nsString.h"
 #include "nsTArray.h"
-#include "nsIDocument.h"
-#include "dombindings.h"
 #include "mozilla/Attributes.h"
 
 class nsDOMTouch MOZ_FINAL : public nsIDOMTouch
 {
 public:
   nsDOMTouch(nsIDOMEventTarget* aTarget,
              PRInt32 aIdentifier,
              PRInt32 aPageX,
@@ -94,56 +92,38 @@ public:
   nsIntPoint mScreenPoint;
   nsIntPoint mRadius;
   float mRotationAngle;
   float mForce;
 protected:
   bool mPointsInitialized;
 };
 
-class nsDOMTouchList MOZ_FINAL : public nsIDOMTouchList,
-                                 public nsWrapperCache
+class nsDOMTouchList : public nsIDOMTouchList
 {
 public:
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
-  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(nsDOMTouchList)
+  NS_DECL_CYCLE_COLLECTION_CLASS(nsDOMTouchList)
   NS_DECL_NSIDOMTOUCHLIST
 
-  nsDOMTouchList(nsISupports *aParent) : mParent(aParent)
-  {
-    SetIsDOMBinding();
-  }
-  nsDOMTouchList(nsISupports *aParent,
-                 nsTArray<nsCOMPtr<nsIDOMTouch> > &aTouches)
-   : mPoints(aTouches),
-     mParent(aParent)
-  {
-    SetIsDOMBinding();
-  }
-
-  virtual JSObject* WrapObject(JSContext *cx, JSObject *scope,
-                               bool *triedToWrap)
-  {
-    return mozilla::dom::binding::TouchList::create(cx, scope, this,
-                                                    triedToWrap);
-  }
-
-  nsISupports *GetParentObject()
-  {
-    return mParent;
-  }
+  nsDOMTouchList() { }
+  nsDOMTouchList(nsTArray<nsCOMPtr<nsIDOMTouch> > &aTouches);
 
   void Append(nsIDOMTouch* aPoint)
   {
     mPoints.AppendElement(aPoint);
   }
 
+  nsIDOMTouch* GetItemAt(PRUint32 aIndex)
+  {
+    return mPoints.SafeElementAt(aIndex, nsnull);
+  }
+
 protected:
   nsTArray<nsCOMPtr<nsIDOMTouch> > mPoints;
-  nsCOMPtr<nsISupports> mParent;
 };
 
 class nsDOMTouchEvent : public nsDOMUIEvent,
                         public nsIDOMTouchEvent
 {
 public:
   nsDOMTouchEvent(nsPresContext* aPresContext, nsTouchEvent* aEvent);
   virtual ~nsDOMTouchEvent();
--- a/content/html/content/src/nsGenericHTMLElement.cpp
+++ b/content/html/content/src/nsGenericHTMLElement.cpp
@@ -483,26 +483,25 @@ nsGenericHTMLElement::GetOffsetRect(nsRe
 
   Element* docElement = GetCurrentDoc()->GetRootElement();
   nsIContent* content = frame->GetContent();
 
   if (content && (content->IsHTML(nsGkAtoms::body) || content == docElement)) {
     parent = frame;
   }
   else {
-    const bool isPositioned = frame->GetStyleDisplay()->IsPositioned();
-    const bool isAbsolutelyPositioned =
-      frame->GetStyleDisplay()->IsAbsolutelyPositioned();
+    const bool isPositioned = frame->IsPositioned();
+    const bool isAbsolutelyPositioned = frame->IsAbsolutelyPositioned();
     origin += frame->GetPositionIgnoringScrolling();
 
     for ( ; parent ; parent = parent->GetParent()) {
       content = parent->GetContent();
 
       // Stop at the first ancestor that is positioned.
-      if (parent->GetStyleDisplay()->IsPositioned()) {
+      if (parent->IsPositioned()) {
         *aOffsetParent = content;
         NS_IF_ADDREF(*aOffsetParent);
         break;
       }
 
       // Add the parent's origin to our own to get to the
       // right coordinate system.
       const bool isOffsetParent = !isPositioned && IsOffsetParent(parent);
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -11376,17 +11376,17 @@ nsDocShell::GetIsContent(bool *aIsConten
 NS_IMETHODIMP
 nsDocShell::GetExtendedOrigin(nsIURI *aUri, nsACString &aResult)
 {
     bool isInBrowserElement;
     GetIsInBrowserElement(&isInBrowserElement);
 
     nsCOMPtr<nsIScriptSecurityManager> ssmgr =
       do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID);
-    NS_ENSURE_TRUE(ssmgr, false);
+    NS_ENSURE_TRUE(ssmgr, NS_ERROR_FAILURE);
 
     return ssmgr->GetExtendedOrigin(aUri, mAppId, isInBrowserElement, aResult);
 }
 
 
 bool
 nsDocShell::IsOKToLoadURI(nsIURI* aURI)
 {
--- a/dom/alarm/AlarmDB.jsm
+++ b/dom/alarm/AlarmDB.jsm
@@ -74,52 +74,81 @@ AlarmDB.prototype = {
       aSuccessCb, 
       aErrorCb
     );
   },
 
   /**
    * @param aId
    *        The ID of record to be removed.
+   * @param aManifestURL
+   *        The manifest URL of the app that alarm belongs to.
+   *        If null, directly remove the ID record; otherwise,
+   *        need to check if the alarm belongs to this app.
    * @param aSuccessCb
    *        Callback function to invoke with result.
    * @param aErrorCb [optional]
    *        Callback function to invoke when there was an error.
    */
-  remove: function remove(aId, aSuccessCb, aErrorCb) {
+  remove: function remove(aId, aManifestURL, aSuccessCb, aErrorCb) {
     debug("remove()");
 
     this.newTxn(
       "readwrite", 
       function txnCb(aTxn, aStore) {
         debug("Going to remove " + aId);
-        aStore.delete(aId);
+
+        // Look up the existing record and compare the manifestURL
+        // to see if the alarm to be removed belongs to this app.
+        aStore.get(aId).onsuccess = function doRemove(aEvent) {
+          let alarm = aEvent.target.result;
+
+          if (!alarm) {
+            debug("Alarm doesn't exist. No need to remove it.");
+            return;
+          }
+
+          if (aManifestURL && aManifestURL != alarm.manifestURL) {
+            debug("Cannot remove the alarm added by other apps.");
+            return;
+          }
+
+          aStore.delete(aId);
+        };
       }, 
       aSuccessCb, 
       aErrorCb
     );
   },
 
   /**
+   * @param aManifestURL
+   *        The manifest URL of the app that alarms belong to.
+   *        If null, directly return all alarms; otherwise,
+   *        only return the alarms that belong to this app.
    * @param aSuccessCb
    *        Callback function to invoke with result array.
    * @param aErrorCb [optional]
    *        Callback function to invoke when there was an error.
    */
-  getAll: function getAll(aSuccessCb, aErrorCb) {
+  getAll: function getAll(aManifestURL, aSuccessCb, aErrorCb) {
     debug("getAll()");
 
     this.newTxn(
       "readonly", 
       function txnCb(aTxn, aStore) {
         if (!aTxn.result)
-          aTxn.result = {};
+          aTxn.result = [];
 
         aStore.mozGetAll().onsuccess = function setTxnResult(aEvent) {
-          aTxn.result = aEvent.target.result;
+          aEvent.target.result.forEach(function addAlarm(aAlarm) {
+            if (!aManifestURL || aManifestURL == aAlarm.manifestURL)
+              aTxn.result.push(aAlarm);
+          });
+
           debug("Request successful. Record count: " + aTxn.result.length);
         };
       }, 
       aSuccessCb, 
       aErrorCb
     );
   }
 };
--- a/dom/alarm/AlarmService.jsm
+++ b/dom/alarm/AlarmService.jsm
@@ -75,16 +75,17 @@ let AlarmService = {
   receiveMessage: function receiveMessage(aMessage) {
     debug("receiveMessage(): " + aMessage.name);
 
     let mm = aMessage.target.QueryInterface(Ci.nsIFrameMessageManager);
     let json = aMessage.json;
     switch (aMessage.name) {
       case "AlarmsManager:GetAll":
         this._db.getAll(
+          json.manifestURL,
           function getAllSuccessCb(aAlarms) {
             debug("Callback after getting alarms from database: " + JSON.stringify(aAlarms));
             this._sendAsyncMessage(mm, "GetAll", true, json.requestId, aAlarms);
           }.bind(this),
           function getAllErrorCb(aErrorMsg) {
             this._sendAsyncMessage(mm, "GetAll", false, json.requestId, aErrorMsg);
           }.bind(this)
         );
@@ -145,30 +146,34 @@ let AlarmService = {
             this._sendAsyncMessage(mm, "Add", false, json.requestId, aErrorMsg);
           }.bind(this)
         );
         break;
 
       case "AlarmsManager:Remove":
         this._removeAlarmFromDb(
           json.id,
+          json.manifestURL,
           function removeSuccessCb() {
             debug("Callback after removing alarm from database.");
 
             // if there is no alarm being set
             if (!this._currentAlarm) {
               this._debugCurrentAlarm();
               return;
             }
 
             // check if the alarm to be removed is in the queue
+            // by ID and whether it belongs to the requesting app
             let alarmQueue = this._alarmQueue;
-            if (this._currentAlarm.id != json.id) {
+            if (this._currentAlarm.id != json.id || 
+                this._currentAlarm.manifestURL != json.manifestURL) {
               for (let i = 0; i < alarmQueue.length; i++) {
-                if (alarmQueue[i].id == json.id) {
+                if (alarmQueue[i].id == json.id && 
+                    alarmQueue[i].manifestURL == json.manifestURL) {
                   alarmQueue.splice(i, 1);
                   break;
                 }
               }
               this._debugCurrentAlarm();
               return;
             }
 
@@ -219,29 +224,30 @@ let AlarmService = {
       default:
         throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
         break;
     }
 
     aMessageManager.sendAsyncMessage("AlarmsManager:" + aMessageName + ":Return:" + (aSuccess ? "OK" : "KO"), json);
   },
 
-  _removeAlarmFromDb: function _removeAlarmFromDb(aId, aRemoveSuccessCb) {
+  _removeAlarmFromDb: function _removeAlarmFromDb(aId, aManifestURL, aRemoveSuccessCb) {
     debug("_removeAlarmFromDb()");
 
     // If the aRemoveSuccessCb is undefined or null, set a 
     // dummy callback for it which is needed for _db.remove()
     if (!aRemoveSuccessCb) {
       aRemoveSuccessCb = function removeSuccessCb() {
         debug("Remove alarm from DB successfully.");
       };
     }
 
     this._db.remove(
       aId,
+      aManifestURL,
       aRemoveSuccessCb,
       function removeErrorCb(aErrorMsg) {
         throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
       }
     );
   },
 
   _fireSystemMessage: function _fireSystemMessage(aAlarm) {
@@ -250,31 +256,31 @@ let AlarmService = {
     messenger.sendMessage("alarm", aAlarm, manifestURI);
   },
 
   _onAlarmFired: function _onAlarmFired() {
     debug("_onAlarmFired()");
 
     if (this._currentAlarm) {
       this._fireSystemMessage(this._currentAlarm);
-      this._removeAlarmFromDb(this._currentAlarm.id);
+      this._removeAlarmFromDb(this._currentAlarm.id, null);
       this._currentAlarm = null;
     }
 
     // Reset the next alarm from the queue.
     let alarmQueue = this._alarmQueue;
     while (alarmQueue.length > 0) {
       let nextAlarm = alarmQueue.shift();
       let nextAlarmTime = this._getAlarmTime(nextAlarm);
 
       // If the next alarm has been expired, directly 
       // fire system message for it instead of setting it.
       if (nextAlarmTime <= Date.now()) {
         this._fireSystemMessage(nextAlarm);
-        this._removeAlarmFromDb(nextAlarm.id);
+        this._removeAlarmFromDb(nextAlarm.id, null);
       } else {
         this._currentAlarm = nextAlarm;
         break;
       }
     }
     this._debugCurrentAlarm();
   },
 
@@ -284,16 +290,17 @@ let AlarmService = {
     this._currentTimezoneOffset = aTimezoneOffset;
     this._restoreAlarmsFromDb();
   },
 
   _restoreAlarmsFromDb: function _restoreAlarmsFromDb() {
     debug("_restoreAlarmsFromDb()");
 
     this._db.getAll(
+      null,
       function getAllSuccessCb(aAlarms) {
         debug("Callback after getting alarms from database: " + JSON.stringify(aAlarms));
 
         // clear any alarms set or queued in the cache
         let alarmQueue = this._alarmQueue;
         alarmQueue.length = 0;
         this._currentAlarm = null;
         
--- a/dom/alarm/AlarmsManager.js
+++ b/dom/alarm/AlarmsManager.js
@@ -73,27 +73,27 @@ AlarmsManager.prototype = {
     return request;
   },
 
   remove: function remove(aId) {
     debug("remove()");
 
     return this._cpmm.sendSyncMessage(
       "AlarmsManager:Remove", 
-      { id: aId }
+      { id: aId, manifestURL: this._manifestURL }
     );
   },
 
   getAll: function getAll() {
     debug("getAll()");
 
     let request = this.createRequest();
     this._cpmm.sendAsyncMessage(
       "AlarmsManager:GetAll", 
-      { requestId: this.getRequestId(request) }
+      { requestId: this.getRequestId(request), manifestURL: this._manifestURL }
     );
     return request;
   },
 
   receiveMessage: function receiveMessage(aMessage) {
     debug("receiveMessage(): " + aMessage.name);
 
     let json = aMessage.json;
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -415,17 +415,16 @@
 
 #include "nsIImageDocument.h"
 
 // Storage includes
 #include "nsDOMStorage.h"
 
 // Device Storage
 #include "nsIDOMDeviceStorage.h"
-#include "nsIDOMDeviceStorageChangeEvent.h"
 #include "nsIDOMDeviceStorageCursor.h"
 
 // Drag and drop
 #include "nsIDOMDataTransfer.h"
 
 // Geolocation
 #include "nsIDOMGeoGeolocation.h"
 #include "nsIDOMGeoPosition.h"
@@ -1435,19 +1434,16 @@ static nsDOMClassInfoData sClassInfoData
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 
   NS_DEFINE_CLASSINFO_DATA(MessageEvent, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 
   NS_DEFINE_CLASSINFO_DATA(DeviceStorage, nsEventTargetSH,
                            EVENTTARGET_SCRIPTABLE_FLAGS)
 
-  NS_DEFINE_CLASSINFO_DATA(DeviceStorageChangeEvent, nsDOMGenericSH,
-                           DOM_DEFAULT_SCRIPTABLE_FLAGS)
-
   NS_DEFINE_CLASSINFO_DATA(DeviceStorageCursor, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 
   NS_DEFINE_CLASSINFO_DATA(GeoGeolocation, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   
   NS_DEFINE_CLASSINFO_DATA(GeoPosition, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS) 
@@ -1628,18 +1624,18 @@ static nsDOMClassInfoData sClassInfoData
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(IDBVersionChangeEvent, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(IDBOpenDBRequest, IDBEventTargetSH,
                            IDBEVENTTARGET_SCRIPTABLE_FLAGS)
 
   NS_DEFINE_CLASSINFO_DATA(Touch, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
-  NS_DEFINE_CLASSINFO_DATA(TouchList, nsDOMGenericSH,
-                           DOM_DEFAULT_SCRIPTABLE_FLAGS)
+  NS_DEFINE_CLASSINFO_DATA(TouchList, nsDOMTouchListSH,
+                           ARRAY_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(TouchEvent, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 
   NS_DEFINE_CLASSINFO_DATA(MozCSSKeyframeRule, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(MozCSSKeyframesRule, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 
@@ -4038,21 +4034,16 @@ nsDOMClassInfo::Init()
     DOM_CLASSINFO_EVENT_MAP_ENTRIES
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(DeviceStorage, nsIDOMDeviceStorage)
      DOM_CLASSINFO_MAP_ENTRY(nsIDOMDeviceStorage)
      DOM_CLASSINFO_MAP_ENTRY(nsIDOMEventTarget)
   DOM_CLASSINFO_MAP_END
 
-  DOM_CLASSINFO_MAP_BEGIN(DeviceStorageChangeEvent, nsIDOMDeviceStorageChangeEvent)
-     DOM_CLASSINFO_MAP_ENTRY(nsIDOMDeviceStorageChangeEvent)
-     DOM_CLASSINFO_MAP_ENTRY(nsIDOMEvent)
-  DOM_CLASSINFO_MAP_END
-
   DOM_CLASSINFO_MAP_BEGIN(DeviceStorageCursor, nsIDOMDeviceStorageCursor)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMDeviceStorageCursor)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMDOMRequest)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMEventTarget)
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(GeoGeolocation, nsIDOMGeoGeolocation)
      DOM_CLASSINFO_MAP_ENTRY(nsIDOMGeoGeolocation)
@@ -4882,16 +4873,24 @@ nsDOMClassInfo::NewResolve(nsIXPConnectW
 {
   if (id == sConstructor_id && !(flags & JSRESOLVE_ASSIGNING)) {
     return ResolveConstructor(cx, obj, objp);
   }
 
   return NS_OK;
 }
 
+nsISupports*
+nsDOMTouchListSH::GetItemAt(nsISupports *aNative, PRUint32 aIndex,
+                            nsWrapperCache **aCache, nsresult *aResult)
+{
+  nsDOMTouchList* list = static_cast<nsDOMTouchList*>(aNative);
+  return list->GetItemAt(aIndex);
+}
+
 NS_IMETHODIMP
 nsDOMClassInfo::Convert(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
                         JSObject *obj, PRUint32 type, jsval *vp,
                         bool *_retval)
 {
   NS_WARNING("nsDOMClassInfo::Convert Don't call me!");
 
   return NS_ERROR_UNEXPECTED;
--- a/dom/base/nsDOMClassInfo.h
+++ b/dom/base/nsDOMClassInfo.h
@@ -1211,16 +1211,37 @@ protected:
 
 public:
   static nsIClassInfo *doCreate(nsDOMClassInfoData* aData)
   {
     return new nsCSSRuleListSH(aData);
   }
 };
 
+class nsDOMTouchListSH : public nsArraySH
+{
+  protected:
+  nsDOMTouchListSH(nsDOMClassInfoData* aData) : nsArraySH(aData)
+  {
+  }
+
+  virtual ~nsDOMTouchListSH()
+  {
+  }
+
+  virtual nsISupports* GetItemAt(nsISupports *aNative, PRUint32 aIndex,
+                                 nsWrapperCache **aCache, nsresult *aResult);
+
+  public:
+  static nsIClassInfo* doCreate(nsDOMClassInfoData* aData)
+  {
+    return new nsDOMTouchListSH(aData);
+  }
+};
+
 #ifdef MOZ_XUL
 // TreeColumns helper
 
 class nsTreeColumnsSH : public nsNamedArraySH
 {
 protected:
   nsTreeColumnsSH(nsDOMClassInfoData* aData) : nsNamedArraySH(aData)
   {
--- a/dom/base/nsDOMClassInfoClasses.h
+++ b/dom/base/nsDOMClassInfoClasses.h
@@ -380,17 +380,16 @@ DOMCI_CLASS(ModalContentWindow)
 // Data Events
 DOMCI_CLASS(DataContainerEvent)
 
 // event used for cross-domain message-passing and for server-sent events in
 // HTML5
 DOMCI_CLASS(MessageEvent)
 
 DOMCI_CLASS(DeviceStorage)
-DOMCI_CLASS(DeviceStorageChangeEvent)
 DOMCI_CLASS(DeviceStorageCursor)
 
 // Geolocation
 DOMCI_CLASS(GeoGeolocation)
 DOMCI_CLASS(GeoPosition)
 DOMCI_CLASS(GeoPositionCoords)
 DOMCI_CLASS(GeoPositionError)
 
--- a/dom/base/nsHistory.cpp
+++ b/dom/base/nsHistory.cpp
@@ -234,18 +234,18 @@ nsHistory::Go(PRInt32 aDelta)
   NS_ENSURE_TRUE(session_history, NS_ERROR_FAILURE);
 
   // QI SHistory to nsIWebNavigation
   nsCOMPtr<nsIWebNavigation> webnav(do_QueryInterface(session_history));
   NS_ENSURE_TRUE(webnav, NS_ERROR_FAILURE);
 
   PRInt32 curIndex=-1;
   PRInt32 len = 0;
-  nsresult rv = session_history->GetIndex(&curIndex);
-  rv = session_history->GetCount(&len);
+  session_history->GetIndex(&curIndex);
+  session_history->GetCount(&len);
 
   PRInt32 index = curIndex + aDelta;
   if (index > -1  &&  index < len)
     webnav->GotoIndex(index);
 
   // We always want to return a NS_OK, since returning errors 
   // from GotoIndex() can lead to exceptions and a possible leak
   // of history length
--- a/dom/browser-element/BrowserElementParent.js
+++ b/dom/browser-element/BrowserElementParent.js
@@ -129,16 +129,17 @@ BrowserElementParentFactory.prototype = 
 };
 
 function BrowserElementParent(frameLoader, hasRemoteFrame) {
   debug("Creating new BrowserElementParent object for " + frameLoader);
   this._domRequestCounter = 0;
   this._pendingDOMRequests = {};
   this._hasRemoteFrame = hasRemoteFrame;
 
+  this._frameLoader = frameLoader;
   this._frameElement = frameLoader.QueryInterface(Ci.nsIFrameLoader).ownerElement;
   if (!this._frameElement) {
     debug("No frame element?");
     return;
   }
 
   this._mm = frameLoader.messageManager;
 
@@ -173,16 +174,17 @@ function BrowserElementParent(frameLoade
   addMessageListener('got-can-go-back', this._gotDOMRequestResult);
   addMessageListener('got-can-go-forward', this._gotDOMRequestResult);
   addMessageListener('fullscreen-origin-change', this._remoteFullscreenOriginChange);
   addMessageListener('rollback-fullscreen', this._remoteFrameFullscreenReverted);
   addMessageListener('exit-fullscreen', this._exitFullscreen);
 
   let os = Cc["@mozilla.org/observer-service;1"].getService(Ci.nsIObserverService);
   os.addObserver(this, 'ask-children-to-exit-fullscreen', /* ownsWeak = */ true);
+  os.addObserver(this, 'oop-frameloader-crashed', /* ownsWeak = */ true);
 
   function defineMethod(name, fn) {
     XPCNativeWrapper.unwrap(self._frameElement)[name] = function() {
       if (self._isAlive()) {
         return fn.apply(self, arguments);
       }
     };
   }
@@ -469,18 +471,36 @@ BrowserElementParent.prototype = {
     let origin = data.json;
     this._windowUtils.remoteFrameFullscreenChanged(this._frameElement, origin);
   },
 
   _remoteFrameFullscreenReverted: function(data) {
     this._windowUtils.remoteFrameFullscreenReverted();
   },
 
+  _fireFatalError: function() {
+    let evt = this._createEvent('error', {type: 'fatal'},
+                                /* cancelable = */ false);
+    this._frameElement.dispatchEvent(evt);
+  },
+
   observe: function(subject, topic, data) {
-    if (topic == 'ask-children-to-exit-fullscreen' &&
-        this._isAlive() &&
-        this._frameElement.ownerDocument == subject &&
-        this._hasRemoteFrame)
-      this._sendAsyncMsg('exit-fullscreen');
+    switch(topic) {
+    case 'oop-frameloader-crashed':
+      if (this._isAlive() && subject == this._frameLoader) {
+        this._fireFatalError();
+      }
+      break;
+    case 'ask-children-to-exit-fullscreen':
+      if (this._isAlive() &&
+          this._frameElement.ownerDocument == subject &&
+          this._hasRemoteFrame) {
+        this._sendAsyncMsg('exit-fullscreen');
+      }
+      break;
+    default:
+      debug('Unknown topic: ' + topic);
+      break;
+    };
   },
 };
 
 var NSGetFactory = XPCOMUtils.generateNSGetFactory([BrowserElementParentFactory]);
--- a/dom/devicestorage/nsDeviceStorage.cpp
+++ b/dom/devicestorage/nsDeviceStorage.cpp
@@ -28,16 +28,17 @@
 #include "nsContentUtils.h"
 #include "nsXULAppAPI.h"
 #include "TabChild.h"
 #include "DeviceStorageRequestChild.h"
 #include "nsIDOMDeviceStorageChangeEvent.h"
 #include "nsCRT.h"
 #include "mozilla/Services.h"
 #include "nsIObserverService.h"
+#include "GeneratedEvents.h"
 
 // Microsoft's API Name hackery sucks
 #undef CreateEvent
 
 #ifdef MOZ_WIDGET_GONK
 #include "nsIVolumeService.h"
 #endif
 
@@ -433,102 +434,16 @@ jsval StringToJsval(nsPIDOMWindow* aWind
   jsval result = JSVAL_NULL;
   if (!xpc::StringToJsval(cx, aString, &result)) {
     return JSVAL_NULL;
   }
 
   return result;
 }
 
-class nsDOMDeviceStorageChangeEvent : public nsDOMEvent, public nsIDOMDeviceStorageChangeEvent
-{
-public:
-  NS_DECL_ISUPPORTS_INHERITED
-  NS_FORWARD_NSIDOMEVENT(nsDOMEvent::)
-  NS_DECL_NSIDOMDEVICESTORAGECHANGEEVENT
-
-  nsDOMDeviceStorageChangeEvent();
-
-  virtual nsresult InitFromCtor(const nsAString& aType,
-                                JSContext* aCx,
-                                jsval* aVal);
-    
-  NS_IMETHOD Init(const nsAString & aEventTypeArg,
-                  bool aCanBubbleArg,
-                  bool aCancelableArg,
-                  nsAString& aPath,
-                  nsAString& aReason);
-
-private:
-  ~nsDOMDeviceStorageChangeEvent();
-
-protected:
-  nsString mPath;
-  nsString mReason;
-};
-
-DOMCI_DATA(DeviceStorageChangeEvent, nsDOMDeviceStorageChangeEvent)
-
-NS_INTERFACE_MAP_BEGIN(nsDOMDeviceStorageChangeEvent)
-  NS_INTERFACE_MAP_ENTRY(nsIDOMDeviceStorageChangeEvent)
-  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(DeviceStorageChangeEvent)
-NS_INTERFACE_MAP_END_INHERITING(nsDOMEvent)
-
-NS_IMPL_ADDREF_INHERITED(nsDOMDeviceStorageChangeEvent, nsDOMEvent)
-NS_IMPL_RELEASE_INHERITED(nsDOMDeviceStorageChangeEvent, nsDOMEvent)
-
-nsDOMDeviceStorageChangeEvent::nsDOMDeviceStorageChangeEvent()
-  : nsDOMEvent(nullptr, nullptr)
-{ 
-}
-
-nsDOMDeviceStorageChangeEvent::~nsDOMDeviceStorageChangeEvent()
-{
-}
-
-NS_IMETHODIMP
-nsDOMDeviceStorageChangeEvent::Init(const nsAString & aEventTypeArg,
-                                    bool aCanBubbleArg,
-                                    bool aCancelableArg,
-                                    nsAString& aPath,
-                                    nsAString& aReason)
-{
-  nsresult rv = nsDOMEvent::InitEvent(aEventTypeArg, aCanBubbleArg, aCancelableArg);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  mPath = aPath;
-  mReason = aReason;
-  return NS_OK;
-}
-
-nsresult
-nsDOMDeviceStorageChangeEvent::InitFromCtor(const nsAString& aType,
-                                            JSContext* aCx,
-                                            jsval* aVal)
-{
-  mozilla::dom::DeviceStorageChangeEventInit d;
-  nsresult rv = d.Init(aCx, aVal);
-  NS_ENSURE_SUCCESS(rv, rv);
-  return Init(aType, d.bubbles, d.cancelable, d.path, d.reason);
-}
-
-NS_IMETHODIMP
-nsDOMDeviceStorageChangeEvent::GetPath(nsAString & aPath)
-{
-  aPath = mPath;
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsDOMDeviceStorageChangeEvent::GetReason(nsAString & aReason)
-{
-  aReason = mReason;
-  return NS_OK;
-}
-
 class DeviceStorageCursorRequest MOZ_FINAL
   : public nsIContentPermissionRequest
   , public PCOMContentPermissionRequestChild
 {
 public:
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(DeviceStorageCursorRequest, nsIContentPermissionRequest)
 
@@ -1663,26 +1578,28 @@ nsDOMDeviceStorage::Update(const char* a
   if (!StringBeginsWith(fullpath, rootpath)) {
     NS_WARNING("Observing a path outside of our root!");
     return NS_OK;
   }
 
   nsAString::size_type len = rootpath.Length() + 1; // +1 for the trailing /
   nsDependentSubstring newPath (fullpath, len, fullpath.Length() - len);
 
-  nsRefPtr<nsDOMDeviceStorageChangeEvent> event = new nsDOMDeviceStorageChangeEvent();
+  nsCOMPtr<nsIDOMEvent> event;
+  NS_NewDOMDeviceStorageChangeEvent(getter_AddRefs(event), nullptr, nullptr);
+
+  nsCOMPtr<nsIDOMDeviceStorageChangeEvent> ce = do_QueryInterface(event);
+
   nsString reason;
   reason.AssignWithConversion(aReason);
-  rv = event->Init(NS_LITERAL_STRING("change"), true, false, newPath, reason);
+  rv = ce->InitDeviceStorageChangeEvent(NS_LITERAL_STRING("change"), true, false, newPath, reason);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  nsCOMPtr<nsIDOMDeviceStorageChangeEvent> e = event.get();
-
   bool ignore;
-  DispatchEvent(e, &ignore);
+  DispatchEvent(ce, &ignore);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDOMDeviceStorage::AddEventListener(const nsAString & aType,
                                      nsIDOMEventListener *aListener,
                                      bool aUseCapture,
                                      bool aWantsUntrusted,
--- a/dom/interfaces/devicestorage/nsIDOMDeviceStorageChangeEvent.idl
+++ b/dom/interfaces/devicestorage/nsIDOMDeviceStorageChangeEvent.idl
@@ -3,16 +3,23 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "domstubs.idl"
 #include "nsIDOMEvent.idl"
 
 [scriptable, uuid(468304d6-aab6-4e1e-8ab2-569d9e703431), builtinclass]
 interface nsIDOMDeviceStorageChangeEvent : nsIDOMEvent
 {
+
+  [noscript] void initDeviceStorageChangeEvent(in DOMString eventTypeArg,
+                                               in boolean canBubbleArg,
+                                               in boolean cancelableArg,
+                                               in DOMString path,
+                                               in DOMString reason);
+  
   readonly attribute DOMString path;
   readonly attribute DOMString reason;
 };
 
 dictionary DeviceStorageChangeEventInit : EventInit
 {
   DOMString path;
   DOMString reason;
--- a/dom/interfaces/events/nsIDOMTouchEvent.idl
+++ b/dom/interfaces/events/nsIDOMTouchEvent.idl
@@ -36,18 +36,17 @@ interface nsIDOMTouch : nsISupports {
     bool mChanged;
     PRUint32 mMessage;
   %}
 };
 
 [scriptable, uuid(60706eb7-d50d-4379-b01c-e78e6af84213)]
 interface nsIDOMTouchList : nsISupports {
   readonly attribute unsigned long length;
-  [getter,forward(getItemAt)] nsIDOMTouch item(in unsigned long index);
-  [noscript,notxpcom,nostdcall] nsIDOMTouch getItemAt(in unsigned long index);
+  nsIDOMTouch item(in unsigned long index);
   nsIDOMTouch identifiedTouch(in long identifier);
 };
 
 [scriptable, builtinclass, uuid(57809468-7c03-4e8a-b080-4e30f157db21)]
 interface nsIDOMTouchEvent : nsIDOMUIEvent {
   readonly attribute nsIDOMTouchList touches;
   readonly attribute nsIDOMTouchList targetTouches;
   readonly attribute nsIDOMTouchList changedTouches;
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -668,24 +668,27 @@ TabChild::RecvUpdateFrame(const nsIntRec
         data += nsPrintfCString(", \"resolution\" : %f", aResolution.width);
         data += nsPrintfCString(" }");
     data += nsPrintfCString(", \"screenSize\" : ");
         data += nsPrintfCString("{ \"width\" : %d", aScreenSize.width);
         data += nsPrintfCString(", \"height\" : %d", aScreenSize.height);
         data += nsPrintfCString(" }");
     data += nsPrintfCString(" }");
 
+    JSAutoRequest ar(mCx);
     jsval json = JSVAL_NULL;
     StructuredCloneData cloneData;
     JSAutoStructuredCloneBuffer buffer;
     if (JS_ParseJSON(mCx,
                       static_cast<const jschar*>(NS_ConvertUTF8toUTF16(data).get()),
                       data.Length(),
                       &json)) {
         WriteStructuredClone(mCx, json, buffer, cloneData.mClosure);
+        cloneData.mData = buffer.data();
+        cloneData.mDataLength = buffer.nbytes();
     }
 
     nsFrameScriptCx cx(static_cast<nsIWebBrowserChrome*>(this), this);
     // Let the BrowserElementScrolling helper (if it exists) for this
     // content manipulate the frame state.
     nsRefPtr<nsFrameMessageManager> mm =
       static_cast<nsFrameMessageManager*>(mTabChildGlobal->mMessageManager.get());
     mm->ReceiveMessage(static_cast<nsIDOMEventTarget*>(mTabChildGlobal),
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -115,16 +115,24 @@ TabParent::Recv__delete__()
 void
 TabParent::ActorDestroy(ActorDestroyReason why)
 {
   if (mIMETabParent == this)
     mIMETabParent = nullptr;
   nsRefPtr<nsFrameLoader> frameLoader = GetFrameLoader();
   if (frameLoader) {
     frameLoader->DestroyChild();
+
+    if (why == AbnormalShutdown) {
+      nsCOMPtr<nsIObserverService> os = services::GetObserverService();
+      if (os) {
+        os->NotifyObservers(NS_ISUPPORTS_CAST(nsIFrameLoader*, frameLoader),
+                            "oop-frameloader-crashed", nullptr);
+      }
+    }
   }
 }
 
 bool
 TabParent::RecvMoveFocus(const bool& aForward)
 {
   nsCOMPtr<nsIFocusManager> fm = do_GetService(FOCUSMANAGER_CONTRACTID);
   if (fm) {
--- a/dom/plugins/test/mochitest/Makefile.in
+++ b/dom/plugins/test/mochitest/Makefile.in
@@ -51,19 +51,16 @@ MOCHITEST_FILES = \
   test_npn_timers.html \
   test_npn_asynccall.html \
   test_bug532208.html \
   large-pic.jpg \
   test_twostreams.html \
   test_streamatclose.html \
   neverending.sjs \
   test_newstreamondestroy.html \
-  test_crashing.html \
-  $(warning test_crashing2.html disabled due to random orange; see bug 566049) \
-  test_hanging.html \
   crashing_subpage.html \
   test_GCrace.html \
   test_propertyAndMethod.html \
   test_bug539565-1.html \
   test_bug539565-2.html \
   test_bug771202.html \
   file_bug771202.html \
   test_bug777098.html \
@@ -116,16 +113,22 @@ MOCHITEST_CHROME_FILES += \
   test_xulbrowser_plugin_visibility.xul \
   xulbrowser_plugin_visibility.xul \
   plugin_visibility_loader.html \
   $(NULL)
 endif
 endif
 
 ifdef MOZ_CRASHREPORTER
+MOCHITEST_FILES += \
+  test_crashing.html \
+  $(warning test_crashing2.html disabled due to random orange; see bug 566049) \
+  test_hanging.html \
+  $(NULL)
+
 MOCHITEST_CHROME_FILES += \
   test_crash_notify.xul \
   test_crash_notify_no_report.xul \
   test_crash_submit.xul \
   $(NULL)
   ifeq ($(OS_ARCH),WINNT)
     MOCHITEST_CHROME_FILES += \
       test_idle_hang.xul \
--- a/gfx/gl/GLContextProviderEGL.cpp
+++ b/gfx/gl/GLContextProviderEGL.cpp
@@ -940,17 +940,17 @@ GLContextEGL::CreateSharedHandle(Texture
         }
 
         return (SharedTextureHandle) new SurfaceTextureWrapper(reinterpret_cast<nsSurfaceTexture*>(aBuffer));
 #endif
     case SharedTextureBufferType::TextureID: {
         if (!mShareWithEGLImage)
             return 0;
 
-        GLuint texture = (GLuint)aBuffer;
+        GLuint texture = (uintptr_t)aBuffer;
         EGLTextureWrapper* tex = new EGLTextureWrapper();
         if (!tex->CreateEGLImage(this, texture)) {
             NS_ERROR("EGLImage creation for EGLTextureWrapper failed");
             delete tex;
             return 0;
         }
 
         return (SharedTextureHandle)tex;
--- a/js/src/builtin/MapObject.cpp
+++ b/js/src/builtin/MapObject.cpp
@@ -646,19 +646,19 @@ class OrderedHashSet
 }  // namespace js
 
 
 /*** HashableValue *******************************************************************************/
 
 bool
 HashableValue::setValue(JSContext *cx, const Value &v)
 {
-    if (v.isString() && v.toString()->isRope()) {
-        // Flatten this rope so that equals() is infallible.
-        JSString *str = v.toString()->ensureLinear(cx);
+    if (v.isString()) {
+        // Atomize so that hash() and equals() are fast and infallible.
+        JSString *str = js_AtomizeString(cx, v.toString(), DoNotInternAtom);
         if (!str)
             return false;
         value = StringValue(str);
     } else if (v.isDouble()) {
         double d = v.toDouble();
         int32_t i;
         if (MOZ_DOUBLE_IS_INT32(d, &i)) {
             // Normalize int32-valued doubles to int32 for faster hashing and testing.
@@ -678,38 +678,25 @@ HashableValue::setValue(JSContext *cx, c
     return true;
 }
 
 HashNumber
 HashableValue::hash() const
 {
     // HashableValue::setValue normalizes values so that the SameValue relation
     // on HashableValues is the same as the == relationship on
-    // value.data.asBits, except for strings.
-    if (value.isString()) {
-        JSLinearString &s = value.toString()->asLinear();
-        return HashChars(s.chars(), s.length());
-    }
-
-    // Having dispensed with strings, we can just hash asBits.
-    uint64_t u = value.asRawBits();
-    return HashNumber((u >> 3) ^
-                      (u >> (HashNumberSizeBits + 3)) ^
-                      (u << (HashNumberSizeBits - 3)));
+    // value.data.asBits.
+    return value.asRawBits();
 }
 
 bool
 HashableValue::equals(const HashableValue &other) const
 {
-    // Two HashableValues are equal if they have equal bits or they're equal strings.
-    bool b = (value.asRawBits() == other.value.asRawBits()) ||
-              (value.isString() &&
-               other.value.isString() &&
-               EqualStrings(&value.toString()->asLinear(),
-                            &other.value.toString()->asLinear()));
+    // Two HashableValues are equal if they have equal bits.
+    bool b = (value.asRawBits() == other.value.asRawBits());
 
 #ifdef DEBUG
     bool same;
     JS_ASSERT(SameValue(NULL, value, other.value, &same));
     JS_ASSERT(same == b);
 #endif
     return b;
 }
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/basic/expression-autopsy.js
@@ -0,0 +1,96 @@
+function check_one(expected, f, err) {
+    var failed = true;
+    try {
+        f();
+        failed = false;
+    } catch (ex) {
+        var s = ex.toString();
+        assertEq(s.slice(0, 11), "TypeError: ");
+        assertEq(s.slice(-err.length), err);
+        assertEq(s.slice(11, -err.length), expected);
+    }
+    if (!failed)
+        throw new Error("didn't fail");
+}
+ieval = eval;
+function check(expr, expected=expr) {
+    var end, err;
+    for ([end, err] of [[".random_prop", " is undefined"], ["()", " is not a function"]]) {
+        var statement = "o = {};" + expr + end, f;
+        var cases = [
+            // Global scope
+            function () {
+                ieval("var o, undef;\n" + statement);
+            },
+            // Function scope
+            Function("o", "undef", statement),
+            // Function scope with variables
+            Function("var o, undef;\n" + statement),
+            // Function scope with some different arugments
+            Function("arg1", "arg2", "var o, undef;\n" + statement),
+            // Deoptimized function scope
+            Function("o", "undef", "with (Object) {}\n" + statement),
+            // Inside with
+            Function("with (Object) { " + statement + " }"),
+            // Closure
+            Function("o", "undef", "function myfunc() { return o + undef; }\n" + statement),
+            // Let definitions in a block
+            Function("{ let o, undef;\n" + statement + "}"),
+            // Let block
+            Function("let (o, undef) { " + statement + " }"),
+            // Let block with some other variables
+            Function("var v1, v2; let (o, undef) { " + statement + " }"),
+            // Shadowed let block
+            Function("o", "undef", "let (o, undef) { " + statement + " }"),
+            // Let in a switch
+            Function("var x = 4; switch (x) { case 4: let o, undef;" + statement + "\ncase 6: break;}"),
+            // Let in for-in
+            Function("var undef, o; for (let z in [1, 2]) { " + statement + " }"),
+            // The more lets the merrier
+            Function("let (x=4, y=5) { x + y; }\nlet (a, b, c) { a + b - c; }\nlet (o, undef) {" + statement + " }"),
+            // Let destructuring
+            Function("o", "undef", "let ([] = 4) {} let (o, undef) { " + statement + " }"),
+            // Try-catch blocks
+            Function("o", "undef", "try { let q = 4; try { let p = 4; } catch (e) {} } catch (e) {} let (o, undef) { " + statement + " }")
+        ];
+        for (var f of cases) {
+            check_one(expected, f, err);
+        }
+    }
+}
+
+check("undef");
+check("o.b");
+check("o.length");
+check("o[true]");
+check("o[false]");
+check("o[null]");
+check("o[0]");
+check("o[1]");
+check("o[3]");
+check("o[256]");
+check("o[65536]");
+check("o[268435455]");
+check("o['1.1']");
+check("o[4 + 'h']", "o['4h']");
+check("this.x");
+check("ieval(undef)", "ieval(...)");
+check("ieval.call()", "ieval.call(...)");
+
+for (let tok of ["|", "^", "&", "==", "!==", "===", "!==", "<", "<=", ">", ">=",
+                 ">>", "<<", ">>>", "+", "-", "*", "/", "%"]) {
+    check("o[(undef " + tok + " 4)]");
+}
+
+check("o[!(o)]");
+check("o[~(o)]");
+check("o[+ (o)]");
+check("o[- (o)]");
+
+// A few one off tests
+check_one("6", (function () { 6() }), " is not a function");
+check_one("Array.prototype.reverse.call(...)", (function () { Array.prototype.reverse.call('123'); }), " is read-only");
+check_one("null", function () { var [{ x }] = [null, {}]; }, " has no properties");
+
+// Check fallback behavior
+check_one("undefined", (function () { for (let x of undefined) {} }), " has no properties");
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/basic/function-tosource-bug779694.js
@@ -0,0 +1,6 @@
+var x = "";
+for (var i=0; i<400; ++i) {
+    x += String.fromCharCode(i * 289);
+}
+var s = "'" + x + "'";
+assertEq(Function("evt", s).toString(), "function anonymous(evt) {\n" + s + "\n}");
--- a/js/src/jit-test/tests/basic/testBug566556.js
+++ b/js/src/jit-test/tests/basic/testBug566556.js
@@ -1,9 +1,9 @@
 var msg = "";
 try {
     this.__defineSetter__('x', Object.create);
     this.watch('x', function() {});
     x = 3;
 } catch (e) {
     msg = e.toString();
 }
-assertEq(msg, "TypeError: (void 0) is not an object or null");
+assertEq(msg, "TypeError: undefined is not an object or null");
--- a/js/src/jit-test/tests/basic/testBug579647.js
+++ b/js/src/jit-test/tests/basic/testBug579647.js
@@ -1,13 +1,13 @@
 expected = "TypeError: NaN is not a function";
 actual = "";
 
 try {
     a = ""
     for each(x in [0, 0, 0, 0]) {
         a %= x
-    } ( - a)()
+    } ( let (a=-a) a)()
 } catch (e) {
     actual = '' + e;
 }
 
 assertEq(expected, actual);
--- a/js/src/jit-test/tests/basic/testInitSingletons.js
+++ b/js/src/jit-test/tests/basic/testInitSingletons.js
@@ -23,17 +23,17 @@ foo();
 
 var q = {0x4fffffff: 0, 0x7fffffff: 1, 0xffffffff: 2};
 assertEq(q[1342177279], 0);
 assertEq(q[2147483647], 1);
 assertEq(q[4294967295], 2);
 
 try {
   [1,2,3,{a:0,b:1}].foo.bar;
-} catch (e) { assertEq(e.message, "[1, 2, 3, {a:0, b:1}].foo is undefined"); }
+} catch (e) { assertEq(e.message.search("\.foo is undefined") != -1, true); }
 
 var a = [1 + 1, 3 * 2, 6 - 5, 14 % 6, 15 / 5, 1 << 3, 
          8 >> 2, 5 | 2, 5 ^ 3, ~3, -3,"a" + "b",  !true, !false];
 assertEq(String(a), "2,6,1,2,3,8,2,7,6,-4,-3,ab,false,true");
 assertEq(a.length, 14);
 
 var b = {
     a: 1 + 1,
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -540,21 +540,18 @@ JS_ValueToSource(JSContext *cx, jsval v)
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, v);
     return js_ValueToSource(cx, v);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_ValueToNumber(JSContext *cx, jsval v, double *dp)
 {
-    AssertHeapIsIdle(cx);
-    CHECK_REQUEST(cx);
-    assertSameCompartment(cx, v);
-
-    return ToNumber(cx, v, dp);
+    RootedValue value(cx, v);
+    return JS::ToNumber(cx, value, dp);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_DoubleIsInt32(double d, int32_t *ip)
 {
     return MOZ_DOUBLE_IS_INT32(d, ip);
 }
 
@@ -568,32 +565,25 @@ JS_PUBLIC_API(uint32_t)
 JS_DoubleToUint32(double d)
 {
     return ToUint32(d);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_ValueToECMAInt32(JSContext *cx, jsval v, int32_t *ip)
 {
-    AssertHeapIsIdle(cx);
-    CHECK_REQUEST(cx);
-    assertSameCompartment(cx, v);
-
     RootedValue value(cx, v);
-    return ToInt32(cx, value, ip);
+    return JS::ToInt32(cx, value, ip);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_ValueToECMAUint32(JSContext *cx, jsval v, uint32_t *ip)
 {
-    AssertHeapIsIdle(cx);
-    CHECK_REQUEST(cx);
-    assertSameCompartment(cx, v);
-
-    return ToUint32(cx, v, (uint32_t *)ip);
+    RootedValue value(cx, v);
+    return JS::ToUint32(cx, value, ip);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_ValueToInt32(JSContext *cx, jsval v, int32_t *ip)
 {
     AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, v);
@@ -618,21 +608,17 @@ JS_ValueToInt32(JSContext *cx, jsval v, 
 
     *ip = (int32_t) floor(d + 0.5);  /* Round to nearest */
     return true;
 }
 
 JS_PUBLIC_API(JSBool)
 JS_ValueToUint16(JSContext *cx, jsval v, uint16_t *ip)
 {
-    AssertHeapIsIdle(cx);
-    CHECK_REQUEST(cx);
-    assertSameCompartment(cx, v);
-
-    return ValueToUint16(cx, v, (uint16_t *)ip);
+    return ToUint16(cx, v, ip);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_ValueToBoolean(JSContext *cx, jsval v, JSBool *bp)
 {
     AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, v);
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -993,18 +993,21 @@ class JS_PUBLIC_API(AutoCheckRequestDept
 #else
 
 # define CHECK_REQUEST(cx) \
     ((void) 0)
 
 #endif /* JS_THREADSAFE && DEBUG */
 
 #ifdef DEBUG
-/* Assert that we're not doing GC on cx, that we're in a request as
-   needed, and that the compartments for cx and v are correct. */
+/*
+ * Assert that we're not doing GC on cx, that we're in a request as
+ * needed, and that the compartments for cx and v are correct.
+ * Also check that GC would be safe at this point.
+ */
 JS_PUBLIC_API(void)
 AssertArgumentsAreSane(JSContext *cx, const Value &v);
 #else
 inline void AssertArgumentsAreSane(JSContext *cx, const Value &v) {
     /* Do nothing */
 }
 #endif /* DEBUG */
 
@@ -2695,20 +2698,23 @@ ToBooleanSlow(const JS::Value &v);
 
 namespace JS {
 
 /* ES5 9.3 ToNumber. */
 JS_ALWAYS_INLINE bool
 ToNumber(JSContext *cx, const Value &v, double *out)
 {
     AssertArgumentsAreSane(cx, v);
+    {
+        JS::SkipRoot root(cx, &v);
+        MaybeCheckStackRoots(cx);
+    }
 
     if (v.isNumber()) {
         *out = v.toNumber();
-        MaybeCheckStackRoots(cx);
         return true;
     }
     return js::ToNumberSlow(cx, v, out);
 }
 
 JS_ALWAYS_INLINE bool
 ToBoolean(const Value &v)
 {
@@ -2745,36 +2751,79 @@ JS_DoubleToUint32(double d);
  * Convert a value to a number, then to an int32_t, according to the ECMA rules
  * for ToInt32.
  */
 extern JS_PUBLIC_API(JSBool)
 JS_ValueToECMAInt32(JSContext *cx, jsval v, int32_t *ip);
 
 #ifdef __cplusplus
 namespace js {
-/*
- * DO NOT CALL THIS.  Use JS::ToInt32
- */
+/* DO NOT CALL THIS.  Use JS::ToInt16. */
+extern JS_PUBLIC_API(bool)
+ToUint16Slow(JSContext *cx, const JS::Value &v, uint16_t *out);
+
+/* DO NOT CALL THIS.  Use JS::ToInt32. */
 extern JS_PUBLIC_API(bool)
 ToInt32Slow(JSContext *cx, const JS::Value &v, int32_t *out);
+
+/* DO NOT CALL THIS.  Use JS::ToUint32. */
+extern JS_PUBLIC_API(bool)
+ToUint32Slow(JSContext *cx, const JS::Value &v, uint32_t *out);
 } /* namespace js */
 
 namespace JS {
 
 JS_ALWAYS_INLINE bool
+ToUint16(JSContext *cx, const js::Value &v, uint16_t *out)
+{
+    AssertArgumentsAreSane(cx, v);
+    {
+        SkipRoot skip(cx, &v);
+        MaybeCheckStackRoots(cx);
+    }
+
+    if (v.isInt32()) {
+        *out = uint16_t(v.toInt32());
+        return true;
+    }
+    return js::ToUint16Slow(cx, v, out);
+}
+
+JS_ALWAYS_INLINE bool
 ToInt32(JSContext *cx, const js::Value &v, int32_t *out)
 {
     AssertArgumentsAreSane(cx, v);
+    {
+        JS::SkipRoot root(cx, &v);
+        MaybeCheckStackRoots(cx);
+    }
+
     if (v.isInt32()) {
         *out = v.toInt32();
         return true;
     }
     return js::ToInt32Slow(cx, v, out);
 }
 
+JS_ALWAYS_INLINE bool
+ToUint32(JSContext *cx, const js::Value &v, uint32_t *out)
+{
+    AssertArgumentsAreSane(cx, v);
+    {
+        JS::SkipRoot root(cx, &v);
+        MaybeCheckStackRoots(cx);
+    }
+
+    if (v.isInt32()) {
+        *out = uint32_t(v.toInt32());
+        return true;
+    }
+    return js::ToUint32Slow(cx, v, out);
+}
+
 } /* namespace JS */
 #endif /* __cplusplus */
 
 /*
  * Convert a value to a number, then to a uint32_t, according to the ECMA rules
  * for ToUint32.
  */
 extern JS_PUBLIC_API(JSBool)
@@ -4958,17 +5007,17 @@ JS_CompileUCFunctionForPrincipalsVersion
                                          JSVersion version);
 
 #ifdef __cplusplus
 JS_END_EXTERN_C
 
 namespace JS {
 
 /* Options for JavaScript compilation. */
-struct CompileOptions {
+struct JS_PUBLIC_API(CompileOptions) {
     JSPrincipals *principals;
     JSPrincipals *originPrincipals;
     JSVersion version;
     bool versionSet;
     bool utf8;
     const char *filename;
     unsigned lineno;
     bool compileAndGo;
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -3874,32 +3874,36 @@ IncrementalCollectSlice(JSRuntime *rt,
     AutoCopyFreeListToArenas copy(rt);
     AutoGCSlice slice(rt);
 
     gc::State initialState = rt->gcIncrementalState;
     SliceBudget sliceBudget(budget);
 
     int zeal = 0;
 #ifdef JS_GC_ZEAL
-    if (reason == gcreason::DEBUG_GC) {
+    if (reason == gcreason::DEBUG_GC && budget != SliceBudget::Unlimited) {
         /*
-         * Do the collection type specified by zeal mode only if the collection
-         * was triggered by RunDebugGC().
+         * Do the incremental collection type specified by zeal mode if the
+         * collection was triggered by RunDebugGC() and incremental GC has not
+         * been cancelled by ResetIncrementalGC.
          */
         zeal = rt->gcZeal();
-        JS_ASSERT_IF(zeal == ZealIncrementalMarkAllThenFinish ||
-                     zeal == ZealIncrementalRootsThenFinish,
-                     budget == SliceBudget::Unlimited);
     }
 #endif
 
     bool isIncremental = rt->gcIncrementalState != NO_INCREMENTAL ||
-                         budget != SliceBudget::Unlimited ||
-                         zeal == ZealIncrementalRootsThenFinish ||
-                         zeal == ZealIncrementalMarkAllThenFinish;
+                         budget != SliceBudget::Unlimited;
+
+    if (zeal == ZealIncrementalRootsThenFinish || zeal == ZealIncrementalMarkAllThenFinish) {
+        /*
+         * Yields between slices occurs at predetermined points in these
+         * modes. sliceBudget is not used.
+         */
+        sliceBudget.reset();
+    }
 
     if (rt->gcIncrementalState == NO_INCREMENTAL) {
         rt->gcIncrementalState = MARK_ROOTS;
         rt->gcLastMarkSlice = false;
     }
 
     switch (rt->gcIncrementalState) {
 
@@ -4499,17 +4503,18 @@ RunDebugGC(JSContext *cx)
              * completion.
              */
             if (initialState == NO_INCREMENTAL)
                 rt->gcIncrementalLimit = rt->gcZealFrequency / 2;
             else
                 rt->gcIncrementalLimit *= 2;
             budget = SliceBudget::WorkBudget(rt->gcIncrementalLimit);
         } else {
-            budget = SliceBudget::Unlimited;
+            // This triggers incremental GC but is actually ignored by IncrementalMarkSlice.
+            budget = SliceBudget::WorkBudget(1);
         }
 
         Collect(rt, true, budget, GC_NORMAL, gcreason::DEBUG_GC);
 
         /*
          * For multi-slice zeal, reset the slice size when we get to the sweep
          * phase.
          */
--- a/js/src/jsnum.cpp
+++ b/js/src/jsnum.cpp
@@ -1410,33 +1410,33 @@ ToInt32Slow(JSContext *cx, const Value &
     } else {
         if (!ToNumberSlow(cx, v, &d))
             return false;
     }
     *out = ToInt32(d);
     return true;
 }
 
-bool
+JS_PUBLIC_API(bool)
 ToUint32Slow(JSContext *cx, const Value &v, uint32_t *out)
 {
     JS_ASSERT(!v.isInt32());
     double d;
     if (v.isDouble()) {
         d = v.toDouble();
     } else {
         if (!ToNumberSlow(cx, v, &d))
             return false;
     }
     *out = ToUint32(d);
     return true;
 }
 
-bool
-ValueToUint16Slow(JSContext *cx, const Value &v, uint16_t *out)
+JS_PUBLIC_API(bool)
+ToUint16Slow(JSContext *cx, const Value &v, uint16_t *out)
 {
     JS_ASSERT(!v.isInt32());
     double d;
     if (v.isDouble()) {
         d = v.toDouble();
     } else if (!ToNumberSlow(cx, v, &d)) {
         return false;
     }
--- a/js/src/jsnum.h
+++ b/js/src/jsnum.h
@@ -139,63 +139,16 @@ ToNumber(JSContext *cx, Value *vp)
     extern bool ToNumberSlow(JSContext *cx, js::Value v, double *dp);
     if (!ToNumberSlow(cx, *vp, &d))
         return false;
 
     vp->setNumber(d);
     return true;
 }
 
-/*
- * Convert a value to a uint32_t, according to the ECMA rules for
- * ToUint32. Return converted value in *out on success, !ok on
- * failure.
- */
-
-JS_ALWAYS_INLINE bool
-ToUint32(JSContext *cx, const js::Value &v, uint32_t *out)
-{
-#ifdef DEBUG
-    {
-        SkipRoot skip(cx, &v);
-        MaybeCheckStackRoots(cx);
-    }
-#endif
-
-    if (v.isInt32()) {
-        *out = (uint32_t)v.toInt32();
-        return true;
-    }
-    extern bool ToUint32Slow(JSContext *cx, const js::Value &v, uint32_t *ip);
-    return ToUint32Slow(cx, v, out);
-}
-
-/*
- * Convert a value to a number, then to a uint16_t according to the ECMA rules
- * for ToUint16. Return converted value on success, !ok on failure. v must be a
- * copy of a rooted value.
- */
-JS_ALWAYS_INLINE bool
-ValueToUint16(JSContext *cx, const js::Value &v, uint16_t *out)
-{
-#ifdef DEBUG
-    {
-        SkipRoot skip(cx, &v);
-        MaybeCheckStackRoots(cx);
-    }
-#endif
-
-    if (v.isInt32()) {
-        *out = uint16_t(v.toInt32());
-        return true;
-    }
-    extern bool ValueToUint16Slow(JSContext *cx, const js::Value &v, uint16_t *out);
-    return ValueToUint16Slow(cx, v, out);
-}
-
 JSBool
 num_parseInt(JSContext *cx, unsigned argc, Value *vp);
 
 }  /* namespace js */
 
 /*
  * Similar to strtod except that it replaces overflows with infinities of the
  * correct sign, and underflows with zeros of the correct sign.  Guaranteed to
--- a/js/src/jsopcode.cpp
+++ b/js/src/jsopcode.cpp
@@ -1326,17 +1326,17 @@ CopyDecompiledTextForDecomposedOp(JSPrin
  *
  * This function cannot raise an exception or error. However, due to a risk of
  * potential bugs when modeling the stack, the function returns -1 if it
  * detects an inconsistency in the model. Such an inconsistency triggers an
  * assert in a debug build.
  */
 static int
 ReconstructPCStack(JSContext *cx, JSScript *script, jsbytecode *pc,
-                   jsbytecode **pcstack, jsbytecode **lastDecomposedPC);
+                   jsbytecode **pcstack);
 
 #define FAILED_EXPRESSION_DECOMPILER ((char *) 1)
 
 /*
  * Decompile a part of expression up to the given pc. The function returns
  * NULL on out-of-memory, or the FAILED_EXPRESSION_DECOMPILER sentinel when
  * the decompiler fails due to a bug and/or unimplemented feature, or the
  * decompiled string on success.
@@ -5729,115 +5729,503 @@ js_DecompileFunction(JSPrinter *jp)
     }
 
     if (!jp->pretty && !jp->grouped && (fun->flags & JSFUN_LAMBDA))
         js_puts(jp, ")");
 
     return JS_TRUE;
 }
 
+static JSObject *
+GetBlockChainAtPC(JSContext *cx, JSScript *script, jsbytecode *pc)
+{
+    jsbytecode *start = script->main();
+    
+    JS_ASSERT(pc >= start && pc < script->code + script->length);
+
+    JSObject *blockChain = NULL;
+    for (jsbytecode *p = start; p < pc; p += GetBytecodeLength(p)) {
+        JSOp op = JSOp(*p);
+
+        switch (op) {
+          case JSOP_ENTERBLOCK:
+          case JSOP_ENTERLET0:
+          case JSOP_ENTERLET1: {
+            JSObject *child = script->getObject(p);
+            JS_ASSERT_IF(blockChain, child->asBlock().stackDepth() >= blockChain->asBlock().stackDepth());
+            blockChain = child;
+            break;
+          }
+          case JSOP_LEAVEBLOCK:
+          case JSOP_LEAVEBLOCKEXPR:
+          case JSOP_LEAVEFORLETIN: {
+            // Some LEAVEBLOCK instructions are due to early exits via
+            // return/break/etc. from block-scoped loops and functions.  We
+            // should ignore these instructions, since they don't really signal
+            // the end of the block.
+            jssrcnote *sn = js_GetSrcNote(script, p);
+            if (!(sn && SN_TYPE(sn) == SRC_HIDDEN)) {
+                JS_ASSERT(blockChain);
+                blockChain = blockChain->asStaticBlock().enclosingBlock();
+                JS_ASSERT_IF(blockChain, blockChain->isBlock());
+            }
+            break;
+          }
+          default:
+            break;
+        }
+    }
+    
+    return blockChain;
+}
+
+class PCStack
+{
+    JSContext *cx;
+    jsbytecode **stack;
+    int depth_;
+
+  public:
+    explicit PCStack(JSContext *cx)
+        : cx(cx),
+          stack(NULL),
+          depth_(0)
+    {}
+    ~PCStack();
+    bool init(JSContext *cx, JSScript *script, jsbytecode *pc);
+    int depth() const { return depth_; }
+    jsbytecode *operator[](int i) const;
+};
+
+PCStack::~PCStack()
+{
+    cx->free_(stack);
+}
+
+bool
+PCStack::init(JSContext *cx, JSScript *script, jsbytecode *pc)
+{
+    stack = static_cast<jsbytecode **>(cx->malloc_(StackDepth(script) * sizeof(*stack)));
+    if (!stack)
+        return false;
+    depth_ = ReconstructPCStack(cx, script, pc, stack);
+    JS_ASSERT(depth_ >= 0);
+    return true;
+}
+
+/* Indexes the pcstack. */
+jsbytecode *
+PCStack::operator[](int i) const
+{
+    if (i < 0) {
+        i += depth_;
+        JS_ASSERT(i >= 0);
+    }
+    JS_ASSERT(i < depth_);
+    return stack[i];
+}
+
+/*
+ * The expression decompiler is invoked by error handling code to produce a
+ * string representation of the erroring expression. As it's only a debugging
+ * tool, it only supports basic expressions. For anything complicated, it simply
+ * puts "(intermediate value)" into the error result.
+ *
+ * Here's the basic algorithm:
+ *
+ * 1. Find the stack location of the value whose expression we wish to
+ * decompile. The error handler can explicitly pass this as an
+ * argument. Otherwise, we search backwards down the stack for the offending
+ * value.
+ *
+ * 2. Call ReconstructPCStack with the current frame's pc. This creates a stack
+ * of pcs parallel to the interpreter stack; given an interpreter stack
+ * location, the corresponding pc stack location contains the opcode that pushed
+ * the value in the interpreter. Now, with the result of step 1, we have the
+ * opcode responsible for pushing the value we want to decompile.
+ *
+ * 3. Pass the opcode to decompilePC. decompilePC is the main decompiler
+ * routine, responsible for a string representation of the expression that
+ * generated a certain stack location. decompilePC looks at one opcode and
+ * returns the JS source equivalent of that opcode.
+ *
+ * 4. Expressions can, of course, contain subexpressions. For example, the
+ * literals "4" and "5" are subexpressions of the addition operator in "4 +
+ * 5". If we need to decompile a subexpression, we call decompilePC (step 2)
+ * recursively on the operands' pcs. The result is a depth-first traversal of
+ * the expression tree.
+ *
+ */
+struct ExpressionDecompiler
+{
+    JSContext *cx;
+    StackFrame *fp;
+    RootedScript script;
+    RootedFunction fun;
+    BindingVector *localNames;
+    Sprinter sprinter;
+
+    ExpressionDecompiler(JSContext *cx, JSScript *script, JSFunction *fun)
+        : cx(cx),
+          script(cx, script),
+          fun(cx, fun),
+          localNames(NULL),
+          sprinter(cx)
+    {}
+    ~ExpressionDecompiler();
+    bool init();
+    bool decompilePC(jsbytecode *pc);
+    JSAtom *getVar(unsigned slot);
+    JSAtom *getArg(unsigned slot);
+    JSAtom *findLetVar(jsbytecode *pc, unsigned depth);
+    JSAtom *loadAtom(jsbytecode *pc);
+    bool quote(JSString *s, uint32_t quote);
+    bool write(const char *s);
+    bool write(JSString *s);
+    bool getOutput(char **out);
+};
+
+bool
+ExpressionDecompiler::decompilePC(jsbytecode *pc)
+{
+    JS_ASSERT(script->code <= pc && pc < script->code + script->length);
+    
+    PCStack pcstack(cx);
+    if (!pcstack.init(cx, script, pc))
+        return NULL;
+
+    JSOp op = (JSOp)*pc;
+
+    // None of these stack-writing ops generates novel values.
+    JS_ASSERT(op != JSOP_CASE && op != JSOP_DUP && op != JSOP_DUP2);
+
+    if (const char *token = CodeToken[op]) {
+        // Handle simple cases of binary and unary operators.
+        switch (js_CodeSpec[op].nuses) {
+          case 2: {
+            jssrcnote *sn = js_GetSrcNote(script, pc);
+            if (!sn || SN_TYPE(sn) != SRC_ASSIGNOP)
+                return write("(") &&
+                       decompilePC(pcstack[-2]) &&
+                       write(" ") &&
+                       write(token) &&
+                       write(" ") &&
+                       decompilePC(pcstack[-1]) &&
+                       write(")");
+            break;
+          }
+          case 1:
+            return write(token) &&
+                   write("(") &&
+                   decompilePC(pcstack[-1]) &&
+                   write(")");
+          default:
+            break;
+        }
+    }
+
+    switch (op) {
+      case JSOP_GETGNAME:
+      case JSOP_CALLGNAME:
+      case JSOP_NAME:
+      case JSOP_CALLNAME:
+        return write(loadAtom(pc));
+      case JSOP_GETARG:
+      case JSOP_CALLARG: {
+        unsigned slot = GET_ARGNO(pc);
+        JSAtom *atom = getArg(slot);
+        if (!atom)
+            break; // Destructuring
+        return write(atom);
+      }
+      case JSOP_GETLOCAL:
+      case JSOP_CALLLOCAL: {
+        unsigned i = GET_SLOTNO(pc);
+        JSAtom *atom;
+        if (i >= script->nfixed) {
+            i -= script->nfixed;
+            JS_ASSERT(i < unsigned(pcstack.depth()));
+            atom = findLetVar(pc, i);
+            if (!atom)
+                return decompilePC(pcstack[i]); // Destructing temporary
+        } else {
+            atom = getVar(i);
+        }
+        JS_ASSERT(atom);
+        return write(atom);
+      }
+      case JSOP_CALLALIASEDVAR:
+      case JSOP_GETALIASEDVAR: {
+        JSAtom *atom = ScopeCoordinateName(cx->runtime, script, pc);
+        JS_ASSERT(atom);
+        return write(atom);
+      }
+      case JSOP_LENGTH:
+      case JSOP_GETPROP:
+      case JSOP_CALLPROP: {
+        JSAtom *prop = (op == JSOP_LENGTH) ? cx->runtime->atomState.lengthAtom : loadAtom(pc);
+        if (!decompilePC(pcstack[-1]))
+            return false;
+        if (IsIdentifier(prop))
+            return write(".") &&
+                   quote(prop, '\0');
+        else
+            return write("[") &&
+                   quote(prop, '\'') &&
+                   write("]") >= 0;
+        return true;
+      }
+      case JSOP_GETELEM:
+      case JSOP_CALLELEM:
+        return decompilePC(pcstack[-2]) &&
+               write("[") &&
+               decompilePC(pcstack[-1]) &&
+               write("]");
+      case JSOP_NULL:
+        return write(js_null_str);
+      case JSOP_TRUE:
+        return write(js_true_str);
+      case JSOP_FALSE:
+        return write(js_false_str);
+      case JSOP_ZERO:
+      case JSOP_ONE:
+      case JSOP_INT8:
+      case JSOP_UINT16:
+      case JSOP_UINT24:
+      case JSOP_INT32: {
+        int32_t i;
+        switch (op) {
+          case JSOP_ZERO:
+            i = 0;
+            break;
+          case JSOP_ONE:
+            i = 1;
+            break;
+          case JSOP_INT8:
+            i = GET_INT8(pc);
+            break;
+          case JSOP_UINT16:
+            i = GET_UINT16(pc);
+            break;
+          case JSOP_UINT24:
+            i = GET_UINT24(pc);
+            break;
+          case JSOP_INT32:
+            i = GET_INT32(pc);
+            break;
+          default:
+            JS_NOT_REACHED("wat?");
+        }
+        return sprinter.printf("%d", i) >= 0;
+      }
+      case JSOP_STRING:
+        return quote(loadAtom(pc), '"');
+      case JSOP_UNDEFINED:
+        return write(js_undefined_str);
+      case JSOP_THIS:
+        // |this| could convert to a very long object initialiser, so cite it by
+        // its keyword name.
+        return write(js_this_str);
+      case JSOP_CALL:
+      case JSOP_FUNCALL:
+        return decompilePC(pcstack[-(GET_ARGC(pc) + 2)]) &&
+               write("(...)");
+      default:
+        break;
+    }
+    return write("(intermediate value)");
+}
+
+ExpressionDecompiler::~ExpressionDecompiler()
+{
+    cx->delete_<BindingVector>(localNames);
+}
+
+bool
+ExpressionDecompiler::init()
+{
+    if (!sprinter.init())
+        return false;
+
+    localNames = cx->new_<BindingVector>(cx);
+    if (!localNames)
+        return false;
+    if (!GetOrderedBindings(cx, script->bindings, localNames))
+        return false;
+
+    return true;
+}
+
+bool
+ExpressionDecompiler::write(const char *s)
+{
+    return sprinter.put(s) >= 0;
+}
+
+bool
+ExpressionDecompiler::write(JSString *s)
+{
+    return sprinter.putString(s) >= 0;
+}
+
+bool
+ExpressionDecompiler::quote(JSString *s, uint32_t quote)
+{
+    return QuoteString(&sprinter, s, quote) >= 0;
+}
+
+JSAtom *
+ExpressionDecompiler::loadAtom(jsbytecode *pc)
+{
+    return script->getAtom(GET_UINT32_INDEX(pc));
+}
+
+JSAtom *
+ExpressionDecompiler::findLetVar(jsbytecode *pc, unsigned depth)
+{
+    if (script->hasObjects()) {
+        JSObject *chain = GetBlockChainAtPC(cx, script, pc);
+        if (!chain)
+            return NULL;
+        JS_ASSERT(chain->isBlock());
+        do {
+            BlockObject &block = chain->asBlock();
+            uint32_t blockDepth = block.stackDepth();
+            uint32_t blockCount = block.slotCount();
+            if (uint32_t(depth - blockDepth) < uint32_t(blockCount)) {
+                for (Shape::Range r(block.lastProperty()); !r.empty(); r.popFront()) {
+                    const Shape &shape = r.front();
+                    if (shape.shortid() == int(depth - blockDepth)) {
+                        // !JSID_IS_ATOM(shape.propid()) happens for empty
+                        // destructuring variables in lets. They can be safely
+                        // ignored.
+                        if (JSID_IS_ATOM(shape.propid()))
+                            return JSID_TO_ATOM(shape.propid());
+                    }
+                }
+            }
+            chain = chain->enclosingScope();
+        } while (chain->isBlock());
+    }
+    return NULL;
+}
+
+JSAtom *
+ExpressionDecompiler::getArg(unsigned slot)
+{
+    JS_ASSERT(fun);
+    JS_ASSERT(slot < script->bindings.count());
+    return (*localNames)[slot].maybeName;
+}
+
+JSAtom *
+ExpressionDecompiler::getVar(unsigned slot)
+{
+    JS_ASSERT(fun);
+    slot += fun->nargs;
+    JS_ASSERT(slot < script->bindings.count());
+    return (*localNames)[slot].maybeName;
+}
+
+bool
+ExpressionDecompiler::getOutput(char **res)
+{
+    ptrdiff_t len = sprinter.stringEnd() - sprinter.stringAt(0);
+    *res = static_cast<char *>(cx->malloc_(len + 1));
+    if (!*res)
+        return false;
+    js_memcpy(*res, sprinter.stringAt(0), len);
+    (*res)[len] = 0;
+    return true;
+}
+
+static bool
+FindStartPC(JSContext *cx, JSScript *script, int spindex, Value v, jsbytecode **valuepc)
+{
+    jsbytecode *current = *valuepc;
+
+    if (spindex == JSDVG_IGNORE_STACK)
+        return true;
+
+    *valuepc = NULL;
+
+    PCStack pcstack(cx);
+    if (!pcstack.init(cx, script, current))
+        return false;
+
+    if (spindex == JSDVG_SEARCH_STACK) {
+        // We search from fp->sp to base to find the most recently calculated
+        // value matching v under assumption that it is it that caused
+        // exception.
+        Value *stackBase = cx->regs().spForStackDepth(0);
+        Value *sp = cx->regs().sp;
+        do {
+            if (sp == stackBase)
+                return true;
+        } while (*--sp != v);
+        if (sp < stackBase + pcstack.depth())
+            *valuepc = pcstack[sp - stackBase];
+    } else {
+        *valuepc = pcstack[spindex];
+    }
+    return true;
+}
+
+static bool
+DecompileExpressionFromStack(JSContext *cx, int spindex, Value v, char **res)
+{
+    JS_ASSERT(spindex < 0 ||
+              spindex == JSDVG_IGNORE_STACK ||
+              spindex == JSDVG_SEARCH_STACK);
+
+    *res = NULL;
+
+    if (!cx->hasfp() || !cx->fp()->isScriptFrame())
+        return true;
+    StackFrame *fp = js_GetTopStackFrame(cx, FRAME_EXPAND_ALL);
+    JSScript *script = fp->script();
+    jsbytecode *valuepc = cx->regs().pc;
+    JSFunction *fun = fp->maybeFun();
+    JS_ASSERT(script->code <= valuepc && valuepc < script->code + script->length);
+
+    // Give up if in prologue.
+    if (valuepc < script->main())
+        return true;
+
+    if (!FindStartPC(cx, script, spindex, v, &valuepc))
+        return false;
+    if (!valuepc)
+        return true;
+
+    ExpressionDecompiler ea(cx, script, fun);
+    if (!ea.init())
+        return false;
+    if (!ea.decompilePC(valuepc))
+        return false;
+
+    return ea.getOutput(res);
+}
+
 char *
 js_DecompileValueGenerator(JSContext *cx, int spindex, jsval v,
                            JSString *fallback)
 {
-    StackFrame *fp;
-    JSScript *script;
-    jsbytecode *pc;
-
-    JS_ASSERT(spindex < 0 ||
-              spindex == JSDVG_IGNORE_STACK ||
-              spindex == JSDVG_SEARCH_STACK);
-
-    if (!cx->hasfp() || !cx->fp()->isScriptFrame())
-        goto do_fallback;
-
-    fp = js_GetTopStackFrame(cx, FRAME_EXPAND_ALL);
-    script = fp->script();
-    pc = cx->regs().pc;
-    JS_ASSERT(script->code <= pc && pc < script->code + script->length);
-
-    if (pc < script->main())
-        goto do_fallback;
-
-    if (spindex != JSDVG_IGNORE_STACK) {
-        jsbytecode **pcstack;
-
-        /*
-         * Prepare computing pcstack containing pointers to opcodes that
-         * populated interpreter's stack with its current content.
-         */
-        pcstack = (jsbytecode **)
-                  cx->malloc_(StackDepth(script) * sizeof *pcstack);
-        if (!pcstack)
+    {
+        char *result;
+        if (!DecompileExpressionFromStack(cx, spindex, v, &result))
             return NULL;
-        jsbytecode *lastDecomposedPC = NULL;
-        int pcdepth = ReconstructPCStack(cx, script, pc, pcstack, &lastDecomposedPC);
-        if (pcdepth < 0)
-            goto release_pcstack;
-
-        if (spindex != JSDVG_SEARCH_STACK) {
-            JS_ASSERT(spindex < 0);
-            pcdepth += spindex;
-            if (pcdepth < 0)
-                goto release_pcstack;
-            pc = pcstack[pcdepth];
-        } else {
-            /*
-             * We search from fp->sp to base to find the most recently
-             * calculated value matching v under assumption that it is
-             * it that caused exception, see bug 328664.
-             */
-            Value *stackBase = cx->regs().spForStackDepth(0);
-            Value *sp = cx->regs().sp;
-            do {
-                if (sp == stackBase) {
-                    pcdepth = -1;
-                    goto release_pcstack;
-                }
-            } while (*--sp != v);
-
-            /*
-             * The value may have come from beyond stackBase + pcdepth, meaning
-             * that it came from a temporary slot pushed by the interpreter or
-             * arguments pushed for an Invoke call. Only update pc if beneath
-             * stackBase + pcdepth. If above, the value may or may not be
-             * produced by the current pc. Since it takes a fairly contrived
-             * combination of calls to produce a situation where this is not
-             * what we want, we just use the current pc.
-             *
-             * If we are in the middle of a decomposed opcode, use the outer
-             * 'fat' opcode itself. Any source notes for the operation which
-             * are needed during decompilation will be associated with the
-             * outer opcode.
-             */
-            if (sp < stackBase + pcdepth) {
-                pc = pcstack[sp - stackBase];
-                if (lastDecomposedPC) {
-                    size_t len = GetDecomposeLength(lastDecomposedPC,
-                                                    js_CodeSpec[*lastDecomposedPC].length);
-                    if (unsigned(pc - lastDecomposedPC) < len)
-                        pc = lastDecomposedPC;
-                }
-            }
+        if (result) {
+            if (strcmp(result, "(intermediate value)"))
+                return result;
+            cx->free_(result);
         }
-
-      release_pcstack:
-        cx->free_(pcstack);
-        if (pcdepth < 0)
-            goto do_fallback;
     }
-
-    {
-        char *name = DecompileExpression(cx, script, fp->maybeFun(), pc);
-        if (name != FAILED_EXPRESSION_DECOMPILER)
-            return name;
-    }
-
-  do_fallback:
     if (!fallback) {
+        if (v.isUndefined())
+            return JS_strdup(cx, js_undefined_str); // Prevent users from seeing "(void 0)"
         fallback = js_ValueToSource(cx, v);
         if (!fallback)
             return NULL;
     }
     size_t length = fallback->length();
     const jschar *chars = fallback->getChars(cx);
     if (!chars)
         return NULL;
@@ -5922,17 +6310,17 @@ DecompileExpression(JSContext *cx, JSScr
             Foreground::free_(pcstack);
         }
     } g;
 
     g.pcstack = (jsbytecode **)OffTheBooks::malloc_(StackDepth(script) * sizeof *g.pcstack);
     if (!g.pcstack)
         return NULL;
 
-    int pcdepth = ReconstructPCStack(cx, script, begin, g.pcstack, NULL);
+    int pcdepth = ReconstructPCStack(cx, script, begin, g.pcstack);
     if (pcdepth < 0)
          return FAILED_EXPRESSION_DECOMPILER;
 
     g.printer = js_NewPrinter(cx, "js_DecompileValueGenerator", fun, 0, false, false, false);
     if (!g.printer)
         return NULL;
 
     g.printer->dvgfence = end;
@@ -5941,17 +6329,17 @@ DecompileExpression(JSContext *cx, JSScr
         return NULL;
 
     return JS_strdup(cx, g.printer->sprinter.string());
 }
 
 unsigned
 js_ReconstructStackDepth(JSContext *cx, JSScript *script, jsbytecode *pc)
 {
-    return ReconstructPCStack(cx, script, pc, NULL, NULL);
+    return ReconstructPCStack(cx, script, pc, NULL);
 }
 
 #define LOCAL_ASSERT(expr)      LOCAL_ASSERT_RV(expr, -1);
 
 static int
 SimulateOp(JSContext *cx, JSScript *script, JSOp op, const JSCodeSpec *cs,
            jsbytecode *pc, jsbytecode **pcstack, unsigned &pcdepth)
 {
@@ -6003,42 +6391,37 @@ SimulateOp(JSContext *cx, JSScript *scri
         break;
     }
     pcdepth += ndefs;
     return pcdepth;
 }
 
 static int
 ReconstructPCStack(JSContext *cx, JSScript *script, jsbytecode *target,
-                   jsbytecode **pcstack, jsbytecode **lastDecomposedPC)
+                   jsbytecode **pcstack)
 {
     /*
      * Walk forward from script->main and compute the stack depth and stack of
      * operand-generating opcode PCs in pcstack.
      *
      * FIXME: Code to compute oplen copied from js_Disassemble1 and reduced.
      * FIXME: Optimize to use last empty-stack sequence point.
      */
 
     LOCAL_ASSERT(script->code <= target && target < script->code + script->length);
     jsbytecode *pc = script->code;
     unsigned pcdepth = 0;
     ptrdiff_t oplen;
     for (; pc < target; pc += oplen) {
         JSOp op = JSOp(*pc);
         const JSCodeSpec *cs = &js_CodeSpec[op];
-        oplen = cs->length;
-        if (oplen < 0)
-            oplen = js_GetVariableBytecodeLength(pc);
-
-        if (cs->format & JOF_DECOMPOSE) {
-            if (lastDecomposedPC)
-                *lastDecomposedPC = pc;
+        oplen = GetBytecodeLength(pc);
+
+        if (cs->format & JOF_DECOMPOSE)
             continue;
-        }
 
         /*
          * A (C ? T : E) expression requires skipping either T (if target is in
          * E) or both T and E (if target is after the whole expression) before
          * adjusting pcdepth based on the JSOP_IFEQ at pc that tests condition
          * C. We know that the stack depth can't change from what it was with
          * C on top of stack.
          */
--- a/js/src/jsstr.cpp
+++ b/js/src/jsstr.cpp
@@ -3027,30 +3027,30 @@ js_String(JSContext *cx, unsigned argc, 
 JSBool
 js::str_fromCharCode(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
     JS_ASSERT(args.length() <= StackSpace::ARGS_LENGTH_MAX);
     if (args.length() == 1) {
         uint16_t code;
-        if (!ValueToUint16(cx, args[0], &code))
+        if (!ToUint16(cx, args[0], &code))
             return JS_FALSE;
         if (StaticStrings::hasUnit(code)) {
             args.rval().setString(cx->runtime->staticStrings.getUnit(code));
             return JS_TRUE;
         }
         args[0].setInt32(code);
     }
     jschar *chars = (jschar *) cx->malloc_((args.length() + 1) * sizeof(jschar));
     if (!chars)
         return JS_FALSE;
     for (unsigned i = 0; i < args.length(); i++) {
         uint16_t code;
-        if (!ValueToUint16(cx, args[i], &code)) {
+        if (!ToUint16(cx, args[i], &code)) {
             cx->free_(chars);
             return JS_FALSE;
         }
         chars[i] = (jschar)code;
     }
     chars[args.length()] = 0;
     JSString *str = js_NewString(cx, chars, args.length());
     if (!str) {
--- a/js/src/jsutil.cpp
+++ b/js/src/jsutil.cpp
@@ -62,17 +62,21 @@ Compressor::compressMore()
 {
     uInt left = inplen - (zs.next_in - inp);
     bool done = left <= CHUNKSIZE;
     if (done)
         zs.avail_in = left;
     else if (zs.avail_in == 0)
         zs.avail_in = CHUNKSIZE;
     int ret = deflate(&zs, done ? Z_FINISH : Z_NO_FLUSH);
-    if (ret == Z_BUF_ERROR) {
+    if (ret == Z_MEM_ERROR) {
+        zs.avail_out = 0;
+        return false;
+    }
+    if (ret == Z_BUF_ERROR || (done && ret == Z_OK)) {
         JS_ASSERT(zs.avail_out == 0);
         return false;
     }
     JS_ASSERT_IF(!done, ret == Z_OK);
     JS_ASSERT_IF(done, ret == Z_STREAM_END);
     return !done;
 }
 
--- a/js/src/tests/e4x/Regress/regress-355478.js
+++ b/js/src/tests/e4x/Regress/regress-355478.js
@@ -9,17 +9,17 @@
 var BUGNUMBER = 355478;
 var summary = 'Do not crash with hasOwnProperty';
 var actual = '';
 var expect = '';
 
 printBugNumber(BUGNUMBER);
 START(summary);
 
-expect = 'TypeError: <x/>.hasOwnProperty is not a constructor';
+expect = 'TypeError: (intermediate value).hasOwnProperty is not a constructor';
 actual = '';
 
 try
 {
     new <x/>.hasOwnProperty("y");
 }
 catch(ex)
 {
--- a/js/src/tests/ecma_3/Object/8.6.1-01.js
+++ b/js/src/tests/ecma_3/Object/8.6.1-01.js
@@ -10,17 +10,17 @@ var summary = 'In strict mode, setting a
 
 printBugNumber(BUGNUMBER);
 printStatus (summary);
 
 enterFunc (String (BUGNUMBER));
 
 // should throw an error in strict mode
 var actual = '';
-var expect = 's.length is read-only';
+var expect = '"length" is read-only';
 var status = summary + ': Throw if STRICT and WERROR is enabled';
 
 if (!options().match(/strict/))
 {
   options('strict');
 }
 if (!options().match(/werror/))
 {
--- a/js/src/tests/js1_5/Regress/regress-372364.js
+++ b/js/src/tests/js1_5/Regress/regress-372364.js
@@ -16,28 +16,28 @@ test();
 
 function test()
 {
   enterFunc ('test');
   printBugNumber(BUGNUMBER);
   printStatus (summary);
 
   print('See Also bug 365891');
-  expect = /TypeError: a\(1\) (has no properties|is null)/;
+  expect = /TypeError: a\(.+\) (has no properties|is null)/;
   try
   {
     function a(){return null;} a(1)[0];
   }
   catch(ex)
   {
     actual = ex + '';
   }
   reportMatch(expect, actual, summary);
 
-  expect = /TypeError: \/a\/\.exec\("b"\) (has no properties|is null)/;
+  expect = /TypeError: \(intermediate value\).exec\(.+\) (has no properties|is null)/;
   try
   {
     /a/.exec("b")[0];
   }
   catch(ex)
   {
     actual = ex + '';
   }
--- a/js/src/tests/js1_5/extensions/regress-50447-1.js
+++ b/js/src/tests/js1_5/extensions/regress-50447-1.js
@@ -94,24 +94,19 @@ function test2()
 {
   /* generate an error with only msg property */
   enterFunc ("test2");
 
   /* note this test incorporates the path to the
      test file and assumes the path to the test case
      is a subdirectory of the directory containing jsDriver.pl
   */
-  var expectedLine = 114;
+  var expectedLine = 109;
   var expectedFileName = 'js1_5/extensions/regress-50447-1.js';
-  if (typeof document == "undefined")
-  {
-    expectedFileName = './' + expectedFileName;
-  }
-  else
-  {
+  if (typeof document != "undefined") {
     expectedFileName = document.location.href.
       replace(/[^\/]*(\?.*)$/, '') +
       expectedFileName;
   }
   var e = new InternalError ("msg");
   reportCompare ("(new InternalError(\"msg\", \"" +
 		 expectedFileName + "\", " + expectedLine + "))",
 		 normalize(e.toSource()),
@@ -132,22 +127,17 @@ function test3()
   /* note this test incorporates the path to the
      test file and assumes the path to the test case
      is a subdirectory of the directory containing jsDriver.pl
   */
 
   enterFunc ("test3");
 
   var expectedFileName = 'js1_5/extensions/regress-50447-1.js';
-  if (typeof document == "undefined")
-  {
-    expectedFileName = './' + expectedFileName;
-  }
-  else
-  {
+  if (typeof document != "undefined") {
     expectedFileName = document.location.href.
       replace(/[^\/]*(\?.*)$/, '') +
       expectedFileName;
   }
 
   var e = new InternalError ("msg");
   e.lineNumber = 10;
   reportCompare ("(new InternalError(\"msg\", \"" +
@@ -163,17 +153,17 @@ function test3()
 }
 
 
 function test4()
 {
   /* generate an error with only msg and filename properties */
   enterFunc ("test4");
 
-  var expectedLine = 173;
+  var expectedLine = 163;
 
   var e = new InternalError ("msg", "file");
   reportCompare ("(new InternalError(\"msg\", \"file\", " + expectedLine + "))",
 		 e.toSource(),
 		 "toSource() returned unexpected result.");
   reportCompare ("file", e.fileName,
 		 "fileName property returned unexpected value.");
   reportCompare (expectedLine, e.lineNumber,
--- a/js/src/tests/js1_6/Array/regress-304828.js
+++ b/js/src/tests/js1_6/Array/regress-304828.js
@@ -24,30 +24,30 @@ try
 catch(e)
 {
   actual = e + '';
 }
 reportCompare(expect, actual, summary + ': join');
 
 // reverse
 value  = '123';
-expect = 'TypeError: Array.prototype.reverse.call(value) is read-only';
+expect = 'TypeError: Array.prototype.reverse.call(...) is read-only';
 try
 {
   actual = Array.prototype.reverse.call(value) + '';
 }
 catch(e)
 {
   actual = e + '';
 }
 reportCompare(expect, actual, summary + ': reverse');
 
 // sort
 value  = 'cba';
-expect = 'TypeError: Array.prototype.sort.call(value) is read-only';
+expect = 'TypeError: Array.prototype.sort.call(...) is read-only';
 try
 {
   actual = Array.prototype.sort.call(value) + '';
 }
 catch(e)
 {
   actual = e + '';
 }
@@ -64,59 +64,59 @@ catch(e)
 {
   actual = e + '';
 }
 reportCompare(expect, actual, summary + ': push');
 reportCompare('abc', value, summary + ': push');
 
 // pop
 value  = 'abc';
-expect = "TypeError: property Array.prototype.pop.call(value) is non-configurable and can't be deleted";
+expect = "TypeError: property Array.prototype.pop.call(...) is non-configurable and can't be deleted";
 try
 {
   actual = Array.prototype.pop.call(value);
 }
 catch(e)
 {
   actual = e + '';
 }
 reportCompare(expect, actual, summary + ': pop');
 reportCompare('abc', value, summary + ': pop');
 
 // unshift
 value  = 'def';
-expect = 'TypeError: Array.prototype.unshift.call(value, "a", "b", "c") is read-only';
+expect = 'TypeError: Array.prototype.unshift.call(...) is read-only';
 try
 {
   actual = Array.prototype.unshift.call(value, 'a', 'b', 'c');
 }
 catch(e)
 {
   actual = e + '';
 }
 reportCompare(expect, actual, summary + ': unshift');
 reportCompare('def', value, summary + ': unshift');
 
 // shift
 value  = 'abc';
-expect = 'TypeError: Array.prototype.shift.call(value) is read-only';
+expect = 'TypeError: Array.prototype.shift.call(...) is read-only';
 try
 {
   actual = Array.prototype.shift.call(value);
 }
 catch(e)
 {
   actual = e + '';
 }
 reportCompare(expect, actual, summary + ': shift');
 reportCompare('abc', value, summary + ': shift');
 
 // splice
 value  = 'abc';
-expect = 'TypeError: Array.prototype.splice.call(value, 1, 1) is read-only';
+expect = 'TypeError: Array.prototype.splice.call(...) is read-only';
 try
 {
   actual = Array.prototype.splice.call(value, 1, 1) + '';
 }
 catch(e)
 {
   actual = e + '';
 }
--- a/js/src/tests/js1_6/Regress/regress-350417.js
+++ b/js/src/tests/js1_6/Regress/regress-350417.js
@@ -15,17 +15,17 @@ test();
 //-----------------------------------------------------------------------------
 
 function test()
 {
   enterFunc ('test');
   printBugNumber(BUGNUMBER);
   printStatus (summary);
 
-  expect = 'TypeError: y.a = [2 for each (p in [])] is not a function';
+  expect = 'TypeError: [] is not a function';
   try
   {
     eval('y = {}; (y.a = [2 for each (p in [])])();');
   }
   catch(ex)
   {
     actual = ex + '';
   }
--- a/js/src/tests/js1_7/block/regress-352616.js
+++ b/js/src/tests/js1_7/block/regress-352616.js
@@ -14,43 +14,43 @@ test();
 //-----------------------------------------------------------------------------
 
 function test()
 {
   enterFunc ('test');
   printBugNumber(BUGNUMBER);
   printStatus (summary);
 
-  expect = /TypeError: (\(let \(b = 1\) 2\).c is not a function|Cannot find function c.)/;
+  expect = /TypeError: (.+\.c is not a function|Cannot find function c.)/;
   actual = 'No Error';
   try
   {
     for(a in (let (b=1) 2).c(3)) { };
   }
   catch(ex)
   {
     actual = ex + '';
   }
 
   reportMatch(expect, actual, summary + ': 1');
 
-  expect = /TypeError: (\(let \(b = 1, d = 2\) 2\).c is not a function|Cannot find function c.)/;
+  expect = /TypeError: (.+\.c is not a function|Cannot find function c.)/;
   actual = 'No Error';
   try
   {
     for(a in (let (b=1,d=2) 2).c(3)) { };
   }
   catch(ex)
   {
     actual = ex + '';
   }
 
   reportMatch(expect, actual, summary + ': 2');
 
-  expect = /TypeError: (\(let \(b = 1, d = 2\) 2\).c is not a function|Cannot find function c.)/;
+  expect = /TypeError: (.+\.c is not a function|Cannot find function c.)/;
   actual = 'No Error';
   try
   {
     for(a in (let (b=1,d=2) 2).c(3)) { };
   }
   catch(ex)
   {
     actual = ex + '';
--- a/js/src/tests/js1_7/extensions/regress-355052-01.js
+++ b/js/src/tests/js1_7/extensions/regress-355052-01.js
@@ -15,17 +15,17 @@ test();
 //-----------------------------------------------------------------------------
 
 function test()
 {
   enterFunc ('test');
   printBugNumber(BUGNUMBER);
   printStatus (summary);
  
-  expect = /TypeError: NaN is not a function/;
+  expect = /TypeError: .+ is not a function/;
   actual = 'No Error';
   try
   {
     ( {valueOf: gc} - [function(){}].__iterator__ )();
   }
   catch(ex)
   {
     actual = ex + '';
--- a/js/src/tests/js1_7/extensions/regress-355052-02.js
+++ b/js/src/tests/js1_7/extensions/regress-355052-02.js
@@ -15,17 +15,17 @@ test();
 //-----------------------------------------------------------------------------
 
 function test()
 {
   enterFunc ('test');
   printBugNumber(BUGNUMBER);
   printStatus (summary);
 
-  expect = /TypeError: NaN is not a function/;
+  expect = /TypeError: .+ is not a function/;
   actual = 'No Error';
   try
   {
     ( {valueOf: gc} - [].a )();
   }
   catch(ex)
   {
     actual = ex + '';
--- a/js/src/tests/js1_7/extensions/regress-355052-03.js
+++ b/js/src/tests/js1_7/extensions/regress-355052-03.js
@@ -15,17 +15,17 @@ test();
 //-----------------------------------------------------------------------------
 
 function test()
 {
   enterFunc ('test');
   printBugNumber(BUGNUMBER);
   printStatus (summary);
 
-  expect = /TypeError: NaN is not a function/;
+  expect = /TypeError: .+ is not a function/;
   actual = 'No Error';
   try
   {
     var obj = {valueOf: gc };
 
     function f() {
       ( obj * [].a )();
     }
--- a/js/src/tests/js1_7/regress/regress-352870-02.js
+++ b/js/src/tests/js1_7/regress/regress-352870-02.js
@@ -16,17 +16,17 @@ test();
 //-----------------------------------------------------------------------------
 
 function test()
 {
   enterFunc ('test');
   printBugNumber(BUGNUMBER);
   printStatus (summary);
  
-  expect = /TypeError: \[1, 2, 3, 4\].g (has no properties|is undefined)/;
+  expect = /TypeError: .+\.g (has no properties|is undefined)/;
   actual = '';
   try
   {
     switch(4) { case [(let (y = [].j(5)) ({}))
                       for (p in ([1,2,3,4].g).v({},((w).y(z, <x/>))))]: }  }
   catch(ex)
   {
     actual = ex + '';
--- a/js/src/tests/js1_8/extensions/regress-469625.js
+++ b/js/src/tests/js1_8/extensions/regress-469625.js
@@ -17,17 +17,17 @@ test();
 //-----------------------------------------------------------------------------
 
 function test()
 {
   enterFunc ('test');
   printBugNumber(BUGNUMBER);
   printStatus (summary);
  
-  expect = 'TypeError: [].__proto__ is not a function';
+  expect = 'TypeError: (intermediate value).__proto__ is not a function';
 
   jit(true);
 
   Array.prototype.__proto__ = function () 3; 
 
   try
   {
     [].__proto__();
--- a/js/src/tests/js1_8_1/regress/regress-420399.js
+++ b/js/src/tests/js1_8_1/regress/regress-420399.js
@@ -15,22 +15,22 @@ test();
 //-----------------------------------------------------------------------------
 
 function test()
 {
   enterFunc ('test');
   printBugNumber(BUGNUMBER);
   printStatus (summary);
  
-  expect = /TypeError: let \(a = undefined\) a (is undefined|has no properties)/;
+  expect = "TypeError: undefined has no properties";
   try
   {
     (let (a=undefined) a).b = 3;
   }
   catch(ex)
   {
     actual = ex + '';
   }
 
-  reportMatch(expect, actual, summary);
+  reportCompare(expect, actual, summary);
 
   exitFunc ('test');
 }
--- a/js/src/tests/js1_8_5/regress/regress-469758.js
+++ b/js/src/tests/js1_8_5/regress/regress-469758.js
@@ -4,11 +4,11 @@
 var err;
 try {
     {let i=1}
     {let j=1; [][j][2]}
 } catch (e) {
     err = e;
 }
 assertEq(err instanceof TypeError, true);
-assertEq(err.message, "[][j] is undefined");
+assertEq(err.message, "(intermediate value)[j] is undefined");
 
 reportCompare(0, 0, 'ok');
--- a/js/src/tests/lib/tests.py
+++ b/js/src/tests/lib/tests.py
@@ -81,18 +81,17 @@ class Test(object):
     def get_command(self, js_cmd_prefix):
         dirname, filename = os.path.split(self.path)
         cmd = js_cmd_prefix
         if self.allowXml:
             cmd = cmd + [ '-e', 'options("allow_xml")' ]
         cmd = cmd + Test.prefix_command(dirname)
         if self.debugMode:
             cmd += [ '-d' ]
-        # There is a test that requires the path to start with './'.
-        cmd += [ '-f', './' + self.path ]
+        cmd += [ '-f', self.path ]
         return cmd
 
     def run(self, js_cmd_prefix, timeout=30.0):
         cmd = self.get_command(js_cmd_prefix)
         out, err, rc, dt, timed_out = run_cmd(cmd, timeout)
         return TestOutput(self, cmd, out, err, rc, dt, timed_out)
 
 class TestCase(Test):
--- a/js/xpconnect/src/dictionary_helper_gen.conf
+++ b/js/xpconnect/src/dictionary_helper_gen.conf
@@ -12,17 +12,16 @@ dictionaries = [
      [ 'BlobPropertyBag', 'nsIDOMFile.idl' ],
      [ 'MutationObserverInit', 'nsIDOMMutationObserver.idl' ],
      [ 'WifiConnectionInfoEventInit', 'nsIWifiEventInits.idl' ],
      [ 'WifiStatusChangeEventInit', 'nsIWifiEventInits.idl' ],
      [ 'GeoPositionOptions', 'nsIDOMGeoGeolocation.idl' ],
      [ 'DOMFileMetadataParameters', 'nsIDOMLockedFile.idl' ],
      [ 'XMLHttpRequestParameters', 'nsIXMLHttpRequest.idl' ],
      [ 'DeviceStorageEnumerationParameters', 'nsIDOMDeviceStorage.idl' ],
-     [ 'DeviceStorageChangeEventInit', 'nsIDOMDeviceStorageChangeEvent.idl' ],
      [ 'CameraSize', 'nsIDOMCameraManager.idl' ],
      [ 'CameraRegion', 'nsIDOMCameraManager.idl' ],
      [ 'CameraPosition', 'nsIDOMCameraManager.idl' ],
      [ 'CameraSelector', 'nsIDOMCameraManager.idl' ],
      [ 'CameraPictureOptions', 'nsIDOMCameraManager.idl' ]
    ]
 
 # include file names
--- a/js/xpconnect/src/dom_quickstubs.qsconf
+++ b/js/xpconnect/src/dom_quickstubs.qsconf
@@ -181,16 +181,17 @@ members = [
     'nsIDOMUIEvent.which',
     'nsIDOMUIEvent.rangeParent',
     'nsIDOMUIEvent.rangeOffset',
     'nsIDOMUIEvent.pageX',
     'nsIDOMUIEvent.pageY',
     'nsIDOMUIEvent.isChar',
 
     'nsIDOMTouch.*',
+    'nsIDOMTouchList.*',
     'nsIDOMTouchEvent.*',
 
     # dom/interfaces/geolocation - None.
 
     # dom/interfaces/html
     'nsIDOMHTMLAnchorElement.href',
     'nsIDOMHTMLAnchorElement.rel',
     'nsIDOMHTMLAnchorElement.target',
--- a/js/xpconnect/src/dombindings.conf
+++ b/js/xpconnect/src/dombindings.conf
@@ -36,20 +36,16 @@ list_classes = [
         'name': 'ClientRectList',
         'nativeClass': 'nsClientRectList'
     },
     {
         'name': 'PaintRequestList',
         'nativeClass': 'nsPaintRequestList'
     },
     {
-        'name': 'TouchList',
-        'nativeClass': 'nsDOMTouchList'
-    },
-    {
         'name': 'FileList',
         'nativeClass': 'nsDOMFileList'
     },
     {
         'name': 'SVGLengthList',
         'nativeClass': 'mozilla::DOMSVGLengthList'
     },
     {
@@ -73,19 +69,16 @@ list_classes = [
 prefableClasses = {
     }
 
 irregularFilenames = {
     'nsHTMLOptionCollection': 'nsHTMLSelectElement',
     'mozilla::dom::PropertyNodeList': 'HTMLPropertiesCollection',
     'nsClientRectList': 'nsClientRect',
     'nsPaintRequestList': 'nsPaintRequest',
-    'nsIDOMTouch': 'nsIDOMTouchEvent',
-    'nsIDOMTouchList': 'nsIDOMTouchEvent',
-    'nsDOMTouchList': 'nsDOMTouchEvent',
     'nsDOMFileList': 'nsDOMFile',
     }
 
 customInheritance = {
     'nsIDOMPropertyNodeList': 'nsIDOMNodeList',
     'nsIDOMHTMLOptionsCollection': 'nsIDOMHTMLCollection',
     'nsIDOMHTMLPropertiesCollection': 'nsIDOMHTMLCollection',
     }
--- a/js/xpconnect/src/event_impl_gen.conf.in
+++ b/js/xpconnect/src/event_impl_gen.conf.in
@@ -15,17 +15,18 @@ simple_events = [
     'CustomEvent',
     'PageTransitionEvent',
     'PopStateEvent',
     'HashChangeEvent',
     'CloseEvent',
     'MozContactChangeEvent',
     'DeviceOrientationEvent',
     'DeviceLightEvent',
-    'MozApplicationEvent'
+    'MozApplicationEvent',
+    'DeviceStorageChangeEvent'
   ]
 
 """ include file names """
 special_includes = [
     'DictionaryHelpers.h',
     'nsContentUtils.h',
     'nsIDOMApplicationRegistry.h'
   ]
--- a/layout/base/nsBidiPresUtils.cpp
+++ b/layout/base/nsBidiPresUtils.cpp
@@ -15,16 +15,17 @@
 #include "nsBidiUtils.h"
 #include "nsCSSFrameConstructor.h"
 #include "nsContainerFrame.h"
 #include "nsInlineFrame.h"
 #include "nsPlaceholderFrame.h"
 #include "nsFirstLetterFrame.h"
 #include "nsUnicodeProperties.h"
 #include "nsTextFrame.h"
+#include "nsStyleStructInlines.h"
 
 #undef NOISY_BIDI
 #undef REALLY_NOISY_BIDI
 
 using namespace mozilla;
 
 static const PRUnichar kSpace            = 0x0020;
 static const PRUnichar kZWSP             = 0x200B;
@@ -512,17 +513,17 @@ CreateContinuation(nsIFrame*  aFrame,
   NS_ASSERTION(parent, "Couldn't get frame parent in nsBidiPresUtils::CreateContinuation");
 
   nsresult rv = NS_OK;
   
   // Have to special case floating first letter frames because the continuation
   // doesn't go in the first letter frame. The continuation goes with the rest
   // of the text that the first letter frame was made out of.
   if (parent->GetType() == nsGkAtoms::letterFrame &&
-      parent->GetStyleDisplay()->IsFloating()) {
+      parent->IsFloating()) {
     nsFirstLetterFrame* letterFrame = do_QueryFrame(parent);
     rv = letterFrame->CreateContinuationForFloatingParent(presContext, aFrame,
                                                           aNewFrame, aIsFluid);
     return rv;
   }
 
   rv = presShell->FrameConstructor()->
     CreateContinuingFrame(presContext, aFrame, parent, aNewFrame, aIsFluid);
@@ -1087,17 +1088,17 @@ nsBidiPresUtils::TraverseFrames(nsBlockF
       } else { 
         // other frame type -- see the Unicode Bidi Algorithm:
         // "...inline objects (such as graphics) are treated as if they are ...
         // U+FFFC"
         // <wbr>, however, is treated as U+200B ZERO WIDTH SPACE. See
         // http://dev.w3.org/html5/spec/Overview.html#phrasing-content-1
         aBpd->AppendUnichar(content->IsHTML(nsGkAtoms::wbr) ?
                             kZWSP : kObjectSubstitute);
-        if (!frame->GetStyleContext()->GetStyleDisplay()->IsInlineOutside()) {
+        if (!frame->IsInlineOutside()) {
           // if it is not inline, end the paragraph
           ResolveParagraphWithinBlock(aBlockFrame, aBpd);
         }
       }
     } else {
       // For a non-leaf frame, recurse into TraverseFrames
       nsIFrame* kid = frame->GetFirstPrincipalChild();
       nsIFrame* overflowKid = frame->GetFirstChild(nsIFrame::kOverflowList);
--- a/layout/base/nsCSSFrameConstructor.cpp
+++ b/layout/base/nsCSSFrameConstructor.cpp
@@ -83,16 +83,17 @@
 #include "nsBox.h"
 #include "nsTArray.h"
 #include "nsGenericDOMDataNode.h"
 #include "mozilla/dom/Element.h"
 #include "FrameLayerBuilder.h"
 #include "nsAutoLayoutPhase.h"
 #include "nsCSSRenderingBorders.h"
 #include "nsRenderingContext.h"
+#include "nsStyleStructInlines.h"
 
 #ifdef MOZ_XUL
 #include "nsIRootBox.h"
 #include "nsIDOMXULCommandDispatcher.h"
 #include "nsIDOMXULDocument.h"
 #include "nsIXULDocument.h"
 #endif
 #ifdef MOZ_FLEXBOX
@@ -355,22 +356,16 @@ GetFieldSetBlockFrame(nsIFrame* aFieldse
 #define FCDATA_DECL(_flags, _func)                          \
   { _flags, { (FrameCreationFunc)_func }, nullptr, nullptr }
 #define FCDATA_WITH_WRAPPING_BLOCK(_flags, _func, _anon_box)  \
   { _flags | FCDATA_CREATE_BLOCK_WRAPPER_FOR_ALL_KIDS,        \
       { (FrameCreationFunc)_func }, nullptr, &_anon_box }
 
 //----------------------------------------------------------------------
 
-static bool
-IsInlineOutside(nsIFrame* aFrame)
-{
-  return aFrame->GetStyleDisplay()->IsInlineOutside();
-}
-
 /**
  * True if aFrame is an actual inline frame in the sense of non-replaced
  * display:inline CSS boxes.  In other words, it can be affected by {ib}
  * splitting and can contain first-letter frames.  Basically, this is either an
  * inline frame (positioned or otherwise) or an line frame (this last because
  * it can contain first-letter and because inserting blocks in the middle of it
  * needs to terminate it).
  */
@@ -469,17 +464,17 @@ static nsIFrame* GetSpecialPrevSibling(n
 static nsIFrame*
 GetLastSpecialSibling(nsIFrame* aFrame, bool aReturnEmptyTrailingInline)
 {
   for (nsIFrame *frame = aFrame, *next; ; frame = next) {
     next = GetSpecialSibling(frame);
     if (!next ||
         (!aReturnEmptyTrailingInline && !next->GetFirstPrincipalChild() &&
          !GetSpecialSibling(next))) {
-      NS_ASSERTION(!next || !IsInlineOutside(frame),
+      NS_ASSERTION(!next || !frame->IsInlineOutside(),
                    "Should have a block here!");
       return frame;
     }
   }
   NS_NOTREACHED("unreachable code");
   return nullptr;
 }
 
@@ -556,31 +551,31 @@ GetIBContainingBlockFor(nsIFrame* aFrame
 
 // After this function returns, aLink is pointing to the first link at or
 // after its starting position for which the next frame is a block.  If there
 // is no such link, it points to the end of the list.
 static void
 FindFirstBlock(nsFrameList::FrameLinkEnumerator& aLink)
 {
   for ( ; !aLink.AtEnd(); aLink.Next()) {
-    if (!IsInlineOutside(aLink.NextFrame())) {
+    if (!aLink.NextFrame()->IsInlineOutside()) {
       return;
     }
   }
 }
 
 // This function returns a frame link enumerator pointing to the first link in
 // the list for which the next frame is not block.  If there is no such link,
 // it points to the end of the list.
 static nsFrameList::FrameLinkEnumerator
 FindFirstNonBlock(const nsFrameList& aList)
 {
   nsFrameList::FrameLinkEnumerator link(aList);
   for (; !link.AtEnd(); link.Next()) {
-    if (IsInlineOutside(link.NextFrame())) {
+    if (link.NextFrame()->IsInlineOutside()) {
       break;
     }
   }
   return link;
 }
 
 inline void
 SetInitialSingleChild(nsIFrame* aParent, nsIFrame* aFrame)
@@ -1063,18 +1058,22 @@ nsFrameConstructorState::GetGeometricPar
   // elements. (1) has the usual problems when multiple frames share the same
   // content (notice all the special cases in this file dealing with inner
   // tables and outer tables which share the same content). (2) requires some
   // work and possible factoring.
   //
   // XXXbz couldn't we just force position to "static" on roots and
   // float to "none"?  That's OK per CSS 2.1, as far as I can tell.
   
-  if (aStyleDisplay->IsFloating() && mFloatedItems.containingBlock) {
-    NS_ASSERTION(!aStyleDisplay->IsAbsolutelyPositioned(),
+  if (aContentParentFrame && aContentParentFrame->IsSVGText()) {
+    return aContentParentFrame;
+  }
+
+  if (aStyleDisplay->IsFloatingStyle() && mFloatedItems.containingBlock) {
+    NS_ASSERTION(!aStyleDisplay->IsAbsolutelyPositionedStyle(),
                  "Absolutely positioned _and_ floating?");
     return mFloatedItems.containingBlock;
   }
 
   if (aStyleDisplay->mPosition == NS_STYLE_POSITION_ABSOLUTE &&
       mAbsoluteItems.containingBlock) {
     return mAbsoluteItems.containingBlock;
   }
@@ -1115,17 +1114,17 @@ nsFrameConstructorState::AddChild(nsIFra
                    "Popup whose parent is not the popup containing block?");
       NS_ASSERTION(mPopupItems.containingBlock, "Must have a popup set frame!");
       needPlaceholder = true;
       frameItems = &mPopupItems;
       placeholderType = PLACEHOLDER_FOR_POPUP;
   }
   else
 #endif // MOZ_XUL
-  if (aCanBeFloated && disp->IsFloating() &&
+  if (aCanBeFloated && aNewFrame->IsFloating() &&
       mFloatedItems.containingBlock) {
     NS_ASSERTION(aNewFrame->GetParent() == mFloatedItems.containingBlock,
                  "Float whose parent is not the float containing block?");
     needPlaceholder = true;
     frameItems = &mFloatedItems;
     placeholderType = PLACEHOLDER_FOR_FLOAT;
   }
   else if (aCanBePositioned) {
@@ -1924,17 +1923,17 @@ nsCSSFrameConstructor::ConstructTable(ns
 
   nsFrameItems childItems;
 
   // Process children
   nsFrameConstructorSaveState absoluteSaveState;
   const nsStyleDisplay* display = outerStyleContext->GetStyleDisplay();
 
   // Mark the table frame as an absolute container if needed
-  if (display->IsPositioned()) {
+  if (display->IsPositioned(aParentFrame)) {
     aState.PushAbsoluteContainingBlock(newFrame, absoluteSaveState);
   }
   if (aItem.mFCData->mBits & FCDATA_USE_CHILD_ITEMS) {
     rv = ConstructFramesFromItemList(aState, aItem.mChildItems,
                                      innerFrame, childItems);
   } else {
     rv = ProcessChildren(aState, content, styleContext, innerFrame,
                          true, childItems, false, aItem.mPendingBinding);
@@ -2469,18 +2468,18 @@ nsCSSFrameConstructor::ConstructDocEleme
       if (!contentFrame)
         return NS_ERROR_OUT_OF_MEMORY;
       nsFrameItems frameItems;
       // Use a null PendingBinding, since our binding is not in fact pending.
       rv = ConstructBlock(state, display, aDocElement,
                           state.GetGeometricParent(display,
                                                    mDocElementContainingBlock),
                           mDocElementContainingBlock, styleContext,
-                          &contentFrame, frameItems, display->IsPositioned(),
-                          nullptr);
+                          &contentFrame, frameItems,
+                          display->IsPositioned(contentFrame), nullptr);
       if (NS_FAILED(rv) || frameItems.IsEmpty())
         return rv;
       *aNewFrame = frameItems.FirstChild();
       NS_ASSERTION(frameItems.OnlyChild(), "multiple root element frames");
     }
   }
 
   // set the primary frame
@@ -2968,19 +2967,19 @@ nsCSSFrameConstructor::ConstructSelectFr
         // Notify the listbox that it is being used as a dropdown list.
       nsIListControlFrame * listControlFrame = do_QueryFrame(listFrame);
       if (listControlFrame) {
         listControlFrame->SetComboboxFrame(comboboxFrame);
       }
          // Notify combobox that it should use the listbox as it's popup
       comboBox->SetDropDown(listFrame);
 
-      NS_ASSERTION(!listStyle->GetStyleDisplay()->IsPositioned(),
+      NS_ASSERTION(!listFrame->IsPositioned(),
                    "Ended up with positioned dropdown list somehow.");
-      NS_ASSERTION(!listStyle->GetStyleDisplay()->IsFloating(),
+      NS_ASSERTION(!listFrame->IsFloating(),
                    "Ended up with floating dropdown list somehow.");
       
       // Initialize the scroll frame positioned. Note that it is NOT
       // initialized as absolutely positioned.
       nsIFrame* scrolledFrame = NS_NewSelectsAreaFrame(mPresShell, styleContext, flags);
 
       InitializeSelectFrame(aState, listFrame, scrolledFrame, content,
                             comboboxFrame, listStyle, true,
@@ -3132,17 +3131,17 @@ nsCSSFrameConstructor::ConstructFieldSet
   if (NS_FAILED(rv)) {
     return rv;
   }
   
   // Process children
   nsFrameConstructorSaveState absoluteSaveState;
   nsFrameItems                childItems;
 
-  if (aStyleDisplay->IsPositioned()) {
+  if (newFrame->IsPositioned()) {
     aState.PushAbsoluteContainingBlock(newFrame, absoluteSaveState);
   }
 
   ProcessChildren(aState, content, styleContext, blockFrame, true,
                   childItems, true, aItem.mPendingBinding);
 
   nsFrameItems fieldsetKids;
   fieldsetKids.AddChild(blockFrame);
@@ -3351,18 +3350,18 @@ nsCSSFrameConstructor::FindHTMLData(Elem
                "Unexpected parent for fieldset content anon box");
   if (aTag == nsGkAtoms::legend &&
       (!aParentFrame ||
        (aParentFrame->GetType() != nsGkAtoms::fieldSetFrame &&
         aParentFrame->GetStyleContext()->GetPseudo() !=
           nsCSSAnonBoxes::fieldsetContent) ||
        !aElement->GetParent() ||
        !aElement->GetParent()->IsHTML(nsGkAtoms::fieldset) ||
-       aStyleContext->GetStyleDisplay()->IsFloating() ||
-       aStyleContext->GetStyleDisplay()->IsAbsolutelyPositioned())) {
+       aStyleContext->GetStyleDisplay()->IsFloatingStyle() ||
+       aStyleContext->GetStyleDisplay()->IsAbsolutelyPositionedStyle())) {
     // <legend> is only special inside fieldset, check both the frame tree
     // parent and content tree parent due to XBL issues. For floated or
     // absolutely positioned legends we want to construct by display type and
     // not do special legend stuff.
     // XXXbz it would be nice if we could just decide this based on the parent
     // tag, and hence just use a SIMPLE_TAG_CHAIN for legend below, but the
     // fact that with XBL we could end up with this legend element in some
     // totally weird insertion point makes that chancy, I think.
@@ -3674,17 +3673,17 @@ nsCSSFrameConstructor::ConstructFrameFro
       }
 
       SetInitialSingleChild(newFrame, blockFrame);
 
       // Now figure out whether newFrame or blockFrame should be the
       // absolute container.  It should be the latter if it's
       // positioned, otherwise the former.
       const nsStyleDisplay* blockDisplay = blockContext->GetStyleDisplay();
-      if (blockDisplay->IsPositioned()) {
+      if (blockDisplay->IsPositioned(blockFrame)) {
         maybeAbsoluteContainingBlockDisplay = blockDisplay;
         maybeAbsoluteContainingBlock = blockFrame;
       }
       
       // Our kids should go into the blockFrame
       newFrame = blockFrame;
     }
 
@@ -3709,17 +3708,18 @@ nsCSSFrameConstructor::ConstructFrameFro
 
     // Process the child content if requested
     nsFrameItems childItems;
     nsFrameConstructorSaveState absoluteSaveState;
 
     if (bits & FCDATA_FORCE_NULL_ABSPOS_CONTAINER) {
       aState.PushAbsoluteContainingBlock(nullptr, absoluteSaveState);
     } else if (!(bits & FCDATA_SKIP_ABSPOS_PUSH) &&
-               maybeAbsoluteContainingBlockDisplay->IsPositioned()) {
+               maybeAbsoluteContainingBlockDisplay->IsPositioned
+                   (maybeAbsoluteContainingBlock)) {
       aState.PushAbsoluteContainingBlock(maybeAbsoluteContainingBlock,
                                          absoluteSaveState);
     }
 
     if (bits & FCDATA_USE_CHILD_ITEMS) {
       NS_ASSERTION(!ShouldSuppressFloatingOfDescendants(newFrame),
                    "uh oh -- this frame is supposed to _suppress_ floats, but "
                    "we're about to push it as a float containing block...");
@@ -4303,25 +4303,26 @@ nsCSSFrameConstructor::BuildScrollFrame(
 
     FinishBuildingScrollFrame(aNewFrame, aScrolledFrame);
     return NS_OK;
 }
 
 const nsCSSFrameConstructor::FrameConstructionData*
 nsCSSFrameConstructor::FindDisplayData(const nsStyleDisplay* aDisplay,
                                        Element* aElement,
+                                       nsIFrame* aParentFrame,
                                        nsStyleContext* aStyleContext)
 {
   PR_STATIC_ASSERT(eParentTypeCount < (1 << (32 - FCDATA_PARENT_TYPE_OFFSET)));
 
   // The style system ensures that floated and positioned frames are
   // block-level.
-  NS_ASSERTION(!(aDisplay->IsFloating() ||
-                 aDisplay->IsAbsolutelyPositioned()) ||
-               aDisplay->IsBlockOutside(),
+  NS_ASSERTION(!(aDisplay->IsFloatingStyle() ||
+                 aDisplay->IsAbsolutelyPositionedStyle()) ||
+               aDisplay->IsBlockOutsideStyle(),
                "Style system did not apply CSS2.1 section 9.7 fixups");
 
   // If this is "body", try propagating its scroll style to the viewport
   // Note that we need to do this even if the body is NOT scrollable;
   // it might have dynamically changed from scrollable to not scrollable,
   // and that might need to be propagated.
   // XXXbz is this the right place to do this?  If this code moves,
   // make this function static.
@@ -4335,38 +4336,40 @@ nsCSSFrameConstructor::FindDisplayData(c
                !mPresShell->GetPresContext()->IsPaginated(),
                "Shouldn't propagate scroll in paginated contexts");
 
   // If the frame is a block-level frame and is scrollable, then wrap it in a
   // scroll frame.
   // XXX Ignore tables for the time being
   // XXXbz it would be nice to combine this with the other block
   // case... Think about how do do this?
-  if (aDisplay->IsBlockInside() &&
+  if ((aParentFrame ? aDisplay->IsBlockInside(aParentFrame) :
+                      aDisplay->IsBlockInsideStyle()) &&
       aDisplay->IsScrollableOverflow() &&
       !propagatedScrollToViewport) {
     // Except we don't want to do that for paginated contexts for
     // frames that are block-outside and aren't frames for native
     // anonymous stuff.
     if (mPresShell->GetPresContext()->IsPaginated() &&
-        aDisplay->IsBlockOutside() &&
+        aDisplay->IsBlockOutsideStyle() &&
         !aElement->IsInNativeAnonymousSubtree()) {
       static const FrameConstructionData sForcedNonScrollableBlockData =
         FULL_CTOR_FCDATA(FCDATA_FORCED_NON_SCROLLABLE_BLOCK,
                          &nsCSSFrameConstructor::ConstructNonScrollableBlock);
       return &sForcedNonScrollableBlockData;
     }
 
     static const FrameConstructionData sScrollableBlockData =
       FULL_CTOR_FCDATA(0, &nsCSSFrameConstructor::ConstructScrollableBlock);
     return &sScrollableBlockData;
   }
 
   // Handle various non-scrollable blocks
-  if (aDisplay->IsBlockInside()) {
+  if ((aParentFrame ? aDisplay->IsBlockInside(aParentFrame) :
+                      aDisplay->IsBlockInsideStyle())) {
     static const FrameConstructionData sNonScrollableBlockData =
       FULL_CTOR_FCDATA(0, &nsCSSFrameConstructor::ConstructNonScrollableBlock);
     return &sNonScrollableBlockData;
   }
 
   static const FrameConstructionDataByInt sDisplayData[] = {
     // To keep the hash table small don't add inline frames (they're
     // typically things like FONT and B), because we can quickly
@@ -4419,18 +4422,20 @@ nsCSSFrameConstructor::FindDisplayData(c
                        FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRowGroup),
                        &nsCSSFrameConstructor::ConstructTableRow) },
     { NS_STYLE_DISPLAY_TABLE_CELL,
       FULL_CTOR_FCDATA(FCDATA_IS_TABLE_PART |
                        FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRow),
                        &nsCSSFrameConstructor::ConstructTableCell) }
   };
 
-  return FindDataByInt(aDisplay->mDisplay, aElement, aStyleContext,
-                       sDisplayData, ArrayLength(sDisplayData));
+  return FindDataByInt((aParentFrame ? aDisplay->GetDisplay(aParentFrame) :
+                                       aDisplay->mDisplay),
+                       aElement, aStyleContext, sDisplayData,
+                       ArrayLength(sDisplayData));
 }
 
 nsresult
 nsCSSFrameConstructor::ConstructScrollableBlock(nsFrameConstructorState& aState,
                                                 FrameConstructionItem&   aItem,
                                                 nsIFrame*                aParentFrame,
                                                 const nsStyleDisplay*    aDisplay,
                                                 nsFrameItems&            aFrameItems,
@@ -4450,17 +4455,18 @@ nsCSSFrameConstructor::ConstructScrollab
   // pass a temporary stylecontext, the correct one will be set later
   nsIFrame* scrolledFrame =
     NS_NewBlockFormattingContext(mPresShell, styleContext);
 
   nsFrameItems blockItem;
   nsresult rv = ConstructBlock(aState,
                                scrolledContentStyle->GetStyleDisplay(), content,
                                *aNewFrame, *aNewFrame, scrolledContentStyle,
-                               &scrolledFrame, blockItem, aDisplay->IsPositioned(),
+                               &scrolledFrame, blockItem,
+                               aDisplay->IsPositioned(scrolledFrame),
                                aItem.mPendingBinding);
   if (NS_UNLIKELY(NS_FAILED(rv))) {
     // XXXbz any cleanup needed here?
     return rv;
   }
 
   NS_ASSERTION(blockItem.FirstChild() == scrolledFrame,
                "Scrollframe's frameItems should be exactly the scrolled frame");
@@ -4482,32 +4488,33 @@ nsCSSFrameConstructor::ConstructNonScrol
   nsStyleContext* const styleContext = aItem.mStyleContext;
 
   // We want a block formatting context root in paginated contexts for
   // every block that would be scrollable in a non-paginated context.
   // We mark our blocks with a bit here if this condition is true, so
   // we can check it later in nsFrame::ApplyPaginatedOverflowClipping.
   bool clipPaginatedOverflow =
     (aItem.mFCData->mBits & FCDATA_FORCED_NON_SCROLLABLE_BLOCK) != 0;
-  if (aDisplay->IsAbsolutelyPositioned() ||
-      aDisplay->IsFloating() ||
-      NS_STYLE_DISPLAY_INLINE_BLOCK == aDisplay->mDisplay ||
-      clipPaginatedOverflow) {
+  if ((aDisplay->IsAbsolutelyPositionedStyle() ||
+       aDisplay->IsFloatingStyle() ||
+       NS_STYLE_DISPLAY_INLINE_BLOCK == aDisplay->mDisplay ||
+       clipPaginatedOverflow) &&
+      !aParentFrame->IsSVGText()) {
     *aNewFrame = NS_NewBlockFormattingContext(mPresShell, styleContext);
     if (clipPaginatedOverflow) {
       (*aNewFrame)->AddStateBits(NS_BLOCK_CLIP_PAGINATED_OVERFLOW);
     }
   } else {
     *aNewFrame = NS_NewBlockFrame(mPresShell, styleContext);
   }
 
   return ConstructBlock(aState, aDisplay, aItem.mContent,
                         aState.GetGeometricParent(aDisplay, aParentFrame),
                         aParentFrame, styleContext, aNewFrame,
-                        aFrameItems, aDisplay->IsPositioned(),
+                        aFrameItems, aDisplay->IsPositioned(*aNewFrame),
                         aItem.mPendingBinding);
 }
 
 
 nsresult 
 nsCSSFrameConstructor::InitAndRestoreFrame(const nsFrameConstructorState& aState,
                                            nsIContent*              aContent,
                                            nsIFrame*                aParentFrame,
@@ -4654,17 +4661,17 @@ nsCSSFrameConstructor::FindMathMLData(El
   if (aNameSpaceID != kNameSpaceID_MathML) 
     return nullptr;
 
   // Handle <math> specially, because it sometimes produces inlines
   if (aTag == nsGkAtoms::math) {
     // This needs to match the test in EnsureBlockDisplay in
     // nsRuleNode.cpp.  Though the behavior here for the display:table
     // case is pretty weird...
-    if (aStyleContext->GetStyleDisplay()->IsBlockOutside()) {
+    if (aStyleContext->GetStyleDisplay()->IsBlockOutsideStyle()) {
       static const FrameConstructionData sBlockMathData =
         FCDATA_DECL(FCDATA_FORCE_NULL_ABSPOS_CONTAINER |
                     FCDATA_WRAP_KIDS_IN_BLOCKS,
                     NS_CreateNewMathMLmathBlockFrame);
       return &sBlockMathData;
     }
 
     static const FrameConstructionData sInlineMathData =
@@ -5249,17 +5256,17 @@ nsCSSFrameConstructor::AddFrameConstruct
 
     // Now check for XUL display types
     if (!data) {
       data = FindXULDisplayData(display, element, styleContext);
     }
 
     // And general display types
     if (!data) {
-      data = FindDisplayData(display, element, styleContext);
+      data = FindDisplayData(display, element, aParentFrame, styleContext);
     }
 
     NS_ASSERTION(data, "Should have frame construction data now");
 
     if (data->mBits & FCDATA_SUPPRESS_FRAME) {
       SetAsUndisplayedContent(aItems, element, styleContext, isGeneratedContent);
       return;
     }
@@ -5289,18 +5296,19 @@ nsCSSFrameConstructor::AddFrameConstruct
        display->mDisplay != NS_STYLE_DISPLAY_TABLE_COLUMN)) {
     SetAsUndisplayedContent(aItems, aContent, styleContext, isGeneratedContent);
     return;
   }
 
   bool canHavePageBreak =
     (aFlags & ITEM_ALLOW_PAGE_BREAK) &&
     aState.mPresContext->IsPaginated() &&
-    !display->IsAbsolutelyPositioned() &&
-    !(bits & FCDATA_IS_TABLE_PART);
+    !display->IsAbsolutelyPositionedStyle() &&
+    !(bits & FCDATA_IS_TABLE_PART) &&
+    !(bits & FCDATA_IS_SVG_TEXT);
 
   if (canHavePageBreak && display->mBreakBefore) {
     AddPageBreakItem(aContent, aStyleContext, aItems);
   }
 
   FrameConstructionItem* item =
     aItems.AppendItem(data, aContent, aTag, aNameSpaceID,
                       pendingBinding, styleContext.forget(),
@@ -5341,17 +5349,18 @@ nsCSSFrameConstructor::AddFrameConstruct
     bool isInline =
       // Table-internal things are inline-outside if and only if they're kids of
       // inlines, since they'll trigger construction of inline-table
       // pseudos.
       ((bits & FCDATA_IS_TABLE_PART) &&
        (!aParentFrame || // No aParentFrame means inline
         aParentFrame->GetStyleDisplay()->mDisplay == NS_STYLE_DISPLAY_INLINE)) ||
       // Things that are inline-outside but aren't inline frames are inline
-      display->IsInlineOutside() ||
+      (aParentFrame ? display->IsInlineOutside(aParentFrame) :
+                      display->IsInlineOutsideStyle()) ||
       // Popups that are certainly out of flow.
       isPopup;
 
     // Set mIsAllInline conservatively.  It just might be that even an inline
     // that has mIsAllInline false doesn't need an {ib} split.  So this is just
     // an optimization to keep from doing too much work in cases when we can
     // show that mIsAllInline is true..
     item->mIsAllInline = item->mHasInlineEnds = isInline ||
@@ -5371,18 +5380,20 @@ nsCSSFrameConstructor::AddFrameConstruct
       (!(bits & FCDATA_DISALLOW_OUT_OF_FLOW) &&
        aState.GetGeometricParent(display, nullptr));
 
     // Set mIsBlock conservatively.  It's OK to set it false for some real
     // blocks, but not OK to set it true for things that aren't blocks.  Since
     // isOutOfFlow might be false even in cases when the frame will end up
     // out-of-flow, we can't use it here.  But we _can_ say that the frame will
     // for sure end up in-flow if it's not floated or absolutely positioned.
-    item->mIsBlock =
-      !isInline && !display->IsAbsolutelyPositioned() && !display->IsFloating();
+    item->mIsBlock = !isInline &&
+                     !display->IsAbsolutelyPositionedStyle() &&
+                     !display->IsFloatingStyle() &&
+                     !(bits & FCDATA_IS_SVG_TEXT);
   }
 
   if (item->mIsAllInline) {
     aItems.InlineItemAdded();
   } else if (item->mIsBlock) {
     aItems.BlockItemAdded();
   }
 
@@ -5591,18 +5602,17 @@ nsCSSFrameConstructor::GetAbsoluteContai
     }
 
     // If the frame is positioned, we will probably return it as the containing
     // block (see the exceptions below).  Otherwise, we'll start looking at the
     // parent frame, unless we're dealing with a scrollframe.
     // Scrollframes are special since they're not positioned, but their
     // scrolledframe might be.  So, we need to check this special case to return
     // the correct containing block (the scrolledframe) in that case.
-    const nsStyleDisplay* disp = frame->GetStyleDisplay();
-    if (!disp->IsPositioned()) {
+    if (!frame->IsPositioned()) {
       continue;
     }
     nsIFrame* absPosCBCandidate = nullptr;
     if (frame->GetType() == nsGkAtoms::scrollFrame) {
       nsIScrollableFrame* scrollFrame = do_QueryFrame(frame);
       absPosCBCandidate = scrollFrame->GetScrolledFrame();
     } else {
       // Only first continuations can be containing blocks.
@@ -5768,17 +5778,17 @@ nsCSSFrameConstructor::AppendFramesToPar
   if (!nextSibling && IsFrameSpecial(aParentFrame)) {
     // When we get here, our frame list might start with a block.  If it does
     // so, and aParentFrame is an inline, and it and all its previous
     // continuations have no siblings, then put the initial blocks from the
     // frame list into the previous block of the {ib} split.  Note that we
     // didn't want to stop at the block part of the split when figuring out
     // initial parent, because that could screw up float parenting; it's easier
     // to do this little fixup here instead.
-    if (aFrameList.NotEmpty() && !IsInlineOutside(aFrameList.FirstChild())) {
+    if (aFrameList.NotEmpty() && !aFrameList.FirstChild()->IsInlineOutside()) {
       // See whether our trailing inline is empty
       nsIFrame* firstContinuation = aParentFrame->GetFirstContinuation();
       if (firstContinuation->PrincipalChildList().IsEmpty()) {
         // Our trailing inline is empty.  Collect our starting blocks from
         // aFrameList, get the right parent frame for them, and put them in.
         nsFrameList::FrameLinkEnumerator firstNonBlockEnumerator =
           FindFirstNonBlock(aFrameList);
         nsFrameList blockKids = aFrameList.ExtractHead(firstNonBlockEnumerator);
@@ -5799,18 +5809,19 @@ nsCSSFrameConstructor::AppendFramesToPar
     nsFrameList inlineKids = aFrameList.ExtractHead(firstBlockEnumerator);
     if (!inlineKids.IsEmpty()) {
       AppendFrames(aParentFrame, kPrincipalList, inlineKids);
     }
 
     if (!aFrameList.IsEmpty()) {
       const nsStyleDisplay* parentDisplay = aParentFrame->GetStyleDisplay();
       bool positioned =
-        parentDisplay->mPosition == NS_STYLE_POSITION_RELATIVE ||
-        parentDisplay->HasTransform();
+        (parentDisplay->mPosition == NS_STYLE_POSITION_RELATIVE ||
+         parentDisplay->HasTransform()) &&
+        !aParentFrame->IsSVGText();
       nsFrameItems ibSiblings;
       CreateIBSiblings(aState, aParentFrame, positioned, aFrameList,
                        ibSiblings);
 
       // Make sure to trigger reflow of the inline that used to be our
       // last one and now isn't anymore, since its GetSkipSides() has
       // changed.
       mPresShell->FrameNeedsReflow(aParentFrame,
@@ -5846,18 +5857,18 @@ nsCSSFrameConstructor::IsValidSibling(ns
   nsIAtom* grandparentType = nullptr;
   if (parentFrame) {
     parentType = parentFrame->GetType();
     nsIFrame* grandparentFrame = parentFrame->GetParent();
     if (grandparentFrame) {
       grandparentType = grandparentFrame->GetType();
     }
   }
-    
-  PRUint8 siblingDisplay = aSibling->GetStyleDisplay()->mDisplay;
+
+  PRUint8 siblingDisplay = aSibling->GetDisplay();
   if ((NS_STYLE_DISPLAY_TABLE_COLUMN_GROUP == siblingDisplay) ||
       (NS_STYLE_DISPLAY_TABLE_COLUMN       == siblingDisplay) ||
       (NS_STYLE_DISPLAY_TABLE_CAPTION      == siblingDisplay) ||
       (NS_STYLE_DISPLAY_TABLE_HEADER_GROUP == siblingDisplay) ||
       (NS_STYLE_DISPLAY_TABLE_ROW_GROUP    == siblingDisplay) ||
       (NS_STYLE_DISPLAY_TABLE_FOOTER_GROUP == siblingDisplay) ||
       nsGkAtoms::menuFrame == parentType) {
     // if we haven't already, construct a style context to find the display type of aContent
@@ -6676,21 +6687,21 @@ nsCSSFrameConstructor::ContentAppended(n
   LAYOUT_PHASE_TEMP_REENTER();
 
   // If the parent is a block frame, and we're not in a special case
   // where frames can be moved around, determine if the list is for the
   // start or end of the block.
   if (nsLayoutUtils::GetAsBlock(parentFrame) && !haveFirstLetterStyle &&
       !haveFirstLineStyle && !parentSpecial) {
     items.SetLineBoundaryAtStart(!prevSibling ||
-        !prevSibling->GetStyleDisplay()->IsInlineOutside() ||
+        !prevSibling->IsInlineOutside() ||
         prevSibling->GetType() == nsGkAtoms::brFrame);
     // :after content can't be <br> so no need to check it
     items.SetLineBoundaryAtEnd(!parentAfterFrame ||
-        !parentAfterFrame->GetStyleDisplay()->IsInlineOutside());
+        !parentAfterFrame->IsInlineOutside());
   }
   // To suppress whitespace-only text frames, we have to verify that
   // our container's DOM child list matches its flattened tree child list.
   // This is guaranteed to be true if GetXBLChildNodesFor() returns null.
   items.SetParentHasNoXBLChildren(haveNoXBLChildren);
 
   nsFrameItems frameItems;
   ConstructFramesFromItemList(state, items, parentFrame, frameItems);
@@ -7056,25 +7067,25 @@ nsCSSFrameConstructor::ContentRangeInser
   nsIFrame* containingBlock = state.mFloatedItems.containingBlock;
   bool haveFirstLetterStyle = false;
   bool haveFirstLineStyle = false;
 
   // In order to shave off some cycles, we only dig up the
   // containing block haveFirst* flags if the parent frame where
   // the insertion/append is occurring is an inline or block
   // container. For other types of containers this isn't relevant.
-  const nsStyleDisplay* parentDisplay = parentFrame->GetStyleDisplay();
+  PRUint8 parentDisplay = parentFrame->GetDisplay();
 
   // Examine the parentFrame where the insertion is taking
   // place. If it's a certain kind of container then some special
   // processing is done.
-  if ((NS_STYLE_DISPLAY_BLOCK == parentDisplay->mDisplay) ||
-      (NS_STYLE_DISPLAY_LIST_ITEM == parentDisplay->mDisplay) ||
-      (NS_STYLE_DISPLAY_INLINE == parentDisplay->mDisplay) ||
-      (NS_STYLE_DISPLAY_INLINE_BLOCK == parentDisplay->mDisplay)) {
+  if ((NS_STYLE_DISPLAY_BLOCK == parentDisplay) ||
+      (NS_STYLE_DISPLAY_LIST_ITEM == parentDisplay) ||
+      (NS_STYLE_DISPLAY_INLINE == parentDisplay) ||
+      (NS_STYLE_DISPLAY_INLINE_BLOCK == parentDisplay)) {
     // Recover the special style flags for the containing block
     if (containingBlock) {
       haveFirstLetterStyle = HasFirstLetterStyle(containingBlock);
       haveFirstLineStyle =
         ShouldHaveFirstLineStyle(containingBlock->GetContent(),
                                  containingBlock->GetStyleContext());
     }
 
@@ -9700,17 +9711,17 @@ nsCSSFrameConstructor::CreateNeededTable
                                 true);
 
     // Here we're cheating a tad... technically, table-internal items should be
     // inline if aParentFrame is inline, but they'll get wrapped in an
     // inline-table in the end, so it'll all work out.  In any case, arguably
     // we don't need to maintain this state at this point... but it's better
     // to, I guess.
     newItem->mIsAllInline = newItem->mHasInlineEnds =
-      newItem->mStyleContext->GetStyleDisplay()->IsInlineOutside();
+      newItem->mStyleContext->GetStyleDisplay()->IsInlineOutsideStyle();
 
     // Table pseudo frames always induce line boundaries around their
     // contents.
     newItem->mChildItems.SetLineBoundaryAtStart(true);
     newItem->mChildItems.SetLineBoundaryAtEnd(true);
     // The parent of the items in aItems is also the parent of the items
     // in mChildItems
     newItem->mChildItems.SetParentHasNoXBLChildren(
@@ -9985,17 +9996,17 @@ nsCSSFrameConstructor::WrapFramesInFirst
   nsIFrame*                aBlockFrame,
   nsIFrame*                aLineFrame,
   nsFrameItems&            aFrameItems)
 {
   nsresult rv = NS_OK;
 
   // Find the part of aFrameItems that we want to put in the first-line
   nsFrameList::FrameLinkEnumerator link(aFrameItems);
-  while (!link.AtEnd() && IsInlineOutside(link.NextFrame())) {
+  while (!link.AtEnd() && link.NextFrame()->IsInlineOutside()) {
     link.Next();
   }
 
   nsFrameList firstLineChildren = aFrameItems.ExtractHead(link);
 
   if (firstLineChildren.IsEmpty()) {
     // Nothing is supposed to go into the first-line; nothing to do
     return NS_OK;
@@ -10422,17 +10433,17 @@ nsCSSFrameConstructor::CreateLetterFrame
     NS_ASSERTION(aBlockContinuation == GetFloatContainingBlock(aParentFrame),
                  "Containing block is confused");
     nsFrameConstructorState state(mPresShell, mFixedContainingBlock,
                                   GetAbsoluteContainingBlock(aParentFrame),
                                   aBlockContinuation);
 
     // Create the right type of first-letter frame
     const nsStyleDisplay* display = sc->GetStyleDisplay();
-    if (display->IsFloating()) {
+    if (display->IsFloating(aParentFrame)) {
       // Make a floating first-letter frame
       CreateFloatingLetterFrame(state, aBlockFrame, aTextContent, textFrame,
                                 blockContent, aParentFrame, sc, aResult);
     }
     else {
       // Make an inflow first-letter frame
       nsIFrame* letterFrame = NS_NewFirstLetterFrame(mPresShell, sc);
 
@@ -11017,17 +11028,18 @@ nsCSSFrameConstructor::ConstructInline(n
   //   Text("f")
 
   nsIContent* const content = aItem.mContent;
   nsStyleContext* const styleContext = aItem.mStyleContext;
 
   bool positioned =
     NS_STYLE_DISPLAY_INLINE == aDisplay->mDisplay &&
     (NS_STYLE_POSITION_RELATIVE == aDisplay->mPosition ||
-     aDisplay->HasTransform());
+     aDisplay->HasTransform()) &&
+    !aParentFrame->IsSVGText();
 
   nsIFrame* newFrame = NS_NewInlineFrame(mPresShell, styleContext);
   if (!newFrame) {
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
   // Initialize the frame
   InitAndRestoreFrame(aState, content, aParentFrame, nullptr, newFrame);
@@ -11117,17 +11129,17 @@ nsCSSFrameConstructor::CreateIBSiblings(
                                  nsCSSAnonBoxes::mozAnonymousBlock,
                                styleContext);
 
   nsIFrame* lastNewInline = aInitialInline->GetFirstContinuation();
   do {
     // On entry to this loop aChildItems is not empty and the first frame in it
     // is block-level.
     NS_PRECONDITION(aChildItems.NotEmpty(), "Should have child items");
-    NS_PRECONDITION(!IsInlineOutside(aChildItems.FirstChild()),
+    NS_PRECONDITION(!aChildItems.FirstChild()->IsInlineOutside(),
                     "Must have list starting with block");
 
     // The initial run of blocks belongs to an anonymous block that we create
     // right now. The anonymous block will be the parent of these block
     // children of the inline.
     nsIFrame* blockFrame;
     blockFrame = NS_NewBlockFrame(mPresShell, blockSC);
 
@@ -11568,17 +11580,17 @@ nsCSSFrameConstructor::WipeContainingBlo
   // 3)  Not an inline frame
   // We're guaranteed to find one, since nsStyleContext::ApplyStyleFixups
   // enforces that the root is display:none, display:table, or display:block.
   // Note that walking up "too far" is OK in terms of correctness, even if it
   // might be a little inefficient.  This is why we walk out of all
   // pseudo-frames -- telling which ones are or are not OK to walk out of is
   // too hard (and I suspect that we do in fact need to walk out of all of
   // them).
-  while (IsFrameSpecial(aContainingBlock) || IsInlineOutside(aContainingBlock) ||
+  while (IsFrameSpecial(aContainingBlock) || aContainingBlock->IsInlineOutside() ||
          aContainingBlock->GetStyleContext()->GetPseudo()) {
     aContainingBlock = aContainingBlock->GetParent();
     NS_ASSERTION(aContainingBlock,
                  "Must have non-inline, non-special, non-pseudo frame as root "
                  "(or child of root, for a table root)!");
   }
 
   // Tell parent of the containing block to reformulate the
--- a/layout/base/nsCSSFrameConstructor.h
+++ b/layout/base/nsCSSFrameConstructor.h
@@ -690,16 +690,19 @@ private:
      would have been scrollable but has been forced to be
      non-scrollable due to being in a paginated context. */
 #define FCDATA_FORCED_NON_SCROLLABLE_BLOCK 0x20000
   /* If FCDATA_CREATE_BLOCK_WRAPPER_FOR_ALL_KIDS is set, then create a
      block formatting context wrapper around the kids of this frame
      using the FrameConstructionData's mPseudoAtom for its anonymous
      box type. */
 #define FCDATA_CREATE_BLOCK_WRAPPER_FOR_ALL_KIDS 0x40000
+  /* If FCDATA_IS_SVG_TEXT is set, then this text frame is a descendant of
+     an SVG text frame. */
+#define FCDATA_IS_SVG_TEXT 0x80000
 
   /* Structure representing information about how a frame should be
      constructed.  */
   struct FrameConstructionData {
     // Flag bits that can modify the way the construction happens
     PRUint32 mBits;
     // We have exactly one of three types of functions, so use a union for
     // better cache locality for the ones that aren't pointer-to-member.  That
@@ -1368,17 +1371,17 @@ private:
                                                   PRInt32 aNameSpaceID,
                                                   nsIFrame* aParentFrame,
                                                   nsStyleContext* aStyleContext);
 
   /* Not static because it does PropagateScrollToViewport.  If this
      changes, make this static */
   const FrameConstructionData*
     FindDisplayData(const nsStyleDisplay* aDisplay, Element* aElement,
-                    nsStyleContext* aStyleContext);
+                    nsIFrame* aParentFrame, nsStyleContext* aStyleContext);
 
   /**
    * Construct a scrollable block frame
    */
   nsresult ConstructScrollableBlock(nsFrameConstructorState& aState,
                                     FrameConstructionItem&   aItem,
                                     nsIFrame*                aParentFrame,
                                     const nsStyleDisplay*    aDisplay,
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -416,17 +416,17 @@ nsLayoutUtils::GetChildListNameFor(nsIFr
 
       // XXX FIXME: Bug 350740
       // Return here, because the postcondition for this function actually
       // fails for this case, since the popups are not in a "real" frame list
       // in the popup set.
       return nsIFrame::kPopupList;
 #endif // MOZ_XUL
     } else {
-      NS_ASSERTION(aChildFrame->GetStyleDisplay()->IsFloating(),
+      NS_ASSERTION(aChildFrame->IsFloating(),
                    "not a floated frame");
       id = nsIFrame::kFloatList;
     }
 
   } else {
     nsIAtom* childType = aChildFrame->GetType();
     if (nsGkAtoms::menuPopupFrame == childType) {
       nsIFrame* parent = aChildFrame->GetParent();
@@ -452,17 +452,17 @@ nsLayoutUtils::GetChildListNameFor(nsIFr
   // corresponding overflow list.
   nsIFrame* parent = aChildFrame->GetParent();
   bool found = parent->GetChildList(id).ContainsFrame(aChildFrame);
   if (!found) {
     if (!(aChildFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW)) {
       found = parent->GetChildList(nsIFrame::kOverflowList)
                 .ContainsFrame(aChildFrame);
     }
-    else if (aChildFrame->GetStyleDisplay()->IsFloating()) {
+    else if (aChildFrame->IsFloating()) {
       found = parent->GetChildList(nsIFrame::kOverflowOutOfFlowList)
                 .ContainsFrame(aChildFrame);
     }
     // else it's positioned and should have been on the 'id' child list.
     NS_POSTCONDITION(found, "not in child list");
   }
 #endif
 
@@ -530,17 +530,17 @@ nsLayoutUtils::GetStyleFrame(nsIFrame* a
 
 nsIFrame*
 nsLayoutUtils::GetFloatFromPlaceholder(nsIFrame* aFrame) {
   NS_ASSERTION(nsGkAtoms::placeholderFrame == aFrame->GetType(),
                "Must have a placeholder here");
   if (aFrame->GetStateBits() & PLACEHOLDER_FOR_FLOAT) {
     nsIFrame *outOfFlowFrame =
       nsPlaceholderFrame::GetRealFrameForPlaceholder(aFrame);
-    NS_ASSERTION(outOfFlowFrame->GetStyleDisplay()->IsFloating(),
+    NS_ASSERTION(outOfFlowFrame->IsFloating(),
                  "How did that happen?");
     return outOfFlowFrame;
   }
 
   return nullptr;
 }
 
 // static
@@ -1883,17 +1883,17 @@ nsLayoutUtils::PaintFrame(nsRenderingCon
 
   // Flush the list so we don't trigger the IsEmpty-on-destruction assertion
   list.DeleteAll();
   return NS_OK;
 }
 
 PRInt32
 nsLayoutUtils::GetZIndex(nsIFrame* aFrame) {
-  if (!aFrame->GetStyleDisplay()->IsPositioned())
+  if (!aFrame->IsPositioned())
     return 0;
 
   const nsStylePosition* position =
     aFrame->GetStylePosition();
   if (position->mZIndex.GetUnit() == eStyleUnit_Integer)
     return position->mZIndex.GetIntValue();
 
   // sort the auto and 0 elements together
@@ -3440,17 +3440,17 @@ nsLayoutUtils::CalculateContentBottom(ns
   return contentBottom;
 }
 
 /* static */ nsIFrame*
 nsLayoutUtils::GetClosestLayer(nsIFrame* aFrame)
 {
   nsIFrame* layer;
   for (layer = aFrame; layer; layer = layer->GetParent()) {
-    if (layer->GetStyleDisplay()->IsPositioned() ||
+    if (layer->IsPositioned() ||
         (layer->GetParent() &&
           layer->GetParent()->GetType() == nsGkAtoms::scrollFrame))
       break;
   }
   if (layer)
     return layer;
   return aFrame->PresContext()->PresShell()->FrameManager()->GetRootFrame();
 }
@@ -4049,31 +4049,23 @@ nsLayoutUtils::GetDisplayRootFrame(nsIFr
       return f;
     nsIFrame* parent = GetCrossDocParentFrame(f);
     if (!parent)
       return f;
     f = parent;
   }
 }
 
-static bool
-IsNonzeroCoord(const nsStyleCoord& aCoord)
-{
-  if (eStyleUnit_Coord == aCoord.GetUnit())
-    return aCoord.GetCoordValue() != 0;
-  return false;
-}
-
 /* static */ PRUint32
 nsLayoutUtils::GetTextRunFlagsForStyle(nsStyleContext* aStyleContext,
-                                       const nsStyleText* aStyleText,
-                                       const nsStyleFont* aStyleFont)
+                                       const nsStyleFont* aStyleFont,
+                                       nscoord aLetterSpacing)
 {
   PRUint32 result = 0;
-  if (IsNonzeroCoord(aStyleText->mLetterSpacing)) {
+  if (aLetterSpacing != 0) {
     result |= gfxTextRunFactory::TEXT_DISABLE_OPTIONAL_LIGATURES;
   }
   switch (aStyleContext->GetStyleSVG()->mTextRendering) {
   case NS_STYLE_TEXT_RENDERING_OPTIMIZESPEED:
     result |= gfxTextRunFactory::TEXT_OPTIMIZE_SPEED;
     break;
   case NS_STYLE_TEXT_RENDERING_AUTO:
     if (aStyleFont->mFont.size <
--- a/layout/base/nsLayoutUtils.h
+++ b/layout/base/nsLayoutUtils.h
@@ -1306,18 +1306,18 @@ public:
   /**
    * Get textrun construction flags determined by a given style; in particular
    * some combination of:
    * -- TEXT_DISABLE_OPTIONAL_LIGATURES if letter-spacing is in use
    * -- TEXT_OPTIMIZE_SPEED if the text-rendering CSS property and font size
    * and prefs indicate we should be optimizing for speed over quality
    */
   static PRUint32 GetTextRunFlagsForStyle(nsStyleContext* aStyleContext,
-                                          const nsStyleText* aStyleText,
-                                          const nsStyleFont* aStyleFont);
+                                          const nsStyleFont* aStyleFont,
+                                          nscoord aLetterSpacing);
 
   /**
    * Takes two rectangles whose origins must be the same, and computes
    * the difference between their union and their intersection as two
    * rectangles. (This difference is a superset of the difference
    * between the two rectangles.)
    */
   static void GetRectDifferenceStrips(const nsRect& aR1, const nsRect& aR2,
--- a/layout/forms/nsLegendFrame.cpp
+++ b/layout/forms/nsLegendFrame.cpp
@@ -12,17 +12,17 @@
 #include "nsStyleConsts.h"
 #include "nsFormControlFrame.h"
 
 nsIFrame*
 NS_NewLegendFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
 {
 #ifdef DEBUG
   const nsStyleDisplay* disp = aContext->GetStyleDisplay();
-  NS_ASSERTION(!disp->IsAbsolutelyPositioned() && !disp->IsFloating(),
+  NS_ASSERTION(!disp->IsAbsolutelyPositionedStyle() && !disp->IsFloatingStyle(),
                "Legends should not be positioned and should not float");
 #endif
 
   nsIFrame* f = new (aPresShell) nsLegendFrame(aContext);
   if (f) {
     f->AddStateBits(NS_BLOCK_FLOAT_MGR | NS_BLOCK_MARGIN_ROOT);
   }
   return f;
--- a/layout/generic/TextOverflow.cpp
+++ b/layout/generic/TextOverflow.cpp
@@ -12,16 +12,17 @@
 #include "nsContentUtils.h"
 #include "nsGfxScrollFrame.h"
 #include "nsIScrollableFrame.h"
 #include "nsLayoutUtils.h"
 #include "nsPresContext.h"
 #include "nsRect.h"
 #include "nsRenderingContext.h"
 #include "nsTextFrame.h"
+#include "nsStyleStructInlines.h"
 #include "mozilla/Util.h"
 
 namespace mozilla {
 namespace css {
 
 static const PRUnichar kEllipsisChar[] = { 0x2026, 0x0 };
 static const PRUnichar kASCIIPeriodsChar[] = { '.', '.', '.', 0x0 };
 
@@ -48,17 +49,17 @@ GetSelfOrNearestBlock(nsIFrame* aFrame)
 
 // Return true if the frame is an atomic inline-level element.
 // It's not supposed to be called for block frames since we never
 // process block descendants for text-overflow.
 static bool
 IsAtomicElement(nsIFrame* aFrame, const nsIAtom* aFrameType)
 {
   NS_PRECONDITION(!nsLayoutUtils::GetAsBlock(aFrame) ||
-                  !aFrame->GetStyleDisplay()->IsBlockOutside(),
+                  !aFrame->IsBlockOutside(),
                   "unexpected block frame");
   NS_PRECONDITION(aFrameType != nsGkAtoms::placeholderFrame,
                   "unexpected placeholder frame");
   return !aFrame->IsFrameOfType(nsIFrame::eLineParticipant);
 }
 
 static bool
 IsFullyClipped(nsTextFrame* aFrame, nscoord aLeft, nscoord aRight,
--- a/layout/generic/nsBlockFrame.cpp
+++ b/layout/generic/nsBlockFrame.cpp
@@ -48,16 +48,17 @@
 #include "nsDisplayList.h"
 #include "nsContentErrors.h"
 #include "nsCSSAnonBoxes.h"
 #include "nsCSSFrameConstructor.h"
 #include "nsCSSRendering.h"
 #include "FrameLayerBuilder.h"
 #include "nsRenderingContext.h"
 #include "TextOverflow.h"
+#include "nsStyleStructInlines.h"
 #include "mozilla/Util.h" // for DebugOnly
 
 #ifdef IBMBIDI
 #include "nsBidiPresUtils.h"
 #endif // IBMBIDI
 
 #include "nsIDOMHTMLBodyElement.h"
 #include "nsIDOMHTMLHtmlElement.h"
@@ -1570,21 +1571,24 @@ nsBlockFrame::MarkLineDirty(line_iterato
 #endif
   }
 }
 
 /**
  * Test whether lines are certain to be aligned left so that we can make
  * resizing optimizations
  */
-bool static inline IsAlignedLeft(const PRUint8 aAlignment,
-                                 const PRUint8 aDirection,
-                                 const PRUint8 aUnicodeBidi)
-{
-  return (NS_STYLE_TEXT_ALIGN_LEFT == aAlignment ||
+static inline bool
+IsAlignedLeft(PRUint8 aAlignment,
+              PRUint8 aDirection,
+              PRUint8 aUnicodeBidi,
+              nsIFrame* aFrame)
+{
+  return (aFrame->IsSVGText() ||
+          NS_STYLE_TEXT_ALIGN_LEFT == aAlignment ||
           ((NS_STYLE_TEXT_ALIGN_DEFAULT == aAlignment &&
             NS_STYLE_DIRECTION_LTR == aDirection) ||
            (NS_STYLE_TEXT_ALIGN_END == aAlignment &&
             NS_STYLE_DIRECTION_RTL == aDirection)) &&
           !(NS_STYLE_UNICODE_BIDI_PLAINTEXT & aUnicodeBidi));
 }
 
 nsresult
@@ -1592,17 +1596,18 @@ nsBlockFrame::PrepareResizeReflow(nsBloc
 {
   const nsStyleText* styleText = GetStyleText();
   const nsStyleTextReset* styleTextReset = GetStyleTextReset();
   // See if we can try and avoid marking all the lines as dirty
   bool tryAndSkipLines =
       // The text must be left-aligned.
     IsAlignedLeft(styleText->mTextAlign, 
                   aState.mReflowState.mStyleVisibility->mDirection,
-                  styleTextReset->mUnicodeBidi) &&
+                  styleTextReset->mUnicodeBidi,
+                  this) &&
       // The left content-edge must be a constant distance from the left
       // border-edge.
       !GetStylePadding()->mPadding.GetLeft().HasPercent();
 
 #ifdef DEBUG
   if (gDisableResizeOpt) {
     tryAndSkipLines = false;
   }
@@ -1631,17 +1636,18 @@ nsBlockFrame::PrepareResizeReflow(nsBloc
       printf(": trying to avoid marking all lines dirty\n");
     }
 #endif
 
     // The last line might not be aligned left even if the rest of the block is
     bool skipLastLine = NS_STYLE_TEXT_ALIGN_AUTO == styleText->mTextAlignLast ||
       IsAlignedLeft(styleText->mTextAlignLast,
                     aState.mReflowState.mStyleVisibility->mDirection,
-                    styleTextReset->mUnicodeBidi);
+                    styleTextReset->mUnicodeBidi,
+                    this);
 
     for (line_iterator line = begin_lines(), line_end = end_lines();
          line != line_end;
          ++line)
     {
       // We let child blocks make their own decisions the same
       // way we are here.
       bool isLastLine = line == mLines.back() && !GetNextInFlow();
@@ -2626,17 +2632,17 @@ nsBlockFrame::PullFrameFrom(nsBlockReflo
                             nsFrameList&         aFromFrameList,
                             nsLineList::iterator aFromLine)
 {
   nsLineBox* fromLine = aFromLine;
   NS_ABORT_IF_FALSE(fromLine, "bad line to pull from");
   NS_ABORT_IF_FALSE(fromLine->GetChildCount(), "empty line");
   NS_ABORT_IF_FALSE(aLine->GetChildCount(), "empty line");
 
-  NS_ASSERTION(fromLine->IsBlock() == fromLine->mFirstChild->GetStyleDisplay()->IsBlockOutside(),
+  NS_ASSERTION(fromLine->IsBlock() == fromLine->mFirstChild->IsBlockOutside(),
                "Disagreement about whether it's a block or not");
 
   if (fromLine->IsBlock()) {
     // If our line is not empty and the child in aFromLine is a block
     // then we cannot pull up the frame into this line. In this case
     // we stop pulling.
     return nullptr;
   }
@@ -4243,25 +4249,27 @@ nsBlockFrame::PlaceLine(nsBlockReflowSta
 
   // Only block frames horizontally align their children because
   // inline frames "shrink-wrap" around their children (therefore
   // there is no extra horizontal space).
   const nsStyleText* styleText = GetStyleText();
 
   /**
    * text-align-last defaults to the same value as text-align when
-   * text-align-last is set to auto (unless when text-align is set to justify),
+   * text-align-last is set to auto (except when text-align is set to justify),
    * so in that case we don't need to set isLastLine.
    *
    * In other words, isLastLine really means isLastLineAndWeCare.
    */
-  bool isLastLine = ((NS_STYLE_TEXT_ALIGN_AUTO != styleText->mTextAlignLast ||
-                            NS_STYLE_TEXT_ALIGN_JUSTIFY == styleText->mTextAlign) &&
-                       (aLineLayout.GetLineEndsInBR() ||
-                        IsLastLine(aState, aLine)));
+  bool isLastLine =
+    !IsSVGText() &&
+    ((NS_STYLE_TEXT_ALIGN_AUTO != styleText->mTextAlignLast ||
+      NS_STYLE_TEXT_ALIGN_JUSTIFY == styleText->mTextAlign) &&
+     (aLineLayout.GetLineEndsInBR() ||
+      IsLastLine(aState, aLine)));
   aLineLayout.HorizontalAlignFrames(aLine->mBounds, isLastLine);
   // XXX: not only bidi: right alignment can be broken after
   // RelativePositionFrames!!!
   // XXXldb Is something here considering relatively positioned frames at
   // other than their original positions?
 #ifdef IBMBIDI
   // XXXldb Why don't we do this earlier?
   if (aState.mPresContext->BidiEnabled()) {
@@ -4943,21 +4951,21 @@ nsBlockFrame::AddFrames(nsFrameList& aFr
 
   // Walk through the new frames being added and update the line data
   // structures to fit.
   for (nsFrameList::Enumerator e(newFrames); !e.AtEnd(); e.Next()) {
     nsIFrame* newFrame = e.get();
     NS_ASSERTION(!aPrevSibling || aPrevSibling->GetNextSibling() == newFrame,
                  "Unexpected aPrevSibling");
     NS_ASSERTION(newFrame->GetType() != nsGkAtoms::placeholderFrame ||
-                 (!newFrame->GetStyleDisplay()->IsAbsolutelyPositioned() &&
-                  !newFrame->GetStyleDisplay()->IsFloating()),
+                 (!newFrame->IsAbsolutelyPositioned() &&
+                  !newFrame->IsFloating()),
                  "Placeholders should not float or be positioned");
 
-    bool isBlock = newFrame->GetStyleDisplay()->IsBlockOutside();
+    bool isBlock = newFrame->IsBlockOutside();
 
     // If the frame is a block frame, or if there is no previous line or if the
     // previous line is a block line we need to make a new line.  We also make
     // a new line, as an optimization, in the two cases we know we'll need it:
     // if the previous line ended with a <br>, or if it has significant whitespace
     // and ended in a newline.
     if (isBlock || prevSibLine == lineList->end() || prevSibLine->IsBlock() ||
         (aPrevSibling && ShouldPutNextSiblingOnNewLine(aPrevSibling))) {
@@ -5120,18 +5128,17 @@ nsBlockFrame::RemoveFrame(ChildListID aL
 
 void
 nsBlockFrame::DoRemoveOutOfFlowFrame(nsIFrame* aFrame)
 {
   // The containing block is always the parent of aFrame.
   nsBlockFrame* block = (nsBlockFrame*)aFrame->GetParent();
 
   // Remove aFrame from the appropriate list.
-  const nsStyleDisplay* display = aFrame->GetStyleDisplay();
-  if (display->IsAbsolutelyPositioned()) {
+  if (aFrame->IsAbsolutelyPositioned()) {
     // This also deletes the next-in-flows
     block->GetAbsoluteContainingBlock()->RemoveFrame(block,
                                                      kAbsoluteList,
                                                      aFrame);
   }
   else {
     // First remove aFrame's next-in-flows
     nsIFrame* nif = aFrame->GetNextInFlow();
@@ -5631,17 +5638,17 @@ nsBlockFrame::DoRemoveFrame(nsIFrame* aD
 nsresult
 nsBlockFrame::StealFrame(nsPresContext* aPresContext,
                          nsIFrame*      aChild,
                          bool           aForceNormal)
 {
   NS_PRECONDITION(aPresContext && aChild, "null pointer");
 
   if ((aChild->GetStateBits() & NS_FRAME_OUT_OF_FLOW) &&
-      aChild->GetStyleDisplay()->IsFloating()) {
+      aChild->IsFloating()) {
     bool removed = mFloats.RemoveFrameIfPresent(aChild);
     if (!removed) {
       nsFrameList* list = GetPushedFloats();
       if (list) {
         removed = list->RemoveFrameIfPresent(aChild);
       }
     }
     return removed ? NS_OK : NS_ERROR_UNEXPECTED;
@@ -6467,17 +6474,17 @@ nsLineBox* nsBlockFrame::GetFirstLineCon
   return cursor.get();
 }
 
 /* virtual */ void
 nsBlockFrame::ChildIsDirty(nsIFrame* aChild)
 {
   // See if the child is absolutely positioned
   if (aChild->GetStateBits() & NS_FRAME_OUT_OF_FLOW &&
-      aChild->GetStyleDisplay()->IsAbsolutelyPositioned()) {
+      aChild->IsAbsolutelyPositioned()) {
     // do nothing
   } else if (aChild == GetOutsideBullet()) {
     // The bullet lives in the first line, unless the first line has
     // height 0 and there is a second line, in which case it lives
     // in the second line.
     line_iterator bulletLine = begin_lines();
     if (bulletLine != end_lines() && bulletLine->mBounds.height == 0 &&
         bulletLine != mLines.back()) {
@@ -6559,17 +6566,18 @@ nsBlockFrame::SetInitialChildList(ChildL
     // block.
     nsIAtom *pseudo = GetStyleContext()->GetPseudo();
     bool haveFirstLetterStyle =
       (!pseudo ||
        (pseudo == nsCSSAnonBoxes::cellContent &&
         mParent->GetStyleContext()->GetPseudo() == nullptr) ||
        pseudo == nsCSSAnonBoxes::fieldsetContent ||
        pseudo == nsCSSAnonBoxes::scrolledContent ||
-       pseudo == nsCSSAnonBoxes::columnContent) &&
+       pseudo == nsCSSAnonBoxes::columnContent ||
+       pseudo == nsCSSAnonBoxes::mozSVGText) &&
       !IsFrameOfType(eMathML) &&
       nsRefPtr<nsStyleContext>(GetFirstLetterStyle(presContext)) != nullptr;
     NS_ASSERTION(haveFirstLetterStyle ==
                  ((mState & NS_BLOCK_HAS_FIRST_LETTER_STYLE) != 0),
                  "NS_BLOCK_HAS_FIRST_LETTER_STYLE state out of sync");
 #endif
     
     rv = AddFrames(aChildList, nullptr);
--- a/layout/generic/nsContainerFrame.cpp
+++ b/layout/generic/nsContainerFrame.cpp
@@ -769,17 +769,17 @@ nsContainerFrame::SyncFrameViewPropertie
     // See if the view should be hidden or visible
     vm->SetViewVisibility(aView,
         aStyleContext->GetStyleVisibility()->IsVisible()
             ? nsViewVisibility_kShow : nsViewVisibility_kHide);
   }
 
   // See if the frame is being relatively positioned or absolutely
   // positioned
-  bool isPositioned = aStyleContext->GetStyleDisplay()->IsPositioned();
+  bool isPositioned = aFrame->IsPositioned();
 
   PRInt32 zIndex = 0;
   bool    autoZIndex = false;
 
   if (!isPositioned) {
     autoZIndex = true;
   } else {
     // Make sure z-index is correct
--- a/layout/generic/nsContainerFrame.h
+++ b/layout/generic/nsContainerFrame.h
@@ -510,17 +510,17 @@ protected:
  * in nsAbsoluteContainingBlock and pretend the continuation is an overflow
  * container. This isn't an ideal solution, but it lets us print the content
  * at least. See bug 154892.
  */
 
 #define IS_TRUE_OVERFLOW_CONTAINER(frame)                      \
   (  (frame->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER)  \
   && !( (frame->GetStateBits() & NS_FRAME_OUT_OF_FLOW) &&      \
-        frame->GetStyleDisplay()->IsAbsolutelyPositioned()  )  )
+        frame->IsAbsolutelyPositioned()  )  )
 //XXXfr This check isn't quite correct, because it doesn't handle cases
 //      where the out-of-flow has overflow.. but that's rare.
 //      We'll need to revisit the way abspos continuations are handled later
 //      for various reasons, this detail is one of them. See bug 154892
 
 /**
  * Helper class for tracking overflow container continuations during reflow.
  *
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -440,18 +440,18 @@ IsFontSizeInflationContainer(nsIFrame* a
    */
 
   // The root frame should always be an inflation container.
   if (!aFrame->GetParent()) {
     return true;
   }
 
   nsIContent *content = aFrame->GetContent();
-  bool isInline = (aStyleDisplay->mDisplay == NS_STYLE_DISPLAY_INLINE ||
-                   (aStyleDisplay->IsFloating() &&
+  bool isInline = (aFrame->GetDisplay() == NS_STYLE_DISPLAY_INLINE ||
+                   (aFrame->IsFloating() &&
                     aFrame->GetType() == nsGkAtoms::letterFrame) ||
                    // Given multiple frames for the same node, only the
                    // outer one should be considered a container.
                    // (Important, e.g., for nsSelectsAreaFrame.)
                    (aFrame->GetParent()->GetContent() == content) ||
                    (content && (content->IsHTML(nsGkAtoms::option) ||
                                 content->IsHTML(nsGkAtoms::optgroup) ||
                                 content->IsInNativeAnonymousSubtree()))) &&
@@ -496,17 +496,18 @@ nsFrame::Init(nsIContent*      aContent,
                        NS_FRAME_MAY_BE_TRANSFORMED |
                        NS_FRAME_MAY_HAVE_GENERATED_CONTENT);
   }
   if (mParent) {
     nsFrameState state = mParent->GetStateBits();
 
     // Make bits that are currently off (see constructor) the same:
     mState |= state & (NS_FRAME_INDEPENDENT_SELECTION |
-                       NS_FRAME_GENERATED_CONTENT);
+                       NS_FRAME_GENERATED_CONTENT |
+                       NS_FRAME_IS_SVG_TEXT);
   }
   const nsStyleDisplay *disp = GetStyleDisplay();
   if (disp->HasTransform()) {
     // The frame gets reconstructed if we toggle the -moz-transform
     // property, so we can set this bit here and then ignore it.
     mState |= NS_FRAME_MAY_BE_TRANSFORMED;
   }
 
@@ -516,17 +517,17 @@ nsFrame::Init(nsIContent*      aContent,
       // font size inflation is not enabled.
       || true
 #endif
       ) {
     if (IsFontSizeInflationContainer(this, disp)) {
       AddStateBits(NS_FRAME_FONT_INFLATION_CONTAINER);
       if (!GetParent() ||
           // I'd use NS_FRAME_OUT_OF_FLOW, but it's not set yet.
-          disp->IsFloating() || disp->IsAbsolutelyPositioned()) {
+          disp->IsFloating(this) || disp->IsAbsolutelyPositioned(this)) {
         AddStateBits(NS_FRAME_FONT_INFLATION_FLOW_ROOT);
       }
     }
     NS_ASSERTION(GetParent() ||
                  (GetStateBits() & NS_FRAME_FONT_INFLATION_CONTAINER),
                  "root frame should always be a container");
   }
 
@@ -806,17 +807,18 @@ const nsIFrame::ChildListID nsIFrame::kS
 const nsIFrame::ChildListID nsIFrame::kNoReflowPrincipalList;
 #endif
 
 /* virtual */ nsMargin
 nsIFrame::GetUsedMargin() const
 {
   nsMargin margin(0, 0, 0, 0);
   if ((mState & NS_FRAME_FIRST_REFLOW) &&
-      !(mState & NS_FRAME_IN_REFLOW))
+      !(mState & NS_FRAME_IN_REFLOW) ||
+      (mState & NS_FRAME_IS_SVG_TEXT))
     return margin;
 
   nsMargin *m = static_cast<nsMargin*>
                            (Properties().Get(UsedMarginProperty()));
   if (m) {
     margin = *m;
   } else {
 #ifdef DEBUG
@@ -828,17 +830,18 @@ nsIFrame::GetUsedMargin() const
   return margin;
 }
 
 /* virtual */ nsMargin
 nsIFrame::GetUsedBorder() const
 {
   nsMargin border(0, 0, 0, 0);
   if ((mState & NS_FRAME_FIRST_REFLOW) &&
-      !(mState & NS_FRAME_IN_REFLOW))
+      !(mState & NS_FRAME_IN_REFLOW) ||
+      (mState & NS_FRAME_IS_SVG_TEXT))
     return border;
 
   // Theme methods don't use const-ness.
   nsIFrame *mutable_this = const_cast<nsIFrame*>(this);
 
   const nsStyleDisplay *disp = GetStyleDisplay();
   if (mutable_this->IsThemed(disp)) {
     nsIntMargin result;
@@ -863,17 +866,18 @@ nsIFrame::GetUsedBorder() const
   return border;
 }
 
 /* virtual */ nsMargin
 nsIFrame::GetUsedPadding() const
 {
   nsMargin padding(0, 0, 0, 0);
   if ((mState & NS_FRAME_FIRST_REFLOW) &&
-      !(mState & NS_FRAME_IN_REFLOW))
+      !(mState & NS_FRAME_IN_REFLOW) ||
+      (mState & NS_FRAME_IS_SVG_TEXT))
     return padding;
 
   // Theme methods don't use const-ness.
   nsIFrame *mutable_this = const_cast<nsIFrame*>(this);
 
   const nsStyleDisplay *disp = GetStyleDisplay();
   if (mutable_this->IsThemed(disp)) {
     nsPresContext *presContext = PresContext();
@@ -1487,17 +1491,17 @@ inline static bool IsSVGContentWithCSSCl
 
 bool
 nsIFrame::GetClipPropClipRect(const nsStyleDisplay* aDisp, nsRect* aRect,
                               const nsSize& aSize) const
 {
   NS_PRECONDITION(aRect, "Must have aRect out parameter");
 
   if (!(aDisp->mClipFlags & NS_STYLE_CLIP_RECT) ||
-      !(aDisp->IsAbsolutelyPositioned() || IsSVGContentWithCSSClip(this))) {
+      !(aDisp->IsAbsolutelyPositioned(this) || IsSVGContentWithCSSClip(this))) {
     return false;
   }
 
   *aRect = aDisp->mClip;
   if (NS_STYLE_CLIP_RIGHT_AUTO & aDisp->mClipFlags) {
     aRect->width = aSize.width - aRect->x;
   }
   if (NS_STYLE_CLIP_BOTTOM_AUTO & aDisp->mClipFlags) {
@@ -2095,18 +2099,18 @@ nsIFrame::BuildDisplayListForChild(nsDis
 
   // Child is composited if it's transformed, partially transparent, or has
   // SVG effects.
   const nsStyleDisplay* disp = child->GetStyleDisplay();
   bool isVisuallyAtomic = child->HasOpacity()
     || child->IsTransformed()
     || nsSVGIntegrationUtils::UsingEffectsForFrame(child);
 
-  bool isPositioned = !isSVG && disp->IsPositioned();
-  if (isVisuallyAtomic || isPositioned || (!isSVG && disp->IsFloating()) ||
+  bool isPositioned = !isSVG && disp->IsPositioned(child);
+  if (isVisuallyAtomic || isPositioned || (!isSVG && disp->IsFloating(child)) ||
       ((disp->mClipFlags & NS_STYLE_CLIP_RECT) &&
        IsSVGContentWithCSSClip(child)) ||
       (aFlags & DISPLAY_CHILD_FORCE_STACKING_CONTEXT)) {
     // If you change this, also change IsPseudoStackingContextFromStyle()
     pseudoStackingContext = true;
   }
 
   // This controls later whether we build an nsDisplayWrapList or an
@@ -2237,17 +2241,17 @@ nsIFrame::BuildDisplayListForChild(nsDis
           nsDisplayList fixedPosDescendantList;
           fixedPosDescendantList.AppendToTop(item);
           aLists.PositionedDescendants()->AppendNewToTop(
               new (aBuilder) nsDisplayFixedPosition(aBuilder, item->GetUnderlyingFrame(),
                                                     child, &fixedPosDescendantList));
         }
       }
     }
-  } else if (!isSVG && disp->IsFloating()) {
+  } else if (!isSVG && disp->IsFloating(child)) {
     if (!list.IsEmpty()) {
       rv = aLists.Floats()->AppendNewToTop(new (aBuilder)
           nsDisplayWrapList(aBuilder, child, &list));
       NS_ENSURE_SUCCESS(rv, rv);
     }
   } else {
     aLists.Content()->AppendToTop(&list);
   }
@@ -3464,17 +3468,17 @@ nsIFrame::ContentOffsets OffsetsForSingl
     offsets.secondaryOffset = range.end;
     offsets.associateWithNext = true;
     return offsets;
   }
 
   // Figure out whether the offsets should be over, after, or before the frame
   nsRect rect(nsPoint(0, 0), aFrame->GetSize());
 
-  bool isBlock = (aFrame->GetStyleDisplay()->mDisplay != NS_STYLE_DISPLAY_INLINE);
+  bool isBlock = aFrame->GetDisplay() != NS_STYLE_DISPLAY_INLINE;
   bool isRtl = (aFrame->GetStyleVisibility()->mDirection == NS_STYLE_DIRECTION_RTL);
   if ((isBlock && rect.y < aPoint.y) ||
       (!isBlock && ((isRtl  && rect.x + rect.width / 2 > aPoint.x) || 
                     (!isRtl && rect.x + rect.width / 2 < aPoint.x)))) {
     offsets.offset = range.end;
     if (rect.Contains(aPoint))
       offsets.secondaryOffset = range.start;
     else
@@ -5009,17 +5013,18 @@ ComputeOutlineAndEffectsRect(nsIFrame* a
   }
 
   return r;
 }
 
 nsPoint
 nsIFrame::GetRelativeOffset(const nsStyleDisplay* aDisplay) const
 {
-  if (!aDisplay || NS_STYLE_POSITION_RELATIVE == aDisplay->mPosition) {
+  if (!aDisplay ||
+      aDisplay->IsRelativelyPositioned(this)) {
     nsPoint *offsets = static_cast<nsPoint*>
       (Properties().Get(ComputedOffsetProperty()));
     if (offsets) {
       return *offsets;
     }
   }
   return nsPoint(0,0);
 }
@@ -5285,17 +5290,17 @@ GetNearestBlockContainer(nsIFrame* frame
 }
 
 nsIFrame*
 nsIFrame::GetContainingBlock() const
 {
   // MathML frames might have absolute positioning style, but they would
   // still be in-flow.  So we have to check to make sure that the frame
   // is really out-of-flow too.
-  if (GetStyleDisplay()->IsAbsolutelyPositioned() &&
+  if (IsAbsolutelyPositioned() &&
       (GetStateBits() & NS_FRAME_OUT_OF_FLOW)) {
     return GetParent(); // the parent is always the containing block
   }
   return GetNearestBlockContainer(GetParent());
 }
 
 #ifdef DEBUG
 
@@ -7404,16 +7409,62 @@ nsIFrame::IsFocusable(PRInt32 *aTabIndex
  * should return false if this is not a text frame.
  */
 bool
 nsIFrame::HasTerminalNewline() const
 {
   return false;
 }
 
+static PRUint8
+ConvertSVGDominantBaselineToVerticalAlign(PRUint8 aDominantBaseline)
+{
+  switch (aDominantBaseline) {
+  case NS_STYLE_DOMINANT_BASELINE_HANGING:
+  case NS_STYLE_DOMINANT_BASELINE_TEXT_BEFORE_EDGE:
+    return NS_STYLE_VERTICAL_ALIGN_TEXT_TOP;
+  case NS_STYLE_DOMINANT_BASELINE_TEXT_AFTER_EDGE:
+  case NS_STYLE_DOMINANT_BASELINE_IDEOGRAPHIC:
+    return NS_STYLE_VERTICAL_ALIGN_TEXT_BOTTOM;
+  case NS_STYLE_DOMINANT_BASELINE_CENTRAL:
+  case NS_STYLE_DOMINANT_BASELINE_MIDDLE:
+    return NS_STYLE_VERTICAL_ALIGN_MIDDLE;
+  case NS_STYLE_DOMINANT_BASELINE_AUTO:
+  case NS_STYLE_DOMINANT_BASELINE_ALPHABETIC:
+    return NS_STYLE_VERTICAL_ALIGN_BASELINE;
+  default:
+    NS_NOTREACHED("unexpected aDominantBaseline value");
+    return NS_STYLE_VERTICAL_ALIGN_BASELINE;
+  }
+}
+
+PRUint8
+nsIFrame::VerticalAlignEnum() const
+{
+  if (mState & NS_FRAME_IS_SVG_TEXT) {
+    PRUint8 dominantBaseline;
+    for (const nsIFrame* frame = this; frame; frame = frame->GetParent()) {
+      dominantBaseline = frame->GetStyleSVGReset()->mDominantBaseline;
+      if (dominantBaseline != NS_STYLE_DOMINANT_BASELINE_AUTO ||
+          frame->GetType() == nsGkAtoms::svgTextFrame) {
+        break;
+      }
+    }
+    return ConvertSVGDominantBaselineToVerticalAlign(dominantBaseline);
+  }
+
+  const nsStyleCoord& verticalAlign =
+    GetStyleContext()->GetStyleTextReset()->mVerticalAlign;
+  if (verticalAlign.GetUnit() == eStyleUnit_Enumerated) {
+    return verticalAlign.GetIntValue();
+  }
+
+  return eInvalidVerticalAlign;
+}
+
 /* static */
 void nsFrame::FillCursorInformationFromStyle(const nsStyleUserInterface* ui,
                                              nsIFrame::Cursor& aCursor)
 {
   aCursor.mCursor = ui->mCursor;
   aCursor.mHaveHotspot = false;
   aCursor.mHotspotX = aCursor.mHotspotY = 0.0f;
 
@@ -9308,19 +9359,19 @@ nsHTMLReflowState::DisplayInitFrameTypeE
     printf("InitFrameType");
 
     const nsStyleDisplay *disp = aState->mStyleDisplay;
 
     if (aFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW)
       printf(" out-of-flow");
     if (aFrame->GetPrevInFlow())
       printf(" prev-in-flow");
-    if (disp->IsAbsolutelyPositioned())
+    if (aFrame->IsAbsolutelyPositioned())
       printf(" abspos");
-    if (disp->IsFloating())
+    if (aFrame->IsFloating())
       printf(" float");
 
     // This array must exactly match the NS_STYLE_DISPLAY constants.
     const char *const displayTypes[] = {
       "none", "block", "inline", "inline-block", "list-item", "marker",
       "run-in", "compact", "table", "inline-table", "table-row-group",
       "table-column", "table-column-group", "table-header-group",
       "table-footer-group", "table-row", "table-cell", "table-caption",
--- a/layout/generic/nsFrameSetFrame.cpp
+++ b/layout/generic/nsFrameSetFrame.cpp
@@ -1511,17 +1511,17 @@ nsHTMLFramesetFrame::EndMouseDrag(nsPres
   gDragInProgress = false;
 }
 
 nsIFrame*
 NS_NewHTMLFramesetFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
 {
 #ifdef DEBUG
   const nsStyleDisplay* disp = aContext->GetStyleDisplay();
-  NS_ASSERTION(!disp->IsAbsolutelyPositioned() && !disp->IsFloating(),
+  NS_ASSERTION(!disp->IsAbsolutelyPositionedStyle() && !disp->IsFloatingStyle(),
                "Framesets should not be positioned and should not float");
 #endif
 
   return new (aPresShell) nsHTMLFramesetFrame(aContext);
 }
 
 NS_IMPL_FRAMEARENA_HELPERS(nsHTMLFramesetFrame)
 
--- a/layout/generic/nsGfxScrollFrame.cpp
+++ b/layout/generic/nsGfxScrollFrame.cpp
@@ -2111,17 +2111,17 @@ void
 nsGfxScrollFrameInner::AppendScrollPartsTo(nsDisplayListBuilder*   aBuilder,
                                            const nsRect&           aDirtyRect,
                                            const nsDisplayListSet& aLists,
                                            bool&                   aCreateLayer,
                                            bool                    aPositioned)
 {
   for (nsIFrame* kid = mOuter->GetFirstPrincipalChild(); kid; kid = kid->GetNextSibling()) {
     if (kid == mScrolledFrame ||
-        (kid->GetStyleDisplay()->IsPositioned() != aPositioned))
+        (kid->IsPositioned() != aPositioned))
       continue;
 
     nsDisplayListCollection partList;
     mOuter->BuildDisplayListForChild(aBuilder, kid, aDirtyRect, partList,
                                      nsIFrame::DISPLAY_CHILD_FORCE_STACKING_CONTEXT);
 
     // Don't append textarea resizers to the positioned descendants because
     // we don't want them to float on top of overlapping elements.
--- a/layout/generic/nsHTMLReflowState.cpp
+++ b/layout/generic/nsHTMLReflowState.cpp
@@ -390,17 +390,17 @@ IsQuirkContainingBlockHeight(const nsHTM
   if (nsGkAtoms::blockFrame == aFrameType ||
 #ifdef MOZ_XUL
       nsGkAtoms::XULLabelFrame == aFrameType ||
 #endif
       nsGkAtoms::scrollFrame == aFrameType) {
     // Note: This next condition could change due to a style change,
     // but that would cause a style reflow anyway, which means we're ok.
     if (NS_AUTOHEIGHT == rs->ComputedHeight()) {
-      if (!rs->frame->GetStyleDisplay()->IsAbsolutelyPositioned()) {
+      if (!rs->frame->IsAbsolutelyPositioned()) {
         return false;
       }
     }
   }
   return true;
 }
 
 
@@ -636,39 +636,39 @@ nsHTMLReflowState::InitFrameType(nsIAtom
 
   DISPLAY_INIT_TYPE(frame, this);
 
   if (aFrameType == nsGkAtoms::tableFrame) {
     mFrameType = NS_CSS_FRAME_TYPE_BLOCK;
     return;
   }
 
-  NS_ASSERTION(frame->GetStyleDisplay()->IsAbsolutelyPositioned() ==
-                 disp->IsAbsolutelyPositioned(),
+  NS_ASSERTION(frame->GetStyleDisplay()->IsAbsolutelyPositionedStyle() ==
+                 disp->IsAbsolutelyPositionedStyle(),
                "Unexpected position style");
-  NS_ASSERTION(frame->GetStyleDisplay()->IsFloating() ==
-                 disp->IsFloating(), "Unexpected float style");
+  NS_ASSERTION(frame->GetStyleDisplay()->IsFloatingStyle() ==
+                 disp->IsFloatingStyle(), "Unexpected float style");
   if (frame->GetStateBits() & NS_FRAME_OUT_OF_FLOW) {
-    if (disp->IsAbsolutelyPositioned()) {
+    if (disp->IsAbsolutelyPositioned(frame)) {
       frameType = NS_CSS_FRAME_TYPE_ABSOLUTE;
       //XXXfr hack for making frames behave properly when in overflow container lists
       //      see bug 154892; need to revisit later
       if (frame->GetPrevInFlow())
         frameType = NS_CSS_FRAME_TYPE_BLOCK;
     }
-    else if (disp->IsFloating()) {
+    else if (disp->IsFloating(frame)) {
       frameType = NS_CSS_FRAME_TYPE_FLOATING;
     } else {
       NS_ASSERTION(disp->mDisplay == NS_STYLE_DISPLAY_POPUP,
                    "unknown out of flow frame type");
       frameType = NS_CSS_FRAME_TYPE_UNKNOWN;
     }
   }
   else {
-    switch (disp->mDisplay) {
+    switch (GetDisplay()) {
     case NS_STYLE_DISPLAY_BLOCK:
     case NS_STYLE_DISPLAY_LIST_ITEM:
     case NS_STYLE_DISPLAY_TABLE:
     case NS_STYLE_DISPLAY_TABLE_CAPTION:
       frameType = NS_CSS_FRAME_TYPE_BLOCK;
       break;
 
     case NS_STYLE_DISPLAY_INLINE:
@@ -1083,17 +1083,17 @@ nsHTMLReflowState::CalculateHypothetical
       aHypotheticalBox.mTop = placeholderOffset.y;
     } else {
       NS_ASSERTION(iter.GetContainer() == blockFrame,
                    "Found placeholder in wrong block!");
       nsBlockFrame::line_iterator lineBox = iter.GetLine();
 
       // How we determine the hypothetical box depends on whether the element
       // would have been inline-level or block-level
-      if (mStyleDisplay->IsOriginalDisplayInlineOutside()) {
+      if (mStyleDisplay->IsOriginalDisplayInlineOutsideStyle()) {
         // Use the top of the inline box which the placeholder lives in
         // as the hypothetical box's top.
         aHypotheticalBox.mTop = lineBox->mBounds.y + blockYOffset;
       } else {
         // The element would have been block-level which means it would
         // be below the line containing the placeholder frame, unless
         // all the frames before it are empty.  In that case, it would
         // have been just before this line.
@@ -1135,17 +1135,17 @@ nsHTMLReflowState::CalculateHypothetical
     aHypotheticalBox.mTop = placeholderOffset.y;
   }
 
   // Second, determine the hypothetical box's mLeft & mRight
   // To determine the left and right offsets we need to look at the block's 'direction'
   if (NS_STYLE_DIRECTION_LTR == blockVis->mDirection) {
     // How we determine the hypothetical box depends on whether the element
     // would have been inline-level or block-level
-    if (mStyleDisplay->IsOriginalDisplayInlineOutside()) {
+    if (mStyleDisplay->IsOriginalDisplayInlineOutsideStyle()) {
       // The placeholder represents the left edge of the hypothetical box
       aHypotheticalBox.mLeft = placeholderOffset.x;
     } else {
       aHypotheticalBox.mLeft = aBlockLeftContentEdge;
     }
 #ifdef DEBUG
     aHypotheticalBox.mLeftIsExact = true;
 #endif
@@ -1162,17 +1162,17 @@ nsHTMLReflowState::CalculateHypothetical
       aHypotheticalBox.mRight = aBlockLeftContentEdge + aBlockContentWidth;
 #ifdef DEBUG
       aHypotheticalBox.mRightIsExact = false;
 #endif
     }
 
   } else {
     // The placeholder represents the right edge of the hypothetical box
-    if (mStyleDisplay->IsOriginalDisplayInlineOutside()) {
+    if (mStyleDisplay->IsOriginalDisplayInlineOutsideStyle()) {
       aHypotheticalBox.mRight = placeholderOffset.x;
     } else {
       aHypotheticalBox.mRight = aBlockLeftContentEdge + aBlockContentWidth;
     }
 #ifdef DEBUG
     aHypotheticalBox.mRightIsExact = true;
 #endif
     
@@ -1603,17 +1603,17 @@ CalcQuirkContainingBlockHeight(const nsH
       secondAncestorRS = firstAncestorRS;
       firstAncestorRS = (nsHTMLReflowState*)rs;
 
       // If the current frame we're looking at is positioned, we don't want to
       // go any further (see bug 221784).  The behavior we want here is: 1) If
       // not auto-height, use this as the percentage base.  2) If auto-height,
       // keep looking, unless the frame is positioned.
       if (NS_AUTOHEIGHT == rs->ComputedHeight()) {
-        if (rs->frame->GetStyleDisplay()->IsAbsolutelyPositioned()) {
+        if (rs->frame->IsAbsolutelyPositioned()) {
           break;
         } else {
           continue;
         }
       }
     }
     else if (nsGkAtoms::canvasFrame == frameType) {
       // Always continue on to the height calculation
@@ -1689,17 +1689,17 @@ nsHTMLReflowState::ComputeContainingBloc
   // formed by the content edge of the nearest block-level ancestor
   aContainingBlockWidth = aContainingBlockRS->mComputedWidth;
   aContainingBlockHeight = aContainingBlockRS->mComputedHeight;
 
   // mFrameType for abs-pos tables is NS_CSS_FRAME_TYPE_BLOCK, so we need to
   // special case them here.
   if (NS_FRAME_GET_TYPE(mFrameType) == NS_CSS_FRAME_TYPE_ABSOLUTE ||
       (frame->GetType() == nsGkAtoms::tableFrame &&
-       frame->GetStyleDisplay()->IsAbsolutelyPositioned() &&
+       frame->IsAbsolutelyPositioned() &&
        (frame->GetParent()->GetStateBits() & NS_FRAME_OUT_OF_FLOW))) {
     // See if the ancestor is block-level or inline-level
     if (NS_FRAME_GET_TYPE(aContainingBlockRS->mFrameType) == NS_CSS_FRAME_TYPE_INLINE) {
       // Base our size on the actual size of the frame.  In cases when this is
       // completely bogus (eg initial reflow), this code shouldn't even be
       // called, since the code in nsInlineFrame::Reflow will pass in
       // the containing block dimensions to our constructor.
       // XXXbz we should be taking the in-flows into account too, but
@@ -1892,17 +1892,17 @@ nsHTMLReflowState::InitConstraints(nsPre
           heightUnit = eStyleUnit_Auto;
         }
       }
     }
 
     // Compute our offsets if the element is relatively positioned.  We need
     // the correct containing block width and height here, which is why we need
     // to do it after all the quirks-n-such above.
-    if (NS_STYLE_POSITION_RELATIVE == mStyleDisplay->mPosition) {
+    if (mStyleDisplay->IsRelativelyPositioned(frame)) {
       PRUint8 direction = NS_STYLE_DIRECTION_LTR;
       if (cbrs && NS_STYLE_DIRECTION_RTL == cbrs->mStyleVisibility->mDirection) {
         direction = NS_STYLE_DIRECTION_RTL;
       }
       ComputeRelativeOffsets(direction, frame, aContainingBlockWidth,
           aContainingBlockHeight, mComputedOffsets);
     } else {
       // Initialize offsets to 0
@@ -2079,16 +2079,19 @@ nsCSSOffsetState::InitOffsets(nscoord aC
                                                 frame, disp->mAppearance,
                                                 &widget)) {
     mComputedPadding.top = presContext->DevPixelsToAppUnits(widget.top);
     mComputedPadding.right = presContext->DevPixelsToAppUnits(widget.right);
     mComputedPadding.bottom = presContext->DevPixelsToAppUnits(widget.bottom);
     mComputedPadding.left = presContext->DevPixelsToAppUnits(widget.left);
     needPaddingProp = false;
   }
+  else if (frame->GetStateBits() & NS_FRAME_IS_SVG_TEXT) {
+    mComputedPadding.SizeTo(0, 0, 0, 0);
+  }
   else if (aPadding) { // padding is an input arg
     mComputedPadding = *aPadding;
     needPaddingProp = frame->GetStylePadding()->IsWidthDependent();
   }
   else {
     needPaddingProp = ComputePadding(aContainingBlockWidth, aFrameType);
   }
 
@@ -2101,16 +2104,19 @@ nsCSSOffsetState::InitOffsets(nscoord aC
       presContext->DevPixelsToAppUnits(widget.top);
     mComputedBorderPadding.right =
       presContext->DevPixelsToAppUnits(widget.right);
     mComputedBorderPadding.bottom =
       presContext->DevPixelsToAppUnits(widget.bottom);
     mComputedBorderPadding.left =
       presContext->DevPixelsToAppUnits(widget.left);
   }
+  else if (frame->GetStateBits() & NS_FRAME_IS_SVG_TEXT) {
+    mComputedBorderPadding.SizeTo(0, 0, 0, 0);
+  }
   else if (aBorder) {  // border is an input arg
     mComputedBorderPadding = *aBorder;
   }
   else {
     mComputedBorderPadding = frame->GetStyleBorder()->GetComputedBorder();
   }
   mComputedBorderPadding += mComputedPadding;
 
@@ -2343,16 +2349,21 @@ nsHTMLReflowState::CalcLineHeight(nsStyl
   NS_ASSERTION(lineHeight >= 0, "ComputeLineHeight screwed up");
 
   return lineHeight;
 }
 
 bool
 nsCSSOffsetState::ComputeMargin(nscoord aContainingBlockWidth)
 {
+  // SVG text frames have no margin.
+  if (frame->GetStateBits() & NS_FRAME_IS_SVG_TEXT) {
+    return false;
+  }
+
   // If style style can provide us the margin directly, then use it.
   const nsStyleMargin *styleMargin = frame->GetStyleMargin();
   bool isWidthDependent = !styleMargin->GetMargin(mComputedMargin);
   if (isWidthDependent) {
     // We have to compute the value
     mComputedMargin.left = nsLayoutUtils::
       ComputeWidthDependentValue(aContainingBlockWidth,
                                  styleMargin->mMargin.GetLeft());
--- a/layout/generic/nsHTMLReflowState.h
+++ b/layout/generic/nsHTMLReflowState.h
@@ -5,16 +5,17 @@
 
 /* struct containing the input to nsIFrame::Reflow */
 
 #ifndef nsHTMLReflowState_h___
 #define nsHTMLReflowState_h___
 
 #include "nsMargin.h"
 #include "nsStyleCoord.h"
+#include "nsStyleStructInlines.h"
 #include "nsIFrame.h"
 #include "mozilla/AutoRestore.h"
 
 class nsPresContext;
 class nsRenderingContext;
 class nsFloatManager;
 class nsLineLayout;
 class nsIPercentHeightObserver;
@@ -287,16 +288,24 @@ public:
   const nsStyleDisplay*    mStyleDisplay;
   const nsStyleVisibility* mStyleVisibility;
   const nsStylePosition*   mStylePosition;
   const nsStyleBorder*     mStyleBorder;
   const nsStyleMargin*     mStyleMargin;
   const nsStylePadding*    mStylePadding;
   const nsStyleText*       mStyleText;
 
+  bool IsFloating() const {
+    return mStyleDisplay->IsFloating(frame);
+  }
+
+  PRUint8 GetDisplay() const {
+    return mStyleDisplay->GetDisplay(frame);
+  }
+
   // a frame (e.g. nsTableCellFrame) which may need to generate a special 
   // reflow for percent height calculations 
   nsIPercentHeightObserver* mPercentHeightObserver;
 
   // CSS margin collapsing sometimes requires us to reflow
   // optimistically assuming that margins collapse to see if clearance
   // is required. When we discover that clearance is required, we
   // store the frame in which clearance was discovered to the location
--- a/layout/generic/nsIFrame.h
+++ b/layout/generic/nsIFrame.h
@@ -18,18 +18,19 @@
 /* nsIFrame is in the process of being deCOMtaminated, i.e., this file is eventually
    going to be eliminated, and all callers will use nsFrame instead.  At the moment
    we're midway through this process, so you will see inlined functions and member
    variables in this file.  -dwh */
 
 #include <stdio.h>
 #include "nsQueryFrame.h"
 #include "nsEvent.h"
+#include "nsStyleContext.h"
 #include "nsStyleStruct.h"
-#include "nsStyleContext.h"
+#include "nsStyleStructFwd.h"
 #include "nsIContent.h"
 #include "nsHTMLReflowMetrics.h"
 #include "gfxMatrix.h"
 #include "nsFrameList.h"
 #include "nsAlgorithm.h"
 #include "mozilla/layout/FrameChildList.h"
 #include "FramePropertyTable.h"
 
@@ -292,16 +293,20 @@ typedef PRUint64 nsFrameState;
 // alpha children. With BasicLayers we avoid creating these, so we mark
 // the frames for future reference.
 #define NS_FRAME_NO_COMPONENT_ALPHA                 NS_FRAME_STATE_BIT(45)
 
 // Frame has a cached rasterization of anV
 // nsDisplayBackground display item
 #define NS_FRAME_HAS_CACHED_BACKGROUND              NS_FRAME_STATE_BIT(46)
 
+// The frame is a descendant of nsSVGTextFrame2 and is thus used for SVG
+// text layout.
+#define NS_FRAME_IS_SVG_TEXT                        NS_FRAME_STATE_BIT(47)
+
 // Box layout bits
 #define NS_STATE_IS_HORIZONTAL                      NS_FRAME_STATE_BIT(22)
 #define NS_STATE_IS_DIRECTION_NORMAL                NS_FRAME_STATE_BIT(31)
 
 // Helper macros
 #define NS_SUBTREE_DIRTY(_frame)  \
   (((_frame)->GetStateBits() &      \
     (NS_FRAME_IS_DIRTY | NS_FRAME_HAS_DIRTY_CHILDREN)) != 0)
@@ -2494,17 +2499,19 @@ public:
   /**
    * Determines whether this frame is a pseudo stacking context, looking
    * only as style --- i.e., assuming that it's in-flow and not a replaced
    * element and not an SVG element.
    * XXX maybe check IsTransformed()?
    */
   bool IsPseudoStackingContextFromStyle() {
     const nsStyleDisplay* disp = GetStyleDisplay();
-    return disp->mOpacity != 1.0f || disp->IsPositioned() || disp->IsFloating();
+    return disp->mOpacity != 1.0f ||
+           disp->IsPositioned(this) ||
+           disp->IsFloating(this);
   }
   
   virtual bool HonorPrintBackgroundSettings() { return true; }
 
   /**
    * Determine whether the frame is logically empty, which is roughly
    * whether the layout would be the same whether or not the frame is
    * present.  Placeholder frames should return true.  Block frames
@@ -2829,16 +2836,37 @@ NS_PTR_TO_INT32(frame->Properties().Get(
   // If the VISIBILITY_CROSS_CHROME_CONTENT_BOUNDARY flag is passed then we
   // ignore the chrome/content boundary, otherwise we stop looking when we
   // reach it.
   enum {
     VISIBILITY_CROSS_CHROME_CONTENT_BOUNDARY = 0x01
   };
   bool IsVisibleConsideringAncestors(PRUint32 aFlags = 0) const;
 
+  inline bool IsBlockInside() const;
+  inline bool IsBlockOutside() const;
+  inline bool IsInlineOutside() const;
+  inline PRUint8 GetDisplay() const;
+  inline bool IsFloating() const;
+  inline bool IsPositioned() const;
+  inline bool IsRelativelyPositioned() const;
+  inline bool IsAbsolutelyPositioned() const;
+
+  /**
+   * Returns the vertical-align value to be used for layout, if it is one
+   * of the enumerated values.  If this is an SVG text frame, it returns a value
+   * that corresponds to the value of dominant-baseline.  If the
+   * vertical-align property has length or percentage value, this returns
+   * eInvalidVerticalAlign.
+   */
+  PRUint8 VerticalAlignEnum() const;
+  enum { eInvalidVerticalAlign = 0xFF };
+
+  bool IsSVGText() const { return mState & NS_FRAME_IS_SVG_TEXT; }
+
 protected:
   // Members
   nsRect           mRect;
   nsIContent*      mContent;
   nsStyleContext*  mStyleContext;
   nsIFrame*        mParent;
 private:
   nsIFrame*        mNextSibling;  // doubly-linked list of frames
@@ -3139,9 +3167,60 @@ nsFrameList::Enumerator::Next()
 inline
 nsFrameList::FrameLinkEnumerator::
 FrameLinkEnumerator(const nsFrameList& aList, nsIFrame* aPrevFrame)
   : Enumerator(aList)
 {
   mPrev = aPrevFrame;
   mFrame = aPrevFrame ? aPrevFrame->GetNextSibling() : aList.FirstChild();
 }
+
+#include "nsStyleStructInlines.h"
+
+bool
+nsIFrame::IsFloating() const
+{
+  return GetStyleDisplay()->IsFloating(this);
+}
+
+bool
+nsIFrame::IsPositioned() const
+{
+  return GetStyleDisplay()->IsPositioned(this);
+}
+
+bool
+nsIFrame::IsRelativelyPositioned() const
+{
+  return GetStyleDisplay()->IsRelativelyPositioned(this);
+}
+
+bool
+nsIFrame::IsAbsolutelyPositioned() const
+{
+  return GetStyleDisplay()->IsAbsolutelyPositioned(this);
+}
+
+bool
+nsIFrame::IsBlockInside() const
+{
+  return GetStyleDisplay()->IsBlockInside(this);
+}
+
+bool
+nsIFrame::IsBlockOutside() const
+{
+  return GetStyleDisplay()->IsBlockOutside(this);
+}
+
+bool
+nsIFrame::IsInlineOutside() const
+{
+  return GetStyleDisplay()->IsInlineOutside(this);
+}
+
+PRUint8
+nsIFrame::GetDisplay() const
+{
+  return GetStyleDisplay()->GetDisplay(this);
+}
+
 #endif /* nsIFrame_h___ */
--- a/layout/generic/nsLineBox.cpp
+++ b/layout/generic/nsLineBox.cpp
@@ -10,16 +10,17 @@
 #include "nsLineLayout.h"
 #include "prprf.h"
 #include "nsBlockFrame.h"
 #include "nsIFrame.h"
 #include "nsPresArena.h"
 #ifdef IBMBIDI
 #include "nsBidiPresUtils.h"
 #endif
+#include "nsStyleStructInlines.h"
 
 #ifdef DEBUG
 static PRInt32 ctorCount;
 PRInt32 nsLineBox::GetCtorCount() { return ctorCount; }
 #endif
 
 #ifndef _MSC_VER
 // static nsLineBox constant; initialized in the header file.
@@ -31,17 +32,17 @@ nsLineBox::nsLineBox(nsIFrame* aFrame, P
 // NOTE: memory is already zeroed since we allocate with AllocateByObjectID.
 {
   MOZ_COUNT_CTOR(nsLineBox);
 #ifdef DEBUG
   ++ctorCount;
   NS_ASSERTION(!aIsBlock || aCount == 1, "Blocks must have exactly one child");
   nsIFrame* f = aFrame;
   for (PRInt32 n = aCount; n > 0; f = f->GetNextSibling(), --n) {
-    NS_ASSERTION(aIsBlock == f->GetStyleDisplay()->IsBlockOutside(),
+    NS_ASSERTION(aIsBlock == f->IsBlockOutside(),
                  "wrong kind of child frame");
   }
 #endif
 
 #if NS_STYLE_CLEAR_NONE > 0
   mFlags.mBreakType = NS_STYLE_CLEAR_NONE;
 #endif
   mChildCount = aCount;
--- a/layout/generic/nsLineLayout.cpp
+++ b/layout/generic/nsLineLayout.cpp
@@ -972,18 +972,17 @@ nsLineLayout::ReflowFrame(nsIFrame* aFra
     if (!continuingTextRun && !pfd->GetFlag(PFD_SKIPWHENTRIMMINGWHITESPACE)) {
       mTrimmableWidth = 0;
     }
 
     // See if we can place the frame. If we can't fit it, then we
     // return now.
     bool optionalBreakAfterFits;
     NS_ASSERTION(isText ||
-                 reflowStateHolder.ref().mStyleDisplay->mFloats ==
-                   NS_STYLE_FLOAT_NONE,
+                 !reflowStateHolder.ref().IsFloating(),
                  "How'd we get a floated inline frame? "
                  "The frame ctor should've dealt with this.");
     // Direction is inherited, so using the psd direction is fine.
     // Get it off the reflow state instead of the frame to save style
     // data computation (especially for the text).
     PRUint8 direction =
       isText ? psd->mReflowState->mStyleVisibility->mDirection :
                reflowStateHolder.ref().mStyleVisibility->mDirection;
@@ -1046,17 +1045,17 @@ nsLineLayout::ReflowFrame(nsIFrame* aFra
 
   return rv;
 }
 
 void
 nsLineLayout::ApplyStartMargin(PerFrameData* pfd,
                                nsHTMLReflowState& aReflowState)
 {
-  NS_ASSERTION(aReflowState.mStyleDisplay->mFloats == NS_STYLE_FLOAT_NONE,
+  NS_ASSERTION(!aReflowState.IsFloating(),
                "How'd we get a floated inline frame? "
                "The frame ctor should've dealt with this.");
 
   // XXXwaterson probably not the right way to get this; e.g., embeddings, etc.
   bool ltr = (NS_STYLE_DIRECTION_LTR == aReflowState.mStyleVisibility->mDirection);
 
   // Only apply start-margin on the first-in flow for inline frames,
   // and make sure to not apply it to any inline other than the first
@@ -1447,21 +1446,17 @@ nsLineLayout::VerticalAlignLine()
   // If the frame being reflowed has text decorations, we simulate the
   // propagation of those decorations to a line-level element by storing the
   // offset in a frame property on any child frames that are vertically-aligned
   // somewhere other than the baseline. This property is then used by
   // nsTextFrame::GetTextDecorations when the same conditions are met.
   if (rootPFD.mFrame->GetStyleContext()->HasTextDecorationLines()) {
     for (const PerFrameData* pfd = psd->mFirstFrame; pfd; pfd = pfd->mNext) {
       const nsIFrame *const f = pfd->mFrame;
-      const nsStyleCoord& vAlign =
-          f->GetStyleContext()->GetStyleTextReset()->mVerticalAlign;
-
-      if (vAlign.GetUnit() != eStyleUnit_Enumerated ||
-          vAlign.GetIntValue() != NS_STYLE_VERTICAL_ALIGN_BASELINE) {
+      if (f->VerticalAlignEnum() != NS_STYLE_VERTICAL_ALIGN_BASELINE) {
         const nscoord offset = baselineY - pfd->mBounds.y;
         f->Properties().Set(nsIFrame::LineBaselineOffset(),
                             NS_INT32_TO_PTR(offset));
       }
     }
   }
 
   // Fill in returned line-box and max-element-width data
@@ -1771,28 +1766,34 @@ nsLineLayout::VerticalAlignFrames(PerSpa
       // frames height plus its margins.
       logicalHeight = pfd->mBounds.height + pfd->mMargin.top +
         pfd->mMargin.bottom;
     }
 
     // Get vertical-align property
     const nsStyleCoord& verticalAlign =
       frame->GetStyleTextReset()->mVerticalAlign;
+    PRUint8 verticalAlignEnum = frame->VerticalAlignEnum();
 #ifdef NOISY_VERTICAL_ALIGN
     printf("  [frame]");
     nsFrame::ListTag(stdout, frame);
-    printf(": verticalAlignUnit=%d (enum == %d)\n",
+    printf(": verticalAlignUnit=%d (enum == %d",
            verticalAlign.GetUnit(),
            ((eStyleUnit_Enumerated == verticalAlign.GetUnit())
             ? verticalAlign.GetIntValue()
             : -1));
+    if (verticalAlignEnum != nsIFrame::eInvalidVerticalAlign) {
+      printf(", after SVG dominant-baseline conversion == %d",
+             verticalAlignEnum);
+    }
+    printf(")\n");
 #endif
 
-    if (verticalAlign.GetUnit() == eStyleUnit_Enumerated) {
-      switch (verticalAlign.GetIntValue()) {
+    if (verticalAlignEnum != nsIFrame::eInvalidVerticalAlign) {
+      switch (verticalAlignEnum) {
         default:
         case NS_STYLE_VERTICAL_ALIGN_BASELINE:
         {
           // The element's baseline is aligned with the baseline of
           // the parent.
           pfd->mBounds.y = baselineY - pfd->mAscent;
           pfd->mVerticalAlign = VALIGN_OTHER;
           break;
@@ -2467,17 +2468,18 @@ nsLineLayout::HorizontalAlignFrames(nsRe
   nscoord remainingWidth = availWidth - aLineBounds.width;
 #ifdef NOISY_HORIZONTAL_ALIGN
     nsFrame::ListTag(stdout, mBlockReflowState->frame);
     printf(": availWidth=%d lineWidth=%d delta=%d\n",
            availWidth, aLineBounds.width, remainingWidth);
 #endif
   nscoord dx = 0;
 
-  if (remainingWidth > 0) {
+  if (remainingWidth > 0 &&
+      !(mBlockReflowState->frame->IsSVGText())) {
     PRUint8 textAlign = mStyleText->mTextAlign;
 
     /* 
      * 'text-align-last: auto' is equivalent to the value of the 'text-align'
      * property except when 'text-align' is set to 'justify', in which case it
      * is 'justify' when 'text-justify' is 'distribute' and 'start' otherwise.
      *
      * XXX: the code below will have to change when we implement text-justify
--- a/layout/generic/nsPlaceholderFrame.cpp
+++ b/layout/generic/nsPlaceholderFrame.cpp
@@ -77,32 +77,32 @@ nsPlaceholderFrame::AddInlineMinWidth(ns
 {
   // Override AddInlineMinWith so that *nothing* happens.  In
   // particular, we don't want to zero out |aData->trailingWhitespace|,
   // since nsLineLayout skips placeholders when trimming trailing
   // whitespace, and we don't want to set aData->skipWhitespace to
   // false.
 
   // ...but push floats onto the list
-  if (mOutOfFlowFrame->GetStyleDisplay()->IsFloating())
+  if (mOutOfFlowFrame->IsFloating())
     aData->floats.AppendElement(mOutOfFlowFrame);
 }
 
 /* virtual */ void
 nsPlaceholderFrame::AddInlinePrefWidth(nsRenderingContext *aRenderingContext,
                                        nsIFrame::InlinePrefWidthData *aData)
 {
   // Override AddInlinePrefWith so that *nothing* happens.  In
   // particular, we don't want to zero out |aData->trailingWhitespace|,
   // since nsLineLayout skips placeholders when trimming trailing
   // whitespace, and we don't want to set aData->skipWhitespace to
   // false.
 
   // ...but push floats onto the list
-  if (mOutOfFlowFrame->GetStyleDisplay()->IsFloating())
+  if (mOutOfFlowFrame->IsFloating())
     aData->floats.AppendElement(mOutOfFlowFrame);
 }
 
 NS_IMETHODIMP
 nsPlaceholderFrame::Reflow(nsPresContext*          aPresContext,
                            nsHTMLReflowMetrics&     aDesiredSize,
                            const nsHTMLReflowState& aReflowState,
                            nsReflowStatus&          aStatus)
--- a/layout/generic/nsTextFrameThebes.cpp
+++ b/layout/generic/nsTextFrameThebes.cpp
@@ -13,16 +13,18 @@
 #include "nsSplittableFrame.h"
 #include "nsLineLayout.h"
 #include "nsString.h"
 #include "nsUnicharUtils.h"
 #include "nsPresContext.h"
 #include "nsIContent.h"
 #include "nsStyleConsts.h"
 #include "nsStyleContext.h"
+#include "nsStyleStruct.h"
+#include "nsStyleStructInlines.h"
 #include "nsCoord.h"
 #include "nsRenderingContext.h"
 #include "nsIPresShell.h"
 #include "nsITimer.h"
 #include "nsTArray.h"
 #include "nsIDocument.h"
 #include "nsCSSPseudoElements.h"
 #include "nsCSSFrameConstructor.h"
@@ -1149,17 +1151,17 @@ BuildTextRuns(gfxContext* aContext, nsTe
       lineContainerChild = aForFrame->PresContext()->PresShell()->
         GetPlaceholderFrameFor(aForFrame->GetParent());
     }
     aLineContainer = FindLineContainer(lineContainerChild);
   } else {
     NS_ASSERTION(!aForFrame ||
                  (aLineContainer == FindLineContainer(aForFrame) ||
                   (aLineContainer->GetType() == nsGkAtoms::letterFrame &&
-                   aLineContainer->GetStyleDisplay()->IsFloating())),
+                   aLineContainer->IsFloating())),
                  "Wrong line container hint");
   }
 
   nsPresContext* presContext = aLineContainer->PresContext();
   BuildTextRunsScanner scanner(presContext, aContext, aLineContainer,
                                aWhichTextRun);
 
   nsBlockFrame* block = nsLayoutUtils::GetAsBlock(aLineContainer);
@@ -1452,16 +1454,40 @@ static bool
 HasTerminalNewline(const nsTextFrame* aFrame)
 {
   if (aFrame->GetContentLength() == 0)
     return false;
   const nsTextFragment* frag = aFrame->GetContent()->GetText();
   return frag->CharAt(aFrame->GetContentEnd() - 1) == '\n';
 }
 
+static nscoord
+LetterSpacing(nsIFrame* aFrame, const nsStyleText* aStyleText = nsnull)
+{
+  if (aFrame->IsSVGText()) {
+    return 0;
+  }
+  if (!aStyleText) {
+    aStyleText = aFrame->GetStyleText();
+  }
+  return StyleToCoord(aStyleText->mLetterSpacing);
+}
+
+static nscoord
+WordSpacing(nsIFrame* aFrame, const nsStyleText* aStyleText = nsnull)
+{
+  if (aFrame->IsSVGText()) {
+    return 0;
+  }
+  if (!aStyleText) {
+    aStyleText = aFrame->GetStyleText();
+  }
+  return aStyleText->mWordSpacing;
+}
+
 bool
 BuildTextRunsScanner::ContinueTextRunAcrossFrames(nsTextFrame* aFrame1, nsTextFrame* aFrame2)
 {
   // We don't need to check font size inflation, since
   // |FindLineContainer| above (via |nsIFrame::CanContinueTextRun|)
   // ensures that text runs never cross block boundaries.  This means
   // that the font size inflation on all text frames in the text run is
   // already guaranteed to be the same as each other (and for the line
@@ -1491,23 +1517,25 @@ BuildTextRunsScanner::ContinueTextRunAcr
     // because that would violate our invariant that two flows in the same
     // textrun have different content elements.
     return false;
   }
 
   nsStyleContext* sc2 = aFrame2->GetStyleContext();
   if (sc1 == sc2)
     return true;
+
   const nsStyleFont* fontStyle1 = sc1->GetStyleFont();
   const nsStyleFont* fontStyle2 = sc2->GetStyleFont();
-  const nsStyleText* textStyle2 = sc2->GetStyleText();
+  nscoord letterSpacing1 = LetterSpacing(aFrame1);
+  nscoord letterSpacing2 = LetterSpacing(aFrame2);
   return fontStyle1->mFont.BaseEquals(fontStyle2->mFont) &&
     sc1->GetStyleFont()->mLanguage == sc2->GetStyleFont()->mLanguage &&
-    nsLayoutUtils::GetTextRunFlagsForStyle(sc1, textStyle1, fontStyle1) ==
-      nsLayoutUtils::GetTextRunFlagsForStyle(sc2, textStyle2, fontStyle2);
+    nsLayoutUtils::GetTextRunFlagsForStyle(sc1, fontStyle1, letterSpacing1) ==
+      nsLayoutUtils::GetTextRunFlagsForStyle(sc2, fontStyle2, letterSpacing2);
 }
 
 void BuildTextRunsScanner::ScanFrame(nsIFrame* aFrame)
 {
   // First check if we can extend the current mapped frame block. This is common.
   if (mMappedFlows.Length() > 0) {
     MappedFlow* mappedFlow = &mMappedFlows[mMappedFlows.Length() - 1];
     if (mappedFlow->mEndFrame == aFrame &&
@@ -1742,17 +1770,18 @@ BuildTextRunsScanner::BuildTextRunForFra
   userData->mLastFlowIndex = 0;
 
   PRUint32 currentTransformedTextOffset = 0;
 
   PRUint32 nextBreakIndex = 0;
   nsTextFrame* nextBreakBeforeFrame = GetNextBreakBeforeFrame(&nextBreakIndex);
   bool enabledJustification = mLineContainer &&
     (mLineContainer->GetStyleText()->mTextAlign == NS_STYLE_TEXT_ALIGN_JUSTIFY ||
-     mLineContainer->GetStyleText()->mTextAlignLast == NS_STYLE_TEXT_ALIGN_JUSTIFY);
+     mLineContainer->GetStyleText()->mTextAlignLast == NS_STYLE_TEXT_ALIGN_JUSTIFY) &&
+    !mLineContainer->IsSVGText();
 
   // for word-break style
   switch (mLineContainer->GetStyleText()->mWordBreak) {
     case NS_STYLE_WORDBREAK_BREAK_ALL:
       mLineBreaker.SetWordBreak(nsILineBreaker::kWordBreak_BreakAll);
       break;
     case NS_STYLE_WORDBREAK_KEEP_ALL:
       mLineBreaker.SetWordBreak(nsILineBreaker::kWordBreak_KeepAll);
@@ -1771,18 +1800,18 @@ BuildTextRunsScanner::BuildTextRunForFra
     nsTextFrame* f = mappedFlow->mStartFrame;
 
     lastStyleContext = f->GetStyleContext();
     // Detect use of text-transform or font-variant anywhere in the run
     textStyle = f->GetStyleText();
     if (NS_STYLE_TEXT_TRANSFORM_NONE != textStyle->mTextTransform) {
       anyTextTransformStyle = true;
     }
-    textFlags |= GetSpacingFlags(StyleToCoord(textStyle->mLetterSpacing));
-    textFlags |= GetSpacingFlags(textStyle->mWordSpacing);
+    textFlags |= GetSpacingFlags(LetterSpacing(f));
+    textFlags |= GetSpacingFlags(WordSpacing(f));
     nsTextFrameUtils::CompressionMode compression =
       CSSWhitespaceToCompressionMode[textStyle->mWhiteSpace];
     if (enabledJustification && !textStyle->WhiteSpaceIsSignificant()) {
       textFlags |= gfxTextRunFactory::TEXT_ENABLE_SPACING;
     }
     fontStyle = f->GetStyleFont();
     if (NS_STYLE_FONT_VARIANT_SMALL_CAPS == fontStyle->mFont.variant) {
       anySmallcapsStyle = true;
@@ -1887,19 +1916,20 @@ BuildTextRunsScanner::BuildTextRunForFra
   }
   if (mNextRunContextInfo & nsTextFrameUtils::INCOMING_WHITESPACE) {
     textFlags |= nsTextFrameUtils::TEXT_TRAILING_WHITESPACE;
   }
   if (mNextRunContextInfo & nsTextFrameUtils::INCOMING_ARABICCHAR) {
     textFlags |= gfxTextRunFactory::TEXT_TRAILING_ARABICCHAR;
   }
   // ContinueTextRunAcrossFrames guarantees that it doesn't matter which
-  // frame's style is used, so use the last frame's
+  // frame's style is used, so we use a mixture of the first frame and
+  // last frame's style
   textFlags |= nsLayoutUtils::GetTextRunFlagsForStyle(lastStyleContext,
-      textStyle, fontStyle);
+      fontStyle, LetterSpacing(firstFrame, textStyle));
   // XXX this is a bit of a hack. For performance reasons, if we're favouring
   // performance over quality, don't try to get accurate glyph extents.
   if (!(textFlags & gfxTextRunFactory::TEXT_OPTIMIZE_SPEED)) {
     textFlags |= gfxTextRunFactory::TEXT_NEED_BOUNDING_BOX;
   }
 
   gfxSkipChars skipChars;
   skipChars.TakeFrom(&builder);
@@ -2602,18 +2632,18 @@ public:
                    nscoord aOffsetFromBlockOriginForTabs,
                    nsTextFrame::TextRunType aWhichTextRun)
     : mTextRun(aTextRun), mFontGroup(nullptr),
       mTextStyle(aTextStyle), mFrag(aFrag),
       mLineContainer(aLineContainer),
       mFrame(aFrame), mStart(aStart), mTempIterator(aStart),
       mTabWidths(nullptr), mTabWidthsAnalyzedLimit(0),
       mLength(aLength),
-      mWordSpacing(mTextStyle->mWordSpacing),
-      mLetterSpacing(StyleToCoord(mTextStyle->mLetterSpacing)),
+      mWordSpacing(WordSpacing(aFrame, aTextStyle)),
+      mLetterSpacing(LetterSpacing(aFrame, aTextStyle)),
       mJustificationSpacing(0),
       mHyphenWidth(-1),
       mOffsetFromBlockOriginForTabs(aOffsetFromBlockOriginForTabs),
       mReflowing(true),
       mWhichTextRun(aWhichTextRun)
   {
     NS_ASSERTION(mStart.IsInitialized(), "Start not initialized?");
   }
@@ -2627,18 +2657,18 @@ public:
                    nsTextFrame::TextRunType aWhichTextRun)
     : mTextRun(aFrame->GetTextRun(aWhichTextRun)), mFontGroup(nullptr),
       mTextStyle(aFrame->GetStyleText()),
       mFrag(aFrame->GetContent()->GetText()),
       mLineContainer(nullptr),
       mFrame(aFrame), mStart(aStart), mTempIterator(aStart),
       mTabWidths(nullptr), mTabWidthsAnalyzedLimit(0),
       mLength(aFrame->GetContentLength()),
-      mWordSpacing(mTextStyle->mWordSpacing),
-      mLetterSpacing(StyleToCoord(mTextStyle->mLetterSpacing)),
+      mWordSpacing(WordSpacing(aFrame)),
+      mLetterSpacing(LetterSpacing(aFrame)),
       mJustificationSpacing(0),
       mHyphenWidth(-1),
       mOffsetFromBlockOriginForTabs(0),
       mReflowing(false),
       mWhichTextRun(aWhichTextRun)
   {
     NS_ASSERTION(mTextRun, "Textrun not initialized!");
   }
@@ -4533,21 +4563,17 @@ nsTextFrame::GetTextDecorations(nsPresCo
     // Not updating positions once we hit a parent block is equivalent to
     // the CSS 2.1 spec that blocks should propagate decorations down to their
     // children (albeit the style should be preserved)
     // However, if we're vertically aligned within a block, then we need to
     // recover the right baseline from the line by querying the FrameProperty
     // that should be set (see nsLineLayout::VerticalAlignLine).
     if (firstBlock) {
       // At this point, fChild can't be null since TextFrames can't be blocks
-      const nsStyleCoord& vAlign =
-        fChild->GetStyleContext()->GetStyleTextReset()->mVerticalAlign;
-      if (vAlign.GetUnit() != eStyleUnit_Enumerated ||
-          vAlign.GetIntValue() != NS_STYLE_VERTICAL_ALIGN_BASELINE)
-      {
+      if (fChild->VerticalAlignEnum() != NS_STYLE_VERTICAL_ALIGN_BASELINE) {
         // Since offset is the offset in the child's coordinate space, we have
         // to undo the accumulation to bring the transform out of the block's
         // coordinate space
         baselineOffset =
           frameTopOffset - (fChild->GetRect().y - fChild->GetRelativeOffset().y)
           - NS_PTR_TO_INT32(
               fChild->Properties().Get(nsIFrame::LineBaselineOffset()));
       }
@@ -4576,31 +4602,31 @@ nsTextFrame::GetTextDecorations(nsPresCo
       if (textDecorations & NS_STYLE_TEXT_DECORATION_LINE_LINE_THROUGH) {
         aDecorations.mStrikes.AppendElement(
           nsTextFrame::LineDecoration(f, baselineOffset, color, style));
       }
     }
 
     // In all modes, if we're on an inline-block or inline-table (or
     // inline-stack, inline-box, inline-grid), we're done.
-    const nsStyleDisplay *disp = context->GetStyleDisplay();
-    if (disp->mDisplay != NS_STYLE_DISPLAY_INLINE &&
-        disp->IsInlineOutside()) {
+    PRUint8 display = f->GetDisplay();
+    if (display != NS_STYLE_DISPLAY_INLINE &&
+        nsStyleDisplay::IsDisplayTypeInlineOutside(display)) {
       break;
     }
 
     if (compatMode == eCompatibility_NavQuirks) {
       // In quirks mode, if we're on an HTML table element, we're done.
       if (f->GetContent()->IsHTML(nsGkAtoms::table)) {
         break;
       }
     } else {
       // In standards/almost-standards mode, if we're on an
       // absolutely-positioned element or a floating element, we're done.
-      if (disp->IsFloating() || disp->IsAbsolutelyPositioned()) {
+      if (f->IsFloating() || f->IsAbsolutelyPositioned()) {
         break;
       }
     }
   }
 }
 
 void
 nsTextFrame::UnionAdditionalOverflow(nsPresContext* aPresContext,
@@ -7151,17 +7177,17 @@ nsTextFrame::SetLength(PRInt32 aLength, 
   }
 #endif
 }
 
 bool
 nsTextFrame::IsFloatingFirstLetterChild() const
 {
   nsIFrame* frame = GetParent();
-  return frame && frame->GetStyleDisplay()->IsFloating() &&
+  return frame && frame->IsFloating() &&
          frame->GetType() == nsGkAtoms::letterFrame;
 }
 
 struct NewlineProperty {
   PRInt32 mStartOffset;
   // The offset of the first \n after mStartOffset, or -1 if there is none
   PRInt32 mNewlineOffset;
 
@@ -7717,17 +7743,18 @@ nsTextFrame::ReflowText(nsLineLayout& aL
     }
   } else if (cachedNewlineOffset) {
     mContent->DeleteProperty(nsGkAtoms::newline);
   }
 
   // Compute space and letter counts for justification, if required
   if (!textStyle->WhiteSpaceIsSignificant() &&
       (lineContainer->GetStyleText()->mTextAlign == NS_STYLE_TEXT_ALIGN_JUSTIFY ||
-       lineContainer->GetStyleText()->mTextAlignLast == NS_STYLE_TEXT_ALIGN_JUSTIFY)) {
+       lineContainer->GetStyleText()->mTextAlignLast == NS_STYLE_TEXT_ALIGN_JUSTIFY) &&
+      !lineContainer->IsSVGText()) {
     AddStateBits(TEXT_JUSTIFICATION_ENABLED);    // This will include a space for trailing whitespace, if any is present.
     // This is corrected for in nsLineLayout::TrimWhiteSpaceIn.
     PRInt32 numJustifiableCharacters =
       provider.ComputeJustifiableCharacters(offset, charsFit);
 
     NS_ASSERTION(numJustifiableCharacters <= charsFit,
                  "Bad justifiable character count");
     aLineLayout.SetTextJustificationWeights(numJustifiableCharacters,
--- a/layout/style/nsCSSAnonBoxList.h
+++ b/layout/style/nsCSSAnonBoxList.h
@@ -78,8 +78,9 @@ CSS_ANON_BOX(moztreeimage, ":-moz-tree-i
 CSS_ANON_BOX(moztreecelltext, ":-moz-tree-cell-text")
 CSS_ANON_BOX(moztreecheckbox, ":-moz-tree-checkbox")
 CSS_ANON_BOX(moztreeprogressmeter, ":-moz-tree-progressmeter")
 CSS_ANON_BOX(moztreedropfeedback, ":-moz-tree-drop-feedback")
 #endif
 
 CSS_ANON_BOX(mozSVGOuterSVGAnonChild, ":-moz-svg-outer-svg-anon-child")
 CSS_ANON_BOX(mozSVGForeignContent, ":-moz-svg-foreign-content")
+CSS_ANON_BOX(mozSVGText, ":-moz-svg-text")
--- a/layout/style/nsRuleNode.cpp
+++ b/layout/style/nsRuleNode.cpp
@@ -4848,17 +4848,17 @@ nsRuleNode::ComputeDisplayData(void* aSt
       display->mOriginalDisplay = display->mDisplay = NS_STYLE_DISPLAY_INLINE;
 
       // We can't cache the data in the rule tree since if a more specific
       // rule has 'float: left' we'll end up with the wrong 'display'
       // property.
       canStoreInRuleTree = false;
     }
 
-    if (display->IsAbsolutelyPositioned()) {
+    if (display->IsAbsolutelyPositionedStyle()) {
       // 1) if position is 'absolute' or 'fixed' then display must be
       // block-level and float must be 'none'
       EnsureBlockDisplay(display->mDisplay);
       display->mFloats = NS_STYLE_FLOAT_NONE;
 
       // Note that it's OK to cache this struct in the ruletree
       // because it's fine as-is for any style context that points to
       // it directly, and any use of it as aStartStruct (e.g. if a
--- a/layout/style/nsStyleStruct.cpp
+++ b/layout/style/nsStyleStruct.cpp
@@ -1033,23 +1033,25 @@ nsChangeHint nsStyleSVGReset::CalcDiffer
   nsChangeHint hint = nsChangeHint(0);
 
   if (!EqualURIs(mClipPath, aOther.mClipPath) ||
       !EqualURIs(mFilter, aOther.mFilter)     ||
       !EqualURIs(mMask, aOther.mMask)) {
     NS_UpdateHint(hint, nsChangeHint_UpdateEffects);
     NS_UpdateHint(hint, nsChangeHint_ReflowFrame);
     NS_UpdateHint(hint, nsChangeHint_RepaintFrame);
-  } else if (mStopColor        != aOther.mStopColor     ||
-             mFloodColor       != aOther.mFloodColor    ||
-             mLightingColor    != aOther.mLightingColor ||
-             mStopOpacity      != aOther.mStopOpacity   ||
-             mFloodOpacity     != aOther.mFloodOpacity  ||
-             mDominantBaseline != aOther.mDominantBaseline ||
-             mVectorEffect     != aOther.mVectorEffect)
+  } else if (mDominantBaseline != aOther.mDominantBaseline) {
+    NS_UpdateHint(hint, nsChangeHint_NeedReflow);
+    NS_UpdateHint(hint, nsChangeHint_NeedDirtyReflow);
+  } else if (mStopColor     != aOther.mStopColor     ||
+             mFloodColor    != aOther.mFloodColor    ||
+             mLightingColor != aOther.mLightingColor ||
+             mStopOpacity   != aOther.mStopOpacity   ||
+             mFloodOpacity  != aOther.mFloodOpacity  ||
+             mVectorEffect  != aOther.mVectorEffect)
     NS_UpdateHint(hint, nsChangeHint_RepaintFrame);
 
   return hint;
 }
 
 #ifdef DEBUG
 /* static */
 nsChangeHint nsStyleSVGReset::MaxDifference()
--- a/layout/style/nsStyleStruct.h
+++ b/layout/style/nsStyleStruct.h
@@ -1595,26 +1595,26 @@ struct nsStyleDisplay {
            mAnimationDurationCount,
            mAnimationDelayCount,
            mAnimationNameCount,
            mAnimationDirectionCount,
            mAnimationFillModeCount,
            mAnimationPlayStateCount,
            mAnimationIterationCountCount;
 
-  bool IsBlockInside() const {
+  bool IsBlockInsideStyle() const {
     return NS_STYLE_DISPLAY_BLOCK == mDisplay ||
            NS_STYLE_DISPLAY_LIST_ITEM == mDisplay ||
            NS_STYLE_DISPLAY_INLINE_BLOCK == mDisplay;
     // Should TABLE_CELL and TABLE_CAPTION go here?  They have
     // block frames nested inside of them.
     // (But please audit all callers before changing.)
   }
 
-  bool IsBlockOutside() const {
+  bool IsBlockOutsideStyle() const {
     return NS_STYLE_DISPLAY_BLOCK == mDisplay ||
 #ifdef MOZ_FLEXBOX
            NS_STYLE_DISPLAY_FLEX == mDisplay ||
 #endif // MOZ_FLEXBOX
            NS_STYLE_DISPLAY_LIST_ITEM == mDisplay ||
            NS_STYLE_DISPLAY_TABLE == mDisplay;
   }
 
@@ -1625,50 +1625,68 @@ struct nsStyleDisplay {
            NS_STYLE_DISPLAY_INLINE_BOX == aDisplay ||
 #ifdef MOZ_FLEXBOX
            NS_STYLE_DISPLAY_INLINE_FLEX == aDisplay ||
 #endif // MOZ_FLEXBOX
            NS_STYLE_DISPLAY_INLINE_GRID == aDisplay ||
            NS_STYLE_DISPLAY_INLINE_STACK == aDisplay;
   }
 
-  bool IsInlineOutside() const {
+  bool IsInlineOutsideStyle() const {
     return IsDisplayTypeInlineOutside(mDisplay);
   }
 
-  bool IsOriginalDisplayInlineOutside() const {
+  bool IsOriginalDisplayInlineOutsideStyle() const {
     return IsDisplayTypeInlineOutside(mOriginalDisplay);
   }
 
-  bool IsFloating() const {
+  bool IsFloatingStyle() const {
     return NS_STYLE_FLOAT_NONE != mFloats;
   }
 
-  bool IsAbsolutelyPositioned() const {return (NS_STYLE_POSITION_ABSOLUTE == mPosition) ||
-                                                (NS_STYLE_POSITION_FIXED == mPosition);}
+  bool IsAbsolutelyPositionedStyle() const {
+    return NS_STYLE_POSITION_ABSOLUTE == mPosition ||
+           NS_STYLE_POSITION_FIXED == mPosition;
+  }
 
   /* Returns true if we're positioned or there's a transform in effect. */
-  bool IsPositioned() const {
-    return IsAbsolutelyPositioned() ||
-      NS_STYLE_POSITION_RELATIVE == mPosition || HasTransform();
+  bool IsPositionedStyle() const {
+    return IsAbsolutelyPositionedStyle() ||
+           IsRelativelyPositionedStyle() ||
+           HasTransform();
+  }
+
+  bool IsRelativelyPositionedStyle() const {
+    return mPosition == NS_STYLE_POSITION_RELATIVE;
   }
 
   bool IsScrollableOverflow() const {
     // mOverflowX and mOverflowY always match when one of them is
     // NS_STYLE_OVERFLOW_VISIBLE or NS_STYLE_OVERFLOW_CLIP.
     return mOverflowX != NS_STYLE_OVERFLOW_VISIBLE &&
            mOverflowX != NS_STYLE_OVERFLOW_CLIP;
   }
 
   /* Returns whether the element has the -moz-transform property. */
   bool HasTransform() const {
     return mSpecifiedTransform != nullptr || 
            mTransformStyle == NS_STYLE_TRANSFORM_STYLE_PRESERVE_3D ||
            mBackfaceVisibility == NS_STYLE_BACKFACE_VISIBILITY_HIDDEN;
   }
+
+  // These are defined in nsStyleStructInlines.h.
+  inline bool IsBlockInside(const nsIFrame* aFrame) const;
+  inline bool IsBlockOutside(const nsIFrame* aFrame) const;
+  inline bool IsInlineOutside(const nsIFrame* aFrame) const;
+  inline bool IsOriginalDisplayInlineOutside(const nsIFrame* aFrame) const;
+  inline PRUint8 GetDisplay(const nsIFrame* aFrame) const;
+  inline bool IsFloating(const nsIFrame* aFrame) const;
+  inline bool IsPositioned(const nsIFrame* aFrame) const;
+  inline bool IsRelativelyPositioned(const nsIFrame* aFrame) const;
+  inline bool IsAbsolutelyPositioned(const nsIFrame* aFrame) const;
 };
 
 struct nsStyleTable {
   nsStyleTable(void);
   nsStyleTable(const nsStyleTable& aOther);
   ~nsStyleTable(void);
 
   void* operator new(size_t sz, nsPresContext* aContext) CPP_THROW_NEW {
--- a/layout/style/nsStyleStructInlines.h
+++ b/layout/style/nsStyleStructInlines.h
@@ -6,16 +6,17 @@
 /*
  * Inline methods that belong in nsStyleStruct.h, except that they
  * require more headers.
  */
 
 #ifndef nsStyleStructInlines_h_
 #define nsStyleStructInlines_h_
 
+#include "nsIFrame.h"
 #include "nsStyleStruct.h"
 #include "imgIRequest.h"
 #include "imgIContainer.h"
 
 inline void
 nsStyleBorder::SetBorderImage(imgIRequest* aImage)
 {
   mBorderImageSource = aImage;
@@ -49,9 +50,81 @@ inline imgIContainer*
 nsStyleBorder::GetSubImage(PRUint8 aIndex) const
 {
   imgIContainer* subImage = nullptr;
   if (aIndex < mSubImages.Count())
     subImage = mSubImages[aIndex];
   return subImage;
 }
 
+bool
+nsStyleDisplay::IsBlockInside(const nsIFrame* aFrame) const
+{
+  if (aFrame->GetStateBits() & NS_FRAME_IS_SVG_TEXT) {
+    return aFrame->GetType() == nsGkAtoms::blockFrame;
+  }
+  return IsBlockInsideStyle();
+}
+
+bool
+nsStyleDisplay::IsBlockOutside(const nsIFrame* aFrame) const
+{
+  if (aFrame->GetStateBits() & NS_FRAME_IS_SVG_TEXT) {
+    return aFrame->GetType() == nsGkAtoms::blockFrame;
+  }
+  return IsBlockOutsideStyle();
+}
+
+bool
+nsStyleDisplay::IsInlineOutside(const nsIFrame* aFrame) const
+{
+  if (aFrame->GetStateBits() & NS_FRAME_IS_SVG_TEXT) {
+    return aFrame->GetType() != nsGkAtoms::blockFrame;
+  }
+  return IsInlineOutsideStyle();
+}
+
+bool
+nsStyleDisplay::IsOriginalDisplayInlineOutside(const nsIFrame* aFrame) const
+{
+  if (aFrame->GetStateBits() & NS_FRAME_IS_SVG_TEXT) {
+    return aFrame->GetType() != nsGkAtoms::blockFrame;
+  }
+  return IsOriginalDisplayInlineOutsideStyle();
+}
+
+PRUint8
+nsStyleDisplay::GetDisplay(const nsIFrame* aFrame) const
+{
+  if ((aFrame->GetStateBits() & NS_FRAME_IS_SVG_TEXT) &&
+      mDisplay != NS_STYLE_DISPLAY_NONE) {
+    return aFrame->GetType() == nsGkAtoms::blockFrame ?
+             NS_STYLE_DISPLAY_BLOCK :
+             NS_STYLE_DISPLAY_INLINE;
+  }
+  return mDisplay;
+}
+
+bool
+nsStyleDisplay::IsFloating(const nsIFrame* aFrame) const
+{
+  return IsFloatingStyle() && !aFrame->IsSVGText();
+}
+
+bool
+nsStyleDisplay::IsPositioned(const nsIFrame* aFrame) const
+{
+  return IsPositionedStyle() && !aFrame->IsSVGText();
+}
+
+bool
+nsStyleDisplay::IsRelativelyPositioned(const nsIFrame* aFrame) const
+{
+  return IsRelativelyPositionedStyle() && !aFrame->IsSVGText();
+}
+
+bool
+nsStyleDisplay::IsAbsolutelyPositioned(const nsIFrame* aFrame) const
+{
+  return IsAbsolutelyPositionedStyle() && !aFrame->IsSVGText();
+}
+
 #endif /* !defined(nsStyleStructInlines_h_) */
--- a/layout/svg/base/src/nsSVGGlyphFrame.cpp
+++ b/layout/svg/base/src/nsSVGGlyphFrame.cpp
@@ -1671,17 +1671,17 @@ nsSVGGlyphFrame::EnsureTextRun(float *aD
 
     font.AddFontFeaturesToStyle(&fontStyle);
 
     nsRefPtr<gfxFontGroup> fontGroup =
       gfxPlatform::GetPlatform()->CreateFontGroup(font.name, &fontStyle, presContext->GetUserFontSet());
 
     PRUint32 flags = gfxTextRunFactory::TEXT_NEED_BOUNDING_BOX |
       GetTextRunFlags(text.Length()) |
-      nsLayoutUtils::GetTextRunFlagsForStyle(GetStyleContext(), GetStyleText(), GetStyleFont());
+      nsLayoutUtils::GetTextRunFlagsForStyle(GetStyleContext(), GetStyleFont(), 0);
 
     // XXX We should use a better surface here! But then we'd have to
     // change things so we can ensure we always have the "right" sort of
     // surface available, by creating the textrun only at the right times
     nsRefPtr<gfxContext> tmpCtx = MakeTmpCtx();
     tmpCtx->SetMatrix(m);
 
     // Use only the fonts' internal word caching here.
--- a/layout/tables/nsTableRowFrame.cpp
+++ b/layout/tables/nsTableRowFrame.cpp
@@ -887,17 +887,17 @@ nsTableRowFrame::ReflowChildren(nsPresCo
         }
         
         desiredSize.width = cellDesiredSize.width;
         desiredSize.height = cellDesiredSize.height;
         desiredSize.mOverflowAreas = cellFrame->GetOverflowAreas();
 
         // if we are in a floated table, our position is not yet established, so we cannot reposition our views
         // the containing block will do this for us after positioning the table
-        if (!aTableFrame.GetStyleDisplay()->IsFloating()) {
+        if (!aTableFrame.IsFloating()) {
           // Because we may have moved the frame we need to make sure any views are
           // positioned properly. We have to do this, because any one of our parent
           // frames could have moved and we have no way of knowing...
           nsTableFrame::RePositionViews(kidFrame);
         }
       }
       
       if (NS_UNCONSTRAINEDSIZE == aReflowState.availableHeight) {
--- a/mobile/android/base/Tab.java
+++ b/mobile/android/base/Tab.java
@@ -449,49 +449,49 @@ public final class Tab {
 
     public void readerMode() {
         if (!mReaderEnabled)
             return;
 
         GeckoApp.mAppContext.loadUrl("about:reader?url=" + Uri.encode(getURL()));
     }
 
-    public boolean doReload() {
+    public void doReload() {
         GeckoEvent e = GeckoEvent.createBroadcastEvent("Session:Reload", "");
         GeckoAppShell.sendEventToGecko(e);
-        return true;
     }
 
+    // Our version of nsSHistory::GetCanGoBack
     public boolean canDoBack() {
-        return (mHistoryIndex < 1 ? false : true);
+        return mHistoryIndex > 0;
     }
 
     public boolean doBack() {
-        if (mHistoryIndex < 1) {
+        if (!canDoBack())
             return false;
-        }
+
         GeckoEvent e = GeckoEvent.createBroadcastEvent("Session:Back", "");
         GeckoAppShell.sendEventToGecko(e);
         return true;
     }
 
-    public boolean doStop() {
+    public void doStop() {
         GeckoEvent e = GeckoEvent.createBroadcastEvent("Session:Stop", "");
         GeckoAppShell.sendEventToGecko(e);
-        return true;
     }
 
+    // Our version of nsSHistory::GetCanGoForward
     public boolean canDoForward() {
-        return (mHistoryIndex + 1 < mHistorySize);
+        return mHistoryIndex < mHistorySize - 1;
     }
 
     public boolean doForward() {
-        if (mHistoryIndex + 1 >= mHistorySize) {
+        if (!canDoForward())
             return false;
-        }
+
         GeckoEvent e = GeckoEvent.createBroadcastEvent("Session:Forward", "");
         GeckoAppShell.sendEventToGecko(e);
         return true;
     }
 
     public void addDoorHanger(String value, DoorHanger dh) {
         mDoorHangers.put(value, dh);
     }
@@ -526,52 +526,58 @@ public final class Tab {
     }
 
     public HashMap<String, DoorHanger> getDoorHangers() {
         return mDoorHangers;
     }
 
     void handleSessionHistoryMessage(String event, JSONObject message) throws JSONException {
         if (event.equals("New")) {
-            final String uri = message.getString("uri");
+            final String url = message.getString("url");
             mHistoryIndex++;
             mHistorySize = mHistoryIndex + 1;
             GeckoAppShell.getHandler().post(new Runnable() {
                 public void run() {
-                    GlobalHistory.getInstance().add(uri);
+                    GlobalHistory.getInstance().add(url);
                 }
             });
         } else if (event.equals("Back")) {
-            if (mHistoryIndex - 1 < 0) {
+            if (!canDoBack()) {
                 Log.e(LOGTAG, "Received unexpected back notification");
                 return;
             }
             mHistoryIndex--;
         } else if (event.equals("Forward")) {
-            if (mHistoryIndex + 1 >= mHistorySize) {
+            if (!canDoForward()) {
                 Log.e(LOGTAG, "Received unexpected forward notification");
                 return;
             }
             mHistoryIndex++;
         } else if (event.equals("Goto")) {
             int index = message.getInt("index");
             if (index < 0 || index >= mHistorySize) {
                 Log.e(LOGTAG, "Received unexpected history-goto notification");
                 return;
             }
             mHistoryIndex = index;
         } else if (event.equals("Purge")) {
-            int numEntries = message.getInt("index");
+            int numEntries = message.getInt("numEntries");
+            if (numEntries > mHistorySize) {
+                Log.e(LOGTAG, "Received unexpectedly large number of history entries to purge");
+                mHistoryIndex = -1;
+                mHistorySize = 0;
+                return;
+            }
+
             mHistorySize -= numEntries;
             mHistoryIndex -= numEntries;
-            if (mHistorySize < 0 || mHistoryIndex < -1) {
-                Log.e(LOGTAG, "Unexpected history state: index = " + mHistoryIndex + ", size = " + mHistorySize);
-                mHistorySize = 0;
-                mHistoryIndex = -1;
-            }
+
+            // If we weren't at the last history entry, mHistoryIndex may have become too small
+            if (mHistoryIndex < -1)
+                 mHistoryIndex = -1;
         }
     }
 
     private void saveThumbnailToDB() {
         try {
             String url = getURL();
             if (url == null)
                 return;
--- a/mobile/android/chrome/content/WebAppRT.js
+++ b/mobile/android/chrome/content/WebAppRT.js
@@ -40,16 +40,21 @@ var WebAppRT = {
           case "boolean":
             Services.prefs.setBoolPref(aPref.name, aPref.value);
             break;
           case "number":
             Services.prefs.setIntPref(aPref.name, aPref.value);
             break;
         }
       });
+
+      // update the blocklist url to use a different app id
+      var blocklist = Services.prefs.getCharPref("extensions.blocklist.url");
+      blocklist = blocklist.replace(/%APP_ID%/g, "webapprt-mobile@mozilla.org");
+      Services.prefs.setCharPref("extensions.blocklist.url", blocklist);
     }
   },
 
   handleEvent: function(event) {
     let target = event.target;
   
     if (!(target instanceof HTMLAnchorElement) ||
         target.getAttribute("target") != "_blank") {
--- a/mobile/android/chrome/content/browser.js
+++ b/mobile/android/chrome/content/browser.js
@@ -2966,59 +2966,63 @@ Tab.prototype = {
   },
 
   onProgressChange: function(aWebProgress, aRequest, aCurSelfProgress, aMaxSelfProgress, aCurTotalProgress, aMaxTotalProgress) {
   },
 
   onStatusChange: function(aBrowser, aWebProgress, aRequest, aStatus, aMessage) {
   },
 
-  _sendHistoryEvent: function(aMessage, aIndex, aUri) {
+  _sendHistoryEvent: function(aMessage, aParams) {
     let message = {
       gecko: {
         type: "SessionHistory:" + aMessage,
         tabID: this.id,
       }
     };
-    if (aIndex != -1) {
-      message.gecko.index = aIndex;
-    }
-    if (aUri != null) {
-      message.gecko.uri = aUri;
-    }
+
+    if (aParams) {
+      if ("url" in aParams)
+        message.gecko.url = aParams.url;
+      if ("index" in aParams)
+        message.gecko.index = aParams.index;
+      if ("numEntries" in aParams)
+        message.gecko.numEntries = aParams.numEntries;
+    }
+
     sendMessageToJava(message);
   },
 
   OnHistoryNewEntry: function(aUri) {
-    this._sendHistoryEvent("New", -1, aUri.spec);
+    this._sendHistoryEvent("New", { url: aUri.spec });
   },
 
   OnHistoryGoBack: function(aUri) {
-    this._sendHistoryEvent("Back", -1, null);
+    this._sendHistoryEvent("Back");
     return true;
   },
 
   OnHistoryGoForward: function(aUri) {
-    this._sendHistoryEvent("Forward", -1, null);
+    this._sendHistoryEvent("Forward");
     return true;
   },
 
   OnHistoryReload: function(aUri, aFlags) {
     // we don't do anything with this, so don't propagate it
     // for now anyway
     return true;
   },
 
   OnHistoryGotoIndex: function(aIndex, aUri) {
-    this._sendHistoryEvent("Goto", aIndex, null);
+    this._sendHistoryEvent("Goto", { index: aIndex });
     return true;
   },
 
   OnHistoryPurge: function(aNumEntries) {
-    this._sendHistoryEvent("Purge", aNumEntries, null);
+    this._sendHistoryEvent("Purge", { numEntries: aNumEntries });
     return true;
   },
 
   get metadata() {
     return ViewportHandler.getMetadataForDocument(this.browser.contentDocument);
   },
 
   /** Update viewport when the metadata changes. */
--- a/mobile/android/components/AboutRedirector.js
+++ b/mobile/android/components/AboutRedirector.js
@@ -34,27 +34,27 @@ let modules = {
     uri: "chrome://browser/content/aboutRights.xhtml",
 #else
     uri: "chrome://global/content/aboutRights-unbranded.xhtml",
 #endif
     privileged: false
   },
   blocked: {
     uri: "chrome://browser/content/blockedSite.xhtml",
-    privileged: true,
+    privileged: false,
     hide: true
   },
   certerror: {
     uri: "chrome://browser/content/aboutCertError.xhtml",
-    privileged: true,
+    privileged: false,
     hide: true
   },
   home: {
     uri: "chrome://browser/content/aboutHome.xhtml",
-    privileged: true
+    privileged: false
   },
   apps: {
     uri: "chrome://browser/content/aboutApps.xhtml",
     privileged: true
   },
   downloads: {
     uri: "chrome://browser/content/aboutDownloads.xhtml",
     privileged: true
--- a/mobile/xul/app/nsBrowserApp.cpp
+++ b/mobile/xul/app/nsBrowserApp.cpp
@@ -195,28 +195,22 @@ int main(int argc, char* argv[])
 
   strcpy(++lastSlash, XPCOM_DLL);
 
   int gotCounters;
 #if defined(XP_UNIX)
   struct rusage initialRUsage;
   gotCounters = !getrusage(RUSAGE_SELF, &initialRUsage);
 #elif defined(XP_WIN)
-  // GetProcessIoCounters().ReadOperationCount seems to have little to
-  // do with actual read operations. It reports 0 or 1 at this stage
-  // in the program. Luckily 1 coincides with when prefetch is
-  // enabled. If Windows prefetch didn't happen we can do our own
-  // faster dll preloading.
   IO_COUNTERS ioCounters;
   gotCounters = GetProcessIoCounters(GetCurrentProcess(), &ioCounters);
-  if (gotCounters && !ioCounters.ReadOperationCount)
 #endif
-  {
-      XPCOMGlueEnablePreload();
-  }
+
+  // We do this because of data in bug 771745
+  XPCOMGlueEnablePreload();
 
 #if MOZ_PLATFORM_MAEMO == 6
   nsFastStartup startup;
   startup.CreateFastStartup(argc, argv, exePath, GeckoPreLoader);
 #else
   rv = XPCOMGlueStartup(exePath);
   if (NS_FAILED(rv)) {
     Output("Couldn't load XPCOM.\n");
--- a/netwerk/base/public/nsISocketTransport.idl
+++ b/netwerk/base/public/nsISocketTransport.idl
@@ -103,16 +103,20 @@ interface nsISocketTransport : nsITransp
      * is no ambiguity.
      *
      * The values of these status codes must never change.
      *
      * The status codes appear in near-chronological order (not in numeric
      * order).  STATUS_RESOLVING may be skipped if the host does not need to be
      * resolved.  STATUS_WAITING_FOR is an optional status code, which the impl
      * of this interface may choose not to generate.
+     *
+     * In C++, these constants have a type of PRUint32, so C++ callers must use
+     * the NS_NET_STATUS_* constants defined below, which have a type of
+     * nsresult.
      */
     const unsigned long STATUS_RESOLVING      = 0x804b0003;
     const unsigned long STATUS_RESOLVED       = 0x804b000b;
     const unsigned long STATUS_CONNECTING_TO  = 0x804b0007;
     const unsigned long STATUS_CONNECTED_TO   = 0x804b0004;
     const unsigned long STATUS_SENDING_TO     = 0x804b0005;
     const unsigned long STATUS_WAITING_FOR    = 0x804b000a;
     const unsigned long STATUS_RECEIVING_FROM = 0x804b0006;
@@ -155,18 +159,25 @@ interface nsISocketTransport : nsITransp
      * IPTOS_PREC_ROUTINE).
      */
     attribute octet QoSBits;
 
 };
 
 %{C++
 /**
- * #define's for compatibility
+ * #define's with the correct type, for use by C++ code
  */
-#define NS_NET_STATUS_RESOLVING_HOST nsISocketTransport::STATUS_RESOLVING
-#define NS_NET_STATUS_RESOLVED_HOST  nsISocketTransport::STATUS_RESOLVED
-#define NS_NET_STATUS_CONNECTED_TO   nsISocketTransport::STATUS_CONNECTED_TO
-#define NS_NET_STATUS_SENDING_TO     nsISocketTransport::STATUS_SENDING_TO
-#define NS_NET_STATUS_RECEIVING_FROM nsISocketTransport::STATUS_RECEIVING_FROM
-#define NS_NET_STATUS_CONNECTING_TO  nsISocketTransport::STATUS_CONNECTING_TO
-#define NS_NET_STATUS_WAITING_FOR    nsISocketTransport::STATUS_WAITING_FOR
+#define NS_NET_STATUS_RESOLVING_HOST \
+  static_cast<nsresult>(nsISocketTransport::STATUS_RESOLVING)
+#define NS_NET_STATUS_RESOLVED_HOST \
+  static_cast<nsresult>(nsISocketTransport::STATUS_RESOLVED)
+#define NS_NET_STATUS_CONNECTED_TO \
+  static_cast<nsresult>(nsISocketTransport::STATUS_CONNECTED_TO)
+#define NS_NET_STATUS_SENDING_TO \
+  static_cast<nsresult>(nsISocketTransport::STATUS_SENDING_TO)
+#define NS_NET_STATUS_RECEIVING_FROM \
+  static_cast<nsresult>(nsISocketTransport::STATUS_RECEIVING_FROM)
+#define NS_NET_STATUS_CONNECTING_TO \
+  static_cast<nsresult>(nsISocketTransport::STATUS_CONNECTING_TO)
+#define NS_NET_STATUS_WAITING_FOR \
+  static_cast<nsresult>(nsISocketTransport::STATUS_WAITING_FOR)
 %}
--- a/netwerk/base/public/nsITransport.idl
+++ b/netwerk/base/public/nsITransport.idl
@@ -123,16 +123,20 @@ interface nsITransport : nsISupports
      */
     void setEventSink(in nsITransportEventSink aSink,
                       in nsIEventTarget aEventTarget); 
     
     /**
      * Generic nsITransportEventSink status codes.  nsITransport
      * implementations may override these status codes with their own more
      * specific status codes (e.g., see nsISocketTransport).
+     *
+     * In C++, these constants have a type of PRUint32, so C++ callers must use
+     * the NS_NET_STATUS_* constants defined below, which have a type of
+     * nsresult.
      */
     const unsigned long STATUS_READING = 0x804b0008;
     const unsigned long STATUS_WRITING = 0x804b0009;
 };
 
 [scriptable, uuid(EDA4F520-67F7-484b-A691-8C3226A5B0A6)]
 interface nsITransportEventSink : nsISupports
 {
@@ -152,8 +156,15 @@ interface nsITransportEventSink : nsISup
      *        the maximum amount of data that will be read or written.  if
      *        unknown, 0xFFFFFFFF will be passed.
      */
     void onTransportStatus(in nsITransport aTransport,
                            in nsresult aStatus,
                            in unsigned long long aProgress,
                            in unsigned long long aProgressMax);
 };
+
+%{C++
+#define NS_NET_STATUS_READING \
+  static_cast<nsresult>(nsITransport::STATUS_READING)
+#define NS_NET_STATUS_WRITING \
+  static_cast<nsresult>(nsITransport::STATUS_WRITING)
+%}
--- a/netwerk/base/src/nsBaseChannel.cpp
+++ b/netwerk/base/src/nsBaseChannel.cpp
@@ -743,17 +743,17 @@ nsBaseChannel::OnDataAvailable(nsIReques
 {
   SUSPEND_PUMP_FOR_SCOPE();
 
   nsresult rv = mListener->OnDataAvailable(this, mListenerContext, stream,
                                            offset, count);
   if (mSynthProgressEvents && NS_SUCCEEDED(rv)) {
     PRUint64 prog = PRUint64(offset) + count;
     PRUint64 progMax = ContentLength64();
-    OnTransportStatus(nullptr, nsITransport::STATUS_READING, prog, progMax);
+    OnTransportStatus(nullptr, NS_NET_STATUS_READING, prog, progMax);
   }
 
   return rv;
 }
 
 NS_IMETHODIMP
 nsBaseChannel::OnRedirectVerifyCallback(nsresult result)
 {
--- a/netwerk/base/src/nsSocketTransport2.cpp
+++ b/netwerk/base/src/nsSocketTransport2.cpp
@@ -353,17 +353,17 @@ nsSocketInputStream::Read(char *buf, PRU
         rv = mCondition;
     }
     if (NS_FAILED(rv))
         mTransport->OnInputClosed(rv);
 
     // only send this notification if we have indeed read some data.
     // see bug 196827 for an example of why this is important.
     if (n > 0)
-        mTransport->SendStatus(nsISocketTransport::STATUS_RECEIVING_FROM);
+        mTransport->SendStatus(NS_NET_STATUS_RECEIVING_FROM);
     return rv;
 }
 
 NS_IMETHODIMP
 nsSocketInputStream::ReadSegments(nsWriteSegmentFun writer, void *closure,
                                   PRUint32 count, PRUint32 *countRead)
 {
     // socket stream is unbuffered
@@ -576,17 +576,17 @@ nsSocketOutputStream::Write(const char *
         rv = mCondition;
     }
     if (NS_FAILED(rv))
         mTransport->OnOutputClosed(rv);
 
     // only send this notification if we have indeed written some data.
     // see bug 196827 for an example of why this is important.
     if (n > 0)
-        mTransport->SendStatus(nsISocketTransport::STATUS_SENDING_TO);
+        mTransport->SendStatus(NS_NET_STATUS_SENDING_TO);
     return rv;
 }
 
 NS_IMETHODIMP
 nsSocketOutputStream::WriteSegments(nsReadSegmentFun reader, void *closure,
                                     PRUint32 count, PRUint32 *countRead)
 {
     // socket stream is unbuffered
@@ -864,20 +864,20 @@ nsSocketTransport::SendStatus(nsresult s
     SOCKET_LOG(("nsSocketTransport::SendStatus [this=%x status=%x]\n", this, status));
 
     nsCOMPtr<nsITransportEventSink> sink;
     PRUint64 progress;
     {
         MutexAutoLock lock(mLock);
         sink = mEventSink;
         switch (status) {
-        case STATUS_SENDING_TO:
+        case NS_NET_STATUS_SENDING_TO:
             progress = mOutput.ByteCount();
             break;
-        case STATUS_RECEIVING_FROM:
+        case NS_NET_STATUS_RECEIVING_FROM:
             progress = mInput.ByteCount();
             break;
         default:
             progress = 0;
             break;
         }
     }
     if (sink)
@@ -918,17 +918,17 @@ nsSocketTransport::ResolveHost()
     mResolving = true;
 
     PRUint32 dnsFlags = 0;
     if (mConnectionFlags & nsSocketTransport::BYPASS_CACHE)
         dnsFlags = nsIDNSService::RESOLVE_BYPASS_CACHE;
     if (mConnectionFlags & nsSocketTransport::DISABLE_IPV6)
         dnsFlags |= nsIDNSService::RESOLVE_DISABLE_IPV6;
 
-    SendStatus(STATUS_RESOLVING);
+    SendStatus(NS_NET_STATUS_RESOLVING_HOST);
     rv = dns->AsyncResolve(SocketHost(), dnsFlags, this, nullptr,
                            getter_AddRefs(mDNSRequest));
     if (NS_SUCCEEDED(rv)) {
         SOCKET_LOG(("  advancing to STATE_RESOLVING\n"));
         mState = STATE_RESOLVING;
     }
     return rv;
 }
@@ -1139,17 +1139,17 @@ nsSocketTransport::InitiateSocket()
         mFD = fd;
         mFDref = 1;
         mFDconnected = false;
     }
 
     SOCKET_LOG(("  advancing to STATE_CONNECTING\n"));
     mState = STATE_CONNECTING;
     mPollTimeout = mTimeouts[TIMEOUT_CONNECT];
-    SendStatus(STATUS_CONNECTING_TO);
+    SendStatus(NS_NET_STATUS_CONNECTING_TO);
 
 #if defined(PR_LOGGING)
     if (SOCKET_LOG_ENABLED()) {
         char buf[64];
         PR_NetAddrToString(&mNetAddr, buf, sizeof(buf));
         SOCKET_LOG(("  trying address: %s\n", buf));
     }
 #endif
@@ -1376,17 +1376,17 @@ nsSocketTransport::OnSocketConnected()
     // to trample over mFDref if mFD is already set.
     {
         MutexAutoLock lock(mLock);
         NS_ASSERTION(mFD, "no socket");
         NS_ASSERTION(mFDref == 1, "wrong socket ref count");
         mFDconnected = true;
     }
 
-    SendStatus(STATUS_CONNECTED_TO);
+    SendStatus(NS_NET_STATUS_CONNECTED_TO);
 }
 
 PRFileDesc *
 nsSocketTransport::GetFD_Locked()
 {
     // mFD is not available to the streams while disconnected.
     if (!mFDconnected)
         return nullptr;
@@ -1439,17 +1439,17 @@ nsSocketTransport::OnSocketEvent(PRUint3
         if (mState == STATE_CLOSED)
             mCondition = ResolveHost();
         else
             SOCKET_LOG(("  ignoring redundant event\n"));
         break;
 
     case MSG_DNS_LOOKUP_COMPLETE:
         if (mDNSRequest)  // only send this if we actually resolved anything
-            SendStatus(STATUS_RESOLVED);
+            SendStatus(NS_NET_STATUS_RESOLVED_HOST);
 
         SOCKET_LOG(("  MSG_DNS_LOOKUP_COMPLETE\n"));
         mDNSRequest = 0;
         if (param) {
             mDNSRecord = static_cast<nsIDNSRecord *>(param);
             mDNSRecord->GetNextAddr(SocketPort(), &mNetAddr);
         }
         // status contains DNS lookup status
--- a/netwerk/base/src/nsStreamTransportService.cpp
+++ b/netwerk/base/src/nsStreamTransportService.cpp
@@ -195,17 +195,18 @@ nsInputStreamTransport::Read(char *buf, 
     if (count > max)
         count = max;
 
     nsresult rv = mSource->Read(buf, count, result);
 
     if (NS_SUCCEEDED(rv)) {
         mOffset += *result;
         if (mEventSink)
-            mEventSink->OnTransportStatus(this, STATUS_READING, mOffset, mLimit);
+            mEventSink->OnTransportStatus(this, NS_NET_STATUS_READING, mOffset,
+                                          mLimit);
     }
     return rv;
 }
 
 NS_IMETHODIMP
 nsInputStreamTransport::ReadSegments(nsWriteSegmentFun writer, void *closure,
                                      PRUint32 count, PRUint32 *result)
 {
@@ -394,17 +395,18 @@ nsOutputStreamTransport::Write(const cha
     if (count > max)
         count = max;
 
     nsresult rv = mSink->Write(buf, count, result);
 
     if (NS_SUCCEEDED(rv)) {
         mOffset += *result;
         if (mEventSink)
-            mEventSink->OnTransportStatus(this, STATUS_WRITING, mOffset, mLimit);
+            mEventSink->OnTransportStatus(this, NS_NET_STATUS_WRITING, mOffset,
+                                          mLimit);
     }
     return rv;
 }
 
 NS_IMETHODIMP
 nsOutputStreamTransport::WriteSegments(nsReadSegmentFun reader, void *closure,
                                        PRUint32 count, PRUint32 *result)
 {
--- a/netwerk/protocol/file/nsFileChannel.cpp
+++ b/netwerk/protocol/file/nsFileChannel.cpp
@@ -94,17 +94,17 @@ nsFileCopyEvent::DoCopy()
     if (result != (PRUint32) num) {
       rv = NS_ERROR_FILE_DISK_FULL;  // stopped prematurely (out of disk space)
       break;
     }
 
     // Dispatch progress notification
     if (mSink) {
       progress += num;
-      mSink->OnTransportStatus(nullptr, nsITransport::STATUS_WRITING, progress,
+      mSink->OnTransportStatus(nullptr, NS_NET_STATUS_WRITING, progress,
                                mLen);
     }
                                
     len -= num;
   }
 
   if (NS_FAILED(rv))
     mStatus = rv;
--- a/netwerk/protocol/http/HttpChannelChild.cpp
+++ b/netwerk/protocol/http/HttpChannelChild.cpp
@@ -358,18 +358,18 @@ HttpChannelChild::OnTransportAndData(con
   // - JDUELL: may not need mStatus/mIsPending checks, given this is always called
   //   during OnDataAvailable, and we've already checked mCanceled.  Code
   //   dupe'd from nsHttpChannel
   if (mProgressSink && NS_SUCCEEDED(mStatus) && mIsPending &&
       !(mLoadFlags & LOAD_BACKGROUND))
   {
     // OnStatus
     //
-    NS_ASSERTION(status == nsISocketTransport::STATUS_RECEIVING_FROM ||
-                 status == nsITransport::STATUS_READING,
+    NS_ASSERTION(status == NS_NET_STATUS_RECEIVING_FROM ||
+                 status == NS_NET_STATUS_READING,
                  "unexpected status code");
 
     nsCAutoString host;
     mURI->GetHost(host);
     mProgressSink->OnStatus(this, nullptr, status,
                             NS_ConvertUTF8toUTF16(host).get());
     // OnProgress
     //
--- a/netwerk/protocol/http/HttpChannelParent.cpp
+++ b/netwerk/protocol/http/HttpChannelParent.cpp
@@ -24,17 +24,17 @@
 #include "nsIRedirectChannelRegistrar.h"
 #include "prinit.h"
 
 namespace mozilla {
 namespace net {
 
 HttpChannelParent::HttpChannelParent(PBrowserParent* iframeEmbedding)
   : mIPCClosed(false)
-  , mStoredStatus(0)
+  , mStoredStatus(NS_OK)
   , mStoredProgress(0)
   , mStoredProgressMax(0)
   , mSentRedirect1Begin(false)
   , mSentRedirect1BeginFailed(false)
   , mReceivedRedirect2Verify(false)
   , mHaveLoadContext(false)
   , mIsContent(false)
   , mUsePrivateBrowsing(false)
@@ -504,41 +504,41 @@ HttpChannelParent::OnDataAvailable(nsIRe
 NS_IMETHODIMP
 HttpChannelParent::OnProgress(nsIRequest *aRequest, 
                               nsISupports *aContext, 
                               PRUint64 aProgress, 
                               PRUint64 aProgressMax)
 {
   // OnStatus has always just set mStoredStatus. If it indicates this precedes
   // OnDataAvailable, store and ODA will send to child.
-  if (mStoredStatus == nsISocketTransport::STATUS_RECEIVING_FROM ||
-      mStoredStatus == nsITransport::STATUS_READING)
+  if (mStoredStatus == NS_NET_STATUS_RECEIVING_FROM ||
+      mStoredStatus == NS_NET_STATUS_READING)
   {
     mStoredProgress = aProgress;
     mStoredProgressMax = aProgressMax;
   } else {
     // Send to child now.  The only case I've observed that this handles (i.e.
     // non-ODA status with progress > 0) is data upload progress notification
-    // (status == nsISocketTransport::STATUS_SENDING_TO)
+    // (status == NS_NET_STATUS_SENDING_TO)
     if (mIPCClosed || !SendOnProgress(aProgress, aProgressMax))
       return NS_ERROR_UNEXPECTED;
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 HttpChannelParent::OnStatus(nsIRequest *aRequest, 
                             nsISupports *aContext, 
                             nsresult aStatus, 
                             const PRUnichar *aStatusArg)
 {
   // If this precedes OnDataAvailable, store and ODA will send to child.
-  if (aStatus == nsISocketTransport::STATUS_RECEIVING_FROM ||
-      aStatus == nsITransport::STATUS_READING)
+  if (aStatus == NS_NET_STATUS_RECEIVING_FROM ||
+      aStatus == NS_NET_STATUS_READING)
   {
     mStoredStatus = aStatus;
     return NS_OK;
   }
   // Otherwise, send to child now
   if (mIPCClosed || !SendOnStatus(aStatus))
     return NS_ERROR_UNEXPECTED;
   return NS_OK;
--- a/netwerk/protocol/http/nsHttpBasicAuth.cpp
+++ b/netwerk/protocol/http/nsHttpBasicAuth.cpp
@@ -84,13 +84,13 @@ nsHttpBasicAuth::GenerateCredentials(nsI
         return NS_ERROR_OUT_OF_MEMORY;
 
     memcpy(*creds, "Basic ", 6);
     PL_Base64Encode(userpass.get(), userpass.Length(), *creds + 6);
     return NS_OK;
 }
 
 NS_IMETHODIMP
-nsHttpBasicAuth::GetAuthFlags(nsresult *flags)
+nsHttpBasicAuth::GetAuthFlags(PRUint32 *flags)
 {
     *flags = REQUEST_BASED | REUSABLE_CREDENTIALS | REUSABLE_CHALLENGE;
     return NS_OK;
 }
--- a/netwerk/protocol/http/nsHttpChannel.cpp
+++ b/netwerk/protocol/http/nsHttpChannel.cpp
@@ -5049,19 +5049,19 @@ nsHttpChannel::OnDataAvailable(nsIReques
     if (mListener) {
         //
         // synthesize transport progress event.  we do this here since we want
         // to delay OnProgress events until we start streaming data.  this is
         // crucially important since it impacts the lock icon (see bug 240053).
         //
         nsresult transportStatus;
         if (request == mCachePump)
-            transportStatus = nsITransport::STATUS_READING;
+            transportStatus = NS_NET_STATUS_READING;
         else
-            transportStatus = nsISocketTransport::STATUS_RECEIVING_FROM;
+            transportStatus = NS_NET_STATUS_RECEIVING_FROM;
 
         // mResponseHead may reference new or cached headers, but either way it
         // holds our best estimate of the total content length.  Even in the case
         // of a byte range request, the content length stored in the cached
         // response headers is what we want to use here.
 
         PRUint64 progressMax(PRUint64(mResponseHead->ContentLength()));
         PRUint64 progress = mLogicalOffset + PRUint64(count);
@@ -5103,18 +5103,18 @@ nsHttpChannel::OnDataAvailable(nsIReques
 NS_IMETHODIMP
 nsHttpChannel::OnTransportStatus(nsITransport *trans, nsresult status,
                                  PRUint64 progress, PRUint64 progressMax)
 {
     // cache the progress sink so we don't have to query for it each time.
     if (!mProgressSink)
         GetCallback(mProgressSink);
 
-    if (status == nsISocketTransport::STATUS_CONNECTED_TO ||
-        status == nsISocketTransport::STATUS_WAITING_FOR) {
+    if (status == NS_NET_STATUS_CONNECTED_TO ||
+        status == NS_NET_STATUS_WAITING_FOR) {
         nsCOMPtr<nsISocketTransport> socketTransport =
             do_QueryInterface(trans);
         if (socketTransport) {
             socketTransport->GetSelfAddr(&mSelfAddr);
             socketTransport->GetPeerAddr(&mPeerAddr);
         }
     }
 
--- a/netwerk/protocol/http/nsHttpConnection.cpp
+++ b/netwerk/protocol/http/nsHttpConnection.cpp
@@ -1262,17 +1262,17 @@ nsHttpConnection::OnSocketWritable()
         else if (n == 0) {
             // 
             // at this point we've written out the entire transaction, and now we
             // must wait for the server's response.  we manufacture a status message
             // here to reflect the fact that we are waiting.  this message will be
             // trumped (overwritten) if the server responds quickly.
             //
             mTransaction->OnTransportStatus(mSocketTransport,
-                                            nsISocketTransport::STATUS_WAITING_FOR,
+                                            NS_NET_STATUS_WAITING_FOR,
                                             LL_ZERO);
 
             rv = ResumeRecv(); // start reading
             again = false;
         }
         // write more to the socket until error or end-of-request...
     } while (again);
 
--- a/netwerk/protocol/http/nsHttpConnectionMgr.cpp
+++ b/netwerk/protocol/http/nsHttpConnectionMgr.cpp
@@ -292,17 +292,18 @@ nsHttpConnectionMgr::RescheduleTransacti
 }
 
 nsresult
 nsHttpConnectionMgr::CancelTransaction(nsHttpTransaction *trans, nsresult reason)
 {
     LOG(("nsHttpConnectionMgr::CancelTransaction [trans=%x reason=%x]\n", trans, reason));
 
     NS_ADDREF(trans);
-    nsresult rv = PostEvent(&nsHttpConnectionMgr::OnMsgCancelTransaction, reason, trans);
+    nsresult rv = PostEvent(&nsHttpConnectionMgr::OnMsgCancelTransaction,
+                            static_cast<PRInt32>(reason), trans);
     if (NS_FAILED(rv))
         NS_RELEASE(trans);
     return rv;
 }
 
 nsresult
 nsHttpConnectionMgr::PruneDeadConnections()
 {
@@ -1874,38 +1875,39 @@ nsHttpConnectionMgr::OnMsgReschedTransac
 }
 
 void
 nsHttpConnectionMgr::OnMsgCancelTransaction(PRInt32 reason, void *param)
 {
     NS_ABORT_IF_FALSE(PR_GetCurrentThread() == gSocketThread, "wrong thread");
     LOG(("nsHttpConnectionMgr::OnMsgCancelTransaction [trans=%p]\n", param));
 
+    nsresult closeCode = static_cast<nsresult>(reason);
     nsHttpTransaction *trans = (nsHttpTransaction *) param;
     //
     // if the transaction owns a connection and the transaction is not done,
     // then ask the connection to close the transaction.  otherwise, close the
     // transaction directly (removing it from the pending queue first).
     //
     nsAHttpConnection *conn = trans->Connection();
     if (conn && !trans->IsDone())
-        conn->CloseTransaction(trans, reason);
+        conn->CloseTransaction(trans, closeCode);
     else {
         nsConnectionEntry *ent = LookupConnectionEntry(trans->ConnectionInfo(),
                                                        nullptr, trans);
 
         if (ent) {
             PRInt32 index = ent->mPendingQ.IndexOf(trans);
             if (index >= 0) {
                 ent->mPendingQ.RemoveElementAt(index);
                 nsHttpTransaction *temp = trans;
                 NS_RELEASE(temp); // b/c NS_RELEASE nulls its argument!
             }
         }
-        trans->Close(reason);
+        trans->Close(closeCode);
     }
     NS_RELEASE(trans);
 }
 
 void
 nsHttpConnectionMgr::OnMsgProcessPendingQ(PRInt32, void *param)
 {
     NS_ABORT_IF_FALSE(PR_GetCurrentThread() == gSocketThread, "wrong thread");
@@ -2689,17 +2691,17 @@ nsHttpConnectionMgr::nsHalfOpenSocket::O
     if (trans != mSocketTransport)
         return NS_OK;
 
     // if we are doing spdy coalescing and haven't recorded the ip address
     // for this entry before then make the hash key if our dns lookup
     // just completed. We can't do coalescing if using a proxy because the
     // ip addresses are not available to the client.
 
-    if (status == nsISocketTransport::STATUS_CONNECTED_TO &&
+    if (status == NS_NET_STATUS_CONNECTED_TO &&
         gHttpHandler->IsSpdyEnabled() &&
         gHttpHandler->CoalesceSpdy() &&
         mEnt && mEnt->mConnInfo && mEnt->mConnInfo->UsingSSL() &&
         !mEnt->mConnInfo->UsingHttpProxy() &&
         mEnt->mCoalescingKey.IsEmpty()) {
 
         PRNetAddr addr;
         nsresult rv = mSocketTransport->GetPeerAddr(&addr);
@@ -2720,30 +2722,30 @@ nsHttpConnectionMgr::nsHalfOpenSocket::O
                  "%s [%s]", mEnt->mConnInfo->Host(),
                  mEnt->mCoalescingKey.get()));
 
             gHttpHandler->ConnMgr()->ProcessSpdyPendingQ(mEnt);
         }
     }
 
     switch (status) {
-    case nsISocketTransport::STATUS_CONNECTING_TO:
+    case NS_NET_STATUS_CONNECTING_TO:
         // Passed DNS resolution, now trying to connect, start the backup timer
         // only prevent creating another backup transport.
         // We also check for mEnt presence to not instantiate the timer after
         // this half open socket has already been abandoned.  It may happen
         // when we get this notification right between main-thread calls to
         // nsHttpConnectionMgr::Shutdown and nsSocketTransportService::Shutdown
         // where the first abandones all half open socket instances and only
         // after that the second stops the socket thread.
         if (mEnt && !mBackupTransport && !mSynTimer)
             SetupBackupTimer();
         break;
 
-    case nsISocketTransport::STATUS_CONNECTED_TO:
+    case NS_NET_STATUS_CONNECTED_TO:
         // TCP connection's up, now transfer or SSL negotiantion starts,
         // no need for backup socket
         CancelBackupTimer();
         break;
 
     default:
         break;
     }
--- a/netwerk/protocol/http/nsHttpPipeline.cpp
+++ b/netwerk/protocol/http/nsHttpPipeline.cpp
@@ -696,18 +696,17 @@ nsHttpPipeline::WriteSegments(nsAHttpSeg
         PRUint32 len = mPushBackLen, n;
         mPushBackLen = 0;
 
         // This progress notification has previously been sent from
         // the socket transport code, but it was delivered to the
         // previous transaction on the pipeline.
         nsITransport *transport = Transport();
         if (transport)
-            OnTransportStatus(transport,
-                              nsISocketTransport::STATUS_RECEIVING_FROM,
+            OnTransportStatus(transport, NS_NET_STATUS_RECEIVING_FROM,
                               mReceivingFromProgress);
 
         // the push back buffer is never larger than NS_HTTP_SEGMENT_SIZE,
         // so we are guaranteed that the next response will eat the entire
         // push back buffer (even though it might again call PushBack).
         rv = WriteSegments(&writer, len, &n);
     }
 
--- a/netwerk/protocol/http/nsHttpTransaction.cpp
+++ b/netwerk/protocol/http/nsHttpTransaction.cpp
@@ -399,38 +399,38 @@ nsHttpTransaction::GetSecurityCallbacks(
 void
 nsHttpTransaction::OnTransportStatus(nsITransport* transport,
                                      nsresult status, PRUint64 progress)
 {
     LOG(("nsHttpTransaction::OnSocketStatus [this=%x status=%x progress=%llu]\n",
         this, status, progress));
 
     if (TimingEnabled()) {
-        if (status == nsISocketTransport::STATUS_RESOLVING) {
+        if (status == NS_NET_STATUS_RESOLVING_HOST) {
             mTimings.domainLookupStart = mozilla::TimeStamp::Now();
-        } else if (status == nsISocketTransport::STATUS_RESOLVED) {
+        } else if (status == NS_NET_STATUS_RESOLVED_HOST) {
             mTimings.domainLookupEnd = mozilla::TimeStamp::Now();
-        } else if (status == nsISocketTransport::STATUS_CONNECTING_TO) {
+        } else if (status == NS_NET_STATUS_CONNECTING_TO) {
             mTimings.connectStart = mozilla::TimeStamp::Now();
-        } else if (status == nsISocketTransport::STATUS_CONNECTED_TO) {
+        } else if (status == NS_NET_STATUS_CONNECTED_TO) {
             mTimings.connectEnd = mozilla::TimeStamp::Now();
         }
     }
 
     if (!mTransportSink)
         return;
 
     NS_ASSERTION(PR_GetCurrentThread() == gSocketThread, "wrong thread");
 
     // Need to do this before the STATUS_RECEIVING_FROM check below, to make
     // sure that the activity distributor gets told about all status events.
     if (mActivityDistributor) {
         // upon STATUS_WAITING_FOR; report request body sent
         if ((mHasRequestBody) &&
-            (status == nsISocketTransport::STATUS_WAITING_FOR))
+            (status == NS_NET_STATUS_WAITING_FOR))
             mActivityDistributor->ObserveActivity(
                 mChannel,
                 NS_HTTP_ACTIVITY_TYPE_HTTP_TRANSACTION,
                 NS_HTTP_ACTIVITY_SUBTYPE_REQUEST_BODY_SENT,
                 PR_Now(), LL_ZERO, EmptyCString());
 
         // report the status and progress
         if (!mRestartInProgressVerifier.IsDiscardingContent())
@@ -439,22 +439,22 @@ nsHttpTransaction::OnTransportStatus(nsI
                 NS_HTTP_ACTIVITY_TYPE_SOCKET_TRANSPORT,
                 static_cast<PRUint32>(status),
                 PR_Now(),
                 progress,
                 EmptyCString());
     }
 
     // nsHttpChannel synthesizes progress events in OnDataAvailable
-    if (status == nsISocketTransport::STATUS_RECEIVING_FROM)
+    if (status == NS_NET_STATUS_RECEIVING_FROM)
         return;
 
     PRUint64 progressMax;
 
-    if (status == nsISocketTransport::STATUS_SENDING_TO) {
+    if (status == NS_NET_STATUS_SENDING_TO) {
         // suppress progress when only writing request headers
         if (!mHasRequestBody)
             return;
 
         nsCOMPtr<nsISeekableStream> seekable = do_QueryInterface(mRequestStream);
         NS_ASSERTION(seekable, "Request stream isn't seekable?!?");
 
         PRInt64 prog = 0;
--- a/nsprpub/TAG-INFO
+++ b/nsprpub/TAG-INFO
@@ -1,1 +1,1 @@
-NSPR_4_9_2_BETA2
+NSPR_4_9_2_RTM
--- a/nsprpub/pr/include/prinit.h
+++ b/nsprpub/pr/include/prinit.h
@@ -26,21 +26,21 @@ PR_BEGIN_EXTERN_C
 /*
 ** NSPR's version is used to determine the likelihood that the version you
 ** used to build your component is anywhere close to being compatible with
 ** what is in the underlying library.
 **
 ** The format of the version string is
 **     "<major version>.<minor version>[.<patch level>] [<Beta>]"
 */
-#define PR_VERSION  "4.9.2 Beta"
+#define PR_VERSION  "4.9.2"
 #define PR_VMAJOR   4
 #define PR_VMINOR   9
 #define PR_VPATCH   2
-#define PR_BETA     PR_TRUE
+#define PR_BETA     PR_FALSE
 
 /*
 ** PRVersionCheck
 **
 ** The basic signature of the function that is called to provide version
 ** checking. The result will be a boolean that indicates the likelihood
 ** that the underling library will perform as the caller expects.
 **
--- a/nsprpub/pr/src/pthreads/ptthread.c
+++ b/nsprpub/pr/src/pthreads/ptthread.c
@@ -1638,41 +1638,46 @@ PR_IMPLEMENT(PRStatus) PR_SetCurrentThre
     memcpy(thread->name, name, nameLen + 1);
 
 #if defined(OPENBSD) || defined(FREEBSD)
     result = pthread_set_name_np(thread->id, name);
 #else /* not BSD */
     /*
      * On OSX, pthread_setname_np is only available in 10.6 or later, so test
      * for it at runtime.  It also may not be available on all linux distros.
-     * The name length limit is 16 bytes.
      */
 #if defined(DARWIN)
     int (*dynamic_pthread_setname_np)(const char*);
 #else
     int (*dynamic_pthread_setname_np)(pthread_t, const char*);
 #endif
 
     *(void**)(&dynamic_pthread_setname_np) =
         dlsym(RTLD_DEFAULT, "pthread_setname_np");
     if (!dynamic_pthread_setname_np)
         return PR_SUCCESS;
 
+    /*
+     * The 15-character name length limit is an experimentally determined
+     * length of a null-terminated string that most linux distros and OS X
+     * accept as an argument to pthread_setname_np.  Otherwise the E2BIG
+     * error is returned by the function.
+     */
 #define SETNAME_LENGTH_CONSTRAINT 15
 #define SETNAME_FRAGMENT1_LENGTH (SETNAME_LENGTH_CONSTRAINT >> 1)
 #define SETNAME_FRAGMENT2_LENGTH \
     (SETNAME_LENGTH_CONSTRAINT - SETNAME_FRAGMENT1_LENGTH - 1)
     char name_dup[SETNAME_LENGTH_CONSTRAINT + 1];
     if (nameLen > SETNAME_LENGTH_CONSTRAINT) {
         memcpy(name_dup, name, SETNAME_FRAGMENT1_LENGTH);
         name_dup[SETNAME_FRAGMENT1_LENGTH] = '~';
+        /* Note that this also copies the null terminator. */
         memcpy(name_dup + SETNAME_FRAGMENT1_LENGTH + 1,
                name + nameLen - SETNAME_FRAGMENT2_LENGTH,
-               SETNAME_FRAGMENT2_LENGTH);
-        name_dup[SETNAME_LENGTH_CONSTRAINT] = '\0';
+               SETNAME_FRAGMENT2_LENGTH + 1);
         name = name_dup;
     }
 
 #if defined(DARWIN)
     result = dynamic_pthread_setname_np(name);
 #else
     result = dynamic_pthread_setname_np(thread->id, name);
 #endif
--- a/testing/mochitest/dynamic/getMyDirectory.sjs
+++ b/testing/mochitest/dynamic/getMyDirectory.sjs
@@ -1,14 +1,14 @@
 function handleRequest(request, response)
 {
   var file;
   getObjectState("SERVER_ROOT", function(serverRoot)
   {
-    var ref = request.getHeader("Referer");
+    var ref = request.getHeader("Referer").split("?")[0];
     // 8 is "https://".length which is the longest string before the host.
     var pathStart = ref.indexOf("/", 8) + 1;
     var pathEnd = ref.lastIndexOf("/") + 1;
     file = serverRoot.getFile(ref.substring(pathStart, pathEnd) + "x");
   });
 
   response.setHeader("Content-Type", "text/plain", false);
   response.write(file.path.substr(0, file.path.length-1));
--- a/testing/mozbase/README
+++ b/testing/mozbase/README
@@ -1,9 +1,27 @@
-This is the git repo for the Mozilla mozbase suite of python utilities.
+This is the git repository for the Mozilla mozbase suite of python utilities.
+
+MozBase is composed of several python packages. These packages work
+together to form the basis of a test harness.
+
+* Firefox is launched via [mozrunner](https://github.com/mozilla/mozbase/tree/master/mozrunner)
+** which sets up a profile with preferences and extensions using
+   [mozprofile ](https://github.com/mozilla/mozbase/tree/master/mozprofile)
+** and runs the application under test using [mozprocess](https://github.com/mozilla/mozbase/tree/master/mozprocess)
+* [mozInstall](https://github.com/mozilla/mozbase/tree/master/mozinstall) is used to install the test application
+* A test harness may direct Firefox to load web pages. These may be
+  served using [mozhttpd](https://github.com/mozilla/mozbase/tree/master/mozhttpd) for testing
+* The machine environment is introspected by [mozinfo](https://github.com/mozilla/mozbase/tree/master/mozinfo)
+* A test manifest may be read to determine the tests to be run. These
+  manifests are processed by [ManifestDestiny](https://github.com/mozilla/mozbase/tree/master/manifestdestiny)
+* For mozbile testing, the test runner communicates to the test agent
+  using [mozdevice](https://github.com/mozilla/mozbase/tree/master/mozdevice)
+  (Note that the canonical location of mozdevice is
+  mozilla-central: http://mxr.mozilla.org/mozilla-central/source/build/mobile/)
 
 Learn more about mozbase here:
 https://wiki.mozilla.org/Auto-tools/Projects/MozBase
 
 Bugs live at
 https://bugzilla.mozilla.org/buglist.cgi?resolution=---&component=Mozbase&product=Testing and https://bugzilla.mozilla.org/buglist.cgi?resolution=---&status_whiteboard_type=allwordssubstr&query_format=advanced&status_whiteboard=mozbase
 
 To file a bug, go to
--- a/testing/mozbase/mozprocess/mozprocess/processhandler.py
+++ b/testing/mozbase/mozprocess/mozprocess/processhandler.py
@@ -557,16 +557,17 @@ falling back to not using job objects fo
         will be logged.
         """
         self.cmd = cmd
         self.args = args
         self.cwd = cwd
         self.didTimeout = False
         self._ignore_children = ignore_children
         self.keywordargs = kwargs
+        self.outThread = None
 
         if env is None:
             env = os.environ.copy()
         self.env = env
 
         # handlers
         self.processOutputLineHandlers = list(processOutputLine)
         self.onTimeoutHandlers = list(onTimeout)
@@ -642,55 +643,79 @@ falling back to not using job objects fo
         for handler in self.onTimeoutHandlers:
             handler()
 
     def onFinish(self):
         """Called when a process finishes without a timeout."""
         for handler in self.onFinishHandlers:
             handler()
 
-    def waitForFinish(self, timeout=None, outputTimeout=None):
+    def processOutput(self, timeout=None, outputTimeout=None):
         """
         Handle process output until the process terminates or times out.
 
         If timeout is not None, the process will be allowed to continue for
         that number of seconds before being killed.
 
         If outputTimeout is not None, the process will be allowed to continue
         for that number of seconds without producing any output before
         being killed.
         """
-
-        if not hasattr(self, 'proc'):
-            self.run()
-
-        self.didTimeout = False
-        logsource = self.proc.stdout
+        def _processOutput():
+            if not hasattr(self, 'proc'):
+                self.run()
 
-        lineReadTimeout = None
-        if timeout:
-            lineReadTimeout = timeout - (datetime.now() - self.startTime).seconds
-        elif outputTimeout:
-            lineReadTimeout = outputTimeout
+            self.didTimeout = False
+            logsource = self.proc.stdout
 
-        (line, self.didTimeout) = self.readWithTimeout(logsource, lineReadTimeout)
-        while line != "" and not self.didTimeout:
-            self.processOutputLine(line.rstrip())
+            lineReadTimeout = None
             if timeout:
                 lineReadTimeout = timeout - (datetime.now() - self.startTime).seconds
+            elif outputTimeout:
+                lineReadTimeout = outputTimeout
+
             (line, self.didTimeout) = self.readWithTimeout(logsource, lineReadTimeout)
+            while line != "" and not self.didTimeout:
+                self.processOutputLine(line.rstrip())
+                if timeout:
+                    lineReadTimeout = timeout - (datetime.now() - self.startTime).seconds
+                (line, self.didTimeout) = self.readWithTimeout(logsource, lineReadTimeout)
+
+            if self.didTimeout:
+                self.proc.kill()
+                self.onTimeout()
+            else:
+                self.onFinish()
+        
+        if not self.outThread:
+            self.outThread = threading.Thread(target=_processOutput)
+            self.outThread.daemon = True
+            self.outThread.start()
 
-        if self.didTimeout:
-            self.proc.kill()
-            self.onTimeout()
-        else:
-            self.onFinish()
+
+    def waitForFinish(self, timeout=None):
+        """
+        Waits until all output has been read and the process is 
+        terminated.
 
-        status = self.proc.wait()
-        return status
+        If timeout is not None, will return after timeout seconds.
+        This timeout is only for waitForFinish and doesn't affect
+        the didTimeout or onTimeout properties.
+        """
+        if self.outThread:
+            # Thread.join() blocks the main thread until outThread is finished
+            # wake up once a second in case a keyboard interrupt is sent
+            count = 0
+            while self.outThread.isAlive():
+                self.outThread.join(timeout=1)
+                count += 1
+                if timeout and count > timeout:
+                    return
+
+        return self.proc.wait()
 
 
     ### Private methods from here on down. Thar be dragons.
 
     if mozinfo.isWin:
         # Windows Specific private functions are defined in this block
         PeekNamedPipe = ctypes.windll.kernel32.PeekNamedPipe
         GetLastError = ctypes.windll.kernel32.GetLastError
@@ -757,17 +782,16 @@ class LogOutput(object):
             self.file = file(self.filename, 'a')
         self.file.write(line + '\n')
         self.file.flush()
 
     def __del__(self):
         if self.file is not None:
             self.file.close()
 
-
 ### front end class with the default handlers
 
 class ProcessHandler(ProcessHandlerMixin):
 
     def __init__(self, cmd, logfile=None, storeOutput=True, **kwargs):
         """
         If storeOutput=True, the output produced by the process will be saved
         as self.output.
--- a/testing/mozbase/mozprocess/tests/mozprocess1.py
+++ b/testing/mozbase/mozprocess/tests/mozprocess1.py
@@ -41,30 +41,30 @@ def check_for_process(processName):
         output -- if process exists, stdout of the process, '' otherwise
     """
     output = ''
     if sys.platform == "win32":
         # On windows we use tasklist
         p1 = subprocess.Popen(["tasklist"], stdout=subprocess.PIPE)
         output = p1.communicate()[0]
         detected = False
-        for line in output:
+        for line in output.splitlines():
             if processName in line:
                 detected = True
                 break
     else:
-        p1 = subprocess.Popen(["ps", "-A"], stdout=subprocess.PIPE)
+        p1 = subprocess.Popen(["ps", "-ef"], stdout=subprocess.PIPE)
         p2 = subprocess.Popen(["grep", processName], stdin=p1.stdout, stdout=subprocess.PIPE)
         p1.stdout.close()
         output = p2.communicate()[0]
         detected = False
-        for line in output:
+        for line in output.splitlines():
             if "grep %s" % processName in line:
                 continue
-            elif processName in line:
+            elif processName in line and not 'defunct' in line: 
                 detected = True
                 break
 
     return detected, output
 
 
 class ProcTest1(unittest.TestCase):
 
@@ -76,47 +76,50 @@ class ProcTest1(unittest.TestCase):
         unittest.TestCase.__init__(self, *args, **kwargs)
 
     def test_process_normal_finish(self):
         """Process is started, runs to completion while we wait for it"""
 
         p = processhandler.ProcessHandler([self.proclaunch, "process_normal_finish.ini"],
                                           cwd=here)
         p.run()
+        p.processOutput()
         p.waitForFinish()
 
         detected, output = check_for_process(self.proclaunch)
         self.determine_status(detected,
                               output,
                               p.proc.returncode,
                               p.didTimeout)
 
     def test_process_waittimeout(self):
         """ Process is started, runs but we time out waiting on it
             to complete
         """
         p = processhandler.ProcessHandler([self.proclaunch, "process_waittimeout.ini"],
                                           cwd=here)
         p.run()
-        p.waitForFinish(timeout=10)
+        p.processOutput(timeout=10) 
+        p.waitForFinish()
 
         detected, output = check_for_process(self.proclaunch)
         self.determine_status(detected,
                               output,
                               p.proc.returncode,
                               p.didTimeout,
                               False,
                               ['returncode', 'didtimeout'])
 
     def test_process_kill(self):
         """ Process is started, we kill it
         """
         p = processhandler.ProcessHandler([self.proclaunch, "process_normal_finish.ini"],
                                           cwd=here)
         p.run()
+        p.processOutput()
         p.kill()
 
         detected, output = check_for_process(self.proclaunch)
         self.determine_status(detected,
                               output,
                               p.proc.returncode,
                               p.didTimeout)
 
@@ -134,24 +137,24 @@ class ProcTest1(unittest.TestCase):
             output -- string of data from detected process, can be ''
             returncode -- return code from process, defaults to 0
             didtimeout -- True if process timed out, defaults to False
             isalive -- Use True to indicate we pass if the process exists; however, by default
                        the test will pass if the process does not exist (isalive == False)
             expectedfail -- Defaults to [], used to indicate a list of fields that are expected to fail
         """
         if 'returncode' in expectedfail:
-            self.assertTrue(returncode, "Detected an expected non-zero return code")
-        else:
+            self.assertTrue(returncode, "Detected an unexpected return code of: %s" % returncode)
+        elif not isalive:
             self.assertTrue(returncode == 0, "Detected non-zero return code of: %d" % returncode)
 
         if 'didtimeout' in expectedfail:
-            self.assertTrue(didtimeout, "Process timed out as expected")
+            self.assertTrue(didtimeout, "Detected that process didn't time out")
         else:
             self.assertTrue(not didtimeout, "Detected that process timed out")
 
-        if detected:
-            self.assertTrue(isalive, "Detected process is still running, process output: %s" % output)
+        if isalive:
+            self.assertTrue(detected, "Detected process is not running, process output: %s" % output)
         else:
-            self.assertTrue(not isalive, "Process ended")
+            self.assertTrue(not detected, "Detected process is still running, process output: %s" % output)
 
 if __name__ == '__main__':
     unittest.main()
--- a/testing/mozbase/mozprocess/tests/mozprocess2.py
+++ b/testing/mozbase/mozprocess/tests/mozprocess2.py
@@ -46,75 +46,97 @@ def check_for_process(processName):
         output -- if process exists, stdout of the process, '' otherwise
     """
     output = ''
     if sys.platform == "win32":
         # On windows we use tasklist
         p1 = subprocess.Popen(["tasklist"], stdout=subprocess.PIPE)
         output = p1.communicate()[0]
         detected = False
-        for line in output:
+        for line in output.splitlines():
             if processName in line:
                 detected = True
                 break
     else:
-        p1 = subprocess.Popen(["ps", "-A"], stdout=subprocess.PIPE)
+        p1 = subprocess.Popen(["ps", "-ef"], stdout=subprocess.PIPE)
         p2 = subprocess.Popen(["grep", processName], stdin=p1.stdout, stdout=subprocess.PIPE)
         p1.stdout.close()
         output = p2.communicate()[0]
         detected = False
-        for line in output:
+        for line in output.splitlines():
             if "grep %s" % processName in line:
                 continue
-            elif processName in line:
+            elif processName in line and not 'defunct' in line:
                 detected = True
                 break
 
     return detected, output
 
 class ProcTest2(unittest.TestCase):
 
     def __init__(self, *args, **kwargs):
 
         # Ideally, I'd use setUpClass but that only exists in 2.7.
         # So, we'll do this make step now.
         self.proclaunch = make_proclaunch(here)
         unittest.TestCase.__init__(self, *args, **kwargs)
 
-    def test_process_waittimeout(self):
+    def test_process_waitnotimeout(self):
         """ Process is started, runs to completion before our wait times out
         """
         p = processhandler.ProcessHandler([self.proclaunch,
                                           "process_waittimeout_10s.ini"],
                                           cwd=here)
         p.run()
-        p.waitForFinish(timeout=30)
+        p.processOutput(timeout=30)
+        p.waitForFinish()
 
         detected, output = check_for_process(self.proclaunch)
         self.determine_status(detected,
                               output,
                               p.proc.returncode,
                               p.didTimeout)
 
-    def test_process_waitnotimeout(self):
+    def test_process_wait(self):
         """ Process is started runs to completion while we wait indefinitely
         """
 
         p = processhandler.ProcessHandler([self.proclaunch,
                                           "process_waittimeout_10s.ini"],
                                           cwd=here)
         p.run()
         p.waitForFinish()
 
         detected, output = check_for_process(self.proclaunch)
         self.determine_status(detected,
                               output,
                               p.proc.returncode,
                               p.didTimeout)
 
+    def test_process_waittimeout(self):
+        """
+        Process is started, then waitForFinish is called and times out.
+        Process is still running and didn't timeout
+        """
+        p = processhandler.ProcessHandler([self.proclaunch,
+                                          "process_waittimeout_10s.ini"],
+                                          cwd=here)
+
+        p.run()
+        p.processOutput()
+        p.waitForFinish(timeout=5)
+
+        detected, output = check_for_process(self.proclaunch)
+        self.determine_status(detected,
+                              output,
+                              p.proc.returncode,
+                              p.didTimeout,
+                              True,
+                              [])
+
     def determine_status(self,
                          detected=False,
                          output = '',
                          returncode = 0,
                          didtimeout = False,
                          isalive=False,
                          expectedfail=[]):
         """
@@ -124,24 +146,24 @@ class ProcTest2(unittest.TestCase):
             output -- string of data from detected process, can be ''
             returncode -- return code from process, defaults to 0
             didtimeout -- True if process timed out, defaults to False
             isalive -- Use True to indicate we pass if the process exists; however, by default
                        the test will pass if the process does not exist (isalive == False)
             expectedfail -- Defaults to [], used to indicate a list of fields that are expected to fail
         """
         if 'returncode' in expectedfail:
-            self.assertTrue(returncode, "Detected an expected non-zero return code")
-        else:
+            self.assertTrue(returncode, "Detected an unexpected return code of: %s" % returncode)
+        elif not isalive:
             self.assertTrue(returncode == 0, "Detected non-zero return code of: %d" % returncode)
 
         if 'didtimeout' in expectedfail:
-            self.assertTrue(didtimeout, "Process timed out as expected")
+            self.assertTrue(didtimeout, "Detected that process didn't time out")
         else:
             self.assertTrue(not didtimeout, "Detected that process timed out")
 
-        if detected:
-            self.assertTrue(isalive, "Detected process is still running, process output: %s" % output)
+        if isalive:
+            self.assertTrue(detected, "Detected process is not running, process output: %s" % output)
         else:
-            self.assertTrue(not isalive, "Process ended")
+            self.assertTrue(not detected, "Detected process is still running, process output: %s" % output)
 
 if __name__ == '__main__':
     unittest.main()
--- a/testing/mozbase/mozprofile/mozprofile/addons.py
+++ b/testing/mozbase/mozprofile/mozprofile/addons.py
@@ -167,18 +167,21 @@ class AddonManager(object):
             os.close(fd)
             tmpfile = path
         else:
             tmpfile = None
 
         # if the addon is a directory, install all addons in it
         addons = [path]
         if not path.endswith('.xpi') and not os.path.exists(os.path.join(path, 'install.rdf')):
-            assert os.path.isdir(path), "Addon '%s' cannot be installed" % path
-            addons = [os.path.join(path, x) for x in os.listdir(path)]
+            # If the path doesn't exist, then we don't really care, just return
+            if not os.path.isdir(path):
+                return
+            addons = [os.path.join(path, x) for x in os.listdir(path) if
+                    os.path.isdir(os.path.join(path, x))]
 
         # install each addon
         for addon in addons:
             tmpdir = None
             xpifile = None
             if addon.endswith('.xpi'):
                 tmpdir = tempfile.mkdtemp(suffix = '.' + os.path.split(addon)[-1])
                 compressed_file = zipfile.ZipFile(addon, 'r')
@@ -196,17 +199,17 @@ class AddonManager(object):
                 addon = tmpdir
 
             # determine the addon id
             addon_details = AddonManager.addon_details(addon)
             addon_id = addon_details.get('id')
             assert addon_id, 'The addon id could not be found: %s' % addon
 
             # copy the addon to the profile
-            extensions_path = os.path.join(self.profile, 'extensions')
+            extensions_path = os.path.join(self.profile, 'extensions', 'staged')
             addon_path = os.path.join(extensions_path, addon_id)
             if not unpack and not addon_details['unpack'] and xpifile:
                 if not os.path.exists(extensions_path):
                     os.makedirs(extensions_path)
                 shutil.copy(xpifile, addon_path + '.xpi')
             else:
                 dir_util.copy_tree(addon, addon_path, preserve_symlinks=1)
                 self._addon_dirs.append(addon_path)
--- a/testing/mozbase/mozprofile/mozprofile/permissions.py
+++ b/testing/mozbase/mozprofile/mozprofile/permissions.py
@@ -123,19 +123,17 @@ class ServerLocations(object):
     def __len__(self):
         return len(self._locations)
 
     def add(self, location, suppress_callback=False):
         if "primary" in location.options:
             if self.hasPrimary:
                 raise MultiplePrimaryLocationsError()
             self.hasPrimary = True
-        for loc in self._locations:
-            if loc.isEqual(location):
-                raise DuplicateLocationError(location.url())
+
         self._locations.append(location)
         if self.add_callback and not suppress_callback:
             self.add_callback([location])
 
     def add_host(self, host, port='80', scheme='http', options='privileged'):
         if isinstance(options, basestring):
             options = options.split(',')
         self.add(Location(scheme, host, port, options))
@@ -145,17 +143,17 @@ class ServerLocations(object):
         Reads the file (in the format of server-locations.txt) and add all
         valid locations to the self._locations array.
 
         If check_for_primary is True, a MissingPrimaryLocationError
         exception is raised if no primary is found.
 
         This format:
         http://mxr.mozilla.org/mozilla-central/source/build/pgo/server-locations.txt
-        The only exception is that the port, if not defined, defaults to 80.
+        The only exception is that the port, if not defined, defaults to 80 or 443.
 
         FIXME: Shouldn't this default to the protocol-appropriate port?  Is
         there any reason to have defaults at all?
         """
 
         locationFile = codecs.open(filename, "r", "UTF-8")
         lineno = 0
         new_locations = []
@@ -180,17 +178,21 @@ class ServerLocations(object):
             if '://' not in server:
                 server = 'http://' + server
             scheme, netloc, path, query, fragment = urlparse.urlsplit(server)
             # get the host and port
             try:
                 host, port = netloc.rsplit(':', 1)
             except ValueError:
                 host = netloc
-                port = '80'
+                default_ports = {'http': '80',
+                                 'https': '443',
+                                 'ws': '443',
+                                 'wss': '443'}
+                port = default_ports.get(scheme, '80')
 
             try:
                 location = Location(scheme, host, port, options)
                 self.add(location, suppress_callback=True)
             except LocationError, e:
                 raise LocationsSyntaxError(lineno, e)
 
             new_locations.append(location)
@@ -263,18 +265,18 @@ class Permissions(object):
         """
 
         # Grant God-power to all the privileged servers on which tests run.
         prefs = []
         privileged = [i for i in self._locations if "privileged" in i.options]
         for (i, l) in itertools.izip(itertools.count(1), privileged):
             prefs.append(("capability.principal.codebase.p%s.granted" % i, "UniversalXPConnect"))
 
-            # TODO: do we need the port?
-            prefs.append(("capability.principal.codebase.p%s.id" % i, l.scheme + "://" + l.host))
+            prefs.append(("capability.principal.codebase.p%s.id" % i, "%s://%s:%s" %
+                        (l.scheme, l.host, l.port)))
             prefs.append(("capability.principal.codebase.p%s.subjectName" % i, ""))
 
         if proxy:
             user_prefs = self.pac_prefs()
         else:
             user_prefs = []
 
         return prefs, user_prefs
@@ -284,37 +286,38 @@ class Permissions(object):
         return preferences for Proxy Auto Config. originally taken from
         http://mxr.mozilla.org/mozilla-central/source/build/automation.py.in
         """
 
         prefs = []
 
         # We need to proxy every server but the primary one.
         origins = ["'%s'" % l.url()
-                   for l in self._locations
-                   if "primary" not in l.options]
+                   for l in self._locations]
+
         origins = ", ".join(origins)
 
-        # TODO: this is not a reliable way to determine the Proxy host
         for l in self._locations:
             if "primary" in l.options:
                 webServer = l.host
-                httpPort  = l.port
-                sslPort   = 443
+                port = l.port
 
         # TODO: this should live in a template!
+        # TODO: So changing the 5th line of the regex below from (\\\\\\\\d+)
+        # to (\\\\d+) makes this code work. Not sure why there would be this
+        # difference between automation.py.in and this file.
         pacURL = """data:text/plain,
 function FindProxyForURL(url, host)
 {
   var origins = [%(origins)s];
   var regex = new RegExp('^([a-z][-a-z0-9+.]*)' +
                          '://' +
                          '(?:[^/@]*@)?' +
                          '(.*?)' +
-                         '(?::(\\\\\\\\d+))?/');
+                         '(?::(\\\\d+))?/');
   var matches = regex.exec(url);
   if (!matches)
     return 'DIRECT';
   var isHttp = matches[1] == 'http';
   var isHttps = matches[1] == 'https';
   var isWebSocket = matches[1] == 'ws';
   var isWebSocketSSL = matches[1] == 'wss';
   if (!matches[3])
@@ -325,25 +328,22 @@ function FindProxyForURL(url, host)
   if (isWebSocket)
     matches[1] = 'http';
   if (isWebSocketSSL)
     matches[1] = 'https';
 
   var origin = matches[1] + '://' + matches[2] + ':' + matches[3];
   if (origins.indexOf(origin) < 0)
     return 'DIRECT';
-  if (isHttp)
-    return 'PROXY %(remote)s:%(httpport)s';
-  if (isHttps || isWebSocket || isWebSocketSSL)
-    return 'PROXY %(remote)s:%(sslport)s';
+  if (isHttp || isHttps || isWebSocket || isWebSocketSSL)
+    return 'PROXY %(remote)s:%(port)s';
   return 'DIRECT';
 }""" % { "origins": origins,
          "remote":  webServer,
-         "httpport":httpPort,
-         "sslport": sslPort }
+         "port": port }
         pacURL = "".join(pacURL.splitlines())
 
         prefs.append(("network.proxy.type", 2))
         prefs.append(("network.proxy.autoconfig_url", pacURL))
 
         return prefs
 
     def clean_db(self):
--- a/testing/mozbase/mozprofile/mozprofile/profile.py
+++ b/testing/mozbase/mozprofile/mozprofile/profile.py
@@ -22,17 +22,17 @@ class Profile(object):
     sets preferences and handles cleanup."""
 
     def __init__(self,
                  profile=None, # Path to the profile
                  addons=None,  # String of one or list of addons to install
                  addon_manifests=None,  # Manifest for addons, see http://ahal.ca/blog/2011/bulk-installing-fx-addons/
                  preferences=None, # Dictionary or class of preferences
                  locations=None, # locations to proxy
-                 proxy=False, # setup a proxy
+                 proxy=None, # setup a proxy - dict of server-loc,server-port,ssl-port
                  restore=True # If true remove all installed addons preferences when cleaning up
                  ):
 
         # if true, remove installed addons/prefs afterwards
         self.restore = restore
 
         # prefs files written to
         self.written_prefs = set()
--- a/testing/mozbase/mozprofile/tests/permissions.py
+++ b/testing/mozbase/mozprofile/tests/permissions.py
@@ -76,38 +76,39 @@ http://127.0.0.1:8888           privileg
         cur.execute("select * from sqlite_master where type='table'")
         entries = cur.fetchall()
         self.assertEqual(len(entries), 0)
         
     def test_nw_prefs(self):
         perms = Permissions(self.profile_dir, self.locations_file.name)
 
         prefs, user_prefs = perms.network_prefs(False)
+
         self.assertEqual(len(user_prefs), 0)
         self.assertEqual(len(prefs), 6)
 
         self.assertEqual(prefs[0], ('capability.principal.codebase.p1.granted',
                                     'UniversalXPConnect'))
         self.assertEqual(prefs[1], ('capability.principal.codebase.p1.id',
-                                    'http://mochi.test'))
+                                    'http://mochi.test:8888'))
         self.assertEqual(prefs[2], ('capability.principal.codebase.p1.subjectName', ''))
 
         self.assertEqual(prefs[3], ('capability.principal.codebase.p2.granted',
                                     'UniversalXPConnect'))
         self.assertEqual(prefs[4], ('capability.principal.codebase.p2.id',
-                                    'http://127.0.0.1'))
+                                    'http://127.0.0.1:8888'))
         self.assertEqual(prefs[5], ('capability.principal.codebase.p2.subjectName', ''))
 
 
         prefs, user_prefs = perms.network_prefs(True)
         self.assertEqual(len(user_prefs), 2)
         self.assertEqual(user_prefs[0], ('network.proxy.type', 2))
         self.assertEqual(user_prefs[1][0], 'network.proxy.autoconfig_url')
 
-        origins_decl = "var origins = ['http://127.0.0.1:80', 'http://127.0.0.1:8888'];"
+        origins_decl = "var origins = ['http://mochi.test:8888', 'http://127.0.0.1:80', 'http://127.0.0.1:8888'];"
         self.assertTrue(origins_decl in user_prefs[1][1])
 
-        proxy_check = "if (isHttp)    return 'PROXY mochi.test:8888';  if (isHttps || isWebSocket || isWebSocketSSL)    return 'PROXY mochi.test:443';"
+        proxy_check = "if (isHttp || isHttps || isWebSocket || isWebSocketSSL)    return 'PROXY mochi.test:8888';"
         self.assertTrue(proxy_check in user_prefs[1][1])
 
 
 if __name__ == '__main__':
     unittest.main()
--- a/testing/mozbase/mozprofile/tests/server_locations.py
+++ b/testing/mozbase/mozprofile/tests/server_locations.py
@@ -77,18 +77,21 @@ http://example.org:80           privileg
         self.assertEqual(len(locations), 7)
         self.compare_location(i.next(), 'http', 'mozilla.org', '80',
                               ['privileged'])
 
         # test some errors
         self.assertRaises(MultiplePrimaryLocationsError, locations.add_host,
                           'primary.test', options='primary')
 
-        self.assertRaises(DuplicateLocationError, locations.add_host,
-                          '127.0.0.1')
+        # We no longer throw these DuplicateLocation Error
+        try:
+            locations.add_host('127.0.0.1')
+        except DuplicateLocationError:
+            self.assertTrue(False, "Should no longer throw DuplicateLocationError")
 
         self.assertRaises(BadPortLocationError, locations.add_host, '127.0.0.1',
                           port='abc')
 
         # test some errors in locations file
         f = self.create_temp_file(self.locations_no_primary)
 
         exc = None
--- a/testing/mozbase/mozrunner/mozrunner/runner.py
+++ b/testing/mozbase/mozrunner/mozrunner/runner.py
@@ -9,17 +9,16 @@
 import mozinfo
 import optparse
 import os
 import platform
 import subprocess
 import sys
 import ConfigParser
 
-from threading import Thread
 from utils import get_metadata_from_egg
 from utils import findInPath
 from mozprofile import *
 from mozprocess.processhandler import ProcessHandler
 
 if mozinfo.isMac:
     from plistlib import readPlist
 
@@ -146,57 +145,68 @@ class Runner(object):
                 except:
                     repository['%s_%s' % (file, id)] = None
 
         return repository
 
     def is_running(self):
         return self.process_handler is not None
 
-    def start(self, debug_args=None, interactive=False):
+    def start(self, debug_args=None, interactive=False, timeout=None, outputTimeout=None):
         """
         Run self.command in the proper environment.
         - debug_args: arguments for the debugger
+        - interactive: uses subprocess.Popen directly
+        - read_output: sends program output to stdout [default=False]
+        - timeout: see process_handler.waitForFinish
+        - outputTimeout: see process_handler.waitForFinish
         """
 
         # ensure you are stopped
         self.stop()
 
         # ensure the profile exists
         if not self.profile.exists():
             self.profile.reset()
             assert self.profile.exists(), "%s : failure to reset profile" % self.__class__.__name__
 
         cmd = self._wrap_command(self.command+self.cmdargs)
 
         # attach a debugger, if specified
         if debug_args:
             cmd = list(debug_args) + cmd
 
-        #
         if interactive:
             self.process_handler = subprocess.Popen(cmd, env=self.env)
             # TODO: other arguments
         else:
             # this run uses the managed processhandler
             self.process_handler = self.process_class(cmd, env=self.env, **self.kp_kwargs)
             self.process_handler.run()
 
-            # Spin a thread to handle reading the output
-            self.outThread = OutputThread(self.process_handler)
-            self.outThread.start()
+            # start processing output from the process
+            self.process_handler.processOutput(timeout, outputTimeout)
 
-    def wait(self, timeout=None, outputTimeout=None):
-        """Wait for the app to exit."""
+    def wait(self, timeout=None):
+        """
+        Wait for the app to exit.
+
+        If timeout is not None, will return after timeout seconds.
+        Use is_running() to determine whether or not a timeout occured.
+        Timeout is ignored if interactive was set to True.
+        """
         if self.process_handler is None:
             return
         if isinstance(self.process_handler, subprocess.Popen):
             self.process_handler.wait()
         else:
-            self.process_handler.waitForFinish(timeout=timeout, outputTimeout=outputTimeout)
+            self.process_handler.waitForFinish(timeout)
+            if not getattr(self.process_handler.proc, 'returncode', False):
+                # waitForFinish timed out
+                return
         self.process_handler = None
 
     def stop(self):
         """Kill the app"""
         if self.process_handler is None:
             return
         self.process_handler.kill()
         self.process_handler = None
@@ -242,23 +252,16 @@ class FirefoxRunner(Runner):
 
 class ThunderbirdRunner(Runner):
     """Specialized Runner subclass for running Thunderbird"""
     profile_class = ThunderbirdProfile
 
 runners = {'firefox': FirefoxRunner,
            'thunderbird': ThunderbirdRunner}
 
-class OutputThread(Thread):
-    def __init__(self, prochandler):
-        Thread.__init__(self)
-        self.ph = prochandler
-    def run(self):
-        self.ph.waitForFinish()
-
 class CLI(MozProfileCLI):
     """Command line interface."""
 
     module = "mozrunner"
 
     def __init__(self, args=sys.argv[1:]):
         """
         Setup command line parser and parse arguments
--- a/testing/mozbase/test-manifest.ini
+++ b/testing/mozbase/test-manifest.ini
@@ -3,12 +3,13 @@
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 # mozbase test manifest, in the format of
 # https://github.com/mozilla/mozbase/blob/master/manifestdestiny/README.txt
 
 # run with
 # https://github.com/mozilla/mozbase/blob/master/test.py
 
+[include:manifestdestiny/tests/manifest.ini]
 [include:mozprocess/tests/manifest.ini]
 [include:mozprofile/tests/manifest.ini]
 [include:mozhttpd/tests/manifest.ini]
 [include:mozdevice/tests/manifest.ini]
--- a/testing/peptest/MANIFEST.in
+++ b/testing/peptest/MANIFEST.in
@@ -1,5 +1,1 @@
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-recursive-include peptest/extension *
\ No newline at end of file
+# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.

recursive-include peptest/extension *
\ No newline at end of file
--- a/testing/peptest/peptest/extension/build.xml
+++ b/testing/peptest/peptest/extension/build.xml
@@ -1,14 +1,13 @@
 <?xml version="1.0"?>
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 
-
 <!--
 build.xml adapted from Shawn Wilsher's rtse
 (http://shawnwilsher.com/extensions/rtse/)
  -->
 
 <project name="pep" default="pepxpi">
   <tstamp>
     <format property="build.number" pattern="yyyyMMdd" offset="-1" unit="hour"/>
--- a/testing/peptest/peptest/extension/resource/mozmill/README.md
+++ b/testing/peptest/peptest/extension/resource/mozmill/README.md
@@ -1,9 +1,9 @@
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 
 These folders are pulled from:
 https://github.com/mozilla/mozmill/tree/master/mozmill/mozmill/extension/resource
 
-To update them, simply checkout the mozmill repo at https://github.com/mozautomation/mozmill, 
+To update them, simply checkout the mozmill repo at https://github.com/mozilla/mozmill, 
 then copy and paste the 'driver' and 'stdlib' folders to this location. 
--- a/testing/peptest/peptest/pepprocess.py
+++ b/testing/peptest/peptest/pepprocess.py
@@ -57,43 +57,40 @@ class PepProcess(ProcessHandler):
                 self.logger.testStart(results.currentTest)
             elif level == 'TEST-END':
                 metric = results.get_metric(results.currentTest)
                 if len(tokens) > 4:
                     threshold = float(tokens[4].rstrip())
                 else:
                     threshold = 0.0
 
-                msg = results.currentTest \
-                      + ' | fail threshold: ' + str(threshold)
+                msg = '%s | fail threshold: %s' % (results.currentTest, threshold)
                 if metric > threshold:
-                    msg += ' < metric: ' + str(metric)
+                    msg += ' < metric: %s' % metric
                     self.logger.testFail(msg)
                 else:
-                    msg += ' >= metric: ' + str(metric)
+                    msg += ' >= metric: %s' % metric
                     self.logger.testPass(msg)
 
-                self.logger.testEnd(
-                        results.currentTest +
-                        ' | finished in: ' + tokens[3].rstrip() + ' ms')
+                self.logger.testEnd('%s | finished in: %s ms' %
+                        (results.currentTest, tokens[3].rstrip()))
                 results.currentTest = None
             elif level == 'ACTION-START':
                 results.currentAction = tokens[3].rstrip()
-                self.logger.debug(level + ' | ' + results.currentAction)
+                self.logger.debug('%s | %s' % (level, results.currentAction))
             elif level == 'ACTION-END':
-                self.logger.debug(level + ' | ' + results.currentAction)
+                self.logger.debug('%s | %s' % (level, results.currentAction))
                 results.currentAction = None
             elif level in ['DEBUG', 'INFO', 'WARNING', 'ERROR']:
                 line = line[len('PEP ' + level)+1:]
                 getattr(self.logger, level.lower())(line.rstrip())
                 if level == 'ERROR':
                     results.fails[str(results.currentTest)].append(0)
             else:
                 line = line[len('PEP'):]
                 self.logger.debug(line.rstrip())
         elif tokens[0] == 'MOZ_EVENT_TRACE' and results.currentAction is not None:
             # The output is generated from EventTracer
             # Format is 'MOZ_EVENT_TRACE sample <TIMESTAMP> <VALUE>
             # <VALUE> is the unresponsive time in ms
-            self.logger.warning(
-                    results.currentTest + ' | ' + results.currentAction +
-                    ' | unresponsive time: ' + tokens[3].rstrip() + ' ms')
+            self.logger.warning('%s | %s | unresponsive time: %s ms' %
+                (results.currentTest, results.currentAction, tokens[3].rstrip()))
             results.fails[results.currentTest].append(int(tokens[3].rstrip()))
--- a/testing/peptest/peptest/runpeptests.py
+++ b/testing/peptest/peptest/runpeptests.py
@@ -44,17 +44,18 @@ class Peptest():
         # create the profile
         enable_proxy = False
         locations = ServerLocations()
         if self.options.proxyLocations:
             if not self.options.serverPath:
                 self.logger.warning('Can\'t set up proxy without server path')
             else:
                 enable_proxy = True
-                locations.read(self.options.proxyLocations, False)
+                for proxyLocation in self.options.proxyLocations:
+                    locations.read(proxyLocation, False)
                 locations.add_host(host='127.0.0.1',
                                    port=self.options.serverPort,
                                    options='primary,privileged')
 
         self.profile = self.profile_class(profile=self.options.profilePath,
                                           addons=[os.path.join(here, 'extension')],
                                           locations=locations,
                                           proxy=enable_proxy)
@@ -108,18 +109,18 @@ class Peptest():
                                         cmdargs=cmdargs,
                                         env=env,
                                         process_class=PepProcess)
 
     def start(self):
         self.logger.debug('Starting Peptest')
 
         # start firefox
-        self.runner.start()
-        self.runner.wait(outputTimeout=self.options.timeout)
+        self.runner.start(outputTimeout=self.options.timeout)
+        self.runner.wait()
         crashed = self.checkForCrashes(results.currentTest)
         self.stop()
 
         if crashed or results.has_fails():
             return 1
         return 0
 
     def runServer(self):
@@ -288,21 +289,21 @@ class PeptestOptions(OptionParser):
 
         self.add_option("-p", "--profile-path", action="store",
                         type="string", dest="profilePath",
                         default=None,
                         help="path to the profile to use. "
                              "If none specified, a temporary profile is created")
 
         self.add_option("--proxy",
-                        action="store", type="string", dest="proxyLocations",
+                        action="append", type="string", dest="proxyLocations",
                         default=None,
-                        help="path to a server-location file specifying "
-                             "domains to proxy. --server-path must also be "
-                             "specified.")
+                        help="a list of paths to server-location files specifying "
+                             "domains to proxy (set with multiple --proxy agruments). "
+                             "--server-path must also be specified.")
 
         self.add_option("--proxy-host-dirs",
                         action="store_true", dest="proxyHostDirs",
                         default=False,
                         help="proxied requests are served from directories "
                              "named by requested host. --proxy must also be "
                              "specified.")
 
--- a/toolkit/components/maintenanceservice/Makefile.in
+++ b/toolkit/components/maintenanceservice/Makefile.in
@@ -11,17 +11,16 @@ include $(DEPTH)/config/autoconf.mk
 
 CPPSRCS = \
   maintenanceservice.cpp \
   serviceinstall.cpp \
   workmonitor.cpp \
   certificatecheck.cpp \
   servicebase.cpp \
   registrycertificates.cpp \
-  prefetch.cpp \
   $(NULL)
 
 # For debugging purposes only
 #DEFINES += -DDISABLE_UPDATER_AUTHENTICODE_CHECK
 
 PROGRAM = maintenanceservice$(BIN_SUFFIX)
 DIST_PROGRAM = maintenanceservice$(BIN_SUFFIX)
 
--- a/toolkit/components/maintenanceservice/maintenanceservice.cpp
+++ b/toolkit/components/maintenanceservice/maintenanceservice.cpp
@@ -9,17 +9,16 @@
 #include <shlobj.h>
 
 #include "serviceinstall.h"
 #include "maintenanceservice.h"
 #include "servicebase.h"
 #include "workmonitor.h"
 #include "uachelper.h"
 #include "updatehelper.h"
-#include "prefetch.h"
 
 SERVICE_STATUS gSvcStatus = { 0 }; 
 SERVICE_STATUS_HANDLE gSvcStatusHandle = NULL; 
 HANDLE gWorkDoneEvent = NULL;
 HANDLE gThread = NULL;
 bool gServiceControlStopping = false;
 
 // logs are pretty small, about 20 lines, so 10 seems reasonable.
deleted file mode 100644
--- a/toolkit/components/maintenanceservice/prefetch.cpp
+++ /dev/null
@@ -1,261 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include <shlwapi.h>
-#include "servicebase.h"
-#include "updatehelper.h"
-#include "nsWindowsHelpers.h"
-#define MAX_KEY_LENGTH 255
-
-/**
- * Writes a registry DWORD with a value of 1 at BASE_SERVICE_REG_KEY
- * if the prefetch was cleared successfully.
- *
- * @return TRUE if successful.
-*/
-BOOL
-WritePrefetchClearedReg()
-{
-  HKEY baseKeyRaw;
-  LONG retCode = RegOpenKeyExW(HKEY_LOCAL_MACHINE, 
-                               BASE_SERVICE_REG_KEY, 0,
-                               KEY_WRITE | KEY_WOW64_64KEY, &baseKeyRaw);
-  if (retCode != ERROR_SUCCESS) {
-    LOG(("Could not open key for prefetch. (%d)\n", retCode));
-    return FALSE;
-  }
-  nsAutoRegKey baseKey(baseKeyRaw);
-  DWORD disabledValue = 1;
-  if (RegSetValueExW(baseKey, L"FFPrefetchDisabled", 0, REG_DWORD,
-                     reinterpret_cast<LPBYTE>(&disabledValue),
-                     sizeof(disabledValue)) != ERROR_SUCCESS) {
-    LOG(("Could not write prefetch cleared value to registry. (%d)\n",
-         GetLastError()));
-    return FALSE;
-  }
-  return TRUE;
-}
-
-/** 
-  * Update: We found that prefetch clearing was a net negative, so this
-  * function has been updated to delete the read only prefetch files.
-  * -----------------------------------------------------------------------
-  * We found that prefetch actually causes large applications like Firefox
-  * to startup slower.  This will get rid of the Windows prefetch files for
-  * applications like firefox (FIREFOX-*.pf files) and instead replace them
-  * with 0 byte files which are read only.  Windows will not use prefetch
-  * if the associated prefetch file is a 0 byte read only file.
-  * Some of the problems with prefetch relating to Windows and Firefox:
-  * - Prefetch reads in a lot before we even run (fonts, plugins, etc...)
-  * - Prefetch happens before our code runs, so it delays UI showing.
-  * - Prefetch does not use windows readahead.
-  * Previous test data on an acer i7 laptop with a 5400rpm HD showed startup
-  * time difference was 1.6s (without prefetch) vs 2.6s+ with prefetch.
-  * The "Windows Internals" book mentions that prefetch can be disabled for 
-  * the whole system only, so there is no other application specific way to
-  * disable it.
-  *
-  * @param prefetchProcessName The name of the process who's prefetch files
-  *                            should be cleared.
-  * @return TRUE if no errors occurred during the clear operation.
-*/
-BOOL
-ClearPrefetch(LPCWSTR prefetchProcessName)
-{
-  LOG(("Clearing prefetch files...\n"));
-  size_t prefetchProcessNameLength = wcslen(prefetchProcessName);
-
-  // Make sure we were passed in a safe value for the prefetch process name
-  // because it will be appended to a filepath and deleted.
-  // We check for < 2 to avoid things like "." as the path 
-  // We check for a max path of MAX_PATH - 10 because we add \\ and '.EXE-*.pf'
-  if (wcsstr(prefetchProcessName, L"..") ||
-      wcsstr(prefetchProcessName, L"\\") ||
-      wcsstr(prefetchProcessName, L"*") ||
-      wcsstr(prefetchProcessName, L"/") ||
-      prefetchProcessNameLength < 2 ||
-      prefetchProcessNameLength >= (MAX_PATH - 10)) {
-    LOG(("Prefetch path to clear is not safe\n"));
-    return FALSE;
-  }
-
-  // Quick shortcut to make sure we don't try to clear multiple times for
-  // different FIREFOX installs.
-  static WCHAR lastPrefetchProcessName[MAX_PATH - 10] = { '\0' };
-  if (!wcscmp(lastPrefetchProcessName, prefetchProcessName)) {
-    LOG(("Already processed process name\n"));
-    return FALSE;
-  }
-  wcscpy(lastPrefetchProcessName, prefetchProcessName);
-
-  // Obtain the windows prefetch directory path.
-  WCHAR prefetchPath[MAX_PATH + 1];
-  if (!GetWindowsDirectoryW(prefetchPath,
-                            sizeof(prefetchPath) / 
-                            sizeof(prefetchPath[0]))) {
-    LOG(("Could not obtain windows directory\n"));
-    return FALSE;
-  }
-  if (!PathAppendSafe(prefetchPath, L"prefetch")) {
-    LOG(("Could not obtain prefetch directory\n"));
-    return FALSE;
-  }
-
-  size_t prefetchDirLen = wcslen(prefetchPath);
-  WCHAR prefetchSearchFile[MAX_PATH + 1];
-  // We know this is safe based on the check at the start of this function
-  wsprintf(prefetchSearchFile, L"\\%s.EXE-*.pf", prefetchProcessName);
-  // Append the search file to the full path
-  wcscpy(prefetchPath + prefetchDirLen, prefetchSearchFile);
-
-  // Find the first path matching and get a find handle for future calls.
-  WIN32_FIND_DATAW findFileData;
-  HANDLE findHandle = FindFirstFileW(prefetchPath, &findFileData);
-  if (INVALID_HANDLE_VALUE == findHandle) {
-    if (GetLastError() == ERROR_FILE_NOT_FOUND) {
-      LOG(("No files matching firefox.exe prefetch path.\n"));
-      return TRUE;
-    } else {
-      LOG(("Error finding firefox.exe prefetch files. (%d)\n",
-           GetLastError()));
-      return FALSE;
-    }
-  }
-  
-  BOOL deletedAllFFPrefetch = TRUE;
-  size_t deletedCount = 0;
-  do {
-    // Reset back to the prefetch directory, we know from an above check that
-    // we aren't exceeding MAX_PATH + 1 characters with prefetchDirLen + 1.
-    // From above we know: prefetchPath[prefetchDirLen] == L'\\';
-    prefetchPath[prefetchDirLen + 1] = L'\0';
-
-    // Get the new file's prefetch path
-    LPWSTR filenameOffsetInBuffer = prefetchPath + prefetchDirLen + 1;
-    if (wcslen(findFileData.cFileName) + prefetchDirLen + 1 > MAX_PATH) {
-      LOG(("Error appending prefetch path %ls, path is too long. (%d)\n",
-           findFileData.cFileName, GetLastError()));
-      deletedAllFFPrefetch = FALSE;
-      continue;
-    }
-    if (!PathAppendSafe(filenameOffsetInBuffer, findFileData.cFileName)) {
-      LOG(("Error appending prefetch path %ls. (%d)\n", findFileData.cFileName,
-           GetLastError()));
-      deletedAllFFPrefetch = FALSE;
-      continue;
-    }
-
-    DWORD attributes = GetFileAttributesW(prefetchPath);
-    if (INVALID_FILE_ATTRIBUTES == attributes) {
-      LOG(("Could not get/set attributes on prefetch file: %ls. (%d)\n", 
-           findFileData.cFileName, GetLastError()));
-      continue;
-    }
-    
-    if (!(attributes & FILE_ATTRIBUTE_READONLY)) {
-      LOG(("Prefetch file is not read-only, don't clear: %ls.\n", 
-           findFileData.cFileName));
-      continue;
-    }
-
-    // Remove the read only attribute so a DeleteFile call will work.
-    if (!SetFileAttributesW(prefetchPath,
-                            attributes & (~FILE_ATTRIBUTE_READONLY))) {
-      LOG(("Could not set read only on prefetch file: %ls. (%d)\n", 
-           findFileData.cFileName, GetLastError()));
-      continue;
-    } 
-
-    if (!DeleteFileW(prefetchPath)) {
-      LOG(("Could not delete read only prefetch file: %ls. (%d)\n",
-            findFileData.cFileName, GetLastError()));
-    }
-
-    ++deletedCount;
-    LOG(("Prefetch file cleared successfully: %ls\n",
-         prefetchPath));
-  } while (FindNextFileW(findHandle, &findFileData));
-  LOG(("Done searching prefetch paths. (%d)\n", GetLastError()));
-
-  // Cleanup after ourselves.
-  FindClose(findHandle);
-
-  if (deletedAllFFPrefetch && deletedCount > 0) {
-    WritePrefetchClearedReg();
-  }
-
-  return deletedAllFFPrefetch;
-}
-
-/**
- * Clears all prefetch files specified in the installation dirctories
- * @return FALSE if there was an error clearing the known prefetch directories
-*/
-BOOL
-ClearKnownPrefetch()
-{
-  // The service always uses the 64-bit registry key
-  HKEY baseKeyRaw;
-  LONG retCode = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
-                               BASE_SERVICE_REG_KEY, 0,
-                               KEY_READ | KEY_WOW64_64KEY, &baseKeyRaw);
-  if (retCode != ERROR_SUCCESS) {
-    LOG(("Could not open maintenance service base key. (%d)\n", retCode));
-    return FALSE;
-  }
-  nsAutoRegKey baseKey(baseKeyRaw);
-
-  // Get the number of subkeys.
-  DWORD subkeyCount = 0;
-  retCode = RegQueryInfoKeyW(baseKey, NULL, NULL, NULL, &subkeyCount, NULL,
-                             NULL, NULL, NULL, NULL, NULL, NULL);
-  if (retCode != ERROR_SUCCESS) {
-    LOG(("Could not query info key: %d\n", retCode));
-    return FALSE;
-  }
-
-  // Enumerate the subkeys, each subkey represents an install
-  for (DWORD i = 0; i < subkeyCount; i++) { 
-    WCHAR subkeyBuffer[MAX_KEY_LENGTH];
-    DWORD subkeyBufferCount = MAX_KEY_LENGTH;  
-    retCode = RegEnumKeyExW(baseKey, i, subkeyBuffer, 
-                            &subkeyBufferCount, NULL, 
-                            NULL, NULL, NULL); 
-    if (retCode != ERROR_SUCCESS) {
-      LOG(("Could not enum installations: %d\n", retCode));
-      return FALSE;
-    }
-
-    // Open the subkey
-    HKEY subKeyRaw;
-    retCode = RegOpenKeyExW(baseKey, 
-                            subkeyBuffer, 
-                            0, 
-                            KEY_READ | KEY_WOW64_64KEY, 
-                            &subKeyRaw);
-    nsAutoRegKey subKey(subKeyRaw);
-    if (retCode != ERROR_SUCCESS) {
-      LOG(("Could not open subkey: %d\n", retCode));
-      continue; // Try the next subkey
-    }
-
-    const int MAX_CHAR_COUNT = 256;
-    DWORD valueBufSize = MAX_CHAR_COUNT * sizeof(WCHAR);
-    WCHAR prefetchProcessName[MAX_CHAR_COUNT] = { L'\0' };
-
-    // Get the prefetch process name from the registry
-    retCode = RegQueryValueExW(subKey, L"prefetchProcessName", 0, NULL, 
-                               (LPBYTE)prefetchProcessName, &valueBufSize);
-    if (retCode != ERROR_SUCCESS) {
-      LOG(("Could not obtain process name from registry: %d\n", retCode));
-      continue; // Try the next subkey
-    }
-
-    // The value for prefetch process name comes from HKLM so is trusted.
-    // We will do some sanity checks on it though inside ClearPrefetch.
-    ClearPrefetch(prefetchProcessName);
-  }
-
-  return TRUE;
-}
deleted file mode 100644
--- a/toolkit/components/maintenanceservice/prefetch.h
+++ /dev/null
@@ -1,5 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-BOOL ClearKnownPrefetch();
--- a/toolkit/components/maintenanceservice/workmonitor.cpp
+++ b/toolkit/components/maintenanceservice/workmonitor.cpp
@@ -19,17 +19,16 @@
 
 #include "workmonitor.h"
 #include "serviceinstall.h"
 #include "servicebase.h"
 #include "registrycertificates.h"
 #include "uachelper.h"
 #include "updatehelper.h"
 #include "errors.h"
-#include "prefetch.h"
 
 // Wait 15 minutes for an update operation to run at most.
 // Updates usually take less than a minute so this seems like a 
 // significantly large and safe amount of time to wait.
 static const int TIME_TO_WAIT_ON_UPDATER = 15 * 60 * 1000;
 PRUnichar* MakeCommandLine(int argc, PRUnichar **argv);
 BOOL WriteStatusFailure(LPCWSTR updateDirPath, int errorCode);
 BOOL PathGetSiblingFilePath(LPWSTR destinationBuffer,  LPCWSTR siblingFilePath, 
@@ -499,18 +498,16 @@ ExecuteServiceCommand(int argc, LPWSTR *
 
   BOOL result = FALSE;
   if (!lstrcmpi(argv[2], L"software-update")) {
     result = ProcessSoftwareUpdateCommand(argc - 3, argv + 3);
     // We might not reach here if the service install succeeded
     // because the service self updates itself and the service
     // installer will stop the service.
     LOG(("Service command %ls complete.\n", argv[2]));
-  } else if (!lstrcmpi(argv[2], L"clear-prefetch")) {
-    result = ClearKnownPrefetch();
   } else {
     LOG(("Service command not recognized: %ls.\n", argv[2]));
     // result is already set to FALSE
   }
 
   LOG(("service command %ls complete with result: %ls.\n", 
        argv[1], (result ? L"Success" : L"Failure")));
   return TRUE;
--- a/widget/gtkxtbin/gtk2xtbin.c
+++ b/widget/gtkxtbin/gtk2xtbin.c
@@ -472,17 +472,17 @@ xt_client_xloop_create(void)
     }
 
     /*
      * hook Xt event loop into the glib event loop.
      */
     /* the assumption is that gtk_init has already been called */
     GSource* gs = g_source_new(&xt_event_funcs, sizeof(GSource));
       if (!gs) {
-       return NULL;
+       return;
       }
     
     g_source_set_priority(gs, GDK_PRIORITY_EVENTS);
     g_source_set_can_recurse(gs, TRUE);
     tag = g_source_attach(gs, (GMainContext*)NULL);
 #ifdef VMS
     cnumber = XConnectionNumber(xtdisplay);
 #else
--- a/widget/xpwidgets/GfxInfoX11.cpp
+++ b/widget/xpwidgets/GfxInfoX11.cpp
@@ -37,16 +37,17 @@ GfxInfo::Init()
     mGLMajorVersion = 0;
     mMajorVersion = 0;
     mMinorVersion = 0;
     mRevisionVersion = 0;
     mIsMesa = false;
     mIsNVIDIA = false;
     mIsFGLRX = false;
     mIsNouveau = false;
+    mIsIntel = false;
     mHasTextureFromPixmap = false;
     return GfxInfoBase::Init();
 }
 
 void
 GfxInfo::GetData()
 {
     // to understand this function, see bug 639842. We retrieve the OpenGL driver information in a
@@ -204,16 +205,18 @@ GfxInfo::GetData()
     const char *Mesa_in_version_string = strstr(mVersion.get(), "Mesa");
     if (Mesa_in_version_string) {
         mIsMesa = true;
         // with Mesa, the version string contains "Mesa major.minor" and that's all the version information we get:
         // there is no actual driver version info.
         whereToReadVersionNumbers = Mesa_in_version_string + strlen("Mesa");
         if (strcasestr(mVendor.get(), "nouveau"))
             mIsNouveau = true;
+        if (strcasestr(mRenderer.get(), "intel")) // yes, intel is in the renderer string
+            mIsIntel = true;
     } else if (strstr(mVendor.get(), "NVIDIA Corporation")) {
         mIsNVIDIA = true;
         // with the NVIDIA driver, the version string contains "NVIDIA major.minor"
         // note that here the vendor and version strings behave differently, that's why we don't put this above
         // alongside Mesa_in_version_string.
         const char *NVIDIA_in_version_string = strstr(mVersion.get(), "NVIDIA");
         if (NVIDIA_in_version_string)
             whereToReadVersionNumbers = NVIDIA_in_version_string + strlen("NVIDIA");
@@ -322,16 +325,23 @@ GfxInfo::GetFeatureStatusImpl(PRInt32 aF
       if (mIsMesa) {
         if (mIsNouveau && version(mMajorVersion, mMinorVersion) < version(8,0)) {
           *aStatus = nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION;
           aSuggestedDriverVersion.AssignLiteral("Mesa 8.0");
         } else if (version(mMajorVersion, mMinorVersion, mRevisionVersion) < version(7,10,3)) {
           *aStatus = nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION;
           aSuggestedDriverVersion.AssignLiteral("Mesa 7.10.3");
         }
+        if (aFeature == nsIGfxInfo::FEATURE_WEBGL_MSAA)
+        {
+          if (mIsIntel && version(mMajorVersion, mMinorVersion) < version(8,1))
+            *aStatus = nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION;
+            aSuggestedDriverVersion.AssignLiteral("Mesa 8.1");
+        }
+
       } else if (mIsNVIDIA) {
         if (version(mMajorVersion, mMinorVersion, mRevisionVersion) < version(257,21)) {
           *aStatus = nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION;
           aSuggestedDriverVersion.AssignLiteral("NVIDIA 257.21");
         }
       } else if (mIsFGLRX) {
         // FGLRX does not report a driver version number, so we have the OpenGL version instead.
         // by requiring OpenGL 3, we effectively require recent drivers.
--- a/widget/xpwidgets/GfxInfoX11.h
+++ b/widget/xpwidgets/GfxInfoX11.h
@@ -62,17 +62,17 @@ protected:
 
 private:
   nsCString mVendor;
   nsCString mRenderer;
   nsCString mVersion;
   nsCString mAdapterDescription;
   nsCString mOS;
   nsCString mOSRelease;
-  bool mIsMesa, mIsNVIDIA, mIsFGLRX, mIsNouveau;
+  bool mIsMesa, mIsNVIDIA, mIsFGLRX, mIsNouveau, mIsIntel;
   bool mHasTextureFromPixmap;
   int mGLMajorVersion, mMajorVersion, mMinorVersion, mRevisionVersion;
 
   void AddCrashReportAnnotations();
 };
 
 } // namespace widget
 } // namespace mozilla
--- a/widget/xpwidgets/nsIdleService.cpp
+++ b/widget/xpwidgets/nsIdleService.cpp
@@ -640,16 +640,18 @@ nsIdleService::IdleTimerCallback(void)
     if (!curListener.isIdle) {
       // If they have an idle time smaller than the actual idle time.
       if (curListener.reqIdleTime <= currentIdleTimeInS) {
         // Then add the listener to the list of listeners that should be
         // notified.
         notifyList.AppendObject(curListener.observer);
         // This listener is now idle.
         curListener.isIdle = true;
+        // Remember we have someone idle.
+        mAnyObserverIdle = true;
       } else {
         // Listeners that are not timed out yet are candidates for timing out.
         mDeltaToNextIdleSwitchInS = PR_MIN(mDeltaToNextIdleSwitchInS,
                                            curListener.reqIdleTime);
       }
     }
   }
 
@@ -661,19 +663,16 @@ nsIdleService::IdleTimerCallback(void)
   Telemetry::Accumulate(Telemetry::IDLE_NOTIFY_IDLE_LISTENERS,
                         numberOfPendingNotifications);
 
   // Bail if nothing to do.
   if (!numberOfPendingNotifications) {
     return;
   }
 
-  // Remember we have someone idle.
-  mAnyObserverIdle = true;
-
   // We need a text string to send with any state change events.
   nsAutoString timeStr;
   timeStr.AppendInt(currentIdleTimeInS);
 
   // Notify all listeners that just timed out.
   while (numberOfPendingNotifications--) {
     PR_LOG(sLog, PR_LOG_DEBUG,
            ("idleService: Idle timer callback: tell observer %x user is idle",
--- a/xpcom/build/mozPoisonWriteMac.cpp
+++ b/xpcom/build/mozPoisonWriteMac.cpp
@@ -26,84 +26,103 @@ using namespace mozilla;
 struct FuncData {
     const char *Name;      // Name of the function for the ones we use dlsym
     const void *Wrapper;   // The function that we will replace 'Function' with
     void *Function;        // The function that will be replaced with 'Wrapper'
     void *Buffer;          // Will point to the jump buffer that lets us call
                            // 'Function' after it has been replaced.
 };
 
+// Wrap aio_write. We have not seen it before, so just assert/report it.
+typedef ssize_t (*aio_write_t)(struct aiocb *aiocbp);
+ssize_t wrap_aio_write(struct aiocb *aiocbp);
+FuncData aio_write_data = { 0, (void*) wrap_aio_write, (void*) aio_write };
+ssize_t wrap_aio_write(struct aiocb *aiocbp) {
+    MOZ_ASSERT(0);
+    aio_write_t old_write = (aio_write_t) aio_write_data.Buffer;
+    return old_write(aiocbp);
+}
+
+// Wrap pwrite-like functions.
+// We have not seen them before, so just assert/report it.
+typedef ssize_t (*pwrite_t)(int fd, const void *buf, size_t nbyte, off_t offset);
+template<FuncData &foo>
+ssize_t wrap_pwrite_temp(int fd, const void *buf, size_t nbyte, off_t offset) {
+    MOZ_ASSERT(0);
+    pwrite_t old_write = (pwrite_t) foo.Buffer;
+    return old_write(fd, buf, nbyte, offset);
+}
+
+// Define a FuncData for a pwrite-like functions.
+// FIXME: clang accepts usinging wrap_pwrite_temp<X ## _data> in the struct
+// initialization. Is this a gcc 4.2 bug?
+#define DEFINE_PWRITE_DATA(X, NAME)                                        \
+ssize_t wrap_ ## X (int fd, const void *buf, size_t nbyte, off_t offset);  \
+FuncData X ## _data = { NAME, (void*) wrap_ ## X };                        \
+ssize_t wrap_ ## X (int fd, const void *buf, size_t nbyte, off_t offset) { \
+    return wrap_pwrite_temp<X ## _data>(fd, buf, nbyte, offset);           \
+}
+
+// This exists everywhere.
+DEFINE_PWRITE_DATA(pwrite, "pwrite")
+// These exist on 32 bit OS X
+DEFINE_PWRITE_DATA(pwrite_NOCANCEL_UNIX2003, "pwrite$NOCANCEL$UNIX2003");
+DEFINE_PWRITE_DATA(pwrite_UNIX2003, "pwrite$UNIX2003");
+// This exists on 64 bit OS X
+DEFINE_PWRITE_DATA(pwrite_NOCANCEL, "pwrite$NOCANCEL");
+
+void AbortOnBadWrite(int fd, const void *wbuf, size_t count);
+
+typedef ssize_t (*writev_t)(int fd, const struct iovec *iov, int iovcnt);
+template<FuncData &foo>
+ssize_t wrap_writev_temp(int fd, const struct iovec *iov, int iovcnt) {
+    AbortOnBadWrite(fd, 0, iovcnt);
+    writev_t old_write = (writev_t) foo.Buffer;
+    return old_write(fd, iov, iovcnt);
+}
+
+// Define a FuncData for a writev-like functions.
+#define DEFINE_WRITEV_DATA(X, NAME)                                  \
+ssize_t wrap_ ## X (int fd, const struct iovec *iov, int iovcnt);    \
+FuncData X ## _data = { NAME, (void*) wrap_ ## X };                  \
+ssize_t wrap_ ## X (int fd, const struct iovec *iov, int iovcnt) {   \
+    return wrap_writev_temp<X ## _data>(fd, iov, iovcnt);            \
+}
+
+// This exists everywhere.
+DEFINE_WRITEV_DATA(writev, "writev");
+// These exist on 32 bit OS X
+DEFINE_WRITEV_DATA(writev_NOCANCEL_UNIX2003, "writev$NOCANCEL$UNIX2003");
+DEFINE_WRITEV_DATA(writev_UNIX2003, "writev$UNIX2003");
+// This exists on 64 bit OS X
+DEFINE_WRITEV_DATA(writev_NOCANCEL, "writev$NOCANCEL");
+
 typedef ssize_t (*write_t)(int fd, const void *buf, size_t count);
-void AbortOnBadWrite(int fd, const void *wbuf, size_t count);
 template<FuncData &foo>
 ssize_t wrap_write_temp(int fd, const void *buf, size_t count) {
     AbortOnBadWrite(fd, buf, count);
     write_t old_write = (write_t) foo.Buffer;
     return old_write(fd, buf, count);
 }
 
-// FIXME: clang accepts usinging wrap_data_temp<X ## _data> in the struct
-// initialization. Is this a gcc 4.2 bug?
-
-// Define a FuncData for a function that can be found without dlsym.
-#define DEFINE_F_DATA(X)                                             \
-ssize_t wrap_ ## X (int fd, const void *buf, size_t count);          \
-FuncData X ## _data = { 0, (void*) wrap_ ## X, (void*) X };          \
-ssize_t wrap_ ## X (int fd, const void *buf, size_t count) {         \
-    return wrap_write_temp<X ## _data>(fd, buf, count);              \
-}
-
-// Define a FuncData for a function that can only be found with dlsym.
-#define DEFINE_F_DATA_DYN(X, NAME)                                   \
+// Define a FuncData for a write-like functions.
+#define DEFINE_WRITE_DATA(X, NAME)                                   \
 ssize_t wrap_ ## X (int fd, const void *buf, size_t count);          \
 FuncData X ## _data = { NAME, (void*) wrap_ ## X };                  \
 ssize_t wrap_ ## X (int fd, const void *buf, size_t count) {         \
     return wrap_write_temp<X ## _data>(fd, buf, count);              \
 }
 
-// Define a simple FuncData that just aborts.
-#define DEFINE_F_DATA_ABORT(X)                                       \
-void wrap_ ## X() { abort(); }                                       \
-FuncData X ## _data = { 0, (void*) wrap_ ## X, (void*) X }
-
-// Define a simple FuncData that just aborts for a function that needs dlsym.
-#define DEFINE_F_DATA_ABORT_DYN(X, NAME)                             \
-void wrap_ ## X() { abort(); }                                       \
-FuncData X ## _data = { NAME, (void*) wrap_ ## X }
-
-DEFINE_F_DATA_ABORT(aio_write);
-DEFINE_F_DATA_ABORT(pwrite);
-
+// This exists everywhere.
+DEFINE_WRITE_DATA(write, "write");
 // These exist on 32 bit OS X
-DEFINE_F_DATA_ABORT_DYN(writev_NOCANCEL_UNIX2003, "writev$NOCANCEL$UNIX2003");
-DEFINE_F_DATA_ABORT_DYN(writev_UNIX2003, "writev$UNIX2003");
-DEFINE_F_DATA_ABORT_DYN(pwrite_NOCANCEL_UNIX2003, "pwrite$NOCANCEL$UNIX2003");
-DEFINE_F_DATA_ABORT_DYN(pwrite_UNIX2003, "pwrite$UNIX2003");
-
-// These exist on 64 bit OS X
-DEFINE_F_DATA_ABORT_DYN(writev_NOCANCEL, "writev$NOCANCEL");
-DEFINE_F_DATA_ABORT_DYN(pwrite_NOCANCEL, "pwrite$NOCANCEL");
-
-DEFINE_F_DATA(write);
-
-typedef ssize_t (*writev_t)(int fd, const struct iovec *iov, int iovcnt);
-ssize_t wrap_writev(int fd, const struct iovec *iov, int iovcnt);
-FuncData writev_data = { 0, (void*) wrap_writev, (void*) writev };
-ssize_t wrap_writev(int fd, const struct iovec *iov, int iovcnt) {
-    AbortOnBadWrite(fd, 0, iovcnt);
-    writev_t old_write = (writev_t) writev_data.Buffer;
-    return old_write(fd, iov, iovcnt);
-}
-
-// These exist on 32 bit OS X
-DEFINE_F_DATA_DYN(write_NOCANCEL_UNIX2003, "write$NOCANCEL$UNIX2003");
-DEFINE_F_DATA_DYN(write_UNIX2003, "write$UNIX2003");
-
-// These exist on 64 bit OS X
-DEFINE_F_DATA_DYN(write_NOCANCEL, "write$NOCANCEL");
+DEFINE_WRITE_DATA(write_NOCANCEL_UNIX2003, "write$NOCANCEL$UNIX2003");
+DEFINE_WRITE_DATA(write_UNIX2003, "write$UNIX2003");
+// This exists on 64 bit OS X
+DEFINE_WRITE_DATA(write_NOCANCEL, "write$NOCANCEL");
 
 FuncData *Functions[] = { &aio_write_data,
 
                           &pwrite_data,
                           &pwrite_NOCANCEL_UNIX2003_data,
                           &pwrite_UNIX2003_data,
                           &pwrite_NOCANCEL_data,
 
--- a/xpfe/appshell/src/nsWebShellWindow.cpp
+++ b/xpfe/appshell/src/nsWebShellWindow.cpp
@@ -87,22 +87,16 @@ nsWebShellWindow::nsWebShellWindow(PRUin
   : nsXULWindow(aChromeFlags)
   , mSPTimerLock("nsWebShellWindow.mSPTimerLock")
 {
 }
 
 
 nsWebShellWindow::~nsWebShellWindow()
 {
-  if (mWindow) {
-    mWindow->SetClientData(0);
-    mWindow->Destroy();
-    mWindow = nullptr; // Force release here.
-  }
-
   MutexAutoLock lock(mSPTimerLock);
   if (mSPTimer)
     mSPTimer->Cancel();
 }
 
 NS_IMPL_ADDREF_INHERITED(nsWebShellWindow, nsXULWindow)
 NS_IMPL_RELEASE_INHERITED(nsWebShellWindow, nsXULWindow)
 
--- a/xpfe/appshell/src/nsWindowMediator.cpp
+++ b/xpfe/appshell/src/nsWindowMediator.cpp
@@ -752,19 +752,29 @@ nsWindowMediator::RemoveListener(nsIWind
 }
 
 NS_IMETHODIMP
 nsWindowMediator::Observe(nsISupports* aSubject,
                           const char* aTopic,
                           const PRUnichar* aData)
 {
   if (!strcmp(aTopic, "xpcom-shutdown") && mReady) {
-    MutexAutoLock lock(mListLock);
-    while (mOldestWindow)
-      UnregisterWindow(mOldestWindow);
+    // Unregistering a window may cause its destructor to run, causing it to
+    // call into the window mediator, try to acquire mListLock, and deadlock.
+    // Our solution is to hold strong refs to all windows until we release
+    // mListLock.
+    nsTArray<nsCOMPtr<nsIXULWindow> > windows;
+
+    {
+      MutexAutoLock lock(mListLock);
+      while (mOldestWindow) {
+        windows.AppendElement(mOldestWindow->mWindow);
+        UnregisterWindow(mOldestWindow);
+      }
+    }
     mReady = false;
   }
   return NS_OK;
 }
 
 bool
 notifyOpenWindow(nsISupports *aElement, void* aData)
 {