Merge m-c again to pick up 75deec1f1a7b
authorKartikaya Gupta <kgupta@mozilla.com>
Tue, 28 Feb 2012 14:37:26 -0500
changeset 89292 5dc30efb809060dee6be95288da4402c05b2aac2
parent 89291 726cd11889e6af5b64ddb55db9e467d3d575a528 (current diff)
parent 87990 30b4f99a137c72345bb0401fa1970598687d80c7 (diff)
child 89293 9320f23871a1bafce28986b4dcfa3472af501b16
push id7119
push usereakhgari@mozilla.com
push dateWed, 14 Mar 2012 17:40:57 +0000
treeherdermozilla-inbound@10d7baa4aff0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone13.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 m-c again to pick up 75deec1f1a7b
configure.in
content/base/src/nsParserUtils.cpp
content/base/src/nsParserUtils.h
gfx/gl/GLContext.cpp
gfx/gl/GLContext.h
gfx/gl/GLContextProviderEGL.cpp
gfx/layers/opengl/LayerManagerOGL.cpp
gfx/layers/opengl/LayerManagerOGL.h
js/src/tests/workers.py
mobile/android/base/AndroidManifest.xml.in
mobile/android/base/GeckoAppShell.java
mobile/android/base/Makefile.in
mobile/android/base/sync/repositories/android/Authorities.java.in
mobile/android/base/sync/repositories/android/BrowserContract.java
mobile/android/chrome/content/browser.js
modules/libpref/src/init/all.js
toolkit/components/feeds/nsIScriptableUnescapeHTML.idl
toolkit/components/feeds/nsScriptableUnescapeHTML.cpp
toolkit/components/feeds/nsScriptableUnescapeHTML.h
widget/android/nsWindow.cpp
widget/xpwidgets/nsBaseWidget.cpp
widget/xpwidgets/nsBaseWidget.h
--- a/accessible/src/atk/nsAccessibleWrap.cpp
+++ b/accessible/src/atk/nsAccessibleWrap.cpp
@@ -866,20 +866,21 @@ refChildCB(AtkObject *aAtkObj, gint aChi
         return nsnull;
 
     AtkObject* childAtkObj = nsAccessibleWrap::GetAtkObject(accChild);
 
     NS_ASSERTION(childAtkObj, "Fail to get AtkObj");
     if (!childAtkObj)
         return nsnull;
     g_object_ref(childAtkObj);
-    
-    //this will addref parent
+
+  if (aAtkObj != childAtkObj->accessible_parent)
     atk_object_set_parent(childAtkObj, aAtkObj);
-    return childAtkObj;
+
+  return childAtkObj;
 }
 
 gint
 getIndexInParentCB(AtkObject *aAtkObj)
 {
     // We don't use nsIAccessible::GetIndexInParent() because
     // for ATK we don't want to include text leaf nodes as children
     nsAccessibleWrap *accWrap = GetAccessibleWrap(aAtkObj);
--- a/accessible/src/base/StyleInfo.cpp
+++ b/accessible/src/base/StyleInfo.cpp
@@ -105,8 +105,21 @@ void
 StyleInfo::Margin(css::Side aSide, nsAString& aValue)
 {
   aValue.Truncate();
 
   nscoord coordVal = mElement->GetPrimaryFrame()->GetUsedMargin().Side(aSide);
   aValue.AppendFloat(nsPresContext::AppUnitsToFloatCSSPixels(coordVal));
   aValue.AppendLiteral("px");
 }
+
+void
+StyleInfo::Format(const nscolor& aValue, nsString& aFormattedValue)
+{
+  // Combine the string like rgb(R, G, B) from nscolor.
+  aFormattedValue.AppendLiteral("rgb(");
+  aFormattedValue.AppendInt(NS_GET_R(aValue));
+  aFormattedValue.AppendLiteral(", ");
+  aFormattedValue.AppendInt(NS_GET_G(aValue));
+  aFormattedValue.AppendLiteral(", ");
+  aFormattedValue.AppendInt(NS_GET_B(aValue));
+  aFormattedValue.Append(')');
+}
--- a/accessible/src/base/StyleInfo.h
+++ b/accessible/src/base/StyleInfo.h
@@ -55,16 +55,18 @@ public:
   void Display(nsAString& aValue);
   void TextAlign(nsAString& aValue);
   void TextIndent(nsAString& aValue);
   void MarginLeft(nsAString& aValue) { Margin(css::eSideLeft, aValue); }
   void MarginRight(nsAString& aValue) { Margin(css::eSideRight, aValue); }
   void MarginTop(nsAString& aValue) { Margin(css::eSideTop, aValue); }
   void MarginBottom(nsAString& aValue) { Margin(css::eSideBottom, aValue); }
 
+  static void Format(const nscolor& aValue, nsString& aFormattedValue);
+
 private:
   StyleInfo() MOZ_DELETE;
   StyleInfo(const StyleInfo&) MOZ_DELETE;
   StyleInfo& operator = (const StyleInfo&) MOZ_DELETE;
 
   void Margin(css::Side aSide, nsAString& aValue);
 
   dom::Element* mElement;
--- a/accessible/src/base/nsAccDocManager.cpp
+++ b/accessible/src/base/nsAccDocManager.cpp
@@ -359,19 +359,19 @@ nsDocAccessible*
 nsAccDocManager::CreateDocOrRootAccessible(nsIDocument *aDocument)
 {
   // Ignore temporary, hiding, resource documents and documents without
   // docshell.
   if (aDocument->IsInitialDocument() || !aDocument->IsVisible() ||
       aDocument->IsResourceDoc() || !aDocument->IsActive())
     return nsnull;
 
-  // Ignore documents without presshell.
-  nsIPresShell *presShell = aDocument->GetShell();
-  if (!presShell)
+  // Ignore documents without presshell and not having root frame.
+  nsIPresShell* presShell = aDocument->GetShell();
+  if (!presShell || !presShell->GetRootFrame())
     return nsnull;
 
   // Do not create document accessible until role content is loaded, otherwise
   // we get accessible document with wrong role.
   nsIContent *rootElm = nsCoreUtils::GetRoleContent(aDocument);
   if (!rootElm)
     return nsnull;
 
--- a/accessible/src/base/nsTextAttrs.cpp
+++ b/accessible/src/base/nsTextAttrs.cpp
@@ -36,22 +36,26 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsTextAttrs.h"
 
 #include "nsAccUtils.h"
 #include "nsCoreUtils.h"
 #include "nsHyperTextAccessibleWrap.h"
+#include "StyleInfo.h"
 
 #include "gfxFont.h"
 #include "gfxUserFontSet.h"
 #include "nsFontMetrics.h"
 #include "nsLayoutUtils.h"
 
+using namespace mozilla;
+using namespace mozilla::a11y;
+
 ////////////////////////////////////////////////////////////////////////////////
 // Constants and structures
 
 /**
  * Item of the gCSSTextAttrsMap map.
  */
 struct nsCSSTextAttrMapItem
 {
@@ -65,17 +69,16 @@ struct nsCSSTextAttrMapItem
  * The map of CSS properties to text attributes.
  */
 const char* const kAnyValue = nsnull;
 const char* const kCopyValue = nsnull;
 
 static nsCSSTextAttrMapItem gCSSTextAttrsMap[] =
 {
   // CSS name            CSS value        Attribute name                                Attribute value
-  { "color",             kAnyValue,       &nsGkAtoms::color,                 kCopyValue },
   { "font-family",       kAnyValue,       &nsGkAtoms::font_family,            kCopyValue },
   { "font-style",        kAnyValue,       &nsGkAtoms::font_style,             kCopyValue },
   { "text-decoration",   "line-through",  &nsGkAtoms::textLineThroughStyle,  "solid" },
   { "text-decoration",   "underline",     &nsGkAtoms::textUnderlineStyle,    "solid" },
   { "vertical-align",    kAnyValue,       &nsGkAtoms::textPosition,          kCopyValue }
 };
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -149,44 +152,44 @@ nsTextAttrsMgr::GetAttributes(nsIPersist
   }
 
   nsTArray<nsITextAttr*> textAttrArray(10);
 
   // "language" text attribute
   nsLangTextAttr langTextAttr(mHyperTextAcc, hyperTextElm, offsetNode);
   textAttrArray.AppendElement(static_cast<nsITextAttr*>(&langTextAttr));
 
-  // "color" text attribute
-  nsCSSTextAttr colorTextAttr(0, hyperTextElm, offsetElm);
-  textAttrArray.AppendElement(static_cast<nsITextAttr*>(&colorTextAttr));
-
   // "font-family" text attribute
-  nsCSSTextAttr fontFamilyTextAttr(1, hyperTextElm, offsetElm);
+  nsCSSTextAttr fontFamilyTextAttr(0, hyperTextElm, offsetElm);
   textAttrArray.AppendElement(static_cast<nsITextAttr*>(&fontFamilyTextAttr));
 
   // "font-style" text attribute
-  nsCSSTextAttr fontStyleTextAttr(2, hyperTextElm, offsetElm);
+  nsCSSTextAttr fontStyleTextAttr(1, hyperTextElm, offsetElm);
   textAttrArray.AppendElement(static_cast<nsITextAttr*>(&fontStyleTextAttr));
 
   // "text-line-through-style" text attribute
-  nsCSSTextAttr lineThroughTextAttr(3, hyperTextElm, offsetElm);
+  nsCSSTextAttr lineThroughTextAttr(2, hyperTextElm, offsetElm);
   textAttrArray.AppendElement(static_cast<nsITextAttr*>(&lineThroughTextAttr));
 
   // "text-underline-style" text attribute
-  nsCSSTextAttr underlineTextAttr(4, hyperTextElm, offsetElm);
+  nsCSSTextAttr underlineTextAttr(3, hyperTextElm, offsetElm);
   textAttrArray.AppendElement(static_cast<nsITextAttr*>(&underlineTextAttr));
 
   // "text-position" text attribute
-  nsCSSTextAttr posTextAttr(5, hyperTextElm, offsetElm);
+  nsCSSTextAttr posTextAttr(4, hyperTextElm, offsetElm);
   textAttrArray.AppendElement(static_cast<nsITextAttr*>(&posTextAttr));
 
   // "background-color" text attribute
   nsBGColorTextAttr bgColorTextAttr(rootFrame, frame);
   textAttrArray.AppendElement(static_cast<nsITextAttr*>(&bgColorTextAttr));
 
+  // "color" text attribute
+  ColorTextAttr colorTextAttr(rootFrame, frame);
+  textAttrArray.AppendElement(static_cast<nsITextAttr*>(&colorTextAttr));
+
   // "font-size" text attribute
   nsFontSizeTextAttr fontSizeTextAttr(rootFrame, frame);
   textAttrArray.AppendElement(static_cast<nsITextAttr*>(&fontSizeTextAttr));
 
   // "font-weight" text attribute
   nsFontWeightTextAttr fontWeightTextAttr(rootFrame, frame);
   textAttrArray.AppendElement(static_cast<nsITextAttr*>(&fontWeightTextAttr));
 
@@ -358,17 +361,17 @@ nsCSSTextAttr::Format(const nsAutoString
   if (attrValue != kCopyValue)
     AppendASCIItoUTF16(attrValue, aFormattedValue);
   else
     aFormattedValue = aValue;
 }
 
 
 ////////////////////////////////////////////////////////////////////////////////
-// nsBackgroundTextAttr
+// nsBGColorTextAttr
 ////////////////////////////////////////////////////////////////////////////////
 
 nsBGColorTextAttr::nsBGColorTextAttr(nsIFrame *aRootFrame, nsIFrame *aFrame) :
   nsTextAttr<nscolor>(aFrame == nsnull), mRootFrame(aRootFrame)
 {
   mIsRootDefined = GetColor(mRootFrame, &mRootNativeValue);
   if (aFrame)
     mIsDefined = GetColor(aFrame, &mNativeValue);
@@ -382,26 +385,18 @@ nsBGColorTextAttr::GetValueFor(nsIConten
     return false;
 
   return GetColor(frame, aValue);
 }
 
 void
 nsBGColorTextAttr::Format(const nscolor& aValue, nsAString& aFormattedValue)
 {
-  // Combine the string like rgb(R, G, B) from nscolor.
   nsAutoString value;
-  value.AppendLiteral("rgb(");
-  value.AppendInt(NS_GET_R(aValue));
-  value.AppendLiteral(", ");
-  value.AppendInt(NS_GET_G(aValue));
-  value.AppendLiteral(", ");
-  value.AppendInt(NS_GET_B(aValue));
-  value.Append(')');
-
+  StyleInfo::Format(aValue, value);
   aFormattedValue = value;
 }
 
 bool
 nsBGColorTextAttr::GetColor(nsIFrame *aFrame, nscolor *aColor)
 {
   const nsStyleBackground *styleBackground = aFrame->GetStyleBackground();
 
@@ -422,16 +417,53 @@ nsBGColorTextAttr::GetColor(nsIFrame *aF
   if (parentFrame == mRootFrame)
     return false;
 
   return GetColor(parentFrame, aColor);
 }
 
 
 ////////////////////////////////////////////////////////////////////////////////
+// ColorTextAttr
+////////////////////////////////////////////////////////////////////////////////
+
+ColorTextAttr::ColorTextAttr(nsIFrame* aRootFrame, nsIFrame* aFrame) :
+  nsTextAttr<nscolor>(!aFrame)
+{
+  mRootNativeValue = aRootFrame->GetStyleColor()->mColor;
+  mIsRootDefined = true;
+
+  if (aFrame) {
+    mNativeValue = aFrame->GetStyleColor()->mColor;
+    mIsDefined = true;
+  }
+}
+
+bool
+ColorTextAttr::GetValueFor(nsIContent* aContent, nscolor* aValue)
+{
+  nsIFrame* frame = aContent->GetPrimaryFrame();
+  if (frame) {
+    *aValue = frame->GetStyleColor()->mColor;
+    return true;
+  }
+
+  return false;
+}
+
+void
+ColorTextAttr::Format(const nscolor& aValue, nsAString& aFormattedValue)
+{
+  nsAutoString value;
+  StyleInfo::Format(aValue, value);
+  aFormattedValue = value;
+}
+
+
+////////////////////////////////////////////////////////////////////////////////
 // nsFontSizeTextAttr
 ////////////////////////////////////////////////////////////////////////////////
 
 nsFontSizeTextAttr::nsFontSizeTextAttr(nsIFrame *aRootFrame, nsIFrame *aFrame) :
   nsTextAttr<nscoord>(aFrame == nsnull)
 {
   mDC = aRootFrame->PresContext()->DeviceContext();
 
--- a/accessible/src/base/nsTextAttrs.h
+++ b/accessible/src/base/nsTextAttrs.h
@@ -303,16 +303,35 @@ protected:
 
 private:
   bool GetColor(nsIFrame *aFrame, nscolor *aColor);
   nsIFrame *mRootFrame;
 };
 
 
 /**
+ * Class is used for the work with 'color' text attribute in nsTextAttrsMgr
+ * class.
+ */
+class ColorTextAttr : public nsTextAttr<nscolor>
+{
+public:
+  ColorTextAttr(nsIFrame* aRootFrame, nsIFrame* aFrame);
+
+  // nsITextAttr
+  virtual nsIAtom* GetName() const { return nsGkAtoms::color; }
+
+protected:
+  // nsTextAttr
+  virtual bool GetValueFor(nsIContent* aContent, nscolor* aValue);
+  virtual void Format(const nscolor& aValue, nsAString& aFormattedValue);
+};
+
+
+/**
  * Class is used for the work with "font-size" text attribute in nsTextAttrsMgr
  * class.
  */
 class nsFontSizeTextAttr : public nsTextAttr<nscoord>
 {
 public:
   nsFontSizeTextAttr(nsIFrame *aRootFrame, nsIFrame *aFrame);
 
--- a/b2g/installer/package-manifest.in
+++ b/b2g/installer/package-manifest.in
@@ -187,16 +187,17 @@
 @BINPATH@/components/fastfind.xpt
 @BINPATH@/components/feeds.xpt
 #ifdef MOZ_GTK2
 @BINPATH@/components/filepicker.xpt
 #endif
 @BINPATH@/components/find.xpt
 @BINPATH@/components/fuel.xpt
 @BINPATH@/components/gfx.xpt
+@BINPATH@/components/html5.xpt
 @BINPATH@/components/htmlparser.xpt
 @BINPATH@/components/imglib2.xpt
 @BINPATH@/components/imgicon.xpt
 @BINPATH@/components/inspector.xpt
 @BINPATH@/components/intl.xpt
 @BINPATH@/components/jar.xpt
 @BINPATH@/components/jetpack.xpt
 @BINPATH@/components/jsdservice.xpt
--- a/browser/components/sessionstore/src/nsSessionStore.js
+++ b/browser/components/sessionstore/src/nsSessionStore.js
@@ -1676,21 +1676,26 @@ SessionStoreService.prototype = {
       if (groupsData.totalNumber > 1)
         return [false, false];
     }
 
     // Step 2 of processing:
     // If we're still here, then the window is usable. Look at the open tabs in
     // comparison to home pages. If all the tabs are home pages then we'll end
     // up overwriting all of them. Otherwise we'll just close the tabs that
-    // match home pages.
-    let homePages = aWindow.gHomeButton.getHomePage().split("|");
+    // match home pages. Tabs with the about:blank URI will always be
+    // overwritten.
+    let homePages = ["about:blank"];
     let removableTabs = [];
     let tabbrowser = aWindow.gBrowser;
     let normalTabsLen = tabbrowser.tabs.length - tabbrowser._numPinnedTabs;
+    let startupPref = this._prefBranch.getIntPref("startup.page");
+    if (startupPref == 1)
+      homePages = homePages.concat(aWindow.gHomeButton.getHomePage().split("|"));
+
     for (let i = tabbrowser._numPinnedTabs; i < tabbrowser.tabs.length; i++) {
       let tab = tabbrowser.tabs[i];
       if (homePages.indexOf(tab.linkedBrowser.currentURI.spec) != -1) {
         removableTabs.push(tab);
       }
     }
 
     if (tabbrowser.tabs.length == removableTabs.length) {
--- a/browser/config/mozconfigs/linux32/debug
+++ b/browser/config/mozconfigs/linux32/debug
@@ -1,10 +1,11 @@
 ac_add_options --enable-debug
 ac_add_options --enable-trace-malloc
+ac_add_options --enable-signmar
 
 . $topsrcdir/build/unix/mozconfig.linux
 
 # Avoid dependency on libstdc++ 4.5
 ac_add_options --enable-stdcxx-compat
 
 # Needed to enable breakpad in application.ini
 export MOZILLA_OFFICIAL=1
--- a/browser/config/mozconfigs/linux32/nightly
+++ b/browser/config/mozconfigs/linux32/nightly
@@ -1,11 +1,12 @@
 ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
 ac_add_options --enable-update-packaging
 ac_add_options --enable-codesighs
+ac_add_options --enable-signmar
 
 # Nightlies only since this has a cost in performance
 ac_add_options --enable-js-diagnostics
 
 . $topsrcdir/build/unix/mozconfig.linux
 
 # Avoid dependency on libstdc++ 4.5
 ac_add_options --enable-stdcxx-compat
--- a/browser/config/mozconfigs/linux64/debug
+++ b/browser/config/mozconfigs/linux64/debug
@@ -1,10 +1,11 @@
 ac_add_options --enable-debug
 ac_add_options --enable-trace-malloc
+ac_add_options --enable-signmar
 
 . $topsrcdir/build/unix/mozconfig.linux
 
 # Avoid dependency on libstdc++ 4.5
 ac_add_options --enable-stdcxx-compat
 
 # Needed to enable breakpad in application.ini
 export MOZILLA_OFFICIAL=1
--- a/browser/config/mozconfigs/linux64/nightly
+++ b/browser/config/mozconfigs/linux64/nightly
@@ -1,11 +1,12 @@
 ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
 ac_add_options --enable-update-packaging
 ac_add_options --enable-codesighs
+ac_add_options --enable-signmar
 
 # Nightlies only since this has a cost in performance
 ac_add_options --enable-js-diagnostics
 
 . $topsrcdir/build/unix/mozconfig.linux
 
 # Avoid dependency on libstdc++ 4.5
 ac_add_options --enable-stdcxx-compat
--- a/browser/config/mozconfigs/macosx-lion-universal/nightly
+++ b/browser/config/mozconfigs/macosx-lion-universal/nightly
@@ -2,16 +2,17 @@
 
 # Universal builds override the default of browser (bug 575283 comment 29)
 ac_add_options --enable-application=browser
 
 ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
 ac_add_options --enable-update-packaging
 ac_add_options --enable-codesighs
 ac_add_options --disable-install-strip
+ac_add_options --enable-signmar
 
 # Nightlies only since this has a cost in performance
 ac_add_options --enable-js-diagnostics
 
 # Needed to enable breakpad in application.ini
 export MOZILLA_OFFICIAL=1
 
 export MOZ_TELEMETRY_REPORTING=1
--- a/browser/config/mozconfigs/macosx-universal/nightly
+++ b/browser/config/mozconfigs/macosx-universal/nightly
@@ -2,16 +2,17 @@
 
 # Universal builds override the default of browser (bug 575283 comment 29)
 ac_add_options --enable-application=browser
 
 ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
 ac_add_options --enable-update-packaging
 ac_add_options --enable-codesighs
 ac_add_options --disable-install-strip
+ac_add_options --enable-signmar
 
 # Nightlies only since this has a cost in performance
 ac_add_options --enable-js-diagnostics
 
 # Needed to enable breakpad in application.ini
 export MOZILLA_OFFICIAL=1
 
 export MOZ_TELEMETRY_REPORTING=1
--- a/browser/config/mozconfigs/macosx32-lion/debug
+++ b/browser/config/mozconfigs/macosx32-lion/debug
@@ -1,11 +1,12 @@
 . $topsrcdir/build/macosx/mozconfig.leopard
 ac_add_options --enable-debug
 ac_add_options --enable-trace-malloc
+ac_add_options --enable-signmar
 
 # Enable parallel compiling
 mk_add_options MOZ_MAKE_FLAGS="-j12"
 
 # Needed to enable breakpad in application.ini
 export MOZILLA_OFFICIAL=1
 
 ac_add_options --with-macbundlename-prefix=Firefox
--- a/browser/config/mozconfigs/macosx32/debug
+++ b/browser/config/mozconfigs/macosx32/debug
@@ -1,11 +1,12 @@
 . $topsrcdir/build/macosx/mozconfig.leopard
 ac_add_options --enable-debug
 ac_add_options --enable-trace-malloc
+ac_add_options --enable-signmar
 
 # Enable parallel compiling
 mk_add_options MOZ_MAKE_FLAGS="-j4"
 
 # Needed to enable breakpad in application.ini
 export MOZILLA_OFFICIAL=1
 
 ac_add_options --with-macbundlename-prefix=Firefox
--- a/browser/config/mozconfigs/macosx64-lion/debug
+++ b/browser/config/mozconfigs/macosx64-lion/debug
@@ -1,13 +1,14 @@
 . $topsrcdir/build/macosx/common
 
 ac_add_options --enable-debug
 ac_add_options --enable-trace-malloc
 ac_add_options --enable-accessibility
+ac_add_options --enable-signmar
 
 # Enable parallel compiling
 mk_add_options MOZ_MAKE_FLAGS="-j12"
 
 # Needed to enable breakpad in application.ini
 export MOZILLA_OFFICIAL=1
 
 ac_add_options --with-macbundlename-prefix=Firefox
--- a/browser/config/mozconfigs/macosx64/debug
+++ b/browser/config/mozconfigs/macosx64/debug
@@ -1,13 +1,14 @@
 . $topsrcdir/build/macosx/common
 
 ac_add_options --enable-debug
 ac_add_options --enable-trace-malloc
 ac_add_options --enable-accessibility
+ac_add_options --enable-signmar
 
 # Enable parallel compiling
 mk_add_options MOZ_MAKE_FLAGS="-j4"
 
 # Needed to enable breakpad in application.ini
 export MOZILLA_OFFICIAL=1
 
 ac_add_options --with-macbundlename-prefix=Firefox
--- a/browser/config/mozconfigs/win32/debug
+++ b/browser/config/mozconfigs/win32/debug
@@ -1,9 +1,10 @@
 ac_add_options --enable-debug
 ac_add_options --enable-trace-malloc
+ac_add_options --enable-signmar
 
 # Needed to enable breakpad in application.ini
 export MOZILLA_OFFICIAL=1
 
 mk_add_options MOZ_MAKE_FLAGS=-j1
 
 . $topsrcdir/browser/config/mozconfigs/win32/vs2010-mozconfig
--- a/browser/config/mozconfigs/win32/nightly
+++ b/browser/config/mozconfigs/win32/nightly
@@ -1,14 +1,15 @@
 # for pgo
 mk_add_options PROFILE_GEN_SCRIPT='$(PYTHON) $(MOZ_OBJDIR)/_profile/pgo/profileserver.py'
 
 ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
 ac_add_options --enable-update-packaging
 ac_add_options --enable-jemalloc
+ac_add_options --enable-signmar
 
 # Nightlies only since this has a cost in performance
 ac_add_options --enable-js-diagnostics
 
 # Needed to enable breakpad in application.ini
 export MOZILLA_OFFICIAL=1
 
 export MOZ_TELEMETRY_REPORTING=1
--- a/browser/config/mozconfigs/win64/debug
+++ b/browser/config/mozconfigs/win64/debug
@@ -1,10 +1,11 @@
 ac_add_options --target=x86_64-pc-mingw32
 ac_add_options --host=x86_64-pc-mingw32
 
 ac_add_options --enable-debug
 ac_add_options --enable-trace-malloc
+ac_add_options --enable-signmar
 
 # Needed to enable breakpad in application.ini
 export MOZILLA_OFFICIAL=1
 
 mk_add_options MOZ_MAKE_FLAGS=-j1
--- a/browser/config/mozconfigs/win64/nightly
+++ b/browser/config/mozconfigs/win64/nightly
@@ -2,16 +2,17 @@ ac_add_options --target=x86_64-pc-mingw3
 ac_add_options --host=x86_64-pc-mingw32
 
 # for pgo
 mk_add_options PROFILE_GEN_SCRIPT='$(PYTHON) $(MOZ_OBJDIR)/_profile/pgo/profileserver.py'
 
 ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
 ac_add_options --enable-update-packaging
 ac_add_options --enable-jemalloc
+ac_add_options --enable-signmar
 
 # Nightlies only since this has a cost in performance
 ac_add_options --enable-js-diagnostics
 
 # Needed to enable breakpad in application.ini
 export MOZILLA_OFFICIAL=1
 
 export MOZ_TELEMETRY_REPORTING=1
--- a/browser/devtools/scratchpad/scratchpad.js
+++ b/browser/devtools/scratchpad/scratchpad.js
@@ -70,16 +70,18 @@ const DEVTOOLS_CHROME_ENABLED = "devtool
 const BUTTON_POSITION_SAVE = 0;
 const BUTTON_POSITION_CANCEL = 1;
 const BUTTON_POSITION_DONT_SAVE = 2;
 
 /**
  * The scratchpad object handles the Scratchpad window functionality.
  */
 var Scratchpad = {
+  _initialWindowTitle: document.title,
+
   /**
    * The script execution context. This tells Scratchpad in which context the
    * script shall execute.
    *
    * Possible values:
    *   - SCRATCHPAD_CONTEXT_CONTENT to execute code in the context of the current
    *   tab content window object.
    *   - SCRATCHPAD_CONTEXT_BROWSER to execute code in the context of the
@@ -146,50 +148,67 @@ var Scratchpad = {
   /**
    * Set the filename in the scratchpad UI and object
    *
    * @param string aFilename
    *        The new filename
    */
   setFilename: function SP_setFilename(aFilename)
   {
-    document.title = this.filename = aFilename;
+    this.filename = aFilename;
+    this._updateTitle();
+  },
+
+  /**
+   * Update the Scratchpad window title based on the current state.
+   * @private
+   */
+  _updateTitle: function SP__updateTitle()
+  {
+    if (this.filename) {
+      document.title = (this.editor && this.editor.dirty ? "*" : "") +
+                       this.filename;
+    } else {
+      document.title = this._initialWindowTitle;
+    }
   },
 
   /**
    * Get the current state of the scratchpad. Called by the
    * Scratchpad Manager for session storing.
    *
    * @return object
    *        An object with 3 properties: filename, text, and
    *        executionContext.
    */
   getState: function SP_getState()
   {
     return {
       filename: this.filename,
       text: this.getText(),
       executionContext: this.executionContext,
-      saved: this.saved
+      saved: !this.editor.dirty,
     };
   },
 
   /**
    * Set the filename and execution context using the given state. Called
    * when scratchpad is being restored from a previous session.
    *
    * @param object aState
    *        An object with filename and executionContext properties.
    */
   setState: function SP_getState(aState)
   {
     if (aState.filename) {
       this.setFilename(aState.filename);
     }
-    this.saved = aState.saved;
+    if (this.editor) {
+      this.editor.dirty = !aState.saved;
+    }
 
     if (aState.executionContext == SCRATCHPAD_CONTEXT_BROWSER) {
       this.setBrowserContext();
     }
     else {
       this.setContentContext();
     }
   },
@@ -633,17 +652,17 @@ var Scratchpad = {
   openFile: function SP_openFile()
   {
     let fp = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker);
     fp.init(window, this.strings.GetStringFromName("openFile.title"),
             Ci.nsIFilePicker.modeOpen);
     fp.defaultString = "";
     if (fp.show() != Ci.nsIFilePicker.returnCancel) {
       this.setFilename(fp.file.path);
-      this.importFromFile(fp.file, false, this.onTextSaved.bind(this));
+      this.importFromFile(fp.file, false);
     }
   },
 
   /**
    * Save the textbox content to the currently open file.
    *
    * @param function aCallback
    *        Optional function you want to call when file is saved
@@ -653,17 +672,19 @@ var Scratchpad = {
     if (!this.filename) {
       return this.saveFileAs(aCallback);
     }
 
     let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile);
     file.initWithPath(this.filename);
 
     this.exportToFile(file, true, false, function(aStatus) {
-      this.onTextSaved();
+      if (Components.isSuccessCode(aStatus)) {
+        this.editor.dirty = false;
+      }
       if (aCallback) {
         aCallback(aStatus);
       }
     });
   },
 
   /**
    * Save the textbox content to a new file.
@@ -676,17 +697,19 @@ var Scratchpad = {
     let fp = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker);
     fp.init(window, this.strings.GetStringFromName("saveFileAs"),
             Ci.nsIFilePicker.modeSave);
     fp.defaultString = "scratchpad.js";
     if (fp.show() != Ci.nsIFilePicker.returnCancel) {
       this.setFilename(fp.file.path);
 
       this.exportToFile(fp.file, true, false, function(aStatus) {
-        this.onTextSaved();
+        if (Components.isSuccessCode(aStatus)) {
+          this.editor.dirty = false;
+        }
         if (aCallback) {
           aCallback(aStatus);
         }
       });
     }
   },
 
   /**
@@ -778,67 +801,69 @@ var Scratchpad = {
    *
    * @param nsIDOMEvent aEvent
    */
   onLoad: function SP_onLoad(aEvent)
   {
     if (aEvent.target != document) {
       return;
     }
-
     let chrome = Services.prefs.getBoolPref(DEVTOOLS_CHROME_ENABLED);
     if (chrome) {
       let environmentMenu = document.getElementById("sp-environment-menu");
       let errorConsoleCommand = document.getElementById("sp-cmd-errorConsole");
       let chromeContextCommand = document.getElementById("sp-cmd-browserContext");
       environmentMenu.removeAttribute("hidden");
       chromeContextCommand.removeAttribute("disabled");
       errorConsoleCommand.removeAttribute("disabled");
     }
 
+    let state = null;
     let initialText = this.strings.GetStringFromName("scratchpadIntro");
     if ("arguments" in window &&
          window.arguments[0] instanceof Ci.nsIDialogParamBlock) {
-      let state = JSON.parse(window.arguments[0].GetString(0));
+      state = JSON.parse(window.arguments[0].GetString(0));
       this.setState(state);
       initialText = state.text;
     }
 
     this.editor = new SourceEditor();
 
     let config = {
       mode: SourceEditor.MODES.JAVASCRIPT,
       showLineNumbers: true,
       initialText: initialText,
+      contextMenu: "scratchpad-text-popup",
     };
 
     let editorPlaceholder = document.getElementById("scratchpad-editor");
-    this.editor.init(editorPlaceholder, config, this.onEditorLoad.bind(this));
+    this.editor.init(editorPlaceholder, config,
+                     this._onEditorLoad.bind(this, state));
   },
 
   /**
    * The load event handler for the source editor. This method does post-load
    * editor initialization.
+   *
+   * @private
+   * @param object aState
+   *        The initial Scratchpad state object.
    */
-  onEditorLoad: function SP_onEditorLoad()
+  _onEditorLoad: function SP__onEditorLoad(aState)
   {
-    this.editor.addEventListener(SourceEditor.EVENTS.CONTEXT_MENU,
-                                 this.onContextMenu);
+    this.editor.addEventListener(SourceEditor.EVENTS.DIRTY_CHANGED,
+                                 this._onDirtyChanged);
     this.editor.focus();
     this.editor.setCaretOffset(this.editor.getCharCount());
+    if (aState) {
+      this.editor.dirty = !aState.saved;
+    }
 
     this.initialized = true;
 
-    if (this.filename && !this.saved) {
-      this.onTextChanged();
-    }
-    else if (this.filename && this.saved) {
-      this.onTextSaved();
-    }
-
     this._triggerObservers("Ready");
   },
 
   /**
    * Insert text at the current caret location.
    *
    * @param string aText
    *        The text you want to insert.
@@ -846,46 +871,27 @@ var Scratchpad = {
   insertTextAtCaret: function SP_insertTextAtCaret(aText)
   {
     let caretOffset = this.editor.getCaretOffset();
     this.setText(aText, caretOffset, caretOffset);
     this.editor.setCaretOffset(caretOffset + aText.length);
   },
 
   /**
-   * The contextmenu event handler for the source editor. This method opens the
-   * Scratchpad context menu popup at the pointer location.
+   * The Source Editor DirtyChanged event handler. This function updates the
+   * Scratchpad window title to show an asterisk when there are unsaved changes.
    *
+   * @private
+   * @see SourceEditor.EVENTS.DIRTY_CHANGED
    * @param object aEvent
-   *        An event object coming from the SourceEditor. This object needs to
-   *        hold the screenX and screenY properties.
+   *        The DirtyChanged event object.
    */
-  onContextMenu: function SP_onContextMenu(aEvent)
+  _onDirtyChanged: function SP__onDirtyChanged(aEvent)
   {
-    let menu = document.getElementById("scratchpad-text-popup");
-    if (menu.state == "closed") {
-      menu.openPopupAtScreen(aEvent.screenX, aEvent.screenY, true);
-    }
-  },
-
-  /**
-   * The popupshowing event handler for the Edit menu. This method updates the
-   * enabled/disabled state of the Undo and Redo commands, based on the editor
-   * state such that the menu items render correctly for the user when the menu
-   * shows.
-   */
-  onEditPopupShowing: function SP_onEditPopupShowing()
-  {
-    goUpdateGlobalEditMenuItems();
-
-    let undo = document.getElementById("sp-cmd-undo");
-    undo.setAttribute("disabled", !this.editor.canUndo());
-
-    let redo = document.getElementById("sp-cmd-redo");
-    redo.setAttribute("disabled", !this.editor.canRedo());
+    Scratchpad._updateTitle();
   },
 
   /**
    * Undo the last action of the user.
    */
   undo: function SP_undo()
   {
     this.editor.undo();
@@ -895,123 +901,133 @@ var Scratchpad = {
    * Redo the previously undone action.
    */
   redo: function SP_redo()
   {
     this.editor.redo();
   },
 
   /**
-   * This method adds a listener to the editor for text changes. Called when
-   * a scratchpad is saved, opened from file, or restored from a saved file.
-   */
-  onTextSaved: function SP_onTextSaved(aStatus)
-  {
-    if (aStatus && !Components.isSuccessCode(aStatus)) {
-      return;
-    }
-    if (!document || !this.initialized) {
-      return;  // file saved to disk after window has closed
-    }
-    document.title = document.title.replace(/^\*/, "");
-    this.saved = true;
-    this.editor.addEventListener(SourceEditor.EVENTS.TEXT_CHANGED,
-                                 this.onTextChanged);
-  },
-
-  /**
-   * The scratchpad handler for editor text change events. This handler
-   * indicates that there are unsaved changes in the UI.
-   */
-  onTextChanged: function SP_onTextChanged()
-  {
-    document.title = "*" + document.title;
-    Scratchpad.saved = false;
-    Scratchpad.editor.removeEventListener(SourceEditor.EVENTS.TEXT_CHANGED,
-                                          Scratchpad.onTextChanged);
-  },
-
-  /**
    * The Scratchpad window unload event handler. This method unloads/destroys
    * the source editor.
    *
    * @param nsIDOMEvent aEvent
    */
   onUnload: function SP_onUnload(aEvent)
   {
     if (aEvent.target != document) {
       return;
     }
 
     this.resetContext();
-    this.editor.removeEventListener(SourceEditor.EVENTS.CONTEXT_MENU,
-                                    this.onContextMenu);
+    this.editor.removeEventListener(SourceEditor.EVENTS.DIRTY_CHANGED,
+                                    this._onDirtyChanged);
     this.editor.destroy();
     this.editor = null;
     this.initialized = false;
   },
 
   /**
    * Prompt to save scratchpad if it has unsaved changes.
    *
    * @param function aCallback
-   *        Optional function you want to call when file is saved
+   *        Optional function you want to call when file is saved. The callback
+   *        receives three arguments:
+   *          - toClose (boolean) - tells if the window should be closed.
+   *          - saved (boolen) - tells if the file has been saved.
+   *          - status (number) - the file save status result (if the file was
+   *          saved).
    * @return boolean
    *         Whether the window should be closed
    */
   promptSave: function SP_promptSave(aCallback)
   {
-    if (this.filename && !this.saved) {
+    if (this.filename && this.editor.dirty) {
       let ps = Services.prompt;
       let flags = ps.BUTTON_POS_0 * ps.BUTTON_TITLE_SAVE +
                   ps.BUTTON_POS_1 * ps.BUTTON_TITLE_CANCEL +
                   ps.BUTTON_POS_2 * ps.BUTTON_TITLE_DONT_SAVE;
 
       let button = ps.confirmEx(window,
                           this.strings.GetStringFromName("confirmClose.title"),
                           this.strings.GetStringFromName("confirmClose"),
                           flags, null, null, null, null, {});
 
       if (button == BUTTON_POSITION_CANCEL) {
+        if (aCallback) {
+          aCallback(false, false);
+        }
         return false;
       }
+
       if (button == BUTTON_POSITION_SAVE) {
-        this.saveFile(aCallback);
+        this.saveFile(function(aStatus) {
+          if (aCallback) {
+            aCallback(true, true, aStatus);
+          }
+        });
+        return true;
       }
     }
+
+    if (aCallback) {
+      aCallback(true, false);
+    }
     return true;
   },
 
   /**
    * Handler for window close event. Prompts to save scratchpad if
    * there are unsaved changes.
    *
    * @param nsIDOMEvent aEvent
    */
   onClose: function SP_onClose(aEvent)
   {
-    let toClose = this.promptSave();
-    if (!toClose) {
-      aEvent.preventDefault();
+    if (this._skipClosePrompt) {
+      return;
     }
+
+    this.promptSave(function(aShouldClose, aSaved, aStatus) {
+      let shouldClose = aShouldClose;
+      if (aSaved && !Components.isSuccessCode(aStatus)) {
+        shouldClose = false;
+      }
+
+      if (shouldClose) {
+        this._skipClosePrompt = true;
+        window.close();
+      }
+    }.bind(this));
+    aEvent.preventDefault();
   },
 
   /**
    * Close the scratchpad window. Prompts before closing if the scratchpad
    * has unsaved changes.
    *
    * @param function aCallback
    *        Optional function you want to call when file is saved
    */
   close: function SP_close(aCallback)
   {
-    let toClose = this.promptSave(aCallback);
-    if (toClose) {
-      window.close();
-    }
+    this.promptSave(function(aShouldClose, aSaved, aStatus) {
+      let shouldClose = aShouldClose;
+      if (aSaved && !Components.isSuccessCode(aStatus)) {
+        shouldClose = false;
+      }
+
+      if (shouldClose) {
+        this._skipClosePrompt = true;
+        window.close();
+      }
+      if (aCallback) {
+        aCallback();
+      }
+    }.bind(this));
   },
 
   _observers: [],
 
   /**
    * Add an observer for Scratchpad events.
    *
    * The observer implements IScratchpadObserver := {
--- a/browser/devtools/scratchpad/scratchpad.xul
+++ b/browser/devtools/scratchpad/scratchpad.xul
@@ -76,21 +76,21 @@
   <command id="sp-cmd-run" oncommand="Scratchpad.run();"/>
   <command id="sp-cmd-inspect" oncommand="Scratchpad.inspect();"/>
   <command id="sp-cmd-display" oncommand="Scratchpad.display();"/>
   <command id="sp-cmd-contentContext" oncommand="Scratchpad.setContentContext();"/>
   <command id="sp-cmd-browserContext" oncommand="Scratchpad.setBrowserContext();" disabled="true"/>
   <command id="sp-cmd-resetContext" oncommand="Scratchpad.resetContext();"/>
   <command id="sp-cmd-errorConsole" oncommand="Scratchpad.openErrorConsole();" disabled="true"/>
   <command id="sp-cmd-webConsole" oncommand="Scratchpad.openWebConsole();"/>
-  <command id="sp-cmd-undo" oncommand="Scratchpad.undo();" disabled="true"/>
-  <command id="sp-cmd-redo" oncommand="Scratchpad.redo();" disabled="true"/>
   <command id="sp-cmd-documentationLink" oncommand="Scratchpad.openDocumentationPage();"/>
 </commandset>
 
+<keyset id="sourceEditorKeys"/>
+
 <keyset id="sp-keyset">
   <key id="sp-key-window"
        key="&newWindowCmd.commandkey;"
        command="sp-cmd-newWindow"
        modifiers="accel"/>
   <key id="sp-key-open"
        key="&openFileCmd.commandkey;"
        command="sp-cmd-openFile"
@@ -118,19 +118,19 @@
   <key id="key_copy"
        key="&copyCmd.key;"
        modifiers="accel"/>
   <key id="key_paste"
        key="&pasteCmd.key;"
        modifiers="accel"/>
   <key id="key_selectAll" key="&selectAllCmd.key;" modifiers="accel"/>
   <key id="key_undo" key="&undoCmd.key;" modifiers="accel"
-       oncommand="Scratchpad.undo();"/>
+       command="se-cmd-undo"/>
   <key id="key_redo" key="&undoCmd.key;" modifiers="accel,shift"
-       oncommand="Scratchpad.redo();"/>
+       command="se-cmd-redo"/>
   <key id="sp-key-run"
        key="&run.key;"
        command="sp-cmd-run"
        modifiers="accel"/>
   <key id="sp-key-inspect"
        key="&inspect.key;"
        command="sp-cmd-inspect"
        modifiers="accel"/>
@@ -163,20 +163,16 @@
   <key id="key_findAgain"
        keycode="VK_F3"
        command="cmd_findAgain"/>
   <key id="key_findPrevious"
        keycode="VK_F3"
        command="cmd_findPrevious"
        modifiers="shift"/>
 #endif
-  <key id="key_gotoLine"
-       key="&gotoLineCmd.key;"
-       command="cmd_gotoLine"
-       modifiers="accel"/>
   <key id="key_openHelp"
        keycode="VK_F1"
        command="sp-cmd-documentationLink"/>
 </keyset>
 
 
 <menubar id="sp-menubar">
   <menu id="sp-file-menu" label="&fileMenu.label;"
@@ -218,27 +214,27 @@
                 accesskey="&closeCmd.accesskey;"
                 command="sp-cmd-close"/>
     </menupopup>
   </menu>
 
   <menu id="sp-edit-menu" label="&editMenu.label;"
         accesskey="&editMenu.accesskey;">
     <menupopup id="sp-menu_editpopup"
-               onpopupshowing="Scratchpad.onEditPopupShowing()">
+               onpopupshowing="goUpdateGlobalEditMenuItems()">
       <menuitem id="sp-menu-undo"
                 label="&undoCmd.label;"
                 key="key_undo"
                 accesskey="&undoCmd.accesskey;"
-                command="sp-cmd-undo"/>
+                command="se-cmd-undo"/>
       <menuitem id="sp-menu-redo"
                 label="&redoCmd.label;"
                 key="key_redo"
                 accesskey="&redoCmd.accesskey;"
-                command="sp-cmd-redo"/>
+                command="se-cmd-redo"/>
       <menuseparator/>
       <menuitem id="sp-menu-cut"
                 label="&cutCmd.label;"
                 key="key_cut"
                 accesskey="&cutCmd.accesskey;"
                 command="cmd_cut"/>
       <menuitem id="sp-menu-copy"
                 label="&copyCmd.label;"
--- a/browser/devtools/scratchpad/test/browser_scratchpad_bug_653427_confirm_close.js
+++ b/browser/devtools/scratchpad/test/browser_scratchpad_bug_653427_confirm_close.js
@@ -41,94 +41,92 @@ function test()
   testSavedFile();
 
   content.location = "data:text/html,<p>test scratchpad save file prompt on closing";
 }
 
 function testNew()
 {
   openScratchpad(function(win) {
-    win.Scratchpad.close();
-    ok(win.closed, "new scratchpad window should close without prompting")
-    done();
+    win.Scratchpad.close(function() {
+      ok(win.closed, "new scratchpad window should close without prompting")
+      done();
+    });
   }, {noFocus: true});
 }
 
 function testSavedFile()
 {
   openScratchpad(function(win) {
     win.Scratchpad.filename = "test.js";
-    win.Scratchpad.saved = true;
-    win.Scratchpad.close();
-
-    ok(win.closed, "scratchpad from file with no changes should close")
-    done();
+    win.Scratchpad.editor.dirty = false;
+    win.Scratchpad.close(function() {
+      ok(win.closed, "scratchpad from file with no changes should close")
+      done();
+    });
   }, {noFocus: true});
 }
 
 function testUnsaved()
 {
   testUnsavedFileCancel();
   testUnsavedFileSave();
   testUnsavedFileDontSave();
 }
 
 function testUnsavedFileCancel()
 {
   openScratchpad(function(win) {
-    win.Scratchpad.filename = "test.js";
-    win.Scratchpad.saved = false;
+    win.Scratchpad.setFilename("test.js");
+    win.Scratchpad.editor.dirty = true;
 
     promptButton = win.BUTTON_POSITION_CANCEL;
 
-    win.Scratchpad.close();
-
-    ok(!win.closed, "cancelling dialog shouldn't close scratchpad");
-
-    win.close();
-    done();
+    win.Scratchpad.close(function() {
+      ok(!win.closed, "cancelling dialog shouldn't close scratchpad");
+      win.close();
+      done();
+    });
   }, {noFocus: true});
 }
 
 function testUnsavedFileSave()
 {
   openScratchpad(function(win) {
     win.Scratchpad.importFromFile(gFile, true, function(status, content) {
-      win.Scratchpad.filename = gFile.path;
-      win.Scratchpad.onTextSaved();
+      win.Scratchpad.setFilename(gFile.path);
 
       let text = "new text";
       win.Scratchpad.setText(text);
 
       promptButton = win.BUTTON_POSITION_SAVE;
 
       win.Scratchpad.close(function() {
+        ok(win.closed, 'pressing "Save" in dialog should close scratchpad');
         readFile(gFile, function(savedContent) {
           is(savedContent, text, 'prompted "Save" worked when closing scratchpad');
           done();
         });
       });
-
-      ok(win.closed, 'pressing "Save" in dialog should close scratchpad');
     });
   }, {noFocus: true});
 }
 
 function testUnsavedFileDontSave()
 {
   openScratchpad(function(win) {
-    win.Scratchpad.filename = gFile.path;
-    win.Scratchpad.saved = false;
+    win.Scratchpad.setFilename(gFile.path);
+    win.Scratchpad.editor.dirty = true;
 
     promptButton = win.BUTTON_POSITION_DONT_SAVE;
 
-    win.Scratchpad.close();
-
-    ok(win.closed, 'pressing "Don\'t Save" in dialog should close scratchpad');
-    done();
+    win.Scratchpad.close(function() {
+      ok(win.closed, 'pressing "Don\'t Save" in dialog should close scratchpad');
+      done();
+    });
   }, {noFocus: true});
 }
 
 function cleanup()
 {
   Services.prompt = oldPrompt;
   gFile.remove(false);
   gFile = null;
--- a/browser/devtools/scratchpad/test/browser_scratchpad_bug_669612_unsaved.js
+++ b/browser/devtools/scratchpad/test/browser_scratchpad_bug_669612_unsaved.js
@@ -1,74 +1,67 @@
 /* vim: set ts=2 et sw=2 tw=80: */
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */  
 
 // only finish() when correct number of tests are done
-const expected = 5;
+const expected = 4;
 var count = 0;
 function done()
 {
   if (++count == expected) {
     finish();
   }
 }
 
 var ScratchpadManager = Scratchpad.ScratchpadManager;
 
 
 function test()
 {
   waitForExplicitFinish();
   
   testListeners();
-  testErrorStatus();
   testRestoreNotFromFile();
   testRestoreFromFileSaved();
   testRestoreFromFileUnsaved();
 
   content.location = "data:text/html,<p>test star* UI for unsaved file changes";
 }
 
 function testListeners()
 {
   openScratchpad(function(aWin, aScratchpad) {
     aScratchpad.setText("new text");
     ok(!isStar(aWin), "no star if scratchpad isn't from a file");
 
-    aScratchpad.onTextSaved();
+    aScratchpad.editor.dirty = false;
     ok(!isStar(aWin), "no star before changing text");
 
+    aScratchpad.setFilename("foo.js");
     aScratchpad.setText("new text2");
     ok(isStar(aWin), "shows star if scratchpad text changes");
 
-    aScratchpad.onTextSaved();
+    aScratchpad.editor.dirty = false;
     ok(!isStar(aWin), "no star if scratchpad was just saved");
 
+    aScratchpad.setText("new text3");
+    ok(isStar(aWin), "shows star if scratchpad has more changes");
+
     aScratchpad.undo();
-    ok(isStar(aWin), "star if scratchpad undo");
+    ok(!isStar(aWin), "no star if scratchpad undo to save point");
+
+    aScratchpad.undo();
+    ok(isStar(aWin), "star if scratchpad undo past save point");
 
     aWin.close();
     done();
   }, {noFocus: true});
 }
 
-function testErrorStatus()
-{
-  openScratchpad(function(aWin, aScratchpad) {
-    aScratchpad.onTextSaved(Components.results.NS_ERROR_FAILURE);
-    aScratchpad.setText("new text");
-    ok(!isStar(aWin), "no star if file save failed");
-
-    aWin.close();
-    done();
-  }, {noFocus: true});
-}
-
-
 function testRestoreNotFromFile()
 {
   let session = [{
     text: "test1",
     executionContext: 1
   }];
 
   let [win] = ScratchpadManager.restoreSession(session);
--- a/browser/devtools/scratchpad/test/browser_scratchpad_ui.js
+++ b/browser/devtools/scratchpad/test/browser_scratchpad_ui.js
@@ -27,18 +27,16 @@ function runTests()
     "sp-menu-save": "saveFile",
     "sp-menu-saveas": "saveFileAs",
     "sp-text-run": "run",
     "sp-text-inspect": "inspect",
     "sp-text-display": "display",
     "sp-text-resetContext": "resetContext",
     "sp-menu-content": "setContentContext",
     "sp-menu-browser": "setBrowserContext",
-    "sp-menu-undo": "undo",
-    "sp-menu-redo": "redo",
   };
 
   let lastMethodCalled = null;
   sp.__noSuchMethod__ = function(aMethodName) {
     lastMethodCalled = aMethodName;
   };
 
   for (let id in methodsAndItems) {
--- a/browser/devtools/sourceeditor/source-editor-orion.jsm
+++ b/browser/devtools/sourceeditor/source-editor-orion.jsm
@@ -141,16 +141,18 @@ function SourceEditor() {
   // Update the SourceEditor defaults from user preferences.
 
   SourceEditor.DEFAULTS.tabSize =
     Services.prefs.getIntPref(SourceEditor.PREFS.TAB_SIZE);
   SourceEditor.DEFAULTS.expandTab =
     Services.prefs.getBoolPref(SourceEditor.PREFS.EXPAND_TAB);
 
   this._onOrionSelection = this._onOrionSelection.bind(this);
+  this._onTextChanged = this._onTextChanged.bind(this);
+  this._onOrionContextMenu = this._onOrionContextMenu.bind(this);
 
   this._eventTarget = {};
   this._eventListenersQueue = [];
   this.ui = new SourceEditorUI(this);
 }
 
 SourceEditor.prototype = {
   _view: null,
@@ -167,16 +169,18 @@ SourceEditor.prototype = {
   _currentLineAnnotation: null,
   _primarySelectionTimeout: null,
   _mode: null,
   _expandTab: null,
   _tabSize: null,
   _iframeWindow: null,
   _eventTarget: null,
   _eventListenersQueue: null,
+  _contextMenu: null,
+  _dirty: false,
 
   /**
    * The Source Editor user interface manager.
    * @type object
    *       An instance of the SourceEditorUI.
    */
   ui: null,
 
@@ -274,17 +278,31 @@ SourceEditor.prototype = {
 
     let onOrionLoad = function() {
       this._view.removeEventListener("Load", onOrionLoad);
       this._onOrionLoad();
     }.bind(this);
 
     this._view.addEventListener("Load", onOrionLoad);
     if (config.highlightCurrentLine || Services.appinfo.OS == "Linux") {
-      this._view.addEventListener("Selection", this._onOrionSelection);
+      this.addEventListener(SourceEditor.EVENTS.SELECTION,
+                            this._onOrionSelection);
+    }
+    this.addEventListener(SourceEditor.EVENTS.TEXT_CHANGED,
+                           this._onTextChanged);
+
+    if (typeof config.contextMenu == "string") {
+      let chromeDocument = this.parentElement.ownerDocument;
+      this._contextMenu = chromeDocument.getElementById(config.contextMenu);
+    } else if (typeof config.contextMenu == "object" ) {
+      this._contextMenu = config._contextMenu;
+    }
+    if (this._contextMenu) {
+      this.addEventListener(SourceEditor.EVENTS.CONTEXT_MENU,
+                            this._onOrionContextMenu);
     }
 
     let KeyBinding = window.require("orion/textview/keyBinding").KeyBinding;
     let TextDND = window.require("orion/textview/textDND").TextDND;
     let Rulers = window.require("orion/textview/rulers");
     let LineNumberRuler = Rulers.LineNumberRuler;
     let AnnotationRuler = Rulers.AnnotationRuler;
     let OverviewRuler = Rulers.OverviewRuler;
@@ -583,16 +601,54 @@ SourceEditor.prototype = {
       }
       this._primarySelectionTimeout =
         window.setTimeout(this._updatePrimarySelection.bind(this),
                           PRIMARY_SELECTION_DELAY);
     }
   },
 
   /**
+   * The TextChanged event handler which tracks the dirty state of the editor.
+   *
+   * @see SourceEditor.EVENTS.TEXT_CHANGED
+   * @see SourceEditor.EVENTS.DIRTY_CHANGED
+   * @see SourceEditor.dirty
+   * @private
+   */
+  _onTextChanged: function SE__onTextChanged()
+  {
+    this._updateDirty();
+  },
+
+  /**
+   * The Orion contextmenu event handler. This method opens the default or
+   * the custom context menu popup at the pointer location.
+   *
+   * @param object aEvent
+   *        The contextmenu event object coming from Orion. This object should
+   *        hold the screenX and screenY properties.
+   */
+  _onOrionContextMenu: function SE__onOrionContextMenu(aEvent)
+  {
+    if (this._contextMenu.state == "closed") {
+      this._contextMenu.openPopupAtScreen(aEvent.screenX || 0,
+                                          aEvent.screenY || 0, true);
+    }
+  },
+
+  /**
+   * Update the dirty state of the editor based on the undo stack.
+   * @private
+   */
+  _updateDirty: function SE__updateDirty()
+  {
+    this.dirty = !this._undoStack.isClean();
+  },
+
+  /**
    * Update the X11 PRIMARY buffer to hold the current selection.
    * @private
    */
   _updatePrimarySelection: function SE__updatePrimarySelection()
   {
     this._primarySelectionTimeout = null;
 
     let text = this.getSelectedText();
@@ -861,28 +917,38 @@ SourceEditor.prototype = {
       this._eventTarget.removeEventListener(aEventType, aCallback);
     } else {
       this._eventListenersQueue.push(["remove", aEventType, aCallback]);
     }
   },
 
   /**
    * Undo a change in the editor.
+   *
+   * @return boolean
+   *         True if there was a change undone, false otherwise.
    */
   undo: function SE_undo()
   {
-    return this._undoStack.undo();
+    let result = this._undoStack.undo();
+    this.ui._onUndoRedo();
+    return result;
   },
 
   /**
    * Redo a change in the editor.
+   *
+   * @return boolean
+   *         True if there was a change redone, false otherwise.
    */
   redo: function SE_redo()
   {
-    return this._undoStack.redo();
+    let result = this._undoStack.redo();
+    this.ui._onUndoRedo();
+    return result;
   },
 
   /**
    * Check if there are changes that can be undone.
    *
    * @return boolean
    *         True if there are changes that can be undone, false otherwise.
    */
@@ -898,21 +964,64 @@ SourceEditor.prototype = {
    *         True if there are changes that can be repeated, false otherwise.
    */
   canRedo: function SE_canRedo()
   {
     return this._undoStack.canRedo();
   },
 
   /**
-   * Reset the Undo stack
+   * Reset the Undo stack.
    */
   resetUndo: function SE_resetUndo()
   {
     this._undoStack.reset();
+    this._updateDirty();
+    this.ui._onUndoRedo();
+  },
+
+  /**
+   * Set the "dirty" state of the editor. Set this to false when you save the
+   * text being edited. The dirty state will become true once the user makes
+   * changes to the text.
+   *
+   * @param boolean aNewValue
+   *        The new dirty state: true if the text is not saved, false if you
+   *        just saved the text.
+   */
+  set dirty(aNewValue)
+  {
+    if (aNewValue == this._dirty) {
+      return;
+    }
+
+    let event = {
+      type: SourceEditor.EVENTS.DIRTY_CHANGED,
+      oldValue: this._dirty,
+      newValue: aNewValue,
+    };
+
+    this._dirty = aNewValue;
+    if (!this._dirty && !this._undoStack.isClean()) {
+      this._undoStack.markClean();
+    }
+    this._dispatchEvent(event);
+  },
+
+  /**
+   * Get the editor "dirty" state. This tells if the text is considered saved or
+   * not.
+   *
+   * @see SourceEditor.EVENTS.DIRTY_CHANGED
+   * @return boolean
+   *         True if there are changes which are not saved, false otherwise.
+   */
+  get dirty()
+  {
+    return this._dirty;
   },
 
   /**
    * Start a compound change in the editor. Compound changes are grouped into
    * only one change that you can undo later, after you invoke
    * endCompoundChange().
    */
   startCompoundChange: function SE_startCompoundChange()
@@ -1321,20 +1430,32 @@ SourceEditor.prototype = {
   },
 
   /**
    * Destroy/uninitialize the editor.
    */
   destroy: function SE_destroy()
   {
     if (this._config.highlightCurrentLine || Services.appinfo.OS == "Linux") {
-      this._view.removeEventListener("Selection", this._onOrionSelection);
+      this.removeEventListener(SourceEditor.EVENTS.SELECTION,
+                               this._onOrionSelection);
     }
     this._onOrionSelection = null;
 
+    this.removeEventListener(SourceEditor.EVENTS.TEXT_CHANGED,
+                             this._onTextChanged);
+    this._onTextChanged = null;
+
+    if (this._contextMenu) {
+      this.removeEventListener(SourceEditor.EVENTS.CONTEXT_MENU,
+                               this._onOrionContextMenu);
+      this._contextMenu = null;
+    }
+    this._onOrionContextMenu = null;
+
     if (this._primarySelectionTimeout) {
       let window = this.parentElement.ownerDocument.defaultView;
       window.clearTimeout(this._primarySelectionTimeout);
       this._primarySelectionTimeout = null;
     }
 
     this._view.destroy();
     this.ui.destroy();
--- a/browser/devtools/sourceeditor/source-editor-overlay.xul
+++ b/browser/devtools/sourceeditor/source-editor-overlay.xul
@@ -30,18 +30,85 @@
    - under the terms of either the GPL or the LGPL, and not to allow others to
    - use your version of this file under the terms of the MPL, indicate your
    - decision by deleting the provisions above and replace them with the notice
    - and other provisions required by the GPL or the LGPL. If you do not delete
    - the provisions above, a recipient may use your version of this file under
    - the terms of any one of the MPL, the GPL or the LGPL.
    -
    - ***** END LICENSE BLOCK ***** -->
-
+<!DOCTYPE overlay SYSTEM "chrome://browser/locale/devtools/sourceeditor.dtd">
 <overlay id="sourceEditorOverlay"
          xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+  <!-- This Source Editor overlay requires the editMenuOverlay.xul to be loaded.
+       The globalOverlay.js script is also required in the XUL document where
+       the source-editor-overlay.xul is loaded. -->
+
   <commandset id="sourceEditorCommands">
     <command id="cmd_find" oncommand="goDoCommand('cmd_find')"/>
     <command id="cmd_findAgain" oncommand="goDoCommand('cmd_findAgain')" disabled="true"/>
     <command id="cmd_findPrevious" oncommand="goDoCommand('cmd_findPrevious')" disabled="true"/>
     <command id="cmd_gotoLine" oncommand="goDoCommand('cmd_gotoLine')"/>
+    <command id="se-cmd-undo" oncommand="goDoCommand('se-cmd-undo')" disabled="true"/>
+    <command id="se-cmd-redo" oncommand="goDoCommand('se-cmd-redo')" disabled="true"/>
   </commandset>
+
+  <keyset id="sourceEditorKeys">
+    <key id="key_gotoLine"
+         key="&gotoLineCmd.key;"
+         command="cmd_gotoLine"
+         modifiers="accel"/>
+  </keyset>
+
+  <menupopup id="sourceEditorContextMenu"
+             onpopupshowing="goUpdateGlobalEditMenuItems()">
+    <menuitem id="se-menu-undo"
+              label="&undoCmd.label;"
+              key="key_undo"
+              accesskey="&undoCmd.accesskey;"
+              command="se-cmd-undo"/>
+    <menuseparator/>
+    <menuitem id="se-menu-cut"
+              label="&cutCmd.label;"
+              key="key_cut"
+              accesskey="&cutCmd.accesskey;"
+              command="cmd_cut"/>
+    <menuitem id="se-menu-copy"
+              label="&copyCmd.label;"
+              key="key_copy"
+              accesskey="&copyCmd.accesskey;"
+              command="cmd_copy"/>
+    <menuitem id="se-menu-paste"
+              label="&pasteCmd.label;"
+              key="key_paste"
+              accesskey="&pasteCmd.accesskey;"
+              command="cmd_paste"/>
+    <menuitem id="se-menu-delete"
+              label="&deleteCmd.label;"
+              key="key_delete"
+              accesskey="&deleteCmd.accesskey;"
+              command="cmd_delete"/>
+    <menuseparator/>
+    <menuitem id="se-menu-selectAll"
+              label="&selectAllCmd.label;"
+              key="key_selectAll"
+              accesskey="&selectAllCmd.accesskey;"
+              command="cmd_selectAll"/>
+    <menuseparator/>
+    <menuitem id="se-menu-find"
+              label="&findCmd.label;"
+              accesskey="&findCmd.accesskey;"
+              key="key_find"
+              command="cmd_find"/>
+    <menuitem id="se-menu-findAgain"
+              label="&findAgainCmd.label;"
+              accesskey="&findAgainCmd.accesskey;"
+              key="key_findAgain"
+              command="cmd_findAgain"/>
+    <menuseparator/>
+    <menuitem id="se-menu-gotoLine"
+              label="&gotoLineCmd.label;"
+              accesskey="&gotoLineCmd.accesskey;"
+              key="key_gotoLine"
+              command="cmd_gotoLine"/>
+  </menupopup>
 </overlay>
--- a/browser/devtools/sourceeditor/source-editor-ui.jsm
+++ b/browser/devtools/sourceeditor/source-editor-ui.jsm
@@ -45,16 +45,17 @@ Cu.import("resource://gre/modules/Servic
 var EXPORTED_SYMBOLS = ["SourceEditorUI"];
 
 /**
  * The Source Editor component user interface.
  */
 function SourceEditorUI(aEditor)
 {
   this.editor = aEditor;
+  this._onDirtyChanged = this._onDirtyChanged.bind(this);
 }
 
 SourceEditorUI.prototype = {
   /**
    * Initialize the user interface. This is called by the SourceEditor.init()
    * method.
    */
   init: function SEU_init()
@@ -67,16 +68,18 @@ SourceEditorUI.prototype = {
    * initialization and it is ready for usage. Currently this code sets up the
    * nsIController.
    */
   onReady: function SEU_onReady()
   {
     if (this._ownerWindow.controllers) {
       this._controller = new SourceEditorController(this.editor);
       this._ownerWindow.controllers.insertControllerAt(0, this._controller);
+      this.editor.addEventListener(this.editor.EVENTS.DIRTY_CHANGED,
+                                   this._onDirtyChanged);
     }
   },
 
   /**
    * The "go to line" command UI. This displays a prompt that allows the user to
    * input the line number to jump to.
    */
   gotoLine: function SEU_gotoLine()
@@ -173,21 +176,49 @@ SourceEditorUI.prototype = {
 
     if (this._ownerWindow.goUpdateCommand) {
       this._ownerWindow.goUpdateCommand("cmd_findAgain");
       this._ownerWindow.goUpdateCommand("cmd_findPrevious");
     }
   },
 
   /**
+   * This is executed after each undo/redo operation.
+   * @private
+   */
+  _onUndoRedo: function SEU__onUndoRedo()
+  {
+    if (this._ownerWindow.goUpdateCommand) {
+      this._ownerWindow.goUpdateCommand("se-cmd-undo");
+      this._ownerWindow.goUpdateCommand("se-cmd-redo");
+    }
+  },
+
+  /**
+   * The DirtyChanged event handler for the editor. This tracks the editor state
+   * changes to make sure the Source Editor overlay Undo/Redo commands are kept
+   * up to date.
+   * @private
+   */
+  _onDirtyChanged: function SEU__onDirtyChanged()
+  {
+    this._onUndoRedo();
+  },
+
+  /**
    * Destroy the SourceEditorUI instance. This is called by the
    * SourceEditor.destroy() method.
    */
   destroy: function SEU_destroy()
   {
+    if (this._ownerWindow.controllers) {
+      this.editor.removeEventListener(this.editor.EVENTS.DIRTY_CHANGED,
+                                      this._onDirtyChanged);
+    }
+
     this._ownerWindow = null;
     this.editor = null;
     this._controller = null;
   },
 };
 
 /**
  * The Source Editor nsIController implements features that need to be available
@@ -215,16 +246,18 @@ SourceEditorController.prototype = {
   {
     let result;
 
     switch (aCommand) {
       case "cmd_find":
       case "cmd_findAgain":
       case "cmd_findPrevious":
       case "cmd_gotoLine":
+      case "se-cmd-undo":
+      case "se-cmd-redo":
         result = true;
         break;
       default:
         result = false;
         break;
     }
 
     return result;
@@ -246,16 +279,22 @@ SourceEditorController.prototype = {
       case "cmd_find":
       case "cmd_gotoLine":
         result = true;
         break;
       case "cmd_findAgain":
       case "cmd_findPrevious":
         result = this._editor.lastFind && this._editor.lastFind.lastFound != -1;
         break;
+      case "se-cmd-undo":
+        result = this._editor.canUndo();
+        break;
+      case "se-cmd-redo":
+        result = this._editor.canRedo();
+        break;
       default:
         result = false;
         break;
     }
 
     return result;
   },
 
@@ -276,13 +315,19 @@ SourceEditorController.prototype = {
         this._editor.ui.findNext();
         break;
       case "cmd_findPrevious":
         this._editor.ui.findPrevious();
         break;
       case "cmd_gotoLine":
         this._editor.ui.gotoLine();
         break;
+      case "se-cmd-undo":
+        this._editor.undo();
+        break;
+      case "se-cmd-redo":
+        this._editor.redo();
+        break;
     }
   },
 
   onEvent: function() { }
 };
--- a/browser/devtools/sourceeditor/source-editor.jsm
+++ b/browser/devtools/sourceeditor/source-editor.jsm
@@ -194,16 +194,32 @@ SourceEditor.DEFAULTS = {
    *   - accel - boolean for the Accel key (Cmd on Macs, Ctrl on Linux/Windows).
    *   - shift - boolean for the Shift key.
    *   - alt - boolean for the Alt key.
    *   - callback - optional function to invoke, if the action is not predefined
    *   in the editor.
    * @type array
    */
   keys: null,
+
+  /**
+   * The editor context menu you want to display when the user right-clicks
+   * within the editor. This property can be:
+   *   - a string that tells the ID of the xul:menupopup you want. This needs to
+   *   be available within the editor parentElement.ownerDocument.
+   *   - an nsIDOMElement object reference pointing to the xul:menupopup you
+   *   want to open when the contextmenu event is fired.
+   *
+   * Set this property to a falsey value to disable the default context menu.
+   *
+   * @see SourceEditor.EVENTS.CONTEXT_MENU for more control over the contextmenu
+   * event.
+   * @type string|nsIDOMElement
+   */
+  contextMenu: "sourceEditorContextMenu",
 };
 
 /**
  * Known editor events you can listen for.
  */
 SourceEditor.EVENTS = {
   /**
    * The contextmenu event is fired when the editor context menu is invoked. The
@@ -211,16 +227,18 @@ SourceEditor.EVENTS = {
    *   - x - the pointer location on the x axis, relative to the document the
    *   user is editing.
    *   - y - the pointer location on the y axis, relative to the document the
    *   user is editing.
    *   - screenX - the pointer location on the x axis, relative to the screen.
    *   This value comes from the DOM contextmenu event.screenX property.
    *   - screenY - the pointer location on the y axis, relative to the screen.
    *   This value comes from the DOM contextmenu event.screenY property.
+   *
+   * @see SourceEditor.DEFAULTS.contextMenu
    */
   CONTEXT_MENU: "ContextMenu",
 
   /**
    * The TextChanged event is fired when the editor content changes. The event
    * object properties:
    *   - start - the character offset in the document where the change has
    *   occured.
@@ -277,16 +295,25 @@ SourceEditor.EVENTS = {
    * a breakpoint is removed - either through API use or through the editor UI.
    * Event object properties:
    *   - added - array that holds the new breakpoints.
    *   - removed - array that holds the breakpoints that have been removed.
    * Each object in the added/removed arrays holds two properties: line and
    * condition.
    */
   BREAKPOINT_CHANGE: "BreakpointChange",
+
+  /**
+   * The DirtyChanged event is fired when the dirty state of the editor is
+   * changed. The dirty state of the editor tells if the are text changes that
+   * have not been saved yet. Event object properties: oldValue and newValue.
+   * Both are booleans telling the old dirty state and the new state,
+   * respectively.
+   */
+  DIRTY_CHANGED: "DirtyChanged",
 };
 
 /**
  * Extend a destination object with properties from a source object.
  *
  * @param object aDestination
  * @param object aSource
  */
@@ -298,16 +325,22 @@ function extend(aDestination, aSource)
     }
   }
 }
 
 /**
  * Add methods common to all components.
  */
 extend(SourceEditor.prototype, {
+  // Expose the static constants on the SourceEditor instances.
+  EVENTS: SourceEditor.EVENTS,
+  MODES: SourceEditor.MODES,
+  THEMES: SourceEditor.THEMES,
+  DEFAULTS: SourceEditor.DEFAULTS,
+
   _lastFind: null,
 
   /**
    * Find a string in the editor.
    *
    * @param string aString
    *        The string you want to search for. If |aString| is not given the
    *        currently selected text is used.
--- a/browser/devtools/sourceeditor/test/Makefile.in
+++ b/browser/devtools/sourceeditor/test/Makefile.in
@@ -53,12 +53,13 @@ include $(topsrcdir)/config/rules.mk
 		browser_bug684546_reset_undo.js \
 		browser_bug695035_middle_click_paste.js \
 		browser_bug687160_line_api.js \
 		browser_bug650345_find.js \
 		browser_bug703692_focus_blur.js \
 		browser_bug725388_mouse_events.js \
 		browser_bug707987_debugger_breakpoints.js \
 		browser_bug712982_line_ruler_click.js \
+		browser_bug700893_dirty_state.js \
 		head.js \
 
 libs:: $(_BROWSER_TEST_FILES)
 	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/browser/$(relativesrcdir)
new file mode 100644
--- /dev/null
+++ b/browser/devtools/sourceeditor/test/browser_bug700893_dirty_state.js
@@ -0,0 +1,94 @@
+/* vim: set ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+function test() {
+
+  let temp = {};
+  Cu.import("resource:///modules/source-editor.jsm", temp);
+  let SourceEditor = temp.SourceEditor;
+
+  let component = Services.prefs.getCharPref(SourceEditor.PREFS.COMPONENT);
+  if (component == "textarea") {
+    ok(true, "skip test for bug 700893: only applicable for non-textarea components");
+    return;
+  }
+
+  waitForExplicitFinish();
+
+  let editor;
+
+  const windowUrl = "data:text/xml,<?xml version='1.0'?>" +
+    "<window xmlns='http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul'" +
+    " title='test for bug 700893' width='600' height='500'><hbox flex='1'/></window>";
+  const windowFeatures = "chrome,titlebar,toolbar,centerscreen,resizable,dialog=no";
+
+  let testWin = Services.ww.openWindow(null, windowUrl, "_blank", windowFeatures, null);
+  testWin.addEventListener("load", function onWindowLoad() {
+    testWin.removeEventListener("load", onWindowLoad, false);
+    waitForFocus(initEditor, testWin);
+  }, false);
+
+  function initEditor()
+  {
+    let hbox = testWin.document.querySelector("hbox");
+    editor = new SourceEditor();
+    editor.init(hbox, {initialText: "foobar"}, editorLoaded);
+  }
+
+  function editorLoaded()
+  {
+    editor.focus();
+
+    is(editor.dirty, false, "editory is not dirty");
+
+    let event = null;
+    let eventHandler = function(aEvent) {
+      event = aEvent;
+    };
+    editor.addEventListener(SourceEditor.EVENTS.DIRTY_CHANGED, eventHandler);
+
+    editor.setText("omg");
+
+    is(editor.dirty, true, "editor is dirty");
+    ok(event, "DirtyChanged event fired")
+    is(event.oldValue, false, "event.oldValue is correct");
+    is(event.newValue, true, "event.newValue is correct");
+
+    event = null;
+    editor.setText("foo 2");
+    ok(!event, "no DirtyChanged event fired");
+
+    editor.dirty = false;
+
+    is(editor.dirty, false, "editor marked as clean");
+    ok(event, "DirtyChanged event fired")
+    is(event.oldValue, true, "event.oldValue is correct");
+    is(event.newValue, false, "event.newValue is correct");
+
+    event = null;
+    editor.setText("foo 3");
+
+    is(editor.dirty, true, "editor is dirty after changes");
+    ok(event, "DirtyChanged event fired")
+    is(event.oldValue, false, "event.oldValue is correct");
+    is(event.newValue, true, "event.newValue is correct");
+
+    editor.undo();
+    is(editor.dirty, false, "editor is not dirty after undo");
+    ok(event, "DirtyChanged event fired")
+    is(event.oldValue, true, "event.oldValue is correct");
+    is(event.newValue, false, "event.newValue is correct");
+
+    editor.removeEventListener(SourceEditor.EVENTS.DIRTY_CHANGED, eventHandler);
+
+    editor.destroy();
+
+    testWin.close();
+    testWin = editor = null;
+
+    waitForFocus(finish, window);
+  }
+}
--- a/browser/devtools/styleeditor/styleeditor.xul
+++ b/browser/devtools/styleeditor/styleeditor.xul
@@ -40,29 +40,39 @@
  %styleEditorDTD;
 ]>
 <?xml-stylesheet href="chrome://global/skin/global.css" type="text/css"?>
 <?xml-stylesheet href="chrome://browser/content/splitview.css" type="text/css"?>
 <?xml-stylesheet href="chrome://browser/skin/devtools/common.css" type="text/css"?>
 <?xml-stylesheet href="chrome://browser/skin/devtools/splitview.css" type="text/css"?>
 <?xml-stylesheet href="chrome://browser/content/styleeditor.css" type="text/css"?>
 <?xml-stylesheet href="chrome://browser/skin/devtools/styleeditor.css" type="text/css"?>
+<?xul-overlay href="chrome://global/content/editMenuOverlay.xul"?>
+<?xul-overlay href="chrome://browser/content/source-editor-overlay.xul"?>
 <xul:window xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
         xmlns="http://www.w3.org/1999/xhtml"
         id="style-editor-chrome-window"
         title="&window.title;"
         windowtype="Tools:StyleEditor"
         width="800" height="280"
         persist="screenX screenY width height sizemode">
 <xul:script type="application/javascript" src="chrome://global/content/globalOverlay.js"/>
 
+<xul:popupset id="style-editor-popups">
+  <xul:menupopup id="sourceEditorContextMenu"/>
+</xul:popupset>
+
+<xul:commandset id="editMenuCommands"/>
+<xul:commandset id="sourceEditorCommands"/>
 <xul:commandset id="style-editor-commandset">
   <xul:command id="style-editor-cmd-close" oncommand="window.close();"/>
 </xul:commandset>
 
+<xul:keyset id="editMenuKeys"/>
+<xul:keyset id="sourceEditorKeys"/>
 <xul:keyset id="style-editor-keyset">
   <xul:key id="style-editor-key-close"
            key="&closeCmd.key;"
            command="style-editor-cmd-close"
            modifiers="accel"/>
 </xul:keyset>
 
 <xul:box id="style-editor-chrome" class="splitview-root loading">
--- a/browser/installer/package-manifest.in
+++ b/browser/installer/package-manifest.in
@@ -185,16 +185,17 @@
 @BINPATH@/components/fastfind.xpt
 @BINPATH@/components/feeds.xpt
 #ifdef MOZ_GTK2
 @BINPATH@/components/filepicker.xpt
 #endif
 @BINPATH@/components/find.xpt
 @BINPATH@/components/fuel.xpt
 @BINPATH@/components/gfx.xpt
+@BINPATH@/components/html5.xpt
 @BINPATH@/components/htmlparser.xpt
 @BINPATH@/components/imglib2.xpt
 @BINPATH@/components/imgicon.xpt
 @BINPATH@/components/inspector.xpt
 @BINPATH@/components/intl.xpt
 @BINPATH@/components/jar.xpt
 @BINPATH@/components/jsdservice.xpt
 @BINPATH@/components/jsdebugger.xpt
--- a/browser/installer/removed-files.in
+++ b/browser/installer/removed-files.in
@@ -1186,16 +1186,17 @@ xpicleanup@BIN_SUFFIX@
   components/exthelper.xpt
   components/fastfind.xpt
   components/feeds.xpt
   components/find.xpt
   components/firefox.xpt
   components/fuel.xpt
   components/gfx.xpt
   components/gksvgrenderer.xpt
+  components/html5.xpt
   components/htmlparser.xpt
   components/imgicon.xpt
   components/imglib2.xpt
   components/inspector.xpt
   components/intl.xpt
   components/jar.xpt
   components/jsconsole.xpt
   components/jsdservice.xpt
new file mode 100644
--- /dev/null
+++ b/browser/locales/en-US/chrome/browser/devtools/sourceeditor.dtd
@@ -0,0 +1,32 @@
+<!-- LOCALIZATION NOTE : FILE This file contains the Source Editor component
+  - strings. The source editor component is used within the Scratchpad and
+  - Style Editor tools. -->
+
+<!-- LOCALIZATION NOTE : FILE Do not translate commandkeys -->
+
+<!-- LOCALIZATION NOTE : FILE The correct localization of this file might be to
+  - keep it in English, or another language commonly spoken among web developers.
+  - You want to make that choice consistent across the developer tools.
+  - A good criteria is the language in which you'd find the best
+  - documentation on web development on the web. -->
+
+<!ENTITY undoCmd.label             "Undo">
+<!ENTITY undoCmd.accesskey         "U">
+<!ENTITY cutCmd.label              "Cut">
+<!ENTITY cutCmd.accesskey          "t">
+<!ENTITY copyCmd.label             "Copy">
+<!ENTITY copyCmd.accesskey         "C">
+<!ENTITY pasteCmd.label            "Paste">
+<!ENTITY pasteCmd.accesskey        "P">
+<!ENTITY deleteCmd.label           "Delete">
+<!ENTITY deleteCmd.accesskey       "D">
+<!ENTITY selectAllCmd.label        "Select All">
+<!ENTITY selectAllCmd.accesskey    "A">
+<!ENTITY findCmd.label             "Find…">
+<!ENTITY findCmd.accesskey         "F">
+<!ENTITY findAgainCmd.label        "Find Again…">
+<!ENTITY findAgainCmd.accesskey    "g">
+<!ENTITY gotoLineCmd.label         "Jump to line…">
+<!ENTITY gotoLineCmd.key           "J">
+<!ENTITY gotoLineCmd.accesskey     "J">
+
--- a/browser/locales/jar.mn
+++ b/browser/locales/jar.mn
@@ -25,16 +25,17 @@
     locale/browser/devtools/scratchpad.properties     (%chrome/browser/devtools/scratchpad.properties)
     locale/browser/devtools/scratchpad.dtd            (%chrome/browser/devtools/scratchpad.dtd)
     locale/browser/devtools/styleeditor.properties    (%chrome/browser/devtools/styleeditor.properties)
     locale/browser/devtools/styleeditor.dtd           (%chrome/browser/devtools/styleeditor.dtd)
     locale/browser/devtools/styleinspector.properties (%chrome/browser/devtools/styleinspector.properties)
     locale/browser/devtools/styleinspector.dtd        (%chrome/browser/devtools/styleinspector.dtd)
     locale/browser/devtools/webConsole.dtd            (%chrome/browser/devtools/webConsole.dtd)
     locale/browser/devtools/sourceeditor.properties   (%chrome/browser/devtools/sourceeditor.properties)
+    locale/browser/devtools/sourceeditor.dtd          (%chrome/browser/devtools/sourceeditor.dtd)
     locale/browser/newTab.dtd                      (%chrome/browser/newTab.dtd)
     locale/browser/newTab.properties               (%chrome/browser/newTab.properties)
     locale/browser/openLocation.dtd                (%chrome/browser/openLocation.dtd)
     locale/browser/openLocation.properties         (%chrome/browser/openLocation.properties)
 *   locale/browser/pageInfo.dtd                    (%chrome/browser/pageInfo.dtd)
     locale/browser/pageInfo.properties             (%chrome/browser/pageInfo.properties)
     locale/browser/quitDialog.properties           (%chrome/browser/quitDialog.properties)
 *   locale/browser/safeMode.dtd                    (%chrome/browser/safeMode.dtd)
--- a/browser/themes/gnomestripe/preferences/preferences.css
+++ b/browser/themes/gnomestripe/preferences/preferences.css
@@ -176,13 +176,9 @@ radio[pane=paneSync] {
   list-style-image: url("chrome://mozapps/skin/profile/profileicon.png");
 }
 
 #syncAddDeviceLabel {
   margin-top: 1em;
   margin-bottom: 1em;
 }
 
-#syncEnginesList {
-  height: 10em;
-}
-
 %endif
--- a/browser/themes/pinstripe/preferences/preferences.css
+++ b/browser/themes/pinstripe/preferences/preferences.css
@@ -234,13 +234,9 @@ caption {
   list-style-image: url("chrome://mozapps/skin/profile/profileicon.png");
 }
 
 #syncAddDeviceLabel {
   margin-top: 1em;
   margin-bottom: 1em;
 }
 
-#syncEnginesList {
-  height: 10em;
-}
-
 %endif
--- a/browser/themes/winstripe/preferences/preferences.css
+++ b/browser/themes/winstripe/preferences/preferences.css
@@ -164,15 +164,11 @@ radio[pane=paneSync] {
 
 #accountCaptionImage {
   list-style-image: url("chrome://mozapps/skin/profile/profileicon.png");
 }
 
 #syncAddDeviceLabel {
   margin-top: 1em;
   margin-bottom: 1em;
- }
-
-#syncEnginesList {
-  height: 11em;
 }
 
 %endif
--- a/build/unix/build-toolchain/build-gcc.py
+++ b/build/unix/build-toolchain/build-gcc.py
@@ -94,16 +94,43 @@ def build_linux_headers_aux(inst_dir):
                                "headers_install"])
     shutil.move(linux_source_dir + "/dest", inst_dir)
 
 def build_linux_headers(inst_dir):
     def f():
         build_linux_headers_aux(inst_dir)
     with_env({"PATH" : aux_inst_dir + "/bin:%s" % os.environ["PATH"]}, f)
 
+def build_gcc(stage_dir, is_stage_one):
+    gcc_build_dir = stage_dir + '/gcc'
+    tool_inst_dir = stage_dir + '/inst'
+    lib_inst_dir = stage_dir + '/libinst'
+    gcc_configure_args = ["--prefix=%s" % tool_inst_dir,
+                          "--enable-__cxa_atexit",
+                          "--with-gmp=%s" % lib_inst_dir,
+                          "--with-mpfr=%s" % lib_inst_dir,
+                          "--with-mpc=%s" % lib_inst_dir,
+                          "--enable-languages=c,c++",
+                          "--disable-multilib",
+                          "--disable-bootstrap"]
+    if is_stage_one:
+        # We build the stage1 gcc without shared libraries. Otherwise its
+        # libgcc.so would depend on the system libc.so, which causes problems
+        # when it tries to use that libgcc.so and the libc we are about to
+        # build.
+        gcc_configure_args.append("--disable-shared")
+
+    build_package(gcc_source_dir, gcc_build_dir, gcc_configure_args)
+
+    if is_stage_one:
+        # The glibc build system uses -lgcc_eh, but at least in this setup
+        # libgcc.a has all it needs.
+        d = tool_inst_dir + "/lib/gcc/x86_64-unknown-linux-gnu/4.5.2/"
+        os.symlink(d + "libgcc.a", d + "libgcc_eh.a")
+
 def build_one_stage(env, stage_dir, is_stage_one):
     def f():
         build_one_stage_aux(stage_dir, is_stage_one)
     with_env(env, f)
 
 def build_one_stage_aux(stage_dir, is_stage_one):
     os.mkdir(stage_dir)
 
@@ -124,43 +151,28 @@ def build_one_stage_aux(stage_dir, is_st
 
     tool_inst_dir = stage_dir + '/inst'
     build_linux_headers(tool_inst_dir)
 
     binutils_build_dir = stage_dir + '/binutils'
     build_package(binutils_source_dir, binutils_build_dir,
                   ["--prefix=%s" % tool_inst_dir])
 
-    gcc_build_dir = stage_dir + '/gcc'
-    gcc_configure_args = ["--prefix=%s" % tool_inst_dir,
-                          "--enable-__cxa_atexit",
-                          "--with-gmp=%s" % lib_inst_dir,
-                          "--with-mpfr=%s" % lib_inst_dir,
-                          "--with-mpc=%s" % lib_inst_dir,
-                          "--enable-languages=c,c++",
-                          "--disable-multilib",
-                          "--disable-bootstrap"]
+    # During stage one we have to build gcc first, this glibc doesn't even
+    # build with gcc 4.6. During stage two, we have to build glibc first.
+    # The problem is that libstdc++ is built with xgcc and if glibc has
+    # not been built yet xgcc will use the system one.
     if is_stage_one:
-        # We build the stage1 gcc without shared libraries. Otherwise its
-        # libgcc.so would depend on the system libc.so, which causes problems
-        # when it tries to use that libgcc.so and the libc we are about to
-        # build.
-        gcc_configure_args.append("--disable-shared")
-
-    build_package(gcc_source_dir, gcc_build_dir, gcc_configure_args)
-
-    if is_stage_one:
-        # The glibc build system uses -lgcc_eh, but at least in this setup
-        # libgcc.a has all it needs.
-        d = tool_inst_dir + "/lib/gcc/x86_64-unknown-linux-gnu/4.5.2/"
-        os.symlink(d + "libgcc.a", d + "libgcc_eh.a")
-
-    build_glibc({"CC"  : tool_inst_dir + "/bin/gcc",
-                 "CXX" : tool_inst_dir + "/bin/g++"},
-                stage_dir, tool_inst_dir)
+        build_gcc(stage_dir, is_stage_one)
+        build_glibc({"CC"  : tool_inst_dir + "/bin/gcc",
+                     "CXX" : tool_inst_dir + "/bin/g++"},
+                    stage_dir, tool_inst_dir)
+    else:
+        build_glibc({}, stage_dir, tool_inst_dir)
+        build_gcc(stage_dir, is_stage_one)
 
 def build_tar_package(tar, name, base, directory):
     name = os.path.realpath(name)
     run_in(base, [tar, "-cf", name, "--mtime=2012-01-01", "--owner=root",
                   directory])
 
 ##############################################
 
--- a/config/autoconf.mk.in
+++ b/config/autoconf.mk.in
@@ -138,16 +138,17 @@ ENABLE_TESTS	= @ENABLE_TESTS@
 IBMBIDI = @IBMBIDI@
 MOZ_UNIVERSALCHARDET = @MOZ_UNIVERSALCHARDET@
 ACCESSIBILITY = @ACCESSIBILITY@
 MOZ_BRANDING_DIRECTORY = @MOZ_BRANDING_DIRECTORY@
 XPCOM_USE_LEA = @XPCOM_USE_LEA@
 MOZ_INSTALLER	= @MOZ_INSTALLER@
 MOZ_MAINTENANCE_SERVICE	= @MOZ_MAINTENANCE_SERVICE@
 MOZ_VERIFY_MAR_SIGNATURE	= @MOZ_VERIFY_MAR_SIGNATURE@
+MOZ_ENABLE_SIGNMAR	= @MOZ_ENABLE_SIGNMAR@
 MOZ_UPDATER	= @MOZ_UPDATER@
 MOZ_UPDATE_CHANNEL	= @MOZ_UPDATE_CHANNEL@
 MOZ_UPDATE_PACKAGING	= @MOZ_UPDATE_PACKAGING@
 MOZ_DISABLE_PARENTAL_CONTROLS = @MOZ_DISABLE_PARENTAL_CONTROLS@
 NS_ENABLE_TSF = @NS_ENABLE_TSF@
 MOZ_SPELLCHECK = @MOZ_SPELLCHECK@
 MOZ_ANDROID_HISTORY = @MOZ_ANDROID_HISTORY@
 MOZ_WEBSMS_BACKEND = @MOZ_WEBSMS_BACKEND@
--- a/configure.in
+++ b/configure.in
@@ -313,17 +313,17 @@ if test -n "$gonkdir" ; then
     LD="$gonk_toolchain"/bin/"$android_tool_prefix"-ld
     AR="$gonk_toolchain"/bin/"$android_tool_prefix"-ar
     RANLIB="$gonk_toolchain"/bin/"$android_tool_prefix"-ranlib
     STRIP="$gonk_toolchain"/bin/"$android_tool_prefix"-strip
 
     STLPORT_CPPFLAGS="-I$gonkdir/ndk/sources/cxx-stl/stlport/stlport/"
     STLPORT_LIBS="-lstlport"
 
-    CPPFLAGS="-DANDROID -isystem $gonkdir/bionic/libc/include/ -isystem $gonkdir/bionic/libc/kernel/common -isystem $gonkdir/bionic/libc/arch-arm/include -isystem $gonkdir/bionic/libc/kernel/arch-arm -isystem $gonkdir/bionic/libm/include -isystem $gonkdir/frameworks/base/opengl/include -isystem $gonkdir/frameworks/base/native/include -isystem $gonkdir/hardware/libhardware/include -isystem $gonkdir/hardware/libhardware_legacy/include -isystem $gonkdir/system/core/include -isystem $gonkdir/bionic -isystem $gonkdir/frameworks/base/include $STLPORT_CPPFLAGS $CPPFLAGS -isystem $gonkdir/frameworks/base/services/sensorservice"
+    CPPFLAGS="-DANDROID -I$gonkdir/bionic/libc/include/ -I$gonkdir/bionic/libc/kernel/common -I$gonkdir/bionic/libc/arch-arm/include -I$gonkdir/bionic/libc/kernel/arch-arm -I$gonkdir/bionic/libm/include -I$gonkdir/frameworks/base/opengl/include -I$gonkdir/frameworks/base/native/include -I$gonkdir/hardware/libhardware/include -I$gonkdir/hardware/libhardware_legacy/include -I$gonkdir/system/core/include -I$gonkdir/bionic -I$gonkdir/frameworks/base/include $STLPORT_CPPFLAGS $CPPFLAGS -I$gonkdir/frameworks/base/services/sensorservice"
     CFLAGS="-mandroid -fno-short-enums -fno-exceptions $CFLAGS"
     CXXFLAGS="-mandroid -fno-short-enums -fno-exceptions $CXXFLAGS"
     LIBS="$LIBS $STLPORT_LIBS"
 
     dnl Add -llog by default, since we use it all over the place.
     LDFLAGS="-mandroid -L$gonkdir/out/target/product/$GONK_PRODUCT/obj/lib -Wl,-rpath-link=$gonkdir/out/target/product/$GONK_PRODUCT/obj/lib --sysroot=$gonkdir/out/target/product/$GONK_PRODUCT/obj/ -llog $LDFLAGS"
 
     dnl prevent cross compile section from using these flags as host flags
@@ -6495,16 +6495,33 @@ if test -n "$MOZ_VERIFY_MAR_SIGNATURE"; 
   if test "$OS_ARCH" = "WINNT"; then
     AC_DEFINE(MOZ_VERIFY_MAR_SIGNATURE)
   else
     AC_MSG_ERROR([Can only build with --enable-verify-mar with a Windows target])
   fi
 fi
 
 dnl ========================================================
+dnl Enable building the signmar program.
+dnl This option is much different than the --enable-verify-mar option.
+dnl --enable-verify-mar is for enabling the verification check on MAR
+dnl files in the updater.  The --enable-signmar option is for building
+dnl the signmar program.
+dnl ========================================================
+
+MOZ_ARG_ENABLE_BOOL(sign-mar,
+[  --enable-signmar     Enable building the signmar program],
+    MOZ_ENABLE_SIGNMAR=1,
+    MOZ_ENABLE_SIGNMAR= )
+
+if test -n "$MOZ_ENABLE_SIGNMAR"; then
+  AC_DEFINE(MOZ_ENABLE_SIGNMAR)
+fi
+
+dnl ========================================================
 dnl Updater
 dnl ========================================================
 
 MOZ_ARG_DISABLE_BOOL(updater,
 [  --disable-updater       Disable building of updater],
     MOZ_UPDATER=,
     MOZ_UPDATER=1 )
 
@@ -8596,16 +8613,17 @@ AC_SUBST(MOZ_UNIVERSALCHARDET)
 AC_SUBST(ACCESSIBILITY)
 AC_SUBST(MOZ_SPELLCHECK)
 AC_SUBST(MOZ_JAVA_COMPOSITOR)
 AC_SUBST(MOZ_ONLY_TOUCH_EVENTS)
 AC_SUBST(MOZ_USER_DIR)
 AC_SUBST(MOZ_CRASHREPORTER)
 AC_SUBST(MOZ_MAINTENANCE_SERVICE)
 AC_SUBST(MOZ_VERIFY_MAR_SIGNATURE)
+AC_SUBST(MOZ_ENABLE_SIGNMAR)
 AC_SUBST(MOZ_UPDATER)
 AC_SUBST(MOZ_ANGLE)
 AC_SUBST(MOZ_DIRECTX_SDK_PATH)
 AC_SUBST(MOZ_DIRECTX_SDK_CPU_SUFFIX)
 AC_SUBST(MOZ_D3DX9_VERSION)
 AC_SUBST(MOZ_D3DX9_CAB)
 AC_SUBST(MOZ_D3DCOMPILER_CAB)
 AC_SUBST(MOZ_D3DX9_DLL)
--- a/content/base/public/nsContentUtils.h
+++ b/content/base/public/nsContentUtils.h
@@ -1139,22 +1139,44 @@ public:
 
   /**
    * Parse a string into a document using the HTML parser.
    * Script elements are marked unexecutable.
    *
    * @param aSourceBuffer the string to parse as an HTML document
    * @param aTargetDocument the document object to parse into. Must not have
    *                        child nodes.
+   * @param aScriptingEnabledForNoscriptParsing whether <noscript> is parsed
+   *                                            as if scripting was enabled
    * @return NS_ERROR_DOM_INVALID_STATE_ERR if a re-entrant attempt to parse
    *         fragments is made, NS_ERROR_OUT_OF_MEMORY if aSourceBuffer is too
    *         long and NS_OK otherwise.
    */
   static nsresult ParseDocumentHTML(const nsAString& aSourceBuffer,
-                                    nsIDocument* aTargetDocument);
+                                    nsIDocument* aTargetDocument,
+                                    bool aScriptingEnabledForNoscriptParsing);
+
+  /**
+   * Converts HTML source to plain text by parsing the source and using the
+   * plain text serializer on the resulting tree.
+   *
+   * @param aSourceBuffer the string to parse as an HTML document
+   * @param aResultBuffer the string where the plain text result appears;
+   *                      may be the same string as aSourceBuffer
+   * @param aFlags Flags from nsIDocumentEncoder.
+   * @param aWrapCol Number of columns after which to line wrap; 0 for no
+   *                 auto-wrapping
+   * @return NS_ERROR_DOM_INVALID_STATE_ERR if a re-entrant attempt to parse
+   *         fragments is made, NS_ERROR_OUT_OF_MEMORY if aSourceBuffer is too
+   *         long and NS_OK otherwise.
+   */
+  static nsresult ConvertToPlainText(const nsAString& aSourceBuffer,
+                                     nsAString& aResultBuffer,
+                                     PRUint32 aFlags,
+                                     PRUint32 aWrapCol);
 
   /**
    * Creates a new XML document, which is marked to be loaded as data.
    *
    * @param aNamespaceURI Namespace for the root element to create and insert in
    *                      the document. Only used if aQualifiedName is not
    *                      empty.
    * @param aQualifiedName Qualified name for the root element to create and
@@ -1936,16 +1958,42 @@ public:
    * comma-separated list of URIs.  Return true if the given URI's prepath is
    * in the list, and false otherwise.
    *
    * Comparisons are case-insensitive, and whitespace between elements of the
    * comma-separated list is ignored.
    */
   static bool URIIsChromeOrInPref(nsIURI *aURI, const char *aPref);
 
+  /**
+   * This will parse aSource, to extract the value of the pseudo attribute
+   * with the name specified in aName. See
+   * http://www.w3.org/TR/xml-stylesheet/#NT-StyleSheetPI for the specification
+   * which is used to parse aSource.
+   *
+   * @param aSource the string to parse
+   * @param aName the name of the attribute to get the value for
+   * @param aValue [out] the value for the attribute with name specified in
+   *                     aAttribute. Empty if the attribute isn't present.
+   * @return true     if the attribute exists and was successfully parsed.
+   *         false if the attribute doesn't exist, or has a malformed
+   *                  value, such as an unknown or unterminated entity.
+   */
+  static bool GetPseudoAttributeValue(const nsString& aSource, nsIAtom *aName,
+                                      nsAString& aValue);
+
+  /**
+   * Returns true if the language name is a version of JavaScript and
+   * false otherwise
+   */
+  static bool IsJavaScriptLanguage(const nsString& aName, PRUint32 *aVerFlags);
+
+  static void SplitMimeType(const nsAString& aValue, nsString& aType,
+                            nsString& aParams);
+
 private:
   static bool InitializeEventTable();
 
   static nsresult EnsureStringBundle(PropertiesFile aFile);
 
   static nsIDOMScriptObjectFactory *GetDOMScriptObjectFactory();
 
   static nsresult HoldScriptObject(PRUint32 aLangID, void* aObject);
--- a/content/base/public/nsIDocumentEncoder.idl
+++ b/content/base/public/nsIDocumentEncoder.idl
@@ -167,17 +167,18 @@ interface nsIDocumentEncoder : nsISuppor
   /**
    * Output the content of noscript elements (only for serializing
    * to plaintext).
    */
   const unsigned long OutputNoScriptContent = (1 << 11);
 
   /**
    * Output the content of noframes elements (only for serializing
-   * to plaintext).
+   * to plaintext). (Used only internally in the plain text serializer;
+   * ignored if passed by the caller.)
    */
   const unsigned long OutputNoFramesContent = (1 << 12);
 
   /**
    * Don't allow any formatting nodes (e.g. <br>, <b>) inside a <pre>.
    * This is used primarily by mail. XHTML/HTML output only.
    */
   const unsigned long OutputNoFormattingInPre = (1 << 13);
--- a/content/base/src/Makefile.in
+++ b/content/base/src/Makefile.in
@@ -122,17 +122,16 @@ CPPSRCS		= \
 		nsMappedAttributes.cpp \
 		nsNameSpaceManager.cpp \
 		nsNoDataProtocolContentPolicy.cpp \
 		nsNodeInfo.cpp \
 		nsNodeInfoManager.cpp \
 		nsNodeIterator.cpp \
 		nsNodeUtils.cpp \
 		nsObjectLoadingContent.cpp \
-		nsParserUtils.cpp \
 		nsPlainTextSerializer.cpp \
 		nsPropertyTable.cpp \
 		nsRange.cpp \
 		nsReferencedElement.cpp \
 		nsScriptElement.cpp \
 		nsScriptLoader.cpp \
 		nsStubDocumentObserver.cpp \
 		nsStubImageDecoderObserver.cpp \
--- a/content/base/src/nsContentSink.cpp
+++ b/content/base/src/nsContentSink.cpp
@@ -75,17 +75,16 @@
 #include "nsIApplicationCacheContainer.h"
 #include "nsIApplicationCacheChannel.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsIDOMLoadStatus.h"
 #include "nsICookieService.h"
 #include "nsIPrompt.h"
 #include "nsServiceManagerUtils.h"
 #include "nsContentUtils.h"
-#include "nsParserUtils.h"
 #include "nsCRT.h"
 #include "nsEscape.h"
 #include "nsWeakReference.h"
 #include "nsUnicharUtils.h"
 #include "nsNodeInfoManager.h"
 #include "nsIAppShell.h"
 #include "nsIWidget.h"
 #include "nsWidgetsCID.h"
@@ -707,17 +706,17 @@ nsContentSink::ProcessStyleLink(nsIConte
 {
   if (aAlternate && aTitle.IsEmpty()) {
     // alternates must have title return without error, for now
     return NS_OK;
   }
 
   nsAutoString  mimeType;
   nsAutoString  params;
-  nsParserUtils::SplitMimeType(aType, mimeType, params);
+  nsContentUtils::SplitMimeType(aType, mimeType, params);
 
   // see bug 18817
   if (!mimeType.IsEmpty() && !mimeType.LowerCaseEqualsLiteral("text/css")) {
     // Unknown stylesheet language
     return NS_OK;
   }
 
   nsCOMPtr<nsIURI> url;
--- a/content/base/src/nsContentUtils.cpp
+++ b/content/base/src/nsContentUtils.cpp
@@ -175,16 +175,17 @@ static NS_DEFINE_CID(kXTFServiceCID, NS_
 #include "BasicLayers.h"
 #include "nsFocusManager.h"
 #include "nsTextEditorState.h"
 #include "nsIPluginHost.h"
 #include "nsICategoryManager.h"
 #include "nsIViewManager.h"
 #include "nsEventStateManager.h"
 #include "nsIDOMHTMLInputElement.h"
+#include "nsParserConstants.h"
 
 #ifdef IBMBIDI
 #include "nsIBidiKeyboard.h"
 #endif
 #include "nsCycleCollectionParticipant.h"
 
 // for ReportToConsole
 #include "nsIStringBundle.h"
@@ -715,16 +716,195 @@ nsContentUtils::URIIsChromeOrInPref(nsIU
     if (whitelistItem.Equals(prePath, nsCaseInsensitiveStringComparator())) {
       return true;
     }
   }
 
   return false;
 }
 
+#define SKIP_WHITESPACE(iter, end_iter, end_res)                 \
+  while ((iter) != (end_iter) && nsCRT::IsAsciiSpace(*(iter))) { \
+    ++(iter);                                                    \
+  }                                                              \
+  if ((iter) == (end_iter)) {                                    \
+    return (end_res);                                            \
+  }
+
+#define SKIP_ATTR_NAME(iter, end_iter)                            \
+  while ((iter) != (end_iter) && !nsCRT::IsAsciiSpace(*(iter)) && \
+         *(iter) != '=') {                                        \
+    ++(iter);                                                     \
+  }
+
+bool
+nsContentUtils::GetPseudoAttributeValue(const nsString& aSource, nsIAtom *aName,
+                                        nsAString& aValue)
+{
+  aValue.Truncate();
+
+  const PRUnichar *start = aSource.get();
+  const PRUnichar *end = start + aSource.Length();
+  const PRUnichar *iter;
+
+  while (start != end) {
+    SKIP_WHITESPACE(start, end, false)
+    iter = start;
+    SKIP_ATTR_NAME(iter, end)
+
+    if (start == iter) {
+      return false;
+    }
+
+    // Remember the attr name.
+    const nsDependentSubstring & attrName = Substring(start, iter);
+
+    // Now check whether this is a valid name="value" pair.
+    start = iter;
+    SKIP_WHITESPACE(start, end, false)
+    if (*start != '=') {
+      // No '=', so this is not a name="value" pair.  We don't know
+      // what it is, and we have no way to handle it.
+      return false;
+    }
+
+    // Have to skip the value.
+    ++start;
+    SKIP_WHITESPACE(start, end, false)
+    PRUnichar q = *start;
+    if (q != kQuote && q != kApostrophe) {
+      // Not a valid quoted value, so bail.
+      return false;
+    }
+
+    ++start;  // Point to the first char of the value.
+    iter = start;
+
+    while (iter != end && *iter != q) {
+      ++iter;
+    }
+
+    if (iter == end) {
+      // Oops, unterminated quoted string.
+      return false;
+    }
+
+    // At this point attrName holds the name of the "attribute" and
+    // the value is between start and iter.
+
+    if (aName->Equals(attrName)) {
+      nsIParserService* parserService = nsContentUtils::GetParserService();
+      NS_ENSURE_TRUE(parserService, false);
+
+      // We'll accumulate as many characters as possible (until we hit either
+      // the end of the string or the beginning of an entity). Chunks will be
+      // delimited by start and chunkEnd.
+      const PRUnichar *chunkEnd = start;
+      while (chunkEnd != iter) {
+        if (*chunkEnd == kLessThan) {
+          aValue.Truncate();
+
+          return false;
+        }
+
+        if (*chunkEnd == kAmpersand) {
+          aValue.Append(start, chunkEnd - start);
+
+          // Point to first character after the ampersand.
+          ++chunkEnd;
+
+          const PRUnichar *afterEntity;
+          PRUnichar result[2];
+          PRUint32 count =
+            parserService->DecodeEntity(chunkEnd, iter, &afterEntity, result);
+          if (count == 0) {
+            aValue.Truncate();
+
+            return false;
+          }
+
+          aValue.Append(result, count);
+
+          // Advance to after the entity and begin a new chunk.
+          start = chunkEnd = afterEntity;
+        }
+        else {
+          ++chunkEnd;
+        }
+      }
+
+      // Append remainder.
+      aValue.Append(start, iter - start);
+
+      return true;
+    }
+
+    // Resume scanning after the end of the attribute value (past the quote
+    // char).
+    start = iter + 1;
+  }
+
+  return false;
+}
+
+bool
+nsContentUtils::IsJavaScriptLanguage(const nsString& aName, PRUint32 *aFlags)
+{
+  JSVersion version = JSVERSION_UNKNOWN;
+
+  if (aName.LowerCaseEqualsLiteral("javascript") ||
+      aName.LowerCaseEqualsLiteral("livescript") ||
+      aName.LowerCaseEqualsLiteral("mocha")) {
+    version = JSVERSION_DEFAULT;
+  } else if (aName.LowerCaseEqualsLiteral("javascript1.0")) {
+    version = JSVERSION_1_0;
+  } else if (aName.LowerCaseEqualsLiteral("javascript1.1")) {
+    version = JSVERSION_1_1;
+  } else if (aName.LowerCaseEqualsLiteral("javascript1.2")) {
+    version = JSVERSION_1_2;
+  } else if (aName.LowerCaseEqualsLiteral("javascript1.3")) {
+    version = JSVERSION_1_3;
+  } else if (aName.LowerCaseEqualsLiteral("javascript1.4")) {
+    version = JSVERSION_1_4;
+  } else if (aName.LowerCaseEqualsLiteral("javascript1.5")) {
+    version = JSVERSION_1_5;
+  } else if (aName.LowerCaseEqualsLiteral("javascript1.6")) {
+    version = JSVERSION_1_6;
+  } else if (aName.LowerCaseEqualsLiteral("javascript1.7")) {
+    version = JSVERSION_1_7;
+  } else if (aName.LowerCaseEqualsLiteral("javascript1.8")) {
+    version = JSVERSION_1_8;
+  }
+
+  if (version == JSVERSION_UNKNOWN) {
+    return false;
+  }
+  *aFlags = version;
+  return true;
+}
+
+void
+nsContentUtils::SplitMimeType(const nsAString& aValue, nsString& aType,
+                              nsString& aParams)
+{
+  aType.Truncate();
+  aParams.Truncate();
+  PRInt32 semiIndex = aValue.FindChar(PRUnichar(';'));
+  if (-1 != semiIndex) {
+    aType = Substring(aValue, 0, semiIndex);
+    aParams = Substring(aValue, semiIndex + 1,
+                       aValue.Length() - (semiIndex + 1));
+    aParams.StripWhitespace();
+  }
+  else {
+    aType = aValue;
+  }
+  aType.StripWhitespace();
+}
+
 /**
  * Access a cached parser service. Don't addref. We need only one
  * reference to it and this class has that one.
  */
 /* static */
 nsIParserService*
 nsContentUtils::GetParserService()
 {
@@ -3742,31 +3922,33 @@ nsContentUtils::ParseFragmentHTML(const 
                                        aQuirks,
                                        aPreventScriptExecution);
   return rv;
 }
 
 /* static */
 nsresult
 nsContentUtils::ParseDocumentHTML(const nsAString& aSourceBuffer,
-                                  nsIDocument* aTargetDocument)
+                                  nsIDocument* aTargetDocument,
+                                  bool aScriptingEnabledForNoscriptParsing)
 {
   if (nsContentUtils::sFragmentParsingActive) {
     NS_NOTREACHED("Re-entrant fragment parsing attempted.");
     return NS_ERROR_DOM_INVALID_STATE_ERR;
   }
   mozilla::AutoRestore<bool> guard(nsContentUtils::sFragmentParsingActive);
   nsContentUtils::sFragmentParsingActive = true;
   if (!sHTMLFragmentParser) {
     NS_ADDREF(sHTMLFragmentParser = new nsHtml5StringParser());
     // Now sHTMLFragmentParser owns the object
   }
   nsresult rv =
     sHTMLFragmentParser->ParseDocument(aSourceBuffer,
-                                       aTargetDocument);
+                                       aTargetDocument,
+                                       aScriptingEnabledForNoscriptParsing);
   return rv;
 }
 
 /* static */
 nsresult
 nsContentUtils::ParseFragmentXML(const nsAString& aSourceBuffer,
                                  nsIDocument* aDocument,
                                  nsTArray<nsString>& aTagStack,
@@ -3807,16 +3989,54 @@ nsContentUtils::ParseFragmentXML(const n
 
   rv = sXMLFragmentSink->FinishFragmentParsing(aReturn);
 
   sXMLFragmentParser->Reset();
 
   return rv;
 }
 
+/* static */
+nsresult
+nsContentUtils::ConvertToPlainText(const nsAString& aSourceBuffer,
+                                   nsAString& aResultBuffer,
+                                   PRUint32 aFlags,
+                                   PRUint32 aWrapCol)
+{
+  nsCOMPtr<nsIURI> uri;
+  NS_NewURI(getter_AddRefs(uri), "about:blank");
+  nsCOMPtr<nsIPrincipal> principal =
+    do_CreateInstance("@mozilla.org/nullprincipal;1");
+  nsCOMPtr<nsIDOMDocument> domDocument;
+  nsresult rv = nsContentUtils::CreateDocument(EmptyString(),
+                                               EmptyString(),
+                                               nsnull,
+                                               uri,
+                                               uri,
+                                               principal,
+                                               nsnull,
+                                               DocumentFlavorHTML,
+                                               getter_AddRefs(domDocument));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  nsCOMPtr<nsIDocument> document = do_QueryInterface(domDocument);
+  rv = nsContentUtils::ParseDocumentHTML(aSourceBuffer, document,
+    !(aFlags & nsIDocumentEncoder::OutputNoScriptContent));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  nsCOMPtr<nsIDocumentEncoder> encoder = do_CreateInstance(
+    "@mozilla.org/layout/documentEncoder;1?type=text/plain");
+
+  rv = encoder->Init(domDocument, NS_LITERAL_STRING("text/plain"), aFlags);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  encoder->SetWrapColumn(aWrapCol);
+
+  return encoder->EncodeToString(aResultBuffer);
+}
 
 /* static */
 nsresult
 nsContentUtils::CreateDocument(const nsAString& aNamespaceURI, 
                                const nsAString& aQualifiedName, 
                                nsIDOMDocumentType* aDoctype,
                                nsIURI* aDocumentURI, nsIURI* aBaseURI,
                                nsIPrincipal* aPrincipal,
--- a/content/base/src/nsCrossSiteListenerProxy.cpp
+++ b/content/base/src/nsCrossSiteListenerProxy.cpp
@@ -43,17 +43,16 @@
 #include "nsIScriptSecurityManager.h"
 #include "nsNetUtil.h"
 #include "nsIParser.h"
 #include "nsParserCIID.h"
 #include "nsICharsetAlias.h"
 #include "nsMimeTypes.h"
 #include "nsIStreamConverterService.h"
 #include "nsStringStream.h"
-#include "nsParserUtils.h"
 #include "nsGkAtoms.h"
 #include "nsWhitespaceTokenizer.h"
 #include "nsIChannelEventSink.h"
 #include "nsIAsyncVerifyRedirectCallback.h"
 #include "nsCharSeparatedTokenizer.h"
 #include "nsAsyncRedirectVerifyHelper.h"
 #include "prclist.h"
 #include "prtime.h"
--- a/content/base/src/nsDOMParser.cpp
+++ b/content/base/src/nsDOMParser.cpp
@@ -97,17 +97,17 @@ nsDOMParser::ParseFromString(const PRUni
   nsresult rv;
 
   if (!nsCRT::strcmp(contentType, "text/html")) {
     nsCOMPtr<nsIDOMDocument> domDocument;
     rv = SetUpDocument(DocumentFlavorHTML, getter_AddRefs(domDocument));
     NS_ENSURE_SUCCESS(rv, rv);
     nsCOMPtr<nsIDocument> document = do_QueryInterface(domDocument);
     nsDependentString sourceBuffer(str);
-    rv = nsContentUtils::ParseDocumentHTML(sourceBuffer, document);
+    rv = nsContentUtils::ParseDocumentHTML(sourceBuffer, document, false);
     NS_ENSURE_SUCCESS(rv, rv);
 
     // Keep the XULXBL state, base URL and principal setting in sync with the
     // XML case
 
     if (nsContentUtils::IsSystemPrincipal(mOriginalPrincipal)) {
       document->ForceEnableXULXBL();
     }
--- a/content/base/src/nsGenericElement.cpp
+++ b/content/base/src/nsGenericElement.cpp
@@ -2896,16 +2896,24 @@ nsGenericElement::GetAttributeNodeNS(con
                                      const nsAString& aLocalName,
                                      nsIDOMAttr** aReturn)
 {
   NS_ENSURE_ARG_POINTER(aReturn);
   *aReturn = nsnull;
 
   OwnerDoc()->WarnOnceAbout(nsIDocument::eGetAttributeNodeNS);
 
+  return GetAttributeNodeNSInternal(aNamespaceURI, aLocalName, aReturn);
+}
+
+nsresult
+nsGenericElement::GetAttributeNodeNSInternal(const nsAString& aNamespaceURI,
+                                             const nsAString& aLocalName,
+                                             nsIDOMAttr** aReturn)
+{
   nsCOMPtr<nsIDOMNamedNodeMap> map;
   nsresult rv = GetAttributes(getter_AddRefs(map));
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsCOMPtr<nsIDOMNode> node;
   rv = map->GetNamedItemNS(aNamespaceURI, aLocalName, getter_AddRefs(node));
 
   if (NS_SUCCEEDED(rv) && node) {
@@ -5203,18 +5211,18 @@ nsGenericElement::SetAttrAndNotify(PRInt
   }
 
   if (aFireMutation) {
     nsMutationEvent mutation(true, NS_MUTATION_ATTRMODIFIED);
 
     nsCOMPtr<nsIDOMAttr> attrNode;
     nsAutoString ns;
     nsContentUtils::NameSpaceManager()->GetNameSpaceURI(aNamespaceID, ns);
-    GetAttributeNodeNS(ns, nsDependentAtomString(aName),
-                       getter_AddRefs(attrNode));
+    GetAttributeNodeNSInternal(ns, nsDependentAtomString(aName),
+                               getter_AddRefs(attrNode));
     mutation.mRelatedNode = attrNode;
 
     mutation.mAttrName = aName;
     nsAutoString newValue;
     GetAttr(aNamespaceID, aName, newValue);
     if (!newValue.IsEmpty()) {
       mutation.mNewAttrValue = do_GetAtom(newValue);
     }
@@ -5383,18 +5391,18 @@ nsGenericElement::UnsetAttr(PRInt32 aNam
                                          NS_EVENT_BITS_MUTATION_ATTRMODIFIED,
                                          this);
 
   // Grab the attr node if needed before we remove it from the attr map
   nsCOMPtr<nsIDOMAttr> attrNode;
   if (hasMutationListeners) {
     nsAutoString ns;
     nsContentUtils::NameSpaceManager()->GetNameSpaceURI(aNameSpaceID, ns);
-    GetAttributeNodeNS(ns, nsDependentAtomString(aName),
-                       getter_AddRefs(attrNode));
+    GetAttributeNodeNSInternal(ns, nsDependentAtomString(aName),
+                               getter_AddRefs(attrNode));
   }
 
   // Clear binding to nsIDOMNamedNodeMap
   nsDOMSlots *slots = GetExistingDOMSlots();
   if (slots && slots->mAttributeMap) {
     slots->mAttributeMap->DropAttribute(aNameSpaceID, aName);
   }
 
--- a/content/base/src/nsGenericElement.h
+++ b/content/base/src/nsGenericElement.h
@@ -789,16 +789,20 @@ protected:
 
   nsIFrame* GetStyledFrame();
 
   virtual mozilla::dom::Element* GetNameSpaceElement()
   {
     return this;
   }
 
+  nsresult GetAttributeNodeNSInternal(const nsAString& aNamespaceURI,
+                                      const nsAString& aLocalName,
+                                      nsIDOMAttr** aReturn);
+
 public:
   // Because of a bug in MS C++ compiler nsDOMSlots must be declared public,
   // otherwise nsXULElement::nsXULSlots doesn't compile.
   /**
    * There are a set of DOM- and scripting-specific instance variables
    * that may only be instantiated when a content object is accessed
    * through the DOM. Rather than burn actual slots in the content
    * objects for each of these instance variables, we put them off
--- a/content/base/src/nsObjectLoadingContent.cpp
+++ b/content/base/src/nsObjectLoadingContent.cpp
@@ -551,17 +551,17 @@ nsObjectLoadingContent::nsObjectLoadingC
   , mChannel(nsnull)
   , mType(eType_Loading)
   , mInstantiating(false)
   , mUserDisabled(false)
   , mSuppressed(false)
   , mNetworkCreated(true)
   // If plugins.click_to_play is false, plugins should always play
   , mShouldPlay(!mozilla::Preferences::GetBool("plugins.click_to_play", false))
-  , mSrcStreamLoadInitiated(false)
+  , mSrcStreamLoading(false)
   , mFallbackReason(ePluginOtherState)
 {
 }
 
 nsObjectLoadingContent::~nsObjectLoadingContent()
 {
   DestroyImageLoadingContent();
   if (mFrameLoader) {
@@ -687,18 +687,16 @@ nsObjectLoadingContent::NotifyOwnerDocum
 
 // nsIRequestObserver
 NS_IMETHODIMP
 nsObjectLoadingContent::OnStartRequest(nsIRequest *aRequest,
                                        nsISupports *aContext)
 {
   SAMPLE_LABEL("nsObjectLoadingContent", "OnStartRequest");
 
-  mSrcStreamLoadInitiated = true;
-
   if (aRequest != mChannel || !aRequest) {
     // This is a bit of an edge case - happens when a new load starts before the
     // previous one got here
     return NS_BINDING_ABORTED;
   }
 
   AutoNotifier notifier(this, true);
 
@@ -878,17 +876,17 @@ nsObjectLoadingContent::OnStartRequest(n
         mType = newType;
         notifier.Notify();
       }
       nsCOMPtr<nsIPluginHost> pluginHostCOM(do_GetService(MOZ_PLUGIN_HOST_CONTRACTID));
       nsPluginHost *pluginHost = static_cast<nsPluginHost*>(pluginHostCOM.get());
       if (!pluginHost) {
         return NS_ERROR_NOT_AVAILABLE;
       }
-      pluginHost->InstantiatePluginForChannel(chan, this, getter_AddRefs(mFinalListener));
+      pluginHost->CreateListenerForChannel(chan, this, getter_AddRefs(mFinalListener));
       break;
     }
     case eType_Loading:
       NS_NOTREACHED("Should not have a loading type here!");
     case eType_Null:
       // Need to fallback here (instead of using the case below), so that we can
       // set mFallbackReason without it being overwritten. This is also why we
       // return early.
@@ -901,30 +899,35 @@ nsObjectLoadingContent::OnStartRequest(n
         mFallbackReason = pluginState;
         FirePluginError(thisContent, pluginState);
       }
       return NS_BINDING_ABORTED;
   }
 
   if (mFinalListener) {
     mType = newType;
+
+    mSrcStreamLoading = true;
     rv = mFinalListener->OnStartRequest(aRequest, aContext);
-    if (NS_FAILED(rv)) {
-#ifdef XP_MACOSX
-      // Shockwave on Mac is special and returns an error here even when it
-      // handles the content
-      if (mContentType.EqualsLiteral("application/x-director")) {
-        rv = NS_OK; // otherwise, the AutoFallback will make us fall back
+    mSrcStreamLoading = false;
+
+    if (NS_SUCCEEDED(rv)) {
+      // Plugins need to set up for NPRuntime.
+      if (mType == eType_Plugin) {
+        NotifyContentObjectWrapper();
+      }
+    } else {
+      // Plugins don't fall back if there is an error here.
+      if (mType == eType_Plugin) {
+        rv = NS_OK; // this is necessary to avoid auto-fallback
         return NS_BINDING_ABORTED;
       }
-#endif
       Fallback(false);
-    } else if (mType == eType_Plugin) {
-      NotifyContentObjectWrapper();
     }
+
     return rv;
   }
 
   Fallback(false);
   return NS_BINDING_ABORTED;
 }
 
 NS_IMETHODIMP
@@ -2106,12 +2109,11 @@ nsObjectLoadingContent::NotifyContentObj
 }
 
 NS_IMETHODIMP
 nsObjectLoadingContent::PlayPlugin()
 {
   if (!nsContentUtils::IsCallerChrome())
     return NS_OK;
 
-  mSrcStreamLoadInitiated = false;
   mShouldPlay = true;
   return LoadObject(mURI, true, mContentType, true);
 }
--- a/content/base/src/nsObjectLoadingContent.h
+++ b/content/base/src/nsObjectLoadingContent.h
@@ -146,17 +146,17 @@ class nsObjectLoadingContent : public ns
       mNetworkCreated = aNetworkCreated;
     }
 
     // Can flush layout.
     nsresult InstantiatePluginInstance(const char* aMimeType, nsIURI* aURI);
 
     void NotifyOwnerDocumentActivityChanged();
 
-    bool SrcStreamLoadInitiated() { return mSrcStreamLoadInitiated; };
+    bool SrcStreamLoading() { return mSrcStreamLoading; };
 
   protected:
     /**
      * Load the object from the given URI.
      * @param aURI       The URI to load.
      * @param aNotify If true, nsIDocumentObserver state change notifications
      *                will be sent as needed.
      * @param aTypeHint  MIME Type hint. Overridden by the server unless this
@@ -396,19 +396,22 @@ class nsObjectLoadingContent : public ns
     // created using NS_FROM_PARSER_NETWORK flag. If the element is modified,
     // it may lose the flag.
     bool                        mNetworkCreated : 1;
 
     // Used to keep track of whether or not a plugin should be played.
     // This is used for click-to-play plugins.
     bool                        mShouldPlay : 1;
 
-    // Used to indicate that a stream for a src/data attribute has been
-    // initiated so that we don't do it twice.
-    bool mSrcStreamLoadInitiated;
+    // Used to track when we might try to instantiate a plugin instance based on
+    // a src data stream being delivered to this object. When this is true we don't
+    // want plugin instance instantiation code to attempt to load src data again or
+    // we'll deliver duplicate streams. Should be cleared when we are not loading
+    // src data.
+    bool mSrcStreamLoading;
 
     // A specific state that caused us to fallback
     PluginSupportState          mFallbackReason;
 
     nsWeakFrame                 mPrintFrame;
 
     nsRefPtr<nsPluginInstanceOwner> mInstanceOwner;
 };
deleted file mode 100644
--- a/content/base/src/nsParserUtils.cpp
+++ /dev/null
@@ -1,236 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is Mozilla Communicator client code.
- *
- * The Initial Developer of the Original Code is
- * Netscape Communications Corporation.
- * Portions created by the Initial Developer are Copyright (C) 1998
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either of the GNU General Public License Version 2 or later (the "GPL"),
- * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
-/*
- * Namespace class for some static parsing-related methods.
- */
-
-#include "nsParserUtils.h"
-#include "jsapi.h"
-#include "nsReadableUtils.h"
-#include "nsCRT.h"
-#include "nsContentUtils.h"
-#include "nsIParserService.h"
-#include "nsParserConstants.h"
-
-#define SKIP_WHITESPACE(iter, end_iter, end_res)                 \
-  while ((iter) != (end_iter) && nsCRT::IsAsciiSpace(*(iter))) { \
-    ++(iter);                                                    \
-  }                                                              \
-  if ((iter) == (end_iter)) {                                    \
-    return (end_res);                                            \
-  }
-
-#define SKIP_ATTR_NAME(iter, end_iter)                            \
-  while ((iter) != (end_iter) && !nsCRT::IsAsciiSpace(*(iter)) && \
-         *(iter) != '=') {                                        \
-    ++(iter);                                                     \
-  }
-
-bool
-nsParserUtils::GetQuotedAttributeValue(const nsString& aSource, nsIAtom *aName,
-                                       nsAString& aValue)
-{
-  aValue.Truncate();
-
-  const PRUnichar *start = aSource.get();
-  const PRUnichar *end = start + aSource.Length();
-  const PRUnichar *iter;
-  
-  while (start != end) {
-    SKIP_WHITESPACE(start, end, false)
-    iter = start;
-    SKIP_ATTR_NAME(iter, end)
-
-    if (start == iter) {
-      return false;
-    }
-
-    // Remember the attr name.
-    const nsDependentSubstring & attrName = Substring(start, iter);
-
-    // Now check whether this is a valid name="value" pair.
-    start = iter;
-    SKIP_WHITESPACE(start, end, false)
-    if (*start != '=') {
-      // No '=', so this is not a name="value" pair.  We don't know
-      // what it is, and we have no way to handle it.
-      return false;
-    }
-    
-    // Have to skip the value.
-    ++start;
-    SKIP_WHITESPACE(start, end, false)
-    PRUnichar q = *start;
-    if (q != kQuote && q != kApostrophe) {
-      // Not a valid quoted value, so bail.
-      return false;
-    }
-    
-    ++start;  // Point to the first char of the value.
-    iter = start;
-
-    while (iter != end && *iter != q) {
-      ++iter;
-    }
-
-    if (iter == end) {
-      // Oops, unterminated quoted string.
-      return false;
-    }
-
-    // At this point attrName holds the name of the "attribute" and
-    // the value is between start and iter.
-    
-    if (aName->Equals(attrName)) {
-      nsIParserService* parserService = nsContentUtils::GetParserService();
-      NS_ENSURE_TRUE(parserService, false);
-
-      // We'll accumulate as many characters as possible (until we hit either
-      // the end of the string or the beginning of an entity). Chunks will be
-      // delimited by start and chunkEnd.
-      const PRUnichar *chunkEnd = start;
-      while (chunkEnd != iter) {
-        if (*chunkEnd == kLessThan) {
-          aValue.Truncate();
-
-          return false;
-        }
-
-        if (*chunkEnd == kAmpersand) {
-          aValue.Append(start, chunkEnd - start);
-
-          // Point to first character after the ampersand.
-          ++chunkEnd;
-
-          const PRUnichar *afterEntity;
-          PRUnichar result[2];
-          PRUint32 count =
-            parserService->DecodeEntity(chunkEnd, iter, &afterEntity, result);
-          if (count == 0) {
-            aValue.Truncate();
-
-            return false;
-          }
-
-          aValue.Append(result, count);
-
-          // Advance to after the entity and begin a new chunk.
-          start = chunkEnd = afterEntity;
-        }
-        else {
-          ++chunkEnd;
-        }
-      }
-
-      // Append remainder.
-      aValue.Append(start, iter - start);
-
-      return true;
-    }
-
-    // Resume scanning after the end of the attribute value (past the quote
-    // char).
-    start = iter + 1;
-  }
-
-  return false;
-}
-
-// Returns true if the language name is a version of JavaScript and
-// false otherwise
-bool
-nsParserUtils::IsJavaScriptLanguage(const nsString& aName, PRUint32 *aFlags)
-{
-  JSVersion version = JSVERSION_UNKNOWN;
-
-  if (aName.LowerCaseEqualsLiteral("javascript") ||
-      aName.LowerCaseEqualsLiteral("livescript") ||
-      aName.LowerCaseEqualsLiteral("mocha")) {
-    version = JSVERSION_DEFAULT;
-  }
-  else if (aName.LowerCaseEqualsLiteral("javascript1.0")) {
-    version = JSVERSION_1_0;
-  }
-  else if (aName.LowerCaseEqualsLiteral("javascript1.1")) {
-    version = JSVERSION_1_1;
-  }
-  else if (aName.LowerCaseEqualsLiteral("javascript1.2")) {
-    version = JSVERSION_1_2;
-  }
-  else if (aName.LowerCaseEqualsLiteral("javascript1.3")) {
-    version = JSVERSION_1_3;
-  }
-  else if (aName.LowerCaseEqualsLiteral("javascript1.4")) {
-    version = JSVERSION_1_4;
-  }
-  else if (aName.LowerCaseEqualsLiteral("javascript1.5")) {
-    version = JSVERSION_1_5;
-  }
-  else if (aName.LowerCaseEqualsLiteral("javascript1.6")) {
-    version = JSVERSION_1_6;
-  }
-  else if (aName.LowerCaseEqualsLiteral("javascript1.7")) {
-    version = JSVERSION_1_7;
-  }
-  else if (aName.LowerCaseEqualsLiteral("javascript1.8")) {
-    version = JSVERSION_1_8;
-  }
-  if (version == JSVERSION_UNKNOWN)
-    return false;
-  *aFlags = version;
-  return true;
-}
-
-void
-nsParserUtils::SplitMimeType(const nsAString& aValue, nsString& aType,
-                             nsString& aParams)
-{
-  aType.Truncate();
-  aParams.Truncate();
-  PRInt32 semiIndex = aValue.FindChar(PRUnichar(';'));
-  if (-1 != semiIndex) {
-    aType = Substring(aValue, 0, semiIndex);
-    aParams = Substring(aValue, semiIndex + 1,
-                       aValue.Length() - (semiIndex + 1));
-    aParams.StripWhitespace();
-  }
-  else {
-    aType = aValue;
-  }
-  aType.StripWhitespace();
-}
deleted file mode 100644
--- a/content/base/src/nsParserUtils.h
+++ /dev/null
@@ -1,79 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is Mozilla Communicator client code.
- *
- * The Initial Developer of the Original Code is
- * Netscape Communications Corporation.
- * Portions created by the Initial Developer are Copyright (C) 1998
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either of the GNU General Public License Version 2 or later (the "GPL"),
- * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
-/*
- * Namespace class for some static parsing-related methods.
- */
-
-#ifndef nsParserUtils_h__
-#define nsParserUtils_h__
-
-#include "nsString.h"
-class nsIAtom;
-
-class nsParserUtils {
-public:
-  /**
-   * This will parse aSource, to extract the value of the pseudo attribute
-   * with the name specified in aName. See
-   * http://www.w3.org/TR/xml-stylesheet/#NT-StyleSheetPI for the specification
-   * which is used to parse aSource.
-   *
-   * @param aSource the string to parse
-   * @param aName the name of the attribute to get the value for
-   * @param aValue [out] the value for the attribute with name specified in
-   *                     aAttribute. Empty if the attribute isn't present.
-   * @return true     if the attribute exists and was successfully parsed.
-   *         false if the attribute doesn't exist, or has a malformed
-   *                  value, such as an unknown or unterminated entity.
-   */
-  static bool
-  GetQuotedAttributeValue(const nsString& aSource, nsIAtom *aName,
-                          nsAString& aValue);
-
-  static bool
-  IsJavaScriptLanguage(const nsString& aName, PRUint32 *aVerFlags);
-
-  static void
-  SplitMimeType(const nsAString& aValue, nsString& aType,
-                nsString& aParams);
-};
-
-#endif // nsParserUtils_h__
-
-
-
--- a/content/base/src/nsScriptLoader.cpp
+++ b/content/base/src/nsScriptLoader.cpp
@@ -39,17 +39,16 @@
 
 /*
  * A class that handles loading and evaluation of <script> elements.
  */
 
 #include "jsapi.h"
 #include "jsfriendapi.h"
 #include "nsScriptLoader.h"
-#include "nsParserUtils.h"
 #include "nsICharsetConverterManager.h"
 #include "nsIUnicodeDecoder.h"
 #include "nsIContent.h"
 #include "mozilla/dom/Element.h"
 #include "nsGkAtoms.h"
 #include "nsNetUtil.h"
 #include "nsIScriptGlobalObject.h"
 #include "nsIScriptContext.h"
@@ -504,24 +503,24 @@ nsScriptLoader::ProcessScriptElement(nsI
     }
   } else {
     // no 'type=' element
     // "language" is a deprecated attribute of HTML, so we check it only for
     // HTML script elements.
     if (scriptContent->IsHTML()) {
       scriptContent->GetAttr(kNameSpaceID_None, nsGkAtoms::language, language);
       if (!language.IsEmpty()) {
-        if (nsParserUtils::IsJavaScriptLanguage(language, &version))
+        if (nsContentUtils::IsJavaScriptLanguage(language, &version))
           typeID = nsIProgrammingLanguage::JAVASCRIPT;
         else
           typeID = nsIProgrammingLanguage::UNKNOWN;
         // IE, Opera, etc. do not respect language version, so neither should
         // we at this late date in the browser wars saga.  Note that this change
         // affects HTML but not XUL or SVG (but note also that XUL has its own
-        // code to check nsParserUtils::IsJavaScriptLanguage -- that's probably
+        // code to check nsContentUtils::IsJavaScriptLanguage -- that's probably
         // a separate bug, one we may not be able to fix short of XUL2).  See
         // bug 255895 (https://bugzilla.mozilla.org/show_bug.cgi?id=255895).
         NS_ASSERTION(JSVERSION_DEFAULT == 0,
                      "We rely on all languages having 0 as a version default");
         version = 0;
       }
     }
   }
--- a/content/base/test/TestPlainTextSerializer.cpp
+++ b/content/base/test/TestPlainTextSerializer.cpp
@@ -32,47 +32,28 @@
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "TestHarness.h"
 
-#include "nsIParser.h"
-#include "nsIHTMLToTextSink.h"
-#include "nsIParser.h"
-#include "nsIContentSink.h"
-#include "nsIParserService.h"
 #include "nsServiceManagerUtils.h"
 #include "nsStringGlue.h"
-#include "nsParserCIID.h"
 #include "nsIDocumentEncoder.h"
 #include "nsCRT.h"
-
-static NS_DEFINE_CID(kCParserCID, NS_PARSER_CID);
+#include "nsIParserUtils.h"
 
 void
 ConvertBufToPlainText(nsString &aConBuf, int aFlag)
 {
-  nsCOMPtr<nsIParser> parser = do_CreateInstance(kCParserCID);
-  if (parser) {
-    nsCOMPtr<nsIContentSink> sink;
-    sink = do_CreateInstance(NS_PLAINTEXTSINK_CONTRACTID);
-    if (sink) {
-      nsCOMPtr<nsIHTMLToTextSink> textSink(do_QueryInterface(sink));
-      if (textSink) {
-        nsAutoString convertedText;
-        textSink->Initialize(&convertedText, aFlag, 72);
-        parser->SetContentSink(sink);
-        parser->Parse(aConBuf, 0, NS_LITERAL_CSTRING("text/html"), true);
-        aConBuf = convertedText;
-      }
-    }
-  }
+  nsCOMPtr<nsIParserUtils> utils =
+    do_GetService(NS_PARSERUTILS_CONTRACTID);
+  utils->ConvertToPlainText(aConBuf, aFlag, 72, aConBuf);
 }
 
 // Test for ASCII with format=flowed; delsp=yes
 nsresult
 TestASCIIWithFlowedDelSp()
 {
   nsString test;
   nsString result;
--- a/content/base/test/chrome/Makefile.in
+++ b/content/base/test/chrome/Makefile.in
@@ -66,15 +66,16 @@ include $(topsrcdir)/config/rules.mk
     test_fileconstructor.xul \
     fileconstructor_file.png \
     test_bug339494.xul \
     test_bug357450.xul \
     test_bug571390.xul \
     test_bug574596.html \
     test_bug683852.xul \
     test_bug599295.html \
+    test_bug650784.html \
     $(NULL)
 
 libs:: $(_TEST_FILES)
 	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/tests/$(relativesrcdir)
 
 libs:: $(_CHROME_FILES)
 	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/chrome/$(relativesrcdir)
new file mode 100644
--- /dev/null
+++ b/content/base/test/chrome/test_bug650784.html
@@ -0,0 +1,43 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=650776
+-->
+<head>
+  <meta charset="utf-8">
+  <title>Test for Bug 650776</title>
+  <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=650776">Mozilla Bug 650776</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+  
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 650776 **/
+
+var c = Components.interfaces.nsIDocumentEncoder;
+var s = Components.classes["@mozilla.org/parserutils;1"]
+        .getService(Components.interfaces.nsIParserUtils);
+
+is(s.convertToPlainText("foo", c.OutputLFLineBreak, 0), "foo", "Wrong conversion result 1");
+is(s.convertToPlainText("foo foo foo", c.OutputWrap | c.OutputLFLineBreak, 7), "foo foo\nfoo", "Wrong conversion result 2");
+is(s.convertToPlainText("<body><noscript>b<span>a</span>r</noscript>foo", c.OutputLFLineBreak, 0), "foo", "Wrong conversion result 3");
+is(s.convertToPlainText("<body><noscript>b<span>a</span>r</noscript>foo", c.OutputNoScriptContent, 0), "barfoo", "Wrong conversion result 4");
+is(s.convertToPlainText("foo\u00A0bar", c.OutputPersistNBSP | c.OutputLFLineBreak, 0), "foo\u00A0bar", "Wrong conversion result 5");
+is(s.convertToPlainText("foo\u00A0bar", c.OutputLFLineBreak, 0), "foo bar", "Wrong conversion result 6");
+is(s.convertToPlainText("<body><noframes>bar</noframes>foo", c.OutputLFLineBreak, 0), "foo", "Wrong conversion result 7");
+// OutputNoFramesContent doesn't actually work, because the flag gets overridden by 
+// the browser.frames.enabled pref in all cases.
+is(s.convertToPlainText("<body><noframes>bar</noframes>foo", c.OutputNoFramesContent | c.OutputLFLineBreak, 0), "foo", "Wrong conversion result 8");
+is(s.convertToPlainText("<i>foo</i> <b>bar</b>", c.OutputFormatted | c.OutputLFLineBreak, 0), "/foo/ *bar*\n", "Wrong conversion result 9");
+is(s.convertToPlainText("<p>foo</p> <p>bar</p>", c.OutputLFLineBreak, 0), "foo\n\nbar", "Wrong conversion result 10");
+
+</script>
+</pre>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/content/canvas/crashtests/729116.html
@@ -0,0 +1,18 @@
+<html>
+<script language=javascript>
+
+function draw() {
+  var canv = document.getElementById("canv");
+  var ctx = canv.getContext("2d");
+  try {
+    canv.width = 50000;
+  } catch (e) { }
+
+  ctx.clearRect(0, 0, 10, 10);
+}
+
+</script>
+<body onload="draw()">
+<canvas id="canv" width="5" height="5"></canvas>
+</body>
+</html>
--- a/content/canvas/crashtests/crashtests.list
+++ b/content/canvas/crashtests/crashtests.list
@@ -1,5 +1,6 @@
 load 360293-1.html
 load 421715-1.html
 load 553938-1.html
 load 647480.html
 load 0px-size-font-667225.html
+skip-if(cocoaWidget&&layersGPUAccelerated) load 729116.html # bug 731117
--- a/content/canvas/src/WebGLContext.cpp
+++ b/content/canvas/src/WebGLContext.cpp
@@ -357,18 +357,16 @@ WebGLContext::SetDimensions(PRInt32 widt
 
         gl->ClearSafely();
 
         return NS_OK;
     }
 
     /*** end of early success return cases ***/
 
-    ScopedGfxFeatureReporter reporter("WebGL");
-
     // 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();
 
     // Get some prefs for some preferred/overriden things
     NS_ENSURE_TRUE(Preferences::GetRootBranch(), NS_ERROR_FAILURE);
 
     bool forceOSMesa =
@@ -381,16 +379,18 @@ WebGLContext::SetDimensions(PRInt32 widt
 #endif
     bool forceEnabled =
         Preferences::GetBool("webgl.force-enabled", false);
     bool disabled =
         Preferences::GetBool("webgl.disabled", false);
     bool verbose =
         Preferences::GetBool("webgl.verbose", false);
 
+    ScopedGfxFeatureReporter reporter("WebGL", forceEnabled);
+
     if (disabled)
         return NS_ERROR_FAILURE;
 
     mVerbose = verbose;
 
     // We're going to create an entirely new context.  If our
     // generation is not 0 right now (that is, if this isn't the first
     // context we're creating), we may have to dispatch a context lost
--- a/content/canvas/src/WebGLContextReporter.cpp
+++ b/content/canvas/src/WebGLContextReporter.cpp
@@ -37,17 +37,17 @@
  * ***** END LICENSE BLOCK ***** */
 
 #include "WebGLContext.h"
 #include "nsIMemoryReporter.h"
 
 using namespace mozilla;
 
 
-class WebGLMemoryMultiReporter : public nsIMemoryMultiReporter 
+class WebGLMemoryMultiReporter MOZ_FINAL : public nsIMemoryMultiReporter 
 {
   public:
     NS_DECL_ISUPPORTS
     NS_DECL_NSIMEMORYMULTIREPORTER
 };
 
 NS_IMPL_ISUPPORTS1(WebGLMemoryMultiReporter, nsIMemoryMultiReporter)
 
--- a/content/canvas/src/nsCanvasRenderingContext2DAzure.cpp
+++ b/content/canvas/src/nsCanvasRenderingContext2DAzure.cpp
@@ -1301,16 +1301,20 @@ nsCanvasRenderingContext2DAzure::Initial
   // will be set to non-null.
   // In all cases, any usable canvas context will have non-null mTarget.
 
   if (target) {
     mValid = true;
     mTarget = target;
   } else {
     mValid = false;
+    // Create a dummy target in the hopes that it will help us deal with users
+    // calling into us after having changed the size where the size resulted
+    // in an inability to create a correct DrawTarget.
+    mTarget = gfxPlatform::GetPlatform()->CreateOffscreenDrawTarget(IntSize(1, 1), FORMAT_B8G8R8A8);
   }
 
   mResetLayer = true;
 
   // set up the initial canvas defaults
   mStyleStack.Clear();
   mPathBuilder = nsnull;
   mPath = nsnull;
--- a/content/canvas/test/webgl/test_webgl_conformance_test_suite.html
+++ b/content/canvas/test/webgl/test_webgl_conformance_test_suite.html
@@ -37,16 +37,18 @@ var OPTIONS = {
     request.open('GET', url, false);
     request.send(null);
     if (request.readyState != 4) {
       throw error;
     }
     return request.responseText;
   };
 
+SimpleTest.waitForExplicitFinish();
+
 function start() {
 
   var kIsWindows = false;
   var kIsMac = false;
   var kIsLinux = false;
   if (navigator.platform.indexOf("Win") == 0)
     kIsWindows = true;
   else if (navigator.platform.indexOf("Linux") == 0)
@@ -57,16 +59,44 @@ function start() {
   var kIsWindowsVistaOrHigher = false;
   if (kIsWindows) {
     // code borrowed from browser/modules/test/browser_taskbar_preview.js
     netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
     var version = Components.classes["@mozilla.org/system-info;1"]
                             .getService(Components.interfaces.nsIPropertyBag2)
                             .getProperty("version");
     kIsWindowsVistaOrHigher = (parseFloat(version) >= 6.0);
+    // Workaround for Windows 2000 (driver?) which may crash itself.
+    if (parseFloat(version) <= 5.0) {
+      todo(false, "Test disabled on Windows 2000 and older. (To prevent possible system crash.)");
+      SimpleTest.finish();
+      return;
+    }
+  }
+
+  // we currently disable this test on version of Mac OSX older than 10.6,
+  // due to various weird failures, including one making getRenderbufferParameter tests
+  // on DEPTH_STENCIL fail
+  var kDarwinVersion = 0;
+  if (kIsMac) {
+    // code borrowed from browser/modules/test/browser_taskbar_preview.js
+    var is106orHigher = false;
+    netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+    kDarwinVersion = parseFloat(Components.classes["@mozilla.org/system-info;1"]
+                                          .getService(Components.interfaces.nsIPropertyBag2)
+                                          .getProperty("version"));
+    // the next line is correct: Mac OS 10.6 corresponds to Darwin version 10 !
+    // Mac OS 10.5 would be Darwin version 9. the |version| string we've got here
+    // is the Darwin version.
+    is106orHigher = (kDarwinVersion >= 10.0);
+    if (!is106orHigher) {
+      dump("WebGL mochitest disabled on Mac OSX versions older than 10.6\n");
+      SimpleTest.finish();
+      return;
+    }
   }
 
   function getEnv(env) {
     netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
     var envsvc = Components.classes["@mozilla.org/process/environment;1"].getService(Components.interfaces.nsIEnvironment);
     var val = envsvc.get(env);
     if (val == "")
       return null;
@@ -338,47 +368,28 @@ function start() {
                 return reporter.reportFunc(type, msg, success);
             },
             OPTIONS);
         testHarness.setTimeoutDelay(20000); // and make it much higher when running under valgrind.
         window.webglTestHarness = testHarness;
     } else {
         var errmsg = "Can't create a WebGL context";
         reporter.fullResultsNode.textContent = errmsg;
-        ok(false, errmsg);
+        // Workaround for SeaMonkey tinderboxes which don't support WebGL.
+        if (navigator.userAgent.match(/ SeaMonkey\//))
+          todo(false, errmsg + " (This is expected on SeaMonkey (tinderboxes).)");
+        else
+          ok(false, errmsg);
         dump("WebGL mochitest failed: " + errmsg + "\n");
         reporter.finishedTestSuite();
     }
   };
 
-  SimpleTest.waitForExplicitFinish();
   SimpleTest.requestLongerTimeout(3);
 
-  // we currently disable this test on version of Mac OSX older than 10.6,
-  // due to various weird failures, including one making getRenderbufferParameter tests
-  // on DEPTH_STENCIL fail
-  var kDarwinVersion = 0;
-  if (kIsMac) {
-    // code borrowed from browser/modules/test/browser_taskbar_preview.js
-    var is106orHigher = false;
-    netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
-    kDarwinVersion = parseFloat(Components.classes["@mozilla.org/system-info;1"]
-                                          .getService(Components.interfaces.nsIPropertyBag2)
-                                          .getProperty("version"));
-    // the next line is correct: Mac OS 10.6 corresponds to Darwin version 10 !
-    // Mac OS 10.5 would be Darwin version 9. the |version| string we've got here
-    // is the Darwin version.
-    is106orHigher = (kDarwinVersion >= 10.0);
-    if (!is106orHigher) {
-      dump("WebGL mochitest disabled on Mac OSX versions older than 10.6\n");
-      SimpleTest.finish();
-      return;
-    }
-  }
-
   var statusElem = document.getElementById("status");
   var statusTextNode = document.createTextNode('');
   statusElem.appendChild(statusTextNode);
 
   var expectedtofailElem = document.getElementById("expectedtofail");
   var expectedtofailTextNode = document.createTextNode('');
   expectedtofailElem.appendChild(expectedtofailTextNode);
 
@@ -426,17 +437,17 @@ function start() {
 
   var testsSuccessful = [];
 
   runTestSuite();
 }
 
 </script>
 </head>
-<body onload="start()">
+<body onload="start();">
 <p id="display"></p>
 <div id="content" style="display: none">
 
 </div>
 <table border="2px">
   <tr style="height: 500px;">
     <td style="width: 500px;">
       <iframe id="testframe" scrolling="no" width="500px" height="500px"></iframe>
--- a/content/html/content/src/nsHTMLLinkElement.cpp
+++ b/content/html/content/src/nsHTMLLinkElement.cpp
@@ -47,17 +47,16 @@
 #include "nsReadableUtils.h"
 #include "nsUnicharUtils.h"
 #include "nsIURL.h"
 #include "nsNetUtil.h"
 #include "nsIDocument.h"
 #include "nsIDOMEvent.h"
 #include "nsIPrivateDOMEvent.h"
 #include "nsIDOMEventTarget.h"
-#include "nsParserUtils.h"
 #include "nsContentUtils.h"
 #include "nsPIDOMWindow.h"
 #include "nsAsyncDOMEvent.h"
 
 #include "Link.h"
 using namespace mozilla::dom;
 
 class nsHTMLLinkElement : public nsGenericHTMLElement,
@@ -434,17 +433,17 @@ nsHTMLLinkElement::GetStyleSheetInfo(nsA
   }
 
   GetAttr(kNameSpaceID_None, nsGkAtoms::media, aMedia);
   ToLowerCase(aMedia); // HTML4.0 spec is inconsistent, make it case INSENSITIVE
 
   nsAutoString mimeType;
   nsAutoString notUsed;
   GetAttr(kNameSpaceID_None, nsGkAtoms::type, aType);
-  nsParserUtils::SplitMimeType(aType, mimeType, notUsed);
+  nsContentUtils::SplitMimeType(aType, mimeType, notUsed);
   if (!mimeType.IsEmpty() && !mimeType.LowerCaseEqualsLiteral("text/css")) {
     return;
   }
 
   // If we get here we assume that we're loading a css file, so set the
   // type to 'text/css'
   aType.AssignLiteral("text/css");
 
--- a/content/html/content/src/nsHTMLStyleElement.cpp
+++ b/content/html/content/src/nsHTMLStyleElement.cpp
@@ -42,17 +42,16 @@
 #include "nsGkAtoms.h"
 #include "nsStyleConsts.h"
 #include "nsIDOMStyleSheet.h"
 #include "nsIStyleSheet.h"
 #include "nsStyleLinkElement.h"
 #include "nsNetUtil.h"
 #include "nsIDocument.h"
 #include "nsUnicharUtils.h"
-#include "nsParserUtils.h"
 #include "nsThreadUtils.h"
 #include "nsContentUtils.h"
 
 class nsHTMLStyleElement : public nsGenericHTMLElement,
                            public nsIDOMHTMLStyleElement,
                            public nsStyleLinkElement,
                            public nsStubMutationObserver
 {
@@ -342,17 +341,17 @@ nsHTMLStyleElement::GetStyleSheetInfo(ns
 
   GetAttr(kNameSpaceID_None, nsGkAtoms::media, aMedia);
   ToLowerCase(aMedia); // HTML4.0 spec is inconsistent, make it case INSENSITIVE
 
   GetAttr(kNameSpaceID_None, nsGkAtoms::type, aType);
 
   nsAutoString mimeType;
   nsAutoString notUsed;
-  nsParserUtils::SplitMimeType(aType, mimeType, notUsed);
+  nsContentUtils::SplitMimeType(aType, mimeType, notUsed);
   if (!mimeType.IsEmpty() && !mimeType.LowerCaseEqualsLiteral("text/css")) {
     return;
   }
 
   // If we get here we assume that we're loading a css file, so set the
   // type to 'text/css'
   aType.AssignLiteral("text/css");
 }
--- a/content/html/document/src/nsHTMLContentSink.cpp
+++ b/content/html/document/src/nsHTMLContentSink.cpp
@@ -45,17 +45,16 @@
 #include "nsContentSink.h"
 #include "nsCOMPtr.h"
 #include "nsReadableUtils.h"
 #include "nsUnicharUtils.h"
 #include "nsIHTMLContentSink.h"
 #include "nsIInterfaceRequestor.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsIParser.h"
-#include "nsParserUtils.h"
 #include "nsScriptLoader.h"
 #include "nsIURI.h"
 #include "nsNetUtil.h"
 #include "nsIContentViewer.h"
 #include "nsIMarkupDocumentViewer.h"
 #include "nsINodeInfo.h"
 #include "nsHTMLTokens.h"
 #include "nsIAppShell.h"
--- a/content/mathml/content/src/nsMathMLElement.cpp
+++ b/content/mathml/content/src/nsMathMLElement.cpp
@@ -141,16 +141,21 @@ nsMathMLElement::ParseAttribute(PRInt32 
       return aResult.ParseColor(aValue);
     }
   }
 
   return nsMathMLElementBase::ParseAttribute(aNamespaceID, aAttribute,
                                              aValue, aResult);
 }
 
+static nsGenericElement::MappedAttributeEntry sMtableStyles[] = {
+  { &nsGkAtoms::width },
+  { nsnull }
+};
+
 static nsGenericElement::MappedAttributeEntry sTokenStyles[] = {
   { &nsGkAtoms::mathsize_ },
   { &nsGkAtoms::fontsize_ },
   { &nsGkAtoms::color },
   { &nsGkAtoms::fontfamily_ },
   { nsnull }
 };
 
@@ -166,16 +171,20 @@ static nsGenericElement::MappedAttribute
   { &nsGkAtoms::mathcolor_ },
   { &nsGkAtoms::mathbackground_ },
   { nsnull }
 };
 
 bool
 nsMathMLElement::IsAttributeMapped(const nsIAtom* aAttribute) const
 {
+  static const MappedAttributeEntry* const mtableMap[] = {
+    sMtableStyles,
+    sCommonPresStyles
+  };
   static const MappedAttributeEntry* const tokenMap[] = {
     sTokenStyles,
     sCommonPresStyles
   };
   static const MappedAttributeEntry* const mstyleMap[] = {
     sTokenStyles,
     sEnvironmentStyles,
     sCommonPresStyles
@@ -189,16 +198,19 @@ nsMathMLElement::IsAttributeMapped(const
   if (tag == nsGkAtoms::ms_ || tag == nsGkAtoms::mi_ ||
       tag == nsGkAtoms::mn_ || tag == nsGkAtoms::mo_ ||
       tag == nsGkAtoms::mtext_ || tag == nsGkAtoms::mspace_)
     return FindAttributeDependence(aAttribute, tokenMap);
   if (tag == nsGkAtoms::mstyle_ ||
       tag == nsGkAtoms::math)
     return FindAttributeDependence(aAttribute, mstyleMap);
 
+  if (tag == nsGkAtoms::mtable_)
+    return FindAttributeDependence(aAttribute, mtableMap);
+
   if (tag == nsGkAtoms::maction_ ||
       tag == nsGkAtoms::maligngroup_ ||
       tag == nsGkAtoms::malignmark_ ||
       tag == nsGkAtoms::menclose_ ||
       tag == nsGkAtoms::merror_ ||
       tag == nsGkAtoms::mfenced_ ||
       tag == nsGkAtoms::mfrac_ ||
       tag == nsGkAtoms::mover_ ||
@@ -206,17 +218,16 @@ nsMathMLElement::IsAttributeMapped(const
       tag == nsGkAtoms::mphantom_ ||
       tag == nsGkAtoms::mprescripts_ ||
       tag == nsGkAtoms::mroot_ ||
       tag == nsGkAtoms::mrow_ ||
       tag == nsGkAtoms::msqrt_ ||
       tag == nsGkAtoms::msub_ ||
       tag == nsGkAtoms::msubsup_ ||
       tag == nsGkAtoms::msup_ ||
-      tag == nsGkAtoms::mtable_ ||
       tag == nsGkAtoms::mtd_ ||
       tag == nsGkAtoms::mtr_ ||
       tag == nsGkAtoms::munder_ ||
       tag == nsGkAtoms::munderover_ ||
       tag == nsGkAtoms::none) {
     return FindAttributeDependence(aAttribute, commonPresMap);
   }
 
@@ -454,16 +465,29 @@ nsMathMLElement::MapMathMLAttributesInto
     }
     nscolor color;
     nsCSSValue* colorValue = aData->ValueForColor();
     if (value && value->GetColorValue(color) &&
         colorValue->GetUnit() == eCSSUnit_Null) {
       colorValue->SetColorValue(color);
     }
   }
+
+  if (aData->mSIDs & NS_STYLE_INHERIT_BIT(Position)) {
+    // width: value
+    nsCSSValue* width = aData->ValueForWidth();
+    if (width->GetUnit() == eCSSUnit_Null) {
+      const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::width);
+      // This does not handle auto and unitless values
+      if (value && value->Type() == nsAttrValue::eString) {
+        ParseNumericValue(value->GetStringValue(), *width, 0);
+      }
+    }
+  }
+
 }
 
 nsresult
 nsMathMLElement::PreHandleEvent(nsEventChainPreVisitor& aVisitor)
 {
   nsresult rv = nsGenericElement::PreHandleEvent(aVisitor);
   NS_ENSURE_SUCCESS(rv, rv);
 
--- a/content/xml/content/src/nsXMLProcessingInstruction.cpp
+++ b/content/xml/content/src/nsXMLProcessingInstruction.cpp
@@ -34,18 +34,18 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsGenericElement.h"
 #include "nsGkAtoms.h"
 #include "nsUnicharUtils.h"
 #include "nsXMLProcessingInstruction.h"
-#include "nsParserUtils.h"
 #include "nsContentCreatorFunctions.h"
+#include "nsContentUtils.h"
 
 nsresult
 NS_NewXMLProcessingInstruction(nsIContent** aInstancePtrResult,
                                nsNodeInfoManager *aNodeInfoManager,
                                const nsAString& aTarget,
                                const nsAString& aData)
 {
   NS_PRECONDITION(aNodeInfoManager, "Missing nodeinfo manager");
@@ -124,17 +124,17 @@ nsXMLProcessingInstruction::GetTarget(ns
 }
 
 bool
 nsXMLProcessingInstruction::GetAttrValue(nsIAtom *aName, nsAString& aValue)
 {
   nsAutoString data;
 
   GetData(data);
-  return nsParserUtils::GetQuotedAttributeValue(data, aName, aValue);
+  return nsContentUtils::GetPseudoAttributeValue(data, aName, aValue);
 }
 
 bool
 nsXMLProcessingInstruction::IsNodeOfType(PRUint32 aFlags) const
 {
   return !(aFlags & ~(eCONTENT | ePROCESSING_INSTRUCTION | eDATA_NODE));
 }
 
--- a/content/xml/content/src/nsXMLStylesheetPI.cpp
+++ b/content/xml/content/src/nsXMLStylesheetPI.cpp
@@ -40,17 +40,16 @@
 #include "nsIDOMStyleSheet.h"
 #include "nsIDocument.h"
 #include "nsIStyleSheet.h"
 #include "nsIURI.h"
 #include "nsStyleLinkElement.h"
 #include "nsNetUtil.h"
 #include "nsXMLProcessingInstruction.h"
 #include "nsUnicharUtils.h"
-#include "nsParserUtils.h"
 #include "nsGkAtoms.h"
 #include "nsThreadUtils.h"
 #include "nsContentUtils.h"
 
 class nsXMLStylesheetPI : public nsXMLProcessingInstruction,
                           public nsStyleLinkElement
 {
 public:
@@ -204,37 +203,39 @@ nsXMLStylesheetPI::GetStyleSheetInfo(nsA
   // xml-stylesheet PI is special only in prolog
   if (!nsContentUtils::InProlog(this)) {
     return;
   }
 
   nsAutoString data;
   GetData(data);
 
-  nsParserUtils::GetQuotedAttributeValue(data, nsGkAtoms::title, aTitle);
+  nsContentUtils::GetPseudoAttributeValue(data, nsGkAtoms::title, aTitle);
 
   nsAutoString alternate;
-  nsParserUtils::GetQuotedAttributeValue(data, nsGkAtoms::alternate, alternate);
+  nsContentUtils::GetPseudoAttributeValue(data,
+                                          nsGkAtoms::alternate,
+                                          alternate);
 
   // if alternate, does it have title?
   if (alternate.EqualsLiteral("yes")) {
     if (aTitle.IsEmpty()) { // alternates must have title
       return;
     }
 
     *aIsAlternate = true;
   }
 
-  nsParserUtils::GetQuotedAttributeValue(data, nsGkAtoms::media, aMedia);
+  nsContentUtils::GetPseudoAttributeValue(data, nsGkAtoms::media, aMedia);
 
   nsAutoString type;
-  nsParserUtils::GetQuotedAttributeValue(data, nsGkAtoms::type, type);
+  nsContentUtils::GetPseudoAttributeValue(data, nsGkAtoms::type, type);
 
   nsAutoString mimeType, notUsed;
-  nsParserUtils::SplitMimeType(type, mimeType, notUsed);
+  nsContentUtils::SplitMimeType(type, mimeType, notUsed);
   if (!mimeType.IsEmpty() && !mimeType.LowerCaseEqualsLiteral("text/css")) {
     aType.Assign(type);
     return;
   }
 
   // If we get here we assume that we're loading a css file, so set the
   // type to 'text/css'
   aType.AssignLiteral("text/css");
--- a/content/xml/document/src/nsXMLContentSink.cpp
+++ b/content/xml/document/src/nsXMLContentSink.cpp
@@ -63,17 +63,16 @@
 #include "nsIScriptContext.h"
 #include "nsINameSpaceManager.h"
 #include "nsIServiceManager.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsIContentViewer.h"
 #include "prtime.h"
 #include "prlog.h"
 #include "prmem.h"
-#include "nsParserUtils.h"
 #include "nsRect.h"
 #include "nsGenericElement.h"
 #include "nsIWebNavigation.h"
 #include "nsIScriptElement.h"
 #include "nsScriptLoader.h"
 #include "nsStyleLinkElement.h"
 #include "nsIImageLoadingContent.h"
 #include "nsReadableUtils.h"
@@ -260,37 +259,37 @@ CheckXSLTParamPI(nsIDOMProcessingInstruc
 {
   nsAutoString target, data;
   aPi->GetTarget(target);
 
   // Check for namespace declarations
   if (target.EqualsLiteral("xslt-param-namespace")) {
     aPi->GetData(data);
     nsAutoString prefix, namespaceAttr;
-    nsParserUtils::GetQuotedAttributeValue(data, nsGkAtoms::prefix,
-                                           prefix);
+    nsContentUtils::GetPseudoAttributeValue(data, nsGkAtoms::prefix,
+                                            prefix);
     if (!prefix.IsEmpty() &&
-        nsParserUtils::GetQuotedAttributeValue(data, nsGkAtoms::_namespace,
-                                               namespaceAttr)) {
+        nsContentUtils::GetPseudoAttributeValue(data, nsGkAtoms::_namespace,
+                                                namespaceAttr)) {
       aProcessor->AddXSLTParamNamespace(prefix, namespaceAttr);
     }
   }
 
   // Check for actual parameters
   else if (target.EqualsLiteral("xslt-param")) {
     aPi->GetData(data);
     nsAutoString name, namespaceAttr, select, value;
-    nsParserUtils::GetQuotedAttributeValue(data, nsGkAtoms::name,
-                                           name);
-    nsParserUtils::GetQuotedAttributeValue(data, nsGkAtoms::_namespace,
-                                           namespaceAttr);
-    if (!nsParserUtils::GetQuotedAttributeValue(data, nsGkAtoms::select, select)) {
+    nsContentUtils::GetPseudoAttributeValue(data, nsGkAtoms::name,
+                                            name);
+    nsContentUtils::GetPseudoAttributeValue(data, nsGkAtoms::_namespace,
+                                            namespaceAttr);
+    if (!nsContentUtils::GetPseudoAttributeValue(data, nsGkAtoms::select, select)) {
       select.SetIsVoid(true);
     }
-    if (!nsParserUtils::GetQuotedAttributeValue(data, nsGkAtoms::value, value)) {
+    if (!nsContentUtils::GetPseudoAttributeValue(data, nsGkAtoms::value, value)) {
       value.SetIsVoid(true);
     }
     if (!name.IsEmpty()) {
       nsCOMPtr<nsIDOMNode> doc = do_QueryInterface(aDocument);
       aProcessor->AddXSLTParam(name, namespaceAttr, select, value, doc);
     }
   }
 }
@@ -1335,17 +1334,17 @@ nsXMLContentSink::HandleProcessingInstru
       }
 
       return NS_OK;
     }
   }
 
   // If it's not a CSS stylesheet PI...
   nsAutoString type;
-  nsParserUtils::GetQuotedAttributeValue(data, nsGkAtoms::type, type);
+  nsContentUtils::GetPseudoAttributeValue(data, nsGkAtoms::type, type);
 
   if (mState != eXMLContentSinkState_InProlog ||
       !target.EqualsLiteral("xml-stylesheet") ||
       type.IsEmpty()                          ||
       type.LowerCaseEqualsLiteral("text/css")) {
     return DidProcessATokenImpl();
   }
 
@@ -1363,26 +1362,28 @@ nsXMLContentSink::HandleProcessingInstru
 
 /* static */
 bool
 nsXMLContentSink::ParsePIData(const nsString &aData, nsString &aHref,
                               nsString &aTitle, nsString &aMedia,
                               bool &aIsAlternate)
 {
   // If there was no href, we can't do anything with this PI
-  if (!nsParserUtils::GetQuotedAttributeValue(aData, nsGkAtoms::href, aHref)) {
+  if (!nsContentUtils::GetPseudoAttributeValue(aData, nsGkAtoms::href, aHref)) {
     return false;
   }
 
-  nsParserUtils::GetQuotedAttributeValue(aData, nsGkAtoms::title, aTitle);
+  nsContentUtils::GetPseudoAttributeValue(aData, nsGkAtoms::title, aTitle);
 
-  nsParserUtils::GetQuotedAttributeValue(aData, nsGkAtoms::media, aMedia);
+  nsContentUtils::GetPseudoAttributeValue(aData, nsGkAtoms::media, aMedia);
 
   nsAutoString alternate;
-  nsParserUtils::GetQuotedAttributeValue(aData, nsGkAtoms::alternate, alternate);
+  nsContentUtils::GetPseudoAttributeValue(aData,
+                                          nsGkAtoms::alternate,
+                                          alternate);
 
   aIsAlternate = alternate.EqualsLiteral("yes");
 
   return true;
 }
 
 NS_IMETHODIMP
 nsXMLContentSink::HandleXMLDeclaration(const PRUnichar *aVersion,
--- a/content/xul/content/src/nsXULElement.cpp
+++ b/content/xul/content/src/nsXULElement.cpp
@@ -1363,17 +1363,18 @@ nsXULElement::UnsetAttr(PRInt32 aNameSpa
     bool hasMutationListeners = aNotify &&
         nsContentUtils::HasMutationListeners(this,
             NS_EVENT_BITS_MUTATION_ATTRMODIFIED, this);
 
     nsCOMPtr<nsIDOMAttr> attrNode;
     if (hasMutationListeners) {
         nsAutoString ns;
         nsContentUtils::NameSpaceManager()->GetNameSpaceURI(aNameSpaceID, ns);
-        GetAttributeNodeNS(ns, nsDependentAtomString(aName), getter_AddRefs(attrNode));
+        GetAttributeNodeNSInternal(ns, nsDependentAtomString(aName),
+                                   getter_AddRefs(attrNode));
     }
 
     nsDOMSlots *slots = GetExistingDOMSlots();
     if (slots && slots->mAttributeMap) {
       slots->mAttributeMap->DropAttribute(aNameSpaceID, aName);
     }
 
     // The id-handling code, and in the future possibly other code, need to
--- a/content/xul/document/src/nsXULContentSink.cpp
+++ b/content/xul/document/src/nsXULContentSink.cpp
@@ -69,17 +69,16 @@
 #include "nsIServiceManager.h"
 #include "nsIURL.h"
 #include "nsIViewManager.h"
 #include "nsIXULDocument.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsLayoutCID.h"
 #include "nsNetUtil.h"
 #include "nsRDFCID.h"
-#include "nsParserUtils.h"
 #include "nsXPIDLString.h"
 #include "nsReadableUtils.h"
 #include "nsXULElement.h"
 #include "prlog.h"
 #include "prmem.h"
 #include "nsCRT.h"
 
 #include "nsXULPrototypeDocument.h"     // XXXbe temporary
@@ -1074,17 +1073,17 @@ XULContentSinkImpl::OpenScript(const PRU
               }
           }
       }
       else if (key.EqualsLiteral("language")) {
           // Language is deprecated, and the impl in nsScriptLoader ignores the
           // various version strings anyway.  So we make no attempt to support
           // languages other than JS for language=
           nsAutoString lang(aAttributes[1]);
-          if (nsParserUtils::IsJavaScriptLanguage(lang, &version)) {
+          if (nsContentUtils::IsJavaScriptLanguage(lang, &version)) {
               langID = nsIProgrammingLanguage::JAVASCRIPT;
 
               // Even when JS version < 1.6 is specified, E4X is
               // turned on in XUL.
               version = js::VersionSetXML(JSVersion(version), true);
           }
       }
       aAttributes += 2;
--- a/content/xul/document/src/nsXULDocument.cpp
+++ b/content/xul/document/src/nsXULDocument.cpp
@@ -79,17 +79,16 @@
 #include "nsITimer.h"
 #include "nsIDocShell.h"
 #include "nsGkAtoms.h"
 #include "nsXMLContentSink.h"
 #include "nsXULContentSink.h"
 #include "nsXULContentUtils.h"
 #include "nsIXULOverlayProvider.h"
 #include "nsNetUtil.h"
-#include "nsParserUtils.h"
 #include "nsParserCIID.h"
 #include "nsPIBoxObject.h"
 #include "nsRDFCID.h"
 #include "nsILocalStore.h"
 #include "nsXPIDLString.h"
 #include "nsPIDOMWindow.h"
 #include "nsPIWindowRoot.h"
 #include "nsXULCommandDispatcher.h"
@@ -2540,19 +2539,19 @@ nsXULDocument::InsertXULOverlayPI(const 
     if (NS_FAILED(rv)) return rv;
 
     // xul-overlay PI is special only in prolog
     if (!nsContentUtils::InProlog(aPINode)) {
         return NS_OK;
     }
 
     nsAutoString href;
-    nsParserUtils::GetQuotedAttributeValue(aProtoPI->mData,
-                                           nsGkAtoms::href,
-                                           href);
+    nsContentUtils::GetPseudoAttributeValue(aProtoPI->mData,
+                                            nsGkAtoms::href,
+                                            href);
 
     // If there was no href, we can't do anything with this PI
     if (href.IsEmpty()) {
         return NS_OK;
     }
 
     // Add the overlay to our list of overlays that need to be processed.
     nsCOMPtr<nsIURI> uri;
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -7662,37 +7662,40 @@ void nsGlobalWindow::MaybeUpdateTouchSta
   nsIFocusManager* fm = nsFocusManager::GetFocusManager();
 
   nsCOMPtr<nsIDOMWindow> focusedWindow;
   fm->GetFocusedWindow(getter_AddRefs(focusedWindow));
 
   if(this == focusedWindow) {
     UpdateTouchState();
   }
+
+  if (mMayHaveTouchEventListener) {
+    nsCOMPtr<nsIObserverService> observerService =
+      do_GetService(NS_OBSERVERSERVICE_CONTRACTID);
+
+    if (observerService) {
+      observerService->NotifyObservers(static_cast<nsIDOMWindow*>(this),
+                                       DOM_TOUCH_LISTENER_ADDED,
+                                       nsnull);
+    }
+  }
 }
 
 void nsGlobalWindow::UpdateTouchState()
 {
   FORWARD_TO_INNER_VOID(UpdateTouchState, ());
 
   nsCOMPtr<nsIWidget> mainWidget = GetMainWidget();
-  if (!mainWidget)
+  if (!mainWidget) {
     return;
+  }
 
   if (mMayHaveTouchEventListener) {
     mainWidget->RegisterTouchWindow();
-
-    nsCOMPtr<nsIObserverService> observerService =
-      do_GetService(NS_OBSERVERSERVICE_CONTRACTID);
-
-    if (observerService) {
-      observerService->NotifyObservers(static_cast<nsIDOMWindow*>(this),
-                                       DOM_TOUCH_LISTENER_ADDED,
-                                       nsnull);
-    }
   } else {
     mainWidget->UnregisterTouchWindow();
   }
 }
 
 void
 nsGlobalWindow::EnableDeviceMotionUpdates()
 {
--- a/dom/plugins/base/nsPluginHost.cpp
+++ b/dom/plugins/base/nsPluginHost.cpp
@@ -927,19 +927,19 @@ nsPluginHost::GetPluginTempDir(nsIFile *
     NS_ENSURE_SUCCESS(rv, rv);
 
     tmpDir.swap(sPluginTempDir);
   }
 
   return sPluginTempDir->Clone(aDir);
 }
 
-nsresult nsPluginHost::InstantiatePluginForChannel(nsIChannel* aChannel,
-                                                   nsObjectLoadingContent* aContent,
-                                                   nsIStreamListener** aListener)
+nsresult nsPluginHost::CreateListenerForChannel(nsIChannel* aChannel,
+                                                nsObjectLoadingContent* aContent,
+                                                nsIStreamListener** aListener)
 {
   NS_PRECONDITION(aChannel && aContent,
                   "Invalid arguments to InstantiatePluginForChannel");
   nsCOMPtr<nsIURI> uri;
   nsresult rv = aChannel->GetURI(getter_AddRefs(uri));
   if (NS_FAILED(rv))
     return rv;
 
@@ -1063,17 +1063,17 @@ nsPluginHost::InstantiateEmbeddedPlugin(
       nsCOMPtr<nsIProtocolHandler> handler = do_GetService(contractID.get());
       if (handler)
         bCanHandleInternally = true;
   }
 
   // if we don't have a MIME type at this point, we still have one more chance by
   // opening the stream and seeing if the server hands one back
   if (!aMimeType) {
-    if (bCanHandleInternally && !aContent->SrcStreamLoadInitiated()) {
+    if (bCanHandleInternally && !aContent->SrcStreamLoading()) {
       NewEmbeddedPluginStream(aURL, aContent, nsnull);
     }
     return NS_ERROR_FAILURE;
   }
 
   rv = SetUpPluginInstance(aMimeType, aURL, instanceOwner);
   if (NS_FAILED(rv)) {
     return NS_ERROR_FAILURE;
@@ -1091,17 +1091,17 @@ nsPluginHost::InstantiateEmbeddedPlugin(
     // If we've got a native window, the let the plugin know about it.
     instanceOwner->CallSetWindow();
 
     // create an initial stream with data
     // don't make the stream if it's a java applet or we don't have SRC or DATA attribute
     // no need to check for "data" as it would have been converted to "src"
     const char *value;
     bool havedata = NS_SUCCEEDED(pti->GetAttribute("SRC", &value));
-    if (havedata && !isJava && bCanHandleInternally && !aContent->SrcStreamLoadInitiated()) {
+    if (havedata && !isJava && bCanHandleInternally && !aContent->SrcStreamLoading()) {
       NewEmbeddedPluginStream(aURL, nsnull, instance.get());
     }
   }
 
   // At this point we consider instantiation to be successful. Do not return an error.
   instanceOwner.forget(aOwner);
 
 #ifdef PLUGIN_LOGGING
--- a/dom/plugins/base/nsPluginHost.h
+++ b/dom/plugins/base/nsPluginHost.h
@@ -108,19 +108,19 @@ public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIPLUGINHOST
   NS_DECL_NSIOBSERVER
   NS_DECL_NSITIMERCALLBACK
 
   nsresult Init();
   nsresult Destroy();
   nsresult LoadPlugins();
-  nsresult InstantiatePluginForChannel(nsIChannel* aChannel,
-                                       nsObjectLoadingContent* aContent,
-                                       nsIStreamListener** aListener);
+  nsresult CreateListenerForChannel(nsIChannel* aChannel,
+                                    nsObjectLoadingContent* aContent,
+                                    nsIStreamListener** aListener);
   nsresult SetUpPluginInstance(const char *aMimeType,
                                nsIURI *aURL,
                                nsIPluginInstanceOwner *aOwner);
   nsresult IsPluginEnabledForType(const char* aMimeType);
   nsresult IsPluginEnabledForExtension(const char* aExtension, const char* &aMimeType);
 
   nsresult GetPluginCount(PRUint32* aPluginCount);
   nsresult GetPlugins(PRUint32 aPluginCount, nsIDOMPlugin** aPluginArray);
--- a/dom/src/geolocation/nsGeoPosition.h
+++ b/dom/src/geolocation/nsGeoPosition.h
@@ -81,28 +81,28 @@ public:
 
 ////////////////////////////////////////////////////
 // nsGeoPositionCoords
 ////////////////////////////////////////////////////
 
 /**
  * Simple object that holds a single point in space.
  */
-class nsGeoPositionCoords : public nsIDOMGeoPositionCoords
+class nsGeoPositionCoords MOZ_FINAL : public nsIDOMGeoPositionCoords
 {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIDOMGEOPOSITIONCOORDS
   
   nsGeoPositionCoords(double aLat, double aLong,
                       double aAlt, double aHError,
                       double aVError, double aHeading,
                       double aSpeed);
+  ~nsGeoPositionCoords();
 private:
-  ~nsGeoPositionCoords();
   const double mLat, mLong, mAlt, mHError, mVError, mHeading, mSpeed;
 };
 
 
 ////////////////////////////////////////////////////
 // nsGeoPosition
 ////////////////////////////////////////////////////
 
--- a/dom/src/geolocation/nsGeoPositionIPCSerialiser.h
+++ b/dom/src/geolocation/nsGeoPositionIPCSerialiser.h
@@ -37,17 +37,17 @@
 #ifndef dom_src_geolocation_IPC_serialiser
 #define dom_src_geolocation_IPC_serialiser
 
 #include "IPC/IPCMessageUtils.h"
 #include "nsGeoPosition.h"
 #include "nsIDOMGeoPosition.h"
 
 typedef nsIDOMGeoPositionAddress  *GeoPositionAddress;
-typedef nsIDOMGeoPositionCoords   *GeoPositionCoords;
+typedef nsGeoPositionCoords       *GeoPositionCoords;
 typedef nsIDOMGeoPosition         *GeoPosition;
 
 namespace IPC {
 
 template <>
 struct ParamTraits<GeoPositionAddress>
 {
   typedef GeoPositionAddress paramType;
@@ -228,17 +228,17 @@ struct ParamTraits<GeoPosition>
     if (isNull) return;
 
     DOMTimeStamp timeStamp;
     aParam->GetTimestamp(&timeStamp);
     WriteParam(aMsg, timeStamp);
 
     nsCOMPtr<nsIDOMGeoPositionCoords> coords;
     aParam->GetCoords(getter_AddRefs(coords));
-    GeoPositionCoords simpleCoords = coords.get();
+    GeoPositionCoords simpleCoords = static_cast<GeoPositionCoords>(coords.get());
     WriteParam(aMsg, simpleCoords);
 
     nsCOMPtr<nsIDOMGeoPositionAddress> address;
     aParam->GetAddress(getter_AddRefs(address));
     GeoPositionAddress simpleAddress = address.get();
     WriteParam(aMsg, simpleAddress);
   }
 
--- a/dom/tests/mochitest/bugs/test_resize_move_windows.html
+++ b/dom/tests/mochitest/bugs/test_resize_move_windows.html
@@ -257,20 +257,22 @@ function checkChangeIsEnabled(aWindow, a
   });
   });
   });
   });
   });
   });
 }
 
+SpecialPowers.pushPrefEnv({"set": [["dom.disable_window_move_resize", false]]}, function() {
 SimpleTest.waitForFocus(function() {
   if (screen.width <= 200 || screen.height <= 200) {
-    todo(false, "The screen is too small to run this test.");
+    todo(false, "The screen needs to be bigger than 200px*200px to run this test.");
     SimpleTest.finish();
+    return;
   }
 
   backValues();
 
   // The current window can't change it's own size and position.
   checkChangeIsDisabled(window, function() {
     // We create a window and check that it can change its own size and position.
     // However, passing size/position parameters to window.open should work.
@@ -313,13 +315,14 @@ SimpleTest.waitForFocus(function() {
               });
             });
           }, w, false);
         });
       })
     }, w, false);
   });
 });
+}); // SpecialPowers.pushPrefEnv()
 
 </script>
 </pre>
 </body>
 </html>
--- a/editor/txmgr/tests/TestTXMgr.cpp
+++ b/editor/txmgr/tests/TestTXMgr.cpp
@@ -787,289 +787,267 @@ quick_test(TestTransactionFactory *facto
   nsresult result;
 
   /*******************************************************************
    *
    * Create a transaction manager implementation:
    *
    *******************************************************************/
 
-  printf("Create transaction manager instance ... ");
-
   nsCOMPtr<nsITransactionManager> mgr =
     do_CreateInstance(NS_TRANSACTIONMANAGER_CONTRACTID, &result);
   if (NS_FAILED(result) || !mgr) {
     printf("ERROR: Failed to create Transaction Manager instance.\n");
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
-  printf("passed\n");
+  passed("Create transaction manager instance");
 
   /*******************************************************************
    *
    * Call DoTransaction() with a null transaction:
    *
    *******************************************************************/
 
-  printf("Call DoTransaction() with null transaction ... ");
   result = mgr->DoTransaction(0);
 
   if (result != NS_ERROR_NULL_POINTER) {
     printf("ERROR: DoTransaction() returned unexpected error. (%d)\n", result);
     return result;
   }
 
-  printf("passed\n");
+  passed("Call DoTransaction() with null transaction");
 
   /*******************************************************************
    *
    * Call UndoTransaction() with an empty undo stack:
    *
    *******************************************************************/
 
-  printf("Call UndoTransaction() with empty undo stack ... ");
   result = mgr->UndoTransaction();
 
   if (NS_FAILED(result)) {
     printf("ERROR: Undo on empty undo stack failed. (%d)\n", result);
     return result;
   }
 
-  printf("passed\n");
+  passed("Call UndoTransaction() with empty undo stack");
 
   /*******************************************************************
    *
    * Call RedoTransaction() with an empty redo stack:
    *
    *******************************************************************/
 
-  printf("Call RedoTransaction() with empty redo stack ... ");
   result = mgr->RedoTransaction();
 
   if (NS_FAILED(result)) {
     printf("ERROR: Redo on empty redo stack failed. (%d)\n", result);
     return result;
   }
 
-  printf("passed\n");
+  passed("Call RedoTransaction() with empty redo stack");
 
   /*******************************************************************
    *
    * Call SetMaxTransactionCount(-1) with empty undo and redo stacks:
    *
    *******************************************************************/
 
-  printf("Call SetMaxTransactionCount(-1) with empty undo and redo stacks ... ");
   result = mgr->SetMaxTransactionCount(-1);
 
   if (NS_FAILED(result)) {
     printf("ERROR: SetMaxTransactionCount(-1) failed. (%d)\n", result);
     return result;
   }
 
-  printf("passed\n");
+  passed("Call SetMaxTransactionCount(-1) with empty undo and redo stacks");
 
   /*******************************************************************
    *
    * Call SetMaxTransactionCount(0) with empty undo and redo stacks:
    *
    *******************************************************************/
 
-  printf("Call SetMaxTransactionCount(0) with empty undo and redo stacks ... ");
   result = mgr->SetMaxTransactionCount(0);
 
   if (NS_FAILED(result)) {
     printf("ERROR: SetMaxTransactionCount(0) failed. (%d)\n", result);
     return result;
   }
 
-  printf("passed\n");
+  passed("Call SetMaxTransactionCount(0) with empty undo and redo stacks");
 
   /*******************************************************************
    *
    * Call SetMaxTransactionCount(10) with empty undo and redo stacks:
    *
    *******************************************************************/
 
-  printf("Call SetMaxTransactionCount(10) with empty undo and redo stacks ... ");
   result = mgr->SetMaxTransactionCount(10);
 
   if (NS_FAILED(result)) {
     printf("ERROR: SetMaxTransactionCount(10) failed. (%d)\n", result);
     return result;
   }
 
-  printf("passed\n");
+  passed("Call SetMaxTransactionCount(10) with empty undo and redo stacks");
 
   /*******************************************************************
    *
    * Call Clear() with empty undo and redo stacks:
    *
    *******************************************************************/
 
-  printf("Call Clear() with empty undo and redo stack ... ");
-
   result = mgr->Clear();
   if (NS_FAILED(result)) {
     printf("ERROR: Clear on empty undo and redo stack failed. (%d)\n", result);
     return result;
   }
 
-  printf("passed\n");
+  passed("Call Clear() with empty undo and redo stack");
 
   PRInt32 numitems;
 
   /*******************************************************************
    *
    * Call GetNumberOfUndoItems() with an empty undo stack:
    *
    *******************************************************************/
 
-  printf("Call GetNumberOfUndoItems() with empty undo stack ... ");
   result = mgr->GetNumberOfUndoItems(&numitems);
 
   if (NS_FAILED(result)) {
     printf("ERROR: GetNumberOfUndoItems() on empty undo stack failed. (%d)\n",
            result);
     return result;
   }
 
   if (numitems != 0) {
     printf("ERROR: GetNumberOfUndoItems() expected 0 got %d. (%d)\n",
            numitems, result);
     return NS_ERROR_FAILURE;
   }
 
-  printf("passed\n");
+  passed("Call GetNumberOfUndoItems() with empty undo stack");
 
   /*******************************************************************
    *
    * Call GetNumberOfRedoItems() with an empty redo stack:
    *
    *******************************************************************/
 
-  printf("Call GetNumberOfRedoItems() with empty redo stack ... ");
   result = mgr->GetNumberOfRedoItems(&numitems);
 
   if (NS_FAILED(result)) {
     printf("ERROR: GetNumberOfRedoItems() on empty redo stack failed. (%d)\n",
            result);
     return result;
   }
 
   if (numitems != 0) {
     printf("ERROR: GetNumberOfRedoItems() expected 0 got %d. (%d)\n",
            numitems, result);
     return NS_ERROR_FAILURE;
   }
 
-  printf("passed\n");
+  passed("Call GetNumberOfRedoItems() with empty redo stack");
 
   nsITransaction *tx;
 
   /*******************************************************************
    *
    * Call PeekUndoStack() with an empty undo stack:
    *
    *******************************************************************/
 
-  printf("Call PeekUndoStack() with empty undo stack ... ");
-
   tx = 0;
   result = mgr->PeekUndoStack(&tx);
 
   TEST_TXMGR_IF_RELEASE(tx); // Don't hold onto any references!
 
   if (NS_FAILED(result)) {
     printf("ERROR: PeekUndoStack() on empty undo stack failed. (%d)\n", result);
     return result;
   }
 
   if (tx != 0) {
     printf("ERROR: PeekUndoStack() on empty undo stack failed. (%d)\n", result);
     return NS_ERROR_FAILURE;
   }
 
-  printf("passed\n");
+  passed("Call PeekUndoStack() with empty undo stack");
 
   /*******************************************************************
    *
    * Call PeekRedoStack() with an empty undo stack:
    *
    *******************************************************************/
 
-  printf("Call PeekRedoStack() with empty undo stack ... ");
-
   tx = 0;
   result = mgr->PeekRedoStack(&tx);
 
   TEST_TXMGR_IF_RELEASE(tx); // Don't hold onto any references!
 
   if (NS_FAILED(result)) {
     printf("ERROR: PeekRedoStack() on empty redo stack failed. (%d)\n", result);
     return result;
   }
 
   if (tx != 0) {
     printf("ERROR: PeekRedoStack() on empty redo stack failed. (%d)\n", result);
     return NS_ERROR_FAILURE;
   }
 
-  printf("passed\n");
+  passed("Call PeekRedoStack() with empty undo stack");
 
   /*******************************************************************
    *
    * Call AddListener() with a null listener pointer:
    *
    *******************************************************************/
 
-  printf("Call AddListener() with null listener ... ");
-
   result = mgr->AddListener(0);
 
   if (result != NS_ERROR_NULL_POINTER) {
     printf("ERROR: AddListener() returned unexpected error. (%d)\n", result);
     return result;
   }
 
-  printf("passed\n");
+  passed("Call AddListener() with null listener");
 
   /*******************************************************************
    *
    * Call RemoveListener() with a null listener pointer:
    *
    *******************************************************************/
 
-  printf("Call RemoveListener() with null listener ... ");
-
   result = mgr->RemoveListener(0);
 
   if (result != NS_ERROR_NULL_POINTER) {
     printf("ERROR: RemoveListener() returned unexpected error. (%d)\n", result);
     return result;
   }
 
-  printf("passed\n");
+  passed("Call RemoveListener() with null listener");
 
   PRInt32 i;
   TestTransaction *tximpl;
   nsITransaction *u1, *u2;
   nsITransaction *r1, *r2;
 
   /*******************************************************************
    *
    * Test coalescing by executing a transaction that can merge any
    * command into itself. Then execute 20 transaction. Afterwards,
    * we should still have the first transaction sitting on the undo
    * stack. Then clear the undo and redo stacks.
    *
    *******************************************************************/
 
-  printf("Test coalescing of transactions ... ");
-
   result = mgr->SetMaxTransactionCount(10);
 
   if (NS_FAILED(result)) {
     printf("ERROR: SetMaxTransactionCount(10) failed. (%d)\n", result);
     return result;
   }
 
 
@@ -1206,27 +1184,25 @@ quick_test(TestTransactionFactory *facto
   }
 
   result = mgr->Clear();
   if (NS_FAILED(result)) {
     printf("ERROR: Clear() failed. (%d)\n", result);
     return result;
   }
 
-  printf("passed\n");
+  passed("Test coalescing of transactions");
 
   /*******************************************************************
    *
    * Execute 20 transactions. Afterwards, we should have 10
    * transactions on the undo stack:
    *
    *******************************************************************/
 
-  printf("Execute 20 transactions ... ");
-
   for (i = 1; i <= 20; i++) {
     tximpl = factory->create(mgr, NONE_FLAG);
 
     if (!tximpl) {
       printf("ERROR: Failed to allocate transaction %d.\n", i);
       return NS_ERROR_OUT_OF_MEMORY;
     }
 
@@ -1270,27 +1246,25 @@ quick_test(TestTransactionFactory *facto
   }
 
   if (numitems != 0) {
     printf("ERROR: GetNumberOfRedoItems() expected 0 got %d. (%d)\n",
            numitems, result);
     return NS_ERROR_FAILURE;
   }
 
-  printf("passed\n");
+  passed("Execute 20 transactions");
 
   /*******************************************************************
    *
    * Execute 20 transient transactions. Afterwards, we should still
    * have the same 10 transactions on the undo stack:
    *
    *******************************************************************/
 
-  printf("Execute 20 transient transactions ... ");
-
   u1 = u2 = r1 = r2 = 0;
 
   result = mgr->PeekUndoStack(&u1);
 
   TEST_TXMGR_IF_RELEASE(u1); // Don't hold onto any references!
 
   if (NS_FAILED(result)) {
     printf("ERROR: Initial PeekUndoStack() failed. (%d)\n", result);
@@ -1382,27 +1356,25 @@ quick_test(TestTransactionFactory *facto
   }
 
   if (numitems != 0) {
     printf("ERROR: GetNumberOfRedoItems() expected 0 got %d. (%d)\n",
            numitems, result);
     return NS_ERROR_FAILURE;
   }
 
-  printf("passed\n");
+  passed("Execute 20 transient transactions");
 
   /*******************************************************************
    *
    * Undo 4 transactions. Afterwards, we should have 6 transactions
    * on the undo stack, and 4 on the redo stack:
    *
    *******************************************************************/
 
-  printf("Undo 4 transactions ... ");
-
   for (i = 1; i <= 4; i++) {
     result = mgr->UndoTransaction();
     if (NS_FAILED(result)) {
       printf("ERROR: Failed to undo transaction %d. (%d)\n", i, result);
       return result;
     }
   }
 
@@ -1429,27 +1401,25 @@ quick_test(TestTransactionFactory *facto
   }
 
   if (numitems != 4) {
     printf("ERROR: GetNumberOfRedoItems() expected 4 got %d. (%d)\n",
            numitems, result);
     return NS_ERROR_FAILURE;
   }
 
-  printf("passed\n");
+  passed("Undo 4 transactions");
 
   /*******************************************************************
    *
    * Redo 2 transactions. Afterwards, we should have 8 transactions
    * on the undo stack, and 2 on the redo stack:
    *
    *******************************************************************/
 
-  printf("Redo 2 transactions ... ");
-
   for (i = 1; i <= 2; ++i) {
     result = mgr->RedoTransaction();
     if (NS_FAILED(result)) {
       printf("ERROR: Failed to redo transaction %d. (%d)\n", i, result);
       return result;
     }
   }
 
@@ -1476,26 +1446,24 @@ quick_test(TestTransactionFactory *facto
   }
 
   if (numitems != 2) {
     printf("ERROR: GetNumberOfRedoItems() expected 2 got %d. (%d)\n",
            numitems, result);
     return NS_ERROR_FAILURE;
   }
 
-  printf("passed\n");
+  passed("Redo 2 transactions");
 
   /*******************************************************************
    *
    * Execute a new transaction. The redo stack should get pruned!
    *
    *******************************************************************/
 
-  printf("Check if new transactions prune the redo stack ... ");
-
   tximpl = factory->create(mgr, NONE_FLAG);
 
   if (!tximpl) {
     printf("ERROR: Failed to allocate transaction.\n");
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
   tx = 0;
@@ -1538,26 +1506,24 @@ quick_test(TestTransactionFactory *facto
   }
 
   if (numitems != 0) {
     printf("ERROR: GetNumberOfRedoItems() expected 0 got %d. (%d)\n",
            numitems, result);
     return NS_ERROR_FAILURE;
   }
 
-  printf("passed\n");
+  passed("Check if new transactions prune the redo stack");
 
   /*******************************************************************
    *
    * Undo 4 transactions then clear the undo and redo stacks.
    *
    *******************************************************************/
 
-  printf("Undo 4 transactions then clear the undo and redo stacks ... ");
-
   for (i = 1; i <= 4; ++i) {
     result = mgr->UndoTransaction();
     if (NS_FAILED(result)) {
       printf("ERROR: Failed to undo transaction %d. (%d)\n", i, result);
       return result;
     }
   }
 
@@ -1619,26 +1585,24 @@ quick_test(TestTransactionFactory *facto
   }
 
   if (numitems != 0) {
     printf("ERROR: GetNumberOfRedoItems() expected 0 got %d. (%d)\n",
            numitems, result);
     return NS_ERROR_FAILURE;
   }
 
-  printf("passed\n");
+  passed("Undo 4 transactions then clear the undo and redo stacks");
 
   /*******************************************************************
    *
    * Execute 5 transactions.
    *
    *******************************************************************/
 
-  printf("Execute 5 transactions ... ");
-
   for (i = 1; i <= 5; i++) {
     tximpl = factory->create(mgr, NONE_FLAG);
 
     if (!tximpl) {
       printf("ERROR: Failed to allocate transaction %d.\n", i);
       return NS_ERROR_OUT_OF_MEMORY;
     }
 
@@ -1682,26 +1646,24 @@ quick_test(TestTransactionFactory *facto
   }
 
   if (numitems != 0) {
     printf("ERROR: GetNumberOfRedoItems() expected 0 got %d. (%d)\n",
            numitems, result);
     return NS_ERROR_FAILURE;
   }
 
-  printf("passed\n");
+  passed("Execute 5 transactions");
 
   /*******************************************************************
    *
    * Test transaction DoTransaction() error:
    *
    *******************************************************************/
 
-  printf("Test transaction DoTransaction() error ... ");
-
   tximpl = factory->create(mgr, THROWS_DO_ERROR_FLAG);
 
   if (!tximpl) {
     printf("ERROR: Failed to allocate transaction.\n");
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
   tx = 0;
@@ -1793,26 +1755,24 @@ quick_test(TestTransactionFactory *facto
   }
 
   if (numitems != 0) {
     printf("ERROR: GetNumberOfRedoItems() expected 0 got %d. (%d)\n",
            numitems, result);
     return NS_ERROR_FAILURE;
   }
 
-  printf("passed\n");
+  passed("Test transaction DoTransaction() error");
 
   /*******************************************************************
    *
    * Test transaction UndoTransaction() error:
    *
    *******************************************************************/
 
-  printf("Test transaction UndoTransaction() error ... ");
-
   tximpl = factory->create(mgr, THROWS_UNDO_ERROR_FLAG);
 
   if (!tximpl) {
     printf("ERROR: Failed to allocate transaction.\n");
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
   tx = 0;
@@ -1911,26 +1871,24 @@ quick_test(TestTransactionFactory *facto
   }
 
   if (numitems != 0) {
     printf("ERROR: GetNumberOfRedoItems() expected 0 got %d. (%d)\n",
            numitems, result);
     return NS_ERROR_FAILURE;
   }
 
-  printf("passed\n");
+  passed("Test transaction UndoTransaction() error");
 
   /*******************************************************************
    *
    * Test transaction RedoTransaction() error:
    *
    *******************************************************************/
 
-  printf("Test transaction RedoTransaction() error ... ");
-
   tximpl = factory->create(mgr, THROWS_REDO_ERROR_FLAG);
 
   if (!tximpl) {
     printf("ERROR: Failed to allocate transaction.\n");
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
   tx = 0;
@@ -2075,28 +2033,26 @@ quick_test(TestTransactionFactory *facto
   }
 
   if (numitems != 2) {
     printf("ERROR: GetNumberOfRedoItems() expected 2 got %d. (%d)\n",
            numitems, result);
     return NS_ERROR_FAILURE;
   }
 
-  printf("passed\n");
+  passed("Test transaction RedoTransaction() error");
 
   /*******************************************************************
    *
    * Make sure that setting the transaction manager's max transaction
    * count to zero, clears both the undo and redo stacks, and executes
    * all new commands without pushing them on the undo stack!
    *
    *******************************************************************/
 
-  printf("Test max transaction count of zero ... ");
-
   result = mgr->SetMaxTransactionCount(0);
 
   if (NS_FAILED(result)) {
     printf("ERROR: SetMaxTransactionCount(0) failed. (%d)\n", result);
     return result;
   }
 
   result = mgr->GetNumberOfUndoItems(&numitems);
@@ -2175,28 +2131,26 @@ quick_test(TestTransactionFactory *facto
 
     if (numitems != 0) {
       printf("ERROR: GetNumberOfRedoItems() expected 0 got %d. (%d)\n",
              numitems, result);
       return NS_ERROR_FAILURE;
     }
   }
 
-  printf("passed\n");
+  passed("Test max transaction count of zero");
 
   /*******************************************************************
    *
    * Make sure that setting the transaction manager's max transaction
    * count to something greater than the number of transactions on
    * both the undo and redo stacks causes no pruning of the stacks:
    *
    *******************************************************************/
 
-  printf("Test SetMaxTransactionCount() greater than num stack items ... ");
-
   result = mgr->SetMaxTransactionCount(-1);
 
   if (NS_FAILED(result)) {
     printf("ERROR: SetMaxTransactionCount(-1) failed. (%d)\n", result);
     return result;
   }
 
   // Push 20 transactions on the undo stack:
@@ -2368,28 +2322,26 @@ quick_test(TestTransactionFactory *facto
   }
 
   if (numitems != 10) {
     printf("ERROR: GetNumberOfRedoItems() expected 10 got %d. (%d)\n",
            numitems, result);
     return NS_ERROR_FAILURE;
   }
 
-  printf("passed\n");
+  passed("Test SetMaxTransactionCount() greater than num stack items");
 
   /*******************************************************************
    *
    * Test undo stack pruning by setting the transaction
    * manager's max transaction count to a number lower than the
    * number of transactions on both the undo and redo stacks:
    *
    *******************************************************************/
 
-  printf("Test SetMaxTransactionCount() pruning undo stack ... ");
-
   u1 = u2 = r1 = r2 = 0;
 
   result = mgr->PeekUndoStack(&u1);
 
   TEST_TXMGR_IF_RELEASE(u1); // Don't hold onto any references!
 
   if (NS_FAILED(result)) {
     printf("ERROR: Initial PeekUndoStack() failed. (%d)\n", result);
@@ -2463,28 +2415,26 @@ quick_test(TestTransactionFactory *facto
   }
 
   if (numitems != 10) {
     printf("ERROR: GetNumberOfRedoItems() expected 10 got %d. (%d)\n",
            numitems, result);
     return NS_ERROR_FAILURE;
   }
 
-  printf("passed\n");
+  passed("Test SetMaxTransactionCount() pruning undo stack");
 
   /*******************************************************************
    *
    * Test redo stack pruning by setting the transaction
    * manager's max transaction count to a number lower than the
    * number of transactions on both the undo and redo stacks:
    *
    *******************************************************************/
 
-  printf("Test SetMaxTransactionCount() pruning redo stack ... ");
-
   u1 = u2 = r1 = r2 = 0;
 
   result = mgr->PeekUndoStack(&u1);
 
   TEST_TXMGR_IF_RELEASE(u1); // Don't hold onto any references!
 
   if (NS_FAILED(result)) {
     printf("ERROR: Initial PeekUndoStack() failed. (%d)\n", result);
@@ -2558,27 +2508,25 @@ quick_test(TestTransactionFactory *facto
   }
 
   if (numitems != 5) {
     printf("ERROR: GetNumberOfRedoItems() expected 5 got %d. (%d)\n",
            numitems, result);
     return NS_ERROR_FAILURE;
   }
 
-  printf("passed\n");
+  passed("Test SetMaxTransactionCount() pruning redo stack");
 
   /*******************************************************************
    *
    * Release the transaction manager. Any transactions on the undo
    * and redo stack should automatically be released:
    *
    *******************************************************************/
 
-  printf("Release the transaction manager ... ");
-
   result = mgr->SetMaxTransactionCount(-1);
 
   if (NS_FAILED(result)) {
     printf("ERROR: SetMaxTransactionCount(-1) failed. (%d)\n", result);
     return result;
   }
 
   // Push 20 transactions on the undo stack:
@@ -2673,35 +2621,33 @@ quick_test(TestTransactionFactory *facto
   }
 
   result = mgr->Clear();
   if (NS_FAILED(result)) {
     printf("ERROR: Clear() failed. (%d)\n", result);
     return result;
   }
 
-  printf("passed\n");
+  passed("Release the transaction manager");
 
   /*******************************************************************
    *
    * Make sure number of transactions created matches number of
    * transactions destroyed!
    *
    *******************************************************************/
 
-  printf("Number of transactions created and destroyed match ... ");
-
   if (sConstructorCount != sDestructorCount) {
     printf("ERROR: Transaction constructor count (%d) != destructor count (%d).\n",
            sConstructorCount, sDestructorCount);
     return NS_ERROR_FAILURE;
   }
 
-  printf("passed\n");
-  printf("%d transactions processed during quick test.\n", sConstructorCount);
+  passed("Number of transactions created and destroyed match");
+  passed("%d transactions processed during quick test", sConstructorCount);
 
   return NS_OK;
 }
 
 nsresult
 simple_test()
 {
   /*******************************************************************
@@ -2769,38 +2715,34 @@ quick_batch_test(TestTransactionFactory 
   nsresult result;
 
   /*******************************************************************
    *
    * Create a transaction manager implementation:
    *
    *******************************************************************/
 
-  printf("Create transaction manager instance ... ");
-
   nsCOMPtr<nsITransactionManager> mgr =
     do_CreateInstance(NS_TRANSACTIONMANAGER_CONTRACTID, &result);
   if (NS_FAILED(result) || !mgr) {
     printf("ERROR: Failed to create Transaction Manager instance.\n");
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
-  printf("passed\n");
+  passed("Create transaction manager instance");
 
   PRInt32 numitems;
 
   /*******************************************************************
    *
    * Make sure an unbalanced call to EndBatch() with empty undo stack
    * throws an error!
    *
    *******************************************************************/
 
-  printf("Test unbalanced EndBatch() with empty undo stack ... ");
-
   result = mgr->GetNumberOfUndoItems(&numitems);
 
   if (NS_FAILED(result)) {
     printf("ERROR: GetNumberOfUndoItems() on empty undo stack failed. (%d)\n",
            result);
     return result;
   }
 
@@ -2826,28 +2768,25 @@ quick_batch_test(TestTransactionFactory 
   }
 
   if (numitems != 0) {
     printf("ERROR: GetNumberOfUndoItems() expected 0 got %d. (%d)\n",
            numitems, result);
     return NS_ERROR_FAILURE;
   }
 
-  printf("passed\n");
-
+  passed("Test unbalanced EndBatch() with empty undo stack");
 
   /*******************************************************************
    *
    * Make sure that an empty batch is not added to the undo stack
    * when it is closed.
    *
    *******************************************************************/
 
-  printf("Test empty batch ... ");
-
   result = mgr->GetNumberOfUndoItems(&numitems);
 
   if (NS_FAILED(result)) {
     printf("ERROR: GetNumberOfUndoItems() on empty undo stack failed. (%d)\n",
            result);
     return result;
   }
 
@@ -2894,31 +2833,29 @@ quick_batch_test(TestTransactionFactory 
   }
 
   if (numitems != 0) {
     printf("ERROR: GetNumberOfUndoItems() expected 0 got %d. (%d)\n",
            numitems, result);
     return NS_ERROR_FAILURE;
   }
 
-  printf("passed\n");
+  passed("Test empty batch");
 
   PRInt32 i;
   TestTransaction *tximpl;
   nsITransaction *tx;
 
   /*******************************************************************
    *
    * Execute 20 transactions. Afterwards, we should have 1
    * transaction on the undo stack:
    *
    *******************************************************************/
 
-  printf("Execute 20 batched transactions ... ");
-
   result = mgr->BeginBatch();
 
   if (NS_FAILED(result)) {
     printf("ERROR: BeginBatch() failed. (%d)\n", result);
     return result;
   }
 
   for (i = 1; i <= 20; i++) {
@@ -2976,30 +2913,28 @@ quick_batch_test(TestTransactionFactory 
   }
 
   if (numitems != 1) {
     printf("ERROR: GetNumberOfUndoItems() expected 1 got %d. (%d)\n",
            numitems, result);
     return NS_ERROR_FAILURE;
   }
 
-  printf("passed\n");
+  passed("Execute 20 batched transactions");
 
   nsITransaction *u1, *u2;
   nsITransaction *r1, *r2;
 
   /*******************************************************************
    *
    * Execute 20 transient transactions. Afterwards, we should still
    * have the same transaction on the undo stack:
    *
    *******************************************************************/
 
-  printf("Execute 20 batched transient transactions ... ");
-
   u1 = u2 = r1 = r2 = 0;
 
   result = mgr->PeekUndoStack(&u1);
 
   TEST_TXMGR_IF_RELEASE(u1); // Don't hold onto any references!
 
   if (NS_FAILED(result)) {
     printf("ERROR: Initial PeekUndoStack() failed. (%d)\n", result);
@@ -3105,27 +3040,25 @@ quick_batch_test(TestTransactionFactory 
   }
 
   if (numitems != 0) {
     printf("ERROR: GetNumberOfRedoItems() expected 0 got %d. (%d)\n",
            numitems, result);
     return NS_ERROR_FAILURE;
   }
 
-  printf("passed\n");
+  passed("Execute 20 batched transient transactions");
 
   /*******************************************************************
    *
    * Test nested batching. Afterwards, we should have 2 transactions
    * on the undo stack:
    *
    *******************************************************************/
 
-  printf("Test nested batched transactions ... ");
-
   result = mgr->BeginBatch();
 
   if (NS_FAILED(result)) {
     printf("ERROR: BeginBatch() failed. (%d)\n", result);
     return result;
   }
 
   tximpl = factory->create(mgr, NONE_FLAG);
@@ -3280,27 +3213,25 @@ quick_batch_test(TestTransactionFactory 
   }
 
   if (numitems != 2) {
     printf("ERROR: GetNumberOfUndoItems() expected 2 got %d. (%d)\n",
            numitems, result);
     return NS_ERROR_FAILURE;
   }
 
-  printf("passed\n");
+  passed("Test nested batched transactions");
 
   /*******************************************************************
    *
    * Undo 2 batch transactions. Afterwards, we should have 0
    * transactions on the undo stack and 2 on the redo stack.
    *
    *******************************************************************/
 
-  printf("Undo 2 batch transactions ... ");
-
   for (i = 1; i <= 2; ++i) {
     result = mgr->UndoTransaction();
     if (NS_FAILED(result)) {
       printf("ERROR: Failed to undo transaction %d. (%d)\n", i, result);
       return result;
     }
   }
 
@@ -3327,28 +3258,25 @@ quick_batch_test(TestTransactionFactory 
   }
 
   if (numitems != 2) {
     printf("ERROR: GetNumberOfRedoItems() expected 2 got %d. (%d)\n",
            numitems, result);
     return NS_ERROR_FAILURE;
   }
 
-  printf("passed\n");
+  passed("Undo 2 batch transactions");
 
   /*******************************************************************
    *
    * Redo 2 batch transactions. Afterwards, we should have 2
    * transactions on the undo stack and 0 on the redo stack.
    *
    *******************************************************************/
 
-
-  printf("Redo 2 batch transactions ... ");
-
   for (i = 1; i <= 2; ++i) {
     result = mgr->RedoTransaction();
     if (NS_FAILED(result)) {
       printf("ERROR: Failed to undo transaction %d. (%d)\n", i, result);
       return result;
     }
   }
 
@@ -3375,27 +3303,25 @@ quick_batch_test(TestTransactionFactory 
   }
 
   if (numitems != 0) {
     printf("ERROR: GetNumberOfRedoItems() expected 0 got %d. (%d)\n",
            numitems, result);
     return NS_ERROR_FAILURE;
   }
 
-  printf("passed\n");
+  passed("Redo 2 batch transactions");
 
   /*******************************************************************
    *
    * Call undo. Afterwards, we should have 1 transaction
    * on the undo stack, and 1 on the redo stack:
    *
    *******************************************************************/
 
-  printf("Undo a batched transaction that was redone ... ");
-
   result = mgr->UndoTransaction();
 
   if (NS_FAILED(result)) {
     printf("ERROR: Failed to undo transaction. (%d)\n", result);
     return result;
   }
 
   result = mgr->GetNumberOfUndoItems(&numitems);
@@ -3421,27 +3347,25 @@ quick_batch_test(TestTransactionFactory 
   }
 
   if (numitems != 1) {
     printf("ERROR: GetNumberOfRedoItems() expected 1 got %d. (%d)\n",
            numitems, result);
     return NS_ERROR_FAILURE;
   }
 
-  printf("passed\n");
+  passed("Undo a batched transaction that was redone");
 
   /*******************************************************************
    *
    * Make sure an unbalanced call to EndBatch() throws an error and
    * doesn't affect the undo and redo stacks!
    *
    *******************************************************************/
 
-  printf("Test effect of unbalanced EndBatch() on undo and redo stacks ... ");
-
   result = mgr->EndBatch();
 
   if (result != NS_ERROR_FAILURE) {
     printf("ERROR: EndBatch() returned unexpected status. (%d)\n", result);
     return result;
   }
 
   result = mgr->GetNumberOfUndoItems(&numitems);
@@ -3467,28 +3391,26 @@ quick_batch_test(TestTransactionFactory 
   }
 
   if (numitems != 1) {
     printf("ERROR: GetNumberOfRedoItems() expected 1 got %d. (%d)\n",
            numitems, result);
     return NS_ERROR_FAILURE;
   }
 
-  printf("passed\n");
+  passed("Test effect of unbalanced EndBatch() on undo and redo stacks");
 
   /*******************************************************************
    *
    * Make sure that an empty batch is not added to the undo stack
    * when it is closed, and that it does not affect the undo and redo
    * stacks.
    *
    *******************************************************************/
 
-  printf("Test effect of empty batch on undo and redo stacks ... ");
-
   result = mgr->BeginBatch();
 
   if (NS_FAILED(result)) {
     printf("ERROR: BeginBatch() failed. (%d)\n", result);
     return result;
   }
 
   result = mgr->GetNumberOfUndoItems(&numitems);
@@ -3549,28 +3471,24 @@ quick_batch_test(TestTransactionFactory 
   }
 
   if (numitems != 1) {
     printf("ERROR: GetNumberOfRedoItems() expected 1 got %d. (%d)\n",
            numitems, result);
     return NS_ERROR_FAILURE;
   }
 
-
-  printf("passed\n");
-
+  passed("Test effect of empty batch on undo and redo stacks");
 
   /*******************************************************************
    *
    * Execute a new transaction. The redo stack should get pruned!
    *
    *******************************************************************/
 
-  printf("Check if new batched transactions prune the redo stack ... ");
-
   result = mgr->BeginBatch();
 
   if (NS_FAILED(result)) {
     printf("ERROR: BeginBatch() failed. (%d)\n", result);
     return result;
   }
 
   for (i = 1; i <= 20; i++) {
@@ -3656,26 +3574,24 @@ quick_batch_test(TestTransactionFactory 
   }
 
   if (numitems != 0) {
     printf("ERROR: GetNumberOfRedoItems() expected 0 got %d. (%d)\n",
            numitems, result);
     return NS_ERROR_FAILURE;
   }
 
-  printf("passed\n");
+  passed("Check if new batched transactions prune the redo stack");
 
   /*******************************************************************
    *
    * Call undo.
    *
    *******************************************************************/
 
-  printf("Call undo ... ");
-
   // Move a transaction over to the redo stack, so that we have one
   // transaction on the undo stack, and one on the redo stack!
 
   result = mgr->UndoTransaction();
 
   if (NS_FAILED(result)) {
     printf("ERROR: Failed to undo transaction. (%d)\n", result);
     return result;
@@ -3704,27 +3620,24 @@ quick_batch_test(TestTransactionFactory 
   }
 
   if (numitems != 1) {
     printf("ERROR: GetNumberOfRedoItems() expected 1 got %d. (%d)\n",
            numitems, result);
     return NS_ERROR_FAILURE;
   }
 
-  printf("passed\n");
+  passed("Call undo");
 
   /*******************************************************************
    *
    * Test transaction DoTransaction() error:
    *
    *******************************************************************/
 
-  printf("Test transaction DoTransaction() error ... ");
-
-
   tximpl = factory->create(mgr, THROWS_DO_ERROR_FLAG);
 
   if (!tximpl) {
     printf("ERROR: Failed to allocate transaction.\n");
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
   tx     = 0;
@@ -3830,26 +3743,24 @@ quick_batch_test(TestTransactionFactory 
   }
 
   if (numitems != 1) {
     printf("ERROR: GetNumberOfRedoItems() expected 1 got %d. (%d)\n",
            numitems, result);
     return NS_ERROR_FAILURE;
   }
 
-  printf("passed\n");
+  passed("Test transaction DoTransaction() error");
 
   /*******************************************************************
    *
    * Test transaction UndoTransaction() error:
    *
    *******************************************************************/
 
-  printf("Test transaction UndoTransaction() error ... ");
-
   tximpl = factory->create(mgr, THROWS_UNDO_ERROR_FLAG);
 
   if (!tximpl) {
     printf("ERROR: Failed to allocate transaction.\n");
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
   tx     = 0;
@@ -3962,26 +3873,24 @@ quick_batch_test(TestTransactionFactory 
   }
 
   if (numitems != 0) {
     printf("ERROR: GetNumberOfRedoItems() expected 0 got %d. (%d)\n",
            numitems, result);
     return NS_ERROR_FAILURE;
   }
 
-  printf("passed\n");
+  passed("Test transaction UndoTransaction() error");
 
   /*******************************************************************
    *
    * Test transaction RedoTransaction() error:
    *
    *******************************************************************/
 
-  printf("Test transaction RedoTransaction() error ... ");
-
   tximpl = factory->create(mgr, THROWS_REDO_ERROR_FLAG);
 
   if (!tximpl) {
     printf("ERROR: Failed to allocate transaction.\n");
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
   tx     = 0;
@@ -4140,28 +4049,26 @@ quick_batch_test(TestTransactionFactory 
   }
 
   if (numitems != 2) {
     printf("ERROR: GetNumberOfRedoItems() expected 2 got %d. (%d)\n",
            numitems, result);
     return NS_ERROR_FAILURE;
   }
 
-  printf("passed\n");
+  passed("Test transaction RedoTransaction() error");
 
   /*******************************************************************
    *
    * Make sure that setting the transaction manager's max transaction
    * count to zero, clears both the undo and redo stacks, and executes
    * all new commands without pushing them on the undo stack!
    *
    *******************************************************************/
 
-  printf("Test max transaction count of zero ... ");
-
   result = mgr->SetMaxTransactionCount(0);
 
   if (NS_FAILED(result)) {
     printf("ERROR: SetMaxTransactionCount(0) failed. (%d)\n", result);
     return result;
   }
 
   result = mgr->GetNumberOfUndoItems(&numitems);
@@ -4254,27 +4161,25 @@ quick_batch_test(TestTransactionFactory 
 
     if (numitems != 0) {
       printf("ERROR: GetNumberOfRedoItems() expected 0 got %d. (%d)\n",
              numitems, result);
       return NS_ERROR_FAILURE;
     }
   }
 
-  printf("passed\n");
+  passed("Test max transaction count of zero");
 
   /*******************************************************************
    *
    * Release the transaction manager. Any transactions on the undo
    * and redo stack should automatically be released:
    *
    *******************************************************************/
 
-  printf("Release the transaction manager ... ");
-
   result = mgr->SetMaxTransactionCount(-1);
 
   if (NS_FAILED(result)) {
     printf("ERROR: SetMaxTransactionCount(0) failed. (%d)\n", result);
     return result;
   }
 
   // Push 20 transactions on the undo stack:
@@ -4383,35 +4288,33 @@ quick_batch_test(TestTransactionFactory 
   }
 
   result = mgr->Clear();
   if (NS_FAILED(result)) {
     printf("ERROR: Clear() failed. (%d)\n", result);
     return result;
   }
 
-  printf("passed\n");
+  passed("Release the transaction manager");
 
   /*******************************************************************
    *
    * Make sure number of transactions created matches number of
    * transactions destroyed!
    *
    *******************************************************************/
 
-  printf("Number of transactions created and destroyed match ... ");
-
   if (sConstructorCount != sDestructorCount) {
     printf("ERROR: Transaction constructor count (%d) != destructor count (%d).\n",
            sConstructorCount, sDestructorCount);
     return NS_ERROR_FAILURE;
   }
 
-  printf("passed\n");
-  printf("%d transactions processed during quick batch test.\n",
+  passed("Number of transactions created and destroyed match");
+  passed("%d transactions processed during quick batch test",
          sConstructorCount);
 
   return NS_OK;
 }
 
 nsresult
 simple_batch_test()
 {
@@ -4576,31 +4479,31 @@ stress_test(TestTransactionFactory *fact
       }
     }
 
     // Trivial feedback not to let the user think the test is stuck.
     if (NS_UNLIKELY(j % 100 == 0))
       printf("%i ", j);
   } // for, iterations.
 
+  printf("passed\n");
+
   result = mgr->Clear();
   if (NS_FAILED(result)) {
     printf("ERROR: Clear() failed. (%d)\n", result);
     return result;
   }
 
   if (sConstructorCount != sDestructorCount) {
     printf("ERROR: Transaction constructor count (%d) != destructor count (%d).\n",
            sConstructorCount, sDestructorCount);
     return NS_ERROR_FAILURE;
   }
 
-  printf("passed\n");
-
-  printf("%d transactions processed during stress test.\n", sConstructorCount);
+  passed("%d transactions processed during stress test", sConstructorCount);
 
   return NS_OK;
 }
 
 nsresult
 simple_stress_test()
 {
   /*******************************************************************
--- a/embedding/components/webbrowserpersist/src/nsWebBrowserPersist.cpp
+++ b/embedding/components/webbrowserpersist/src/nsWebBrowserPersist.cpp
@@ -80,16 +80,17 @@
 #include "nsIDOMNamedNodeMap.h"
 #include "nsIDOMNodeList.h"
 #include "nsIWebProgressListener.h"
 #include "nsIAuthPrompt.h"
 #include "nsIPrompt.h"
 #include "nsISHEntry.h"
 #include "nsIWebPageDescriptor.h"
 #include "nsIFormControl.h"
+#include "nsContentUtils.h"
 
 #include "nsIDOMNodeFilter.h"
 #include "nsIDOMProcessingInstruction.h"
 #include "nsIDOMHTMLBodyElement.h"
 #include "nsIDOMHTMLTableElement.h"
 #include "nsIDOMHTMLTableRowElement.h"
 #include "nsIDOMHTMLTableCellElement.h"
 #include "nsIDOMHTMLAnchorElement.h"
@@ -2599,108 +2600,54 @@ nsWebBrowserPersist::EnumCleanupUploadLi
     {
         channel->Cancel(NS_BINDING_ABORTED);
     }
     UploadData *data = (UploadData *) aData;
     delete data; // Delete data associated with key
     return true;
 }
 
-
-bool
-nsWebBrowserPersist::GetQuotedAttributeValue(
-    const nsAString &aSource, const nsAString &aAttribute, nsAString &aValue)
-{  
-    // NOTE: This code was lifted verbatim from nsParserUtils.cpp
-    aValue.Truncate();
-    nsAString::const_iterator start, end;
-    aSource.BeginReading(start);
-    aSource.EndReading(end);
-    nsAString::const_iterator iter(end);
-
-    while (start != end) {
-        if (FindInReadable(aAttribute, start, iter))
-        {
-            // walk past any whitespace
-            while (iter != end && nsCRT::IsAsciiSpace(*iter))
-            {
-                ++iter;
-            }
-
-            if (iter == end)
-                break;
-            
-            // valid name="value" pair?
-            if (*iter != '=')
-            {
-                start = iter;
-                iter = end;
-                continue;
-            }
-            // move past the =
-            ++iter;
-
-            while (iter != end && nsCRT::IsAsciiSpace(*iter))
-            {
-                ++iter;
-            }
-
-            if (iter == end)
-                break;
-
-            PRUnichar q = *iter;
-            if (q != '"' && q != '\'')
-            {
-                start = iter;
-                iter = end;
-                continue;
-            }
-
-            // point to the first char of the value
-            ++iter;
-            start = iter;
-            if (FindCharInReadable(q, iter, end))
-            {
-                aValue = Substring(start, iter);
-                return true;
-            }
-
-            // we've run out of string.  Just return...
-            break;
-         }
-    }
-    return false;
-}
-
 nsresult nsWebBrowserPersist::FixupXMLStyleSheetLink(nsIDOMProcessingInstruction *aPI, const nsAString &aHref)
 {
     NS_ENSURE_ARG_POINTER(aPI);
     nsresult rv = NS_OK;
 
     nsAutoString data;
     rv = aPI->GetData(data);
     NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
 
     nsAutoString href;
-    GetQuotedAttributeValue(data, NS_LITERAL_STRING("href"), href);
+    nsContentUtils::GetPseudoAttributeValue(data,
+                                            nsGkAtoms::href,
+                                            href);
 
     // Construct and set a new data value for the xml-stylesheet
     if (!aHref.IsEmpty() && !href.IsEmpty())
     {
         nsAutoString alternate;
         nsAutoString charset;
         nsAutoString title;
         nsAutoString type;
         nsAutoString media;
 
-        GetQuotedAttributeValue(data, NS_LITERAL_STRING("alternate"), alternate);
-        GetQuotedAttributeValue(data, NS_LITERAL_STRING("charset"), charset);
-        GetQuotedAttributeValue(data, NS_LITERAL_STRING("title"), title);
-        GetQuotedAttributeValue(data, NS_LITERAL_STRING("type"), type);
-        GetQuotedAttributeValue(data, NS_LITERAL_STRING("media"), media);
+        nsContentUtils::GetPseudoAttributeValue(data,
+                                                nsGkAtoms::alternate,
+                                                alternate);
+        nsContentUtils::GetPseudoAttributeValue(data,
+                                                nsGkAtoms::charset,
+                                                charset);
+        nsContentUtils::GetPseudoAttributeValue(data,
+                                                nsGkAtoms::title,
+                                                title);
+        nsContentUtils::GetPseudoAttributeValue(data,
+                                                nsGkAtoms::type,
+                                                type);
+        nsContentUtils::GetPseudoAttributeValue(data,
+                                                nsGkAtoms::media,
+                                                media);
 
         NS_NAMED_LITERAL_STRING(kCloseAttr, "\" ");
         nsAutoString newData;
         newData += NS_LITERAL_STRING("href=\"") + aHref + kCloseAttr;
         if (!title.IsEmpty())
         {
             newData += NS_LITERAL_STRING("title=\"") + title + kCloseAttr;
         }
@@ -2731,17 +2678,17 @@ nsresult nsWebBrowserPersist::GetXMLStyl
 {
     NS_ENSURE_ARG_POINTER(aPI);
 
     nsresult rv = NS_OK;
     nsAutoString data;
     rv = aPI->GetData(data);
     NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
 
-    GetQuotedAttributeValue(data, NS_LITERAL_STRING("href"), aHref);
+    nsContentUtils::GetPseudoAttributeValue(data, nsGkAtoms::href, aHref);
 
     return NS_OK;
 }
 
 nsresult nsWebBrowserPersist::OnWalkDOMNode(nsIDOMNode *aNode)
 {
     // Fixup xml-stylesheet processing instructions
     nsCOMPtr<nsIDOMProcessingInstruction> nodeAsPI = do_QueryInterface(aNode);
--- a/embedding/components/webbrowserpersist/src/nsWebBrowserPersist.h
+++ b/embedding/components/webbrowserpersist/src/nsWebBrowserPersist.h
@@ -147,18 +147,16 @@ private:
         URIData **aData = nsnull);
     nsresult StoreURIAttribute(
         nsIDOMNode *aNode, const char *aAttribute,
         bool aNeedsPersisting = true,
         URIData **aData = nsnull)
     {
         return StoreURIAttributeNS(aNode, "", aAttribute, aNeedsPersisting, aData);
     }
-    bool GetQuotedAttributeValue(
-    const nsAString &aSource, const nsAString &aAttribute, nsAString &aValue);
     bool DocumentEncoderExists(const PRUnichar *aContentType);
 
     nsresult GetNodeToFixup(nsIDOMNode *aNodeIn, nsIDOMNode **aNodeOut);
     nsresult FixupURI(nsAString &aURI);
     nsresult FixupNodeAttributeNS(nsIDOMNode *aNode, const char *aNamespaceURI, const char *aAttribute);
     nsresult FixupNodeAttribute(nsIDOMNode *aNode, const char *aAttribute)
     {
         return FixupNodeAttributeNS(aNode, "", aAttribute);
--- a/gfx/layers/d3d10/LayerManagerD3D10.cpp
+++ b/gfx/layers/d3d10/LayerManagerD3D10.cpp
@@ -120,19 +120,19 @@ LayerManagerD3D10::~LayerManagerD3D10()
       delete attachments;
     }
   }
 
   Destroy();
 }
 
 bool
-LayerManagerD3D10::Initialize()
+LayerManagerD3D10::Initialize(bool force)
 {
-  ScopedGfxFeatureReporter reporter("D3D10 Layers");
+  ScopedGfxFeatureReporter reporter("D3D10 Layers", force);
 
   HRESULT hr;
 
   /* Create an Nv3DVUtils instance */
   if (!mNv3DVUtils) {
     mNv3DVUtils = new Nv3DVUtils();
     if (!mNv3DVUtils) {
       NS_WARNING("Could not create a new instance of Nv3DVUtils.\n");
--- a/gfx/layers/d3d10/LayerManagerD3D10.h
+++ b/gfx/layers/d3d10/LayerManagerD3D10.h
@@ -95,17 +95,17 @@ public:
   /*
    * Initializes the layer manager, this is when the layer manager will
    * actually access the device and attempt to create the swap chain used
    * to draw to the window. If this method fails the device cannot be used.
    * This function is not threadsafe.
    *
    * \return True is initialization was succesful, false when it was not.
    */
-  bool Initialize();
+  bool Initialize(bool force = false);
 
   /*
    * LayerManager implementation.
    */
   virtual void Destroy();
 
   virtual ShadowLayerForwarder* AsShadowForwarder()
   { return this; }
--- a/gfx/layers/d3d9/LayerManagerD3D9.cpp
+++ b/gfx/layers/d3d9/LayerManagerD3D9.cpp
@@ -65,19 +65,19 @@ LayerManagerD3D9::LayerManagerD3D9(nsIWi
 }
 
 LayerManagerD3D9::~LayerManagerD3D9()
 {
   Destroy();
 }
 
 bool
-LayerManagerD3D9::Initialize()
+LayerManagerD3D9::Initialize(bool force)
 {
-  ScopedGfxFeatureReporter reporter("D3D9 Layers");
+  ScopedGfxFeatureReporter reporter("D3D9 Layers", force);
 
   /* XXX: this preference and blacklist code should move out of the layer manager */
   bool forceAccelerate =
     Preferences::GetBool("layers.acceleration.force-enabled", false);
 
   nsCOMPtr<nsIGfxInfo> gfxInfo = do_GetService("@mozilla.org/gfx/info;1");
   if (gfxInfo) {
     PRInt32 status;
--- a/gfx/layers/d3d9/LayerManagerD3D9.h
+++ b/gfx/layers/d3d9/LayerManagerD3D9.h
@@ -98,17 +98,17 @@ public:
   /*
    * Initializes the layer manager, this is when the layer manager will
    * actually access the device and attempt to create the swap chain used
    * to draw to the window. If this method fails the device cannot be used.
    * This function is not threadsafe.
    *
    * \return True is initialization was succesful, false when it was not.
    */
-  bool Initialize();
+  bool Initialize(bool force = false);
 
   /*
    * Sets the clipping region for this layer manager. This is important on
    * windows because using OGL we no longer have GDI's native clipping. Therefor
    * widget must tell us what part of the screen is being invalidated,
    * and we should clip to this.
    *
    * \param aClippingRegion Region to clip to. Setting an empty region
--- a/gfx/layers/opengl/LayerManagerOGL.cpp
+++ b/gfx/layers/opengl/LayerManagerOGL.cpp
@@ -172,19 +172,19 @@ LayerManagerOGL::CreateContext()
 
   if (!context) {
     NS_WARNING("Failed to create LayerManagerOGL context");
   }
   return context.forget();
 }
 
 bool
-LayerManagerOGL::Initialize(nsRefPtr<GLContext> aContext)
+LayerManagerOGL::Initialize(nsRefPtr<GLContext> aContext, bool force)
 {
-  ScopedGfxFeatureReporter reporter("GL Layers");
+  ScopedGfxFeatureReporter reporter("GL Layers", force);
 
   // Do not allow double intiailization
   NS_ABORT_IF_FALSE(mGLContext == nsnull, "Don't reiniailize layer managers");
 
   if (!aContext)
     return false;
 
   mGLContext = aContext;
--- a/gfx/layers/opengl/LayerManagerOGL.h
+++ b/gfx/layers/opengl/LayerManagerOGL.h
@@ -101,21 +101,21 @@ public:
   /**
    * Initializes the layer manager with a given GLContext. If aContext is null
    * then the layer manager will try to create one for the associated widget.
    *
    * \param aContext an existing GL context to use. Can be created with CreateContext()
    *
    * \return True is initialization was succesful, false when it was not.
    */
-  bool Initialize() {
-    return Initialize(CreateContext());
+  bool Initialize(bool force = false) {
+    return Initialize(CreateContext(), force);
   }
 
-  bool Initialize(nsRefPtr<GLContext> aContext);
+  bool Initialize(nsRefPtr<GLContext> aContext, bool force = false);
 
   /**
    * Sets the clipping region for this layer manager. This is important on 
    * windows because using OGL we no longer have GDI's native clipping. Therefor
    * widget must tell us what part of the screen is being invalidated,
    * and we should clip to this.
    *
    * \param aClippingRegion Region to clip to. Setting an empty region
--- a/gfx/src/gfxCrashReporterUtils.cpp
+++ b/gfx/src/gfxCrashReporterUtils.cpp
@@ -98,20 +98,19 @@ ScopedGfxFeatureReporter::WriteAppNote(c
     if (NS_FAILED(rv)) {
       observer = nsnull;
       return;
     }
     gFeaturesAlreadyReported = new nsTArray<nsCString>;
   }
 
   nsCAutoString featureString;
-  featureString.AppendPrintf("%s%c%c",
+  featureString.AppendPrintf("%s%c ",
                              mFeature,
-                             statusChar,
-                             statusChar == '?' ? ' ' : '\n');
+                             statusChar);
 
   if (!gFeaturesAlreadyReported->Contains(featureString)) {
     gFeaturesAlreadyReported->AppendElement(featureString);
     CrashReporter::AppendAppNotesToCrashReport(featureString);
   }
 }
 
 } // end namespace mozilla
--- a/gfx/src/gfxCrashReporterUtils.h
+++ b/gfx/src/gfxCrashReporterUtils.h
@@ -48,19 +48,20 @@ namespace mozilla {
   *
   * This ScopedGfxFeatureReporter class is designed to be fool-proof to use in functions that
   * have many exit points. We don't want to encourage having function with many exit points.
   * It just happens that our graphics features initialization functions are like that.
   */
 class NS_GFX ScopedGfxFeatureReporter
 {
 public:
-  ScopedGfxFeatureReporter(const char *aFeature) : mFeature(aFeature), mStatusChar('-')
+  ScopedGfxFeatureReporter(const char *aFeature, bool force = false)
+    : mFeature(aFeature), mStatusChar('-')
   {
-    WriteAppNote('?');
+    WriteAppNote(force ? '!' : '?');
   }
   ~ScopedGfxFeatureReporter() {
     WriteAppNote(mStatusChar);
   }
   void SetSuccessful() { mStatusChar = '+'; }
 
 protected:
   const char *mFeature;
--- a/gfx/thebes/gfxWindowsPlatform.cpp
+++ b/gfx/thebes/gfxWindowsPlatform.cpp
@@ -496,17 +496,17 @@ gfxWindowsPlatform::VerifyD2DDevice(bool
         ID3D10Device1 *device = cairo_d2d_device_get_device(mD2DDevice);
 
         if (SUCCEEDED(device->GetDeviceRemovedReason())) {
             return;
         }
         mD2DDevice = nsnull;
     }
 
-    mozilla::ScopedGfxFeatureReporter reporter("D2D");
+    mozilla::ScopedGfxFeatureReporter reporter("D2D", aAttemptForce);
 
     HMODULE d3d10module = LoadLibraryA("d3d10_1.dll");
     D3D10CreateDevice1Func createD3DDevice = (D3D10CreateDevice1Func)
         GetProcAddress(d3d10module, "D3D10CreateDevice1");
     nsRefPtr<ID3D10Device1> device;
 
     if (createD3DDevice) {
         HMODULE dxgiModule = LoadLibraryA("dxgi.dll");
--- a/js/public/MemoryMetrics.h
+++ b/js/public/MemoryMetrics.h
@@ -123,16 +123,17 @@ struct RuntimeStats
                  DestroyNameCallback destroyNameCb)
       : runtimeObject(0)
       , runtimeAtomsTable(0)
       , runtimeContexts(0)
       , runtimeNormal(0)
       , runtimeTemporary(0)
       , runtimeRegexpCode(0)
       , runtimeStackCommitted(0)
+      , runtimeGCMarker(0)
       , gcHeapChunkTotal(0)
       , gcHeapChunkCleanUnused(0)
       , gcHeapChunkDirtyUnused(0)
       , gcHeapChunkCleanDecommitted(0)
       , gcHeapChunkDirtyDecommitted(0)
       , gcHeapArenaUnused(0)
       , gcHeapChunkAdmin(0)
       , gcHeapUnusedPercentage(0)
@@ -154,16 +155,17 @@ struct RuntimeStats
 
     size_t runtimeObject;
     size_t runtimeAtomsTable;
     size_t runtimeContexts;
     size_t runtimeNormal;
     size_t runtimeTemporary;
     size_t runtimeRegexpCode;
     size_t runtimeStackCommitted;
+    size_t runtimeGCMarker;
     size_t gcHeapChunkTotal;
     size_t gcHeapChunkCleanUnused;
     size_t gcHeapChunkDirtyUnused;
     size_t gcHeapChunkCleanDecommitted;
     size_t gcHeapChunkDirtyDecommitted;
     size_t gcHeapArenaUnused;
     size_t gcHeapChunkAdmin;
     size_t gcHeapUnusedPercentage;
--- a/js/public/Vector.h
+++ b/js/public/Vector.h
@@ -494,16 +494,27 @@ class Vector : private AllocPolicy
      */
     bool insert(T *p, const T &val);
 
     /*
      * Removes the element |t|, which must fall in the bounds [begin, end),
      * shifting existing elements from |t + 1| onward one position lower.
      */
     void erase(T *t);
+
+    /*
+     * Measure the size of the Vector's heap-allocated storage.
+     */
+    size_t sizeOfExcludingThis(JSMallocSizeOfFun mallocSizeOf) const;
+
+    /* 
+     * Like sizeOfExcludingThis, but also measures the size of the Vector
+     * object (which must be heap-allocated) itself.
+     */
+    size_t sizeOfIncludingThis(JSMallocSizeOfFun mallocSizeOf) const;
 };
 
 /* This does the re-entrancy check plus several other sanity checks. */
 #define REENTRANCY_GUARD_ET_AL \
     ReentrancyGuard g(*this); \
     JS_ASSERT_IF(usingInlineStorage(), mCapacity == sInlineCapacity); \
     JS_ASSERT(reserved() <= mCapacity); \
     JS_ASSERT(mLength <= reserved()); \
@@ -991,15 +1002,29 @@ Vector<T,N,AP>::replaceRawBuffer(T *p, s
         mLength = length;
         mCapacity = length;
     }
 #ifdef DEBUG
     mReserved = length;
 #endif
 }
 
+template <class T, size_t N, class AP>
+inline size_t
+Vector<T,N,AP>::sizeOfExcludingThis(JSMallocSizeOfFun mallocSizeOf) const
+{
+    return usingInlineStorage() ? 0 : mallocSizeOf(beginNoCheck());
+}
+
+template <class T, size_t N, class AP>
+inline size_t
+Vector<T,N,AP>::sizeOfIncludingThis(JSMallocSizeOfFun mallocSizeOf) const
+{
+    return mallocSizeOf(this) + sizeOfExcludingThis(mallocSizeOf);
+}
+
 }  /* namespace js */
 
 #ifdef _MSC_VER
 #pragma warning(pop)
 #endif
 
 #endif /* jsvector_h_ */
--- a/js/src/MemoryMetrics.cpp
+++ b/js/src/MemoryMetrics.cpp
@@ -206,20 +206,19 @@ CollectRuntimeStats(JSRuntime *rt, Runti
         IterateChunks(cx, rtStats, StatsChunkCallback);
 
         rtStats->runtimeObject = rtStats->mallocSizeOf(rt);
 
         rt->sizeOfExcludingThis(rtStats->mallocSizeOf,
                                 &rtStats->runtimeNormal,
                                 &rtStats->runtimeTemporary,
                                 &rtStats->runtimeRegexpCode,
-                                &rtStats->runtimeStackCommitted);
+                                &rtStats->runtimeStackCommitted,
+                                &rtStats->runtimeGCMarker);
 
-        // Nb: we use sizeOfExcludingThis() because atomState.atoms is within
-        // JSRuntime, and so counted when JSRuntime is counted.
         rtStats->runtimeAtomsTable =
             rt->atomState.atoms.sizeOfExcludingThis(rtStats->mallocSizeOf);
 
         JSContext *acx, *iter = NULL;
         while ((acx = JS_ContextIteratorUnlocked(rt, &iter)) != NULL)
             rtStats->runtimeContexts += acx->sizeOfIncludingThis(rtStats->mallocSizeOf);
     }
 
@@ -330,17 +329,18 @@ GetExplicitNonHeapForRuntime(JSRuntime *
 
         // explicit/runtime/regexp-code
         // explicit/runtime/stack-committed
         size_t regexpCode, stackCommitted;
         rt->sizeOfExcludingThis(mallocSizeOf,
                                 NULL,
                                 NULL,
                                 &regexpCode,
-                                &stackCommitted);
+                                &stackCommitted,
+                                NULL);
 
         *amount += regexpCode;
         *amount += stackCommitted;
     }
 
     JS_DestroyContextNoGC(cx);
 
     return true;
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -238,16 +238,18 @@ UpdateDecomposeLength(BytecodeEmitter *b
     uintN end = bce->offset();
     JS_ASSERT(uintN(end - start) < 256);
     bce->code(start)[-1] = end - start;
 }
 
 ptrdiff_t
 frontend::Emit1(JSContext *cx, BytecodeEmitter *bce, JSOp op)
 {
+    JS_ASSERT_IF(op == JSOP_ARGUMENTS, !bce->mayOverwriteArguments());
+
     ptrdiff_t offset = EmitCheck(cx, bce, 1);
 
     if (offset >= 0) {
         *bce->current->next++ = (jsbytecode)op;
         UpdateDepth(cx, bce, offset);
     }
     return offset;
 }
@@ -978,16 +980,24 @@ EmitSlotObjectOp(JSContext *cx, JSOp op,
 
     jsbytecode *pc = bce->code(off);
     SET_SLOTNO(pc, slot);
     pc += SLOTNO_LEN;
     SET_UINT32_INDEX(pc, index);
     return true;
 }
 
+static bool
+EmitArguments(JSContext *cx, BytecodeEmitter *bce)
+{
+    if (!bce->mayOverwriteArguments())
+        return Emit1(cx, bce, JSOP_ARGUMENTS) >= 0;
+    return EmitAtomOp(cx, cx->runtime->atomState.argumentsAtom, JSOP_NAME, bce);
+}
+
 bool
 BytecodeEmitter::shouldNoteClosedName(ParseNode *pn)
 {
     return !callsEval() && pn->isDefn() && pn->isClosed();
 }
 
 /*
  * Adjust the slot for a block local to account for the number of variables
@@ -1828,17 +1838,20 @@ EmitNameOp(JSContext *cx, BytecodeEmitte
             op = JSOP_CALLFCSLOT;
             break;
           default:
             JS_ASSERT(op == JSOP_ARGUMENTS || op == JSOP_CALLEE);
             break;
         }
     }
 
-    if (op == JSOP_ARGUMENTS || op == JSOP_CALLEE) {
+    if (op == JSOP_ARGUMENTS) {
+        if (!EmitArguments(cx, bce))
+            return JS_FALSE;
+    } else if (op == JSOP_CALLEE) {
         if (Emit1(cx, bce, op) < 0)
             return JS_FALSE;
     } else {
         if (!pn->pn_cookie.isFree()) {
             JS_ASSERT(JOF_OPTYPE(op) != JOF_ATOM);
             EMIT_UINT16_IMM_OP(op, pn->pn_cookie.asInteger());
         } else {
             if (!EmitAtomOp(cx, pn, op, bce))
@@ -3584,17 +3597,17 @@ EmitVariables(JSContext *cx, BytecodeEmi
                                  (pn->isOp(JSOP_DEFCONST))
                                  ? SRC_DECL_CONST
                                  : (pn->isOp(JSOP_DEFVAR))
                                  ? SRC_DECL_VAR
                                  : SRC_DECL_LET) < 0) {
             return JS_FALSE;
         }
         if (op == JSOP_ARGUMENTS) {
-            if (Emit1(cx, bce, op) < 0)
+            if (!EmitArguments(cx, bce))
                 return JS_FALSE;
         } else if (!pn2->pn_cookie.isFree()) {
             EMIT_UINT16_IMM_OP(op, atomIndex);
         } else {
             if (!EmitIndexOp(cx, op, atomIndex, bce))
                 return false;
         }
 
@@ -3695,17 +3708,17 @@ EmitAssignment(JSContext *cx, BytecodeEm
     if (op != JSOP_NOP) {
         JS_ASSERT(rhs);
         switch (lhs->getKind()) {
           case PNK_NAME:
             if (lhs->isConst()) {
                 if (lhs->isOp(JSOP_CALLEE)) {
                     if (Emit1(cx, bce, JSOP_CALLEE) < 0)
                         return false;
-                } else if (lhs->isOp(JSOP_NAME)) {
+                } else if (lhs->isOp(JSOP_NAME) || lhs->isOp(JSOP_GETGNAME)) {
                     if (!EmitIndex32(cx, lhs->getOp(), atomIndex, bce))
                         return false;
                 } else {
                     JS_ASSERT(JOF_OPTYPE(lhs->getOp()) != JOF_ATOM);
                     EMIT_UINT16_IMM_OP(lhs->getOp(), atomIndex);
                 }
             } else if (lhs->isOp(JSOP_SETNAME)) {
                 if (Emit1(cx, bce, JSOP_DUP) < 0)
--- a/js/src/frontend/BytecodeEmitter.h
+++ b/js/src/frontend/BytecodeEmitter.h
@@ -163,31 +163,30 @@ struct StmtInfo {
 
 #define TCF_COMPILING           0x01 /* TreeContext is BytecodeEmitter */
 #define TCF_IN_FUNCTION         0x02 /* parsing inside function body */
 #define TCF_RETURN_EXPR         0x04 /* function has 'return expr;' */
 #define TCF_RETURN_VOID         0x08 /* function has 'return;' */
 #define TCF_IN_FOR_INIT         0x10 /* parsing init expr of for; exclude 'in' */
 #define TCF_FUN_SETS_OUTER_NAME 0x20 /* function set outer name (lexical or free) */
 #define TCF_FUN_PARAM_ARGUMENTS 0x40 /* function has parameter named arguments */
-#define TCF_FUN_USES_ARGUMENTS  0x80 /* function uses arguments except as a
+#define TCF_FUN_LOCAL_ARGUMENTS 0x80 /* function has local named arguments */
+#define TCF_FUN_USES_ARGUMENTS 0x100 /* function uses arguments except as a
                                         parameter name */
-#define TCF_FUN_HEAVYWEIGHT    0x100 /* function needs Call object per call */
-#define TCF_FUN_IS_GENERATOR   0x200 /* parsed yield statement in function */
-#define TCF_FUN_USES_OWN_NAME  0x400 /* named function expression that uses its
+#define TCF_FUN_HEAVYWEIGHT    0x200 /* function needs Call object per call */
+#define TCF_FUN_IS_GENERATOR   0x400 /* parsed yield statement in function */
+#define TCF_FUN_USES_OWN_NAME  0x800 /* named function expression that uses its
                                         own name */
-#define TCF_HAS_FUNCTION_STMT  0x800 /* block contains a function statement */
-#define TCF_GENEXP_LAMBDA     0x1000 /* flag lambda from generator expression */
-#define TCF_COMPILE_N_GO      0x2000 /* compile-and-go mode of script, can
+#define TCF_HAS_FUNCTION_STMT 0x1000 /* block contains a function statement */
+#define TCF_GENEXP_LAMBDA     0x2000 /* flag lambda from generator expression */
+#define TCF_COMPILE_N_GO      0x4000 /* compile-and-go mode of script, can
                                         optimize name references based on scope
                                         chain */
-#define TCF_NO_SCRIPT_RVAL    0x4000 /* API caller does not want result value
+#define TCF_NO_SCRIPT_RVAL    0x8000 /* API caller does not want result value
                                         from global script */
-/* bit 0x8000 is unused */
-
 /*
  * Set when parsing a declaration-like destructuring pattern.  This
  * flag causes PrimaryExpr to create PN_NAME parse nodes for variable
  * references which are not hooked into any definition's use chain,
  * added to any tree context's AtomList, etc. etc.  CheckDestructuring
  * will do that work later.
  *
  * The comments atop CheckDestructuring explain the distinction
@@ -268,16 +267,17 @@ struct StmtInfo {
 #define TCF_RETURN_FLAGS        (TCF_RETURN_EXPR | TCF_RETURN_VOID)
 
 /*
  * Sticky deoptimization flags to propagate from FunctionBody.
  */
 #define TCF_FUN_FLAGS           (TCF_FUN_SETS_OUTER_NAME |                    \
                                  TCF_FUN_USES_ARGUMENTS  |                    \
                                  TCF_FUN_PARAM_ARGUMENTS |                    \
+                                 TCF_FUN_LOCAL_ARGUMENTS |                    \
                                  TCF_FUN_HEAVYWEIGHT     |                    \
                                  TCF_FUN_IS_GENERATOR    |                    \
                                  TCF_FUN_USES_OWN_NAME   |                    \
                                  TCF_FUN_CALLS_EVAL      |                    \
                                  TCF_FUN_MIGHT_ALIAS_LOCALS |                 \
                                  TCF_FUN_MUTATES_PARAMETER |                  \
                                  TCF_STRICT_MODE_CODE    |                    \
                                  TCF_FUN_EXTENSIBLE_SCOPE)
@@ -429,16 +429,25 @@ struct TreeContext {                /* t
         flags |= TCF_FUN_MUTATES_PARAMETER;
     }
 
     bool mutatesParameter() const {
         JS_ASSERT(inFunction());
         return flags & TCF_FUN_MUTATES_PARAMETER;
     }
 
+    bool mayOverwriteArguments() const {
+        JS_ASSERT(inFunction());
+        JS_ASSERT_IF(inStrictMode(),
+                     !(flags & (TCF_FUN_PARAM_ARGUMENTS | TCF_FUN_LOCAL_ARGUMENTS)));
+        return !inStrictMode() &&
+               (callsEval() ||
+                flags & (TCF_FUN_PARAM_ARGUMENTS | TCF_FUN_LOCAL_ARGUMENTS));
+    }
+
     void noteArgumentsNameUse(ParseNode *node) {
         JS_ASSERT(inFunction());
         JS_ASSERT(node->isKind(PNK_NAME));
         JS_ASSERT(node->pn_atom == parser->context->runtime->atomState.argumentsAtom);
         countArgumentsUse(node);
         flags |= TCF_FUN_USES_ARGUMENTS;
         if (funbox)
             funbox->node->pn_dflags |= PND_FUNARG;
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -2426,17 +2426,17 @@ NoteLValue(JSContext *cx, ParseNode *pn,
      * depending on code strictness.  Assignment to arguments is a syntax error
      * in strict mode and thus cannot happen.  Outside strict mode, we optimize
      * away assignment to the function name.  For assignment to function name
      * to fail in strict mode, we must have a binding for it in the scope
      * chain; we ensure this happens by making such functions heavyweight.
      */
     JSAtom *lname = pn->pn_atom;
     if (lname == cx->runtime->atomState.argumentsAtom) {
-        tc->flags |= TCF_FUN_HEAVYWEIGHT;
+        tc->flags |= (TCF_FUN_HEAVYWEIGHT | TCF_FUN_LOCAL_ARGUMENTS);
         tc->countArgumentsUse(pn);
     } else if (tc->inFunction() && lname == tc->fun()->atom) {
         tc->flags |= TCF_FUN_HEAVYWEIGHT;
     }
 }
 
 #if JS_HAS_DESTRUCTURING
 
@@ -2448,17 +2448,17 @@ BindDestructuringVar(JSContext *cx, Bind
     /*
      * Destructuring is a form of assignment, so just as for an initialized
      * simple variable, we must check for assignment to 'arguments' and flag
      * the enclosing function (if any) as heavyweight.
      */
     JS_ASSERT(pn->isKind(PNK_NAME));
     atom = pn->pn_atom;
     if (atom == cx->runtime->atomState.argumentsAtom)
-        tc->flags |= TCF_FUN_HEAVYWEIGHT;
+        tc->flags |= (TCF_FUN_HEAVYWEIGHT | TCF_FUN_LOCAL_ARGUMENTS);
 
     data->pn = pn;
     if (!data->binder(cx, data, atom, tc))
         return JS_FALSE;
 
     /*
      * Select the appropriate name-setting opcode, respecting eager selection
      * done by the data->binder function.
@@ -4419,17 +4419,17 @@ Parser::variables(ParseNodeKind kind, St
             NoteLValue(context, pn2, tc, data.fresh ? PND_INITIALIZED : PND_ASSIGNED);
 
             /* The declarator's position must include the initializer. */
             pn2->pn_pos.end = init->pn_pos.end;
 
             if (tc->inFunction() && name == context->runtime->atomState.argumentsAtom) {
                 tc->noteArgumentsNameUse(pn2);
                 if (!blockObj)
-                    tc->flags |= TCF_FUN_HEAVYWEIGHT;
+                    tc->flags |= (TCF_FUN_HEAVYWEIGHT | TCF_FUN_LOCAL_ARGUMENTS);
             }
         }
     } while (tokenStream.matchToken(TOK_COMMA));
 
     pn->pn_pos.end = pn->last()->pn_pos.end;
     return pn;
 }
 
--- a/js/src/frontend/TokenStream.cpp
+++ b/js/src/frontend/TokenStream.cpp
@@ -173,18 +173,18 @@ TokenStream::init(const jschar *base, si
     version = v;
     xml = VersionHasXML(v);
 
     userbuf.init(base, length);
     linebase = base;
     prevLinebase = NULL;
     sourceMap = NULL;
 
-    JSSourceHandler listener = cx->debugHooks->sourceHandler;
-    void *listenerData = cx->debugHooks->sourceHandlerData;
+    JSSourceHandler listener = cx->runtime->debugHooks.sourceHandler;
+    void *listenerData = cx->runtime->debugHooks.sourceHandlerData;
 
     if (listener)
         listener(fn, ln, base, length, &listenerTSData, listenerData);
 
     /*
      * This table holds all the token kinds that satisfy these properties:
      * - A single char long.
      * - Cannot be a prefix of any longer token (eg. '+' is excluded because
@@ -516,18 +516,18 @@ TokenStream::reportCompileErrorNumberVA(
      * uncaught exception report.
      */
     if (!js_ErrorToException(cx, message, &report, NULL, NULL)) {
         /*
          * If debugErrorHook is present then we give it a chance to veto
          * sending the error on to the regular error reporter.
          */
         bool reportError = true;
-        if (JSDebugErrorHook hook = cx->debugHooks->debugErrorHook)
-            reportError = hook(cx, message, &report, cx->debugHooks->debugErrorHookData);
+        if (JSDebugErrorHook hook = cx->runtime->debugHooks.debugErrorHook)
+            reportError = hook(cx, message, &report, cx->runtime->debugHooks.debugErrorHookData);
 
         /* Report the error */
         if (reportError && cx->errorReporter)
             cx->errorReporter(cx, message, &report);
     }
 
   out:
     if (linebytes)
--- a/js/src/gc/Barrier-inl.h
+++ b/js/src/gc/Barrier-inl.h
@@ -41,58 +41,69 @@
 
 #include "gc/Barrier.h"
 
 #ifndef jsgc_barrier_inl_h___
 #define jsgc_barrier_inl_h___
 
 namespace js {
 
-static JS_ALWAYS_INLINE void
-ClearValueRange(JSCompartment *comp, HeapValue *vec, uintN len, bool useHoles)
+inline void
+EncapsulatedValue::writeBarrierPre(const Value &value)
 {
-    if (useHoles) {
-        for (uintN i = 0; i < len; i++)
-            vec[i].set(comp, MagicValue(JS_ARRAY_HOLE));
-    } else {
-        for (uintN i = 0; i < len; i++)
-            vec[i].set(comp, UndefinedValue());
+#ifdef JSGC_INCREMENTAL
+    if (value.isMarkable()) {
+        js::gc::Cell *cell = (js::gc::Cell *)value.toGCThing();
+        writeBarrierPre(cell->compartment(), value);
     }
+#endif
 }
 
-static JS_ALWAYS_INLINE void
-InitValueRange(HeapValue *vec, uintN len, bool useHoles)
+inline void
+EncapsulatedValue::writeBarrierPre(JSCompartment *comp, const Value &value)
 {
-    if (useHoles) {
-        for (uintN i = 0; i < len; i++)
-            vec[i].init(MagicValue(JS_ARRAY_HOLE));
-    } else {
-        for (uintN i = 0; i < len; i++)
-            vec[i].init(UndefinedValue());
+#ifdef JSGC_INCREMENTAL
+    if (comp->needsBarrier()) {
+        Value tmp(value);
+        js::gc::MarkValueUnbarriered(comp->barrierTracer(), &tmp, "write barrier");
+        JS_ASSERT(tmp == value);
     }
+#endif
 }
 
-static JS_ALWAYS_INLINE void
-DestroyValueRange(HeapValue *vec, uintN len)
+inline void
+EncapsulatedValue::pre()
+{
+    writeBarrierPre(value);
+}
+
+inline void
+EncapsulatedValue::pre(JSCompartment *comp)
 {
-    for (uintN i = 0; i < len; i++)
-        vec[i].~HeapValue();
+    writeBarrierPre(comp, value);
+}
+
+inline
+HeapValue::HeapValue()
+    : EncapsulatedValue(UndefinedValue())
+{
+    post();
 }
 
 inline
 HeapValue::HeapValue(const Value &v)
-    : value(v)
+    : EncapsulatedValue(v)
 {
     JS_ASSERT(!IsPoisonedValue(v));
     post();
 }
 
 inline
 HeapValue::HeapValue(const HeapValue &v)
-    : value(v.value)
+    : EncapsulatedValue(v.value)
 {
     JS_ASSERT(!IsPoisonedValue(v.value));
     post();
 }
 
 inline
 HeapValue::~HeapValue()
 {
@@ -109,71 +120,16 @@ HeapValue::init(const Value &v)
 
 inline void
 HeapValue::init(JSCompartment *comp, const Value &v)
 {
     value = v;
     post(comp);
 }
 
-inline void
-HeapValue::writeBarrierPre(const Value &value)
-{
-#ifdef JSGC_INCREMENTAL
-    if (value.isMarkable()) {
-        js::gc::Cell *cell = (js::gc::Cell *)value.toGCThing();
-        writeBarrierPre(cell->compartment(), value);
-    }
-#endif
-}
-
-inline void
-HeapValue::writeBarrierPost(const Value &value, void *addr)
-{
-}
-
-inline void
-HeapValue::writeBarrierPre(JSCompartment *comp, const Value &value)
-{
-#ifdef JSGC_INCREMENTAL
-    if (comp->needsBarrier()) {
-        Value tmp(value);
-        js::gc::MarkValueUnbarriered(comp->barrierTracer(), &tmp, "write barrier");
-        JS_ASSERT(tmp == value);
-    }
-#endif
-}
-
-inline void
-HeapValue::writeBarrierPost(JSCompartment *comp, const Value &value, void *addr)
-{
-}
-
-inline void
-HeapValue::pre()
-{
-    writeBarrierPre(value);
-}
-
-inline void
-HeapValue::post()
-{
-}
-
-inline void
-HeapValue::pre(JSCompartment *comp)
-{
-    writeBarrierPre(comp, value);
-}
-
-inline void
-HeapValue::post(JSCompartment *comp)
-{
-}
-
 inline HeapValue &
 HeapValue::operator=(const Value &v)
 {
     pre();
     JS_ASSERT(!IsPoisonedValue(v));
     value = v;
     post();
     return *this;
@@ -201,16 +157,119 @@ HeapValue::set(JSCompartment *comp, cons
 #endif
 
     pre(comp);
     JS_ASSERT(!IsPoisonedValue(v));
     value = v;
     post(comp);
 }
 
+inline void
+HeapValue::writeBarrierPost(const Value &value, void *addr)
+{
+}
+
+inline void
+HeapValue::writeBarrierPost(JSCompartment *comp, const Value &value, void *addr)
+{
+}
+
+inline void
+HeapValue::post()
+{
+}
+
+inline void
+HeapValue::post(JSCompartment *comp)
+{
+}
+
+inline
+HeapSlot::HeapSlot(JSObject *obj, uint32_t slot, const Value &v)
+    : EncapsulatedValue(v)
+{
+    JS_ASSERT(!IsPoisonedValue(v));
+    post(obj, slot);
+}
+
+inline
+HeapSlot::HeapSlot(JSObject *obj, uint32_t slot, const HeapSlot &s)
+    : EncapsulatedValue(s.value)
+{
+    JS_ASSERT(!IsPoisonedValue(s.value));
+    post(obj, slot);
+}
+
+inline
+HeapSlot::~HeapSlot()
+{
+    pre();
+}
+
+inline void
+HeapSlot::init(JSObject *obj, uint32_t slot, const Value &v)
+{
+    value = v;
+    post(obj, slot);
+}
+
+inline void
+HeapSlot::init(JSCompartment *comp, JSObject *obj, uint32_t slot, const Value &v)
+{
+    value = v;
+    post(comp, obj, slot);
+}
+
+inline void
+HeapSlot::set(JSObject *obj, uint32_t slot, const Value &v)
+{
+    JS_ASSERT_IF(!obj->isArray(), &obj->getSlotRef(slot) == this);
+    JS_ASSERT_IF(obj->isDenseArray(), &obj->getDenseArrayElement(slot) == (const Value *)this);
+
+    pre();
+    JS_ASSERT(!IsPoisonedValue(v));
+    value = v;
+    post(obj, slot);
+}
+
+inline void
+HeapSlot::set(JSCompartment *comp, JSObject *obj, uint32_t slot, const Value &v)
+{
+    JS_ASSERT_IF(!obj->isArray(), &const_cast<JSObject *>(obj)->getSlotRef(slot) == this);
+    JS_ASSERT_IF(obj->isDenseArray(), &obj->getDenseArrayElement(slot) == (const Value *)this);
+    JS_ASSERT(obj->compartment() == comp);
+
+    pre(comp);
+    JS_ASSERT(!IsPoisonedValue(v));
+    value = v;
+    post(comp, obj, slot);
+}
+
+inline void
+HeapSlot::writeBarrierPost(JSObject *obj, uint32_t slot)
+{
+}
+
+inline void
+HeapSlot::writeBarrierPost(JSCompartment *comp, JSObject *obj, uint32_t slotno)
+{
+}
+
+inline void
+HeapSlot::post(JSObject *owner, uint32_t slot)
+{
+    HeapSlot::writeBarrierPost(owner, slot);
+}
+
+inline void
+HeapSlot::post(JSCompartment *comp, JSObject *owner, uint32_t slot)
+{
+    HeapSlot::writeBarrierPost(comp, owner, slot);
+}
+
 inline
 HeapId::HeapId(jsid id)
     : value(id)
 {
     JS_ASSERT(!IsPoisonedId(id));
     post();
 }
 
--- a/js/src/gc/Barrier.h
+++ b/js/src/gc/Barrier.h
@@ -294,41 +294,34 @@ struct HeapPtrHasher
     static HashNumber hash(Lookup obj) { return DefaultHasher<T *>::hash(obj); }
     static bool match(const Key &k, Lookup l) { return k.get() == l; }
 };
 
 /* Specialized hashing policy for HeapPtrs. */
 template <class T>
 struct DefaultHasher< HeapPtr<T> >: HeapPtrHasher<T> { };
 
-class HeapValue
+class EncapsulatedValue
 {
+  protected:
     Value value;
 
+    /*
+     * Ensure that EncapsulatedValue is not constructable, except by our
+     * implementations.
+     */
+    EncapsulatedValue() MOZ_DELETE;
+    EncapsulatedValue(const EncapsulatedValue &v) MOZ_DELETE;
+    EncapsulatedValue &operator=(const Value &v) MOZ_DELETE;
+    EncapsulatedValue &operator=(const EncapsulatedValue &v) MOZ_DELETE;
+
+    EncapsulatedValue(const Value &v) : value(v) {}
+    ~EncapsulatedValue() {}
+
   public:
-    explicit HeapValue() : value(UndefinedValue()) {}
-    explicit inline HeapValue(const Value &v);
-    explicit inline HeapValue(const HeapValue &v);
-
-    inline ~HeapValue();
-
-    inline void init(const Value &v);
-    inline void init(JSCompartment *comp, const Value &v);
-
-    inline HeapValue &operator=(const Value &v);
-    inline HeapValue &operator=(const HeapValue &v);
-
-    /*
-     * This is a faster version of operator=. Normally, operator= has to
-     * determine the compartment of the value before it can decide whether to do
-     * the barrier. If you already know the compartment, it's faster to pass it
-     * in.
-     */
-    inline void set(JSCompartment *comp, const Value &v);
-
     const Value &get() const { return value; }
     Value *unsafeGet() { return &value; }
     operator const Value &() const { return value; }
 
     bool isUndefined() const { return value.isUndefined(); }
     bool isNull() const { return value.isNull(); }
     bool isBoolean() const { return value.isBoolean(); }
     bool isTrue() const { return value.isTrue(); }
@@ -355,48 +348,103 @@ class HeapValue
 
     uint64_t asRawBits() const { return value.asRawBits(); }
 
 #ifdef DEBUG
     JSWhyMagic whyMagic() const { return value.whyMagic(); }
 #endif
 
     static inline void writeBarrierPre(const Value &v);
-    static inline void writeBarrierPost(const Value &v, void *addr);
+    static inline void writeBarrierPre(JSCompartment *comp, const Value &v);
+
+  protected:
+    inline void pre();
+    inline void pre(JSCompartment *comp);
+};
+
+class HeapValue : public EncapsulatedValue
+{
+  public:
+    explicit inline HeapValue();
+    explicit inline HeapValue(const Value &v);
+    explicit inline HeapValue(const HeapValue &v);
+    inline ~HeapValue();
 
-    static inline void writeBarrierPre(JSCompartment *comp, const Value &v);
+    inline void init(const Value &v);
+    inline void init(JSCompartment *comp, const Value &v);
+
+    inline HeapValue &operator=(const Value &v);
+    inline HeapValue &operator=(const HeapValue &v);
+
+    /*
+     * This is a faster version of operator=. Normally, operator= has to
+     * determine the compartment of the value before it can decide whether to do
+     * the barrier. If you already know the compartment, it's faster to pass it
+     * in.
+     */
+    inline void set(JSCompartment *comp, const Value &v);
+
+    static inline void writeBarrierPost(const Value &v, void *addr);
     static inline void writeBarrierPost(JSCompartment *comp, const Value &v, void *addr);
 
   private:
-    inline void pre();
     inline void post();
+    inline void post(JSCompartment *comp);
+};
+
+class HeapSlot : public EncapsulatedValue
+{
+    /*
+     * Operator= is not valid for HeapSlot because is must take the object and
+     * slot offset to provide to the post/generational barrier.
+     */
+    inline HeapSlot &operator=(const Value &v) MOZ_DELETE;
+    inline HeapSlot &operator=(const HeapValue &v) MOZ_DELETE;
+    inline HeapSlot &operator=(const HeapSlot &v) MOZ_DELETE;
 
-    inline void pre(JSCompartment *comp);
-    inline void post(JSCompartment *comp);
+  public:
+    explicit inline HeapSlot() MOZ_DELETE;
+    explicit inline HeapSlot(JSObject *obj, uint32_t slot, const Value &v);
+    explicit inline HeapSlot(JSObject *obj, uint32_t slot, const HeapSlot &v);
+    inline ~HeapSlot();
+
+    inline void init(JSObject *owner, uint32_t slot, const Value &v);
+    inline void init(JSCompartment *comp, JSObject *owner, uint32_t slot, const Value &v);
+
+    inline void set(JSObject *owner, uint32_t slot, const Value &v);
+    inline void set(JSCompartment *comp, JSObject *owner, uint32_t slot, const Value &v);
+
+    static inline void writeBarrierPost(JSObject *obj, uint32_t slot);
+    static inline void writeBarrierPost(JSCompartment *comp, JSObject *obj, uint32_t slotno);
+
+  private:
+    inline void post(JSObject *owner, uint32_t slot);
+    inline void post(JSCompartment *comp, JSObject *owner, uint32_t slot);
 };
 
 static inline const Value *
-Valueify(const HeapValue *array)
+Valueify(const EncapsulatedValue *array)
 {
-    JS_ASSERT(sizeof(HeapValue) == sizeof(Value));
+    JS_STATIC_ASSERT(sizeof(HeapValue) == sizeof(Value));
+    JS_STATIC_ASSERT(sizeof(HeapSlot) == sizeof(Value));
     return (const Value *)array;
 }
 
-class HeapValueArray
+class HeapSlotArray
 {
-    HeapValue *array;
+    HeapSlot *array;
 
   public:
-    HeapValueArray(HeapValue *array) : array(array) {}
+    HeapSlotArray(HeapSlot *array) : array(array) {}
 
     operator const Value *() const { return Valueify(array); }
-    operator HeapValue *() const { return array; }
+    operator HeapSlot *() const { return array; }
 
-    HeapValueArray operator +(int offset) const { return HeapValueArray(array + offset); }
-    HeapValueArray operator +(uint32_t offset) const { return HeapValueArray(array + offset); }
+    HeapSlotArray operator +(int offset) const { return HeapSlotArray(array + offset); }
+    HeapSlotArray operator +(uint32_t offset) const { return HeapSlotArray(array + offset); }
 };
 
 class HeapId
 {
     jsid value;
 
   public:
     explicit HeapId() : value(JSID_VOID) {}
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/basic/testOverwrittenArgumentsWithUndefined.js
@@ -0,0 +1,24 @@
+function f() {
+    var a = arguments;
+    eval("assertEq(arguments[0], 42)");
+    eval("assertEq(arguments, a)");
+    arguments = undefined;
+    eval("assertEq(arguments, undefined)");
+    arguments = a;
+    eval("assertEq(arguments[0], 42)");
+    eval("assertEq(arguments, a)");
+}
+f(42);
+
+function f(z) {
+    var a = arguments;
+    eval("assertEq(arguments[0], 42)");
+    eval("assertEq(arguments, a)");
+    arguments = undefined;
+    eval("assertEq(arguments, undefined)");
+    z = 17;
+    eval("assertEq(a[0], 17)");
+    a[0] = 'ponies';
+    eval("assertEq(z, 'ponies')");
+}
+f(42);
--- a/js/src/jsapi-tests/testDebugger.cpp
+++ b/js/src/jsapi-tests/testDebugger.cpp
@@ -105,45 +105,43 @@ BEGIN_TEST(testDebugger_getThisStrict)
 }
 END_TEST(testDebugger_getThisStrict)
 
 bool called = false;
 
 static JSTrapStatus
 ThrowHook(JSContext *cx, JSScript *, jsbytecode *, jsval *rval, void *closure)
 {
+    JS_ASSERT(!closure);
     called = true;
 
     JSObject *global = JS_GetGlobalForScopeChain(cx);
 
     char text[] = "new Error()";
     jsval _;
     JS_EvaluateScript(cx, global, text, strlen(text), "", 0, &_);
 
     return JSTRAP_CONTINUE;
 }
 
 BEGIN_TEST(testDebugger_throwHook)
 {
     uint32_t newopts = JS_GetOptions(cx) | JSOPTION_METHODJIT | JSOPTION_METHODJIT_ALWAYS;
     uint32_t oldopts = JS_SetOptions(cx, newopts);
 
-    JSDebugHooks hooks = { 0 };
-    hooks.throwHook = ThrowHook;
-    JSDebugHooks *old = JS_SetContextDebugHooks(cx, &hooks);
+    CHECK(JS_SetThrowHook(rt, ThrowHook, NULL));
     EXEC("function foo() { throw 3 };\n"
          "for (var i = 0; i < 10; ++i) { \n"
          "  var x = <tag></tag>;\n"
          "  try {\n"
          "    foo(); \n"
          "  } catch(e) {}\n"
          "}\n");
     CHECK(called);
-
-    JS_SetContextDebugHooks(cx, old);
+    CHECK(JS_SetThrowHook(rt, NULL, NULL));
     JS_SetOptions(cx, oldopts);
     return true;
 }
 END_TEST(testDebugger_throwHook)
 
 BEGIN_TEST(testDebugger_debuggerObjectVsDebugMode)
 {
     CHECK(JS_DefineDebuggerObject(cx, global));
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -795,17 +795,17 @@ JSRuntime::JSRuntime()
 #endif
     inOOMReport(0),
     jitHardening(false)
 {
     /* Initialize infallibly first, so we can goto bad and JS_DestroyRuntime. */
     JS_INIT_CLIST(&contextList);
     JS_INIT_CLIST(&debuggerList);
 
-    PodZero(&globalDebugHooks);
+    PodZero(&debugHooks);
     PodZero(&atomState);
 
 #if JS_STACK_GROWTH_DIRECTION > 0
     nativeStackLimit = UINTPTR_MAX;
 #endif
 }
 
 bool
--- a/js/src/jsarray.cpp
+++ b/js/src/jsarray.cpp
@@ -1189,17 +1189,17 @@ array_deleteSpecial(JSContext *cx, JSObj
 }
 
 static void
 array_trace(JSTracer *trc, JSObject *obj)
 {
     JS_ASSERT(obj->isDenseArray());
 
     uint32_t initLength = obj->getDenseArrayInitializedLength();
-    MarkValueRange(trc, initLength, obj->getDenseArrayElements(), "element");
+    MarkSlotRange(trc, initLength, obj->getDenseArrayElements(), "element");
 }
 
 static JSBool
 array_fix(JSContext *cx, JSObject *obj, bool *success, AutoIdVector *props)
 {
     JS_ASSERT(obj->isDenseArray());
 
     /*
@@ -1372,29 +1372,30 @@ JSObject::makeDenseArraySlow(JSContext *
     gc::AllocKind kind = getAllocKind();
     Shape *shape = EmptyShape::getInitialShape(cx, &SlowArrayClass, getProto(),
                                                oldShape->getObjectParent(), kind);
     if (!shape)
         return false;
     this->shape_ = shape;
 
     /* Take ownership of the dense elements, reset to an empty dense array. */
-    HeapValue *elems = elements;
+    HeapSlot *elems = elements;
     elements = emptyObjectElements;
 
     /* Root all values in the array during conversion. */
     AutoValueArray autoArray(cx, (Value *) elems, arrayInitialized);
 
     /*
      * Begin with the length property to share more of the property tree.
      * The getter/setter here will directly access the object's private value.
      */
     if (!AddLengthProperty(cx, this)) {
         this->shape_ = oldShape;
-        cx->free_(getElementsHeader());
+        if (elements != emptyObjectElements)
+            cx->free_(getElementsHeader());
         elements = elems;
         return false;
     }
 
     /*
      * Create new properties pointing to existing elements. Pack the array to
      * remove holes, so that shapes use successive slots (as for other objects).
      */
--- a/js/src/jsarrayinlines.h
+++ b/js/src/jsarrayinlines.h
@@ -59,17 +59,22 @@ JSObject::ensureDenseArrayInitializedLen
      * for a write.
      */
     JS_ASSERT(index + extra <= getDenseArrayCapacity());
     uint32_t &initlen = getElementsHeader()->initializedLength;
     if (initlen < index)
         markDenseArrayNotPacked(cx);
 
     if (initlen < index + extra) {
-        js::InitValueRange(elements + initlen, index + extra - initlen, true);
+        JSCompartment *comp = compartment();
+        size_t offset = initlen;
+        for (js::HeapSlot *sp = elements + initlen;
+             sp != elements + (index + extra);
+             sp++, offset++)
+            sp->init(comp, this, offset, js::MagicValue(JS_ARRAY_HOLE));
         initlen = index + extra;
     }
 }
 
 inline JSObject::EnsureDenseResult
 JSObject::ensureDenseArrayElements(JSContext *cx, uintN index, uintN extra)
 {
     JS_ASSERT(isDenseArray());
--- a/js/src/jscntxt.cpp
+++ b/js/src/jscntxt.cpp
@@ -90,17 +90,17 @@
 #include "jscompartment.h"
 #include "jsobjinlines.h"
 
 using namespace js;
 using namespace js::gc;
 
 void
 JSRuntime::sizeOfExcludingThis(JSMallocSizeOfFun mallocSizeOf, size_t *normal, size_t *temporary,
-                               size_t *regexpCode, size_t *stackCommitted)
+                               size_t *regexpCode, size_t *stackCommitted, size_t *gcMarkerSize)
 {
     if (normal)
         *normal = mallocSizeOf(dtoaState);
 
     if (temporary)
         *temporary = tempLifoAlloc.sizeOfExcludingThis(mallocSizeOf);
 
     if (regexpCode) {
@@ -108,16 +108,19 @@ JSRuntime::sizeOfExcludingThis(JSMallocS
         if (execAlloc_)
             execAlloc_->sizeOfCode(&method, &regexp, &unused);
         JS_ASSERT(method == 0);     /* this execAlloc is only used for regexp code */
         *regexpCode = regexp + unused;
     }
 
     if (stackCommitted)
         *stackCommitted = stackSpace.sizeOfCommitted();
+
+    if (gcMarkerSize)
+        *gcMarkerSize = gcMarker.sizeOfExcludingThis(mallocSizeOf);
 }
 
 JS_FRIEND_API(void)
 JSRuntime::triggerOperationCallback()
 {
     /*
      * Use JS_ATOMIC_SET in the hope that it ensures the write will become
      * immediately visible to other processors polling the flag.
@@ -351,21 +354,19 @@ ReportError(JSContext *cx, const char *m
      * If an exception was raised, then we call the debugErrorHook
      * (if present) to give it a chance to see the error before it
      * propagates out of scope.  This is needed for compatibility
      * with the old scheme.
      */
     if (!JS_IsRunning(cx) ||
         !js_ErrorToException(cx, message, reportp, callback, userRef)) {
         js_ReportErrorAgain(cx, message, reportp);
-    } else if (cx->debugHooks->debugErrorHook && cx->errorReporter) {
-        JSDebugErrorHook hook = cx->debugHooks->debugErrorHook;
-        /* test local in case debugErrorHook changed on another thread */
-        if (hook)
-            hook(cx, message, reportp, cx->debugHooks->debugErrorHookData);
+    } else if (JSDebugErrorHook hook = cx->runtime->debugHooks.debugErrorHook) {
+        if (cx->errorReporter)
+            hook(cx, message, reportp, cx->runtime->debugHooks.debugErrorHookData);
     }
 }
 
 /*
  * The given JSErrorReport object have been zeroed and must not outlive
  * cx->fp() (otherwise report->originPrincipals may become invalid).
  */
 static void
@@ -414,19 +415,19 @@ js_ReportOutOfMemory(JSContext *cx)
     /*
      * If debugErrorHook is present then we give it a chance to veto sending
      * the error on to the regular ErrorReporter. We also clear a pending
      * exception if any now so the hooks can replace the out-of-memory error
      * by a script-catchable exception.
      */
     cx->clearPendingException();
     if (onError) {
-        JSDebugErrorHook hook = cx->debugHooks->debugErrorHook;
+        JSDebugErrorHook hook = cx->runtime->debugHooks.debugErrorHook;
         if (hook &&
-            !hook(cx, msg, &report, cx->debugHooks->debugErrorHookData)) {
+            !hook(cx, msg, &report, cx->runtime->debugHooks.debugErrorHookData)) {
             onError = NULL;
         }
     }
 
     if (onError) {
         AutoAtomicIncrement incr(&cx->runtime->inOOMReport);
         onError(cx, msg, &report);
     }
@@ -746,22 +747,19 @@ js_ReportErrorAgain(JSContext *cx, const
         return;
     onError = cx->errorReporter;
 
     /*
      * If debugErrorHook is present then we give it a chance to veto
      * sending the error on to the regular ErrorReporter.
      */
     if (onError) {
-        JSDebugErrorHook hook = cx->debugHooks->debugErrorHook;
-        if (hook &&
-            !hook(cx, cx->lastMessage, reportp,
-                  cx->debugHooks->debugErrorHookData)) {
+        JSDebugErrorHook hook = cx->runtime->debugHooks.debugErrorHook;
+        if (hook && !hook(cx, cx->lastMessage, reportp, cx->runtime->debugHooks.debugErrorHookData))
             onError = NULL;
-        }
     }
     if (onError)
         onError(cx, cx->lastMessage, reportp);
 }
 
 void
 js_ReportIsNotDefined(JSContext *cx, const char *name)
 {
@@ -976,17 +974,16 @@ JSContext::JSContext(JSRuntime *rt)
     errorReporter(NULL),
     operationCallback(NULL),
     data(NULL),
     data2(NULL),
 #ifdef JS_THREADSAFE
     outstandingRequests(0),
 #endif
     autoGCRooters(NULL),
-    debugHooks(&rt->globalDebugHooks),
     securityCallbacks(NULL),
     resolveFlags(0),
     rngSeed(0),
     iterValue(MagicValue(JS_NO_ITER_VALUE)),
 #ifdef JS_METHODJIT
     methodJitEnabled(false),
 #endif
     inferenceEnabled(false),
--- a/js/src/jscntxt.h
+++ b/js/src/jscntxt.h
@@ -470,17 +470,17 @@ struct JSRuntime : js::RuntimeFriendFiel
     /* List of active contexts sharing this runtime. */
     JSCList             contextList;
 
     bool hasContexts() const {
         return !JS_CLIST_IS_EMPTY(&contextList);
     }
 
     /* Per runtime debug hooks -- see jsprvtd.h and jsdbgapi.h. */
-    JSDebugHooks        globalDebugHooks;
+    JSDebugHooks        debugHooks;
 
     /* If true, new compartments are initially in debug mode. */
     bool                debugMode;
 
     /* If true, new scripts must be created with PC counter information. */
     bool                profilingScripts;
 
     /* Had an out-of-memory error which did not populate an exception. */
@@ -684,17 +684,17 @@ struct JSRuntime : js::RuntimeFriendFiel
     JS_FRIEND_API(void) triggerOperationCallback();
 
     void setJitHardening(bool enabled);
     bool getJitHardening() const {
         return jitHardening;
     }
 
     void sizeOfExcludingThis(JSMallocSizeOfFun mallocSizeOf, size_t *normal, size_t *temporary,
-                             size_t *regexpCode, size_t *stackCommitted);
+                             size_t *regexpCode, size_t *stackCommitted, size_t *gcMarker);
 
     void purge(JSContext *cx);
 };
 
 /* Common macros to access thread-local caches in JSRuntime. */
 #define JS_PROPERTY_CACHE(cx)   (cx->runtime->propertyCache)
 
 #define JS_KEEP_ATOMS(rt)   (rt)->gcKeepAtoms++;
@@ -709,18 +709,16 @@ struct JSRuntime : js::RuntimeFriendFiel
 struct JSArgumentFormatMap {
     const char          *format;
     size_t              length;
     JSArgumentFormatter formatter;
     JSArgumentFormatMap *next;
 };
 #endif
 
-extern const JSDebugHooks js_NullDebugHooks;  /* defined in jsdbgapi.cpp */
-
 namespace js {
 
 template <typename T> class Root;
 class CheckRoot;
 
 struct AutoResolving;
 
 static inline bool
@@ -1010,19 +1008,16 @@ struct JSContext : js::ContextFriendFiel
      * location as holding a relocatable pointer, but have no other effect on
      * GC behavior.
      */
     js::CheckRoot *checkGCRooters;
 #endif
 
 #endif /* JSGC_ROOT_ANALYSIS */
 
-    /* Debug hooks associated with the current context. */
-    const JSDebugHooks  *debugHooks;
-
     /* Security callbacks that override any defined on the runtime. */
     JSSecurityCallbacks *securityCallbacks;
 
     /* Stored here to avoid passing it around as a parameter. */
     uintN               resolveFlags;
 
     /* Random number generator state, used by jsmath.cpp. */
     int64_t             rngSeed;
--- a/js/src/jsdbgapi.cpp
+++ b/js/src/jsdbgapi.cpp
@@ -108,21 +108,21 @@ JS_SetRuntimeDebugMode(JSRuntime *rt, JS
 namespace js {
 
 JSTrapStatus
 ScriptDebugPrologue(JSContext *cx, StackFrame *fp)
 {
     JS_ASSERT(fp == cx->fp());
 
     if (fp->isFramePushedByExecute()) {
-        if (JSInterpreterHook hook = cx->debugHooks->executeHook)
-            fp->setHookData(hook(cx, Jsvalify(fp), true, 0, cx->debugHooks->executeHookData));
+        if (JSInterpreterHook hook = cx->runtime->debugHooks.executeHook)
+            fp->setHookData(hook(cx, Jsvalify(fp), true, 0, cx->runtime->debugHooks.executeHookData));
     } else {
-        if (JSInterpreterHook hook = cx->debugHooks->callHook)
-            fp->setHookData(hook(cx, Jsvalify(fp), true, 0, cx->debugHooks->callHookData));
+        if (JSInterpreterHook hook = cx->runtime->debugHooks.callHook)
+            fp->setHookData(hook(cx, Jsvalify(fp), true, 0, cx->runtime->debugHooks.callHookData));
     }
 
     Value rval;
     JSTrapStatus status = Debugger::onEnterFrame(cx, &rval);
     switch (status) {
       case JSTRAP_CONTINUE:
         break;
       case JSTRAP_THROW:
@@ -143,20 +143,20 @@ ScriptDebugPrologue(JSContext *cx, Stack
 bool
 ScriptDebugEpilogue(JSContext *cx, StackFrame *fp, bool okArg)
 {
     JS_ASSERT(fp == cx->fp());
     JSBool ok = okArg;
 
     if (void *hookData = fp->maybeHookData()) {
         if (fp->isFramePushedByExecute()) {
-            if (JSInterpreterHook hook = cx->debugHooks->executeHook)
+            if (JSInterpreterHook hook = cx->runtime->debugHooks.executeHook)
                 hook(cx, Jsvalify(fp), false, &ok, hookData);
         } else {
-            if (JSInterpreterHook hook = cx->debugHooks->callHook)
+            if (JSInterpreterHook hook = cx->runtime->debugHooks.callHook)
                 hook(cx, Jsvalify(fp), false, &ok, hookData);
         }
     }
     Debugger::onLeaveFrame(cx);
 
     return ok;
 }
 
@@ -233,30 +233,30 @@ JS_PUBLIC_API(void)
 JS_ClearAllTrapsForCompartment(JSContext *cx)
 {
     cx->compartment->clearTraps(cx);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_SetInterrupt(JSRuntime *rt, JSInterruptHook hook, void *closure)
 {
-    rt->globalDebugHooks.interruptHook = hook;
-    rt->globalDebugHooks.interruptHookData = closure;
+    rt->debugHooks.interruptHook = hook;
+    rt->debugHooks.interruptHookData = closure;
     return JS_TRUE;
 }
 
 JS_PUBLIC_API(JSBool)
 JS_ClearInterrupt(JSRuntime *rt, JSInterruptHook *hoop, void **closurep)
 {
     if (hoop)
-        *hoop = rt->globalDebugHooks.interruptHook;
+        *hoop = rt->debugHooks.interruptHook;
     if (closurep)
-        *closurep = rt->globalDebugHooks.interruptHookData;
-    rt->globalDebugHooks.interruptHook = 0;
-    rt->globalDebugHooks.interruptHookData = 0;
+        *closurep = rt->debugHooks.interruptHookData;
+    rt->debugHooks.interruptHook = 0;
+    rt->debugHooks.interruptHookData = 0;
     return JS_TRUE;
 }
 
 /************************************************************************/
 
 JS_PUBLIC_API(JSBool)
 JS_SetWatchPoint(JSContext *cx, JSObject *obj, jsid id,
                  JSWatchPointHandler handler, JSObject *closure)
@@ -584,17 +584,17 @@ JS_GetFrameCallObject(JSContext *cx, JSS
     if (!ac.enter())
         return NULL;
 
     /*
      * XXX ill-defined: null return here means error was reported, unlike a
      *     null returned above or in the #else
      */
     if (!fp->hasCallObj() && fp->isNonEvalFunctionFrame())
-        return CreateFunCallObject(cx, fp);
+        return CallObject::createForFunction(cx, fp);
     return &fp->callObj();
 }
 
 JS_PUBLIC_API(JSBool)
 JS_GetFrameThis(JSContext *cx, JSStackFrame *fpArg, jsval *thisv)
 {
     StackFrame *fp = Valueify(fpArg);
     if (fp->isDummyFrame())
@@ -723,26 +723,26 @@ JS_GetScriptVersion(JSContext *cx, JSScr
     return VersionNumber(script->getVersion());
 }
 
 /***************************************************************************/
 
 JS_PUBLIC_API(void)
 JS_SetNewScriptHook(JSRuntime *rt, JSNewScriptHook hook, void *callerdata)
 {
-    rt->globalDebugHooks.newScriptHook = hook;
-    rt->globalDebugHooks.newScriptHookData = callerdata;
+    rt->debugHooks.newScriptHook = hook;
+    rt->debugHooks.newScriptHookData = callerdata;
 }
 
 JS_PUBLIC_API(void)
 JS_SetDestroyScriptHook(JSRuntime *rt, JSDestroyScriptHook hook,
                         void *callerdata)
 {
-    rt->globalDebugHooks.destroyScriptHook = hook;
-    rt->globalDebugHooks.destroyScriptHookData = callerdata;
+    rt->debugHooks.destroyScriptHook = hook;
+    rt->debugHooks.destroyScriptHookData = callerdata;
 }
 
 /***************************************************************************/
 
 JS_PUBLIC_API(JSBool)
 JS_EvaluateUCInStackFrame(JSContext *cx, JSStackFrame *fpArg,
                           const jschar *chars, uintN length,
                           const char *filename, uintN lineno,
@@ -839,20 +839,20 @@ JS_GetPropertyDesc(JSContext *cx, JSObje
 
     if (wasThrowing)
         cx->setPendingException(lastException);
 
     pd->flags |= (shape->enumerable() ? JSPD_ENUMERATE : 0)
               |  (!shape->writable()  ? JSPD_READONLY  : 0)
               |  (!shape->configurable() ? JSPD_PERMANENT : 0);
     pd->spare = 0;
-    if (shape->getter() == GetCallArg) {
+    if (shape->getter() == CallObject::getArgOp) {
         pd->slot = shape->shortid();
         pd->flags |= JSPD_ARGUMENT;
-    } else if (shape->getter() == GetCallVar) {
+    } else if (shape->getter() == CallObject::getVarOp) {
         pd->slot = shape->shortid();
         pd->flags |= JSPD_VARIABLE;
     } else {
         pd->slot = 0;
     }
     pd->alias = JSVAL_VOID;
 
     return JS_TRUE;
@@ -923,58 +923,58 @@ JS_PutPropertyDescArray(JSContext *cx, J
     cx->free_(pd);
 }
 
 /************************************************************************/
 
 JS_PUBLIC_API(JSBool)
 JS_SetDebuggerHandler(JSRuntime *rt, JSDebuggerHandler handler, void *closure)
 {
-    rt->globalDebugHooks.debuggerHandler = handler;
-    rt->globalDebugHooks.debuggerHandlerData = closure;
+    rt->debugHooks.debuggerHandler = handler;
+    rt->debugHooks.debuggerHandlerData = closure;
     return JS_TRUE;
 }
 
 JS_PUBLIC_API(JSBool)
 JS_SetSourceHandler(JSRuntime *rt, JSSourceHandler handler, void *closure)
 {
-    rt->globalDebugHooks.sourceHandler = handler;
-    rt->globalDebugHooks.sourceHandlerData = closure;
+    rt->debugHooks.sourceHandler = handler;
+    rt->debugHooks.sourceHandlerData = closure;
     return JS_TRUE;
 }
 
 JS_PUBLIC_API(JSBool)
 JS_SetExecuteHook(JSRuntime *rt, JSInterpreterHook hook, void *closure)
 {
-    rt->globalDebugHooks.executeHook = hook;
-    rt->globalDebugHooks.executeHookData = closure;
+    rt->debugHooks.executeHook = hook;
+    rt->debugHooks.executeHookData = closure;
     return JS_TRUE;
 }
 
 JS_PUBLIC_API(JSBool)
 JS_SetCallHook(JSRuntime *rt, JSInterpreterHook hook, void *closure)
 {
-    rt->globalDebugHooks.callHook = hook;
-    rt->globalDebugHooks.callHookData = closure;
+    rt->debugHooks.callHook = hook;
+    rt->debugHooks.callHookData = closure;
     return JS_TRUE;
 }
 
 JS_PUBLIC_API(JSBool)
 JS_SetThrowHook(JSRuntime *rt, JSThrowHook hook, void *closure)
 {
-    rt->globalDebugHooks.throwHook = hook;
-    rt->globalDebugHooks.throwHookData = closure;
+    rt->debugHooks.throwHook = hook;
+    rt->debugHooks.throwHookData = closure;
     return JS_TRUE;
 }
 
 JS_PUBLIC_API(JSBool)
 JS_SetDebugErrorHook(JSRuntime *rt, JSDebugErrorHook hook, void *closure)
 {
-    rt->globalDebugHooks.debugErrorHook = hook;
-    rt->globalDebugHooks.debugErrorHookData = closure;
+    rt->debugHooks.debugErrorHook = hook;
+    rt->debugHooks.debugErrorHookData = closure;
     return JS_TRUE;
 }
 
 /************************************************************************/
 
 JS_PUBLIC_API(size_t)
 JS_GetObjectTotalSize(JSContext *cx, JSObject *obj)
 {
@@ -1081,35 +1081,17 @@ JS_FRIEND_API(void)
 js_RevertVersion(JSContext *cx)
 {
     cx->clearVersionOverride();
 }
 
 JS_PUBLIC_API(const JSDebugHooks *)
 JS_GetGlobalDebugHooks(JSRuntime *rt)
 {
-    return &rt->globalDebugHooks;
-}
-
-const JSDebugHooks js_NullDebugHooks = {};
-
-JS_PUBLIC_API(JSDebugHooks *)
-JS_SetContextDebugHooks(JSContext *cx, const JSDebugHooks *hooks)
-{
-    JS_ASSERT(hooks);
-
-    JSDebugHooks *old = const_cast<JSDebugHooks *>(cx->debugHooks);
-    cx->debugHooks = hooks;
-    return old;
-}
-
-JS_PUBLIC_API(JSDebugHooks *)
-JS_ClearContextDebugHooks(JSContext *cx)
-{
-    return JS_SetContextDebugHooks(cx, &js_NullDebugHooks);
+    return &rt->debugHooks;
 }
 
 /************************************************************************/
 
 /* Profiling-related API */
 
 /* Thread-unsafe error management */
 
--- a/js/src/jsdbgapi.h
+++ b/js/src/jsdbgapi.h
@@ -472,23 +472,16 @@ JS_MakeSystemObject(JSContext *cx, JSObj
 /************************************************************************/
 
 extern JS_FRIEND_API(void)
 js_RevertVersion(JSContext *cx);
 
 extern JS_PUBLIC_API(const JSDebugHooks *)
 JS_GetGlobalDebugHooks(JSRuntime *rt);
 
-extern JS_PUBLIC_API(JSDebugHooks *)
-JS_SetContextDebugHooks(JSContext *cx, const JSDebugHooks *hooks);
-
-/* Disable debug hooks for this context. */
-extern JS_PUBLIC_API(JSDebugHooks *)
-JS_ClearContextDebugHooks(JSContext *cx);
-
 /**
  * Start any profilers that are available and have been configured on for this
  * platform. This is NOT thread safe.
  *
  * The profileName is used by some profilers to describe the current profiling
  * run. It may be used for part of the filename of the output, but the
  * specifics depend on the profiler. Many profilers will ignore it. Passing in
  * NULL is legal; some profilers may use it to output to stdout or similar.
--- a/js/src/jsfriendapi.cpp
+++ b/js/src/jsfriendapi.cpp
@@ -586,27 +586,27 @@ VersionSetXML(JSVersion version, bool en
 {
     return enable ? JSVersion(uint32_t(version) | VersionFlags::HAS_XML)
                   : JSVersion(uint32_t(version) & ~VersionFlags::HAS_XML);
 }
 
 JS_FRIEND_API(bool)
 CanCallContextDebugHandler(JSContext *cx)
 {
-    return cx->debugHooks && cx->debugHooks->debuggerHandler;
+    return !!cx->runtime->debugHooks.debuggerHandler;
 }
 
 JS_FRIEND_API(JSTrapStatus)
 CallContextDebugHandler(JSContext *cx, JSScript *script, jsbytecode *bc, Value *rval)
 {
-    if (!CanCallContextDebugHandler(cx))
+    if (!cx->runtime->debugHooks.debuggerHandler)
         return JSTRAP_RETURN;
 
-    return cx->debugHooks->debuggerHandler(cx, script, bc, rval,
-                                           cx->debugHooks->debuggerHandlerData);
+    return cx->runtime->debugHooks.debuggerHandler(cx, script, bc, rval,
+                                                   cx->runtime->debugHooks.debuggerHandlerData);
 }
 
 #ifdef JS_THREADSAFE
 void *
 GetOwnerThread(const JSContext *cx)
 {
     return cx->runtime->ownerThread();
 }
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -96,31 +96,16 @@
 #include "vm/ScopeObject-inl.h"
 #include "vm/Stack-inl.h"
 
 using namespace mozilla;
 using namespace js;
 using namespace js::gc;
 using namespace js::types;
 
-JSBool
-js_GetArgsValue(JSContext *cx, StackFrame *fp, Value *vp)
-{
-    JSObject *argsobj;
-    if (fp->hasOverriddenArgs()) {
-        JS_ASSERT(fp->hasCallObj());
-        return fp->callObj().getProperty(cx, cx->runtime->atomState.argumentsAtom, vp);
-    }
-    argsobj = js_GetArgsObject(cx, fp);
-    if (!argsobj)
-        return JS_FALSE;
-    vp->setObject(*argsobj);
-    return JS_TRUE;
-}
-
 js::ArgumentsObject *
 ArgumentsObject::create(JSContext *cx, uint32_t argc, JSObject &callee)
 {
     JS_ASSERT(argc <= StackSpace::ARGS_LENGTH_MAX);
 
     JSObject *proto = callee.global().getOrCreateObjectPrototype(cx);
     if (!proto)
         return NULL;
@@ -143,17 +128,18 @@ ArgumentsObject::create(JSContext *cx, u
         return NULL;
 
     ArgumentsData *data = (ArgumentsData *)
         cx->malloc_(offsetof(ArgumentsData, slots) + argc * sizeof(Value));
     if (!data)
         return NULL;
 
     data->callee.init(ObjectValue(callee));
-    InitValueRange(data->slots, argc, false);
+    for (HeapValue *vp = data->slots; vp != data->slots + argc; vp++)
+        vp->init(UndefinedValue());
 
     /* We have everything needed to fill in the object, so make the object. */
     JSObject *obj = JSObject::create(cx, FINALIZE_KIND, emptyArgumentsShape, type, NULL);
     if (!obj)
         return NULL;
 
     ArgumentsObject &argsobj = obj->asArguments();
 
@@ -177,17 +163,17 @@ struct STATIC_SKIP_INFERENCE PutArg
         JS_ASSERT(dst->isMagic(JS_ARGS_HOLE) || dst->isUndefined());
         if (!dst->isMagic(JS_ARGS_HOLE))
             dst->set(compartment, *src);
         ++dst;
         return true;
     }
 };
 
-JSObject *
+ArgumentsObject *
 js_GetArgsObject(JSContext *cx, StackFrame *fp)
 {
     /*
      * Arguments and Call objects are owned by the enclosing non-eval function
      * frame, thus any eval frames must be skipped before testing hasArgsObj.
      */
     JS_ASSERT(fp->isFunctionFrame());
     while (fp->isEvalInFunction())
@@ -608,360 +594,16 @@ Class js::StrictArgumentsObjectClass = {
         NULL,       /* outerObject */
         NULL,       /* innerObject */
         JS_ElementIteratorStub,
         NULL,       /* unused      */
         false,      /* isWrappedNative */
     }
 };
 
-namespace js {
-
-CallObject *
-CreateFunCallObject(JSContext *cx, StackFrame *fp)
-{
-    JS_ASSERT(fp->isNonEvalFunctionFrame());
-    JS_ASSERT(!fp->hasCallObj());
-
-    JSObject *scopeChain = &fp->scopeChain();
-    JS_ASSERT_IF(scopeChain->isWith() || scopeChain->isBlock() || scopeChain->isCall(),
-                 scopeChain->getPrivate() != fp);
-
-    /*
-     * For a named function expression Call's parent points to an environment
-     * object holding function's name.
-     */
-    if (JSAtom *lambdaName = CallObjectLambdaName(fp->fun())) {
-        scopeChain = DeclEnvObject::create(cx, fp);
-        if (!scopeChain)
-            return NULL;
-
-        if (!DefineNativeProperty(cx, scopeChain, ATOM_TO_JSID(lambdaName),
-                                  ObjectValue(fp->callee()), NULL, NULL,
-                                  JSPROP_PERMANENT | JSPROP_READONLY, 0, 0)) {
-            return NULL;
-        }
-    }
-
-    CallObject *callobj = CallObject::create(cx, fp->script(), *scopeChain, &fp->callee());
-    if (!callobj)
-        return NULL;
-
-    callobj->setStackFrame(fp);
-    fp->setScopeChainWithOwnCallObj(*callobj);
-    return callobj;
-}
-
-CallObject *
-CreateEvalCallObject(JSContext *cx, StackFrame *fp)
-{
-    CallObject *callobj = CallObject::create(cx, fp->script(), fp->scopeChain(), NULL);
-    if (!callobj)
-        return NULL;
-
-    callobj->setStackFrame(fp);
-    fp->setScopeChainWithOwnCallObj(*callobj);
-    return callobj;
-}
-
-} // namespace js
-
-void
-js_PutCallObject(StackFrame *fp)
-{
-    CallObject &callobj = fp->callObj().asCall();
-    JS_ASSERT(callobj.maybeStackFrame() == fp);
-    JS_ASSERT_IF(fp->isEvalFrame(), fp->isStrictEvalFrame());
-    JS_ASSERT(fp->isEvalFrame() == callobj.isForEval());
-
-    /* Get the arguments object to snapshot fp's actual argument values. */
-    if (fp->hasArgsObj()) {
-        if (!fp->hasOverriddenArgs())
-            callobj.initArguments(ObjectValue(fp->argsObj()));
-        js_PutArgsObject(fp);
-    }
-
-    JSScript *script = fp->script();
-    Bindings &bindings = script->bindings;
-
-    if (callobj.isForEval()) {
-        JS_ASSERT(script->strictModeCode);
-        JS_ASSERT(bindings.countArgs() == 0);
-
-        /* This could be optimized as below, but keep it simple for now. */
-        callobj.copyValues(0, NULL, bindings.countVars(), fp->slots());
-    } else {
-        JSFunction *fun = fp->fun();
-        JS_ASSERT(script == callobj.getCalleeFunction()->script());
-        JS_ASSERT(script == fun->script());
-
-        uintN n = bindings.countArgsAndVars();
-        if (n > 0) {
-            uint32_t nvars = bindings.countVars();
-            uint32_t nargs = bindings.countArgs();
-            JS_ASSERT(fun->nargs == nargs);
-            JS_ASSERT(nvars + nargs == n);
-
-            JSScript *script = fun->script();
-            if (script->usesEval
-#ifdef JS_METHODJIT
-                || script->debugMode
-#endif
-                ) {
-                callobj.copyValues(nargs, fp->formalArgs(), nvars, fp->slots());
-            } else {
-                /*
-                 * For each arg & var that is closed over, copy it from the stack
-                 * into the call object. We use initArg/VarUnchecked because,
-                 * when you call a getter on a call object, js_NativeGetInline
-                 * caches the return value in the slot, so we can't assert that
-                 * it's undefined.
-                 */
-                uint32_t nclosed = script->nClosedArgs;
-                for (uint32_t i = 0; i < nclosed; i++) {
-                    uint32_t e = script->getClosedArg(i);
-#ifdef JS_GC_ZEAL
-                    callobj.setArg(e, fp->formalArg(e));
-#else
-                    callobj.initArgUnchecked(e, fp->formalArg(e));
-#endif
-                }
-
-                nclosed = script->nClosedVars;
-                for (uint32_t i = 0; i < nclosed; i++) {
-                    uint32_t e = script->getClosedVar(i);
-#ifdef JS_GC_ZEAL
-                    callobj.setVar(e, fp->slots()[e]);
-#else
-                    callobj.initVarUnchecked(e, fp->slots()[e]);
-#endif
-                }
-            }
-
-            /*
-             * Update the args and vars for the active call if this is an outer
-             * function in a script nesting.
-             */
-            types::TypeScriptNesting *nesting = script->nesting();
-            if (nesting && script->isOuterFunction) {
-                nesting->argArray = callobj.argArray();
-                nesting->varArray = callobj.varArray();
-            }
-        }
-
-        /* Clear private pointers to fp, which is about to go away. */
-        if (js_IsNamedLambda(fun)) {
-            JSObject &env = callobj.enclosingScope();
-            JS_ASSERT(env.asDeclEnv().maybeStackFrame() == fp);
-            env.setPrivate(NULL);
-        }
-    }
-
-    callobj.setStackFrame(NULL);
-}
-
-namespace js {
-
-static JSBool
-GetCallArguments(JSContext *cx, JSObject *obj, jsid id, Value *vp)
-{
-    CallObject &callobj = obj->asCall();
-
-    StackFrame *fp = callobj.maybeStackFrame();
-    if (fp && !fp->hasOverriddenArgs()) {
-        JSObject *argsobj = js_GetArgsObject(cx, fp);
-        if (!argsobj)
-            return false;
-        vp->setObject(*argsobj);
-    } else {
-        *vp = callobj.getArguments();
-    }
-    return true;
-}
-
-static JSBool
-SetCallArguments(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value *vp)
-{
-    CallObject &callobj = obj->asCall();
-
-    if (StackFrame *fp = callobj.maybeStackFrame())
-        fp->setOverriddenArgs();
-    callobj.setArguments(*vp);
-    return true;
-}
-
-JSBool
-GetCallArg(JSContext *cx, JSObject *obj, jsid id, Value *vp)
-{
-    CallObject &callobj = obj->asCall();
-    JS_ASSERT((int16_t) JSID_TO_INT(id) == JSID_TO_INT(id));
-    uintN i = (uint16_t) JSID_TO_INT(id);
-
-    if (StackFrame *fp = callobj.maybeStackFrame())
-        *vp = fp->formalArg(i);
-    else
-        *vp = callobj.arg(i);
-    return true;
-}
-
-JSBool
-SetCallArg(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value *vp)
-{
-    CallObject &callobj = obj->asCall();
-    JS_ASSERT((int16_t) JSID_TO_INT(id) == JSID_TO_INT(id));
-    uintN i = (uint16_t) JSID_TO_INT(id);
-
-    if (StackFrame *fp = callobj.maybeStackFrame())
-        fp->formalArg(i) = *vp;
-    else
-        callobj.setArg(i, *vp);
-
-    JSFunction *fun = callobj.getCalleeFunction();
-    JSScript *script = fun->script();
-    if (!script->ensureHasTypes(cx))
-        return false;
-
-    TypeScript::SetArgument(cx, script, i, *vp);
-
-    return true;
-}
-
-JSBool
-GetCallUpvar(JSContext *cx, JSObject *obj, jsid id, Value *vp)
-{
-    CallObject &callobj = obj->asCall();
-    JS_ASSERT((int16_t) JSID_TO_INT(id) == JSID_TO_INT(id));
-    uintN i = (uint16_t) JSID_TO_INT(id);
-
-    *vp = callobj.getCallee()->toFunction()->getFlatClosureUpvar(i);
-    return true;
-}
-
-JSBool
-SetCallUpvar(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value *vp)
-{
-    CallObject &callobj = obj->asCall();
-    JS_ASSERT((int16_t) JSID_TO_INT(id) == JSID_TO_INT(id));
-    uintN i = (uint16_t) JSID_TO_INT(id);
-
-    callobj.getCallee()->toFunction()->setFlatClosureUpvar(i, *vp);
-    return true;
-}
-
-JSBool
-GetCallVar(JSContext *cx, JSObject *obj, jsid id, Value *vp)
-{
-    CallObject &callobj = obj->asCall();
-    JS_ASSERT((int16_t) JSID_TO_INT(id) == JSID_TO_INT(id));
-    uintN i = (uint16_t) JSID_TO_INT(id);
-
-    if (StackFrame *fp = callobj.maybeStackFrame())
-        *vp = fp->varSlot(i);
-    else
-        *vp = callobj.var(i);
-    return true;
-}
-
-JSBool
-SetCallVar(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value *vp)
-{
-    CallObject &callobj = obj->asCall();
-
-    JS_ASSERT((int16_t) JSID_TO_INT(id) == JSID_TO_INT(id));
-    uintN i = (uint16_t) JSID_TO_INT(id);
-
-    if (StackFrame *fp = callobj.maybeStackFrame())
-        fp->varSlot(i) = *vp;
-    else
-        callobj.setVar(i, *vp);
-
-    JSFunction *fun = callobj.getCalleeFunction();
-    JSScript *script = fun->script();
-    if (!script->ensureHasTypes(cx))
-        return false;
-
-    TypeScript::SetLocal(cx, script, i, *vp);
-
-    return true;
-}
-
-} // namespace js
-
-static JSBool
-call_resolve(JSContext *cx, JSObject *obj, jsid id, uintN flags, JSObject **objp)
-{
-    JS_ASSERT(!obj->getProto());
-
-    if (!JSID_IS_ATOM(id))
-        return true;
-
-    JSObject *callee = obj->asCall().getCallee();
-#ifdef DEBUG
-    if (callee) {
-        JSScript *script = callee->toFunction()->script();
-        JS_ASSERT(!script->bindings.hasBinding(cx, JSID_TO_ATOM(id)));
-    }
-#endif
-
-    /*
-     * Resolve arguments so that we never store a particular Call object's
-     * arguments object reference in a Call prototype's |arguments| slot.
-     *
-     * Include JSPROP_ENUMERATE for consistency with all other Call object
-     * properties; see js::Bindings::add and js::Interpret's JSOP_DEFFUN
-     * rebinding-Call-property logic.
-     */
-    if (callee && id == ATOM_TO_JSID(cx->runtime->atomState.argumentsAtom)) {
-        if (!DefineNativeProperty(cx, obj, id, UndefinedValue(),
-                                  GetCallArguments, SetCallArguments,
-                                  JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_ENUMERATE,
-                                  0, 0, DNP_DONT_PURGE)) {
-            return false;
-        }
-        *objp = obj;
-        return true;
-    }
-
-    /* Control flow reaches here only if id was not resolved. */
-    return true;
-}
-
-static void
-call_trace(JSTracer *trc, JSObject *obj)
-{
-    JS_ASSERT(obj->isCall());
-
-    /* Mark any generator frame, as for arguments objects. */
-#if JS_HAS_GENERATORS
-    StackFrame *fp = (StackFrame *) obj->getPrivate();
-    if (fp && fp->isFloatingGenerator())
-        MarkObject(trc, &js_FloatingFrameToGenerator(fp)->obj, "generator object");
-#endif
-}
-
-JS_PUBLIC_DATA(Class) js::CallClass = {
-    "Call",
-    JSCLASS_HAS_PRIVATE | JSCLASS_IMPLEMENTS_BARRIERS |
-    JSCLASS_HAS_RESERVED_SLOTS(CallObject::RESERVED_SLOTS) |
-    JSCLASS_NEW_RESOLVE | JSCLASS_IS_ANONYMOUS,
-    JS_PropertyStub,         /* addProperty */
-    JS_PropertyStub,         /* delProperty */
-    JS_PropertyStub,         /* getProperty */
-    JS_StrictPropertyStub,   /* setProperty */
-    JS_EnumerateStub,
-    (JSResolveOp)call_resolve,
-    NULL,                    /* convert: Leave it NULL so we notice if calls ever escape */
-    NULL,                    /* finalize */
-    NULL,                    /* checkAccess */
-    NULL,                    /* call        */
-    NULL,                    /* construct   */
-    NULL,                    /* hasInstance */
-    call_trace
-};
-
 bool
 StackFrame::getValidCalleeObject(JSContext *cx, Value *vp)
 {
     if (!isFunctionFrame()) {
         vp->setNull();
         return true;
     }
 
--- a/js/src/jsfun.h
+++ b/js/src/jsfun.h
@@ -357,40 +357,16 @@ js_ValueToCallableObject(JSContext *cx, 
 extern void
 js_ReportIsNotFunction(JSContext *cx, const js::Value *vp, uintN flags);
 
 extern void
 js_PutCallObject(js::StackFrame *fp);
 
 namespace js {
 
-CallObject *
-CreateFunCallObject(JSContext *cx, StackFrame *fp);
-
-CallObject *
-CreateEvalCallObject(JSContext *cx, StackFrame *fp);
-
-extern JSBool
-GetCallArg(JSContext *cx, JSObject *obj, jsid id, js::Value *vp);
-
-extern JSBool
-GetCallVar(JSContext *cx, JSObject *obj, jsid id, js::Value *vp);
-
-extern JSBool
-GetCallUpvar(JSContext *cx, JSObject *obj, jsid id, js::Value *vp);
-
-extern JSBool
-SetCallArg(JSContext *cx, JSObject *obj, jsid id, JSBool strict, js::Value *vp);
-
-extern JSBool
-SetCallVar(JSContext *cx, JSObject *obj, jsid id, JSBool strict, js::Value *vp);
-
-extern JSBool
-SetCallUpvar(JSContext *cx, JSObject *obj, jsid id, JSBool strict, js::Value *vp);
-
 /*
  * Function extended with reserved slots for use by various kinds of functions.
  * Most functions do not have these extensions, but enough are that efficient
  * storage is required (no malloc'ed reserved slots).
  */
 class FunctionExtended : public JSFunction
 {
     friend struct JSFunction;
@@ -410,30 +386,27 @@ JSFunction::toExtended()
 
 inline const js::FunctionExtended *
 JSFunction::toExtended() const
 {
     JS_ASSERT(isExtended());
     return static_cast<const js::FunctionExtended *>(this);
 }
 
-extern JSBool
-js_GetArgsValue(JSContext *cx, js::StackFrame *fp, js::Value *vp);
-
 /*
  * Get the arguments object for the given frame.  If the frame is strict mode
  * code, its current arguments will be copied into the arguments object.
  *
  * NB: Callers *must* get the arguments object before any parameters are
  *     mutated when the frame is strict mode code!  The emitter ensures this
  *     occurs for strict mode functions containing syntax which might mutate a
  *     named parameter by synthesizing an arguments access at the start of the
  *     function.
  */
-extern JSObject *
+extern js::ArgumentsObject *
 js_GetArgsObject(JSContext *cx, js::StackFrame *fp);
 
 extern void
 js_PutArgsObject(js::StackFrame *fp);
 
 inline bool
 js_IsNamedLambda(JSFunction *fun) { return (fun->flags & JSFUN_LAMBDA) && fun->atom; }
 
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -2113,16 +2113,23 @@ GCMarker::appendGrayRoot(void *thing, JS
 
 void
 GCMarker::GrayCallback(JSTracer *trc, void **thingp, JSGCTraceKind kind)
 {
     GCMarker *gcmarker = static_cast<GCMarker *>(trc);
     gcmarker->appendGrayRoot(*thingp, kind);
 }
 
+size_t
+GCMarker::sizeOfExcludingThis(JSMallocSizeOfFun mallocSizeOf) const
+{
+    return stack.sizeOfExcludingThis(mallocSizeOf) +
+           grayRoots.sizeOfExcludingThis(mallocSizeOf);
+}
+
 void
 SetMarkStackLimit(JSRuntime *rt, size_t limit)
 {
     JS_ASSERT(!rt->gcRunning);
     rt->gcMarker.setSizeLimit(limit);
     for (CompartmentsIter c(rt); !c.done(); c.next())
         c->barrierMarker_.setSizeLimit(limit);
 }
@@ -3073,37 +3080,45 @@ ValidateIncrementalMarking(JSContext *cx
     typedef HashMap<Chunk *, uintptr_t *, GCChunkHasher, SystemAllocPolicy> BitmapMap;
     BitmapMap map;
     if (!map.init())
         return;
 
     JSRuntime *rt = cx->runtime;
     FullGCMarker *gcmarker = &rt->gcMarker;
 
-    /* Save existing mark bits */
+    /* Save existing mark bits. */
     for (GCChunkSet::Range r(rt->gcChunkSet.all()); !r.empty(); r.popFront()) {
         ChunkBitmap *bitmap = &r.front()->bitmap;
         uintptr_t *entry = (uintptr_t *)js_malloc(sizeof(bitmap->bitmap));
         if (!entry)
             return;
 
         memcpy(entry, bitmap->bitmap, sizeof(bitmap->bitmap));
         if (!map.putNew(r.front(), entry))
             return;
     }
 
+    /* Save the existing weakmaps. */
+    WeakMapVector weakmaps;
+    if (!WeakMapBase::saveWeakMapList(rt, weakmaps))
+        return;
+
     /*
      * After this point, the function should run to completion, so we shouldn't
      * do anything fallible.
      */
 
     /* Re-do all the marking, but non-incrementally. */
     js::gc::State state = rt->gcIncrementalState;
     rt->gcIncrementalState = NO_INCREMENTAL;
 
+    /* As we're re-doing marking, we need to reset the weak map list. */
+    WeakMapBase::resetWeakMapList(rt);
+
     JS_ASSERT(gcmarker->isDrained());
     gcmarker->reset();
 
     for (GCChunkSet::Range r(rt->gcChunkSet.all()); !r.empty(); r.popFront())
         r.front()->bitmap.clear();
 
     MarkRuntime(gcmarker, true);
     SliceBudget budget;
@@ -3141,16 +3156,20 @@ ValidateIncrementalMarking(JSContext *cx
                 JS_ASSERT_IF(bitmap->isMarked(cell, BLACK), incBitmap.isMarked(cell, BLACK));
                 thing += Arena::thingSize(kind);
             }
         }
 
         memcpy(bitmap->bitmap, incBitmap.bitmap, sizeof(incBitmap.bitmap));
     }
 
+    /* Restore the weak map list. */
+    WeakMapBase::resetWeakMapList(rt);
+    WeakMapBase::restoreWeakMapList(rt, weakmaps);
+
     rt->gcIncrementalState = state;
 }
 #endif
 
 static void
 SweepPhase(JSContext *cx, JSGCInvocationKind gckind)
 {
     JSRuntime *rt = cx->runtime;
--- a/js/src/jsgc.h
+++ b/js/src/jsgc.h
@@ -1685,16 +1685,24 @@ struct MarkStack {
             if (!newStack)
                 return false;
         }
         stack = newStack;
         tos = stack + tosIndex;
         limit = newStack + newcap;
         return true;
     }
+
+    size_t sizeOfExcludingThis(JSMallocSizeOfFun mallocSizeOf) const {
+        size_t n = 0;
+        if (stack != ballast)
+            n += mallocSizeOf(stack);
+        n += mallocSizeOf(ballast);
+        return n;
+    }
 };
 
 /*
  * This class records how much work has been done in a given GC slice, so that
  * we can return before pausing for too long. Some slices are allowed to run for
  * unlimited time, and others are bounded. To reduce the number of gettimeofday
  * calls, we only check the time every 1000 operations.
  */
@@ -1822,16 +1830,18 @@ struct GCMarker : public JSTracer {
      */
     bool hasBufferedGrayRoots() const;
     void startBufferingGrayRoots();
     void endBufferingGrayRoots();
     void markBufferedGrayRoots();
 
     static void GrayCallback(JSTracer *trc, void **thing, JSGCTraceKind kind);
 
+    size_t sizeOfExcludingThis(JSMallocSizeOfFun mallocSizeOf) const;
+
     MarkStack<uintptr_t> stack;
 
   private:
 #ifdef DEBUG
     void checkCompartment(void *p);
 #else
     void checkCompartment(void *p) {}
 #endif
--- a/js/src/jsgcmark.cpp
+++ b/js/src/jsgcmark.cpp
@@ -351,16 +351,51 @@ MarkValueRootRange(JSTracer *trc, size_t
 {
     JS_ROOT_MARKING_ASSERT(trc);
     for (size_t i = 0; i < len; ++i) {
         JS_SET_TRACING_INDEX(trc, name, i);
         MarkValueInternal(trc, &vec[i]);
     }
 }
 
+/*** Slot Marking ***/
+
+void
+MarkSlot(JSTracer *trc, HeapSlot *s, const char *name)
+{
+    JS_SET_TRACING_NAME(trc, name);
+    MarkValueInternal(trc, s->unsafeGet());
+}
+
+void
+MarkSlotRange(JSTracer *trc, size_t len, HeapSlot *vec, const char *name)
+{
+    for (size_t i = 0; i < len; ++i) {
+        JS_SET_TRACING_INDEX(trc, name, i);
+        MarkValueInternal(trc, vec[i].unsafeGet());
+    }
+}
+
+void
+MarkCrossCompartmentSlot(JSTracer *trc, HeapSlot *s, const char *name)
+{
+    if (s->isMarkable()) {
+        Cell *cell = (Cell *)s->toGCThing();
+        JSRuntime *rt = trc->runtime;
+        if (rt->gcCurrentCompartment && cell->compartment() != rt->gcCurrentCompartment)
+            return;
+
+        /* In case we're called from a write barrier. */
+        if (rt->gcIncrementalCompartment && cell->compartment() != rt->gcIncrementalCompartment)
+            return;
+
+        MarkSlot(trc, s, name);
+    }
+}
+
 /*** Special Marking ***/
 
 /*
  * The unioned HeapPtr stored in script->globalObj needs special treatment to
  * typecheck correctly.
  */
 static void
 MarkObject(JSTracer *trc, const HeapPtr<GlobalObject, JSScript *> &thing, const char *name)
@@ -371,33 +406,16 @@ MarkObject(JSTracer *trc, const HeapPtr<
 
 void
 MarkValueUnbarriered(JSTracer *trc, Value *v, const char *name)
 {
     JS_SET_TRACING_NAME(trc, name);
     MarkValueInternal(trc, v);
 }
 
-void
-MarkCrossCompartmentValue(JSTracer *trc, HeapValue *v, const char *name)
-{
-    if (v->isMarkable()) {
-        Cell *cell = (Cell *)v->toGCThing();
-        JSRuntime *rt = trc->runtime;
-        if (rt->gcCurrentCompartment && cell->compartment() != rt->gcCurrentCompartment)
-            return;
-
-        /* In case we're called from a write barrier. */
-        if (rt->gcIncrementalCompartment && cell->compartment() != rt->gcIncrementalCompartment)
-            return;
-
-        MarkValue(trc, v, name);
-    }
-}
-
 /*** Push Mark Stack ***/
 
 #define JS_COMPARTMENT_ASSERT(rt, thing)                                 \
     JS_ASSERT_IF((rt)->gcCurrentCompartment,                             \
                  (thing)->compartment() == (rt)->gcCurrentCompartment);
 
 #define JS_COMPARTMENT_ASSERT_STR(rt, thing)                             \
     JS_ASSERT_IF((rt)->gcCurrentCompartment,                             \
@@ -891,31 +909,31 @@ PushArena(GCMarker *gcmarker, ArenaHeade
 #endif
     }
 }
 
 } /* namespace gc */
 
 using namespace js::gc;
 
-struct ValueArrayLayout
+struct SlotArrayLayout
 {
     union {
-        HeapValue *end;
+        HeapSlot *end;
         js::Class *clasp;
     };
     union {
-        HeapValue *start;
+        HeapSlot *start;
         uintptr_t index;
     };
     JSObject *obj;
 
     static void staticAsserts() {
         /* This should have the same layout as three mark stack items. */
-        JS_STATIC_ASSERT(sizeof(ValueArrayLayout) == 3 * sizeof(uintptr_t));
+        JS_STATIC_ASSERT(sizeof(SlotArrayLayout) == 3 * sizeof(uintptr_t));
     }
 };
 
 /*
  * During incremental GC, we return from drainMarkStack without having processed
  * the entire stack. At that point, JS code can run and reallocate slot arrays
  * that are stored on the stack. To prevent this from happening, we replace all
  * ValueArrayTag stack items with SavedValueArrayTag. In the latter, slots
@@ -928,26 +946,26 @@ struct ValueArrayLayout
  */
 void
 GCMarker::saveValueRanges()
 {
     for (uintptr_t *p = stack.tos; p > stack.stack; ) {
         uintptr_t tag = *--p & StackTagMask;
         if (tag == ValueArrayTag) {
             p -= 2;
-            ValueArrayLayout *arr = reinterpret_cast<ValueArrayLayout *>(p);
+            SlotArrayLayout *arr = reinterpret_cast<SlotArrayLayout *>(p);
             JSObject *obj = arr->obj;
 
             if (obj->getClass() == &ArrayClass) {
-                HeapValue *vp = obj->getDenseArrayElements();
+                HeapSlot *vp = obj->getDenseArrayElements();
                 JS_ASSERT(arr->start >= vp &&
                           arr->end == vp + obj->getDenseArrayInitializedLength());
                 arr->index = arr->start - vp;
             } else {
-                HeapValue *vp = obj->fixedSlots();
+                HeapSlot *vp = obj->fixedSlots();
                 unsigned nfixed = obj->numFixedSlots();
                 if (arr->start >= vp && arr->start < vp + nfixed) {
                     JS_ASSERT(arr->end == vp + Min(nfixed, obj->slotSpan()));
                     arr->index = arr->start - vp;
                 } else {
                     JS_ASSERT(arr->start >= obj->slots &&
                               arr->end == obj->slots + obj->slotSpan() - nfixed);
                     arr->index = (arr->start - obj->slots) + nfixed;
@@ -970,26 +988,26 @@ GCMarker::restoreValueArray(JSObject *ob
     JS_ASSERT(obj->getClass() == clasp ||
               (clasp == &ArrayClass && obj->getClass() == &SlowArrayClass));
 
     if (clasp == &ArrayClass) {
         if (obj->getClass() != &ArrayClass)
             return false;
 
         uint32_t initlen = obj->getDenseArrayInitializedLength();
-        HeapValue *vp = obj->getDenseArrayElements();
+        HeapSlot *vp = obj->getDenseArrayElements();
         if (start < initlen) {
             *vpp = vp + start;
             *endp = vp + initlen;
         } else {
             /* The object shrunk, in which case no scanning is needed. */
             *vpp = *endp = vp;
         }
     } else {
-        HeapValue *vp = obj->fixedSlots();
+        HeapSlot *vp = obj->fixedSlots();
         unsigned nfixed = obj->numFixedSlots();
         unsigned nslots = obj->slotSpan();
         if (start < nfixed) {
             *vpp = vp + start;
             *endp = vp + Min(nfixed, nslots);
         } else if (start < nslots) {
             *vpp = obj->slots + start - nfixed;
             *endp = obj->slots + nslots - nfixed;
@@ -1006,33 +1024,33 @@ GCMarker::restoreValueArray(JSObject *ob
 inline void
 GCMarker::processMarkStackTop(SliceBudget &budget)
 {
     /*
      * The function uses explicit goto and implements the scanning of the
      * object directly. It allows to eliminate the tail recursion and
      * significantly improve the marking performance, see bug 641025.
      */
-    HeapValue *vp, *end;
+    HeapSlot *vp, *end;
     JSObject *obj;
 
     uintptr_t addr = stack.pop();
     uintptr_t tag = addr & StackTagMask;
     addr &= ~StackTagMask;
 
     if (tag == ValueArrayTag) {
         JS_STATIC_ASSERT(ValueArrayTag == 0);
         JS_ASSERT(!(addr & Cell::CellMask));
         obj = reinterpret_cast<JSObject *>(addr);
         uintptr_t addr2 = stack.pop();
         uintptr_t addr3 = stack.pop();
         JS_ASSERT(addr2 <= addr3);
         JS_ASSERT((addr3 - addr2) % sizeof(Value) == 0);
-        vp = reinterpret_cast<HeapValue *>(addr2);
-        end = reinterpret_cast<HeapValue *>(addr3);
+        vp = reinterpret_cast<HeapSlot *>(addr2);
+        end = reinterpret_cast<HeapSlot *>(addr3);
         goto scan_value_array;
     }
 
     if (tag == ObjectTag) {
         obj = reinterpret_cast<JSObject *>(addr);
         JS_COMPARTMENT_ASSERT(runtime, obj);
         goto scan_obj;
     }
--- a/js/src/jsgcmark.h
+++ b/js/src/jsgcmark.h
@@ -109,28 +109,36 @@ void
 MarkValueRootRange(JSTracer *trc, size_t len, Value *vec, const char *name);
 
 inline void
 MarkValueRootRange(JSTracer *trc, Value *begin, Value *end, const char *name)
 {
     MarkValueRootRange(trc, end - begin, begin, name);
 }
 
-/*** Special Cases ***/
+/*** Slot Marking ***/
 
-/* Direct value access used by the write barriers and the methodjit */
 void
-MarkValueUnbarriered(JSTracer *trc, Value *v, const char *name);
+MarkSlot(JSTracer *trc, HeapSlot *s, const char *name);
+
+void
+MarkSlotRange(JSTracer *trc, size_t len, HeapSlot *vec, const char *name);
 
 /*
  * Mark a value that may be in a different compartment from the compartment
  * being GC'd. (Although it won't be marked if it's in the wrong compartment.)
  */
 void
-MarkCrossCompartmentValue(JSTracer *trc, HeapValue *v, const char *name);
+MarkCrossCompartmentSlot(JSTracer *trc, HeapSlot *s, const char *name);
+
+/*** Special Cases ***/
+
+/* Direct value access used by the write barriers and the methodjit. */
+void
+MarkValueUnbarriered(JSTracer *trc, Value *v, const char *name);
 
 /*
  * MarkChildren<JSObject> is exposed solely for preWriteBarrier on
  * JSObject::TradeGuts. It should not be considered external interface.
  */
 void
 MarkChildren(JSTracer *trc, JSObject *obj);
 
--- a/js/src/jsinfer.cpp
+++ b/js/src/jsinfer.cpp
@@ -1683,20 +1683,18 @@ types::MarkArgumentsCreated(JSContext *c
         StackFrame *fp = iter.fp();
         if (fp->isScriptFrame() && fp->script() == script) {
             /*
              * Check locals and stack slots, assignment to individual arguments
              * is treated as an escape on the arguments.
              */
             Value *sp = fp->base() + analysis->getCode(iter.pc()).stackDepth;
             for (Value *vp = fp->slots(); vp < sp; vp++) {
-                if (vp->isParticularMagic(JS_LAZY_ARGUMENTS)) {
-                    if (!js_GetArgsValue(cx, fp, vp))
-                        vp->setNull();
-                }
+                if (vp->isParticularMagic(JS_LAZY_ARGUMENTS))
+                    *vp = ObjectOrNullValue(js_GetArgsObject(cx, fp));
             }
         }
     }
 }
 
 static inline void
 ObjectStateChange(JSContext *cx, TypeObject *object, bool markingUnknown, bool force)
 {
@@ -2407,16 +2405,21 @@ ScriptAnalysis::addTypeBarrier(JSContext
 
     InferSpew(ISpewOps, "typeBarrier: #%u:%05u: %sT%p%s %s",
               script->id(), pc - script->code,
               InferSpewColor(target), target, InferSpewColorReset(),
               TypeString(type));
 
     barrier = cx->typeLifoAlloc().new_<TypeBarrier>(target, type, (JSObject *) NULL, JSID_VOID);
 
+    if (!barrier) {
+        cx->compartment->types.setPendingNukeTypes(cx);
+        return;
+    }
+
     barrier->next = code.typeBarriers;
     code.typeBarriers = barrier;
 }
 
 void
 ScriptAnalysis::addSingletonTypeBarrier(JSContext *cx, const jsbytecode *pc, TypeSet *target, JSObject *singleton, jsid singletonId)
 {
     JS_ASSERT(singletonId == MakeTypeId(cx, singletonId) && !JSID_IS_VOID(singletonId));
@@ -2433,16 +2436,21 @@ ScriptAnalysis::addSingletonTypeBarrier(
     InferSpew(ISpewOps, "singletonTypeBarrier: #%u:%05u: %sT%p%s %p %s",
               script->id(), pc - script->code,
               InferSpewColor(target), target, InferSpewColorReset(),
               (void *) singleton, TypeIdString(singletonId));
 
     TypeBarrier *barrier = cx->typeLifoAlloc().new_<TypeBarrier>(target, Type::UndefinedType(),
                               singleton, singletonId);
 
+    if (!barrier) {
+        cx->compartment->types.setPendingNukeTypes(cx);
+        return;
+    }
+
     barrier->next = code.typeBarriers;
     code.typeBarriers = barrier;
 }
 
 void
 TypeCompartment::print(JSContext *cx, bool force)
 {
     JSCompartment *compartment = this->compartment();
--- a/js/src/jsinterp.cpp
+++ b/js/src/jsinterp.cpp
@@ -155,17 +155,17 @@ js::GetScopeChain(JSContext *cx, StackFr
      * make sure there's a call object at the current head of the scope chain,
      * if this frame is a call frame.
      *
      * Also, identify the innermost compiler-allocated block we needn't clone.
      */
     JSObject *limitBlock, *limitClone;
     if (fp->isNonEvalFunctionFrame() && !fp->hasCallObj()) {
         JS_ASSERT_IF(fp->scopeChain().isClonedBlock(), fp->scopeChain().getPrivate() != fp);
-        if (!CreateFunCallObject(cx, fp))
+        if (!CallObject::createForFunction(cx, fp))
             return NULL;
 
         /* We know we must clone everything on blockChain. */
         limitBlock = limitClone = NULL;
     } else {
         /*
          * scopeChain includes all blocks whose static scope we're within that
          * have already been cloned.  Find the innermost such block.  Its
@@ -641,17 +641,17 @@ js::ExecuteKernel(JSContext *cx, JSScrip
     if (!cx->stack.pushExecuteFrame(cx, script, thisv, scopeChain, type, evalInFrame, &efg))
         return false;
 
     if (!script->ensureRanAnalysis(cx, &scopeChain))
         return false;
 
     /* Give strict mode eval its own fresh lexical environment. */
     StackFrame *fp = efg.fp();
-    if (fp->isStrictEvalFrame() && !CreateEvalCallObject(cx, fp))
+    if (fp->isStrictEvalFrame() && !CallObject::createForStrictEval(cx, fp))
         return false;
 
     Probes::startExecution(cx, script);
 
     TypeScript::SetThis(cx, script, fp->thisValue());
 
     AutoPreserveEnumerators preserve(cx);
     JSBool ok = RunScript(cx, script, fp);
@@ -1439,17 +1439,17 @@ js::Interpret(JSContext *cx, StackFrame 
         if (script->pcCounters)                                               \
             ENABLE_INTERRUPTS();                                              \
         JS_ASSERT_IF(interpMode == JSINTERP_SKIP_TRAP,                        \
                      script->hasAnyBreakpointsOrStepMode());                  \
     JS_END_MACRO
 
 #define CHECK_INTERRUPT_HANDLER()                                             \
     JS_BEGIN_MACRO                                                            \
-        if (cx->debugHooks->interruptHook)                                    \
+        if (cx->runtime->debugHooks.interruptHook)                            \
             ENABLE_INTERRUPTS();                                              \
     JS_END_MACRO
 
     /* Repoint cx->regs to a local variable for faster access. */
     FrameRegs regs = cx->regs();
     PreserveRegsGuard interpGuard(cx, regs);
 
     /*
@@ -1586,22 +1586,22 @@ js::Interpret(JSContext *cx, StackFrame 
         }
 
         if (script->pcCounters) {
             OpcodeCounts counts = script->getCounts(regs.pc);
             counts.get(OpcodeCounts::BASE_INTERP)++;
             moreInterrupts = true;
         }
 
-        JSInterruptHook hook = cx->debugHooks->interruptHook;
+        JSInterruptHook hook = cx->runtime->debugHooks.interruptHook;
         if (hook || script->stepModeEnabled()) {
             Value rval;
             JSTrapStatus status = JSTRAP_CONTINUE;
             if (hook)
-                status = hook(cx, script, regs.pc, &rval, cx->debugHooks->interruptHookData);
+                status = hook(cx, script, regs.pc, &rval, cx->runtime->debugHooks.interruptHookData);
             if (status == JSTRAP_CONTINUE && script->stepModeEnabled())
                 status = Debugger::onSingleStep(cx, &rval);
             switch (status) {
               case JSTRAP_ERROR:
                 goto error;
               case JSTRAP_CONTINUE:
                 break;
               case JSTRAP_RETURN:
@@ -1962,17 +1962,17 @@ BEGIN_CASE(JSOP_IN)
     regs.sp[-1].setBoolean(cond);
 }
 END_CASE(JSOP_IN)
 
 BEGIN_CASE(JSOP_ITER)
 {
     JS_ASSERT(regs.sp > regs.fp()->base());
     uint8_t flags = GET_UINT8(regs.pc);
-    if (!js_ValueToIterator(cx, flags, &regs.sp[-1]))
+    if (!ValueToIterator(cx, flags, &regs.sp[-1]))
         goto error;
     CHECK_INTERRUPT_HANDLER();
     JS_ASSERT(!regs.sp[-1].isPrimitive());
 }
 END_CASE(JSOP_ITER)
 
 BEGIN_CASE(JSOP_MOREITER)
 {
@@ -1996,17 +1996,17 @@ BEGIN_CASE(JSOP_ITERNEXT)
     if (!IteratorNext(cx, &itervp->toObject(), &regs.sp[-1]))
         goto error;
 }
 END_CASE(JSOP_ITERNEXT)
 
 BEGIN_CASE(JSOP_ENDITER)
 {
     JS_ASSERT(regs.sp - 1 >= regs.fp()->base());
-    bool ok = !!js_CloseIterator(cx, &regs.sp[-1].toObject());
+    bool ok = CloseIterator(cx, &regs.sp[-1].toObject());
     regs.sp--;
     if (!ok)
         goto error;
 }
 END_CASE(JSOP_ENDITER)
 
 BEGIN_CASE(JSOP_DUP)
 {
@@ -2995,24 +2995,28 @@ END_VARLEN_CASE
 
 BEGIN_CASE(JSOP_ARGUMENTS)
 {
     Value rval;
     if (cx->typeInferenceEnabled() && !script->strictModeCode) {
         if (!script->ensureRanInference(cx))
             goto error;
         if (script->createdArgs) {
-            if (!js_GetArgsValue(cx, regs.fp(), &rval))
+            ArgumentsObject *arguments = js_GetArgsObject(cx, regs.fp());
+            if (!arguments)
                 goto error;
+            rval = ObjectValue(*arguments);
         } else {
             rval = MagicValue(JS_LAZY_ARGUMENTS);
         }
     } else {
-        if (!js_GetArgsValue(cx, regs.fp(), &rval))
+        ArgumentsObject *arguments = js_GetArgsObject(cx, regs.fp());
+        if (!arguments)
             goto error;
+        rval = ObjectValue(*arguments);
     }
     PUSH_COPY(rval);
 }
 END_CASE(JSOP_ARGUMENTS)
 
 BEGIN_CASE(JSOP_GETARG)
 BEGIN_CASE(JSOP_CALLARG)
     PUSH_COPY(regs.fp()->formalArg(GET_ARGNO(regs.pc)));
@@ -3662,18 +3666,18 @@ BEGIN_CASE(JSOP_INSTANCEOF)
     regs.sp[-1].setBoolean(cond);
 }
 END_CASE(JSOP_INSTANCEOF)
 
 BEGIN_CASE(JSOP_DEBUGGER)
 {
     JSTrapStatus st = JSTRAP_CONTINUE;
     Value rval;
-    if (JSDebuggerHandler handler = cx->debugHooks->debuggerHandler)
-        st = handler(cx, script, regs.pc, &rval, cx->debugHooks->debuggerHandlerData);
+    if (JSDebuggerHandler handler = cx->runtime->debugHooks.debuggerHandler)
+        st = handler(cx, script, regs.pc, &rval, cx->runtime->debugHooks.debuggerHandlerData);
     if (st == JSTRAP_CONTINUE)
         st = Debugger::onDebuggerStatement(cx, &rval);
     switch (st) {
       case JSTRAP_ERROR:
         goto error;
       case JSTRAP_CONTINUE:
         break;
       case JSTRAP_RETURN:
@@ -4222,23 +4226,23 @@ END_CASE(JSOP_ARRAYPUSH)
         JSThrowHook handler;
         JSTryNote *tn, *tnlimit;
         uint32_t offset;
 
         /* Restore atoms local in case we will resume. */
         atoms = script->atoms;
 
         /* Call debugger throw hook if set. */
-        if (cx->debugHooks->throwHook || !cx->compartment->getDebuggees().empty()) {
+        if (cx->runtime->debugHooks.throwHook || !cx->compartment->getDebuggees().empty()) {
             Value rval;
             JSTrapStatus st = Debugger::onExceptionUnwind(cx, &rval);
             if (st == JSTRAP_CONTINUE) {
-                handler = cx->debugHooks->throwHook;
+                handler = cx->runtime->debugHooks.throwHook;
                 if (handler)
-                    st = handler(cx, script, regs.pc, &rval, cx->debugHooks->throwHookData);
+                    st = handler(cx, script, regs.pc, &rval, cx->runtime->debugHooks.throwHookData);
             }
 
             switch (st) {
               case JSTRAP_ERROR:
                 cx->clearPendingException();
                 goto error;
               case JSTRAP_RETURN:
                 cx->clearPendingException();
@@ -4325,23 +4329,20 @@ END_CASE(JSOP_ARRAYPUSH)
                 PUSH_COPY(cx->getPendingException());
                 cx->clearPendingException();
                 len = 0;
                 DO_NEXT_OP(len);
 
               case JSTRY_ITER: {
                 /* This is similar to JSOP_ENDITER in the interpreter loop. */
                 JS_ASSERT(JSOp(*regs.pc) == JSOP_ENDITER);
-                Value v = cx->getPendingException();
-                cx->clearPendingException();
-                bool ok = js_CloseIterator(cx, &regs.sp[-1].toObject());
+                bool ok = UnwindIteratorForException(cx, &regs.sp[-1].toObject());
                 regs.sp -= 1;
                 if (!ok)
                     goto error;
-                cx->setPendingException(v);
               }
            }
         } while (++tn != tnlimit);
 
       no_catch:
         /*
          * Propagate the exception or error to the caller unless the exception
          * is an asynchronous return from a generator.
--- a/js/src/jsinterp.h
+++ b/js/src/jsinterp.h
@@ -347,11 +347,27 @@ Debug_SetValueRangeToCrashOnTouch(Value 
 static JS_ALWAYS_INLINE void
 Debug_SetValueRangeToCrashOnTouch(HeapValue *vec, size_t len)
 {
 #ifdef DEBUG
     Debug_SetValueRangeToCrashOnTouch((Value *) vec, len);
 #endif
 }
 
+static JS_ALWAYS_INLINE void
+Debug_SetSlotRangeToCrashOnTouch(HeapSlot *vec, size_t len)
+{
+#ifdef DEBUG
+    Debug_SetValueRangeToCrashOnTouch((Value *) vec, len);
+#endif
+}
+
+static JS_ALWAYS_INLINE void
+Debug_SetSlotRangeToCrashOnTouch(HeapSlot *begin, HeapSlot *end)
+{
+#ifdef DEBUG
+    Debug_SetValueRangeToCrashOnTouch((Value *) begin, end - begin);
+#endif
+}
+
 }  /* namespace js */
 
 #endif /* jsinterp_h___ */
--- a/js/src/jsiter.cpp
+++ b/js/src/jsiter.cpp
@@ -824,17 +824,17 @@ iterator_iterator(JSContext *cx, JSObjec
 
 static JSBool
 Iterator(JSContext *cx, uintN argc, Value *vp)
 {
     Value *argv = JS_ARGV(cx, vp);
     bool keyonly = argc >= 2 ? js_ValueToBoolean(argv[1]) : false;
     uintN flags = JSITER_OWNONLY | (keyonly ? 0 : (JSITER_FOREACH | JSITER_KEYVALUE));
     *vp = argc >= 1 ? argv[0] : UndefinedValue();
-    return js_ValueToIterator(cx, flags, vp);
+    return ValueToIterator(cx, flags, vp);
 }
 
 JSBool
 js_ThrowStopIteration(JSContext *cx)
 {
     Value v;
 
     JS_ASSERT(!JS_IsExceptionPending(cx));
@@ -866,22 +866,29 @@ iterator_next(JSContext *cx, uintN argc,
 
 #define JSPROP_ROPERM   (JSPROP_READONLY | JSPROP_PERMANENT)
 
 static JSFunctionSpec iterator_methods[] = {
     JS_FN(js_next_str,      iterator_next,  0,JSPROP_ROPERM),
     JS_FS_END
 };
 
+#if JS_HAS_GENERATORS
+static JSBool
+CloseGenerator(JSContext *cx, JSObject *genobj);
+#endif
+
+namespace js {
+
 /*
  * Call ToObject(v).__iterator__(keyonly) if ToObject(v).__iterator__ exists.
  * Otherwise construct the default iterator.
  */
-JS_FRIEND_API(JSBool)
-js_ValueToIterator(JSContext *cx, uintN flags, Value *vp)
+JSBool
+ValueToIterator(JSContext *cx, uintN flags, Value *vp)
 {
     /* JSITER_KEYVALUE must always come with JSITER_FOREACH */
     JS_ASSERT_IF(flags & JSITER_KEYVALUE, flags & JSITER_FOREACH);
 
     /*
      * Make sure the more/next state machine doesn't get stuck. A value might be
      * left in iterValue when a trace is left due to an operation time-out after
      * JSOP_MOREITER but before the value is picked up by FOR*.
@@ -909,23 +916,18 @@ js_ValueToIterator(JSContext *cx, uintN 
             if (!obj)
                 return false;
         }
     }
 
     return GetIterator(cx, obj, flags, vp);
 }
 
-#if JS_HAS_GENERATORS
-static JSBool
-CloseGenerator(JSContext *cx, JSObject *genobj);
-#endif
-
-JS_FRIEND_API(JSBool)
-js_CloseIterator(JSContext *cx, JSObject *obj)
+bool
+CloseIterator(JSContext *cx, JSObject *obj)
 {
     cx->iterValue.setMagic(JS_NO_ITER_VALUE);
 
     if (obj->isIterator()) {
         /* Remove enumerators from the active list, which is a stack. */
         NativeIterator *ni = obj->getNativeIterator();
 
         if (ni->flags & JSITER_ENUMERATE) {
@@ -945,16 +947,29 @@ js_CloseIterator(JSContext *cx, JSObject
 #if JS_HAS_GENERATORS
     else if (obj->isGenerator()) {
         return CloseGenerator(cx, obj);
     }
 #endif
     return JS_TRUE;
 }
 
+bool
+UnwindIteratorForException(JSContext *cx, JSObject *obj)
+{
+    Value v = cx->getPendingException();
+    cx->clearPendingException();
+    if (!CloseIterator(cx, obj))
+        return false;
+    cx->setPendingException(v);
+    return true;
+}
+
+} // namespace js
+
 /*
  * Suppress enumeration of deleted properties. This function must be called
  * when a property is deleted and there might be active enumerators.
  *
  * We maintain a list of active non-escaping for-in enumerators. To suppress
  * a property, we check whether each active enumerator contains the (obj, id)
  * pair and has not yet enumerated |id|. If so, and |id| is the next property,
  * we simply advance the cursor. Otherwise, we delete |id| from the list.
--- a/js/src/jsiter.h
+++ b/js/src/jsiter.h
@@ -176,29 +176,32 @@ VectorToValueIterator(JSContext *cx, JSO
 
 /*
  * Creates either a key or value iterator, depending on flags. For a value
  * iterator, performs value-lookup to convert the given list of jsids.
  */
 bool
 EnumeratedIdVectorToIterator(JSContext *cx, JSObject *obj, uintN flags, js::AutoIdVector &props, js::Value *vp);
 
-}
-
 /*
  * Convert the value stored in *vp to its iteration object. The flags should
  * contain JSITER_ENUMERATE if js_ValueToIterator is called when enumerating
  * for-in semantics are required, and when the caller can guarantee that the
  * iterator will never be exposed to scripts.
  */
-extern JS_FRIEND_API(JSBool)
-js_ValueToIterator(JSContext *cx, uintN flags, js::Value *vp);
+extern JSBool
+ValueToIterator(JSContext *cx, uintN flags, js::Value *vp);
 
-extern JS_FRIEND_API(JSBool)
-js_CloseIterator(JSContext *cx, JSObject *iterObj);
+extern bool
+CloseIterator(JSContext *cx, JSObject *iterObj);
+
+extern bool
+UnwindIteratorForException(JSContext *cx, JSObject *obj);
+
+}
 
 extern bool
 js_SuppressDeletedProperty(JSContext *cx, JSObject *obj, jsid id);
 
 extern bool
 js_SuppressDeletedElement(JSContext *cx, JSObject *obj, uint32_t index);
 
 extern bool
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -2748,17 +2748,17 @@ NewObject(JSContext *cx, Class *clasp, t
 
     RootTypeObject typeRoot(cx, &type);
 
     RootedVarShape shape(cx);
     shape = EmptyShape::getInitialShape(cx, clasp, type->proto, parent, kind);
     if (!shape)
         return NULL;
 
-    HeapValue *slots;
+    HeapSlot *slots;
     if (!PreallocateObjectDynamicSlots(cx, shape, &slots))
         return NULL;
 
     JSObject *obj = JSObject::create(cx, kind, shape, typeRoot, slots);
     if (!obj)
         return NULL;
 
     /*
@@ -3245,18 +3245,18 @@ JS_CloneObject(JSContext *cx, JSObject *
 struct JSObject::TradeGutsReserved {
     JSContext *cx;
     Vector<Value> avals;
     Vector<Value> bvals;
     int newafixed;
     int newbfixed;
     Shape *newashape;
     Shape *newbshape;
-    HeapValue *newaslots;
-    HeapValue *newbslots;
+    HeapSlot *newaslots;
+    HeapSlot *newbslots;
 
     TradeGutsReserved(JSContext *cx)
         : cx(cx), avals(cx), bvals(cx),
           newafixed(0), newbfixed(0),
           newashape(NULL), newbshape(NULL),
           newaslots(NULL), newbslots(NULL)
     {}
 
@@ -3345,26 +3345,26 @@ JSObject::ReserveForTradeGuts(JSContext 
      * if they do not have enough fixed slots to accomodate the slots in the
      * other object.
      */
 
     unsigned adynamic = dynamicSlotsCount(reserved.newafixed, b->slotSpan());
     unsigned bdynamic = dynamicSlotsCount(reserved.newbfixed, a->slotSpan());
 
     if (adynamic) {
-        reserved.newaslots = (HeapValue *) cx->malloc_(sizeof(HeapValue) * adynamic);
+        reserved.newaslots = (HeapSlot *) cx->malloc_(sizeof(HeapSlot) * adynamic);
         if (!reserved.newaslots)
             return false;
-        Debug_SetValueRangeToCrashOnTouch(reserved.newaslots, adynamic);
+        Debug_SetSlotRangeToCrashOnTouch(reserved.newaslots, adynamic);
     }
     if (bdynamic) {
-        reserved.newbslots = (HeapValue *) cx->malloc_(sizeof(HeapValue) * bdynamic);
+        reserved.newbslots = (HeapSlot *) cx->malloc_(sizeof(HeapSlot) * bdynamic);
         if (!reserved.newbslots)
             return false;
-        Debug_SetValueRangeToCrashOnTouch(reserved.newbslots, bdynamic);
+        Debug_SetSlotRangeToCrashOnTouch(reserved.newbslots, bdynamic);
     }
 
     return true;
 }
 
 void
 JSObject::TradeGuts(JSContext *cx, JSObject *a, JSObject *b, TradeGutsReserved &reserved)
 {
@@ -3416,21 +3416,20 @@ JSObject::TradeGuts(JSContext *cx, JSObj
         js_memcpy(a, b, size);
         js_memcpy(b, tmp, size);
 
 #ifdef JSGC_GENERATIONAL
         /*
          * Trigger post barriers for fixed slots. JSObject bits are barriered
          * below, in common with the other case.
          */
+        JSCompartment *comp = cx->compartment;
         for (size_t i = 0; i < a->numFixedSlots(); ++i) {
-            HeapValue *slotA = &a->getFixedSlotRef(i);
-            HeapValue *slotB = &b->getFixedSlotRef(i);
-            HeapValue::writeBarrierPost(*slotA, slotA);
-            HeapValue::writeBarrierPost(*slotB, slotB);
+            HeapSlot::writeBarrierPost(comp, a, i);
+            HeapSlot::writeBarrierPost(comp, b, i);
         }
 #endif
     } else {
         /*
          * If the objects are of differing sizes, use the space we reserved
          * earlier to save the slots from each object and then copy them into
          * the new layout for the other object.
          */
@@ -3811,87 +3810,49 @@ js_InitClass(JSContext *cx, HandleObject
         return NULL;
     }
 
     return DefineConstructorAndPrototype(cx, obj, key, atom, protoProto, clasp, constructor, nargs,
                                          ps, fs, static_ps, static_fs, ctorp, ctorKind);
 }
 
 void
-JSObject::getSlotRange(size_t start, size_t length,
-                       HeapValue **fixedStart, HeapValue **fixedEnd,
-                       HeapValue **slotsStart, HeapValue **slotsEnd)
-{
-    JS_ASSERT(!isDenseArray());
-    JS_ASSERT(slotInRange(start + length, SENTINEL_ALLOWED));
-
-    size_t fixed = numFixedSlots();
-    if (start < fixed) {
-        if (start + length < fixed) {
-            *fixedStart = &fixedSlots()[start];
-            *fixedEnd = &fixedSlots()[start + length];
-            *slotsStart = *slotsEnd = NULL;
-        } else {
-            size_t localCopy = fixed - start;
-            *fixedStart = &fixedSlots()[start];
-            *fixedEnd = &fixedSlots()[start + localCopy];
-            *slotsStart = &slots[0];
-            *slotsEnd = &slots[length - localCopy];
-        }
-    } else {
-        *fixedStart = *fixedEnd = NULL;
-        *slotsStart = &slots[start - fixed];
-        *slotsEnd = &slots[start - fixed + length];
-    }
-}
-
-void
 JSObject::initSlotRange(size_t start, const Value *vector, size_t length)
 {
     JSCompartment *comp = compartment();
-    HeapValue *fixedStart, *fixedEnd, *slotsStart, *slotsEnd;
+    HeapSlot *fixedStart, *fixedEnd, *slotsStart, *slotsEnd;
     getSlotRange(start, length, &fixedStart, &fixedEnd, &slotsStart, &slotsEnd);
-    for (HeapValue *vp = fixedStart; vp != fixedEnd; vp++)
-        vp->init(comp, *vector++);
-    for (HeapValue *vp = slotsStart; vp != slotsEnd; vp++)
-        vp->init(comp, *vector++);
+    for (HeapSlot *sp = fixedStart; sp != fixedEnd; sp++)
+        sp->init(comp, this, start++, *vector++);
+    for (HeapSlot *sp = slotsStart; sp != slotsEnd; sp++)
+        sp->init(comp, this, start++, *vector++);
 }
 
 void
 JSObject::copySlotRange(size_t start, const Value *vector, size_t length)
 {
     JSCompartment *comp = compartment();
-    HeapValue *fixedStart, *fixedEnd, *slotsStart, *slotsEnd;
+    HeapSlot *fixedStart, *fixedEnd, *slotsStart, *slotsEnd;
     getSlotRange(start, length, &fixedStart, &fixedEnd, &slotsStart, &slotsEnd);
-    for (HeapValue *vp = fixedStart; vp != fixedEnd; vp++)
-        vp->set(comp, *vector++);
-    for (HeapValue *vp = slotsStart; vp != slotsEnd; vp++)
-        vp->set(comp, *vector++);
+    for (HeapSlot *sp = fixedStart; sp != fixedEnd; sp++)
+        sp->set(comp, this, start++, *vector++);
+    for (HeapSlot *sp = slotsStart; sp != slotsEnd; sp++)
+        sp->set(comp, this, start++, *vector++);
 }
 
 inline void
 JSObject::invalidateSlotRange(size_t start, size_t length)
 {
 #ifdef DEBUG
     JS_ASSERT(!isDenseArray());
 
-    size_t fixed = numFixedSlots();
-
-    /* No bounds checks, allocated space has been updated but not the shape. */
-    if (start < fixed) {
-        if (start + length < fixed) {
-            Debug_SetValueRangeToCrashOnTouch(fixedSlots() + start, length);
-        } else {
-            size_t localClear = fixed - start;
-            Debug_SetValueRangeToCrashOnTouch(fixedSlots() + start, localClear);
-            Debug_SetValueRangeToCrashOnTouch(slots, length - localClear);
-        }
-    } else {
-        Debug_SetValueRangeToCrashOnTouch(slots + start - fixed, length);
-    }
+    HeapSlot *fixedStart, *fixedEnd, *slotsStart, *slotsEnd;
+    getSlotRange(start, length, &fixedStart, &fixedEnd, &slotsStart, &slotsEnd);
+    Debug_SetSlotRangeToCrashOnTouch(fixedStart, fixedEnd);
+    Debug_SetSlotRangeToCrashOnTouch(slotsStart, slotsEnd);
 #endif /* DEBUG */
 }
 
 inline bool
 JSObject::updateSlotsForSpan(JSContext *cx, size_t oldSpan, size_t newSpan)
 {
     JS_ASSERT(oldSpan != newSpan);
 
@@ -4001,34 +3962,34 @@ JSObject::growSlots(JSContext *cx, uint3
 
             type()->newScript->allocKind = kind;
             type()->newScript->shape = obj->lastProperty();
             type()->markStateChange(cx);
         }
     }
 
     if (!oldCount) {
-        slots = (HeapValue *) cx->malloc_(newCount * sizeof(HeapValue));
+        slots = (HeapSlot *) cx->malloc_(newCount * sizeof(HeapSlot));
         if (!slots)
             return false;
-        Debug_SetValueRangeToCrashOnTouch(slots, newCount);
+        Debug_SetSlotRangeToCrashOnTouch(slots, newCount);
         if (Probes::objectResizeActive())
             Probes::resizeObject(cx, this, oldSize, newSize);
         return true;
     }
 
-    HeapValue *newslots = (HeapValue*) cx->realloc_(slots, oldCount * sizeof(HeapValue),
-                                                    newCount * sizeof(HeapValue));
+    HeapSlot *newslots = (HeapSlot*) cx->realloc_(slots, oldCount * sizeof(HeapSlot),
+                                                  newCount * sizeof(HeapSlot));
     if (!newslots)
         return false;  /* Leave slots at its old size. */
 
     bool changed = slots != newslots;
     slots = newslots;
 
-    Debug_SetValueRangeToCrashOnTouch(slots + oldCount, newCount - oldCount);
+    Debug_SetSlotRangeToCrashOnTouch(slots + oldCount, newCount - oldCount);
 
     /* Changes in the slots of global objects can trigger recompilation. */
     if (changed && isGlobal())
         types::MarkObjectStateChange(cx, this);
 
     if (Probes::objectResizeActive())
         Probes::resizeObject(cx, this, oldSize, newSize);
 
@@ -4058,17 +4019,17 @@ JSObject::shrinkSlots(JSContext *cx, uin
         slots = NULL;
         if (Probes::objectResizeActive())
             Probes::resizeObject(cx, this, oldSize, newSize);
         return;
     }
 
     JS_ASSERT(newCount >= SLOT_CAPACITY_MIN);
 
-    HeapValue *newslots = (HeapValue*) cx->realloc_(slots, newCount * sizeof(HeapValue));
+    HeapSlot *newslots = (HeapSlot *) cx->realloc_(slots, newCount * sizeof(HeapSlot));
     if (!newslots)
         return;  /* Leave slots at its old size. */
 
     bool changed = slots != newslots;
     slots = newslots;
 
     /* Watch for changes in global object slots, as for growSlots. */
     if (changed && isGlobal())
@@ -4131,17 +4092,17 @@ JSObject::growElements(JSContext *cx, ui
             return false;  /* Ditto. */
         js_memcpy(newheader, getElementsHeader(),
                   (ObjectElements::VALUES_PER_HEADER + initlen) * sizeof(Value));
     }
 
     newheader->capacity = actualCapacity;
     elements = newheader->elements();
 
-    Debug_SetValueRangeToCrashOnTouch(elements + initlen, actualCapacity - initlen);
+    Debug_SetSlotRangeToCrashOnTouch(elements + initlen, actualCapacity - initlen);
 
     if (Probes::objectResizeActive())
         Probes::resizeObject(cx, this, oldSize, computedSizeOfThisSlotsElements());
 
     return true;
 }
 
 void
@@ -6533,18 +6494,16 @@ js_DumpStackFrame(JSContext *cx, StackFr
         } else {
             fprintf(stderr, "dummy frame");
         }
         fputc('\n', stderr);
 
         fprintf(stderr, "  flags:");
         if (fp->isConstructing())
             fprintf(stderr, " constructing");
-        if (fp->hasOverriddenArgs())
-            fprintf(stderr, " overridden_args");
         if (fp->isDebuggerFrame())
             fprintf(stderr, " debugger");
         if (fp->isEvalFrame())
             fprintf(stderr, " eval");
         if (fp->isYielding())
             fprintf(stderr, " yielding");
         if (fp->isGeneratorFrame())
             fprintf(stderr, " generator");
--- a/js/src/jsobj.h
+++ b/js/src/jsobj.h
@@ -429,17 +429,17 @@ struct JSObject : public js::ObjectImpl
     /* As above, but does not change the slot span. */
     inline void setLastPropertyInfallible(const js::Shape *shape);
 
     /* Make a non-array object with the specified initial state. */
     static inline JSObject *create(JSContext *cx,
                                    js::gc::AllocKind kind,
                                    js::HandleShape shape,
                                    js::HandleTypeObject type,
-                                   js::HeapValue *slots);
+                                   js::HeapSlot *slots);
 
     /* Make a dense array object with the specified initial state. */
     static inline JSObject *createDenseArray(JSContext *cx,
                                              js::gc::AllocKind kind,
                                              js::HandleShape shape,
                                              js::HandleTypeObject type,
                                              uint32_t length);
 
@@ -541,31 +541,34 @@ struct JSObject : public js::ObjectImpl
 
     static const uint32_t MAX_FIXED_SLOTS = 16;
 
   private:
     /*
      * Get internal pointers to the range of values starting at start and
      * running for length.
      */
-    void getSlotRange(size_t start, size_t length,
-                      js::HeapValue **fixedStart, js::HeapValue **fixedEnd,
-                      js::HeapValue **slotsStart, js::HeapValue **slotsEnd);
+    inline void getSlotRangeUnchecked(size_t start, size_t length,
+                                      js::HeapSlot **fixedStart, js::HeapSlot **fixedEnd,
+                                      js::HeapSlot **slotsStart, js::HeapSlot **slotsEnd);
+    inline void getSlotRange(size_t start, size_t length,
+                             js::HeapSlot **fixedStart, js::HeapSlot **fixedEnd,
+                             js::HeapSlot **slotsStart, js::HeapSlot **slotsEnd);
   public:
 
     /* Accessors for properties. */
 
     /* Whether a slot is at a fixed offset from this object. */
     inline bool isFixedSlot(size_t slot);
 
     /* Index into the dynamic slots array to use for a dynamic slot. */
     inline size_t dynamicSlotIndex(size_t slot);
 
     /* Get a raw pointer to the object's properties. */
-    inline const js::HeapValue *getRawSlots();
+    inline const js::HeapSlot *getRawSlots();
 
     /*
      * Grow or shrink slots immediately before changing the slot span.
      * The number of allocated slots is not stored explicitly, and changes to
      * the slots must track changes in the slot span.
      */
     bool growSlots(JSContext *cx, uint32_t oldCount, uint32_t newCount);
     void shrinkSlots(JSContext *cx, uint32_t oldCount, uint32_t newCount);
@@ -615,39 +618,41 @@ struct JSObject : public js::ObjectImpl
 
     /*
      * Check that slot is in range for the object's allocated slots.
      * If sentinelAllowed then slot may equal the slot capacity.
      */
     bool slotInRange(uintN slot, SentinelAllowed sentinel = SENTINEL_NOT_ALLOWED) const;
 #endif
 
-    js::HeapValue *getSlotAddressUnchecked(uintN slot) {
+  private:
+    js::HeapSlot *getSlotAddressUnchecked(uintN slot) {
         size_t fixed = numFixedSlots();
         if (slot < fixed)
             return fixedSlots() + slot;
         return slots + (slot - fixed);
     }
 
-    js::HeapValue *getSlotAddress(uintN slot) {
+  public:
+    js::HeapSlot *getSlotAddress(uintN slot) {
         /*
          * This can be used to get the address of the end of the slots for the
          * object, which may be necessary when fetching zero-length arrays of
          * slots (e.g. for callObjVarArray).
          */
         JS_ASSERT(slotInRange(slot, SENTINEL_ALLOWED));
         return getSlotAddressUnchecked(slot);
     }
 
-    js::HeapValue &getSlotRef(uintN slot) {
+    js::HeapSlot &getSlotRef(uintN slot) {
         JS_ASSERT(slotInRange(slot));
         return *getSlotAddress(slot);
     }
 
-    inline js::HeapValue &nativeGetSlotRef(uintN slot);
+    inline js::HeapSlot &nativeGetSlotRef(uintN slot);
 
     const js::Value &getSlot(uintN slot) const {
         JS_ASSERT(slotInRange(slot));
         size_t fixed = numFixedSlots();
         if (slot < fixed)
             return fixedSlots()[slot];
         return slots[slot - fixed];
     }
@@ -658,22 +663,23 @@ struct JSObject : public js::ObjectImpl
     inline void setSlot(uintN slot, const js::Value &value);
     inline void initSlot(uintN slot, const js::Value &value);
     inline void initSlotUnchecked(uintN slot, const js::Value &value);
 
     inline void nativeSetSlot(uintN slot, const js::Value &value);
     inline void nativeSetSlotWithType(JSContext *cx, const js::Shape *shape, const js::Value &value);
 
     inline const js::Value &getReservedSlot(uintN index) const;
-    inline js::HeapValue &getReservedSlotRef(uintN index);
+    inline js::HeapSlot &getReservedSlotRef(uintN index);
+    inline void initReservedSlot(uintN index, const js::Value &v);
     inline void setReservedSlot(uintN index, const js::Value &v);
 
     /* For slots which are known to always be fixed, due to the way they are allocated. */
 
-    js::HeapValue &getFixedSlotRef(uintN slot) {
+    js::HeapSlot &getFixedSlotRef(uintN slot) {
         JS_ASSERT(slot < numFixedSlots());
         return fixedSlots()[slot];
     }
 
     const js::Value &getFixedSlot(uintN slot) const {
         JS_ASSERT(slot < numFixedSlots());
         return fixedSlots()[slot];
     }
@@ -829,17 +835,17 @@ struct JSObject : public js::ObjectImpl
     inline uint32_t getArrayLength() const;
     inline void setArrayLength(JSContext *cx, uint32_t length);
 
     inline uint32_t getDenseArrayCapacity();
     inline uint32_t getDenseArrayInitializedLength();
     inline void setDenseArrayLength(uint32_t length);
     inline void setDenseArrayInitializedLength(uint32_t length);
     inline void ensureDenseArrayInitializedLength(JSContext *cx, uintN index, uintN extra);
-    inline js::HeapValueArray getDenseArrayElements();
+    inline js::HeapSlotArray getDenseArrayElements();
     inline const js::Value &getDenseArrayElement(uintN idx);
     inline void setDenseArrayElement(uintN idx, const js::Value &val);
     inline void initDenseArrayElement(uintN idx, const js::Value &val);
     inline void setDenseArrayElementWithType(JSContext *cx, uintN idx, const js::Value &val);
     inline void initDenseArrayElementWithType(JSContext *cx, uintN idx, const js::Value &val);
     inline void copyDenseArrayElements(uintN dstStart, const js::Value *src, uintN count);
     inline void initDenseArrayElements(uintN dstStart, const js::Value *src, uintN count);
     inline void moveDenseArrayElements(uintN dstStart, uintN srcStart, uintN count);
--- a/js/src/jsobjinlines.h
+++ b/js/src/jsobjinlines.h
@@ -96,17 +96,17 @@ JSObject::privateRef(uint32_t nfixed) co
 {
     /*
      * The private pointer of an object can hold any word sized value.
      * Private pointers are stored immediately after the last fixed slot of
      * the object.
      */
     JS_ASSERT(nfixed == numFixedSlots());
     JS_ASSERT(hasPrivate());
-    js::HeapValue *end = &fixedSlots()[nfixed];
+    js::HeapSlot *end = &fixedSlots()[nfixed];
     return *reinterpret_cast<void**>(end);
 }
 
 inline void *
 JSObject::getPrivate() const { return privateRef(numFixedSlots()); }
 
 inline void *
 JSObject::getPrivate(size_t nfixed) const { return privateRef(nfixed); }
@@ -401,69 +401,76 @@ JSObject::canRemoveLastProperty()
      * converted to dictionary mode instead. See BaseShape comment in jsscope.h
      */
     JS_ASSERT(!inDictionaryMode());
     const js::Shape *previous = lastProperty()->previous();
     return previous->getObjectParent() == lastProperty()->getObjectParent()
         && previous->getObjectFlags() == lastProperty()->getObjectFlags();
 }
 
-inline const js::HeapValue *
+inline const js::HeapSlot *
 JSObject::getRawSlots()
 {
     JS_ASSERT(isGlobal());
     return slots;
 }
 
 inline const js::Value &
 JSObject::getReservedSlot(uintN index) const
 {
     JS_ASSERT(index < JSSLOT_FREE(getClass()));
     return getSlot(index);
 }
 
-inline js::HeapValue &
+inline js::HeapSlot &
 JSObject::getReservedSlotRef(uintN index)
 {
     JS_ASSERT(index < JSSLOT_FREE(getClass()));
     return getSlotRef(index);
 }
 
 inline void
 JSObject::setReservedSlot(uintN index, const js::Value &v)
 {
     JS_ASSERT(index < JSSLOT_FREE(getClass()));
     setSlot(index, v);
 }
 
+inline void
+JSObject::initReservedSlot(uintN index, const js::Value &v)
+{
+    JS_ASSERT(index < JSSLOT_FREE(getClass()));
+    initSlot(index, v);
+}
+
 inline bool
 JSObject::hasContiguousSlots(size_t start, size_t count) const
 {
     /*
      * Check that the range [start, start+count) is either all inline or all
      * out of line.
      */
     JS_ASSERT(slotInRange(start + count, SENTINEL_ALLOWED));
     return (start + count <= numFixedSlots()) || (start >= numFixedSlots());
 }
 
 inline void
 JSObject::prepareSlotRangeForOverwrite(size_t start, size_t end)
 {
     for (size_t i = start; i < end; i++)
-        getSlotAddressUnchecked(i)->js::HeapValue::~HeapValue();
+        getSlotAddressUnchecked(i)->js::HeapSlot::~HeapSlot();
 }
 
 inline void
 JSObject::prepareElementRangeForOverwrite(size_t start, size_t end)
 {
     JS_ASSERT(isDenseArray());
     JS_ASSERT(end <= getDenseArrayInitializedLength());
     for (size_t i = start; i < end; i++)
-        elements[i].js::HeapValue::~HeapValue();
+        elements[i].js::HeapSlot::~HeapSlot();
 }
 
 inline uint32_t
 JSObject::getArrayLength() const
 {
     JS_ASSERT(isArray());
     return getElementsHeader()->length;
 }
@@ -524,42 +531,42 @@ JSObject::getDenseArrayCapacity()
 inline bool
 JSObject::ensureElements(JSContext *cx, uint32_t capacity)
 {
     if (capacity > getDenseArrayCapacity())
         return growElements(cx, capacity);
     return true;
 }
 
-inline js::HeapValueArray
+inline js::HeapSlotArray
 JSObject::getDenseArrayElements()
 {
     JS_ASSERT(isDenseArray());
-    return js::HeapValueArray(elements);
+    return js::HeapSlotArray(elements);
 }
 
 inline const js::Value &
 JSObject::getDenseArrayElement(uintN idx)
 {
     JS_ASSERT(isDenseArray() && idx < getDenseArrayInitializedLength());
     return elements[idx];
 }
 
 inline void
 JSObject::setDenseArrayElement(uintN idx, const js::Value &val)
 {
     JS_ASSERT(isDenseArray() && idx < getDenseArrayInitializedLength());
-    elements[idx] = val;
+    elements[idx].set(this, idx, val);
 }
 
 inline void
 JSObject::initDenseArrayElement(uintN idx, const js::Value &val)
 {
     JS_ASSERT(isDenseArray() && idx < getDenseArrayInitializedLength());
-    elements[idx].init(val);
+    elements[idx].init(this, idx, val);
 }
 
 inline void
 JSObject::setDenseArrayElementWithType(JSContext *cx, uintN idx, const js::Value &val)
 {
     js::types::AddTypePropertyId(cx, this, JSID_VOID, val);
     setDenseArrayElement(idx, val);
 }
@@ -572,26 +579,26 @@ JSObject::initDenseArrayElementWithType(
 }
 
 inline void
 JSObject::copyDenseArrayElements(uintN dstStart, const js::Value *src, uintN count)
 {
     JS_ASSERT(dstStart + count <= getDenseArrayCapacity());
     JSCompartment *comp = compartment();
     for (unsigned i = 0; i < count; ++i)
-        elements[dstStart + i].set(comp, src[i]);
+        elements[dstStart + i].set(comp, this, dstStart + i, src[i]);
 }
 
 inline void
 JSObject::initDenseArrayElements(uintN dstStart, const js::Value *src, uintN count)
 {
     JS_ASSERT(dstStart + count <= getDenseArrayCapacity());
     JSCompartment *comp = compartment();
     for (unsigned i = 0; i < count; ++i)
-        elements[dstStart + i].init(comp, src[i]);
+        elements[dstStart + i].init(comp, this, dstStart + i, src[i]);
 }
 
 inline void
 JSObject::moveDenseArrayElements(uintN dstStart, uintN srcStart, uintN count)
 {
     JS_ASSERT(dstStart + count <= getDenseArrayCapacity());
     JS_ASSERT(srcStart + count <= getDenseArrayInitializedLength());
 
@@ -602,30 +609,31 @@ JSObject::moveDenseArrayElements(uintN d
      * 1. Incremental GC marks slot 0 of array (i.e., A), then returns to JS code.
      * 2. JS code moves slots 1..2 into slots 0..1, so it contains [B, C, C].
      * 3. Incremental GC finishes by marking slots 1 and 2 (i.e., C).
      *
      * Since normal marking never happens on B, it is very important that the
      * write barrier is invoked here on B, despite the fact that it exists in
      * the array before and after the move.
     */
-    if (compartment()->needsBarrier()) {
+    JSCompartment *comp = compartment();
+    if (comp->needsBarrier()) {
         if (dstStart < srcStart) {
-            js::HeapValue *dst = elements + dstStart;
-            js::HeapValue *src = elements + srcStart;
+            js::HeapSlot *dst = elements + dstStart;
+            js::HeapSlot *src = elements + srcStart;
             for (unsigned i = 0; i < count; i++, dst++, src++)
-                *dst = *src;
+                dst->set(comp, this, dst - elements, *src);
         } else {
-            js::HeapValue *dst = elements + dstStart + count - 1;
-            js::HeapValue *src = elements + srcStart + count - 1;
+            js::HeapSlot *dst = elements + dstStart + count - 1;
+            js::HeapSlot *src = elements + srcStart + count - 1;
             for (unsigned i = 0; i < count; i++, dst--, src--)
-                *dst = *src;
+                dst->set(comp, this, dst - elements, *src);
         }
     } else {
-        memmove(elements + dstStart, elements + srcStart, count * sizeof(js::Value));
+        memmove(elements + dstStart, elements + srcStart, count * sizeof(js::HeapSlot));
     }
 }
 
 inline void
 JSObject::moveDenseArrayElementsUnbarriered(uintN dstStart, uintN srcStart, uintN count)
 {
     JS_ASSERT(!compartment()->needsBarrier());
 
@@ -966,40 +974,72 @@ inline bool
 JSObject::isQName() const
 {
     return hasClass(&js::QNameClass)
         || hasClass(&js::AttributeNameClass)
         || hasClass(&js::AnyNameClass);
 }
 
 inline void
+JSObject::getSlotRangeUnchecked(size_t start, size_t length,
+                                js::HeapSlot **fixedStart, js::HeapSlot **fixedEnd,
+                                js::HeapSlot **slotsStart, js::HeapSlot **slotsEnd)
+{
+    JS_ASSERT(!isDenseArray());
+
+    size_t fixed = numFixedSlots();
+    if (start < fixed) {
+        if (start + length < fixed) {
+            *fixedStart = &fixedSlots()[start];
+            *fixedEnd = &fixedSlots()[start + length];
+            *slotsStart = *slotsEnd = NULL;
+        } else {
+            size_t localCopy = fixed - start;
+            *fixedStart = &fixedSlots()[start];
+            *fixedEnd = &fixedSlots()[start + localCopy];
+            *slotsStart = &slots[0];
+            *slotsEnd = &slots[length - localCopy];
+        }
+    } else {
+        *fixedStart = *fixedEnd = NULL;
+        *slotsStart = &slots[start - fixed];
+        *slotsEnd = &slots[start - fixed + length];
+    }
+}
+
+inline void
+JSObject::getSlotRange(size_t start, size_t length,
+                       js::HeapSlot **fixedStart, js::HeapSlot **fixedEnd,
+                       js::HeapSlot **slotsStart, js::HeapSlot **slotsEnd)
+{
+    JS_ASSERT(slotInRange(start + length, SENTINEL_ALLOWED));
+    getSlotRangeUnchecked(start, length, fixedStart, fixedEnd, slotsStart, slotsEnd);
+}
+
+inline void
 JSObject::initializeSlotRange(size_t start, size_t length)
 {
     /*
      * No bounds check, as this is used when the object's shape does not
      * reflect its allocated slots (updateSlotsForSpan).
      */
-    JS_ASSERT(!isDenseArray());
-    size_t fixed = numFixedSlots();
-    if (start < fixed) {
-        if (start + length < fixed) {
-            js::InitValueRange(fixedSlots() + start, length, false);
-        } else {
-            size_t localClear = fixed - start;
-            js::InitValueRange(fixedSlots() + start, localClear, false);
-            js::InitValueRange(slots, length - localClear, false);
-        }
-    } else {
-        js::InitValueRange(slots + start - fixed, length, false);
-    }
+    js::HeapSlot *fixedStart, *fixedEnd, *slotsStart, *slotsEnd;
+    getSlotRangeUnchecked(start, length, &fixedStart, &fixedEnd, &slotsStart, &slotsEnd);
+
+    JSCompartment *comp = compartment();
+    size_t offset = start;
+    for (js::HeapSlot *sp = fixedStart; sp != fixedEnd; sp++)
+        sp->init(comp, this, offset++, js::UndefinedValue());
+    for (js::HeapSlot *sp = slotsStart; sp != slotsEnd; sp++)
+        sp->init(comp, this, offset++, js::UndefinedValue());
 }
 
 /* static */ inline JSObject *
 JSObject::create(JSContext *cx, js::gc::AllocKind kind,
-                 js::HandleShape shape, js::HandleTypeObject type, js::HeapValue *slots)
+                 js::HandleShape shape, js::HandleTypeObject type, js::HeapSlot *slots)
 {
     /*
      * Callers must use dynamicSlotsCount to size the initial slot array of the
      * object. We can't check the allocated capacity of the dynamic slots, but
      * make sure their presence is consistent with the shape.
      */
     JS_ASSERT(shape && type);
     JS_ASSERT(!!dynamicSlotsCount(shape->numFixedSlots(), shape->slotSpan()) == !!slots);
@@ -1097,17 +1137,17 @@ JSObject::principals(JSContext *cx)
 inline uint32_t
 JSObject::slotSpan() const
 {
     if (inDictionaryMode())
         return lastProperty()->base()->slotSpan();
     return lastProperty()->slotSpan();
 }
 
-inline js::HeapValue &
+inline js::HeapSlot &
 JSObject::nativeGetSlotRef(uintN slot)
 {
     JS_ASSERT(isNative());
     JS_ASSERT(slot < slotSpan());
     return getSlotRef(slot);
 }
 
 inline const js::Value &
@@ -1339,17 +1379,17 @@ JSObject::getSpecial(JSContext *cx, JSOb
 {
     return getGeneric(cx, receiver, SPECIALID_TO_JSID(sid), vp);
 }
 
 inline JSBool
 JSObject::getGenericAttributes(JSContext *cx, jsid id, uintN *attrsp)
 {
     js::GenericAttributesOp op = getOps()->getGenericAttributes;
-    return (op ? op : js_GetAttributes)(cx, this, id, attrsp);    
+    return (op ? op : js_GetAttributes)(cx, this, id, attrsp);
 }
 
 inline JSBool
 JSObject::getPropertyAttributes(JSContext *cx, js::PropertyName *name, uintN *attrsp)
 {
     return getGenericAttributes(cx, ATOM_TO_JSID(name), attrsp);
 }
 
@@ -1808,23 +1848,23 @@ NewObjectGCKind(JSContext *cx, js::Class
     return gc::FINALIZE_OBJECT4;
 }
 
 /*
  * Fill slots with the initial slot array to use for a newborn object which
  * may or may not need dynamic slots.
  */
 inline bool
-PreallocateObjectDynamicSlots(JSContext *cx, Shape *shape, HeapValue **slots)
+PreallocateObjectDynamicSlots(JSContext *cx, Shape *shape, HeapSlot **slots)
 {
     if (size_t count = JSObject::dynamicSlotsCount(shape->numFixedSlots(), shape->slotSpan())) {
-        *slots = (HeapValue *) cx->malloc_(count * sizeof(HeapValue));
+        *slots = (HeapSlot *) cx->malloc_(count * sizeof(HeapSlot));
         if (!*slots)
             return false;
-        Debug_SetValueRangeToCrashOnTouch(*slots, count);
+        Debug_SetSlotRangeToCrashOnTouch(*slots, count);
         return true;
     }
     *slots = NULL;
     return true;
 }
 
 inline bool
 DefineConstructorAndPrototype(JSContext *cx, GlobalObject *global,
@@ -1964,40 +2004,40 @@ js_PurgeScopeChain(JSContext *cx, JSObje
         return js_PurgeScopeChainHelper(cx, obj, id);
     return true;
 }
 
 inline void
 JSObject::setSlot(uintN slot, const js::Value &value)
 {
     JS_ASSERT(slotInRange(slot));
-    getSlotRef(slot).set(compartment(), value);
+    getSlotRef(slot).set(this, slot, value);
 }
 
 inline void
 JSObject::initSlot(uintN slot, const js::Value &value)
 {
     JS_ASSERT(getSlot(slot).isUndefined() || getSlot(slot).isMagic(JS_ARRAY_HOLE));
     JS_ASSERT(slotInRange(slot));
     initSlotUnchecked(slot, value);
 }
 
 inline void
 JSObject::initSlotUnchecked(uintN slot, const js::Value &value)
 {
-    getSlotAddressUnchecked(slot)->init(value);
+    getSlotAddressUnchecked(slot)->init(this, slot, value);
 }
 
 inline void
 JSObject::setFixedSlot(uintN slot, const js::Value &value)
 {
     JS_ASSERT(slot < numFixedSlots());
-    fixedSlots()[slot] = value;
+    fixedSlots()[slot].set(this, slot, value);
 }
 
 inline void
 JSObject::initFixedSlot(uintN slot, const js::Value &value)
 {
     JS_ASSERT(slot < numFixedSlots());
-    fixedSlots()[slot].init(value);
+    fixedSlots()[slot].init(this, slot, value);
 }
 
 #endif /* jsobjinlines_h___ */
--- a/js/src/jsproxy.cpp
+++ b/js/src/jsproxy.cpp
@@ -54,32 +54,32 @@
 
 #include "jsatominlines.h"
 #include "jsinferinlines.h"
 #include "jsobjinlines.h"
 
 using namespace js;
 using namespace js::gc;
 
-static inline HeapValue &
+static inline HeapSlot &
 GetCall(JSObject *proxy)
 {
     JS_ASSERT(IsFunctionProxy(proxy));
     return proxy->getSlotRef(JSSLOT_PROXY_CALL);
 }
 
 static inline Value
 GetConstruct(JSObject *proxy)
 {
     if (proxy->slotSpan() <= JSSLOT_PROXY_CONSTRUCT)
         return UndefinedValue();
     return proxy->getSlot(JSSLOT_PROXY_CONSTRUCT);
 }
 
-static inline HeapValue &
+static inline HeapSlot &
 GetFunctionProxyConstruct(JSObject *proxy)
 {
     JS_ASSERT(IsFunctionProxy(proxy));
     JS_ASSERT(proxy->slotSpan() > JSSLOT_PROXY_CONSTRUCT);
     return proxy->getSlotRef(JSSLOT_PROXY_CONSTRUCT);
 }
 
 static bool
@@ -1243,31 +1243,31 @@ proxy_DeleteSpecial(JSContext *cx, JSObj
 {
     return proxy_DeleteGeneric(cx, obj, SPECIALID_TO_JSID(sid), rval, strict);
 }
 
 static void
 proxy_TraceObject(JSTracer *trc, JSObject *obj)
 {
     GetProxyHandler(obj)->trace(trc, obj);
-    MarkCrossCompartmentValue(trc, &obj->getReservedSlotRef(JSSLOT_PROXY_PRIVATE), "private");
-    MarkCrossCompartmentValue(trc, &obj->getReservedSlotRef(JSSLOT_PROXY_EXTRA + 0), "extra0");
-    MarkCrossCompartmentValue(trc, &obj->getReservedSlotRef(JSSLOT_PROXY_EXTRA + 1), "extra1");
+    MarkCrossCompartmentSlot(trc, &obj->getReservedSlotRef(JSSLOT_PROXY_PRIVATE), "private");
+    MarkCrossCompartmentSlot(trc, &obj->getReservedSlotRef(JSSLOT_PROXY_EXTRA + 0), "extra0");
+    MarkCrossCompartmentSlot(trc, &obj->getReservedSlotRef(JSSLOT_PROXY_EXTRA + 1), "extra1");
     if (IsFunctionProxy(obj)) {
-        MarkCrossCompartmentValue(trc, &GetCall(obj), "call");
-        MarkCrossCompartmentValue(trc, &GetFunctionProxyConstruct(obj), "construct");
+        MarkCrossCompartmentSlot(trc, &GetCall(obj), "call");
+        MarkCrossCompartmentSlot(trc, &GetFunctionProxyConstruct(obj), "construct");
     }
 }
 
 static void
 proxy_TraceFunction(JSTracer *trc, JSObject *obj)
 {
     proxy_TraceObject(trc, obj);
-    MarkCrossCompartmentValue(trc, &GetCall(obj), "call");
-    MarkCrossCompartmentValue(trc, &GetFunctionProxyConstruct(obj), "construct");
+    MarkCrossCompartmentSlot(trc, &GetCall(obj), "call");
+    MarkCrossCompartmentSlot(trc, &GetFunctionProxyConstruct(obj), "construct");
 }
 
 static JSBool
 proxy_Convert(JSContext *cx, JSObject *proxy, JSType hint, Value *vp)
 {
     JS_ASSERT(proxy->isProxy());
     return Proxy::defaultValue(cx, proxy, hint, vp);
 }
--- a/js/src/jsscript.cpp
+++ b/js/src/jsscript.cpp
@@ -93,19 +93,19 @@ Bindings::lookup(JSContext *cx, JSAtom *
     Shape **spp;
     Shape *shape = Shape::search(cx, lastBinding, ATOM_TO_JSID(name), &spp);
     if (!shape)
         return NONE;
 
     if (indexp)
         *indexp = shape->shortid();
 
-    if (shape->getter() == GetCallArg)
+    if (shape->getter() == CallObject::getArgOp)
         return ARGUMENT;
-    if (shape->getter() == GetCallUpvar)
+    if (shape->getter() == CallObject::getUpvarOp)
         return UPVAR;
 
     return shape->writable() ? VARIABLE : CONSTANT;
 }
 
 bool
 Bindings::add(JSContext *cx, JSAtom *name, BindingKind kind)
 {
@@ -123,32 +123,32 @@ Bindings::add(JSContext *cx, JSAtom *nam
     PropertyOp getter;
     StrictPropertyOp setter;
     uint32_t slot = CallObject::RESERVED_SLOTS;
 
     if (kind == ARGUMENT) {
         JS_ASSERT(nvars == 0);
         JS_ASSERT(nupvars == 0);
         indexp = &nargs;
-        getter = GetCallArg;
-        setter = SetCallArg;
+        getter = CallObject::getArgOp;
+        setter = CallObject::setArgOp;
         slot += nargs;
     } else if (kind == UPVAR) {
         indexp = &nupvars;
-        getter = GetCallUpvar;
-        setter = SetCallUpvar;
+        getter = CallObject::getUpvarOp;
+        setter = CallObject::setUpvarOp;
         slot = lastBinding->maybeSlot();
         attrs |= JSPROP_SHARED;
     } else {
         JS_ASSERT(kind == VARIABLE || kind == CONSTANT);
         JS_ASSERT(nupvars == 0);
 
         indexp = &nvars;
-        getter = GetCallVar;
-        setter = SetCallVar;
+        getter = CallObject::getVarOp;
+        setter = CallObject::setVarOp;
         if (kind == CONSTANT)
             attrs |= JSPROP_READONLY;
         slot += nargs + nvars;
     }
 
     if (*indexp == BINDING_COUNT_LIMIT) {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
                              (kind == ARGUMENT)
@@ -243,31 +243,31 @@ Bindings::getLocalNameArray(JSContext *c
     for (uintN i = 0; i < n; i++)
         names[i] = POISON;
 #endif
 
     for (Shape::Range r = lastBinding->all(); !r.empty(); r.popFront()) {
         const Shape &shape = r.front();
         uintN index = uint16_t(shape.shortid());
 
-        if (shape.getter() == GetCallArg) {
+        if (shape.getter() == CallObject::getArgOp) {
             JS_ASSERT(index < nargs);
-        } else if (shape.getter() == GetCallUpvar) {
+        } else if (shape.getter() == CallObject::getUpvarOp) {
             JS_ASSERT(index < nupvars);
             index += nargs + nvars;
         } else {
             JS_ASSERT(index < nvars);
             index += nargs;
         }
 
         if (JSID_IS_ATOM(shape.propid())) {
             names[index] = JSID_TO_ATOM(shape.propid());
         } else {
             JS_ASSERT(JSID_IS_INT(shape.propid()));
-            JS_ASSERT(shape.getter() == GetCallArg);
+            JS_ASSERT(shape.getter() == CallObject::getArgOp);
             names[index] = NULL;
         }
     }
 
 #ifdef DEBUG
     for (uintN i = 0; i < n; i++)
         JS_ASSERT(names[i] != POISON);
 #endif
@@ -277,30 +277,30 @@ Bindings::getLocalNameArray(JSContext *c
 
 const Shape *
 Bindings::lastArgument() const
 {
     JS_ASSERT(lastBinding);
 
     const js::Shape *shape = lastVariable();
     if (nvars > 0) {
-        while (shape->previous() && shape->getter() != GetCallArg)
+        while (shape->previous() && shape->getter() != CallObject::getArgOp)
             shape = shape->previous();
     }
     return shape;
 }
 
 const Shape *
 Bindings::lastVariable() const
 {
     JS_ASSERT(lastBinding);
 
     const js::Shape *shape = lastUpvar();
     if (nupvars > 0) {
-        while (shape->getter() == GetCallUpvar)
+        while (shape->getter() == CallObject::getUpvarOp)
             shape = shape->previous();
     }
     return shape;
 }
 
 const Shape *
 Bindings::lastUpvar() const
 {
@@ -1428,32 +1428,32 @@ JSScript::numNotes()
         continue;
     return sn - notes_ + 1;    /* +1 for the terminator */
 }
 
 JS_FRIEND_API(void)
 js_CallNewScriptHook(JSContext *cx, JSScript *script, JSFunction *fun)
 {
     JS_ASSERT(!script->callDestroyHook);
-    if (JSNewScriptHook hook = cx->debugHooks->newScriptHook) {
+    if (JSNewScriptHook hook = cx->runtime->debugHooks.newScriptHook) {
         AutoKeepAtoms keep(cx->runtime);
         hook(cx, script->filename, script->lineno, script, fun,
-             cx->debugHooks->newScriptHookData);
+             cx->runtime->debugHooks.newScriptHookData);
     }
     script->callDestroyHook = true;
 }
 
 void
 js_CallDestroyScriptHook(JSContext *cx, JSScript *script)
 {
     if (!script->callDestroyHook)
         return;
 
-    if (JSDestroyScriptHook hook = cx->debugHooks->destroyScriptHook)
-        hook(cx, script, cx->debugHooks->destroyScriptHookData);
+    if (JSDestroyScriptHook hook = cx->runtime->debugHooks.destroyScriptHook)
+        hook(cx, script, cx->runtime->debugHooks.destroyScriptHookData);
     script->callDestroyHook = false;
     JS_ClearScriptTraps(cx, script);
 }
 
 void
 JSScript::finalize(JSContext *cx, bool background)
 {
     CheckScript(this, NULL);
--- a/js/src/jstypedarray.cpp
+++ b/js/src/jstypedarray.cpp
@@ -1094,17 +1094,17 @@ class TypedArrayTemplate
     static inline Class *fastClass()
     {
         return &TypedArray::fastClasses[ArrayTypeID()];
     }
 
     static void
     obj_trace(JSTracer *trc, JSObject *obj)
     {
-        MarkValue(trc, &obj->getFixedSlotRef(FIELD_BUFFER), "typedarray.buffer");
+        MarkSlot(trc, &obj->getFixedSlotRef(FIELD_BUFFER), "typedarray.buffer");
     }
 
     static JSBool
     obj_getProperty(JSContext *cx, JSObject *obj, JSObject *receiver, PropertyName *name,
                     Value *vp)
     {
         JSObject *tarray = getTypedArray(obj);
 
--- a/js/src/jsval.h
+++ b/js/src/jsval.h
@@ -281,16 +281,17 @@ typedef enum JSWhyMagic
                                   * enumerated like a native object. */
     JS_NO_ITER_VALUE,            /* there is not a pending iterator value */
     JS_GENERATOR_CLOSING,        /* exception value thrown when closing a generator */
     JS_NO_CONSTANT,              /* compiler sentinel value */
     JS_THIS_POISON,              /* used in debug builds to catch tracing errors */
     JS_ARG_POISON,               /* used in debug builds to catch tracing errors */
     JS_SERIALIZE_NO_NODE,        /* an empty subnode in the AST serializer */
     JS_LAZY_ARGUMENTS,           /* lazy arguments value on the stack */
+    JS_UNASSIGNED_ARGUMENTS,     /* the initial value of callobj.arguments */
     JS_IS_CONSTRUCTING,          /* magic value passed to natives to indicate construction */
     JS_GENERIC_MAGIC             /* for local use */
 } JSWhyMagic;
 
 #if defined(IS_LITTLE_ENDIAN)
 # if JS_BITS_PER_WORD == 32
 typedef union jsval_layout
 {
--- a/js/src/jsweakmap.cpp
+++ b/js/src/jsweakmap.cpp
@@ -97,16 +97,40 @@ WeakMapBase::resetWeakMapList(JSRuntime 
     rt->gcWeakMapList = NULL;
     while (m) {
         WeakMapBase *n = m->next;
         m->next = WeakMapNotInList;
         m = n;
     }
 }
 
+bool
+WeakMapBase::saveWeakMapList(JSRuntime *rt, WeakMapVector &vector)
+{
+    WeakMapBase *m = rt->gcWeakMapList;
+    while (m) {
+        if (!vector.append(m))
+            return false;
+        m = m->next;
+    }
+    return true;
+}
+
+void
+WeakMapBase::restoreWeakMapList(JSRuntime *rt, WeakMapVector &vector)
+{
+    JS_ASSERT(!rt->gcWeakMapList);
+    for (WeakMapBase **p = vector.begin(); p != vector.end(); p++) {
+        WeakMapBase *m = *p;
+        JS_ASSERT(m->next == WeakMapNotInList);
+        m->next = rt->gcWeakMapList;
+        rt->gcWeakMapList = m;
+    }
+}
+
 } /* namespace js */
 
 typedef WeakMap<HeapPtr<JSObject>, HeapValue> ObjectValueMap;
 
 static ObjectValueMap *
 GetObjectMap(JSObject *obj)
 {
     JS_ASSERT(obj->isWeakMap());
--- a/js/src/jsweakmap.h
+++ b/js/src/jsweakmap.h
@@ -104,16 +104,18 @@ template <class Type> class DefaultMarkP
 
 // A policy template holding default tracing algorithms for common type combinations. This
 // provides default types for WeakMap's TracePolicy template parameter.
 template <class Key, class Value> class DefaultTracePolicy;
 
 // The value for the next pointer for maps not in the map list.
 static WeakMapBase * const WeakMapNotInList = reinterpret_cast<WeakMapBase *>(1);
 
+typedef Vector<WeakMapBase *, 0, SystemAllocPolicy> WeakMapVector;
+
 // Common base class for all WeakMap specializations. The collector uses this to call
 // their markIteratively and sweep methods.
 class WeakMapBase {
   public:
     WeakMapBase(JSObject *memOf) : memberOf(memOf), next(WeakMapNotInList) { }
     virtual ~WeakMapBase() { }
 
     void trace(JSTracer *tracer) {
@@ -156,16 +158,20 @@ class WeakMapBase {
     // Trace all delayed weak map bindings. Used by the cycle collector.
     static void traceAllMappings(WeakMapTracer *tracer);
 
     void check() { JS_ASSERT(next == WeakMapNotInList); }
 
     // Remove everything from the live weak map list.
     static void resetWeakMapList(JSRuntime *rt);
 
+    // Save and restore the live weak map list to a vector.
+    static bool saveWeakMapList(JSRuntime *rt, WeakMapVector &vector);
+    static void restoreWeakMapList(JSRuntime *rt, WeakMapVector &vector);
+
   protected:
     // Instance member functions called by the above. Instantiations of WeakMap override
     // these with definitions appropriate for their Key and Value types.
     virtual void nonMarkingTrace(JSTracer *tracer) = 0;
     virtual bool markIteratively(JSTracer *tracer) = 0;
     virtual void sweep(JSTracer *tracer) = 0;
     virtual void traceMappings(WeakMapTracer *tracer) = 0;
 
--- a/js/src/jswrapper.cpp
+++ b/js/src/jswrapper.cpp
@@ -358,17 +358,17 @@ Wrapper::iteratorNext(JSContext *cx, JSO
         vp->setMagic(JS_NO_ITER_VALUE);
     }
     return true;
 }
 
 void
 Wrapper::trace(JSTracer *trc, JSObject *wrapper)
 {
-    MarkValue(trc, &wrapper->getReservedSlotRef(JSSLOT_PROXY_PRIVATE), "wrappedObject");
+    MarkSlot(trc, &wrapper->getReservedSlotRef(JSSLOT_PROXY_PRIVATE), "wrappedObject");
 }
 
 JSObject *
 Wrapper::wrappedObject(const JSObject *wrapper)
 {
     return GetProxyPrivate(wrapper).toObjectOrNull();
 }
 
@@ -651,17 +651,17 @@ CanReify(Value *vp)
            (obj = &vp->toObject())->getClass() == &IteratorClass &&
            (obj->getNativeIterator()->flags & JSITER_ENUMERATE);
 }
 
 struct AutoCloseIterator
 {
     AutoCloseIterator(JSContext *cx, JSObject *obj) : cx(cx), obj(obj) {}
 
-    ~AutoCloseIterator() { if (obj) js_CloseIterator(cx, obj); }
+    ~AutoCloseIterator() { if (obj) CloseIterator(cx, obj); }
 
     void clear() { obj = NULL; }
 
   private:
     JSContext *cx;
     JSObject *obj;
 };
 
@@ -696,17 +696,17 @@ Reify(JSContext *cx, JSCompartment *orig
             id = js_CheckForStringIndex(id);
             keys[i] = id;
             if (!origin->wrapId(cx, &keys[i]))
                 return false;
         }
     }
 
     close.clear();
-    if (!js_CloseIterator(cx, iterObj))
+    if (!CloseIterator(cx, iterObj))
         return false;
 
     if (isKeyIter)
         return VectorToKeyIterator(cx, obj, ni->flags, keys, vp);
     return VectorToValueIterator(cx, obj, ni->flags, keys, vp); 
 }
 
 bool
@@ -866,18 +866,18 @@ CrossCompartmentWrapper::iteratorNext(JS
            NOTHING,
            Wrapper::iteratorNext(cx, wrapper, vp),
            call.origin->wrap(cx, vp));
 }
 
 void
 CrossCompartmentWrapper::trace(JSTracer *trc, JSObject *wrapper)
 {
-    MarkCrossCompartmentValue(trc, &wrapper->getReservedSlotRef(JSSLOT_PROXY_PRIVATE),
-                              "wrappedObject");
+    MarkCrossCompartmentSlot(trc, &wrapper->getReservedSlotRef(JSSLOT_PROXY_PRIVATE),
+                             "wrappedObject");
 }
 
 CrossCompartmentWrapper CrossCompartmentWrapper::singleton(0u);
 
 /* Security wrappers. */
 
 template <class Base>
 SecurityWrapper<Base>::SecurityWrapper(uintN flags)
--- a/js/src/jsxml.cpp
+++ b/js/src/jsxml.cpp
@@ -7533,17 +7533,17 @@ js_InitXMLClasses(JSContext *cx, JSObjec
     return js_InitXMLClass(cx, obj);
 }
 
 namespace js {
 
 bool
 GlobalObject::getFunctionNamespace(JSContext *cx, Value *vp)
 {
-    HeapValue &v = getSlotRef(FUNCTION_NS);
+    HeapSlot &v = getSlotRef(FUNCTION_NS);
     if (v.isUndefined()) {
         JSRuntime *rt = cx->runtime;
         JSLinearString *prefix = rt->atomState.typeAtoms[JSTYPE_FUNCTION];
         JSLinearString *uri = rt->atomState.functionNamespaceURIAtom;
         JSObject *obj = NewXMLNamespace(cx, prefix, uri, JS_FALSE);
         if (!obj)
             return false;
 
@@ -7552,17 +7552,17 @@ GlobalObject::getFunctionNamespace(JSCon
          * Namespace.prototype is not detectable, as there is no way to
          * refer to this instance in scripts.  When used to qualify method
          * names, its prefix and uri references are copied to the QName.
          * The parent remains set and links back to global.
          */
         if (!obj->clearType(cx))
             return false;
 
-        v.set(compartment(), ObjectValue(*obj));
+        v.set(this, FUNCTION_NS, ObjectValue(*obj));
     }
 
     *vp = v;
     return true;
 }
 
 } // namespace js
 
--- a/js/src/methodjit/Compiler.cpp
+++ b/js/src/methodjit/Compiler.cpp
@@ -1150,18 +1150,17 @@ mjit::Compiler::generatePrologue()
 
         if (outerScript->usesArguments && !script->function()->isHeavyweight()) {
             /*
              * Make sure that fp->u.nactual is always coherent. This may be
              * inspected directly by JIT code, and is not guaranteed to be
              * correct if the UNDERFLOW and OVERF