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 id23447
push userdanderson@mozilla.com
push dateTue, 11 Sep 2012 17:34:27 +0000
treeherdermozilla-central@fdfaef738a00 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone17.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge 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);
 }