Merge from mozilla-central.
authorDavid Anderson <danderson@mozilla.com>
Fri, 03 Aug 2012 18:58:30 -0700
changeset 106630 0bc212d0183b8c9a9e21db665b6dc25c686a9650
parent 106629 b457b592f609045e92165f30ddc47070d8635eb8 (current diff)
parent 101325 a7fadfbad93262a227f70459aa36d968aed3ae61 (diff)
child 106631 b8084b0700fa586f1208dfe58076d1cb7cff2edc
push id1
push userroot
push dateMon, 20 Oct 2014 17:29:22 +0000
milestone17.0a1
Merge from mozilla-central.
accessible/src/atk/ApplicationAccessibleWrap.cpp
accessible/src/atk/ApplicationAccessibleWrap.h
accessible/src/base/nsAccDocManager.cpp
accessible/src/base/nsAccessNode.cpp
accessible/src/base/nsTextEquivUtils.cpp
accessible/src/generic/Accessible.cpp
accessible/src/generic/Accessible.h
accessible/src/generic/ApplicationAccessible.cpp
accessible/src/generic/ApplicationAccessible.h
accessible/src/generic/DocAccessible.cpp
accessible/src/generic/DocAccessible.h
accessible/src/xul/XULTreeAccessible.cpp
accessible/src/xul/XULTreeAccessible.h
accessible/src/xul/XULTreeGridAccessible.cpp
accessible/src/xul/XULTreeGridAccessible.h
b2g/app/nsBrowserApp.cpp
browser/app/nsBrowserApp.cpp
browser/base/content/browser.js
browser/components/shell/src/nsWindowsShellService.cpp
browser/components/shell/src/nsWindowsShellService.h
browser/devtools/highlighter/test/browser_inspector_editor.js
browser/devtools/webconsole/HUDService.jsm
browser/devtools/webconsole/test/Makefile.in
build/mobile/devicemanagerADB.py
build/mobile/devicemanagerSUT.py
content/base/public/nsDOMFile.h
content/base/src/nsDocument.cpp
content/canvas/src/WebGLContext.cpp
content/canvas/src/WebGLContext.h
content/canvas/src/WebGLContextGL.cpp
content/events/src/nsDOMTouchEvent.cpp
content/events/src/nsDOMTouchEvent.h
content/html/content/src/nsGenericHTMLElement.cpp
docshell/base/nsDocShell.cpp
dom/base/ConsoleAPI.js
dom/base/nsDOMClassInfo.cpp
dom/base/nsDOMClassInfo.h
dom/base/nsDOMClassInfoClasses.h
dom/base/nsGlobalWindow.cpp
dom/base/nsHistory.cpp
dom/indexedDB/IDBObjectStore.cpp
dom/ipc/ContentChild.cpp
dom/ipc/ContentParent.cpp
dom/ipc/PContent.ipdl
dom/ipc/TabChild.cpp
dom/ipc/TabParent.cpp
dom/tests/browser/browser_ConsoleAPITests.js
gfx/gl/GLContextProviderEGL.cpp
gfx/layers/ImageLayers.h
js/src/frontend/BytecodeEmitter.cpp
js/src/ion/IonMacroAssembler.cpp
js/src/jsapi.cpp
js/src/jsapi.h
js/src/jsarray.cpp
js/src/jsatom.cpp
js/src/jsatom.h
js/src/jsatominlines.h
js/src/jscntxt.h
js/src/jscompartment.h
js/src/jsdate.cpp
js/src/jsfriendapi.cpp
js/src/jsfriendapi.h
js/src/jsgc.cpp
js/src/jsgc.h
js/src/jsinterp.cpp
js/src/jsnum.cpp
js/src/jsnum.h
js/src/jsobj.cpp
js/src/json.cpp
js/src/jsopcode.cpp
js/src/jsstr.cpp
js/src/shell/jsoptparse.cpp
js/src/vm/Debugger.cpp
js/xpconnect/src/XPCInlines.h
js/xpconnect/src/XPCJSRuntime.cpp
js/xpconnect/src/dom_quickstubs.qsconf
js/xpconnect/src/xpcprivate.h
layout/base/nsBidiPresUtils.cpp
layout/base/nsCSSFrameConstructor.cpp
layout/base/nsCSSFrameConstructor.h
layout/base/nsLayoutUtils.cpp
layout/base/nsLayoutUtils.h
layout/generic/TextOverflow.cpp
layout/generic/nsBlockFrame.cpp
layout/generic/nsContainerFrame.cpp
layout/generic/nsContainerFrame.h
layout/generic/nsFrame.cpp
layout/generic/nsFrameSetFrame.cpp
layout/generic/nsGfxScrollFrame.cpp
layout/generic/nsHTMLReflowState.cpp
layout/generic/nsHTMLReflowState.h
layout/generic/nsIFrame.h
layout/generic/nsLineBox.cpp
layout/generic/nsLineLayout.cpp
layout/generic/nsPlaceholderFrame.cpp
layout/generic/nsTextFrameThebes.cpp
layout/style/AnimationCommon.cpp
layout/style/nsRuleNode.cpp
layout/style/nsStyleStruct.cpp
layout/style/nsStyleStruct.h
layout/style/nsStyleStructInlines.h
layout/svg/base/src/nsSVGGlyphFrame.cpp
layout/tables/nsTableRowFrame.cpp
mobile/android/chrome/content/browser.js
mobile/xul/app/nsBrowserApp.cpp
modules/libpref/src/init/all.js
netwerk/base/src/nsBaseChannel.cpp
netwerk/base/src/nsSocketTransport2.cpp
netwerk/base/src/nsStreamTransportService.cpp
netwerk/protocol/file/nsFileChannel.cpp
netwerk/protocol/http/HttpChannelChild.cpp
netwerk/protocol/http/HttpChannelParent.cpp
netwerk/protocol/http/nsHttpBasicAuth.cpp
netwerk/protocol/http/nsHttpChannel.cpp
netwerk/protocol/http/nsHttpConnection.cpp
netwerk/protocol/http/nsHttpConnectionMgr.cpp
netwerk/protocol/http/nsHttpPipeline.cpp
netwerk/protocol/http/nsHttpTransaction.cpp
nsprpub/TAG-INFO
security/manager/boot/src/nsSecurityWarningDialogs.cpp
security/manager/boot/src/nsSecurityWarningDialogs.h
services/common/aitcserver.js
services/common/storageserver.js
services/sync/modules/policies.js
services/sync/services-sync.js
services/sync/tests/unit/test_utils_deepCopy.js
services/sync/tests/unit/xpcshell.ini
testing/mochitest/runtests.py
toolkit/components/maintenanceservice/prefetch.cpp
toolkit/components/maintenanceservice/prefetch.h
toolkit/components/telemetry/TelemetryHistograms.h
toolkit/mozapps/extensions/XPIProvider.jsm
widget/xpwidgets/GfxInfoX11.cpp
widget/xpwidgets/GfxInfoX11.h
widget/xpwidgets/nsIdleService.cpp
xpfe/appshell/src/nsWebShellWindow.cpp
xpfe/appshell/src/nsWindowMediator.cpp
--- 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/accessible/tests/mochitest/name/markuprules.xml
+++ b/accessible/tests/mochitest/name/markuprules.xml
@@ -197,16 +197,17 @@
                      aria-labelledby="l1 l2"
                      label="test4"
                      title="test5"
                      a11yname="option1">option1</html:option>
         <html:option>option2</html:option>
       </html:select>
     </markup>
 
+<!-- Temporarily disabled for causing bug 733848
     <markup ref="html:img" ruleset="htmlimage">
       <html:span id="l1" a11yname="test2">test2</html:span>
       <html:span id="l2" a11yname="test3">test3</html:span>
       <html:img id="img"
                 aria-label="Logo of Mozilla"
                 aria-labelledby="l1 l2"
                 alt="Mozilla logo"
                 title="This is a logo"
@@ -218,16 +219,17 @@
       <html:span id="l2" a11yname="test3">test3</html:span>
       <html:img id="img"
                  aria-label="Logo of Mozilla"
                  aria-labelledby="l1 l2"
                  title="This is a logo"
                  alt=""
                  src="../moz.png"/>
     </markup>
+-->
 
     <markup ref="html:table/html:tr/html:td" ruleset="htmlelm"
             id="markup4test">
       <html:span id="l1" a11yname="test2">test2</html:span>
       <html:span id="l2" a11yname="test3">test3</html:span>
       <html:label for="tc" a11yname="test4">test4</html:label>
       <html:table>
         <html:tr>
--- 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/base/content/browser-addons.js
+++ b/browser/base/content/browser-addons.js
@@ -72,24 +72,27 @@ const gXPInstallObserver = {
 
       PopupNotifications.show(browser, notificationID, messageString, anchorID,
                               action, null, options);
       break;
     case "addon-install-blocked":
       messageString = gNavigatorBundle.getFormattedString("xpinstallPromptWarning",
                         [brandShortName, installInfo.originatingURI.host]);
 
+      let secHistogram = Components.classes["@mozilla.org/base/telemetry;1"].getService(Ci.nsITelemetry).getHistogramById("SECURITY_UI");
       action = {
         label: gNavigatorBundle.getString("xpinstallPromptAllowButton"),
         accessKey: gNavigatorBundle.getString("xpinstallPromptAllowButton.accesskey"),
         callback: function() {
+          secHistogram.add(Ci.nsISecurityUITelemetry.WARNING_ADDON_ASKING_PREVENTED_CLICK_THROUGH);
           installInfo.install();
         }
       };
 
+      secHistogram.add(Ci.nsISecurityUITelemetry.WARNING_ADDON_ASKING_PREVENTED);
       PopupNotifications.show(browser, notificationID, messageString, anchorID,
                               action, null, options);
       break;
     case "addon-install-started":
       function needsDownload(aInstall) {
         return aInstall.state != AddonManager.STATE_DOWNLOADED;
       }
       // If all installs have already been downloaded then there is no need to
--- a/browser/base/content/browser-social.js
+++ b/browser/base/content/browser-social.js
@@ -155,20 +155,20 @@ let SocialShareButton = {
   init: function SSB_init() {
     this.updateButtonHiddenState();
     this.updateProfileInfo();
   },
 
   updateProfileInfo: function SSB_updateProfileInfo() {
     let profileRow = document.getElementById("editSharePopupHeader");
     let profile = Social.provider.profile;
-    if (profile && profile.portrait && profile.displayName) {
+    if (profile && profile.displayName) {
       profileRow.hidden = false;
       let portrait = document.getElementById("socialUserPortrait");
-      portrait.style.listStyleImage = profile.portrait;
+      portrait.setAttribute("src", profile.portrait || "chrome://browser/skin/social/social.png");
       let displayName = document.getElementById("socialUserDisplayName");
       displayName.setAttribute("label", profile.displayName);
     } else {
       profileRow.hidden = true;
     }
   },
 
   get shareButton() {
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -2514,19 +2514,23 @@ let BrowserOnClick = {
     }
     else if (/^about:home$/i.test(ownerDoc.documentURI)) {
       this.onAboutHome(originalTarget, ownerDoc);
     }
   },
 
   onAboutCertError: function BrowserOnClick_onAboutCertError(aTargetElm, aOwnerDoc) {
     let elmId = aTargetElm.getAttribute("id");
+    let secHistogram = Cc["@mozilla.org/base/telemetry;1"].
+                        getService(Ci.nsITelemetry).
+                        getHistogramById("SECURITY_UI");
 
     switch (elmId) {
       case "exceptionDialogButton":
+        secHistogram.add(Ci.nsISecurityUITelemetry.WARNING_BAD_CERT_CLICK_ADD_EXCEPTION);
         let params = { exceptionAdded : false, handlePrivateBrowsing : true };
 
         try {
           switch (Services.prefs.getIntPref("browser.ssl_override_behavior")) {
             case 2 : // Pre-fetch & pre-populate
               params.prefetchCert = true;
             case 1 : // Pre-populate
               params.location = aOwnerDoc.location.href;
@@ -2540,39 +2544,59 @@ let BrowserOnClick = {
 
         // If the user added the exception cert, attempt to reload the page
         if (params.exceptionAdded) {
           aOwnerDoc.location.reload();
         }
         break;
 
       case "getMeOutOfHereButton":
+        secHistogram.add(Ci.nsISecurityUITelemetry.WARNING_BAD_CERT_GET_ME_OUT_OF_HERE);
         getMeOutOfHere();
         break;
+
+      case "technicalContent":
+        secHistogram.add(Ci.nsISecurityUITelemetry.WARNING_BAD_CERT_TECHNICAL_DETAILS);
+        break;
+
+      case "expertContent":
+        secHistogram.add(Ci.nsISecurityUITelemetry.WARNING_BAD_CERT_UNDERSTAND_RISKS);
+        break;
+
     }
   },
 
   onAboutBlocked: function BrowserOnClick_onAboutBlocked(aTargetElm, aOwnerDoc) {
     let elmId = aTargetElm.getAttribute("id");
+    let secHistogram = Cc["@mozilla.org/base/telemetry;1"].
+                        getService(Ci.nsITelemetry).
+                        getHistogramById("SECURITY_UI");
 
     // The event came from a button on a malware/phishing block page
     // First check whether it's malware or phishing, so that we can
     // use the right strings/links
     let isMalware = /e=malwareBlocked/.test(aOwnerDoc.documentURI);
+    let bucketName = isMalware ? "WARNING_MALWARE_PAGE_":"WARNING_PHISHING_PAGE_";
+    let nsISecTel = Ci.nsISecurityUITelemetry;
 
     switch (elmId) {
       case "getMeOutButton":
+        secHistogram.add(nsISecTel[bucketName + "GET_ME_OUT_OF_HERE"]);
         getMeOutOfHere();
         break;
 
       case "reportButton":
         // This is the "Why is this site blocked" button.  For malware,
         // we can fetch a site-specific report, for phishing, we redirect
         // to the generic page describing phishing protection.
 
+        // We log even if malware/phishing info URL couldn't be found: 
+        // the measurement is for how many users clicked the WHY BLOCKED button
+        secHistogram.add(nsISecTel[bucketName + "WHY_BLOCKED"]);
+
         if (isMalware) {
           // Get the stop badware "why is this blocked" report url,
           // append the current url, and go there.
           try {
             let reportURL = formatURL("browser.safebrowsing.malware.reportURL", true);
             reportURL += aOwnerDoc.location.href;
             content.location = reportURL;
           } catch (e) {
@@ -2584,16 +2608,17 @@ let BrowserOnClick = {
             content.location = formatURL("browser.safebrowsing.warning.infoURL", true);
           } catch (e) {
             Components.utils.reportError("Couldn't get phishing info URL: " + e);
           }
         }
         break;
 
       case "ignoreWarningButton":
+        secHistogram.add(nsISecTel[bucketName + "IGNORE_WARNING"]);
         this.ignoreWarningButton(isMalware);
         break;
     }
   },
 
   ignoreWarningButton: function BrowserOnClick_ignoreWarningButton(aIsMalware) {
     // Allow users to override and continue through to the site,
     // but add a notify bar as a reminder, so that they don't lose
--- a/browser/base/content/test/browser_social_toolbar.js
+++ b/browser/base/content/test/browser_social_toolbar.js
@@ -18,25 +18,25 @@ function test() {
       SocialService.removeProvider(Social.provider.origin, finish);
     });
   });
 }
 
 var tests = {
   testProfileSet: function(next) {
     let profile = {
-      portrait: "chrome://branding/content/icon48.png",
+      portrait: "https://example.com/portrait.jpg",
       userName: "trickster",
       displayName: "Kuma Lisa",
       profileURL: "http://en.wikipedia.org/wiki/Kuma_Lisa"
     }
     Social.provider.updateUserProfile(profile);
     // check dom values
     let portrait = document.getElementById("social-statusarea-user-portrait").getAttribute("src");
-    is(portrait, profile.portrait, "portrait is set");
+    is(profile.portrait, portrait, "portrait is set");
     let userButton = document.getElementById("social-statusarea-username");
     ok(!userButton.hidden, "username is visible");
     is(userButton.label, profile.userName, "username is set");
     next();
   },
   testAmbientNotifications: function(next) {
     let ambience = {
       name: "testIcon",
--- 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/browser/devtools/debugger/debugger-controller.js
+++ b/browser/devtools/debugger/debugger-controller.js
@@ -903,16 +903,21 @@ SourceScripts.prototype = {
   _onNewScript: function SS__onNewScript(aNotification, aPacket) {
     // Ignore scripts generated from 'clientEvaluate' packets.
     if (aPacket.url == "debugger eval code") {
       return;
     }
 
     this._addScript({ url: aPacket.url, startLine: aPacket.startLine }, true);
 
+    // Select the script if it's the preferred one.
+    if (aPacket.url === DebuggerView.Scripts.preferredScriptUrl) {
+      DebuggerView.Scripts.selectScript(aPacket.url);
+    }
+
     // If there are any stored breakpoints for this script, display them again,
     // both in the editor and the pane.
     for each (let breakpoint in DebuggerController.Breakpoints.store) {
       if (breakpoint.location.url == aPacket.url) {
         DebuggerController.Breakpoints.displayBreakpoint(breakpoint);
       }
     }
   },
@@ -921,16 +926,24 @@ SourceScripts.prototype = {
    * Handler for the thread client's scriptsadded notification.
    */
   _onScriptsAdded: function SS__onScriptsAdded() {
     for each (let script in this.activeThread.cachedScripts) {
       this._addScript(script, false);
     }
     DebuggerView.Scripts.commitScripts();
     DebuggerController.Breakpoints.updatePaneBreakpoints();
+
+    // Select the preferred script if one exists, the first entry otherwise.
+    let preferredScriptUrl = DebuggerView.Scripts.preferredScriptUrl;
+    if (preferredScriptUrl) {
+      DebuggerView.Scripts.selectScript(preferredScriptUrl);
+    } else {
+      DebuggerView.Scripts.selectIndex(0);
+    }
   },
 
   /**
    * Handler for the thread client's scriptscleared notification.
    */
   _onScriptsCleared: function SS__onScriptsCleared() {
     DebuggerView.Scripts.empty();
     DebuggerView.Breakpoints.emptyText();
--- a/browser/devtools/debugger/debugger-view.js
+++ b/browser/devtools/debugger/debugger-view.js
@@ -235,16 +235,26 @@ ScriptsView.prototype = {
     }
     if (this._scripts.getElementsByAttribute("label", aLabel).length > 0) {
       return true;
     }
     return false;
   },
 
   /**
+   * Selects the script with the specified index from the list.
+   *
+   * @param number aIndex
+   *        The script index.
+   */
+  selectIndex: function DVS_selectIndex(aIndex) {
+    this._scripts.selectedIndex = aIndex;
+  },
+
+  /**
    * Selects the script with the specified URL from the list.
    *
    * @param string aUrl
    *        The script URL.
    */
   selectScript: function DVS_selectScript(aUrl) {
     for (let i = 0, l = this._scripts.itemCount; i < l; i++) {
       if (this._scripts.getItemAtIndex(i).value == aUrl) {
@@ -273,16 +283,23 @@ ScriptsView.prototype = {
    * @return string | null
    */
   get selected() {
     return this._scripts.selectedItem ?
            this._scripts.selectedItem.value : null;
   },
 
   /**
+   * Gets the most recently selected script url.
+   * @return string | null
+   */
+  get preferredScriptUrl()
+    this._preferredScriptUrl ? this._preferredScriptUrl : null,
+
+  /**
    * Returns the list of labels in the scripts container.
    * @return array
    */
   get scriptLabels() {
     let labels = [];
     for (let i = 0, l = this._scripts.itemCount; i < l; i++) {
       labels.push(this._scripts.getItemAtIndex(i).label);
     }
@@ -340,17 +357,17 @@ ScriptsView.prototype = {
     // Find the target position in the menulist and insert the script there.
     for (let i = 0, l = this._scripts.itemCount; i < l; i++) {
       if (this._scripts.getItemAtIndex(i).label > aLabel) {
         this._createScriptElement(aLabel, aScript, i);
         return;
       }
     }
     // The script is alphabetically the last one.
-    this._createScriptElement(aLabel, aScript, -1, true);
+    this._createScriptElement(aLabel, aScript, -1);
   },
 
   /**
    * Adds all the prepared scripts to the scripts container.
    * If a script already exists (was previously added), nothing happens.
    */
   commitScripts: function DVS_commitScripts() {
     let newScripts = this._tmpScripts;
@@ -360,53 +377,45 @@ ScriptsView.prototype = {
       return;
     }
     newScripts.sort(function(a, b) {
       return a.label.toLowerCase() > b.label.toLowerCase();
     });
 
     for (let i = 0, l = newScripts.length; i < l; i++) {
       let item = newScripts[i];
-      this._createScriptElement(item.label, item.script, -1, true);
+      this._createScriptElement(item.label, item.script, -1);
     }
   },
 
   /**
    * Creates a custom script element and adds it to the scripts container.
    * If the script with the specified label already exists, nothing happens.
    *
    * @param string aLabel
    *        The simplified script location to be shown.
    * @param string aScript
    *        The source script.
    * @param number aIndex
    *        The index where to insert to new script in the container.
    *        Pass -1 to append the script at the end.
-   * @param boolean aSelectIfEmptyFlag
-   *        True to set the newly created script as the currently selected item
-   *        if there are no other existing scripts in the container.
    */
-  _createScriptElement: function DVS__createScriptElement(
-    aLabel, aScript, aIndex, aSelectIfEmptyFlag)
+  _createScriptElement: function DVS__createScriptElement(aLabel, aScript, aIndex)
   {
     // Make sure we don't duplicate anything.
     if (aLabel == "null" || this.containsLabel(aLabel) || this.contains(aScript.url)) {
       return;
     }
 
     let scriptItem =
       aIndex == -1 ? this._scripts.appendItem(aLabel, aScript.url)
                    : this._scripts.insertItemAt(aIndex, aLabel, aScript.url);
 
     scriptItem.setAttribute("tooltiptext", aScript.url);
     scriptItem.setUserData("sourceScript", aScript, null);
-
-    if (this._scripts.itemCount == 1 && aSelectIfEmptyFlag) {
-      this._scripts.selectedItem = scriptItem;
-    }
   },
 
   /**
    * Gets the entered file, line and token entered in the searchbox.
    *
    * @return array
    *         A [file, line, token] array.
    */
@@ -432,16 +441,17 @@ ScriptsView.prototype = {
    */
   _onScriptsChange: function DVS__onScriptsChange() {
     let selectedItem = this._scripts.selectedItem;
     if (!selectedItem) {
       return;
     }
 
     this._preferredScript = selectedItem;
+    this._preferredScriptUrl = selectedItem.value;
     this._scripts.setAttribute("tooltiptext", selectedItem.value);
     DebuggerController.SourceScripts.showScript(selectedItem.getUserData("sourceScript"));
   },
 
   /**
    * The search listener for the scripts search box.
    */
   _onScriptsSearch: function DVS__onScriptsSearch(e) {
--- a/browser/devtools/debugger/test/Makefile.in
+++ b/browser/devtools/debugger/test/Makefile.in
@@ -30,16 +30,17 @@ MOCHITEST_BROWSER_TESTS = \
 	browser_dbg_propertyview-04.js \
 	browser_dbg_propertyview-05.js \
 	browser_dbg_propertyview-06.js \
 	browser_dbg_propertyview-07.js \
 	browser_dbg_propertyview-08.js \
 	browser_dbg_propertyview-09.js \
 	browser_dbg_propertyview-10.js \
 	browser_dbg_propertyview-edit.js \
+	browser_dbg_reload-same-script.js \
 	browser_dbg_panesize.js \
 	browser_dbg_panesize-inner.js \
 	browser_dbg_stack-01.js \
 	browser_dbg_stack-02.js \
 	browser_dbg_stack-03.js \
 	browser_dbg_stack-04.js \
 	browser_dbg_stack-05.js \
 	browser_dbg_location-changes.js \
new file mode 100644
--- /dev/null
+++ b/browser/devtools/debugger/test/browser_dbg_reload-same-script.js
@@ -0,0 +1,126 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Tests if the same script is shown after a page is reloaded.
+ */
+
+const TAB_URL = EXAMPLE_URL + "browser_dbg_script-switching.html";
+
+let gPane = null;
+let gTab = null;
+let gDebuggee = null;
+let gDebugger = null;
+let gView = null;
+
+function test()
+{
+  let step = 0;
+  let scriptShown = false;
+  let scriptShownUrl = null;
+  let resumed = false;
+  let testStarted = false;
+
+  debug_tab_pane(TAB_URL, function(aTab, aDebuggee, aPane) {
+    gTab = aTab;
+    gDebuggee = aDebuggee;
+    gPane = aPane;
+    gDebugger = gPane.contentWindow;
+    gView = gDebugger.DebuggerView;
+    resumed = true;
+
+    executeSoon(startTest);
+  });
+
+  function onScriptShown(aEvent)
+  {
+    scriptShown = aEvent.detail.url.indexOf("-01.js") != -1;
+    scriptShownUrl = aEvent.detail.url;
+    executeSoon(startTest);
+  }
+
+  function onUlteriorScriptShown(aEvent)
+  {
+    scriptShownUrl = aEvent.detail.url;
+    executeSoon(testScriptShown);
+  }
+
+  window.addEventListener("Debugger:ScriptShown", onScriptShown);
+
+  function startTest()
+  {
+    if (scriptShown && resumed && !testStarted) {
+      window.removeEventListener("Debugger:ScriptShown", onScriptShown);
+      window.addEventListener("Debugger:ScriptShown", onUlteriorScriptShown);
+      testStarted = true;
+      Services.tm.currentThread.dispatch({ run: performTest }, 0);
+    }
+  }
+
+  function finishTest()
+  {
+    if (scriptShown && resumed && testStarted) {
+      window.removeEventListener("Debugger:ScriptShown", onUlteriorScriptShown);
+      closeDebuggerAndFinish();
+    }
+  }
+
+  function performTest()
+  {
+    testCurrentScript("-01.js", step);
+    step = 1;
+    reloadPage();
+  }
+
+  function testScriptShown()
+  {
+    if (step === 1) {
+      testCurrentScript("-01.js", step);
+      step = 2;
+      reloadPage();
+    }
+    else if (step === 2) {
+      testCurrentScript("-01.js", step);
+      step = 3;
+      gView.Scripts.selectScript(gView.Scripts.scriptLocations[1]);
+    }
+    else if (step === 3) {
+      testCurrentScript("-02.js", step);
+      step = 4;
+      reloadPage();
+    }
+    else if (step === 4) {
+      testCurrentScript("-02.js", step);
+      finishTest();
+    }
+  }
+
+  function testCurrentScript(part, step)
+  {
+    info("Currently preferred script: " + gView.Scripts.preferredScriptUrl);
+    info("Currently selected script: " + gView.Scripts.selected);
+
+    isnot(gView.Scripts.preferredScriptUrl.indexOf(part), -1,
+      "The preferred script url wasn't set correctly. (" + step + ")");
+    isnot(gView.Scripts.selected.indexOf(part), -1,
+      "The selected script isn't the correct one. (" + step + ")");
+    is(gView.Scripts.selected, scriptShownUrl,
+      "The shown script is not the the correct one. (" + step + ")");
+  }
+
+  function reloadPage()
+  {
+    executeSoon(function() {
+      gDebuggee.location.reload();
+    });
+  }
+
+  registerCleanupFunction(function() {
+    removeTab(gTab);
+    gPane = null;
+    gTab = null;
+    gDebuggee = null;
+    gDebugger = null;
+    gView = null;
+  });
+}
--- a/browser/devtools/highlighter/TreePanel.jsm
+++ b/browser/devtools/highlighter/TreePanel.jsm
@@ -514,17 +514,21 @@ TreePanel.prototype = {
     }
   },
 
   /**
    * Close the editor and cleanup.
    */
   closeEditor: function TP_closeEditor()
   {
+    if (!this.treeBrowserDocument) // already closed, bug 706092
+      return;
+
     let editor = this.treeBrowserDocument.getElementById("attribute-editor");
+
     let editorInput =
       this.treeBrowserDocument.getElementById("attribute-editor-input");
 
     // remove highlight from attribute-value node in tree
     this.removeClass(this.editingContext.attrObj, "editingAttributeValue");
 
     // hide editor
     this.removeClass(editor, "editing");
--- a/browser/devtools/highlighter/test/browser_inspector_editor.js
+++ b/browser/devtools/highlighter/test/browser_inspector_editor.js
@@ -6,17 +6,21 @@
  * ***** END LICENSE BLOCK *****
  */
 
 let doc;
 let div;
 let editorTestSteps;
 
 function doNextStep() {
-  editorTestSteps.next();
+  try {
+    editorTestSteps.next();
+  } catch(exception) {
+    info("caught:", exception);
+  }
 }
 
 function setupEditorTests()
 {
   div = doc.createElement("div");
   div.setAttribute("id", "foobar");
   div.setAttribute("class", "barbaz");
   doc.body.appendChild(div);
@@ -209,26 +213,43 @@ function doEditorTestSteps()
 
   // single-click the `class` attribute-value node
   executeSoon(function() {
     EventUtils.synthesizeMouse(attrValNode_class, 2, 2, {}, attrValNode_class.ownerDocument.defaultView);
   });
 
   yield; // End of Step 7
 
-
   // Step 8: validate that the editor was closed and that the editing was not saved
   ok(!treePanel.editingContext, "Step 8: editor session ended");
   editorVisible = editor.classList.contains("editing");
   ok(!editorVisible, "editor popup hidden");
   is(div.getAttribute("id"), "Hello World", "`id` attribute-value *not* updated");
   is(attrValNode_id.innerHTML, "Hello World", "attribute-value node in HTML panel *not* updated");
+  executeSoon(doNextStep);
 
-  // End of Step 8
-  executeSoon(finishUp);
+  yield; // End of Step 8
+
+  // Step 9: Open the Editor and verify that closing the tree panel does not make the
+  // Inspector go cray-cray.
+  executeSoon(function() {
+    // firing 2 clicks right in a row to simulate a double-click
+    EventUtils.synthesizeMouse(attrValNode_id, 2, 2, {clickCount: 2}, attrValNode_id.ownerDocument.defaultView);
+    doNextStep();
+  });
+
+  yield; // End of Step 9
+
+  ok(treePanel.editingContext, "Step 9: editor session started");
+  editorVisible = editor.classList.contains("editing");
+  ok(editorVisible, "editor popup is visible");
+  executeSoon(function() {
+    InspectorUI.toggleHTMLPanel();
+    finishUp();
+  });
 }
 
 function finishUp() {
   // end of all steps, so clean up
   Services.obs.removeObserver(doNextStep, InspectorUI.INSPECTOR_NOTIFICATIONS.EDITOR_OPENED, false);
   Services.obs.removeObserver(doNextStep, InspectorUI.INSPECTOR_NOTIFICATIONS.EDITOR_CLOSED, false);
   Services.obs.removeObserver(doNextStep, InspectorUI.INSPECTOR_NOTIFICATIONS.EDITOR_SAVED, false);
   doc = div = null;
--- a/browser/devtools/scratchpad/scratchpad.js
+++ b/browser/devtools/scratchpad/scratchpad.js
@@ -486,19 +486,34 @@ var Scratchpad = {
 
   /**
    * Write out an error at the current insertion point as a block comment
    * @param object aValue
    *        The Error object to write out the message and stack trace
    */
   writeAsErrorComment: function SP_writeAsErrorComment(aError)
   {
-    let stack = aError.stack || aError.fileName + ":" + aError.lineNumber;
-    let newComment = "Exception: " + aError.message + "\n" + stack.replace(/\n$/, "");
+    let stack = "";
+    if (aError.stack) {
+      stack = aError.stack;
+    }
+    else if (aError.fileName) {
+      if (aError.lineNumber) {
+        stack = "@" + aError.fileName + ":" + aError.lineNumber;
+      }
+      else {
+        stack = "@" + aError.fileName;
+      }
+    }
+    else if (aError.lineNumber) {
+      stack = "@" + aError.lineNumber;
+    }
     
+    let newComment = "Exception: " + ( aError.message || aError) + ( stack == "" ? stack : "\n" + stack.replace(/\n$/, "") );
+
     this.writeAsComment(newComment);
   },
 
   /**
    * Open the Property Panel to inspect the given object.
    *
    * @param string aEvalString
    *        The string that was evaluated. This is re-used when the user updates
--- a/browser/devtools/scratchpad/test/Makefile.in
+++ b/browser/devtools/scratchpad/test/Makefile.in
@@ -27,11 +27,12 @@ MOCHITEST_BROWSER_FILES = \
 		browser_scratchpad_bug_669612_unsaved.js \
 		browser_scratchpad_bug_653427_confirm_close.js \
 		browser_scratchpad_bug684546_reset_undo.js \
 		browser_scratchpad_bug690552_display_outputs_errors.js \
 		browser_scratchpad_bug650345_find_ui.js \
 		browser_scratchpad_bug714942_goto_line_ui.js \
 		browser_scratchpad_bug_650760_help_key.js \
 		browser_scratchpad_bug_651942_recent_files.js \
+		browser_scratchpad_bug756681_display_non_error_exceptions.js \
 		head.js \
 
 include $(topsrcdir)/config/rules.mk
new file mode 100644
--- /dev/null
+++ b/browser/devtools/scratchpad/test/browser_scratchpad_bug756681_display_non_error_exceptions.js
@@ -0,0 +1,104 @@
+/* vim: set ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+function test()
+{
+  waitForExplicitFinish();
+
+  gBrowser.selectedTab = gBrowser.addTab();
+  gBrowser.selectedBrowser.addEventListener("load", function browserLoad() {
+    gBrowser.selectedBrowser.removeEventListener("load", browserLoad, true);
+    openScratchpad(runTests, {"state":{"text":""}});
+  }, true);
+
+  content.location = "data:text/html, test that exceptions are output as " +
+      "comments correctly in Scratchpad";
+}
+
+function runTests()
+{
+  var scratchpad = gScratchpadWindow.Scratchpad;
+
+  var message = "\"Hello World!\""
+  var openComment = "\n/*\n";
+  var closeComment = "\n*/";
+  var error1 = "throw new Error(\"Ouch!\")";
+  var error2 = "throw \"A thrown string\"";
+  var error3 = "throw {}";
+  var error4 = "document.body.appendChild(document.body)";
+  let messageArray = {};
+  let count = {};
+
+  // Display message
+  scratchpad.setText(message);
+  scratchpad.display();
+  is(scratchpad.getText(),
+      message + openComment + "Hello World!" + closeComment,
+      "message display output");
+
+  // Display error1, throw new Error("Ouch")
+  scratchpad.setText(error1);
+  scratchpad.display();
+  is(scratchpad.getText(),
+      error1 + openComment + "Exception: Ouch!\n@Scratchpad:1" + closeComment,
+      "error display output");
+
+  // Display error2, throw "A thrown string"
+  scratchpad.setText(error2);
+  scratchpad.display();
+  is(scratchpad.getText(),
+      error2 + openComment + "Exception: A thrown string" + closeComment,
+      "thrown string display output");
+
+  // Display error3, throw {}
+  scratchpad.setText(error3);
+  scratchpad.display();
+  is(scratchpad.getText(),
+      error3 + openComment + "Exception: [object Object]" + closeComment,
+      "thrown object display output");
+
+  // Display error4, document.body.appendChild(document.body)
+  scratchpad.setText(error4);
+  scratchpad.display();
+  is(scratchpad.getText(),
+      error4 + openComment + "Exception: Node cannot be inserted " +
+      "at the specified point in the hierarchy\n@1" + closeComment,
+      "Alternative format error display output");
+
+  // Run message
+  scratchpad.setText(message);
+  scratchpad.run();
+  is(scratchpad.getText(), message, "message run output");
+
+  // Run error1, throw new Error("Ouch")
+  scratchpad.setText(error1);
+  scratchpad.run();
+  is(scratchpad.getText(),
+      error1 + openComment + "Exception: Ouch!\n@Scratchpad:1" + closeComment,
+      "error run output");
+
+  // Run error2, throw "A thrown string"
+  scratchpad.setText(error2);
+  scratchpad.run();
+  is(scratchpad.getText(),
+      error2 + openComment + "Exception: A thrown string" + closeComment,
+      "thrown string run output");
+
+  // Run error3, throw {}
+  scratchpad.setText(error3);
+  scratchpad.run();
+  is(scratchpad.getText(),
+      error3 + openComment + "Exception: [object Object]" + closeComment,
+      "thrown object run output");
+
+  // Run error4, document.body.appendChild(document.body)
+  scratchpad.setText(error4);
+  scratchpad.run();
+  is(scratchpad.getText(),
+      error4 + openComment + "Exception: Node cannot be inserted " +
+      "at the specified point in the hierarchy\n@1" + closeComment,
+      "Alternative format error run output");
+
+  finish();
+}
--- a/browser/devtools/webconsole/HUDService-content.js
+++ b/browser/devtools/webconsole/HUDService-content.js
@@ -518,21 +518,21 @@ let Manager = {
 function JSTermHelper(aJSTerm)
 {
   /**
    * Find a node by ID.
    *
    * @param string aId
    *        The ID of the element you want.
    * @return nsIDOMNode or null
-   *         The result of calling document.getElementById(aId).
+   *         The result of calling document.querySelector(aSelector).
    */
-  aJSTerm.sandbox.$ = function JSTH_$(aId)
+  aJSTerm.sandbox.$ = function JSTH_$(aSelector)
   {
-    return aJSTerm.window.document.getElementById(aId);
+    return aJSTerm.window.document.querySelector(aSelector);
   };
 
   /**
    * Find the nodes matching a CSS selector.
    *
    * @param string aSelector
    *        A string that is passed to window.document.querySelectorAll.
    * @return nsIDOMNodeList
--- a/browser/devtools/webconsole/HUDService.jsm
+++ b/browser/devtools/webconsole/HUDService.jsm
@@ -606,29 +606,30 @@ WebConsole.prototype = {
     this.iframe.setAttribute("animated", "true");
     this.iframe.setAttribute("tooltip", "aHTMLTooltip");
     this.iframe.style.height = 0;
     this.iframe.addEventListener("load", this._onIframeLoad, true);
     this.iframe.setAttribute("src", UI_IFRAME_URL);
 
     let position = Services.prefs.getCharPref("devtools.webconsole.position");
     this.positionConsole(position);
-    this._currentUIPosition = position;
   },
 
   /**
    * The "load" event handler for the Web Console iframe.
    * @private
    */
   _onIframeLoad: function WC__onIframeLoad()
   {
     this.iframe.removeEventListener("load", this._onIframeLoad, true);
 
+    let position = Services.prefs.getCharPref("devtools.webconsole.position");
+
     this.iframeWindow = this.iframe.contentWindow.wrappedJSObject;
-    this.ui = new this.iframeWindow.WebConsoleFrame(this, this._currentUIPosition);
+    this.ui = new this.iframeWindow.WebConsoleFrame(this, position);
     this._setupMessageManager();
   },
 
   /**
    * Create a panel to open the web console if it should float above
    * the content in its own window.
    * @private
    */
@@ -690,18 +691,16 @@ WebConsole.prototype = {
       // Make sure that the HUDBox size updates when the panel is resized.
 
       let height = panel.clientHeight;
 
       this.iframe.style.height = "auto";
       this.iframe.flex = 1;
 
       panel.setAttribute("height", height);
-
-      this._afterPositionConsole("window", lastIndex);
     }).bind(this);
 
     panel.addEventListener("popupshown", onPopupShown,false);
 
     let onPopupHidden = (function HUD_onPopupHidden(aEvent) {
       if (aEvent.target != panel) {
         return;
       }
@@ -731,16 +730,19 @@ WebConsole.prototype = {
     if (this.outputNode && this.outputNode.getIndexOfFirstVisibleRow) {
       lastIndex = this.outputNode.getIndexOfFirstVisibleRow() +
                   this.outputNode.getNumberOfVisibleRows() - 1;
     }
 
     if (this.splitter.parentNode) {
       this.splitter.parentNode.removeChild(this.splitter);
     }
+
+    this._beforePositionConsole("window", lastIndex);
+
     panel.appendChild(this.iframe);
 
     let space = this.chromeDocument.createElement("spacer");
     space.flex = 1;
 
     let bottomBox = this.chromeDocument.createElement("hbox");
 
     let resizer = this.chromeDocument.createElement("resizer");
@@ -817,16 +819,18 @@ WebConsole.prototype = {
                   this.outputNode.getNumberOfVisibleRows() - 1;
     }
 
     // remove the console and splitter and reposition
     if (this.splitter.parentNode) {
       this.splitter.parentNode.removeChild(this.splitter);
     }
 
+    this._beforePositionConsole(aPosition, lastIndex);
+
     if (aPosition == "below") {
       nBox.appendChild(this.splitter);
       nBox.appendChild(this.iframe);
     }
     else {
       nBox.insertBefore(this.splitter, node);
       nBox.insertBefore(this.iframe, this.splitter);
     }
@@ -836,31 +840,29 @@ WebConsole.prototype = {
       this.consoleWindowUnregisterOnHide = false;
       this.consolePanel.hidePopup();
       this.consolePanel.parentNode.removeChild(this.consolePanel);
       this.consolePanel = null;   // remove this as we're not in panel anymore
       this.iframe.removeAttribute("flex");
       this.iframe.removeAttribute("height");
       this.iframe.style.height = height + "px";
     }
-
-    this._afterPositionConsole(aPosition, lastIndex);
   },
 
   /**
-   * Common code that needs to execute after the Web Console is repositioned.
+   * Common code that needs to execute before the Web Console is repositioned.
    * @private
    * @param string aPosition
    *        The new position: "above", "below" or "window".
    * @param number aLastIndex
    *        The last visible message in the console output before repositioning
    *        occurred.
    */
-  _afterPositionConsole:
-  function WC__afterPositionConsole(aPosition, aLastIndex)
+  _beforePositionConsole:
+  function WC__beforePositionConsole(aPosition, aLastIndex)
   {
     if (!this.ui) {
       return;
     }
 
     let onLoad = function() {
       this.iframe.removeEventListener("load", onLoad, true);
       this.iframeWindow = this.iframe.contentWindow.wrappedJSObject;
--- a/browser/devtools/webconsole/test/browser_webconsole_jsterm.js
+++ b/browser/devtools/webconsole/test/browser_webconsole_jsterm.js
@@ -47,17 +47,17 @@ function checkResult(msg, desc, lines) {
   });
 }
 
 function testJSTerm(hud)
 {
   jsterm = hud.jsterm;
 
   jsterm.clearOutput();
-  jsterm.execute("'id=' + $('header').getAttribute('id')");
+  jsterm.execute("'id=' + $('#header').getAttribute('id')");
   checkResult('"id=header"', "$() worked", 1);
   yield;
 
   jsterm.clearOutput();
   jsterm.execute("headerQuery = $$('h1')");
   jsterm.execute("'length=' + headerQuery.length");
   checkResult('"length=1"', "$$() worked", 2);
   yield;
--- a/browser/devtools/webconsole/test/browser_webconsole_position_ui.js
+++ b/browser/devtools/webconsole/test/browser_webconsole_position_ui.js
@@ -32,17 +32,17 @@ function testEnd() {
 
 function waitForPosition(aPosition, aCallback) {
   waitForSuccess({
     name: "web console position changed to '" + aPosition + "'",
     validatorFn: function()
     {
       return hudRef._currentUIPosition == aPosition;
     },
-    successFn: aCallback,
+    successFn: executeSoon.bind(null, aCallback),
     failureFn: finishTest,
   });
 }
 
 function consoleOpened(aHudRef) {
   hudRef = aHudRef;
   testMenuitems();
 
@@ -50,19 +50,20 @@ function consoleOpened(aHudRef) {
 
   is(hudBox.parentNode.childNodes[2].getAttribute("id"), hudRef.hudId,
      "initial console position is correct");
 
   is(hudRef.ui.positionMenuitems.below.getAttribute("checked"), "true",
      "position menu checkbox is below");
   is(Services.prefs.getCharPref(POSITION_PREF), "below", "pref is below");
 
-  hudRef.positionConsole("above");
-
-  waitForPosition("above", onPositionAbove);
+  executeSoon(function() {
+    hudRef.positionConsole("above");
+    waitForPosition("above", onPositionAbove);
+  });
 }
 
 function onPositionAbove() {
   let hudBox = hudRef.iframe;
 
   let id = hudBox.parentNode.childNodes[0].getAttribute("id");
   is(id, hudRef.hudId, "above position is correct");
 
@@ -76,18 +77,20 @@ function onPositionAbove() {
   hudBox.style.height = boxHeight + "px";
 
   boxHeight = hudBox.clientHeight;
 
   Services.prefs.setIntPref(WIDTH_PREF, panelWidth);
   Services.prefs.setIntPref(TOP_PREF, 50);
   Services.prefs.setIntPref(LEFT_PREF, 51);
 
-  hudRef.positionConsole("window");
-  waitForPosition("window", onPositionWindow);
+  executeSoon(function() {
+    hudRef.positionConsole("window");
+    waitForPosition("window", onPositionWindow);
+  });
 }
 
 function onPositionWindow() {
   let hudBox = hudRef.iframe;
 
   let id = hudBox.parentNode.getAttribute("id");
   is(id, "console_window_" + hudRef.hudId, "window position is correct");
   is(Services.prefs.getCharPref(POSITION_PREF), "window", "pref is window");
--- a/build/automation.py.in
+++ b/build/automation.py.in
@@ -814,17 +814,17 @@ user_pref("camino.use_system_proxy_setti
         # We should have a "crashinject" program in our utility path
         crashinject = os.path.normpath(os.path.join(utilityPath, "crashinject.exe"))
         if os.path.exists(crashinject) and subprocess.Popen([crashinject, str(proc.pid)]).wait() == 0:
           return
       #TODO: kill the process such that it triggers Breakpad on OS X (bug 525296)
     self.log.info("Can't trigger Breakpad, just killing process")
     proc.kill()
 
-  def waitForFinish(self, proc, utilityPath, timeout, maxTime, startTime, debuggerInfo, symbolsPath, logger):
+  def waitForFinish(self, proc, utilityPath, timeout, maxTime, startTime, debuggerInfo, symbolsPath):
     """ Look for timeout or crashes and return the status after the process terminates """
     stackFixerProcess = None
     stackFixerFunction = None
     didTimeout = False
     hitMaxTime = False
     if proc.stdout is None:
       self.log.info("TEST-INFO: Not logging stdout or stderr due to debugger connection")
     else:
@@ -851,18 +851,16 @@ user_pref("camino.use_system_proxy_setti
                                          stdout=subprocess.PIPE)
         logsource = stackFixerProcess.stdout
 
       (line, didTimeout) = self.readWithTimeout(logsource, timeout)
       while line != "" and not didTimeout:
         if stackFixerFunction:
           line = stackFixerFunction(line)
         self.log.info(line.rstrip().decode("UTF-8", "ignore"))
-        if logger:
-          logger.log(line)
         if "TEST-START" in line and "|" in line:
           self.lastTestSeen = line.split("|")[1].strip()
         if not debuggerInfo and "TEST-UNEXPECTED-FAIL" in line and "Test timed out" in line:
           if self.haveDumpedScreen:
             self.log.info("Not taking screenshot here: see the one that was previously logged")
           else:
             self.dumpScreen(utilityPath)
 
@@ -942,17 +940,17 @@ user_pref("camino.use_system_proxy_setti
           self.log.info("TEST-UNEXPECTED-FAIL | automation.py | child process %d still alive after shutdown", processPID)
           self.killPid(processPID)
 
   def checkForCrashes(self, profileDir, symbolsPath):
     automationutils.checkForCrashes(os.path.join(profileDir, "minidumps"), symbolsPath, self.lastTestSeen)
 
   def runApp(self, testURL, env, app, profileDir, extraArgs,
              runSSLTunnel = False, utilityPath = None,
-             xrePath = None, certPath = None, logger = None,
+             xrePath = None, certPath = None,
              debuggerInfo = None, symbolsPath = None,
              timeout = -1, maxTime = None):
     """
     Run the app, log the duration it took to execute, return the status code.
     Kills the app if it runs for longer than |maxTime| seconds, or outputs nothing for |timeout| seconds.
     """
 
     if utilityPath == None:
@@ -1001,17 +999,17 @@ user_pref("camino.use_system_proxy_setti
     self.lastTestSeen = "automation.py"
     proc = self.Process([cmd] + args,
                  env = self.environment(env, xrePath = xrePath,
                                    crashreporter = not debuggerInfo),
                  stdout = outputPipe,
                  stderr = subprocess.STDOUT)
     self.log.info("INFO | automation.py | Application pid: %d", proc.pid)
 
-    status = self.waitForFinish(proc, utilityPath, timeout, maxTime, startTime, debuggerInfo, symbolsPath, logger)
+    status = self.waitForFinish(proc, utilityPath, timeout, maxTime, startTime, debuggerInfo, symbolsPath)
     self.log.info("INFO | automation.py | Application ran for: %s", str(datetime.now() - startTime))
 
     # Do a final check for zombie child processes.
     self.checkForZombies(processLog)
     self.checkForCrashes(profileDir, symbolsPath)
 
     if os.path.exists(processLog):
       os.unlink(processLog)
--- a/build/automationutils.py
+++ b/build/automationutils.py
@@ -2,30 +2,28 @@
 # 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/.
 
 from __future__ import with_statement
 import glob, logging, os, platform, shutil, subprocess, sys, tempfile, urllib2, zipfile
 import re
 from urlparse import urlparse
-from operator import itemgetter
 
 __all__ = [
   "ZipFileReader",
   "addCommonOptions",
   "checkForCrashes",
   "dumpLeakLog",
   "isURL",
   "processLeakLog",
   "getDebuggerInfo",
   "DEBUGGER_INFO",
   "replaceBackSlashes",
   "wrapCommand",
-  "ShutdownLeakLogger"
   ]
 
 # Map of debugging programs to information about them, like default arguments
 # and whether or not they are interactive.
 DEBUGGER_INFO = {
   # gdb requires that you supply the '--args' flag in order to pass arguments
   # after the executable name to the executable.
   "gdb": {
@@ -414,120 +412,8 @@ def wrapCommand(cmd):
   binary.
   """
   if platform.system() == "Darwin" and \
      hasattr(platform, 'mac_ver') and \
      platform.mac_ver()[0][:4] < '10.6':
     return ["arch", "-arch", "i386"] + cmd
   # otherwise just execute the command normally
   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
-
-  def __init__(self, logger):
-    self.logger = logger
-    self.tests = []
-    self.leakedWindows = {}
-    self.leakedDocShells = set()
-    self.currentTest = None
-    self.seenShutdown = False
-
-  def log(self, line):
-    if line[2:11] == "DOMWINDOW":
-      self._logWindow(line)
-    elif line[2:10] == "DOCSHELL":
-      self._logDocShell(line)
-    elif line.startswith("TEST-START"):
-      fileName = line.split(" ")[-1].strip().replace("chrome://mochitests/content/browser/", "")
-      self.currentTest = {"fileName": fileName, "windows": set(), "docShells": set()}
-    elif line.startswith("INFO TEST-END"):
-      # don't track a test if no windows or docShells leaked
-      if self.currentTest and (self.currentTest["windows"] or self.currentTest["docShells"]):
-        self.tests.append(self.currentTest)
-      self.currentTest = None
-    elif line.startswith("INFO TEST-START | Shutdown"):
-      self.seenShutdown = True
-
-  def parse(self):
-    leakingTests = self._parseLeakingTests()
-
-    if leakingTests:
-      totalWindows = sum(len(test["leakedWindows"]) for test in leakingTests)
-      totalDocShells = sum(len(test["leakedDocShells"]) for test in leakingTests)
-      msgType = "TEST-INFO" if totalWindows + totalDocShells <= self.MAX_LEAK_COUNT else "TEST-UNEXPECTED-FAIL"
-      self.logger.info("%s | ShutdownLeaks | leaked %d DOMWindow(s) and %d DocShell(s) until shutdown", msgType, totalWindows, totalDocShells)
-
-    for test in leakingTests:
-      for url, count in self._zipLeakedWindows(test["leakedWindows"]):
-        self.logger.info("%s | %s | leaked %d window(s) until shutdown [url = %s]", msgType, test["fileName"], count, url)
-
-      if test["leakedDocShells"]:
-        self.logger.info("%s | %s | leaked %d docShell(s) until shutdown", msgType, test["fileName"], len(test["leakedDocShells"]))
-
-  def _logWindow(self, line):
-    created = line[:2] == "++"
-    id = self._parseValue(line, "serial")
-
-    # log line has invalid format
-    if not id:
-      return
-
-    if self.currentTest:
-      windows = self.currentTest["windows"]
-      if created:
-        windows.add(id)
-      else:
-        windows.discard(id)
-    elif self.seenShutdown and not created:
-      self.leakedWindows[id] = self._parseValue(line, "url")
-
-  def _logDocShell(self, line):
-    created = line[:2] == "++"
-    id = self._parseValue(line, "id")
-
-    # log line has invalid format
-    if not id:
-      return
-
-    if self.currentTest:
-      docShells = self.currentTest["docShells"]
-      if created:
-        docShells.add(id)
-      else:
-        docShells.discard(id)
-    elif self.seenShutdown and not created:
-      self.leakedDocShells.add(id)
-
-  def _parseValue(self, line, name):
-    match = re.search("\[%s = (.+?)\]" % name, line)
-    if match:
-      return match.group(1)
-    return None
-
-  def _parseLeakingTests(self):
-    leakingTests = []
-
-    for test in self.tests:
-      test["leakedWindows"] = [self.leakedWindows[id] for id in test["windows"] if id in self.leakedWindows]
-      test["leakedDocShells"] = [id for id in test["docShells"] if id in self.leakedDocShells]
-      test["leakCount"] = len(test["leakedWindows"]) + len(test["leakedDocShells"])
-
-      if test["leakCount"]:
-        leakingTests.append(test)
-
-    return sorted(leakingTests, key=itemgetter("leakCount"), reverse=True)
-
-  def _zipLeakedWindows(self, leakedWindows):
-    counts = []
-    counted = set()
-
-    for url in leakedWindows:
-      if not url in counted:
-        counts.append((url, leakedWindows.count(url)))
-        counted.add(url)
-
-    return sorted(counts, key=itemgetter(1), reverse=True)
--- 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/remoteautomation.py
+++ b/build/mobile/remoteautomation.py
@@ -57,17 +57,17 @@ class RemoteAutomation(Automation):
         if crashreporter:
             env['MOZ_CRASHREPORTER_NO_REPORT'] = '1'
             env['MOZ_CRASHREPORTER'] = '1'
         else:
             env['MOZ_CRASHREPORTER_DISABLE'] = '1'
 
         return env
 
-    def waitForFinish(self, proc, utilityPath, timeout, maxTime, startTime, debuggerInfo, symbolsDir, logger):
+    def waitForFinish(self, proc, utilityPath, timeout, maxTime, startTime, debuggerInfo, symbolsDir):
         # maxTime is used to override the default timeout, we should honor that
         status = proc.wait(timeout = maxTime)
 
         print proc.stdout
 
         if (status == 1 and self._devicemanager.processExist(proc.procName)):
             # Then we timed out, make sure Fennec is dead
             proc.kill()
--- 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/public/nsDOMFile.h
+++ b/content/base/public/nsDOMFile.h
@@ -50,16 +50,34 @@ public:
   virtual const nsTArray<nsCOMPtr<nsIDOMBlob> >*
   GetSubBlobs() const { return nullptr; }
 
   NS_DECL_NSIDOMBLOB
   NS_DECL_NSIDOMFILE
   NS_DECL_NSIXHRSENDABLE
   NS_DECL_NSIMUTABLE
 
+  void
+  SetLazyData(const nsAString& aName, const nsAString& aContentType,
+              PRUint64 aLength)
+  {
+    NS_ASSERTION(aLength, "must have length");
+
+    mName = aName;
+    mContentType = aContentType;
+    mLength = aLength;
+
+    mIsFile = !aName.IsVoid();
+  }
+
+  bool IsSizeUnknown() const
+  {
+    return mLength == UINT64_MAX;
+  }
+
 protected:
   nsDOMFileBase(const nsAString& aName, const nsAString& aContentType,
                 PRUint64 aLength)
     : mIsFile(true), mImmutable(false), mContentType(aContentType),
       mName(aName), mStart(0), mLength(aLength)
   {
     // Ensure non-null mContentType by default
     mContentType.SetIsVoid(false);
@@ -81,21 +99,16 @@ protected:
     NS_ASSERTION(aLength != UINT64_MAX,
                  "Must know length when creating slice");
     // Ensure non-null mContentType by default
     mContentType.SetIsVoid(false);
   }
 
   virtual ~nsDOMFileBase() {}
 
-  bool IsSizeUnknown() const
-  {
-    return mLength == UINT64_MAX;
-  }
-
   virtual bool IsStoredFile() const
   {
     return false;
   }
 
   virtual bool IsWholeFile() const
   {
     NS_NOTREACHED("Should only be called on dom blobs backed by files!");
--- 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/content/media/test/Makefile.in
+++ b/content/media/test/Makefile.in
@@ -100,47 +100,53 @@ MOCHITEST_FILES = \
 		test_playback_errors.html \
 		test_seekable1.html \
 		test_preload_actions.html \
 		test_preload_attribute.html \
 		test_progress.html \
 		test_reactivate.html \
 		test_readyState.html \
 		test_replay_metadata.html \
-		test_seek.html \
 		test_seek2.html \
-		test_seek_out_of_range.html \
 		test_source.html \
 		test_source_write.html \
 	        test_source_null.html \
 		test_standalone.html \
 		test_streams_element_capture.html \
 		test_streams_element_capture_reset.html \
-		test_timeupdate_small_files.html \
 		test_too_many_elements.html \
 		test_volume.html \
 		test_video_to_canvas.html \
 		use_large_cache.js \
 		test_audiowrite.html \
 		test_mozHasAudio.html \
 		test_source_media.html \
-		$(NULL)
-
-# Bug 759221
-MOCHITEST_FILES += \
 		test_autoplay_contentEditable.html \
 		test_buffered.html \
 		test_bug448534.html \
 		test_bug463162.xhtml \
 		test_decoder_disable.html \
 		test_media_selection.html \
 		test_playback.html \
 		test_seekLies.html \
 		$(NULL)
 
+# Tests disabled on Linux for frequent intermittent failures
+ifneq (Linux,$(OS_ARCH))
+MOCHITEST_FILES += \
+		test_seek.html \
+		test_seek_out_of_range.html \
+		test_timeupdate_small_files.html \
+		$(NULL)
+else
+$(warning test_seek.html is disabled on Linux for timeouts. Bug 620598)
+$(warning test_seek_out_of_range.html is disabled on Linux for timeouts. Bug 661076)
+$(warning test_timeupdate_small_files.html is disabled on Linux for timeouts. Bug 687972)
+endif
+
 # Don't run in suite
 ifndef MOZ_SUITE
 MOCHITEST_FILES += test_play_twice.html
 else
 $(warning test_play_twice.html is disabled pending investigation. Bug 598252)
 endif
 
 # These tests are disabled until we figure out random failures.
--- a/content/media/test/manifest.js
+++ b/content/media/test/manifest.js
@@ -2,29 +2,29 @@
 // be ignored. To make sure tests respect that, we include a file of type
 // "bogus/duh" in each list.
 
 // These are small test files, good for just seeing if something loads. We
 // really only need one test file per backend here.
 var gSmallTests = [
   { name:"small-shot.ogg", type:"audio/ogg", duration:0.276 },
   { name:"r11025_s16_c1.wav", type:"audio/x-wav", duration:1.0 },
-  { name:"320x240.ogv", type:"video/ogg", width:320, height:240, duration:0.233 },
+  { name:"320x240.ogv", type:"video/ogg", width:320, height:240, duration:0.266 },
   { name:"seek.webm", type:"video/webm", width:320, height:240, duration:3.966 },
   { name:"detodos.opus", type:"audio/ogg; codecs=opus", duration:2.9135 },
   { name:"bogus.duh", type:"bogus/duh" }
 ];
 
 // Used by test_progress to ensure we get the correct progress information
 // during resource download.
 var gProgressTests = [
   { name:"r11025_u8_c1.wav", type:"audio/x-wav", duration:1.0, size:11069 },
   { name:"big.wav", type:"audio/x-wav", duration:9.278981, size:102444 },
   { name:"seek.ogv", type:"video/ogg", duration:3.966, size:285310 },
-  { name:"320x240.ogv", type:"video/ogg", width:320, height:240, duration:0.233, size:28942 },
+  { name:"320x240.ogv", type:"video/ogg", width:320, height:240, duration:0.266, size:28942 },
   { name:"seek.webm", type:"video/webm", duration:3.966, size:215529 },
   { name:"bogus.duh", type:"bogus/duh" }
 ];
 
 // Used by test_played.html
 var gPlayedTests = [
   { name:"big.wav", type:"audio/x-wav", duration:9.0 },
   { name:"sound.ogg", type:"audio/ogg", duration:4.0 },
@@ -35,17 +35,17 @@ var gPlayedTests = [
 // Used by test_mozLoadFrom.  Need one test file per decoder backend, plus
 // anything for testing clone-specific bugs.
 var cloneKey = Math.floor(Math.random()*100000000);
 var gCloneTests = gSmallTests.concat([
   // Actual duration is ~200ms, we have Content-Duration lie about it.
   { name:"bug520908.ogv", type:"video/ogg", duration:9000 },
   // short-video is more like 1s, so if you load this twice you'll get an unexpected duration
   { name:"dynamic_resource.sjs?key=" + cloneKey + "&res1=320x240.ogv&res2=short-video.ogv",
-    type:"video/ogg", duration:0.233 },
+    type:"video/ogg", duration:0.266 },
 ]);
 
 // Used by test_play_twice.  Need one test file per decoder backend, plus
 // anything for testing bugs that occur when replying a played file.
 var gReplayTests = gSmallTests.concat([
   { name:"bug533822.ogg", type:"audio/ogg" },
 ]);
 
@@ -54,17 +54,17 @@ var gReplayTests = gSmallTests.concat([
 var gPausedAfterEndedTests = gSmallTests.concat([
   { name:"r11025_u8_c1.wav", type:"audio/x-wav", duration:1.0 },
   { name:"small-shot.ogg", type:"video/ogg", duration:0.276 }
 ]);
 
 // Test the mozHasAudio property
 var gMozHasAudioTests = [
   { name:"big.wav", type:"audio/x-wav", duration:9.278981, size:102444, hasAudio:undefined },
-  { name:"320x240.ogv", type:"video/ogg", width:320, height:240, duration:0.233, size:28942, hasAudio:false },
+  { name:"320x240.ogv", type:"video/ogg", width:320, height:240, duration:0.266, size:28942, hasAudio:false },
   { name:"short-video.ogv", type:"video/ogg", duration:1.081, hasAudio:true },
   { name:"seek.webm", type:"video/webm", duration:3.966, size:215529, hasAudio:false },
   { name:"bogus.duh", type:"bogus/duh" }
 ];
 
 // These are files that we want to make sure we can play through.  We can
 // also check metadata.  Put files of the same type together in this list so if
 // something crashes we have some idea of which backend is responsible.
@@ -123,17 +123,17 @@ var gPlayTests = [
   { name:"audio-overhang.ogg", type:"audio/ogg", duration:2.3 },
   { name:"video-overhang.ogg", type:"audio/ogg", duration:3.966 },
 
   // bug461281.ogg with the middle second chopped out.
   { name:"audio-gaps.ogg", type:"audio/ogg", duration:2.208 },
 
   // Test playback/metadata work after a redirect
   { name:"redirect.sjs?domain=mochi.test:8888&file=320x240.ogv",
-    type:"video/ogg", duration:0.233 },
+    type:"video/ogg", duration:0.266 },
 
   // Test playback of a webm file
   { name:"seek.webm", type:"video/webm", duration:3.966 },
 
   // Test playback of a WebM file with non-zero start time.
   { name:"split.webm", type:"video/webm", duration:1.967 },
   
   // Test playback of a raw file
@@ -253,17 +253,17 @@ var gErrorTests = [
   { name:"bogus.duh", type:"bogus/duh" }
 ];
 
 // These are files that have nontrivial duration and are useful for seeking within.
 var gSeekTests = [
   { name:"r11025_s16_c1.wav", type:"audio/x-wav", duration:1.0 },
   { name:"audio.wav", type:"audio/x-wav", duration:0.031247 },
   { name:"seek.ogv", type:"video/ogg", duration:3.966 },
-  { name:"320x240.ogv", type:"video/ogg", duration:0.233 },
+  { name:"320x240.ogv", type:"video/ogg", duration:0.266 },
   { name:"seek.webm", type:"video/webm", duration:3.966 },
   { name:"bug516323.indexed.ogv", type:"video/ogg", duration:4.208 },
   { name:"split.webm", type:"video/webm", duration:1.967 },
   { name:"detodos.opus", type:"audio/ogg; codecs=opus", duration:2.9135 },
   { name:"bogus.duh", type:"bogus/duh", duration:123 }
 ];
 
 // These are files suitable for using with a "new Audio" constructor.
--- a/content/media/test/test_timeupdate_small_files.html
+++ b/content/media/test/test_timeupdate_small_files.html
@@ -49,17 +49,21 @@ function ended(e) {
     500);
 }
 
 var eventsToLog = ["play", "canplay", "canplaythrough", "loadstart", "loadedmetadata",
   "loadeddata", "playing", "progress", "timeupdate", "ended", "suspend", "error", "stalled", "emptied", "abort",
   "waiting", "pause"];
 function logEvent(event) {
   if (event.target.gotEnded > (event.type == "ended" ? 1 : 0)) {
-    ok(false, event.target.currentSrc + " got unexpected " + event.type + " after ended");
+    if (event.target.currentSrc.slice(-9) == "seek.webm" && event.type == "stalled") {
+      todo(false, event.target.currentSrc + " got unexpected stalled after ended (bug 760770)");
+    } else {
+      ok(false, event.target.currentSrc + " got unexpected " + event.type + " after ended");
+    }
   } else {
     info(event.target.currentSrc + " got " + event.type);
   }
 }
 
 function startTest(test, token) {
   var type = /^video/.test(test.type) ? "video" : "audio";
   var v = document.createElement(type);
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -187,16 +187,19 @@
 
 #include "nsXULAppAPI.h"
 
 #include "nsDOMNavigationTiming.h"
 #include "nsITimedChannel.h"
 #include "mozilla/StartupTimeline.h"
 #include "nsIFrameMessageManager.h"
 
+#include "mozilla/Telemetry.h"
+#include "nsISecurityUITelemetry.h"
+
 static NS_DEFINE_CID(kDOMScriptObjectFactoryCID,
                      NS_DOM_SCRIPT_OBJECT_FACTORY_CID);
 static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID);
 
 #if defined(DEBUG_bryner) || defined(DEBUG_chb)
 //#define DEBUG_DOCSHELL_FOCUS
 #define DEBUG_PAGE_CACHE
 #endif
@@ -4035,30 +4038,42 @@ nsDocShell::DisplayLoadError(nsresult aE
                 nsCOMPtr<nsIStrictTransportSecurityService> stss =
                           do_GetService(NS_STSSERVICE_CONTRACTID, &rv);
                 NS_ENSURE_SUCCESS(rv, rv);
 
                 bool isStsHost = false;
                 rv = stss->IsStsURI(aURI, &isStsHost);
                 NS_ENSURE_SUCCESS(rv, rv);
 
-                if (isStsHost)
+                PRUint32 bucketId;
+                if (isStsHost) {
                   cssClass.AssignLiteral("badStsCert");
+                  //measuring STS separately allows us to measure click through
+                  //rates easily
+                  bucketId = nsISecurityUITelemetry::WARNING_BAD_CERT_STS;
+                } else {
+                  bucketId = nsISecurityUITelemetry::WARNING_BAD_CERT;
+                }
+
 
                 if (Preferences::GetBool(
                         "browser.xul.error_pages.expert_bad_cert", false)) {
                     cssClass.AssignLiteral("expertBadCert");
                 }
 
                 // See if an alternate cert error page is registered
                 nsAdoptingCString alternateErrorPage =
                     Preferences::GetCString(
                         "security.alternate_certificate_error_page");
                 if (alternateErrorPage)
                     errorPage.Assign(alternateErrorPage);
+
+                if (errorPage.EqualsIgnoreCase("certerror")) 
+                    mozilla::Telemetry::Accumulate(mozilla::Telemetry::SECURITY_UI, bucketId);
+
             } else {
                 error.AssignLiteral("nssFailure2");
             }
         }
     } else if (NS_ERROR_PHISHING_URI == aError || NS_ERROR_MALWARE_URI == aError) {
         nsCAutoString host;
         aURI->GetHost(host);
         CopyUTF8toUTF16(host, formatStrs[0]);
@@ -4066,20 +4081,29 @@ nsDocShell::DisplayLoadError(nsresult aE
 
         // Malware and phishing detectors may want to use an alternate error
         // page, but if the pref's not set, we'll fall back on the standard page
         nsAdoptingCString alternateErrorPage =
             Preferences::GetCString("urlclassifier.alternate_error_page");
         if (alternateErrorPage)
             errorPage.Assign(alternateErrorPage);
 
-        if (NS_ERROR_PHISHING_URI == aError)
+        PRUint32 bucketId;
+        if (NS_ERROR_PHISHING_URI == aError) {
             error.AssignLiteral("phishingBlocked");
-        else
+            bucketId = nsISecurityUITelemetry::WARNING_PHISHING_PAGE;
+        } else {
             error.AssignLiteral("malwareBlocked");
+            bucketId = nsISecurityUITelemetry::WARNING_MALWARE_PAGE;
+        }
+
+        if (errorPage.EqualsIgnoreCase("blocked"))
+            mozilla::Telemetry::Accumulate(mozilla::Telemetry::SECURITY_UI,
+                                           bucketId);
+
         cssClass.AssignLiteral("blacklist");
     }
     else {
         // Errors requiring simple formatting
         switch (aError) {
         case NS_ERROR_MALFORMED_URI:
             // URI is malformed
             error.AssignLiteral("malformedURI");
@@ -11376,17 +11400,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/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -1241,16 +1241,22 @@ NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_
   return tmp->IsBlackForCC();
 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END
 
 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(nsGlobalWindow)
   return tmp->IsBlackForCC();
 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsGlobalWindow)
+  if (NS_UNLIKELY(cb.WantDebugInfo())) {
+    char name[512];
+    PR_snprintf(name, sizeof(name), "nsGlobalWindow #%ld", tmp->mWindowID);
+    cb.DescribeRefCountedNode(tmp->mRefCnt.get(), sizeof(nsGlobalWindow), name);
+  }
+
   if (!cb.WantAllTraces() && tmp->IsBlackForCC()) {
     return NS_SUCCESS_INTERRUPTED_TRAVERSE;
   }
 
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mContext)
 
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mControllers)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mArguments)
--- 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/indexedDB/IDBObjectStore.cpp
+++ b/dom/indexedDB/IDBObjectStore.cpp
@@ -3,16 +3,17 @@
 /* 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 "base/basictypes.h"
 
 #include "IDBObjectStore.h"
 
+#include "mozilla/dom/ipc/nsIRemoteBlob.h"
 #include "nsIJSContextStack.h"
 #include "nsIOutputStream.h"
 
 #include "jsfriendapi.h"
 #include "mozilla/dom/ContentChild.h"
 #include "mozilla/dom/ContentParent.h"
 #include "mozilla/dom/StructuredCloneTags.h"
 #include "mozilla/dom/ipc/Blob.h"
@@ -580,16 +581,57 @@ GetAddInfoCallback(JSContext* aCx, void*
   if (!IDBObjectStore::SerializeValue(aCx, data->mCloneWriteInfo,
                                       data->mValue)) {
     return NS_ERROR_DOM_DATA_CLONE_ERR;
   }
 
   return NS_OK;
 }
 
+inline
+BlobChild*
+ActorFromRemoteBlob(nsIDOMBlob* aBlob)
+{
+  NS_ASSERTION(!IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
+  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+
+  nsCOMPtr<nsIRemoteBlob> remoteBlob = do_QueryInterface(aBlob);
+  if (remoteBlob) {
+    BlobChild* actor =
+      static_cast<BlobChild*>(static_cast<PBlobChild*>(remoteBlob->GetPBlob()));
+    NS_ASSERTION(actor, "Null actor?!");
+    return actor;
+  }
+  return nullptr;
+}
+
+inline
+bool
+ResolveMysteryBlob(nsIDOMBlob* aBlob, const nsString& aName,
+                   const nsString& aContentType, PRUint64 aSize)
+{
+  BlobChild* actor = ActorFromRemoteBlob(aBlob);
+  if (actor) {
+    return actor->SetMysteryBlobInfo(aName, aContentType, aSize);
+  }
+  return true;
+}
+
+inline
+bool
+ResolveMysteryBlob(nsIDOMBlob* aBlob, const nsString& aContentType,
+                   PRUint64 aSize)
+{
+  BlobChild* actor = ActorFromRemoteBlob(aBlob);
+  if (actor) {
+    return actor->SetMysteryBlobInfo(aContentType, aSize);
+  }
+  return true;
+}
+
 } // anonymous namespace
 
 JSClass IDBObjectStore::sDummyPropJSClass = {
   "dummy", 0,
   JS_PropertyStub,  JS_PropertyStub,
   JS_PropertyStub,  JS_StrictPropertyStub,
   JS_EnumerateStub, JS_ResolveStub,
   JS_ConvertStub
@@ -1093,16 +1135,19 @@ IDBObjectStore::StructuredCloneReadCallb
         NS_WARNING("Failed to get file!");
         return nullptr;
       }
     }
 
     if (aTag == SCTAG_DOM_BLOB) {
       nsCOMPtr<nsIDOMBlob> domBlob;
       if (file.mFile) {
+        if (!ResolveMysteryBlob(file.mFile, convType, size)) {
+          return nullptr;
+        }
         domBlob = file.mFile;
       }
       else {
         domBlob = new nsDOMFileFile(convType, size, nativeFile, fileInfo);
       }
 
       jsval wrappedBlob;
        rv =
@@ -1121,16 +1166,19 @@ IDBObjectStore::StructuredCloneReadCallb
     nsCString name;
     if (!StructuredCloneReadString(aReader, name)) {
       return nullptr;
     }
     NS_ConvertUTF8toUTF16 convName(name);
 
     nsCOMPtr<nsIDOMFile> domFile;
     if (file.mFile) {
+      if (!ResolveMysteryBlob(file.mFile, convName, convType, size)) {
+        return nullptr;
+      }
       domFile = do_QueryInterface(file.mFile);
       NS_ASSERTION(domFile, "This should never fail!");
     }
     else {
       domFile = new nsDOMFileFile(convName, convType, size, nativeFile,
                                   fileInfo);
     }
 
--- a/dom/indexedDB/test/test_blob_simple.html
+++ b/dom/indexedDB/test/test_blob_simple.html
@@ -177,16 +177,15 @@
     event = yield;
 
     is(event.data, BLOB_DATA[0][1], "Correct text");
 
     finishTest();
     yield;
   }
   </script>
-  <script type="text/javascript;version=1.7" src="file.js"></script>
   <script type="text/javascript;version=1.7" src="helpers.js"></script>
 
 </head>
 
 <body onload="runTest();"></body>
 
 </html>
--- 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/Blob.cpp
+++ b/dom/ipc/Blob.cpp
@@ -10,16 +10,17 @@
 
 #include "nsIDOMFile.h"
 #include "nsIInputStream.h"
 #include "nsIRemoteBlob.h"
 #include "nsISeekableStream.h"
 
 #include "mozilla/Assertions.h"
 #include "mozilla/Monitor.h"
+#include "mozilla/unused.h"
 #include "mozilla/net/NeckoMessageUtils.h"
 #include "nsDOMFile.h"
 #include "nsThreadUtils.h"
 
 #include "ContentChild.h"
 #include "ContentParent.h"
 
 using namespace mozilla::dom;
@@ -296,16 +297,26 @@ SetBlobOnParams(BlobChild* aActor, Slice
 
 inline
 void
 SetBlobOnParams(BlobParent* aActor, SlicedBlobConstructorParams& aParams)
 {
   aParams.sourceParent() = aActor;
 }
 
+inline
+nsDOMFileBase*
+ToConcreteBlob(nsIDOMBlob* aBlob)
+{
+  // XXX This is only safe so long as all blob implementations in our tree
+  //     inherit nsDOMFileBase. If that ever changes then this will need to grow
+  //     a real interface or something.
+  return static_cast<nsDOMFileBase*>(aBlob);
+}
+
 } // anonymous namespace
 
 namespace mozilla {
 namespace dom {
 namespace ipc {
 
 template <ActorFlavorEnum ActorFlavor>
 class RemoteBlob : public nsDOMFile,
@@ -525,23 +536,33 @@ private:
       }
     }
   };
 
 public:
   NS_DECL_ISUPPORTS_INHERITED
 
   RemoteBlob(const nsAString& aName, const nsAString& aContentType,
-              PRUint64 aLength)
+             PRUint64 aLength)
   : nsDOMFile(aName, aContentType, aLength), mActor(nullptr)
-  { }
+  {
+    mImmutable = true;
+  }
 
   RemoteBlob(const nsAString& aContentType, PRUint64 aLength)
   : nsDOMFile(aContentType, aLength), mActor(nullptr)
-  { }
+  {
+    mImmutable = true;
+  }
+
+  RemoteBlob()
+  : nsDOMFile(EmptyString(), EmptyString(), UINT64_MAX), mActor(nullptr)
+  {
+    mImmutable = true;
+  }
 
   virtual ~RemoteBlob()
   {
     if (mActor) {
       mActor->NoteDyingRemoteBlob();
     }
   }
 
@@ -589,68 +610,77 @@ public:
 };
 
 } // namespace ipc
 } // namespace dom
 } // namespace mozilla
 
 template <ActorFlavorEnum ActorFlavor>
 Blob<ActorFlavor>::Blob(nsIDOMBlob* aBlob)
-: mBlob(aBlob), mRemoteBlob(nullptr), mOwnsBlob(true)
+: mBlob(aBlob), mRemoteBlob(nullptr), mOwnsBlob(true), mBlobIsFile(false)
 {
+  MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aBlob);
   aBlob->AddRef();
+
+  nsCOMPtr<nsIDOMFile> file = do_QueryInterface(aBlob);
+  mBlobIsFile = !!file;
 }
 
 template <ActorFlavorEnum ActorFlavor>
 Blob<ActorFlavor>::Blob(const BlobConstructorParams& aParams)
-: mBlob(nullptr), mRemoteBlob(nullptr), mOwnsBlob(true)
+: mBlob(nullptr), mRemoteBlob(nullptr), mOwnsBlob(false), mBlobIsFile(false)
 {
+  MOZ_ASSERT(NS_IsMainThread());
+
   nsRefPtr<RemoteBlobType> remoteBlob;
 
   switch (aParams.type()) {
     case BlobConstructorParams::TNormalBlobConstructorParams: {
       const NormalBlobConstructorParams& params =
         aParams.get_NormalBlobConstructorParams();
       remoteBlob = new RemoteBlobType(params.contentType(), params.length());
       break;
     }
 
     case BlobConstructorParams::TFileBlobConstructorParams: {
       const FileBlobConstructorParams& params =
         aParams.get_FileBlobConstructorParams();
       remoteBlob =
         new RemoteBlobType(params.name(), params.contentType(),
                            params.length());
+      mBlobIsFile = true;
+      break;
+    }
+
+    case BlobConstructorParams::TMysteryBlobConstructorParams: {
+      remoteBlob = new RemoteBlobType();
+      mBlobIsFile = true;
       break;
     }
 
     default:
       MOZ_NOT_REACHED("Unknown params!");
   }
 
   MOZ_ASSERT(remoteBlob);
 
-  if (NS_FAILED(remoteBlob->SetMutable(false))) {
-    MOZ_NOT_REACHED("Failed to make remote blob immutable!");
-  }
-
-  remoteBlob->SetActor(this);
-  remoteBlob.forget(&mRemoteBlob);
-
-  mBlob = mRemoteBlob;
+  SetRemoteBlob(remoteBlob);
 }
 
 template <ActorFlavorEnum ActorFlavor>
 Blob<ActorFlavor>*
 Blob<ActorFlavor>::Create(const BlobConstructorParams& aParams)
 {
+  MOZ_ASSERT(NS_IsMainThread());
+
   switch (aParams.type()) {
     case BlobConstructorParams::TNormalBlobConstructorParams:
     case BlobConstructorParams::TFileBlobConstructorParams:
+    case BlobConstructorParams::TMysteryBlobConstructorParams:
       return new Blob<ActorFlavor>(aParams);
 
     case BlobConstructorParams::TSlicedBlobConstructorParams: {
       const SlicedBlobConstructorParams& params =
         aParams.get_SlicedBlobConstructorParams();
 
       nsCOMPtr<nsIDOMBlob> source = GetBlobFromParams<ActorFlavor>(params);
       MOZ_ASSERT(source);
@@ -670,16 +700,17 @@ Blob<ActorFlavor>::Create(const BlobCons
 
   return nullptr;
 }
 
 template <ActorFlavorEnum ActorFlavor>
 already_AddRefed<nsIDOMBlob>
 Blob<ActorFlavor>::GetBlob()
 {
+  MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(mBlob);
 
   nsCOMPtr<nsIDOMBlob> blob;
 
   // Remote blobs are held alive until the first call to GetBlob. Thereafter we
   // only hold a weak reference. Normal blobs are held alive until the actor is
   // destroyed.
   if (mRemoteBlob && mOwnsBlob) {
@@ -691,81 +722,185 @@ Blob<ActorFlavor>::GetBlob()
   }
 
   MOZ_ASSERT(blob);
 
   return blob.forget();
 }
 
 template <ActorFlavorEnum ActorFlavor>
+bool
+Blob<ActorFlavor>::SetMysteryBlobInfo(const nsString& aName,
+                                      const nsString& aContentType,
+                                      PRUint64 aLength)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(mBlob);
+  MOZ_ASSERT(mRemoteBlob);
+  MOZ_ASSERT(aLength);
+
+  ToConcreteBlob(mBlob)->SetLazyData(aName, aContentType, aLength);
+
+  FileBlobConstructorParams params(aName, aContentType, aLength);
+  return BaseType::SendResolveMystery(params);
+}
+
+template <ActorFlavorEnum ActorFlavor>
+bool
+Blob<ActorFlavor>::SetMysteryBlobInfo(const nsString& aContentType,
+                                      PRUint64 aLength)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(mBlob);
+  MOZ_ASSERT(mRemoteBlob);
+  MOZ_ASSERT(aLength);
+
+  nsString voidString;
+  voidString.SetIsVoid(true);
+
+  ToConcreteBlob(mBlob)->SetLazyData(voidString, aContentType, aLength);
+
+  NormalBlobConstructorParams params(aContentType, aLength);
+  return BaseType::SendResolveMystery(params);
+}
+
+template <ActorFlavorEnum ActorFlavor>
+void
+Blob<ActorFlavor>::SetRemoteBlob(nsRefPtr<RemoteBlobType>& aRemoteBlob)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(!mBlob);
+  MOZ_ASSERT(!mRemoteBlob);
+  MOZ_ASSERT(!mOwnsBlob);
+  MOZ_ASSERT(aRemoteBlob);
+
+  if (NS_FAILED(aRemoteBlob->SetMutable(false))) {
+    MOZ_NOT_REACHED("Failed to make remote blob immutable!");
+  }
+
+  aRemoteBlob->SetActor(this);
+  aRemoteBlob.forget(&mRemoteBlob);
+
+  mBlob = mRemoteBlob;
+  mOwnsBlob = true;
+}
+
+template <ActorFlavorEnum ActorFlavor>
 void
 Blob<ActorFlavor>::NoteDyingRemoteBlob()
 {
   MOZ_ASSERT(mBlob);
   MOZ_ASSERT(mRemoteBlob);
   MOZ_ASSERT(!mOwnsBlob);
 
+  // This may be called on any thread due to the fact that RemoteBlob is
+  // designed to be passed between threads. We must start the shutdown process
+  // on the main thread, so we proxy here if necessary.
   if (!NS_IsMainThread()) {
     nsCOMPtr<nsIRunnable> runnable =
       NS_NewNonOwningRunnableMethod(this,
                                     &Blob<ActorFlavor>::NoteDyingRemoteBlob);
     if (NS_FAILED(NS_DispatchToMainThread(runnable))) {
-      MOZ_NOT_REACHED("Should never fail!");
+      MOZ_ASSERT(false, "Should never fail!");
     }
 
     return;
   }
 
   // Must do this before calling Send__delete__ or we'll crash there trying to
   // access a dangling pointer.
   mRemoteBlob = nullptr;
 
-  BaseType::Send__delete__(this);
+  mozilla::unused << BaseType::Send__delete__(this);
 }
 
 template <ActorFlavorEnum ActorFlavor>
 void
 Blob<ActorFlavor>::ActorDestroy(ActorDestroyReason aWhy)
 {
+  MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(mBlob);
 
   if (mRemoteBlob) {
     mRemoteBlob->SetActor(nullptr);
   }
 
   if (mOwnsBlob) {
     mBlob->Release();
   }
 }
 
 template <ActorFlavorEnum ActorFlavor>
 bool
+Blob<ActorFlavor>::RecvResolveMystery(const ResolveMysteryParams& aParams)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(mBlob);
+  MOZ_ASSERT(!mRemoteBlob);
+  MOZ_ASSERT(mOwnsBlob);
+
+  if (!mBlobIsFile) {
+    MOZ_ASSERT(false, "Must always be a file!");
+    return false;
+  }
+
+  nsDOMFileBase* blob = ToConcreteBlob(mBlob);
+
+  switch (aParams.type()) {
+    case ResolveMysteryParams::TNormalBlobConstructorParams: {
+      const NormalBlobConstructorParams& params =
+        aParams.get_NormalBlobConstructorParams();
+      nsString voidString;
+      voidString.SetIsVoid(true);
+      blob->SetLazyData(voidString, params.contentType(), params.length());
+      break;
+    }
+
+    case ResolveMysteryParams::TFileBlobConstructorParams: {
+      const FileBlobConstructorParams& params =
+        aParams.get_FileBlobConstructorParams();
+      blob->SetLazyData(params.name(), params.contentType(), params.length());
+      break;
+    }
+
+    default:
+      MOZ_NOT_REACHED("Unknown params!");
+  }
+
+  return true;
+}
+
+template <ActorFlavorEnum ActorFlavor>
+bool
 Blob<ActorFlavor>::RecvPBlobStreamConstructor(StreamType* aActor)
 {
+  MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(mBlob);
   MOZ_ASSERT(!mRemoteBlob);
 
   nsCOMPtr<nsIInputStream> stream;
   nsresult rv = mBlob->GetInternalStream(getter_AddRefs(stream));
   NS_ENSURE_SUCCESS(rv, false);
 
   return aActor->Send__delete__(aActor, stream.get());
 }
 
 template <ActorFlavorEnum ActorFlavor>
 typename Blob<ActorFlavor>::StreamType*
 Blob<ActorFlavor>::AllocPBlobStream()
 {
+  MOZ_ASSERT(NS_IsMainThread());
   return new InputStreamActor<ActorFlavor>();
 }
 
 template <ActorFlavorEnum ActorFlavor>
 bool
 Blob<ActorFlavor>::DeallocPBlobStream(StreamType* aActor)
 {
+  MOZ_ASSERT(NS_IsMainThread());
   delete aActor;
   return true;
 }
 
 template <ActorFlavorEnum ActorFlavor>
 NS_IMPL_ADDREF_INHERITED(RemoteBlob<ActorFlavor>, nsDOMFile)
 
 template <ActorFlavorEnum ActorFlavor>
--- a/dom/ipc/Blob.h
+++ b/dom/ipc/Blob.h
@@ -50,61 +50,82 @@ struct BlobTraits<Child>
 };
 
 template <ActorFlavorEnum>
 class RemoteBlob;
 
 template <ActorFlavorEnum ActorFlavor>
 class Blob : public BlobTraits<ActorFlavor>::BaseType
 {
+  friend class RemoteBlob<ActorFlavor>;
+
 public:
   typedef typename BlobTraits<ActorFlavor>::BaseType BaseType;
   typedef typename BlobTraits<ActorFlavor>::StreamType StreamType;
   typedef typename BlobTraits<ActorFlavor>::ManagerType ManagerType;
   typedef RemoteBlob<ActorFlavor> RemoteBlobType;
   typedef mozilla::ipc::IProtocolManager<
                       mozilla::ipc::RPCChannel::RPCListener>::ActorDestroyReason
           ActorDestroyReason;
   typedef mozilla::dom::BlobConstructorParams BlobConstructorParams;
 
 protected:
   nsIDOMBlob* mBlob;
   RemoteBlobType* mRemoteBlob;
   bool mOwnsBlob;
+  bool mBlobIsFile;
 
 public:
   // This create function is called on the sending side.
   static Blob*
   Create(nsIDOMBlob* aBlob)
   {
     return new Blob(aBlob);
   }
 
   // This create function is called on the receiving side.
   static Blob*
   Create(const BlobConstructorParams& aParams);
 
+  // Get the blob associated with this actor. This may always be called on the
+  // sending side. It may also be called on the receiving side unless this is a
+  // "mystery" blob that has not yet received a SetMysteryBlobInfo() call.
   already_AddRefed<nsIDOMBlob>
   GetBlob();
 
-  void
-  NoteDyingRemoteBlob();
+  // Use this for files.
+  bool
+  SetMysteryBlobInfo(const nsString& aName, const nsString& aContentType,
+                     PRUint64 aLength);
+
+  // Use this for non-file blobs.
+  bool
+  SetMysteryBlobInfo(const nsString& aContentType, PRUint64 aLength);
 
 private:
   // This constructor is called on the sending side.
   Blob(nsIDOMBlob* aBlob);
 
   // This constructor is called on the receiving side.
   Blob(const BlobConstructorParams& aParams);
 
+  void
+  SetRemoteBlob(nsRefPtr<RemoteBlobType>& aRemoteBlob);
+
+  void
+  NoteDyingRemoteBlob();
+
   // These methods are only called by the IPDL message machinery.
   virtual void
   ActorDestroy(ActorDestroyReason aWhy) MOZ_OVERRIDE;
 
   virtual bool
+  RecvResolveMystery(const ResolveMysteryParams& aParams) MOZ_OVERRIDE;
+
+  virtual bool
   RecvPBlobStreamConstructor(StreamType* aActor) MOZ_OVERRIDE;
 
   virtual StreamType*
   AllocPBlobStream() MOZ_OVERRIDE;
 
   virtual bool
   DeallocPBlobStream(StreamType* aActor) MOZ_OVERRIDE;
 };
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -80,17 +80,17 @@
 #ifdef ACCESSIBILITY
 #include "nsIAccessibilityService.h"
 #endif
 
 #include "mozilla/dom/indexedDB/PIndexedDBChild.h"
 #include "mozilla/dom/sms/SmsChild.h"
 #include "mozilla/dom/devicestorage/DeviceStorageRequestChild.h"
 
-#include "nsIDOMFile.h"
+#include "nsDOMFile.h"
 #include "nsIRemoteBlob.h"
 #include "StructuredCloneUtils.h"
 
 using namespace mozilla::docshell;
 using namespace mozilla::dom::devicestorage;
 using namespace mozilla::dom::sms;
 using namespace mozilla::dom::indexedDB;
 using namespace mozilla::hal_sandbox;
@@ -428,53 +428,66 @@ ContentChild::DeallocPBlob(PBlobChild* a
 {
   delete aActor;
   return true;
 }
 
 BlobChild*
 ContentChild::GetOrCreateActorForBlob(nsIDOMBlob* aBlob)
 {
+  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   NS_ASSERTION(aBlob, "Null pointer!");
 
   nsCOMPtr<nsIRemoteBlob> remoteBlob = do_QueryInterface(aBlob);
   if (remoteBlob) {
     BlobChild* actor =
       static_cast<BlobChild*>(static_cast<PBlobChild*>(remoteBlob->GetPBlob()));
     NS_ASSERTION(actor, "Null actor?!");
 
     return actor;
   }
 
+  // XXX This is only safe so long as all blob implementations in our tree
+  //     inherit nsDOMFileBase. If that ever changes then this will need to grow
+  //     a real interface or something.
+  const nsDOMFileBase* blob = static_cast<nsDOMFileBase*>(aBlob);
+
   BlobConstructorParams params;
 
-  nsString contentType;
-  nsresult rv = aBlob->GetType(contentType);
-  NS_ENSURE_SUCCESS(rv, nullptr);
+  if (blob->IsSizeUnknown()) {
+    // We don't want to call GetSize yet since that may stat a file on the main
+    // thread here. Instead we'll learn the size lazily from the other process.
+    params = MysteryBlobConstructorParams();
+  }
+  else {
+    nsString contentType;
+    nsresult rv = aBlob->GetType(contentType);
+    NS_ENSURE_SUCCESS(rv, nullptr);
 
-  PRUint64 length;
-  rv = aBlob->GetSize(&length);
-  NS_ENSURE_SUCCESS(rv, nullptr);
-
-  nsCOMPtr<nsIDOMFile> file = do_QueryInterface(aBlob);
-  if (file) {
-    FileBlobConstructorParams fileParams;
-
-    rv = file->GetName(fileParams.name());
+    PRUint64 length;
+    rv = aBlob->GetSize(&length);
     NS_ENSURE_SUCCESS(rv, nullptr);
 
-    fileParams.contentType() = contentType;
-    fileParams.length() = length;
+    nsCOMPtr<nsIDOMFile> file = do_QueryInterface(aBlob);
+    if (file) {
+      FileBlobConstructorParams fileParams;
+
+      rv = file->GetName(fileParams.name());
+      NS_ENSURE_SUCCESS(rv, nullptr);
 
-    params = fileParams;
-  } else {
-    NormalBlobConstructorParams blobParams;
-    blobParams.contentType() = contentType;
-    blobParams.length() = length;
-    params = blobParams;
+      fileParams.contentType() = contentType;
+      fileParams.length() = length;
+
+      params = fileParams;
+    } else {
+      NormalBlobConstructorParams blobParams;
+      blobParams.contentType() = contentType;
+      blobParams.length() = length;
+      params = blobParams;
+    }
   }
 
   BlobChild* actor = BlobChild::Create(aBlob);
   NS_ENSURE_TRUE(actor, nullptr);
 
   if (!SendPBlobConstructor(actor, params)) {
     return nullptr;
   }
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -37,23 +37,23 @@
 #include "nsAppRunner.h"
 #include "nsAutoPtr.h"
 #include "nsCExternalHandlerService.h"
 #include "nsCOMPtr.h"
 #include "nsChromeRegistryChrome.h"
 #include "nsConsoleMessage.h"
 #include "nsDebugImpl.h"
 #include "nsDirectoryServiceDefs.h"
+#include "nsDOMFile.h"
 #include "nsExternalHelperAppService.h"
 #include "nsFrameMessageManager.h"
 #include "nsHashPropertyBag.h"
 #include "nsIAlertsService.h"
 #include "nsIClipboard.h"
 #include "nsIConsoleService.h"
-#include "nsIDOMFile.h"
 #include "nsIDOMGeoGeolocation.h"
 #include "nsIDOMWindow.h"
 #include "nsIFilePicker.h"
 #include "nsIMemoryReporter.h"
 #include "nsIObserverService.h"
 #include "nsIPresShell.h"
 #include "nsIRemoteBlob.h"
 #include "nsIScriptError.h"
@@ -886,54 +886,67 @@ ContentParent::DeallocPBlob(PBlobParent*
 {
   delete aActor;
   return true;
 }
 
 BlobParent*
 ContentParent::GetOrCreateActorForBlob(nsIDOMBlob* aBlob)
 {
+  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   NS_ASSERTION(aBlob, "Null pointer!");
 
   nsCOMPtr<nsIRemoteBlob> remoteBlob = do_QueryInterface(aBlob);
   if (remoteBlob) {
     BlobParent* actor =
       static_cast<BlobParent*>(
         static_cast<PBlobParent*>(remoteBlob->GetPBlob()));
     NS_ASSERTION(actor, "Null actor?!");
 
     return actor;
   }
 
+  // XXX This is only safe so long as all blob implementations in our tree
+  //     inherit nsDOMFileBase. If that ever changes then this will need to grow
+  //     a real interface or something.
+  const nsDOMFileBase* blob = static_cast<nsDOMFileBase*>(aBlob);
+
   BlobConstructorParams params;
 
-  nsString contentType;
-  nsresult rv = aBlob->GetType(contentType);
-  NS_ENSURE_SUCCESS(rv, nullptr);
+  if (blob->IsSizeUnknown()) {
+    // We don't want to call GetSize yet since that may stat a file on the main
+    // thread here. Instead we'll learn the size lazily from the other process.
+    params = MysteryBlobConstructorParams();
+  }
+  else {
+    nsString contentType;
+    nsresult rv = aBlob->GetType(contentType);
+    NS_ENSURE_SUCCESS(rv, nullptr);
 
-  PRUint64 length;
-  rv = aBlob->GetSize(&length);
-  NS_ENSURE_SUCCESS(rv, nullptr);
-
-  nsCOMPtr<nsIDOMFile> file = do_QueryInterface(aBlob);
-  if (file) {
-    FileBlobConstructorParams fileParams;
-
-    rv = file->GetName(fileParams.name());
+    PRUint64 length;
+    rv = aBlob->GetSize(&length);
     NS_ENSURE_SUCCESS(rv, nullptr);
 
-    fileParams.contentType() = contentType;
-    fileParams.length() = length;
+    nsCOMPtr<nsIDOMFile> file = do_QueryInterface(aBlob);
+    if (file) {
+      FileBlobConstructorParams fileParams;
+
+      rv = file->GetName(fileParams.name());
+      NS_ENSURE_SUCCESS(rv, nullptr);
 
-    params = fileParams;
-  } else {
-    NormalBlobConstructorParams blobParams;
-    blobParams.contentType() = contentType;
-    blobParams.length() = length;
-    params = blobParams;
+      fileParams.contentType() = contentType;
+      fileParams.length() = length;
+
+      params = fileParams;
+    } else {
+      NormalBlobConstructorParams blobParams;
+      blobParams.contentType() = contentType;
+      blobParams.length() = length;
+      params = blobParams;
+    }
   }
 
   BlobParent* actor = BlobParent::Create(aBlob);
   NS_ENSURE_TRUE(actor, nullptr);
 
   if (!SendPBlobConstructor(actor, params)) {
     return nullptr;
   }
--- a/dom/ipc/DOMTypes.ipdlh
+++ b/dom/ipc/DOMTypes.ipdlh
@@ -12,10 +12,23 @@ namespace mozilla {
 namespace dom {
 
 struct ClonedMessageData
 {
   SerializedStructuredCloneBuffer data;
   PBlob[] blobs;
 };
 
+struct NormalBlobConstructorParams
+{
+  nsString contentType;
+  uint64_t length;
+};
+
+struct FileBlobConstructorParams
+{
+  nsString name;
+  nsString contentType;
+  uint64_t length;
+};
+
 } // namespace dom
 } // namespace mozilla
--- a/dom/ipc/PBlob.ipdl
+++ b/dom/ipc/PBlob.ipdl
@@ -1,23 +1,33 @@
 /* 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 protocol PBlobStream;
 include protocol PContent;
 
+include DOMTypes;
+
 namespace mozilla {
 namespace dom {
 
+union ResolveMysteryParams
+{
+  NormalBlobConstructorParams;
+  FileBlobConstructorParams;
+};
+
 protocol PBlob
 {
   manager PContent;
   manages PBlobStream;
 
 both:
   __delete__();
 
   PBlobStream();
+
+  ResolveMystery(ResolveMysteryParams params);
 };
 
 } // namespace dom
 } // namespace mozilla
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -96,42 +96,35 @@ struct DeviceStorageEnumerationParams
 union DeviceStorageParams
 {
   DeviceStorageAddParams;
   DeviceStorageGetParams;
   DeviceStorageDeleteParams;
   DeviceStorageEnumerationParams;
 };
 
-struct NormalBlobConstructorParams
-{
-  nsString contentType;
-  uint64_t length;
-};
-
-struct FileBlobConstructorParams
-{
-  nsString name;
-  nsString contentType;
-  uint64_t length;
-};
-
 struct SlicedBlobConstructorParams
 {
   PBlob source;
   uint64_t begin;
   uint64_t end;
   nsString contentType;
 };
 
+struct MysteryBlobConstructorParams
+{
+  // Nothing is known about this type of blob.
+};
+
 union BlobConstructorParams
 {
   NormalBlobConstructorParams;
   FileBlobConstructorParams;
   SlicedBlobConstructorParams;
+  MysteryBlobConstructorParams;
 };
 
 rpc protocol PContent
 {
     parent opens PCompositor;
 
     manages PAudio;
     manages PBlob;
--- 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/dom/system/gonk/nsVolumeService.cpp
+++ b/dom/system/gonk/nsVolumeService.cpp
@@ -134,17 +134,17 @@ void nsVolumeService::UpdateVolume(const
   MOZ_ASSERT(NS_IsMainThread());
 
   nsRefPtr<nsVolume> vol = FindAddVolumeByName(aVolume->Name());
   if (vol->Equals(aVolume)) {
     // Nothing has really changed. Don't bother telling anybody.
     return;
   }
   vol->Set(aVolume);
-  nsRefPtr<nsIObserverService> obs = GetObserverService();
+  nsCOMPtr<nsIObserverService> obs = GetObserverService();
   if (!obs) {
     return;
   }
   nsString stateStr(NS_ConvertUTF8toUTF16(vol->StateStr()));
   obs->NotifyObservers(vol, NS_VOLUME_STATE_CHANGED, stateStr.get());
 }
 
 /***************************************************************************
--- a/dom/wifi/DOMWifiManager.js
+++ b/dom/wifi/DOMWifiManager.js
@@ -285,17 +285,19 @@ DOMWifiManager.prototype = {
       throw new Components.Exception("Denied", Cr.NS_ERROR_FAILURE);
     return exposeReadOnly({ status: this._connectionStatus,
                             network: this._currentNetwork });
   },
 
   get connectionInformation() {
     if (!this._hasPrivileges)
       throw new Components.Exception("Denied", Cr.NS_ERROR_FAILURE);
-    return exposeReadOnly(this._lastConnectionInfo);
+    return this._lastConnectionInfo
+           ? exposeReadOnly(this._lastConnectionInfo)
+           : null;
   },
 
   set onstatuschange(callback) {
     if (!this._hasPrivileges)
       throw new Components.Exception("Denied", Cr.NS_ERROR_FAILURE);
     this._onStatusChange = callback;
   },
 
--- 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/gfx/layers/ImageLayers.h
+++ b/gfx/layers/ImageLayers.h
@@ -296,16 +296,33 @@ struct RemoteImageData {
 };
 
 /**
  * A class that manages Images for an ImageLayer. The only reason
  * we need a separate class here is that ImageLayers aren't threadsafe
  * (because layers can only be used on the main thread) and we want to
  * be able to set the current Image from any thread, to facilitate
  * video playback without involving the main thread, for example.
+ *
+ * An ImageContainer can operate in one of three modes:
+ * 1) Normal. Triggered by constructing the ImageContainer with
+ * DISABLE_ASYNC or when compositing is happening on the main thread.
+ * SetCurrentImage changes ImageContainer state but nothing is sent to the
+ * compositor until the next layer transaction.
+ * 2) Asynchronous. Initiated by constructing the ImageContainer with
+ * ENABLE_ASYNC when compositing is happening on the main thread.
+ * SetCurrentImage sends a message through the ImageBridge to the compositor
+ * thread to update the image, without going through the main thread or
+ * a layer transaction.
+ * 3) Remote. Initiated by calling SetRemoteImageData on the ImageContainer
+ * before any other activity.
+ * The ImageContainer uses a shared memory block containing a cross-process mutex
+ * to communicate with the compositor thread. SetCurrentImage synchronously
+ * updates the shared state to point to the new image and the old image
+ * is immediately released (not true in Normal or Asynchronous modes).
  */
 class THEBES_API ImageContainer {
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ImageContainer)
 public:
 
   enum { DISABLE_ASYNC = 0x0, ENABLE_ASYNC = 0x01 };
 
   ImageContainer(int flag = 0);
--- a/js/jsd/jsd_text.c
+++ b/js/jsd/jsd_text.c
@@ -439,17 +439,17 @@ jsd_AppendUCSourceText(JSDContext* jsdc,
         buf = malloc(UNICODE_TRUNCATE_BUF_SIZE);
         if(!buf)
         {
             JSD_UNLOCK_SOURCE_TEXT(jsdc);
             return NULL;
         }
     }
     while(remaining && jsdsrc) {
-        int bytes = JS_MIN(remaining, UNICODE_TRUNCATE_BUF_SIZE);
+        int bytes = (remaining < UNICODE_TRUNCATE_BUF_SIZE) ? remaining : UNICODE_TRUNCATE_BUF_SIZE;
         int i;
         for(i = 0; i < bytes; i++)
             buf[i] = (const char) *(text++);
         jsdsrc = jsd_AppendSourceText(jsdc,jsdsrc,
                                       buf, bytes,
                                       JSD_SOURCE_PARTIAL);
         remaining -= bytes;
     }
--- 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;
 }
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -6726,17 +6726,17 @@ frontend::NewSrcNote(JSContext *cx, Byte
      * Compute delta from the last annotated bytecode's offset.  If it's too
      * big to fit in sn, allocate one or more xdelta notes and reset sn.
      */
     offset = bce->offset();
     delta = offset - bce->lastNoteOffset();
     bce->current->lastNoteOffset = offset;
     if (delta >= SN_DELTA_LIMIT) {
         do {
-            xdelta = JS_MIN(delta, SN_XDELTA_MASK);
+            xdelta = Min(delta, SN_XDELTA_MASK);
             SN_MAKE_XDELTA(sn, xdelta);
             delta -= xdelta;
             index = AllocSrcNote(cx, bce);
             if (index < 0)
                 return -1;
             sn = &bce->notes()[index];
         } while (delta >= SN_DELTA_LIMIT);
     }
@@ -6959,17 +6959,17 @@ frontend::FinishTakingSrcNotes(JSContext
             if (offset < delta)
                 delta = offset;
             for (;;) {
                 if (!AddToSrcNoteDelta(cx, bce, sn, delta))
                     return false;
                 offset -= delta;
                 if (offset == 0)
                     break;
-                delta = JS_MIN(offset, SN_XDELTA_MASK);
+                delta = Min(offset, SN_XDELTA_MASK);
                 sn = bce->main.notes;
             }
         }
     }
 
     mainCount = bce->main.noteCount;
     totalCount = prologCount + mainCount;
     if (prologCount)
--- a/js/src/gc/Memory.cpp
+++ b/js/src/gc/Memory.cpp
@@ -318,17 +318,17 @@ MapAlignedPages(size_t size, size_t alig
     int flags = MAP_PRIVATE | MAP_ANON;
 
     /* Special case: If we want page alignment, no further work is needed. */
     if (alignment == PageSize) {
         return mmap(NULL, size, prot, flags, -1, 0);
     }
 
     /* Overallocate and unmap the region's edges. */
-    size_t reqSize = JS_MIN(size + 2 * alignment, 2 * size);
+    size_t reqSize = Min(size + 2 * alignment, 2 * size);
     void *region = mmap(NULL, reqSize, prot, flags, -1, 0);
     if (region == MAP_FAILED)
         return NULL;
 
     uintptr_t regionEnd = uintptr_t(region) + reqSize;
     uintptr_t offset = uintptr_t(region) % alignment;
     JS_ASSERT(offset < reqSize - size);
 
--- a/js/src/ion/IonMacroAssembler.cpp
+++ b/js/src/ion/IonMacroAssembler.cpp
@@ -397,17 +397,17 @@ MacroAssembler::initGCThing(const Regist
                 Address(obj, elementsOffset + ObjectElements::offsetOfInitializedLength()));
         store32(Imm32(templateObject->getArrayLength()),
                 Address(obj, elementsOffset + ObjectElements::offsetOfLength()));
     } else {
         storePtr(ImmWord(emptyObjectElements), Address(obj, JSObject::offsetOfElements()));
 
         // Fixed slots of non-array objects are required to be initialized.
         // Use the values currently in the template object.
-        size_t nslots = JS_MIN(templateObject->numFixedSlots(), templateObject->slotSpan());
+        size_t nslots = Min(templateObject->numFixedSlots(), templateObject->slotSpan());
         for (unsigned i = 0; i < nslots; i++) {
             storeValue(templateObject->getFixedSlot(i),
                        Address(obj, JSObject::getFixedSlotOffset(i)));
         }
     }
 
     if (templateObject->hasPrivate()) {
         uint32_t nfixed = templateObject->numFixedSlots();
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
@@ -545,21 +545,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);
 }
 
@@ -573,32 +570,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);
@@ -623,21 +613,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);
@@ -2137,17 +2123,17 @@ SetIdArrayLength(JSContext *cx, JSIdArra
 }
 
 static JSIdArray *
 AddNameToArray(JSContext *cx, PropertyName *name, JSIdArray *ida, int *ip)
 {
     int i = *ip;
     int length = ida->length;
     if (i >= length) {
-        ida = SetIdArrayLength(cx, ida, JS_MAX(length * 2, 8));
+        ida = SetIdArrayLength(cx, ida, Max(length * 2, 8));
         if (!ida)
             return NULL;
         JS_ASSERT(i < ida->length);
     }
     ida->vector[i].init(NameToId(name));
     *ip = i + 1;
     return ida;
 }
--- 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 */
 
@@ -2696,20 +2699,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)
 {
@@ -2746,36 +2752,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)
@@ -4961,17 +5010,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/jsarray.cpp
+++ b/js/src/jsarray.cpp
@@ -2648,27 +2648,27 @@ array_splice(JSContext *cx, unsigned arg
     /* Step 5. */
     double relativeStart;
     if (!ToInteger(cx, argc >= 1 ? args[0] : UndefinedValue(), &relativeStart))
         return false;
 
     /* Step 6. */
     uint32_t actualStart;
     if (relativeStart < 0)
-        actualStart = JS_MAX(len + relativeStart, 0);
+        actualStart = Max(len + relativeStart, 0.0);
     else
-        actualStart = JS_MIN(relativeStart, len);
+        actualStart = Min(relativeStart, double(len));
 
     /* Step 7. */
     uint32_t actualDeleteCount;
     if (argc != 1) {
         double deleteCountDouble;
         if (!ToInteger(cx, argc >= 2 ? args[1] : Int32Value(0), &deleteCountDouble))
             return false;
-        actualDeleteCount = JS_MIN(JS_MAX(deleteCountDouble, 0), len - actualStart);
+        actualDeleteCount = Min(Max(deleteCountDouble, 0.0), double(len - actualStart));
     } else {
         /*
          * Non-standard: if start was specified but deleteCount was omitted,
          * delete to the end of the array.  See bug 668024 for discussion.
          */
         actualDeleteCount = len - actualStart;
     }
 
--- a/js/src/jsclone.cpp
+++ b/js/src/jsclone.cpp
@@ -374,17 +374,17 @@ JSStructuredCloneWriter::writeId(jsid id
 
 inline void
 JSStructuredCloneWriter::checkStack()
 {
 #ifdef DEBUG
     /* To avoid making serialization O(n^2), limit stack-checking at 10. */
     const size_t MAX = 10;
 
-    size_t limit = JS_MIN(counts.length(), MAX);
+    size_t limit = Min(counts.length(), MAX);
     JS_ASSERT(objs.length() == counts.length());
     size_t total = 0;
     for (size_t i = 0; i < limit; i++) {
         JS_ASSERT(total + counts[i] >= total);
         total += counts[i];
     }
     if (counts.length() <= MAX)
         JS_ASSERT(total == ids.length());
--- a/js/src/jscntxt.h
+++ b/js/src/jscntxt.h
@@ -541,16 +541,19 @@ struct JSRuntime : js::RuntimeFriendFiel
     js::gcstats::Statistics gcStats;
 
     /* Incremented on every GC slice. */
     uint64_t            gcNumber;
 
     /* The gcNumber at the time of the most recent GC's first slice. */
     uint64_t            gcStartNumber;
 
+    /* Whether the currently running GC can finish in multiple slices. */
+    int                 gcIsIncremental;
+
     /* Whether all compartments are being collected in first GC slice. */
     bool                gcIsFull;
 
     /* The reason that an interrupt-triggered GC should be called. */
     js::gcreason::Reason gcTriggerReason;
 
     /*
      * If this is true, all marked objects must belong to a compartment being
--- a/js/src/jsdate.cpp
+++ b/js/src/jsdate.cpp
@@ -733,17 +733,17 @@ fractional(double *result, const jschar 
  * Succeed if exactly n digits are converted. Advance *i only
  * on success.
  */
 static JSBool
 ndigits(size_t n, size_t *result, const jschar *s, size_t* i, size_t limit)
 {
     size_t init = *i;
 
-    if (digits(result, s, i, JS_MIN(limit, init+n)))
+    if (digits(result, s, i, Min(limit, init+n)))
         return ((*i - init) == n);
 
     *i = init;
     return JS_FALSE;
 }
 
 static int
 DaysInMonth(int year, int month)
--- a/js/src/jsdhash.cpp
+++ b/js/src/jsdhash.cpp
@@ -270,29 +270,29 @@ JS_DHashTableSetAlphaBounds(JSDHashTable
     /*
      * Ensure that at least one entry will always be free.  If maxAlpha at
      * minimum size leaves no entries free, reduce maxAlpha based on minimum
      * size and the precision limit of maxAlphaFrac's fixed point format.
      */
     JS_ASSERT(JS_DHASH_MIN_SIZE - (maxAlpha * JS_DHASH_MIN_SIZE) >= 1);
     if (JS_DHASH_MIN_SIZE - (maxAlpha * JS_DHASH_MIN_SIZE) < 1) {
         maxAlpha = (float)
-                   (JS_DHASH_MIN_SIZE - JS_MAX(JS_DHASH_MIN_SIZE / 256, 1))
+                   (JS_DHASH_MIN_SIZE - Max(JS_DHASH_MIN_SIZE / 256, 1))
                    / JS_DHASH_MIN_SIZE;
     }
 
     /*
      * Ensure that minAlpha is strictly less than half maxAlpha.  Take care
      * not to truncate an entry's worth of alpha when storing in minAlphaFrac
      * (8-bit fixed point format).
      */
     JS_ASSERT(minAlpha < maxAlpha / 2);
     if (minAlpha >= maxAlpha / 2) {
         size = JS_DHASH_TABLE_SIZE(table);
-        minAlpha = (size * maxAlpha - JS_MAX(size / 256, 1)) / (2 * size);
+        minAlpha = (size * maxAlpha - Max(size / 256, 1U)) / (2 * size);
     }
 
     table->maxAlphaFrac = (uint8_t)(maxAlpha * 256);
     table->minAlphaFrac = (uint8_t)(minAlpha * 256);
 }
 
 /*
  * Double hashing needs the second hash code to be relatively prime to table
--- a/js/src/jsfriendapi.cpp
+++ b/js/src/jsfriendapi.cpp
@@ -775,16 +775,22 @@ SizeOfJSContext()
 JS_FRIEND_API(GCSliceCallback)
 SetGCSliceCallback(JSRuntime *rt, GCSliceCallback callback)
 {
     GCSliceCallback old = rt->gcSliceCallback;
     rt->gcSliceCallback = callback;
     return old;
 }
 
+JS_FRIEND_API(bool)
+WasIncrementalGC(JSRuntime *rt)
+{
+    return rt->gcIsIncremental;
+}
+
 jschar *
 GCDescription::formatMessage(JSRuntime *rt) const
 {
     return rt->gcStats.formatMessage();
 }
 
 jschar *
 GCDescription::formatJSON(JSRuntime *rt, uint64_t timestamp) const
--- a/js/src/jsfriendapi.h
+++ b/js/src/jsfriendapi.h
@@ -740,16 +740,20 @@ struct JS_FRIEND_API(GCDescription) {
 };
 
 typedef void
 (* GCSliceCallback)(JSRuntime *rt, GCProgress progress, const GCDescription &desc);
 
 extern JS_FRIEND_API(GCSliceCallback)
 SetGCSliceCallback(JSRuntime *rt, GCSliceCallback callback);
 
+/* Was the most recent GC run incrementally? */
+extern JS_FRIEND_API(bool)
+WasIncrementalGC(JSRuntime *rt);
+
 /*
  * Signals a good place to do an incremental slice, because the browser is
  * drawing a frame.
  */
 extern JS_FRIEND_API(void)
 NotifyDidPaint(JSRuntime *rt);
 
 extern JS_FRIEND_API(bool)
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -3238,28 +3238,28 @@ ShouldPreserveJITCode(JSCompartment *c, 
         return true;
     }
 
     c->lastCodeRelease = currentTime;
     return false;
 }
 
 static void
-BeginMarkPhase(JSRuntime *rt, bool isIncremental)
+BeginMarkPhase(JSRuntime *rt)
 {
     int64_t currentTime = PRMJ_Now();
 
     /*
      * At the end of each incremental slice, we call prepareForIncrementalGC,
      * which marks objects in all arenas that we're currently allocating
      * into. This can cause leaks if unreachable objects are in these
      * arenas. This purge call ensures that we only mark arenas that have had
      * allocations after the incremental GC started.
      */
-    if (isIncremental) {
+    if (rt->gcIsIncremental) {
         for (GCCompartmentsIter c(rt); !c.done(); c.next())
             c->arenas.purge();
     }
 
     rt->gcIsFull = true;
     for (CompartmentsIter c(rt); !c.done(); c.next()) {
         JS_ASSERT(!c->wasGCStarted());
         for (unsigned i = 0 ; i < FINALIZE_LIMIT ; ++i)
@@ -3273,17 +3273,17 @@ BeginMarkPhase(JSRuntime *rt, bool isInc
         c->setPreservingCode(ShouldPreserveJITCode(c, currentTime));
     }
 
     rt->gcMarker.start(rt);
     JS_ASSERT(!rt->gcMarker.callback);
     JS_ASSERT(IS_GC_MARKING_TRACER(&rt->gcMarker));
 
     /* For non-incremental GC the following sweep discards the jit code. */
-    if (isIncremental) {
+    if (rt->gcIsIncremental) {
         for (GCCompartmentsIter c(rt); !c.done(); c.next()) {
             gcstats::AutoPhase ap(rt->gcStats, gcstats::PHASE_MARK_DISCARD_CODE);
             c->discardJitCode(rt->defaultFreeOp());
         }
     }
 
     GCMarker *gcmarker = &rt->gcMarker;
 
@@ -3366,27 +3366,27 @@ MarkGrayAndWeak(JSRuntime *rt)
 }
 
 #ifdef DEBUG
 static void
 ValidateIncrementalMarking(JSRuntime *rt);
 #endif
 
 static void
-EndMarkPhase(JSRuntime *rt, bool isIncremental)
+EndMarkPhase(JSRuntime *rt)
 {
     {
         gcstats::AutoPhase ap1(rt->gcStats, gcstats::PHASE_MARK);
         MarkGrayAndWeak(rt);
     }
 
     JS_ASSERT(rt->gcMarker.isDrained());
 
 #ifdef DEBUG
-    if (isIncremental)
+    if (rt->gcIsIncremental)
         ValidateIncrementalMarking(rt);
 #endif
 
     /*
      * Having black->gray edges violates our promise to the cycle
      * collector. This can happen if we're collecting a compartment and it has
      * an edge to an uncollected compartment: it's possible that the source and
      * destination of the cross-compartment edge should be gray, but the source
@@ -3937,42 +3937,46 @@ 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;
+    rt->gcIsIncremental = rt->gcIncrementalState != NO_INCREMENTAL ||
+                          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) {
 
       case MARK_ROOTS:
-        BeginMarkPhase(rt, isIncremental);
+        BeginMarkPhase(rt);
         PushZealSelectedObjects(rt);
 
         rt->gcIncrementalState = MARK;
 
         if (zeal == ZealIncrementalRootsThenFinish)
             break;
 
         /* fall through */
@@ -3997,17 +4001,17 @@ IncrementalCollectSlice(JSRuntime *rt,
              * Yield with the aim of starting the sweep in the next
              * slice.  We will need to mark anything new on the stack
              * when we resume, so we stay in MARK state.
              */
             rt->gcLastMarkSlice = true;
             break;
         }
 
-        EndMarkPhase(rt, isIncremental);
+        EndMarkPhase(rt);
 
         rt->gcIncrementalState = SWEEP;
 
         /*
          * This runs to completion, but we don't continue if the budget is
          * now exhasted.
          */
         BeginSweepPhase(rt);
@@ -4562,17 +4566,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/jsinterp.cpp
+++ b/js/src/jsinterp.cpp
@@ -2772,17 +2772,17 @@ BEGIN_CASE(JSOP_LOOKUPSWITCH)
   end_lookup_switch:
     len = GET_JUMP_OFFSET(pc2);
 }
 END_VARLEN_CASE
 }
 
 BEGIN_CASE(JSOP_ACTUALSFILLED)
 {
-    PUSH_INT32(JS_MAX(regs.fp()->numActualArgs(), GET_UINT16(regs.pc)));
+    PUSH_INT32(Max(regs.fp()->numActualArgs(), GET_UINT16(regs.pc)));
 }
 END_CASE(JSOP_ACTUALSFILLED)
 
 BEGIN_CASE(JSOP_ARGUMENTS)
     JS_ASSERT(!regs.fp()->fun()->hasRest());
     if (script->needsArgsObj()) {
         ArgumentsObject *obj = ArgumentsObject::createExpected(cx, regs.fp());
         if (!obj)
--- 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/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -3612,17 +3612,17 @@ JSObject::growElements(JSContext *cx, un
     JS_ASSERT(oldcap <= newcap);
 
     size_t oldSize = Probes::objectResizeActive() ? computedSizeOfThisSlotsElements() : 0;
 
     uint32_t nextsize = (oldcap <= CAPACITY_DOUBLING_MAX)
                       ? oldcap * 2
                       : oldcap + (oldcap >> 3);
 
-    uint32_t actualCapacity = JS_MAX(newcap, nextsize);
+    uint32_t actualCapacity = Max(newcap, nextsize);
     if (actualCapacity >= CAPACITY_CHUNK)
         actualCapacity = JS_ROUNDUP(actualCapacity, CAPACITY_CHUNK);
     else if (actualCapacity < SLOT_CAPACITY_MIN)
         actualCapacity = SLOT_CAPACITY_MIN;
 
     /* Don't let nelements get close to wrapping around uint32_t. */
     if (actualCapacity >= NELEMENTS_LIMIT || actualCapacity < oldcap || actualCapacity < newcap) {
         JS_ReportOutOfMemory(cx);
--- a/js/src/json.cpp
+++ b/js/src/json.cpp
@@ -624,17 +624,17 @@ js_Stringify(JSContext *cx, MutableHandl
              *         a. Append item to the end of PropertyList.
              *      7. Let i be i + 1.
              */
 
             /* Step 4b(ii). */
             uint32_t len;
             JS_ALWAYS_TRUE(js_GetLengthProperty(cx, replacer, &len));
             if (replacer->isDenseArray())
-                len = JS_MIN(len, replacer->getDenseArrayCapacity());
+                len = Min(len, replacer->getDenseArrayCapacity());
 
             HashSet<jsid> idSet(cx);
             if (!idSet.init(len))
                 return false;
 
             /* Step 4b(iii). */
             uint32_t i = 0;
 
@@ -697,26 +697,26 @@ js_Stringify(JSContext *cx, MutableHandl
     }
 
     StringBuffer gap(cx);
 
     if (space.isNumber()) {
         /* Step 6. */
         double d;
         JS_ALWAYS_TRUE(ToInteger(cx, space, &d));
-        d = JS_MIN(10, d);
+        d = Min(10.0, d);
         if (d >= 1 && !gap.appendN(' ', uint32_t(d)))
             return false;
     } else if (space.isString()) {
         /* Step 7. */
         JSLinearString *str = space.toString()->ensureLinear(cx);
         if (!str)
             return false;
         JS::Anchor<JSString *> anchor(str);
-        size_t len = JS_MIN(10, space.toString()->length());
+        size_t len = Min(size_t(10), space.toString()->length());
         if (!gap.append(str->chars(), len))
             return false;
     } else {
         /* Step 8. */
         JS_ASSERT(gap.empty());
     }
 
     /* Step 9. */
--- a/js/src/jsopcode.cpp
+++ b/js/src/jsopcode.cpp
@@ -1338,17 +1338,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.
@@ -4704,17 +4704,17 @@ Decompile(SprintStack *ss, jsbytecode *p
                      * All allocation when decompiling is LIFO, using malloc or,
                      * more commonly, arena-allocating from cx->tempLifoAlloc
                      * Therefore after InitSprintStack succeeds, we must release
                      * to mark before returning.
                      */
                     LifoAllocScope las(&cx->tempLifoAlloc());
                     outerLocalNames = jp->localNames;
                     if (!SetPrinterLocalNames(cx, fun->script(), jp))
-                            return NULL;
+                        return NULL;
 
                     inner = fun->script();
                     if (!InitSprintStack(cx, &ss2, jp, StackDepth(inner))) {
                         Foreground::delete_(jp->localNames);
                         jp->localNames = outerLocalNames;
                         return NULL;
                     }
                     ss2.inGenExp = JS_TRUE;
@@ -5496,16 +5496,17 @@ DecompileCode(JSPrinter *jp, JSScript *s
         }
     }
 
     for (unsigned i = 0; i < initialStackDepth; i++) {
         if (!PushStr(&ss, "", JSOP_NOP))
             return false;
     }
 
+    /* Call recursive subroutine to do the hard work. */
     JSScript *oldscript = jp->script;
     BindingVector *oldLocalNames = jp->localNames;
     if (!SetPrinterLocalNames(cx, script, jp))
         return false;
     jp->script = script;
 
     /* Call recursive subroutine to do the hard work. */
     bool ok = Decompile(&ss, pc, len) != NULL;
@@ -5746,128 +5747,513 @@ 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, ScriptFrameIter &iter, 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, iter.script(), current))
+        return false;
+
+    if (spindex == JSDVG_SEARCH_STACK) {
+        size_t index = iter.numFrameSlots();
+        Value s;
+
+        // 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.
+        do {
+            if (!index)
+                return true;
+            s = iter.frameSlotValue(--index);
+        } while (s != v);
+        if (index < size_t(pcstack.depth()))
+            *valuepc = pcstack[index];
+    } 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;
+
+    ScriptFrameIter frameIter(cx);
+
+    if (frameIter.done())
+        return true;
+
+    if (!cx->hasfp() || !cx->fp()->isScriptFrame())
+        return true;
+
+    JSScript *script = frameIter.script();
+    jsbytecode *valuepc = frameIter.pc();
+    JSFunction *fun = frameIter.isFunctionFrame()
+                      ? frameIter.callee()
+                      : NULL;
+
+    JS_ASSERT(script->code <= valuepc && valuepc < script->code + script->length);
+
+    // Give up if in prologue.
+    if (valuepc < script->main())
+        return true;
+
+    if (!FindStartPC(cx, frameIter, 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)
 {
-    JSScript *script;
-    jsbytecode *pc;
-    ScriptFrameIter frameIter(cx);
-
-    JS_ASSERT(spindex < 0 ||
-              spindex == JSDVG_IGNORE_STACK ||
-              spindex == JSDVG_SEARCH_STACK);
-
-#ifdef JS_MORE_DETERMINISTIC
-    /*
-     * Always execute the fallback code if we need determistic behavior for
-     * differential testing. IonMonkey does not use StackFrames and this ensures
-     * we get the same error messages.
-     */
-    goto do_fallback;
-#endif
-    if (frameIter.done())
-        goto do_fallback;
-
-    if (!cx->hasfp() || !cx->fp()->isScriptFrame())
-        goto do_fallback;
-
-    script = frameIter.script();
-    pc = frameIter.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 {
-            size_t index = frameIter.numFrameSlots();
-            Value s;
-
-            /*
-             * 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.
-             */
-            do {
-                if (!index) {
-                    pcdepth = -1;
-                    goto release_pcstack;
-                }
-                s = frameIter.frameSlotValue(--index);
-            } while(s != 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 (index < size_t(pcdepth)) {
-                pc = pcstack[index];
-                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, script->function(), 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;
@@ -5952,17 +6338,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;
@@ -5971,17 +6357,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)
 {
@@ -6033,17 +6419,17 @@ 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.
      */
@@ -6051,25 +6437,20 @@ ReconstructPCStack(JSContext *cx, JSScri
     LOCAL_ASSERT(script->code <= target && target < script->code + script->length);
     jsbytecode *pc = script->code;
     unsigned pcdepth = 0;
     unsigned hpcdepth = unsigned(-1);
     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;
-        }
 
         if (op == JSOP_GOTO) {
             ptrdiff_t jmpoff = GET_JUMP_OFFSET(pc);
             if (0 < jmpoff && pc + jmpoff < target) {
                 pc += jmpoff;
                 oplen = 0;
                 continue;
             }
--- 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/jsstrinlines.h
+++ b/js/src/jsstrinlines.h
@@ -105,17 +105,17 @@ SkipSpace(const jschar *s, const jschar 
 
 /*
  * Return less than, equal to, or greater than zero depending on whether
  * s1 is less than, equal to, or greater than s2.
  */
 inline bool
 CompareChars(const jschar *s1, size_t l1, const jschar *s2, size_t l2, int32_t *result)
 {
-    size_t n = JS_MIN(l1, l2);
+    size_t n = Min(l1, l2);
     for (size_t i = 0; i < n; i++) {
         if (int32_t cmp = s1[i] - s2[i]) {
             *result = cmp;
             return true;
         }
     }
 
     *result = (int32_t)(l1 - l2);
--- a/js/src/jstypes.h
+++ b/js/src/jstypes.h
@@ -142,18 +142,16 @@
 **              JS_ROUNDUP
 **              JS_MIN
 **              JS_MAX
 ** DESCRIPTION:
 **      Commonly used macros for operations on compatible types.
 ***********************************************************************/
 #define JS_HOWMANY(x,y) (((x)+(y)-1)/(y))
 #define JS_ROUNDUP(x,y) (JS_HOWMANY(x,y)*(y))
-#define JS_MIN(x,y)     ((x)<(y)?(x):(y))
-#define JS_MAX(x,y)     ((x)>(y)?(x):(y))
 
 #include "jscpucfg.h"
 
 /*
  * Define JS_64BIT iff we are building in an environment with 64-bit
  * addresses.
  */
 #ifdef _MSC_VER
--- 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;
 }
 
@@ -168,17 +172,17 @@ ValToBin(unsigned logscale, uint32_t val
 
     if (val <= 1)
         return val;
     bin = (logscale == 10)
         ? (unsigned) ceil(log10((double) val))
         : (logscale == 2)
         ? (unsigned) JS_CEILING_LOG2W(val)
         : val;
-    return JS_MIN(bin, 10);
+    return Min(bin, 10U);
 }
 
 void
 JS_BasicStatsAccum(JSBasicStats *bs, uint32_t val)
 {
     unsigned oldscale, newscale, bin;
     double mean;
 
--- a/js/src/methodjit/BaseCompiler.h
+++ b/js/src/methodjit/BaseCompiler.h
@@ -69,18 +69,18 @@ class BaseCompiler : public MacroAssembl
 
 #ifdef JS_CPU_X64
 inline bool
 VerifyRange(void *start1, size_t size1, void *start2, size_t size2)
 {
     uintptr_t end1 = uintptr_t(start1) + size1;
     uintptr_t end2 = uintptr_t(start2) + size2;
 
-    uintptr_t lowest = JS_MIN(uintptr_t(start1), uintptr_t(start2));
-    uintptr_t highest = JS_MAX(end1, end2);
+    uintptr_t lowest = Min(uintptr_t(start1), uintptr_t(start2));
+    uintptr_t highest = Max(end1, end2);
 
     return (highest - lowest < INT_MAX);
 }
 #endif
 
 // This class wraps JSC::LinkBuffer for Mozilla-specific memory handling.
 // Every return |false| guarantees an OOM that has been correctly propagated,
 // and should continue to propagate.
--- a/js/src/prmjtime.cpp
+++ b/js/src/prmjtime.cpp
@@ -418,17 +418,17 @@ PRMJ_Now(void)
 
             MUTEX_LOCK(&calibration.data_lock);
             highresTime = calibration.offset + PRMJ_USEC_PER_SEC*
                  (highresTimerValue-calibration.timer_offset)/calibration.freq;
             cachedOffset = calibration.offset;
 
             /* On some dual processor/core systems, we might get an earlier time
                so we cache the last time that we returned */
-            calibration.last = JS_MAX(calibration.last, int64_t(highresTime));
+            calibration.last = js::Max(calibration.last, int64_t(highresTime));
             returnedTime = calibration.last;
             MUTEX_UNLOCK(&calibration.data_lock);
 
             /* Rather than assume the NT kernel ticks every 15.6ms, ask it */
             if (GetSystemTimeAdjustment(&timeAdjustment,
                                         &timeIncrement,
                                         &timeAdjustmentDisabled)) {
                 if (timeAdjustmentDisabled) {
@@ -687,17 +687,17 @@ DSTOffsetCache::getDSTOffsetMilliseconds
         return oldOffsetMilliseconds;
     }
 
     oldOffsetMilliseconds = offsetMilliseconds;
     oldRangeStartSeconds = rangeStartSeconds;
     oldRangeEndSeconds = rangeEndSeconds;
 
     if (rangeStartSeconds <= localTimeSeconds) {
-        int64_t newEndSeconds = JS_MIN(rangeEndSeconds + RANGE_EXPANSION_AMOUNT, MAX_UNIX_TIMET);
+        int64_t newEndSeconds = js::Min(rangeEndSeconds + RANGE_EXPANSION_AMOUNT, MAX_UNIX_TIMET);
         if (newEndSeconds >= localTimeSeconds) {
             int64_t endOffsetMilliseconds = computeDSTOffsetMilliseconds(newEndSeconds);
             if (endOffsetMilliseconds == offsetMilliseconds) {
                 rangeEndSeconds = newEndSeconds;
                 return offsetMilliseconds;
             }
 
             offsetMilliseconds = computeDSTOffsetMilliseconds(localTimeSeconds);
@@ -710,17 +710,17 @@ DSTOffsetCache::getDSTOffsetMilliseconds
             return offsetMilliseconds;
         }
 
         offsetMilliseconds = computeDSTOffsetMilliseconds(localTimeSeconds);
         rangeStartSeconds = rangeEndSeconds = localTimeSeconds;
         return offsetMilliseconds;
     }
 
-    int64_t newStartSeconds = JS_MAX(rangeStartSeconds - RANGE_EXPANSION_AMOUNT, 0);
+    int64_t newStartSeconds = js::Max(rangeStartSeconds - RANGE_EXPANSION_AMOUNT, int64_t(0));
     if (newStartSeconds <= localTimeSeconds) {
         int64_t startOffsetMilliseconds = computeDSTOffsetMilliseconds(newStartSeconds);
         if (startOffsetMilliseconds == offsetMilliseconds) {
             rangeStartSeconds = newStartSeconds;
             return offsetMilliseconds;
         }
 
         offsetMilliseconds = computeDSTOffsetMilliseconds(localTimeSeconds);
--- a/js/src/shell/jsoptparse.cpp
+++ b/js/src/shell/jsoptparse.cpp
@@ -173,17 +173,17 @@ OptionParser::printHelp(const char *prog
 
     if (!arguments.empty()) {
         printf("Arguments:\n");
 
         static const char fmt[] = "  %s ";
         size_t fmtChars = sizeof(fmt) - 2;
         size_t lhsLen = 0;
         for (Option **it = arguments.begin(), **end = arguments.end(); it != end; ++it)
-            lhsLen = JS_MAX(lhsLen, strlen((*it)->longflag) + fmtChars);
+            lhsLen = Max(lhsLen, strlen((*it)->longflag) + fmtChars);
 
         for (Option **it = arguments.begin(), **end = arguments.end(); it != end; ++it) {
             Option *arg = *it;
             size_t chars = printf(fmt, arg->longflag);
             for (; chars < lhsLen; ++chars)
                 putchar(' ');
             PrintParagraph(arg->help, lhsLen, helpWidth, false);
             putchar('\n');
@@ -201,17 +201,17 @@ OptionParser::printHelp(const char *prog
             size_t longflagLen = strlen(opt->longflag);
 
             size_t fmtLen;
             OptionFlagsToFormatInfo(opt->shortflag, opt->isValued(), &fmtLen);
 
             size_t len = fmtLen + longflagLen;
             if (opt->isValued())
                 len += strlen(opt->asValued()->metavar);
-            lhsLen = JS_MAX(lhsLen, len);
+            lhsLen = Max(lhsLen, len);
         }
 
         /* Print option help text. */
         for (Option **it = options.begin(), **end = options.end(); it != end; ++it) {
             Option *opt = *it;
             size_t fmtLen;
             const char *fmt = OptionFlagsToFormatInfo(opt->shortflag, opt->isValued(), &fmtLen);
             size_t chars;
--- 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/src/vm/Debugger.cpp
+++ b/js/src/vm/Debugger.cpp
@@ -4097,23 +4097,23 @@ ApplyOrCall(JSContext *cx, unsigned argc
             if (!args[1].isObject()) {
                 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_APPLY_ARGS,
                                      js_apply_str);
                 return false;
             }
             RootedObject argsobj(cx, &args[1].toObject());
             if (!js_GetLengthProperty(cx, argsobj, &callArgc))
                 return false;
-            callArgc = unsigned(JS_MIN(callArgc, StackSpace::ARGS_LENGTH_MAX));
+            callArgc = unsigned(Min(callArgc, StackSpace::ARGS_LENGTH_MAX));
             if (!argv.growBy(callArgc) || !GetElements(cx, argsobj, callArgc, argv.begin()))
                 return false;
             callArgv = argv.begin();
         }
     } else {
-        callArgc = argc > 0 ? unsigned(JS_MIN(argc - 1, StackSpace::ARGS_LENGTH_MAX)) : 0;
+        callArgc = argc > 0 ? unsigned(Min(argc - 1, StackSpace::ARGS_LENGTH_MAX)) : 0;
         callArgv = args.array() + 1;
     }
     for (unsigned i = 0; i < callArgc; i++) {
         if (!dbg->unwrapDebuggeeValue(cx, &callArgv[i]))
             return false;
     }
 
     /*
--- a/js/src/yarr/wtfbridge.h
+++ b/js/src/yarr/wtfbridge.h
@@ -272,24 +272,24 @@ namespace std {
 # undef min
 # undef max
 #endif
 
 template<typename T>
 inline T
 min(T t1, T t2)
 {
-    return JS_MIN(t1, t2);
+    return js::Min(t1, t2);
 }
 
 template<typename T>
 inline T
 max(T t1, T t2)
 {
-    return JS_MAX(t1, t2);
+    return js::Max(t1, t2);
 }
 
 template<typename T>
 inline void
 swap(T &t1, T &t2)
 {
     T tmp = t1;
     t1 = t2;
--- a/js/xpconnect/src/XPCInlines.h
+++ b/js/xpconnect/src/XPCInlines.h
@@ -477,17 +477,17 @@ XPCNativeSet::HasInterfaceWithAncestor(c
 
     return false;
 }
 
 inline JSBool
 XPCNativeSet::MatchesSetUpToInterface(const XPCNativeSet* other,
                                       XPCNativeInterface* iface) const
 {
-    int count = JS_MIN((int)mInterfaceCount, (int)other->mInterfaceCount);
+    int count = js::Min(int(mInterfaceCount), int(other->mInterfaceCount));
 
     XPCNativeInterface* const * pp1 = mInterfaces;
     XPCNativeInterface* const * pp2 = other->mInterfaces;
 
     for (int i = (int) count; i > 0; i--, pp1++, pp2++) {
         XPCNativeInterface* cur = (*pp1);
         if (cur != (*pp2))
             return false;
--- a/js/xpconnect/src/XPCJSRuntime.cpp
+++ b/js/xpconnect/src/XPCJSRuntime.cpp
@@ -17,16 +17,17 @@
 #include "nsIMemoryReporter.h"
 #include "nsPIDOMWindow.h"
 #include "nsPrintfCString.h"
 #include "mozilla/FunctionTimer.h"
 #include "prsystem.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/Telemetry.h"
 
+#include "nsLayoutStatics.h"
 #include "nsContentUtils.h"
 #include "nsCCUncollectableMarker.h"
 #include "jsfriendapi.h"
 #include "js/MemoryMetrics.h"
 #include "mozilla/dom/DOMJSClass.h"
 #include "mozilla/dom/BindingUtils.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/Attributes.h"
@@ -559,16 +560,113 @@ DoDeferredRelease(nsTArray<T> &array)
             break;
         }
         T wrapper = array[count-1];
         array.RemoveElementAt(count-1);
         NS_RELEASE(wrapper);
     }
 }
 
+class XPCIncrementalReleaseRunnable : public nsRunnable
+{
+    XPCJSRuntime *runtime;
+    nsTArray<nsISupports *> items;
+
+    static const PRTime SliceMillis = 10; /* ms */
+
+  public:
+    XPCIncrementalReleaseRunnable(XPCJSRuntime *rt, nsTArray<nsISupports *> &items);
+    virtual ~XPCIncrementalReleaseRunnable();
+
+    void ReleaseNow(bool limited);
+
+    NS_DECL_NSIRUNNABLE
+};
+
+XPCIncrementalReleaseRunnable::XPCIncrementalReleaseRunnable(XPCJSRuntime *rt,
+                                                             nsTArray<nsISupports *> &items)
+  : runtime(rt)
+{
+    nsLayoutStatics::AddRef();
+    this->items.SwapElements(items);
+}
+
+XPCIncrementalReleaseRunnable::~XPCIncrementalReleaseRunnable()
+{
+    MOZ_ASSERT(this != runtime->mReleaseRunnable);
+    nsLayoutStatics::Release();
+}
+
+void
+XPCIncrementalReleaseRunnable::ReleaseNow(bool limited)
+{
+    MOZ_ASSERT(NS_IsMainThread());
+
+    TimeDuration sliceTime = TimeDuration::FromMilliseconds(SliceMillis);
+    TimeStamp started = TimeStamp::Now();
+    PRUint32 counter = 0;
+    while (1) {
+        PRUint32 count = items.Length();
+        if (!count)
+            break;
+
+        nsISupports *wrapper = items[count - 1];
+        items.RemoveElementAt(count - 1);
+        NS_RELEASE(wrapper);
+
+        if (limited) {
+            /* We don't want to read the clock too often. */
+            counter++;
+            if (counter == 100) {
+                counter = 0;
+                if (TimeStamp::Now() - started >= sliceTime)
+                    break;
+            }
+        }
+    }
+
+    MOZ_ASSERT_IF(items.Length(), limited);
+
+    if (!items.Length()) {
+        MOZ_ASSERT(runtime->mReleaseRunnable == this);
+        runtime->mReleaseRunnable = nullptr;
+    }
+}
+
+NS_IMETHODIMP
+XPCIncrementalReleaseRunnable::Run()
+{
+    if (runtime->mReleaseRunnable != this) {
+        /* These items were already processed synchronously in JSGC_BEGIN. */
+        MOZ_ASSERT(!items.Length());
+        return NS_OK;
+    }
+
+    ReleaseNow(true);
+
+    if (items.Length()) {
+        nsresult rv = NS_DispatchToMainThread(this);
+        if (NS_FAILED(rv))
+            ReleaseNow(false);
+    }
+
+    return NS_OK;
+}
+
+void
+XPCJSRuntime::ReleaseIncrementally(nsTArray<nsISupports *> &array)
+{
+    MOZ_ASSERT(!mReleaseRunnable);
+    mReleaseRunnable = new XPCIncrementalReleaseRunnable(this, array);
+
+    nsresult rv = NS_DispatchToMainThread(mReleaseRunnable);
+    if (NS_FAILED(rv))
+        mReleaseRunnable->ReleaseNow(false);
+}
+
 /* static */ void
 XPCJSRuntime::GCCallback(JSRuntime *rt, JSGCStatus status)
 {
     XPCJSRuntime* self = nsXPConnect::GetRuntimeInstance();
     if (!self)
         return;
 
     switch (status) {
@@ -580,25 +678,31 @@ XPCJSRuntime::GCCallback(JSRuntime *rt, 
             while (JSContext *acx = JS_ContextIterator(rt, &iter)) {
                 if (!js::HasUnrootedGlobal(acx))
                     JS_ToggleOptions(acx, JSOPTION_UNROOTED_GLOBAL);
             }
             break;
         }
         case JSGC_END:
         {
+            /*
+             * If the previous GC created a runnable to release objects
+             * incrementally, and if it hasn't finished yet, finish it now. We
+             * don't want these to build up. We also don't want to allow any
+             * existing incremental release runnables to run after a
+             * non-incremental GC, since they are often used to detect leaks.
+             */
+            if (self->mReleaseRunnable)
+                self->mReleaseRunnable->ReleaseNow(false);
+
             // Do any deferred releases of native objects.
-#ifdef XPC_TRACK_DEFERRED_RELEASES
-            printf("XPC - Begin deferred Release of %d nsISupports pointers\n",
-                   self->mNativesToReleaseArray.Length());
-#endif
-            DoDeferredRelease(self->mNativesToReleaseArray);
-#ifdef XPC_TRACK_DEFERRED_RELEASES
-            printf("XPC - End deferred Releases\n");
-#endif
+            if (js::WasIncrementalGC(rt))
+                self->ReleaseIncrementally(self->mNativesToReleaseArray);
+            else
+                DoDeferredRelease(self->mNativesToReleaseArray);
 
             self->GetXPConnect()->ClearGCBeforeCC();
             break;
         }
     }
 
     nsTArray<JSGCCallback> callbacks(self->extraGCCallbacks);
     for (PRUint32 i = 0; i < callbacks.Length(); ++i)
@@ -959,16 +1063,18 @@ XPCJSRuntime::GetJSCycleCollectionContex
         if (!mJSCycleCollectionContext)
             return nullptr;
     }
     return mJSCycleCollectionContext;
 }
 
 XPCJSRuntime::~XPCJSRuntime()
 {
+    MOZ_ASSERT(!mReleaseRunnable);
+
     if (mWatchdogWakeup) {
         // If the watchdog thread is running, tell it to terminate waking it
         // up if necessary and wait until it signals that it finished. As we
         // must release the lock before calling PR_DestroyCondVar, we use an
         // extra block here.
         {
             AutoLockWatchdog lock(this);
             if (mWatchdogThread) {
@@ -1995,16 +2101,17 @@ XPCJSRuntime::XPCJSRuntime(nsXPConnect* 
    mVariantRoots(nullptr),
    mWrappedJSRoots(nullptr),
    mObjectHolderRoots(nullptr),
    mWatchdogLock(nullptr),
    mWatchdogWakeup(nullptr),
    mWatchdogThread(nullptr),
    mWatchdogHibernating(false),
    mLastActiveTime(-1),
+   mReleaseRunnable(nullptr),
    mExceptionManagerNotAvailable(false)
 {
 #ifdef XPC_CHECK_WRAPPERS_AT_SHUTDOWN
     DEBUG_WrappedNativeHashtable =
         JS_NewDHashTable(JS_DHashGetStubOps(), nullptr,
                          sizeof(JSDHashEntryStub), 128);
 #endif
     NS_TIME_FUNCTION;
--- 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/js/xpconnect/src/xpcprivate.h
+++ b/js/xpconnect/src/xpcprivate.h
@@ -633,16 +633,17 @@ private:
 
 /***************************************************************************/
 
 // In the current xpconnect system there can only be one XPCJSRuntime.
 // So, xpconnect can only be used on one JSRuntime within the process.
 
 // no virtuals. no refcounting.
 class XPCJSContextStack;
+class XPCIncrementalReleaseRunnable;
 class XPCJSRuntime
 {
 public:
     static XPCJSRuntime* newXPCJSRuntime(nsXPConnect* aXPConnect);
     static XPCJSRuntime* Get() { return nsXPConnect::GetXPConnect()->GetRuntime(); }
 
     JSRuntime*     GetJSRuntime() const {return mJSRuntime;}
     nsXPConnect*   GetXPConnect() const {return mXPConnect;}
@@ -861,16 +862,18 @@ private:
     XPCJSRuntime(); // no implementation
     XPCJSRuntime(nsXPConnect* aXPConnect);
 
     // The caller must be holding the GC lock
     void RescheduleWatchdog(XPCContext* ccx);
 
     static void WatchdogMain(void *arg);
 
+    void ReleaseIncrementally(nsTArray<nsISupports *> &array);
+
     static bool gNewDOMBindingsEnabled;
     static bool gExperimentalBindingsEnabled;
 
     static const char* mStrings[IDX_TOTAL_COUNT];
     jsid mStrIDs[IDX_TOTAL_COUNT];
     jsval mStrJSVals[IDX_TOTAL_COUNT];
 
     nsXPConnect*             mXPConnect;
@@ -901,22 +904,24 @@ private:
     XPCRootSetElem *mObjectHolderRoots;
     JSDHashTable mJSHolders;
     PRLock *mWatchdogLock;
     PRCondVar *mWatchdogWakeup;
     PRThread *mWatchdogThread;
     nsTArray<JSGCCallback> extraGCCallbacks;
     bool mWatchdogHibernating;
     PRTime mLastActiveTime; // -1 if active NOW
+    XPCIncrementalReleaseRunnable *mReleaseRunnable;
 
     nsCOMPtr<nsIException>   mPendingException;
     nsCOMPtr<nsIExceptionManager> mExceptionManager;
     bool mExceptionManagerNotAvailable;
 
     friend class AutoLockWatchdog;
+    friend class XPCIncrementalReleaseRunnable;
 };
 
 /***************************************************************************/
 /***************************************************************************/
 // XPCContext is mostly a dumb class to hold JSContext specific data and
 // maps that let us find wrappers created for the given JSContext.
 
 // no virtuals
--- 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");