Merge last PGO-green changeset of mozilla-inbound to mozilla-central
authorEd Morley <emorley@mozilla.com>
Mon, 13 Aug 2012 19:08:26 +0100
changeset 104149 75cdb3f932c629a06f811404fb1ff1322610a6be
parent 104116 c14e2d5f17de87fefd570085152f394ebc59a3e0 (current diff)
parent 104148 6627eca98f7e969920e40dea08696996970efcf6 (diff)
child 104150 22fe5c9f4433b25951d0471f44f1cf82f43b26c8
child 104153 22f6adf8685b7b8277b84eaafcce94d5a2369b08
child 104176 743d539a61e385f08d967b3370b8c14baab7b2e8
child 111033 7a7aff2f35d33cdb857902753bdee8c45b5c1c67
push id37
push usershu@rfrn.org
push dateThu, 16 Aug 2012 01:15:22 +0000
milestone17.0a1
Merge last PGO-green changeset of mozilla-inbound to mozilla-central
--- a/config/config.mk
+++ b/config/config.mk
@@ -82,30 +82,22 @@ BUILD_TOOLS	= $(WIN_TOP_SRC)/build/unix
 else
 win_srcdir	:= $(srcdir)
 BUILD_TOOLS	= $(topsrcdir)/build/unix
 endif
 
 CONFIG_TOOLS	= $(MOZ_BUILD_ROOT)/config
 AUTOCONF_TOOLS	= $(topsrcdir)/build/autoconf
 
-ifeq ($(OS_ARCH),QNX)
-ifeq ($(OS_TARGET),NTO)
-LD		:= qcc -Vgcc_ntox86 -nostdlib
-else
-LD		:= $(CC)
-endif
-endif
-
 #
 # Strip off the excessively long version numbers on these platforms,
 # but save the version to allow multiple versions of the same base
 # platform to be built in the same tree.
 #
-ifneq (,$(filter FreeBSD HP-UX Linux NetBSD OpenBSD OSF1 SunOS,$(OS_ARCH)))
+ifneq (,$(filter FreeBSD HP-UX Linux NetBSD OpenBSD SunOS,$(OS_ARCH)))
 OS_RELEASE	:= $(basename $(OS_RELEASE))
 
 # Allow the user to ignore the OS_VERSION, which is usually irrelevant.
 ifdef WANT_MOZILLA_CONFIG_OS_VERSION
 OS_VERS		:= $(suffix $(OS_RELEASE))
 OS_VERSION	:= $(shell echo $(OS_VERS) | sed 's/-.*//')
 endif
 
--- a/config/rules.mk
+++ b/config/rules.mk
@@ -496,27 +496,16 @@ ifdef IS_COMPONENT
 ifneq ($(HAS_EXTRAEXPORTS),1)
 MKSHLIB += -bE:$(MOZILLA_DIR)/build/unix/aix.exp -bnoexpall
 MKCSHLIB += -bE:$(MOZILLA_DIR)/build/unix/aix.exp -bnoexpall
 endif # HAS_EXTRAEXPORTS
 endif # IS_COMPONENT
 endif # AIX
 
 #
-# OSF1: add -B symbolic flag for components
-#
-ifeq ($(OS_ARCH),OSF1)
-ifdef IS_COMPONENT
-ifeq ($(GNU_CC)$(GNU_CXX),)
-EXTRA_DSO_LDOPTS += -B symbolic
-endif
-endif
-endif
-
-#
 # Linux: add -Bsymbolic flag for components
 #
 ifeq ($(OS_ARCH),Linux)
 ifdef IS_COMPONENT
 EXTRA_DSO_LDOPTS += -Wl,-Bsymbolic
 endif
 endif
 
--- a/content/base/src/nsGenericElement.cpp
+++ b/content/base/src/nsGenericElement.cpp
@@ -602,68 +602,58 @@ nsGenericElement::GetScrollFrame(nsIFram
 
   return nullptr;
 }
 
 PRInt32
 nsGenericElement::GetScrollTop()
 {
   nsIScrollableFrame* sf = GetScrollFrame();
-
-  return sf ?
-         nsPresContext::AppUnitsToIntCSSPixels(sf->GetScrollPosition().y) :
-         0;
+  return sf ? sf->GetScrollPositionCSSPixels().y : 0;
 }
 
 NS_IMETHODIMP
 nsGenericElement::GetScrollTop(PRInt32* aScrollTop)
 {
   *aScrollTop = GetScrollTop();
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsGenericElement::SetScrollTop(PRInt32 aScrollTop)
 {
   nsIScrollableFrame* sf = GetScrollFrame();
   if (sf) {
-    nsPoint pt = sf->GetScrollPosition();
-    sf->ScrollToCSSPixels(nsIntPoint(nsPresContext::AppUnitsToIntCSSPixels(pt.x),
-                                     aScrollTop));
+    sf->ScrollToCSSPixels(nsIntPoint(sf->GetScrollPositionCSSPixels().x, aScrollTop));
   }
   return NS_OK;
 }
 
 PRInt32
 nsGenericElement::GetScrollLeft()
 {
   nsIScrollableFrame* sf = GetScrollFrame();
-
-  return sf ?
-         nsPresContext::AppUnitsToIntCSSPixels(sf->GetScrollPosition().x) :
-         0;
+  return sf ? sf->GetScrollPositionCSSPixels().x : 0;
 }
 
 NS_IMETHODIMP
 nsGenericElement::GetScrollLeft(PRInt32* aScrollLeft)
 {
   *aScrollLeft = GetScrollLeft();
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsGenericElement::SetScrollLeft(PRInt32 aScrollLeft)
 {
   nsIScrollableFrame* sf = GetScrollFrame();
   if (sf) {
-    nsPoint pt = sf->GetScrollPosition();
-    sf->ScrollToCSSPixels(nsIntPoint(aScrollLeft,
-                                     nsPresContext::AppUnitsToIntCSSPixels(pt.y)));
+    sf->ScrollToCSSPixels(nsIntPoint(aScrollLeft, sf->GetScrollPositionCSSPixels().y));
   }
   return NS_OK;
 }
 
 PRInt32
 nsGenericElement::GetScrollHeight()
 {
   if (IsSVG())
--- a/content/canvas/src/nsCanvasRenderingContext2DAzure.cpp
+++ b/content/canvas/src/nsCanvasRenderingContext2DAzure.cpp
@@ -4640,33 +4640,30 @@ nsCanvasRenderingContext2DAzure::GetCanv
   }
 
   nsRefPtr<CanvasLayer> canvasLayer = aManager->CreateCanvasLayer();
   if (!canvasLayer) {
     NS_WARNING("CreateCanvasLayer returned null!");
     return nullptr;
   }
   CanvasRenderingContext2DUserDataAzure *userData = nullptr;
-  if (aBuilder->IsPaintingToWindow()) {
-    // Make the layer tell us whenever a transaction finishes (including
-    // the current transaction), so we can clear our invalidation state and
-    // start invalidating again. We need to do this for the layer that is
-    // being painted to a window (there shouldn't be more than one at a time,
-    // and if there is, flushing the invalidation state more often than
-    // necessary is harmless).
-
-    // The layer will be destroyed when we tear down the presentation
-    // (at the latest), at which time this userData will be destroyed,
-    // releasing the reference to the element.
-    // The userData will receive DidTransactionCallbacks, which flush the
-    // the invalidation state to indicate that the canvas is up to date.
-    userData = new CanvasRenderingContext2DUserDataAzure(this);
-    canvasLayer->SetDidTransactionCallback(
-            CanvasRenderingContext2DUserDataAzure::DidTransactionCallback, userData);
-  }
+  // Make the layer tell us whenever a transaction finishes (including
+  // the current transaction), so we can clear our invalidation state and
+  // start invalidating again. We need to do this for all layers since
+  // callers of DrawWindow may be expecting to receive normal invalidation
+  // notifications after this paint.
+
+  // The layer will be destroyed when we tear down the presentation
+  // (at the latest), at which time this userData will be destroyed,
+  // releasing the reference to the element.
+  // The userData will receive DidTransactionCallbacks, which flush the
+  // the invalidation state to indicate that the canvas is up to date.
+  userData = new CanvasRenderingContext2DUserDataAzure(this);
+  canvasLayer->SetDidTransactionCallback(
+          CanvasRenderingContext2DUserDataAzure::DidTransactionCallback, userData);
   canvasLayer->SetUserData(&g2DContextLayerUserData, userData);
 
   CanvasLayer::Data data;
 
   data.mDrawTarget = mTarget;
   data.mSize = nsIntSize(mWidth, mHeight);
 
   canvasLayer->Initialize(data);
--- a/content/events/src/nsEventStateManager.cpp
+++ b/content/events/src/nsEventStateManager.cpp
@@ -327,17 +327,16 @@ public:
   static void EndTransaction();
   static void OnEvent(nsEvent* aEvent);
   static void Shutdown();
   static PRUint32 GetTimeoutTime();
 
 
   static DeltaValues AccelerateWheelDelta(widget::WheelEvent* aEvent,
                                           bool aAllowScrollSpeedOverride);
-  static bool IsAccelerationEnabled();
 
   enum {
     kScrollSeriesTimeout = 80
   };
 protected:
   static nsIntPoint GetScreenPoint(nsGUIEvent* aEvent);
   static void OnFailToScrollTarget();
   static void OnTimeout(nsITimer *aTimer, void *aClosure);
@@ -583,22 +582,16 @@ nsMouseWheelTransaction::GetTimeoutTime(
 }
 
 PRUint32
 nsMouseWheelTransaction::GetIgnoreMoveDelayTime()
 {
   return Preferences::GetUint("mousewheel.transaction.ignoremovedelay", 100);
 }
 
-bool
-nsMouseWheelTransaction::IsAccelerationEnabled()
-{
-  return GetAccelerationStart() >= 0 && GetAccelerationFactor() > 0;
-}
-
 DeltaValues
 nsMouseWheelTransaction::AccelerateWheelDelta(widget::WheelEvent* aEvent,
                                               bool aAllowScrollSpeedOverride)
 {
   DeltaValues result(aEvent);
 
   // Don't accelerate the delta values if the event isn't line scrolling.
   if (aEvent->deltaMode != nsIDOMWheelEvent::DOM_DELTA_LINE) {
--- a/content/html/content/test/forms/test_formnovalidate_attribute.html
+++ b/content/html/content/test/forms/test_formnovalidate_attribute.html
@@ -56,17 +56,16 @@ var observers = os.enumerateObservers("i
  * used to submit the form.
  *
  * The following test should not be done if there is no observer for
  * "invalidformsubmit" because the form submission will not be canceled in that
  * case.
  */
 
 if (observers.hasMoreElements()) {
-
   document.getElementById('av').addEventListener("invalid", function(aEvent) {
     aEvent.target.removeAttribute("invalid", arguments.callee, false);
     ok(true, "formnovalidate should not apply on if not set on the submit " +
              "control used for the submission");
     document.getElementById('b').click();
   }, false);
 
   document.getElementById('bv').addEventListener("invalid", function(aEvent) {
@@ -128,14 +127,16 @@ if (observers.hasMoreElements()) {
   document.forms[2].addEventListener("submit", unexpectedSubmit, false);
 
   SimpleTest.waitForExplicitFinish();
 
   // This is going to call all the tests (with a chain reaction).
   SimpleTest.waitForFocus(function() {
     document.getElementById('a').click();
   });
+} else {
+  todo(false, "No 'invalidformsubmit' observers. Skip test.");
 }
 
 </script>
 </pre>
 </body>
 </html>
--- a/content/html/content/test/test_bug605124-1.html
+++ b/content/html/content/test/test_bug605124-1.html
@@ -93,14 +93,16 @@ if (observers.hasMoreElements()) {
   checkPseudoClass(input, true);
   checkPseudoClass(select, true);
 
   // Remove the form.
   document.getElementsByTagName('table')[0].removeChild(form);
   checkPseudoClass(textarea, false);
   checkPseudoClass(input, false);
   checkPseudoClass(select, false);
+} else {
+  todo(false, "No 'invalidformsubmit' observers. Skip test.");
 }
 
 </script>
 </pre>
 </body>
 </html>
--- a/content/html/content/test/test_bug605125-1.html
+++ b/content/html/content/test/test_bug605125-1.html
@@ -99,14 +99,16 @@ if (observers.hasMoreElements()) {
   checkPseudoClass(input, true);
   checkPseudoClass(select, true);
 
   // Remove the form.
   document.getElementsByTagName('table')[0].removeChild(form);
   checkPseudoClass(textarea, false);
   checkPseudoClass(input, false);
   checkPseudoClass(select, false);
+} else {
+  todo(false, "No 'invalidformsubmit' observers. Skip test.");
 }
 
 </script>
 </pre>
 </body>
 </html>
--- a/dom/base/Navigator.cpp
+++ b/dom/base/Navigator.cpp
@@ -49,16 +49,18 @@
 #include "nsIDOMBluetoothManager.h"
 #include "BluetoothManager.h"
 #endif
 #include "nsIDOMCameraManager.h"
 #include "DOMCameraManager.h"
 
 #include "nsIDOMGlobalPropertyInitializer.h"
 
+using namespace mozilla::dom::power;
+
 // This should not be in the namespace.
 DOMCI_DATA(Navigator, mozilla::dom::Navigator)
 
 namespace mozilla {
 namespace dom {
 
 static const char sJSStackContractID[] = "@mozilla.org/js/xpc/ContextStack;1";
 
@@ -1024,21 +1026,21 @@ Navigator::GetBattery(nsIDOMBatteryManag
 }
 
 NS_IMETHODIMP
 Navigator::GetMozPower(nsIDOMMozPowerManager** aPower)
 {
   *aPower = nullptr;
 
   if (!mPowerManager) {
-    nsCOMPtr<nsPIDOMWindow> win = do_QueryReferent(mWindow);
-    NS_ENSURE_TRUE(win, NS_OK);
+    nsCOMPtr<nsPIDOMWindow> window = do_QueryReferent(mWindow);
+    NS_ENSURE_TRUE(window, NS_OK);
 
-    mPowerManager = new power::PowerManager();
-    mPowerManager->Init(win);
+    mPowerManager = PowerManager::CheckPermissionAndCreateInstance(window);
+    NS_ENSURE_TRUE(mPowerManager, NS_OK);
   }
 
   nsCOMPtr<nsIDOMMozPowerManager> power(mPowerManager);
   power.forget(aPower);
 
   return NS_OK;
 }
 
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -535,16 +535,17 @@ using mozilla::dom::indexedDB::IDBWrappe
 #include "nsIOpenWindowEventDetail.h"
 #include "nsIDOMGlobalObjectConstructor.h"
 
 #include "DOMFileHandle.h"
 #include "FileRequest.h"
 #include "LockedFile.h"
 #include "GeneratedEvents.h"
 #include "mozilla/Likely.h"
+#include "nsDebug.h"
 
 #undef None // something included above defines this preprocessor symbol, maybe Xlib headers
 #include "WebGLContext.h"
 #include "nsICanvasRenderingContextInternal.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
@@ -2068,18 +2069,20 @@ static inline nsresult
 SetParentToWindow(nsGlobalWindow *win, JSObject **parent)
 {
   MOZ_ASSERT(win);
   MOZ_ASSERT(win->IsInnerWindow());
   *parent = win->FastGetGlobalJSObject();
 
   if (MOZ_UNLIKELY(!*parent)) {
     // The only known case where this can happen is when the inner window has
-    // been torn down. See bug 691178 comment 11.
-    MOZ_ASSERT(win->IsClosedOrClosing());
+    // been torn down. See bug 691178 comment 11. Should be a fatal MOZ_ASSERT,
+    // but we've found a way to hit it too often in mochitests. See bugs 777875
+    // 778424, 781078.
+    NS_ASSERTION(win->IsClosedOrClosing(), "win should be closed or closing");
     return NS_ERROR_FAILURE;
   }
   return NS_OK;
 }
 
 // static
 
 nsISupports *
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -4317,21 +4317,23 @@ nsGlobalWindow::GetScrollXY(PRInt32* aSc
   nsPoint scrollPos = sf->GetScrollPosition();
   if (scrollPos != nsPoint(0,0) && !aDoFlush) {
     // Oh, well.  This is the expensive case -- the window is scrolled and we
     // didn't actually flush yet.  Repeat, but with a flush, since the content
     // may get shorter and hence our scroll position may decrease.
     return GetScrollXY(aScrollX, aScrollY, true);
   }
 
-  if (aScrollX)
-    *aScrollX = nsPresContext::AppUnitsToIntCSSPixels(scrollPos.x);
-  if (aScrollY)
-    *aScrollY = nsPresContext::AppUnitsToIntCSSPixels(scrollPos.y);
-
+  nsIntPoint scrollPosCSSPixels = sf->GetScrollPositionCSSPixels();
+  if (aScrollX) {
+    *aScrollX = scrollPosCSSPixels.x;
+  }
+  if (aScrollY) {
+    *aScrollY = scrollPosCSSPixels.y;
+  }
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsGlobalWindow::GetScrollX(PRInt32* aScrollX)
 {
   NS_ENSURE_ARG_POINTER(aScrollX);
   *aScrollX = 0;
--- a/dom/plugins/ipc/PluginInstanceParent.cpp
+++ b/dom/plugins/ipc/PluginInstanceParent.cpp
@@ -649,16 +649,22 @@ PluginInstanceParent::RecvShow(const NPR
         gfxRect ur(updatedRect.left, updatedRect.top,
                    updatedRect.right - updatedRect.left,
                    updatedRect.bottom - updatedRect.top);
         surface->MarkDirty(ur);
         surface->Flush();
     }
 
     mFrontSurface = surface;
+    if (!surface) {
+      ImageContainer* container = GetImageContainer();
+      if (container) {
+        container->SetCurrentImage(nullptr);
+      }
+    }
     RecvNPN_InvalidateRect(updatedRect);
 
     PLUGIN_LOG_DEBUG(("   (RecvShow invalidated for surface %p)",
                       mFrontSurface.get()));
 
     return true;
 }
 
--- a/dom/power/PowerManager.cpp
+++ b/dom/power/PowerManager.cpp
@@ -1,19 +1,20 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/Hal.h"
 #include "PowerManager.h"
 #include "WakeLock.h"
-#include "nsContentUtils.h"
 #include "nsDOMClassInfoID.h"
 #include "nsIDOMWakeLockListener.h"
+#include "nsIDocument.h"
+#include "nsIPermissionManager.h"
 #include "nsIPowerManagerService.h"
 #include "nsIPrincipal.h"
 #include "nsPIDOMWindow.h"
 #include "nsServiceManagerUtils.h"
 #include "nsDOMError.h"
 
 DOMCI_DATA(MozPowerManager, mozilla::dom::power::PowerManager)
 
@@ -52,93 +53,61 @@ PowerManager::Shutdown()
     do_GetService(POWERMANAGERSERVICE_CONTRACTID);
   NS_ENSURE_STATE(pmService);
 
   // Remove ourself from the global notification list.
   pmService->RemoveWakeLockListener(this);
   return NS_OK;
 }
 
-bool
-PowerManager::CheckPermission()
-{
-  if (nsContentUtils::IsCallerChrome()) {
-    return true;
-  }
-
-  nsCOMPtr<nsPIDOMWindow> win = do_QueryReferent(mWindow);
-  NS_ENSURE_TRUE(win, false);
-  nsCOMPtr<nsIDocument> doc = do_QueryInterface(win->GetExtantDocument());
-  NS_ENSURE_TRUE(doc, false);
-
-  nsCOMPtr<nsIURI> uri;
-  doc->NodePrincipal()->GetURI(getter_AddRefs(uri));
-
-  if (!nsContentUtils::URIIsChromeOrInPref(uri, "dom.power.whitelist")) {
-    return false;
-  }
-
-  return true;
-}
-
 NS_IMETHODIMP
 PowerManager::Reboot()
 {
-  NS_ENSURE_TRUE(CheckPermission(), NS_ERROR_DOM_SECURITY_ERR);
-
   nsCOMPtr<nsIPowerManagerService> pmService =
     do_GetService(POWERMANAGERSERVICE_CONTRACTID);
   NS_ENSURE_STATE(pmService);
 
   pmService->Reboot();
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 PowerManager::PowerOff()
 {
-  NS_ENSURE_TRUE(CheckPermission(), NS_ERROR_DOM_SECURITY_ERR);
-
   nsCOMPtr<nsIPowerManagerService> pmService =
     do_GetService(POWERMANAGERSERVICE_CONTRACTID);
   NS_ENSURE_STATE(pmService);
 
   pmService->PowerOff();
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 PowerManager::AddWakeLockListener(nsIDOMMozWakeLockListener *aListener)
 {
-  NS_ENSURE_TRUE(CheckPermission(), NS_ERROR_DOM_SECURITY_ERR);
-
   // already added? bail out.
   if (mListeners.Contains(aListener))
     return NS_OK;
 
   mListeners.AppendElement(aListener);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 PowerManager::RemoveWakeLockListener(nsIDOMMozWakeLockListener *aListener)
 {
-  NS_ENSURE_TRUE(CheckPermission(), NS_ERROR_DOM_SECURITY_ERR);
-
   mListeners.RemoveElement(aListener);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 PowerManager::GetWakeLockState(const nsAString &aTopic, nsAString &aState)
 {
-  NS_ENSURE_TRUE(CheckPermission(), NS_ERROR_DOM_SECURITY_ERR);
-
   nsCOMPtr<nsIPowerManagerService> pmService =
     do_GetService(POWERMANAGERSERVICE_CONTRACTID);
   NS_ENSURE_STATE(pmService);
 
   return pmService->GetWakeLockState(aTopic, aState);
 }
 
 NS_IMETHODIMP
@@ -158,74 +127,81 @@ PowerManager::Callback(const nsAString &
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 PowerManager::GetScreenEnabled(bool *aEnabled)
 {
-  if (!CheckPermission()) {
-    *aEnabled = true;
-    return NS_OK;
-  }
-
   *aEnabled = hal::GetScreenEnabled();
   return NS_OK;
 }
 
 NS_IMETHODIMP
 PowerManager::SetScreenEnabled(bool aEnabled)
 {
-  NS_ENSURE_TRUE(CheckPermission(), NS_ERROR_DOM_SECURITY_ERR);
-
-  // TODO bug 707589: When the screen's state changes, all visible windows
-  // should fire a visibility change event.
   hal::SetScreenEnabled(aEnabled);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 PowerManager::GetScreenBrightness(double *aBrightness)
 {
-  if (!CheckPermission()) {
-    *aBrightness = 1;
-    return NS_OK;
-  }
-
   *aBrightness = hal::GetScreenBrightness();
   return NS_OK;
 }
 
 NS_IMETHODIMP
 PowerManager::SetScreenBrightness(double aBrightness)
 {
-  NS_ENSURE_TRUE(CheckPermission(), NS_ERROR_DOM_SECURITY_ERR);
-
   NS_ENSURE_TRUE(0 <= aBrightness && aBrightness <= 1, NS_ERROR_INVALID_ARG);
   hal::SetScreenBrightness(aBrightness);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 PowerManager::GetCpuSleepAllowed(bool *aAllowed)
 {
-  if (!CheckPermission()) {
-    *aAllowed = true;
-    return NS_OK;
-  }
-
   *aAllowed = hal::GetCpuSleepAllowed();
   return NS_OK;
 }
 
 NS_IMETHODIMP
 PowerManager::SetCpuSleepAllowed(bool aAllowed)
 {
-  NS_ENSURE_TRUE(CheckPermission(), NS_ERROR_DOM_SECURITY_ERR);
-
   hal::SetCpuSleepAllowed(aAllowed);
   return NS_OK;
 }
 
+already_AddRefed<PowerManager>
+PowerManager::CheckPermissionAndCreateInstance(nsPIDOMWindow* aWindow)
+{
+  nsPIDOMWindow* innerWindow = aWindow->IsInnerWindow() ?
+    aWindow :
+    aWindow->GetCurrentInnerWindow();
+
+  // Need the document for security check.
+  nsCOMPtr<nsIDocument> document = innerWindow->GetExtantDoc();
+  NS_ENSURE_TRUE(document, nullptr);
+
+  nsCOMPtr<nsIPrincipal> principal = document->NodePrincipal();
+
+  nsCOMPtr<nsIPermissionManager> permMgr =
+    do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
+  NS_ENSURE_TRUE(permMgr, nullptr);
+
+  PRUint32 permission = nsIPermissionManager::DENY_ACTION;
+  permMgr->TestPermissionFromPrincipal(principal, "power", &permission);
+
+  if (permission != nsIPermissionManager::ALLOW_ACTION) {
+    return nullptr;
+  }
+
+  nsRefPtr<PowerManager> powerManager = new PowerManager();
+  powerManager->Init(aWindow);
+
+  return powerManager.forget();
+}
+
 } // power
 } // dom
 } // mozilla
--- a/dom/power/PowerManager.h
+++ b/dom/power/PowerManager.h
@@ -7,16 +7,18 @@
 
 #include "nsCOMPtr.h"
 #include "nsTArray.h"
 #include "nsIDOMPowerManager.h"
 #include "nsIDOMWakeLockListener.h"
 #include "nsIDOMWindow.h"
 #include "nsWeakReference.h"
 
+class nsPIDOMWindow;
+
 namespace mozilla {
 namespace dom {
 namespace power {
 
 class PowerManager
   : public nsIDOMMozPowerManager
   , public nsIDOMMozWakeLockListener
 {
@@ -26,18 +28,20 @@ public:
   NS_DECL_NSIDOMMOZWAKELOCKLISTENER
 
   PowerManager() {};
   virtual ~PowerManager() {};
 
   nsresult Init(nsIDOMWindow *aWindow);
   nsresult Shutdown();
 
+  static already_AddRefed<PowerManager>
+  CheckPermissionAndCreateInstance(nsPIDOMWindow*);
+
 private:
-  bool CheckPermission();
 
   nsWeakPtr mWindow;
   nsTArray<nsCOMPtr<nsIDOMMozWakeLockListener> > mListeners;
 };
 
 } // namespace power
 } // namespace dom
 } // namespace mozilla
--- a/dom/power/test/browser_bug697132.js
+++ b/dom/power/test/browser_bug697132.js
@@ -1,24 +1,27 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
 "use strict";
 
 waitForExplicitFinish();
 
-let kPrefNode = "dom.power.whitelist";
-let kPageSource1 = "data:text/html,1";
-let kPageSource2 = "data:text/html,2";
+let kUrlSource = "http://mochi.test:8888/";
+let kDataSource = "data:text/html,";
 
 let gOldPref;
 let gWin, gWin1, gWin2;
 let gTab, gTab1, gTab2;
 let gLock, gLock1, gLock2;
 let gCurStepIndex = -1;
 let gSteps = [
   function basicWakeLock() {
-    gTab = gBrowser.addTab(kPageSource1);
+    gTab = gBrowser.addTab(kUrlSource);
     gWin = gBrowser.getBrowserForTab(gTab).contentWindow;
     let browser = gBrowser.getBrowserForTab(gTab);
 
     browser.addEventListener("load", function onLoad(e) {
       browser.removeEventListener("load", onLoad, true);
       let nav = gWin.navigator;
       let power = nav.mozPower;
       gLock = nav.requestWakeLock("test");
@@ -46,17 +49,17 @@ let gSteps = [
       }
 
       gBrowser.removeTab(gTab);
 
       executeSoon(runNextStep);
     }, true);
   },
   function multiWakeLock() {
-    gTab = gBrowser.addTab(kPageSource1);
+    gTab = gBrowser.addTab(kUrlSource);
     gWin = gBrowser.getBrowserForTab(gTab).contentWindow;
     let browser = gBrowser.getBrowserForTab(gTab);
 
     browser.addEventListener("load", function onLoad(e) {
       browser.removeEventListener("load", onLoad, true);
       let nav = gWin.navigator;
       let power = nav.mozPower;
       let count = 0;
@@ -95,19 +98,19 @@ let gSteps = [
       gLock1.unlock();
       isnot(power.getWakeLockState("test"), "unlocked",
             "topic is locked");
 
       gLock2.unlock();
     }, true);
   },
   function crossTabWakeLock1() {
-    gTab1 = gBrowser.addTab(kPageSource1);
+    gTab1 = gBrowser.addTab(kUrlSource);
     gWin1 = gBrowser.getBrowserForTab(gTab1).contentWindow;
-    gTab2 = gBrowser.addTab(kPageSource1);
+    gTab2 = gBrowser.addTab(kUrlSource);
     gWin2 = gBrowser.getBrowserForTab(gTab2).contentWindow;
 
     gBrowser.selectedTab = gTab1;
     let browser = gBrowser.getBrowserForTab(gTab2);
 
     browser.addEventListener("load", function onLoad(e) {
       browser.removeEventListener("load", onLoad, true);
       gLock2 = gWin2.navigator.requestWakeLock("test");
@@ -133,17 +136,17 @@ let gSteps = [
     gWin2.addEventListener("pagehide", function onPageHide(e) {
       gWin2.removeEventListener("pagehide", onPageHide, true);
       executeSoon(runNextStep);
     }, true);
     gWin2.addEventListener("pageshow", function onPageShow(e) {
       gWin2.removeEventListener("pageshow", onPageShow, true);
       executeSoon(runNextStep);
     }, true);
-    gWin2.location = kPageSource2;
+    gWin2.location = kDataSource;
   },
   function crossTabWakeLock3() {
     is(gWin1.navigator.mozPower.getWakeLockState("test"), "unlocked",
        "wake lock should auto-unlock when page is unloaded");
     gWin2.back();
     // runNextStep called in onPageShow
   },
   function crossTabWakeLock4() {
@@ -161,17 +164,17 @@ let gSteps = [
     gWin2.addEventListener("pagehide", function onPageHide(e) {
       gWin2.removeEventListener("pagehide", onPageHide, true);
       executeSoon(runNextStep);
     }, true);
     gWin2.addEventListener("pageshow", function onPageShow(e) {
       gWin2.removeEventListener("pageshow", onPageShow, true);
       executeSoon(runNextStep);
     }, true);
-    gWin2.location = kPageSource2;
+    gWin2.location = kDataSource;
   },
   function crossTabWakeLock6() {
     is(gWin1.navigator.mozPower.getWakeLockState("test"), "unlocked",
        "wake lock should auto-unlock when page is unloaded");
     gWin2.back();
     // runNextStep called in onPageShow
   },
   function crossTabWakeLock7() {
@@ -214,23 +217,17 @@ let gSteps = [
   },
 ];
 
 function runNextStep() {
   gCurStepIndex++;
   if (gCurStepIndex < gSteps.length) {
     gSteps[gCurStepIndex]();
   } else {
-    Services.prefs.setCharPref(kPrefNode, gOldPref);
+    SpecialPowers.removePermission("power", kUrlSource);
     finish();
   }
 }
 
 function test() {
-  try {
-    gOldPref = Services.prefs.getCharPref(kPrefNode);
-  } catch (e) {
-    gOldPref = "";
-  }
-  // data url inherits its parent's principal, which is |about:| here.
-  Services.prefs.setCharPref(kPrefNode, "about:");
+  SpecialPowers.addPermission("power", true, kUrlSource);
   runNextStep();
 }
--- a/dom/power/test/test_power_basics.html
+++ b/dom/power/test/test_power_basics.html
@@ -11,12 +11,24 @@
 </div>
 <pre id="test">
 <script type="application/javascript">
 
 /** Test for Power API **/
 
 ok('mozPower' in navigator, "navigator.mozPower should exist");
 
+/** Test permission **/
+
+SpecialPowers.removePermission("power", document);
+
+power = navigator.mozPower;
+ok(!power, "Shouldn't be able to access power manager without permission.");
+
+SpecialPowers.addPermission("power", true, document);
+
+power = navigator.mozPower;
+ok(power, "Shouldn be able to access power manager with permission.");
+
 </script>
 </pre>
 </body>
 </html>
--- a/dom/system/gonk/RadioInterfaceLayer.js
+++ b/dom/system/gonk/RadioInterfaceLayer.js
@@ -536,17 +536,17 @@ RadioInterfaceLayer.prototype = {
     if (!this.dataCallSettings["enabled"]) {
       return;
     }
 
     let isRegistered =
       newInfo.state == RIL.GECKO_MOBILE_CONNECTION_STATE_REGISTERED &&
       (!newInfo.roaming || this._isDataRoamingEnabled());
     let haveDataConnection =
-      newInfo.type != GECKO_MOBILE_CONNECTION_STATE_UNKNOWN;
+      newInfo.type != RIL.GECKO_MOBILE_CONNECTION_STATE_UNKNOWN;
 
     if (isRegistered && haveDataConnection) {
       debug("Radio is ready for data connection.");
       this.updateRILNetworkInterface();
     }
   },
 
   handleSignalStrengthChange: function handleSignalStrengthChange(message) {
@@ -675,18 +675,19 @@ RadioInterfaceLayer.prototype = {
       case nsIRadioInterfaceLayer.CALL_STATE_INCOMING:
         gAudioManager.phoneState = nsIAudioManager.PHONE_STATE_RINGTONE;
         debug("Incoming call, put audio system into PHONE_STATE_RINGTONE: "
               + gAudioManager.phoneState);
         break;
       case nsIRadioInterfaceLayer.CALL_STATE_DIALING: // Fall through...
       case nsIRadioInterfaceLayer.CALL_STATE_CONNECTED:
         gAudioManager.phoneState = nsIAudioManager.PHONE_STATE_IN_CALL;
-        gAudioManager.setForceForUse(nsIAudioManager.USE_COMMUNICATION,
-                                     nsIAudioManager.FORCE_NONE);
+        let force = this.speakerEnabled ? nsIAudioManager.FORCE_SPEAKER
+                                        : nsIAudioManager.FORCE_NONE;
+        gAudioManager.setForceForUse(nsIAudioManager.USE_COMMUNICATION, force);
         debug("Active call, put audio system into PHONE_STATE_IN_CALL: "
               + gAudioManager.phoneState);
         break;
     }
   },
 
   /**
    * Handle call state changes by updating our current state and the audio
--- a/dom/system/gonk/ril_worker.js
+++ b/dom/system/gonk/ril_worker.js
@@ -48,24 +48,24 @@ const UINT8_SIZE  = 1;
 const UINT16_SIZE = 2;
 const UINT32_SIZE = 4;
 const PARCEL_SIZE_SIZE = UINT32_SIZE;
 
 const PDU_HEX_OCTET_SIZE = 4;
 
 const DEFAULT_EMERGENCY_NUMBERS = ["112", "911"];
 
-let RILQUIRKS_CALLSTATE_EXTRA_UINT32 = false;
-let RILQUIRKS_DATACALLSTATE_DOWN_IS_UP = false;
-// This flag defaults to true since on RIL v6 and later, we get the
-// version number via the UNSOLICITED_RIL_CONNECTED parcel.
-let RILQUIRKS_V5_LEGACY = true;
-let RILQUIRKS_REQUEST_USE_DIAL_EMERGENCY_CALL = false;
-let RILQUIRKS_MODEM_DEFAULTS_TO_EMERGENCY_MODE = false;
-let RILQUIRKS_SIM_APP_STATE_EXTRA_FIELDS = false;
+let RILQUIRKS_CALLSTATE_EXTRA_UINT32 = libcutils.property_get("ro.moz.ril.callstate_extra_int");
+let RILQUIRKS_DATACALLSTATE_DOWN_IS_UP = libcutils.property_get("ro.moz.ril.callstate_down_is_up");
+// This may change at runtime since in RIL v6 and later, we get the version
+// number via the UNSOLICITED_RIL_CONNECTED parcel.
+let RILQUIRKS_V5_LEGACY = libcutils.property_get("ro.moz.ril.v5_legacy");
+let RILQUIRKS_REQUEST_USE_DIAL_EMERGENCY_CALL = libcutils.property_get("ro.moz.ril.dial_emergency_call");
+let RILQUIRKS_MODEM_DEFAULTS_TO_EMERGENCY_MODE = libcutils.property_get("ro.moz.ril.emergency_by_default");
+let RILQUIRKS_SIM_APP_STATE_EXTRA_FIELDS = libcutils.property_get("ro.moz.ril.simstate_extra_field");
 
 // Marker object.
 let PENDING_NETWORK_TYPE = {};
 
 /**
  * This object contains helpers buffering incoming data & deconstructing it
  * into parcels as well as buffering outgoing data & constructing parcels.
  * For that it maintains two buffers and corresponding uint8 views, indexes.
@@ -686,81 +686,16 @@ let RIL = {
   set muted(val) {
     val = Boolean(val);
     if (this._muted != val) {
       this.setMute(val);
       this._muted = val;
     }
   },
 
-
-  /**
-   * Set quirk flags based on the RIL model detected. Note that this
-   * requires the RIL being "warmed up" first, which happens when on
-   * an incoming or outgoing voice call or data call.
-   */
-  rilQuirksInitialized: false,
-  initRILQuirks: function initRILQuirks() {
-    if (this.rilQuirksInitialized) {
-      return;
-    }
-
-    let ril_impl = libcutils.property_get("gsm.version.ril-impl");
-    if (DEBUG) debug("Detected RIL implementation " + ril_impl);
-    switch (ril_impl) {
-      case "Samsung RIL(IPC) v2.0":
-        // The Samsung Galaxy S2 I-9100 radio sends an extra Uint32 in the
-        // call state.
-        let model_id = libcutils.property_get("ril.model_id");
-        if (DEBUG) debug("Detected RIL model " + model_id);
-        if (!model_id) {
-          // On some RIL models, the RIL has to be "warmed up" for us to read this property.
-          // It apparently isn't warmed up yet, going to try again later.
-          if (DEBUG) debug("Could not detect correct model_id. Going to try later.");
-          return;
-        }
-        if (model_id == "I9100") {
-          if (DEBUG) {
-            debug("Detected I9100, enabling " +
-                  "RILQUIRKS_CALLSTATE_EXTRA_UINT32, " +
-                  "RILQUIRKS_DATACALLSTATE_DOWN_IS_UP, " +
-                  "RILQUIRKS_REQUEST_USE_DIAL_EMERGENCY_CALL.");
-          }
-          RILQUIRKS_CALLSTATE_EXTRA_UINT32 = true;
-          RILQUIRKS_DATACALLSTATE_DOWN_IS_UP = true;
-          RILQUIRKS_REQUEST_USE_DIAL_EMERGENCY_CALL = true;
-        }
-        if (model_id == "I9023" || model_id == "I9020") {
-          if (DEBUG) {
-            debug("Detected I9020/I9023, enabling " +
-                  "RILQUIRKS_DATACALLSTATE_DOWN_IS_UP");
-          }
-          RILQUIRKS_DATACALLSTATE_DOWN_IS_UP = true;
-        }
-        break;
-      case "Qualcomm RIL 1.0":
-        let product_model = libcutils.property_get("ro.product.model");
-        if (DEBUG) debug("Detected product model " + product_model);
-        if (product_model == "otoro1") {
-          if (DEBUG) debug("Enabling RILQUIRKS_SIM_APP_STATE_EXTRA_FIELDS.");
-          RILQUIRKS_SIM_APP_STATE_EXTRA_FIELDS = true;
-        }
-        if (DEBUG) {
-          debug("Detected Qualcomm RIL 1.0, " +
-                "disabling RILQUIRKS_V5_LEGACY and " +
-                "enabling RILQUIRKS_MODEM_DEFAULTS_TO_EMERGENCY_MODE.");
-        }
-        RILQUIRKS_V5_LEGACY = false;
-        RILQUIRKS_MODEM_DEFAULTS_TO_EMERGENCY_MODE = true;
-        break;
-    }
-
-    this.rilQuirksInitialized = true;
-  },
-
   /**
    * Parse an integer from a string, falling back to a default value
    * if the the provided value is not a string or does not contain a valid
    * number.
    *
    * @param string
    *        String to be parsed.
    * @param defaultValue
@@ -2256,18 +2191,16 @@ let RIL = {
       changed = true;
       curState.radioTech = radioTech;
       curState.type = GECKO_RADIO_TECH[radioTech] || null;
     }
     return changed;
   },
 
   _processVoiceRegistrationState: function _processVoiceRegistrationState(state) {
-    this.initRILQuirks();
-
     let rs = this.voiceRegistrationState;
     let stateChanged = this._processCREG(rs, state);
     if (stateChanged && rs.connected) {
       RIL.getSMSCAddress();
     }
 
     let cell = this.cellLocation;
     let cellChanged = false;
@@ -2946,18 +2879,16 @@ RIL[REQUEST_CHANGE_SIM_PIN2] = function 
                        requestId: options.requestId});
 };
 RIL[REQUEST_ENTER_NETWORK_DEPERSONALIZATION] = null;
 RIL[REQUEST_GET_CURRENT_CALLS] = function REQUEST_GET_CURRENT_CALLS(length, options) {
   if (options.rilRequestError) {
     return;
   }
 
-  this.initRILQuirks();
-
   let calls_length = 0;
   // The RIL won't even send us the length integer if there are no active calls.
   // So only read this integer if the parcel actually has it.
   if (length) {
     calls_length = Buf.readUint32();
   }
   if (!calls_length) {
     this._processCalls(null);
@@ -3472,17 +3403,16 @@ RIL.readDataCall_v6 = function readDataC
   return options;
 };
 
 RIL[REQUEST_DATA_CALL_LIST] = function REQUEST_DATA_CALL_LIST(length, options) {
   if (options.rilRequestError) {
     return;
   }
 
-  this.initRILQuirks();
   if (!length) {
     this._processDataCallList(null);
     return;
   }
 
   let version = 0;
   if (!RILQUIRKS_V5_LEGACY) {
     version = Buf.readUint32();
@@ -3731,17 +3661,16 @@ RIL[UNSOLICITED_CDMA_OTA_PROVISION_STATU
 RIL[UNSOLICITED_CDMA_INFO_REC] = null;
 RIL[UNSOLICITED_OEM_HOOK_RAW] = null;
 RIL[UNSOLICITED_RINGBACK_TONE] = null;
 RIL[UNSOLICITED_RESEND_INCALL_MUTE] = null;
 RIL[UNSOLICITED_RIL_CONNECTED] = function UNSOLICITED_RIL_CONNECTED(length) {
   // Prevent response id collision between UNSOLICITED_RIL_CONNECTED and
   // UNSOLICITED_VOICE_RADIO_TECH_CHANGED for Akami on gingerbread branch.
   if (!length) {
-    this.initRILQuirks();
     return;
   }
 
   let version = Buf.readUint32List()[0];
   RILQUIRKS_V5_LEGACY = (version < 5);
   if (DEBUG) {
     debug("Detected RIL version " + version);
     debug("RILQUIRKS_V5_LEGACY is " + RILQUIRKS_V5_LEGACY);
--- a/gfx/2d/DrawTargetD2D.cpp
+++ b/gfx/2d/DrawTargetD2D.cpp
@@ -1574,62 +1574,93 @@ DrawTargetD2D::FinalizeRTForOperation(Co
   }
 
   mDevice->OMSetBlendState(GetBlendStateForOperator(aOperator), NULL, 0xffffffff);
   
   mDevice->Draw(4, 0);
 }
 
 TemporaryRef<ID2D1Geometry>
+DrawTargetD2D::ConvertRectToGeometry(const D2D1_RECT_F& aRect)
+{
+  RefPtr<ID2D1RectangleGeometry> rectGeom;
+  factory()->CreateRectangleGeometry(&aRect, byRef(rectGeom));
+  return rectGeom.forget();
+}
+
+static D2D1_RECT_F
+IntersectRect(const D2D1_RECT_F& aRect1, const D2D1_RECT_F& aRect2)
+{
+  D2D1_RECT_F result;
+  result.left = max(aRect1.left, aRect2.left);
+  result.top = max(aRect1.top, aRect2.top);
+  result.right = min(aRect1.right, aRect2.right);
+  result.bottom = min(aRect1.bottom, aRect2.bottom);
+  return result;
+}
+
+TemporaryRef<ID2D1Geometry>
 DrawTargetD2D::GetClippedGeometry()
 {
   if (mCurrentClippedGeometry) {
     return mCurrentClippedGeometry;
   }
 
-  RefPtr<ID2D1GeometrySink> currentSink;
-
-  factory()->CreatePathGeometry(byRef(mCurrentClippedGeometry));
-  mCurrentClippedGeometry->Open(byRef(currentSink));
-      
+  // if pathGeom is null then pathRect represents the path.
+  RefPtr<ID2D1Geometry> pathGeom;
+  D2D1_RECT_F pathRect;
   std::vector<DrawTargetD2D::PushedClip>::iterator iter = mPushedClips.begin();
-
   if (iter->mPath) {
+    RefPtr<ID2D1PathGeometry> tmpGeometry;
+    factory()->CreatePathGeometry(byRef(tmpGeometry));
+    RefPtr<ID2D1GeometrySink> currentSink;
+    tmpGeometry->Open(byRef(currentSink));
     iter->mPath->GetGeometry()->Simplify(D2D1_GEOMETRY_SIMPLIFICATION_OPTION_CUBICS_AND_LINES,
                                          iter->mTransform, currentSink);
+    currentSink->Close();
+    pathGeom = tmpGeometry.forget();
   } else {
-    RefPtr<ID2D1RectangleGeometry> rectGeom;
-    factory()->CreateRectangleGeometry(iter->mBounds, byRef(rectGeom));
-    rectGeom->Simplify(D2D1_GEOMETRY_SIMPLIFICATION_OPTION_CUBICS_AND_LINES,
-                       D2D1::IdentityMatrix(), currentSink);
+    pathRect = iter->mBounds;
   }
-  currentSink->Close();
 
   iter++;
   for (;iter != mPushedClips.end(); iter++) {
+    if (!pathGeom) {
+      if (iter->mPath) {
+        pathGeom = ConvertRectToGeometry(pathRect);
+      } else {
+        pathRect = IntersectRect(pathRect, iter->mBounds);
+        continue;
+      }
+    }
+
     RefPtr<ID2D1PathGeometry> newGeom;
     factory()->CreatePathGeometry(byRef(newGeom));
 
+    RefPtr<ID2D1GeometrySink> currentSink;
     newGeom->Open(byRef(currentSink));
 
     if (iter->mPath) {
-      mCurrentClippedGeometry->CombineWithGeometry(iter->mPath->GetGeometry(), D2D1_COMBINE_MODE_INTERSECT,
-                                           iter->mTransform, currentSink);
+      pathGeom->CombineWithGeometry(iter->mPath->GetGeometry(), D2D1_COMBINE_MODE_INTERSECT,
+                                    iter->mTransform, currentSink);
     } else {
-      RefPtr<ID2D1RectangleGeometry> rectGeom;
-      factory()->CreateRectangleGeometry(iter->mBounds, byRef(rectGeom));
-      mCurrentClippedGeometry->CombineWithGeometry(rectGeom, D2D1_COMBINE_MODE_INTERSECT,
-                                                   D2D1::IdentityMatrix(), currentSink);
+      RefPtr<ID2D1Geometry> rectGeom = ConvertRectToGeometry(iter->mBounds);
+      pathGeom->CombineWithGeometry(rectGeom, D2D1_COMBINE_MODE_INTERSECT,
+                                    D2D1::IdentityMatrix(), currentSink);
     }
 
     currentSink->Close();
 
-    mCurrentClippedGeometry = newGeom;
+    pathGeom = newGeom.forget();
   }
 
+  if (!pathGeom) {
+    pathGeom = ConvertRectToGeometry(pathRect);
+  }
+  mCurrentClippedGeometry = pathGeom.forget();
   return mCurrentClippedGeometry;
 }
 
 TemporaryRef<ID2D1RenderTarget>
 DrawTargetD2D::CreateRTForTexture(ID3D10Texture2D *aTexture, SurfaceFormat aFormat)
 {
   HRESULT hr;
 
--- a/gfx/2d/DrawTargetD2D.h
+++ b/gfx/2d/DrawTargetD2D.h
@@ -177,16 +177,17 @@ private:
 
   bool FillGlyphsManual(ScaledFontDWrite *aFont,
                         const GlyphBuffer &aBuffer,
                         const Color &aColor,
                         IDWriteRenderingParams *aParams,
                         const DrawOptions &aOptions = DrawOptions());
 
   TemporaryRef<ID2D1RenderTarget> CreateRTForTexture(ID3D10Texture2D *aTexture, SurfaceFormat aFormat);
+  TemporaryRef<ID2D1Geometry> ConvertRectToGeometry(const D2D1_RECT_F& aRect);
   TemporaryRef<ID2D1Geometry> GetClippedGeometry();
 
   TemporaryRef<ID2D1Brush> CreateBrushForPattern(const Pattern &aPattern, Float aAlpha = 1.0f);
 
   TemporaryRef<ID3D10Texture2D> CreateGradientTexture(const GradientStopsD2D *aStops);
   TemporaryRef<ID3D10Texture2D> CreateTextureForAnalysis(IDWriteGlyphRunAnalysis *aAnalysis, const IntRect &aBounds);
 
   // This creates a (partially) uploaded bitmap for a DataSourceSurface. It
@@ -200,17 +201,17 @@ private:
 
   static const uint32_t test = 4;
 
   IntSize mSize;
 
   RefPtr<ID3D10Device1> mDevice;
   RefPtr<ID3D10Texture2D> mTexture;
   RefPtr<ID3D10Texture2D> mCurrentClipMaskTexture;
-  RefPtr<ID2D1PathGeometry> mCurrentClippedGeometry;
+  RefPtr<ID2D1Geometry> mCurrentClippedGeometry;
   mutable RefPtr<ID2D1RenderTarget> mRT;
 
   // We store this to prevent excessive SetTextRenderingParams calls.
   RefPtr<IDWriteRenderingParams> mTextRenderingParams;
 
   // Temporary texture and render target used for supporting alternative operators.
   RefPtr<ID3D10Texture2D> mTempTexture;
   RefPtr<ID3D10RenderTargetView> mRTView;
--- a/gfx/layers/Layers.h
+++ b/gfx/layers/Layers.h
@@ -176,25 +176,32 @@ public:
   /**
    * Start a new transaction. Nested transactions are not allowed so
    * there must be no transaction currently in progress. 
    * This transaction will render the contents of the layer tree to
    * the given target context. The rendering will be complete when
    * EndTransaction returns.
    */
   virtual void BeginTransactionWithTarget(gfxContext* aTarget) = 0;
+  
+  enum EndTransactionFlags {
+    END_DEFAULT = 0,
+    END_NO_IMMEDIATE_REDRAW = 1 << 0,  // Do not perform the drawing phase
+    END_NO_COMPOSITE = 1 << 1 // Do not composite after drawing thebes layer contents.
+  };
+
   /**
    * Attempts to end an "empty transaction". There must have been no
    * changes to the layer tree since the BeginTransaction().
    * It's possible for this to fail; ThebesLayers may need to be updated
    * due to VRAM data being lost, for example. In such cases this method
    * returns false, and the caller must proceed with a normal layer tree
    * update and EndTransaction.
    */
-  virtual bool EndEmptyTransaction() = 0;
+  virtual bool EndEmptyTransaction(EndTransactionFlags aFlags = END_DEFAULT) = 0;
 
   /**
    * Function called to draw the contents of each ThebesLayer.
    * aRegionToDraw contains the region that needs to be drawn.
    * This would normally be a subregion of the visible region.
    * The callee must draw all of aRegionToDraw. Drawing outside
    * aRegionToDraw will be clipped out or ignored.
    * The callee must draw all of aRegionToDraw.
@@ -218,32 +225,30 @@ public:
    * The origin of aContext is 0,0 in the ThebesLayer.
    */
   typedef void (* DrawThebesLayerCallback)(ThebesLayer* aLayer,
                                            gfxContext* aContext,
                                            const nsIntRegion& aRegionToDraw,
                                            const nsIntRegion& aRegionToInvalidate,
                                            void* aCallbackData);
 
-  enum EndTransactionFlags {
-    END_DEFAULT = 0,
-    END_NO_IMMEDIATE_REDRAW = 1 << 0  // Do not perform the drawing phase
-  };
-
   /**
    * Finish the construction phase of the transaction, perform the
    * drawing phase, and end the transaction.
    * During the drawing phase, all ThebesLayers in the tree are
    * drawn in tree order, exactly once each, except for those layers
    * where it is known that the visible region is empty.
    */
   virtual void EndTransaction(DrawThebesLayerCallback aCallback,
                               void* aCallbackData,
                               EndTransactionFlags aFlags = END_DEFAULT) = 0;
 
+  virtual bool HasShadowManagerInternal() const { return false; }
+  bool HasShadowManager() const { return HasShadowManagerInternal(); }
+
   bool IsSnappingEffectiveTransforms() { return mSnapEffectiveTransforms; } 
 
   /** 
    * Returns true if this LayerManager can properly support layers with
    * SURFACE_COMPONENT_ALPHA. This can include disabling component
    * alpha if required.
    */
   virtual bool AreComponentAlphaLayersEnabled() { return true; }
--- a/gfx/layers/basic/BasicLayerManager.cpp
+++ b/gfx/layers/basic/BasicLayerManager.cpp
@@ -416,16 +416,22 @@ BasicLayerManager::EndTransactionInterna
   mPhase = PHASE_DRAWING;
 #endif
 
   Layer* aLayer = GetRoot();
   RenderTraceLayers(aLayer, "FF00");
 
   mTransactionIncomplete = false;
 
+  if (aFlags & END_NO_COMPOSITE) {
+    // TODO: We should really just set mTarget to null and make sure we can handle that further down the call chain
+    nsRefPtr<gfxASurface> surf = gfxPlatform::GetPlatform()->CreateOffscreenSurface(gfxIntSize(1, 1), gfxASurface::CONTENT_COLOR);
+    mTarget = new gfxContext(surf);
+  }
+
   if (mTarget && mRoot && !(aFlags & END_NO_IMMEDIATE_REDRAW)) {
     nsIntRect clipRect;
     if (HasShadowManager()) {
       // If this has a shadow manager, the clip extents of mTarget are meaningless.
       // So instead just use the root layer's visible region bounds.
       const nsIntRect& bounds = mRoot->GetVisibleRegion().GetBounds();
       gfxRect deviceRect =
           mTarget->UserToDevice(gfxRect(bounds.x, bounds.y, bounds.width, bounds.height));
@@ -445,19 +451,29 @@ BasicLayerManager::EndTransactionInterna
     if (IsRetained()) {
       nsIntRegion region;
       MarkLayersHidden(mRoot, clipRect, clipRect, region, ALLOW_OPAQUE);
       if (mUsingDefaultTarget && mDoubleBuffering != BUFFER_NONE) {
         ApplyDoubleBuffering(mRoot, clipRect);
       }
     }
 
-    PaintLayer(mTarget, mRoot, aCallback, aCallbackData, nullptr);
-    if (mWidget) {
-      FlashWidgetUpdateArea(mTarget);
+    if (aFlags & END_NO_COMPOSITE) {
+      if (IsRetained()) {
+        // Clip the destination out so that we don't draw to it, and
+        // only end up validating ThebesLayers.
+        mTarget->Clip(gfxRect(0, 0, 0, 0));
+        PaintLayer(mTarget, mRoot, aCallback, aCallbackData, nullptr);
+      }
+      // If we're not retained, then don't composite means do nothing at all.
+    } else {
+      PaintLayer(mTarget, mRoot, aCallback, aCallbackData, nullptr);
+      if (mWidget) {
+        FlashWidgetUpdateArea(mTarget);
+      }
     }
 
     if (!mTransactionIncomplete) {
       // Clear out target if we have a complete transaction.
       mTarget = nullptr;
     }
   }
 
@@ -503,23 +519,23 @@ BasicLayerManager::FlashWidgetUpdateArea
     float g = float(rand()) / RAND_MAX;
     float b = float(rand()) / RAND_MAX;
     aContext->SetColor(gfxRGBA(r, g, b, 0.2));
     aContext->Paint();
   }
 }
 
 bool
-BasicLayerManager::EndEmptyTransaction()
+BasicLayerManager::EndEmptyTransaction(EndTransactionFlags aFlags)
 {
   if (!mRoot) {
     return false;
   }
 
-  return EndTransactionInternal(nullptr, nullptr);
+  return EndTransactionInternal(nullptr, nullptr, aFlags);
 }
 
 void
 BasicLayerManager::SetRoot(Layer* aLayer)
 {
   NS_ASSERTION(aLayer, "Root can't be null");
   NS_ASSERTION(aLayer->Manager() == this, "Wrong manager");
   NS_ASSERTION(InConstruction(), "Only allowed in construction phase");
@@ -1034,19 +1050,19 @@ BasicShadowLayerManager::EndTransaction(
   } else if (mShadowTarget) {
     // Draw to shadow target at the recursion tail of the repeat transactions
     ShadowLayerForwarder::ShadowDrawToTarget(mShadowTarget);
     mShadowTarget = nullptr;
   }
 }
 
 bool
-BasicShadowLayerManager::EndEmptyTransaction()
+BasicShadowLayerManager::EndEmptyTransaction(EndTransactionFlags aFlags)
 {
-  if (!BasicLayerManager::EndEmptyTransaction()) {
+  if (!BasicLayerManager::EndEmptyTransaction(aFlags)) {
     // Return without calling ForwardTransaction. This leaves the
     // ShadowLayerForwarder transaction open; the following
     // EndTransaction will complete it.
     return false;
   }
   ForwardTransaction();
   return true;
 }
--- a/gfx/layers/basic/BasicLayers.h
+++ b/gfx/layers/basic/BasicLayers.h
@@ -82,17 +82,17 @@ public:
 
   nsIWidget* GetRetainerWidget() { return mWidget; }
   void ClearRetainerWidget() { mWidget = nullptr; }
 
   virtual bool IsWidgetLayerManager() { return mWidget != nullptr; }
 
   virtual void BeginTransaction();
   virtual void BeginTransactionWithTarget(gfxContext* aTarget);
-  virtual bool EndEmptyTransaction();
+  virtual bool EndEmptyTransaction(EndTransactionFlags aFlags = END_DEFAULT);
   virtual void EndTransaction(DrawThebesLayerCallback aCallback,
                               void* aCallbackData,
                               EndTransactionFlags aFlags = END_DEFAULT);
   virtual bool AreComponentAlphaLayersEnabled() { return HasShadowManager(); }
 
   void AbortTransaction();
 
   virtual void SetRoot(Layer* aLayer);
@@ -145,18 +145,16 @@ public:
   already_AddRefed<gfxContext> PushGroupForLayer(gfxContext* aContext, Layer* aLayer,
                                                  const nsIntRegion& aRegion,
                                                  bool* aNeedsClipToVisibleRegion);
   already_AddRefed<gfxContext> PushGroupWithCachedSurface(gfxContext *aTarget,
                                                           gfxASurface::gfxContentType aContent);
   void PopGroupToSourceWithCachedSurface(gfxContext *aTarget, gfxContext *aPushed);
 
   virtual bool IsCompositingCheap() { return false; }
-  virtual bool HasShadowManagerInternal() const { return false; }
-  bool HasShadowManager() const { return HasShadowManagerInternal(); }
   virtual PRInt32 GetMaxTextureSize() const { return PR_INT32_MAX; }
 
 protected:
   enum TransactionPhase {
     PHASE_NONE, PHASE_CONSTRUCTION, PHASE_DRAWING, PHASE_FORWARD
   };
   TransactionPhase mPhase;
 
@@ -216,17 +214,17 @@ public:
     return this;
   }
 
   virtual PRInt32 GetMaxTextureSize() const;
 
   virtual void SetDefaultTarget(gfxContext* aContext, BufferMode aDoubleBuffering,
                                 ScreenRotation aRotation) MOZ_OVERRIDE;
   virtual void BeginTransactionWithTarget(gfxContext* aTarget);
-  virtual bool EndEmptyTransaction();
+  virtual bool EndEmptyTransaction(EndTransactionFlags aFlags = END_DEFAULT);
   virtual void EndTransaction(DrawThebesLayerCallback aCallback,
                               void* aCallbackData,
                               EndTransactionFlags aFlags = END_DEFAULT);
 
   virtual void SetRoot(Layer* aLayer);
 
   virtual void Mutated(Layer* aLayer);
 
--- a/gfx/layers/basic/BasicThebesLayer.cpp
+++ b/gfx/layers/basic/BasicThebesLayer.cpp
@@ -22,19 +22,17 @@ BasicThebesLayer::CreateBuffer(Buffer::C
 {
   nsRefPtr<gfxASurface> referenceSurface = mBuffer.GetBuffer();
   if (!referenceSurface) {
     gfxContext* defaultTarget = BasicManager()->GetDefaultTarget();
     if (defaultTarget) {
       referenceSurface = defaultTarget->CurrentSurface();
     } else {
       nsIWidget* widget = BasicManager()->GetRetainerWidget();
-      if (widget) {
-        referenceSurface = widget->GetThebesSurface();
-      } else {
+      if (!widget || !(referenceSurface = widget->GetThebesSurface())) {
         referenceSurface = BasicManager()->GetTarget()->CurrentSurface();
       }
     }
   }
   return referenceSurface->CreateSimilarSurface(
     aType, gfxIntSize(aSize.width, aSize.height));
 }
 
--- a/gfx/layers/d3d10/ContainerLayerD3D10.cpp
+++ b/gfx/layers/d3d10/ContainerLayerD3D10.cpp
@@ -23,92 +23,105 @@ ContainerLayerD3D10::ContainerLayerD3D10
 }
 
 ContainerLayerD3D10::~ContainerLayerD3D10()
 {
   while (mFirstChild) {
     RemoveChild(mFirstChild);
   }
 }
+template<class Container>
+static void
+ContainerInsertAfter(Container* aContainer, Layer* aChild, Layer* aAfter)
+{
+    aChild->SetParent(aContainer);
+    if (!aAfter) {
+        Layer *oldFirstChild = aContainer->GetFirstChild();
+        aContainer->mFirstChild = aChild;
+        aChild->SetNextSibling(oldFirstChild);
+        aChild->SetPrevSibling(nullptr);
+        if (oldFirstChild) {
+            oldFirstChild->SetPrevSibling(aChild);
+        } else {
+            aContainer->mLastChild = aChild;
+        }
+        NS_ADDREF(aChild);
+        aContainer->DidInsertChild(aChild);
+        return;
+    }
+    for (Layer *child = aContainer->GetFirstChild(); 
+        child; child = child->GetNextSibling()) {
+            if (aAfter == child) {
+                Layer *oldNextSibling = child->GetNextSibling();
+                child->SetNextSibling(aChild);
+                aChild->SetNextSibling(oldNextSibling);
+                if (oldNextSibling) {
+                    oldNextSibling->SetPrevSibling(aChild);
+                } else {
+                    aContainer->mLastChild = aChild;
+                }
+                aChild->SetPrevSibling(child);
+                NS_ADDREF(aChild);
+                aContainer->DidInsertChild(aChild);
+                return;
+            }
+    }
+    NS_WARNING("Failed to find aAfter layer!");
+}
+
+template<class Container>
+static void
+ContainerRemoveChild(Container* aContainer, Layer* aChild)
+{
+    if (aContainer->GetFirstChild() == aChild) {
+        aContainer->mFirstChild = aContainer->GetFirstChild()->GetNextSibling();
+        if (aContainer->mFirstChild) {
+            aContainer->mFirstChild->SetPrevSibling(nullptr);
+        } else {
+            aContainer->mLastChild = nullptr;
+        }
+        aChild->SetNextSibling(nullptr);
+        aChild->SetPrevSibling(nullptr);
+        aChild->SetParent(nullptr);
+        aContainer->DidRemoveChild(aChild);
+        NS_RELEASE(aChild);
+        return;
+    }
+    Layer *lastChild = nullptr;
+    for (Layer *child = aContainer->GetFirstChild(); child; 
+        child = child->GetNextSibling()) {
+            if (child == aChild) {
+                // We're sure this is not our first child. So lastChild != NULL.
+                lastChild->SetNextSibling(child->GetNextSibling());
+                if (child->GetNextSibling()) {
+                    child->GetNextSibling()->SetPrevSibling(lastChild);
+                } else {
+                    aContainer->mLastChild = lastChild;
+                }
+                child->SetNextSibling(nullptr);
+                child->SetPrevSibling(nullptr);
+                child->SetParent(nullptr);
+                aContainer->DidRemoveChild(aChild);
+                NS_RELEASE(aChild);
+                return;
+            }
+            lastChild = child;
+    }
+}
 
 void
 ContainerLayerD3D10::InsertAfter(Layer* aChild, Layer* aAfter)
 {
-  aChild->SetParent(this);
-  if (!aAfter) {
-    Layer *oldFirstChild = GetFirstChild();
-    mFirstChild = aChild;
-    aChild->SetNextSibling(oldFirstChild);
-    aChild->SetPrevSibling(nullptr);
-    if (oldFirstChild) {
-      oldFirstChild->SetPrevSibling(aChild);
-    } else {
-      mLastChild = aChild;
-    }
-    NS_ADDREF(aChild);
-    DidInsertChild(aChild);
-    return;
-  }
-  for (Layer *child = GetFirstChild();
-       child; child = child->GetNextSibling()) {
-    if (aAfter == child) {
-      Layer *oldNextSibling = child->GetNextSibling();
-      child->SetNextSibling(aChild);
-      aChild->SetNextSibling(oldNextSibling);
-      if (oldNextSibling) {
-        oldNextSibling->SetPrevSibling(aChild);
-      } else {
-        mLastChild = aChild;
-      }
-      aChild->SetPrevSibling(child);
-      NS_ADDREF(aChild);
-      DidInsertChild(aChild);
-      return;
-    }
-  }
-  NS_WARNING("Failed to find aAfter layer!");
+  ContainerInsertAfter(this, aChild, aAfter);
 }
 
 void
 ContainerLayerD3D10::RemoveChild(Layer *aChild)
 {
-  if (GetFirstChild() == aChild) {
-    mFirstChild = GetFirstChild()->GetNextSibling();
-    if (mFirstChild) {
-      mFirstChild->SetPrevSibling(nullptr);
-    } else {
-      mLastChild = nullptr;
-    }
-    aChild->SetNextSibling(nullptr);
-    aChild->SetPrevSibling(nullptr);
-    aChild->SetParent(nullptr);
-    DidRemoveChild(aChild);
-    NS_RELEASE(aChild);
-    return;
-  }
-  Layer *lastChild = nullptr;
-  for (Layer *child = GetFirstChild(); child;
-       child = child->GetNextSibling()) {
-    if (child == aChild) {
-      // We're sure this is not our first child. So lastChild != NULL.
-      lastChild->SetNextSibling(child->GetNextSibling());
-      if (child->GetNextSibling()) {
-        child->GetNextSibling()->SetPrevSibling(lastChild);
-      } else {
-        mLastChild = lastChild;
-      }
-      child->SetNextSibling(nullptr);
-      child->SetPrevSibling(nullptr);
-      child->SetParent(nullptr);
-      DidRemoveChild(aChild);
-      NS_RELEASE(aChild);
-      return;
-    }
-    lastChild = child;
-  }
+  ContainerRemoveChild(this, aChild);
 }
 
 Layer*
 ContainerLayerD3D10::GetLayer()
 {
   return this;
 }
 
@@ -363,28 +376,33 @@ ContainerLayerD3D10::Validate()
 
 ShadowContainerLayerD3D10::ShadowContainerLayerD3D10(LayerManagerD3D10 *aManager) 
   : ShadowContainerLayer(aManager, NULL)
   , LayerD3D10(aManager)
 {
   mImplData = static_cast<LayerD3D10*>(this);
 }
 
-ShadowContainerLayerD3D10::~ShadowContainerLayerD3D10() {}
+ShadowContainerLayerD3D10::~ShadowContainerLayerD3D10() 
+{
+  while (mFirstChild) {
+    RemoveChild(mFirstChild);
+  }  
+}
 
 void
 ShadowContainerLayerD3D10::InsertAfter(Layer* aChild, Layer* aAfter)
 {
-  mFirstChild = aChild;
+  ContainerInsertAfter(this, aChild, aAfter);
 }
 
 void
 ShadowContainerLayerD3D10::RemoveChild(Layer* aChild)
 {
-
+  ContainerRemoveChild(this, aChild);
 }
 
 void
 ShadowContainerLayerD3D10::ComputeEffectiveTransforms(const gfx3DMatrix& aTransformToSurface)
 {
   DefaultComputeEffectiveTransforms(aTransformToSurface);
 }
 
@@ -404,12 +422,16 @@ ShadowContainerLayerD3D10::RenderLayer()
 void
 ShadowContainerLayerD3D10::Validate()
 {
 }
  
 void
 ShadowContainerLayerD3D10::LayerManagerDestroyed()
 {
+  while (mFirstChild) {
+    GetFirstChildD3D10()->LayerManagerDestroyed();
+    RemoveChild(mFirstChild);
+  }
 }
 
 } /* layers */
 } /* mozilla */
--- a/gfx/layers/d3d10/ContainerLayerD3D10.h
+++ b/gfx/layers/d3d10/ContainerLayerD3D10.h
@@ -6,19 +6,28 @@
 #ifndef GFX_CONTAINERLAYERD3D10_H
 #define GFX_CONTAINERLAYERD3D10_H
 
 #include "LayerManagerD3D10.h"
 
 namespace mozilla {
 namespace layers {
 
+template<class Container>
+static void ContainerInsertAfter(Container* aContainer, Layer* aChild, Layer* aAfter);
+template<class Container>
+static void ContainerRemoveChild(Container* aContainer, Layer* aChild);
+
 class ContainerLayerD3D10 : public ContainerLayer,
                             public LayerD3D10
 {
+  template<class Container>
+  friend void ContainerInsertAfter(Container* aContainer, Layer* aChild, Layer* aAfter);
+  template<class Container>
+  friend void ContainerRemoveChild(Container* aContainer, Layer* aChild);
 public:
   ContainerLayerD3D10(LayerManagerD3D10 *aManager);
   ~ContainerLayerD3D10();
 
   nsIntRect GetVisibleRect() { return mVisibleRegion.GetBounds(); }
 
   /* ContainerLayer implementation */
   virtual void InsertAfter(Layer* aChild, Layer* aAfter);
@@ -42,16 +51,20 @@ public:
 };
 
 // This is a bare-bones implementation of a container layer, only
 // enough to contain a shadow "window texture".  This impl doesn't
 // honor the transform/cliprect/etc. when rendering.
 class ShadowContainerLayerD3D10 : public ShadowContainerLayer,
                                   public LayerD3D10
 {
+  template<class Container>
+  friend void ContainerInsertAfter(Container* aContainer, Layer* aChild, Layer* aAfter);
+  template<class Container>
+  friend void ContainerRemoveChild(Container* aContainer, Layer* aChild);
 public:
   ShadowContainerLayerD3D10(LayerManagerD3D10 *aManager);
   ~ShadowContainerLayerD3D10();
 
   void InsertAfter(Layer* aChild, Layer* aAfter);
 
   void RemoveChild(Layer* aChild);
 
--- a/gfx/layers/d3d10/LayerManagerD3D10.cpp
+++ b/gfx/layers/d3d10/LayerManagerD3D10.cpp
@@ -195,17 +195,17 @@ LayerManagerD3D10::Initialize(bool force
 
     attachments->mVertexBuffer = mVertexBuffer;
   } else {
     mEffect = attachments->mEffect;
     mVertexBuffer = attachments->mVertexBuffer;
     mInputLayout = attachments->mInputLayout;
   }
 
-  if (HasShadowManager()) {
+  if (ShadowLayerForwarder::HasShadowManager()) {
     reporter.SetSuccessful();
     return true;
   }
 
   nsRefPtr<IDXGIDevice> dxgiDevice;
   nsRefPtr<IDXGIAdapter> dxgiAdapter;
 
   mDevice->QueryInterface(dxgiDevice.StartAssignment());
@@ -330,22 +330,22 @@ LayerManagerD3D10::BeginTransaction()
 
 void
 LayerManagerD3D10::BeginTransactionWithTarget(gfxContext* aTarget)
 {
   mTarget = aTarget;
 }
 
 bool
-LayerManagerD3D10::EndEmptyTransaction()
+LayerManagerD3D10::EndEmptyTransaction(EndTransactionFlags aFlags)
 {
   if (!mRoot)
     return false;
 
-  EndTransaction(nullptr, nullptr);
+  EndTransaction(nullptr, nullptr, aFlags);
   return true;
 }
 
 void
 LayerManagerD3D10::EndTransaction(DrawThebesLayerCallback aCallback,
                                   void* aCallbackData,
                                   EndTransactionFlags aFlags)
 {
@@ -357,17 +357,17 @@ LayerManagerD3D10::EndTransaction(DrawTh
     // so we don't need to pass any global transform here.
     mRoot->ComputeEffectiveTransforms(gfx3DMatrix());
 
 #ifdef MOZ_LAYERS_HAVE_LOG
     MOZ_LAYERS_LOG(("  ----- (beginning paint)"));
     Log();
 #endif
 
-    Render();
+    Render(aFlags);
     mCurrentCallbackInfo.Callback = nullptr;
     mCurrentCallbackInfo.CallbackData = nullptr;
   }
 
 #ifdef MOZ_LAYERS_HAVE_LOG
   Log();
   MOZ_LAYERS_LOG(("]----- EndTransaction"));
 #endif
@@ -698,20 +698,24 @@ LayerManagerD3D10::EnsureReadbackManager
     return;
   }
 
   mReadbackManager = new ReadbackManagerD3D10();
   attachments->mReadbackManager = mReadbackManager;
 }
 
 void
-LayerManagerD3D10::Render()
+LayerManagerD3D10::Render(EndTransactionFlags aFlags)
 {
   static_cast<LayerD3D10*>(mRoot->ImplData())->Validate();
 
+  if (aFlags & END_NO_COMPOSITE) {
+    return;
+  }
+
   SetupPipeline();
 
   float black[] = { 0, 0, 0, 0 };
   device()->ClearRenderTargetView(mRTView, black);
 
   nsIntRect rect;
   mWidget->GetClientBounds(rect);
 
--- a/gfx/layers/d3d10/LayerManagerD3D10.h
+++ b/gfx/layers/d3d10/LayerManagerD3D10.h
@@ -80,17 +80,17 @@ public:
   { return this; }
 
   virtual void SetRoot(Layer *aLayer);
 
   virtual void BeginTransaction();
 
   virtual void BeginTransactionWithTarget(gfxContext* aTarget);
 
-  virtual bool EndEmptyTransaction();
+  virtual bool EndEmptyTransaction(EndTransactionFlags aFlags = END_DEFAULT);
 
   struct CallbackInfo {
     DrawThebesLayerCallback Callback;
     void *CallbackData;
   };
 
   virtual void EndTransaction(DrawThebesLayerCallback aCallback,
                               void* aCallbackData,
@@ -173,17 +173,17 @@ public:
   static void ReportFailure(const nsACString &aMsg, HRESULT aCode);
 
 private:
   void SetupPipeline();
   void UpdateRenderTarget();
   void VerifyBufferSize();
   void EnsureReadbackManager();
 
-  void Render();
+  void Render(EndTransactionFlags aFlags);
 
   nsRefPtr<ID3D10Device1> mDevice;
 
   nsRefPtr<ID3D10Effect> mEffect;
   nsRefPtr<ID3D10InputLayout> mInputLayout;
   nsRefPtr<ID3D10Buffer> mVertexBuffer;
   nsRefPtr<ReadbackManagerD3D10> mReadbackManager;
 
--- a/gfx/layers/d3d9/CanvasLayerD3D9.cpp
+++ b/gfx/layers/d3d9/CanvasLayerD3D9.cpp
@@ -182,16 +182,19 @@ CanvasLayerD3D9::GetLayer()
 {
   return this;
 }
 
 void
 CanvasLayerD3D9::RenderLayer()
 {
   UpdateSurface();
+  if (mD3DManager->CompositingDisabled()) {
+    return;
+  }
   FireDidTransactionCallback();
 
   if (!mTexture)
     return;
 
   /*
    * We flip the Y axis here, note we can only do this because we are in 
    * CULL_NONE mode!
@@ -350,17 +353,17 @@ Layer*
 ShadowCanvasLayerD3D9::GetLayer()
 {
   return this;
 }
 
 void
 ShadowCanvasLayerD3D9::RenderLayer()
 {
-  if (!mBuffer) {
+  if (!mBuffer || mD3DManager->CompositingDisabled()) {
     return;
   }
 
   mBuffer->RenderTo(mD3DManager, GetEffectiveVisibleRegion());
 }
 
 
 } /* namespace layers */
--- a/gfx/layers/d3d9/ColorLayerD3D9.cpp
+++ b/gfx/layers/d3d9/ColorLayerD3D9.cpp
@@ -14,16 +14,19 @@ ColorLayerD3D9::GetLayer()
   return this;
 }
 
 static void
 RenderColorLayerD3D9(ColorLayer* aLayer, LayerManagerD3D9 *aManager)
 {
   // XXX we might be able to improve performance by using
   // IDirect3DDevice9::Clear
+  if (aManager->CompositingDisabled()) {
+    return;
+  }
 
   nsIntRect visibleRect = aLayer->GetEffectiveVisibleRegion().GetBounds();
 
   aManager->device()->SetVertexShaderConstantF(
     CBvLayerQuad,
     ShaderConstantRect(visibleRect.x,
                        visibleRect.y,
                        visibleRect.width,
--- a/gfx/layers/d3d9/ContainerLayerD3D9.cpp
+++ b/gfx/layers/d3d9/ContainerLayerD3D9.cpp
@@ -142,31 +142,34 @@ ContainerRender(Container* aContainer,
   ReadbackProcessor readback;
   readback.BuildUpdates(aContainer);
 
   nsIntRect visibleRect = aContainer->GetEffectiveVisibleRegion().GetBounds();
   bool useIntermediate = aContainer->UseIntermediateSurface();
 
   aContainer->mSupportsComponentAlphaChildren = false;
   if (useIntermediate) {
-    aManager->device()->GetRenderTarget(0, getter_AddRefs(previousRenderTarget));
-    HRESULT hr = aManager->device()->CreateTexture(visibleRect.width, visibleRect.height, 1,
-                                                   D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8,
-                                                   D3DPOOL_DEFAULT, getter_AddRefs(renderTexture),
-                                                   NULL);
-    if (FAILED(hr)) {
-      aManager->ReportFailure(NS_LITERAL_CSTRING("ContainerLayerD3D9::ContainerRender(): Failed to create texture"),
-                              hr);
-      return;
+    nsRefPtr<IDirect3DSurface9> renderSurface;
+    if (!aManager->CompositingDisabled()) {
+      aManager->device()->GetRenderTarget(0, getter_AddRefs(previousRenderTarget));
+      HRESULT hr = aManager->device()->CreateTexture(visibleRect.width, visibleRect.height, 1,
+                                                     D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8,
+                                                     D3DPOOL_DEFAULT, getter_AddRefs(renderTexture),
+                                                     NULL);
+      if (FAILED(hr)) {
+        aManager->ReportFailure(NS_LITERAL_CSTRING("ContainerLayerD3D9::ContainerRender(): Failed to create texture"),
+                                hr);
+        return;
+      }
+
+      nsRefPtr<IDirect3DSurface9> renderSurface;
+      renderTexture->GetSurfaceLevel(0, getter_AddRefs(renderSurface));
+      aManager->device()->SetRenderTarget(0, renderSurface);
     }
 
-    nsRefPtr<IDirect3DSurface9> renderSurface;
-    renderTexture->GetSurfaceLevel(0, getter_AddRefs(renderSurface));
-    aManager->device()->SetRenderTarget(0, renderSurface);
-
     if (aContainer->mVisibleRegion.GetNumRects() == 1 && 
         (aContainer->GetContentFlags() & aContainer->CONTENT_OPAQUE)) {
       // don't need a background, we're going to paint all opaque stuff
       aContainer->mSupportsComponentAlphaChildren = true;
     } else {
       const gfx3DMatrix& transform3D = aContainer->GetEffectiveTransform();
       gfxMatrix transform;
       // If we have an opaque ancestor layer, then we can be sure that
@@ -177,22 +180,24 @@ ContainerRender(Container* aContainer,
       if (HasOpaqueAncestorLayer(aContainer) &&
           transform3D.Is2D(&transform) && !transform.HasNonIntegerTranslation()) {
         // Copy background up from below
         RECT dest = { 0, 0, visibleRect.width, visibleRect.height };
         RECT src = dest;
         ::OffsetRect(&src,
                      visibleRect.x + PRInt32(transform.x0),
                      visibleRect.y + PRInt32(transform.y0));
-        hr = aManager->device()->
-          StretchRect(previousRenderTarget, &src, renderSurface, &dest, D3DTEXF_NONE);
+        if (!aManager->CompositingDisabled()) {
+          hr = aManager->device()->
+            StretchRect(previousRenderTarget, &src, renderSurface, &dest, D3DTEXF_NONE);
+        }
       }
       if (hr == S_OK) {
         aContainer->mSupportsComponentAlphaChildren = true;
-      } else {
+      } else if (!aManager->CompositingDisabled()) {
         aManager->device()->
           Clear(0, 0, D3DCLEAR_TARGET, D3DCOLOR_RGBA(0, 0, 0, 0), 0, 0);
       }
     }
 
     aManager->device()->
       GetVertexShaderConstantF(CBvRenderTargetOffset, previousRenderTargetOffset, 1);
     renderTargetOffset[0] = (float)visibleRect.x;
@@ -251,17 +256,17 @@ ContainerRender(Container* aContainer,
       static_cast<ThebesLayerD3D9*>(layerToRender)->RenderThebesLayer(&readback);
     } else {
       layerToRender->RenderLayer();
     }
   }
     
   aManager->device()->SetScissorRect(&containerD3D9ClipRect);
 
-  if (useIntermediate) {
+  if (useIntermediate && !aManager->CompositingDisabled()) {
     aManager->device()->SetRenderTarget(0, previousRenderTarget);
     aManager->device()->SetVertexShaderConstantF(CBvRenderTargetOffset, previousRenderTargetOffset, 1);
     aManager->device()->SetVertexShaderConstantF(CBmProjection, &oldViewMatrix[0][0], 4);
 
     aManager->device()->SetVertexShaderConstantF(CBvLayerQuad,
                                        ShaderConstantRect(visibleRect.x,
                                                           visibleRect.y,
                                                           visibleRect.width,
--- a/gfx/layers/d3d9/ImageLayerD3D9.cpp
+++ b/gfx/layers/d3d9/ImageLayerD3D9.cpp
@@ -350,17 +350,17 @@ ImageLayerD3D9::GetTexture(Image *aImage
 
   return data->mTexture;
 }
 
 void
 ImageLayerD3D9::RenderLayer()
 {
   ImageContainer *container = GetContainer();
-  if (!container) {
+  if (!container || mD3DManager->CompositingDisabled()) {
     return;
   }
 
   AutoLockImage autoLock(container);
 
   Image *image = autoLock.GetImage();
   if (!image) {
     return;
@@ -604,16 +604,20 @@ Layer*
 ShadowImageLayerD3D9::GetLayer()
 {
   return this;
 }
 
 void
 ShadowImageLayerD3D9::RenderLayer()
 {
+  if (mD3DManager->CompositingDisabled()) {
+    return;
+  }
+
   if (mBuffer) {
     mBuffer->RenderTo(mD3DManager, GetEffectiveVisibleRegion());
   } else if (mYCbCrImage) {
     if (!mYCbCrImage->mBufferSize) {
       return;
     }
 
     if (!mYCbCrImage->GetBackendData(mozilla::layers::LAYERS_D3D9)) {
--- a/gfx/layers/d3d9/LayerManagerD3D9.cpp
+++ b/gfx/layers/d3d9/LayerManagerD3D9.cpp
@@ -116,26 +116,26 @@ LayerManagerD3D9::BeginTransactionWithTa
 }
 
 void
 LayerManagerD3D9::EndConstruction()
 {
 }
 
 bool
-LayerManagerD3D9::EndEmptyTransaction()
+LayerManagerD3D9::EndEmptyTransaction(EndTransactionFlags aFlags)
 {
   // If the device reset count from our last EndTransaction doesn't match
   // the current device reset count, the device must have been reset one or
   // more times since our last transaction. In that case, an empty transaction
   // is not possible, because layers may need to be rerendered.
   if (!mRoot || mDeviceResetCount != mDeviceManager->GetDeviceResetCount())
     return false;
 
-  EndTransaction(nullptr, nullptr);
+  EndTransaction(nullptr, nullptr, aFlags);
   return true;
 }
 
 void
 LayerManagerD3D9::EndTransaction(DrawThebesLayerCallback aCallback,
                                  void* aCallbackData,
                                  EndTransactionFlags aFlags)
 {
@@ -144,16 +144,17 @@ LayerManagerD3D9::EndTransaction(DrawThe
   if (mRoot && !(aFlags & END_NO_IMMEDIATE_REDRAW)) {
     mCurrentCallbackInfo.Callback = aCallback;
     mCurrentCallbackInfo.CallbackData = aCallbackData;
 
     // The results of our drawing always go directly into a pixel buffer,
     // so we don't need to pass any global transform here.
     mRoot->ComputeEffectiveTransforms(gfx3DMatrix());
 
+    SetCompositingDisabled(aFlags & END_NO_COMPOSITE);
     Render();
     /* Clean this out for sanity */
     mCurrentCallbackInfo.Callback = NULL;
     mCurrentCallbackInfo.CallbackData = NULL;
   }
 
   // Clear mTarget, next transaction could have no target
   mTarget = NULL;
@@ -279,16 +280,22 @@ void
 LayerManagerD3D9::Render()
 {
   if (!mSwapChain->PrepareForRendering()) {
     return;
   }
   deviceManager()->SetupRenderState();
 
   SetupPipeline();
+
+  if (CompositingDisabled()) {
+    static_cast<LayerD3D9*>(mRoot->ImplData())->RenderLayer();
+    return;
+  }
+
   nsIntRect rect;
   mWidget->GetClientBounds(rect);
 
   device()->Clear(0, NULL, D3DCLEAR_TARGET, 0x00000000, 0, 0);
 
   device()->BeginScene();
 
   const nsIntRect *clipRect = mRoot->GetClipRect();
--- a/gfx/layers/d3d9/LayerManagerD3D9.h
+++ b/gfx/layers/d3d9/LayerManagerD3D9.h
@@ -93,17 +93,17 @@ public:
   { return this; }
 
   virtual void BeginTransaction();
 
   virtual void BeginTransactionWithTarget(gfxContext* aTarget);
 
   void EndConstruction();
 
-  virtual bool EndEmptyTransaction();
+  virtual bool EndEmptyTransaction(EndTransactionFlags aFlags = END_DEFAULT);
 
   struct CallbackInfo {
     DrawThebesLayerCallback Callback;
     void *CallbackData;
   };
 
   virtual void EndTransaction(DrawThebesLayerCallback aCallback,
                               void* aCallbackData,
@@ -171,16 +171,19 @@ public:
   }
 
 #ifdef MOZ_LAYERS_HAVE_LOG
   virtual const char* Name() const { return "D3D9"; }
 #endif // MOZ_LAYERS_HAVE_LOG
 
   void ReportFailure(const nsACString &aMsg, HRESULT aCode);
 
+  bool CompositingDisabled() { return mCompositingDisabled; }
+  void SetCompositingDisabled(bool aCompositingDisabled) { mCompositingDisabled = aCompositingDisabled; }
+
 private:
   /* Default device manager instance */
   static DeviceManagerD3D9 *mDefaultDeviceManager;
 
   /* Device manager instance for this layer manager */
   nsRefPtr<DeviceManagerD3D9> mDeviceManager;
 
   /* Swap chain associated with this layer manager */
@@ -204,16 +207,22 @@ private:
 
   /*
    * Device reset count at last paint. Whenever this changes, we need to
    * do a full layer tree update.
    */
   PRUint32 mDeviceResetCount;
 
   /*
+   * True if we should only be drawing layer contents, not
+   * compositing them to the target.
+   */
+  bool mCompositingDisabled;
+
+  /*
    * Render the current layer tree to the active target.
    */
   void Render();
 
   /*
    * Setup the pipeline.
    */
   void SetupPipeline();
--- a/gfx/layers/d3d9/ThebesLayerD3D9.cpp
+++ b/gfx/layers/d3d9/ThebesLayerD3D9.cpp
@@ -232,16 +232,20 @@ ThebesLayerD3D9::RenderThebesLayer(Readb
       return;
     }
 
     DrawRegion(drawRegion, mode, readbackUpdates);
 
     mValidRegion = neededRegion;
   }
 
+  if (mD3DManager->CompositingDisabled()) {
+    return;
+  }
+
   SetShaderTransformAndOpacity();
 
   if (mode == SURFACE_COMPONENT_ALPHA) {
     mD3DManager->SetShaderMode(DeviceManagerD3D9::COMPONENTLAYERPASS1,
                                GetMaskLayer());
     device()->SetTexture(0, mTexture);
     device()->SetTexture(1, mTextureOnWhite);
     device()->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ZERO);
@@ -650,17 +654,17 @@ bool
 ShadowThebesLayerD3D9::IsEmpty()
 {
   return !mBuffer;
 }
 
 void
 ShadowThebesLayerD3D9::RenderThebesLayer()
 {
-  if (!mBuffer) {
+  if (!mBuffer || mD3DManager->CompositingDisabled()) {
     return;
   }
   NS_ABORT_IF_FALSE(mBuffer, "should have a buffer here");
 
   mBuffer->RenderTo(mD3DManager, GetEffectiveVisibleRegion());
 }
 
 void
--- a/gfx/layers/opengl/CanvasLayerOGL.cpp
+++ b/gfx/layers/opengl/CanvasLayerOGL.cpp
@@ -224,16 +224,19 @@ CanvasLayerOGL::UpdateSurface()
   }
 }
 
 void
 CanvasLayerOGL::RenderLayer(int aPreviousDestination,
                             const nsIntPoint& aOffset)
 {
   UpdateSurface();
+  if (mOGLManager->CompositingDisabled()) {
+    return;
+  }
   FireDidTransactionCallback();
 
   mOGLManager->MakeCurrent();
 
   // XXX We're going to need a different program depending on if
   // mGLBufferIsPremultiplied is TRUE or not.  The RGBLayerProgram
   // assumes that it's true.
 
@@ -441,16 +444,19 @@ ShadowCanvasLayerOGL::GetLayer()
 void
 ShadowCanvasLayerOGL::RenderLayer(int aPreviousFrameBuffer,
                                   const nsIntPoint& aOffset)
 {
   if (!mTexImage && !IsValidSharedTexDescriptor(mFrontBufferDescriptor)) {
     return;
   }
 
+  if (mOGLManager->CompositingDisabled()) {
+    return;
+  }
   mOGLManager->MakeCurrent();
 
   gfx3DMatrix effectiveTransform = GetEffectiveTransform();
   gfxPattern::GraphicsFilter filter = mFilter;
 #ifdef ANDROID
   // Bug 691354
   // Using the LINEAR filter we get unexplained artifacts.
   // Use NEAREST when no scaling is required.
--- a/gfx/layers/opengl/ColorLayerOGL.cpp
+++ b/gfx/layers/opengl/ColorLayerOGL.cpp
@@ -7,16 +7,20 @@
 
 namespace mozilla {
 namespace layers {
 
 static void
 RenderColorLayer(ColorLayer* aLayer, LayerManagerOGL *aManager,
                  const nsIntPoint& aOffset)
 {
+  if (aManager->CompositingDisabled()) {
+    return;
+  }
+
   aManager->MakeCurrent();
 
   // XXX we might be able to improve performance by using glClear
 
   nsIntRect visibleRect = aLayer->GetEffectiveVisibleRegion().GetBounds();
 
   /* Multiply color by the layer opacity, as the shader
    * ignores layer opacity and expects a final color to
--- a/gfx/layers/opengl/ContainerLayerOGL.cpp
+++ b/gfx/layers/opengl/ContainerLayerOGL.cpp
@@ -174,22 +174,24 @@ ContainerRender(Container* aContainer,
         mode = LayerManagerOGL::InitModeCopy;
         framebufferRect.x += transform.x0;
         framebufferRect.y += transform.y0;
         aContainer->mSupportsComponentAlphaChildren = true;
       }
     }
 
     aContainer->gl()->PushViewportRect();
-    framebufferRect -= childOffset; 
-    aManager->CreateFBOWithTexture(framebufferRect,
-                                   mode,
-                                   aPreviousFrameBuffer,
-                                   &frameBuffer,
-                                   &containerSurface);
+    framebufferRect -= childOffset;
+    if (!aManager->CompositingDisabled()) {
+      aManager->CreateFBOWithTexture(framebufferRect,
+                                     mode,
+                                     aPreviousFrameBuffer,
+                                     &frameBuffer,
+                                     &containerSurface);
+    }
     childOffset.x = visibleRect.x;
     childOffset.y = visibleRect.y;
   } else {
     frameBuffer = aPreviousFrameBuffer;
     aContainer->mSupportsComponentAlphaChildren = (aContainer->GetContentFlags() & Layer::CONTENT_OPAQUE) ||
       (aContainer->GetParent() && aContainer->GetParent()->SupportsComponentAlphaChildren());
   }
 
@@ -234,55 +236,57 @@ ContainerRender(Container* aContainer,
 #endif
     
     // Restore the viewport
     aContainer->gl()->PopViewportRect();
     nsIntRect viewport = aContainer->gl()->ViewportRect();
     aManager->SetupPipeline(viewport.width, viewport.height,
                             LayerManagerOGL::ApplyWorldTransform);
     aContainer->gl()->PopScissorRect();
-
     aContainer->gl()->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, aPreviousFrameBuffer);
-    aContainer->gl()->fDeleteFramebuffers(1, &frameBuffer);
 
-    aContainer->gl()->fActiveTexture(LOCAL_GL_TEXTURE0);
+    if (!aManager->CompositingDisabled()) {
+      aContainer->gl()->fDeleteFramebuffers(1, &frameBuffer);
 
-    aContainer->gl()->fBindTexture(aManager->FBOTextureTarget(), containerSurface);
+      aContainer->gl()->fActiveTexture(LOCAL_GL_TEXTURE0);
+
+      aContainer->gl()->fBindTexture(aManager->FBOTextureTarget(), containerSurface);
 
-    MaskType maskType = MaskNone;
-    if (aContainer->GetMaskLayer()) {
-      if (!aContainer->GetTransform().CanDraw2D()) {
-        maskType = Mask3d;
-      } else {
-        maskType = Mask2d;
+      MaskType maskType = MaskNone;
+      if (aContainer->GetMaskLayer()) {
+        if (!aContainer->GetTransform().CanDraw2D()) {
+          maskType = Mask3d;
+        } else {
+          maskType = Mask2d;
+        }
       }
-    }
-    ShaderProgramOGL *rgb =
-      aManager->GetFBOLayerProgram(maskType);
+      ShaderProgramOGL *rgb =
+        aManager->GetFBOLayerProgram(maskType);
 
-    rgb->Activate();
-    rgb->SetLayerQuadRect(visibleRect);
-    rgb->SetLayerTransform(transform);
-    rgb->SetLayerOpacity(opacity);
-    rgb->SetRenderOffset(aOffset);
-    rgb->SetTextureUnit(0);
-    rgb->LoadMask(aContainer->GetMaskLayer());
+      rgb->Activate();
+      rgb->SetLayerQuadRect(visibleRect);
+      rgb->SetLayerTransform(transform);
+      rgb->SetLayerOpacity(opacity);
+      rgb->SetRenderOffset(aOffset);
+      rgb->SetTextureUnit(0);
+      rgb->LoadMask(aContainer->GetMaskLayer());
 
-    if (rgb->GetTexCoordMultiplierUniformLocation() != -1) {
-      // 2DRect case, get the multiplier right for a sampler2DRect
-      rgb->SetTexCoordMultiplier(visibleRect.width, visibleRect.height);
-    }
+      if (rgb->GetTexCoordMultiplierUniformLocation() != -1) {
+        // 2DRect case, get the multiplier right for a sampler2DRect
+        rgb->SetTexCoordMultiplier(visibleRect.width, visibleRect.height);
+      }
 
-    // Drawing is always flipped, but when copying between surfaces we want to avoid
-    // this. Pass true for the flip parameter to introduce a second flip
-    // that cancels the other one out.
-    aManager->BindAndDrawQuad(rgb, true);
+      // Drawing is always flipped, but when copying between surfaces we want to avoid
+      // this. Pass true for the flip parameter to introduce a second flip
+      // that cancels the other one out.
+      aManager->BindAndDrawQuad(rgb, true);
 
-    // Clean up resources.  This also unbinds the texture.
-    aContainer->gl()->fDeleteTextures(1, &containerSurface);
+      // Clean up resources.  This also unbinds the texture.
+      aContainer->gl()->fDeleteTextures(1, &containerSurface);
+    }
   } else {
     aContainer->gl()->PopScissorRect();
   }
 }
 
 ContainerLayerOGL::ContainerLayerOGL(LayerManagerOGL *aManager)
   : ContainerLayer(aManager, NULL)
   , LayerOGL(aManager)
--- a/gfx/layers/opengl/ImageLayerOGL.cpp
+++ b/gfx/layers/opengl/ImageLayerOGL.cpp
@@ -220,17 +220,17 @@ ImageLayerOGL::GetLayer()
 }
 
 void
 ImageLayerOGL::RenderLayer(int,
                            const nsIntPoint& aOffset)
 {
   nsRefPtr<ImageContainer> container = GetContainer();
 
-  if (!container)
+  if (!container || mOGLManager->CompositingDisabled())
     return;
 
   mOGLManager->MakeCurrent();
 
   AutoLockImage autoLock(container);
 
   Image *image = autoLock.GetImage();
   if (!image) {
@@ -870,16 +870,19 @@ void ShadowImageLayerOGL::UploadSharedYU
   UploadYUVToTexture(gl(), data, &mYUVTexture[0], &mYUVTexture[1], &mYUVTexture[2]);
 }
 
 
 void
 ShadowImageLayerOGL::RenderLayer(int aPreviousFrameBuffer,
                                  const nsIntPoint& aOffset)
 {
+  if (mOGLManager->CompositingDisabled()) {
+    return;
+  }
   mOGLManager->MakeCurrent();
   if (mImageContainerID) {
     ImageContainerParent::SetCompositorIDForImage(mImageContainerID,
                                                   mOGLManager->GetCompositorID());
     PRUint32 imgVersion = ImageContainerParent::GetSharedImageVersion(mImageContainerID);
     if (imgVersion != mImageVersion) {
       SharedImage* img = ImageContainerParent::GetSharedImage(mImageContainerID);
       if (img && (img->type() == SharedImage::TYUVImage)) {
--- a/gfx/layers/opengl/LayerManagerOGL.cpp
+++ b/gfx/layers/opengl/LayerManagerOGL.cpp
@@ -375,22 +375,22 @@ LayerManagerOGL::BeginTransactionWithTar
     NS_WARNING("Call on destroyed layer manager");
     return;
   }
 
   mTarget = aTarget;
 }
 
 bool
-LayerManagerOGL::EndEmptyTransaction()
+LayerManagerOGL::EndEmptyTransaction(EndTransactionFlags aFlags)
 {
   if (!mRoot)
     return false;
 
-  EndTransaction(nullptr, nullptr);
+  EndTransaction(nullptr, nullptr, aFlags);
   return true;
 }
 
 void
 LayerManagerOGL::EndTransaction(DrawThebesLayerCallback aCallback,
                                 void* aCallbackData,
                                 EndTransactionFlags aFlags)
 {
@@ -406,16 +406,17 @@ LayerManagerOGL::EndTransaction(DrawTheb
 
   if (mRoot && !(aFlags & END_NO_IMMEDIATE_REDRAW)) {
     // The results of our drawing always go directly into a pixel buffer,
     // so we don't need to pass any global transform here.
     mRoot->ComputeEffectiveTransforms(gfx3DMatrix());
 
     mThebesLayerCallback = aCallback;
     mThebesLayerCallbackData = aCallbackData;
+    SetCompositingDisabled(aFlags & END_NO_COMPOSITE);
 
     Render();
 
     mThebesLayerCallback = nullptr;
     mThebesLayerCallbackData = nullptr;
   }
 
   mTarget = NULL;
@@ -769,16 +770,23 @@ LayerManagerOGL::Render()
   if (clipRect) {
     nsIntRect r = *clipRect;
     WorldTransformRect(r);
     mGLContext->fScissor(r.x, r.y, r.width, r.height);
   } else {
     mGLContext->fScissor(0, 0, width, height);
   }
 
+  if (CompositingDisabled()) {
+    RootLayer()->RenderLayer(mGLContext->IsDoubleBuffered() ? 0 : mBackBufferFBO,
+                             nsIntPoint(0, 0));
+    mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
+    return;
+  }
+
   mGLContext->fEnable(LOCAL_GL_SCISSOR_TEST);
 
   // If the Java compositor is being used, this clear will be done in
   // DrawWindowUnderlay. Make sure the bits used here match up with those used
   // in mobile/android/base/gfx/LayerRenderer.java
 #ifndef MOZ_JAVA_COMPOSITOR
   mGLContext->fClearColor(0.0, 0.0, 0.0, 0.0);
   mGLContext->fClear(LOCAL_GL_COLOR_BUFFER_BIT | LOCAL_GL_DEPTH_BUFFER_BIT);
--- a/gfx/layers/opengl/LayerManagerOGL.h
+++ b/gfx/layers/opengl/LayerManagerOGL.h
@@ -97,17 +97,17 @@ public:
   }
 
   void BeginTransaction();
 
   void BeginTransactionWithTarget(gfxContext* aTarget);
 
   void EndConstruction();
 
-  virtual bool EndEmptyTransaction();
+  virtual bool EndEmptyTransaction(EndTransactionFlags aFlags = END_DEFAULT);
   virtual void EndTransaction(DrawThebesLayerCallback aCallback,
                               void* aCallbackData,
                               EndTransactionFlags aFlags = END_DEFAULT);
 
   virtual void SetRoot(Layer* aLayer) { mRoot = aLayer; }
 
   virtual bool CanUseCanvasLayerForSize(const gfxIntSize &aSize)
   {
@@ -345,16 +345,19 @@ public:
   gfxMatrix& GetWorldTransform(void);
   void WorldTransformRect(nsIntRect& aRect);
 
   /**
    * Set the size of the surface we're rendering to.
    */
   void SetSurfaceSize(int width, int height);
 
+  bool CompositingDisabled() { return mCompositingDisabled; }
+  void SetCompositingDisabled(bool aCompositingDisabled) { mCompositingDisabled = aCompositingDisabled; }
+
 private:
   /** Widget associated with this layer manager */
   nsIWidget *mWidget;
   nsIntSize mWidgetSize;
 
   /** The size of the surface we are rendering to */
   nsIntSize mSurfaceSize;
 
@@ -386,16 +389,17 @@ private:
    *  flipped and unflipped textures */
   GLuint mQuadVBO;
 
   /** Region we're clipping our current drawing to. */
   nsIntRegion mClippingRegion;
 
   /** Misc */
   bool mHasBGRA;
+  bool mCompositingDisabled;
 
   /**
    * When rendering to an EGL surface (e.g. on Android), we rely on being told
    * about size changes (via SetSurfaceSize) rather than pulling this information
    * from the widget, since the widget's information can lag behind.
    */
   bool mIsRenderingToEGLSurface;
 
--- a/gfx/layers/opengl/ThebesLayerOGL.cpp
+++ b/gfx/layers/opengl/ThebesLayerOGL.cpp
@@ -83,16 +83,18 @@ public:
 
   enum { PAINT_WILL_RESAMPLE = ThebesLayerBuffer::PAINT_WILL_RESAMPLE };
   virtual PaintState BeginPaint(ContentType aContentType,
                                 PRUint32 aFlags) = 0;
 
   void RenderTo(const nsIntPoint& aOffset, LayerManagerOGL* aManager,
                 PRUint32 aFlags);
 
+  void EndUpdate();
+
   nsIntSize GetSize() {
     if (mTexImage)
       return mTexImage->GetSize();
     return nsIntSize(0, 0);
   }
 
   bool Initialised() { return mInitialised; }
 
@@ -103,33 +105,38 @@ protected:
 
   ThebesLayer* mLayer;
   LayerOGL* mOGLLayer;
   nsRefPtr<TextureImage> mTexImage;
   nsRefPtr<TextureImage> mTexImageOnWhite;
   bool mInitialised;
 };
 
+void ThebesLayerBufferOGL::EndUpdate()
+{
+  if (mTexImage && mTexImage->InUpdate()) {
+    mTexImage->EndUpdate();
+  }
+
+  if (mTexImageOnWhite && mTexImageOnWhite->InUpdate()) {
+    mTexImageOnWhite->EndUpdate();
+  }
+}
+
 void
 ThebesLayerBufferOGL::RenderTo(const nsIntPoint& aOffset,
                                LayerManagerOGL* aManager,
                                PRUint32 aFlags)
 {
   NS_ASSERTION(Initialised(), "RenderTo with uninitialised buffer!");
 
   if (!mTexImage || !Initialised())
     return;
 
-  if (mTexImage->InUpdate()) {
-    mTexImage->EndUpdate();
-  }
-
-  if (mTexImageOnWhite && mTexImageOnWhite->InUpdate()) {
-    mTexImageOnWhite->EndUpdate();
-  }
+  EndUpdate();
 
 #ifdef MOZ_DUMP_PAINTING
   if (gfxUtils::sDumpPainting) {
     nsRefPtr<gfxImageSurface> surf = 
       gl()->GetTexImage(mTexImage->GetTextureID(), false, mTexImage->GetShaderProgramType());
     
     WriteSnapshotToDumpFile(mLayer, surf);
   }
@@ -833,16 +840,21 @@ ThebesLayerOGL::RenderLayer(int aPreviou
       // here (OR doesn't automatically simplify to the simplest possible
       // representation of a region.)
       nsIntRegion tmp;
       tmp.Or(mVisibleRegion, state.mRegionToDraw);
       mValidRegion.Or(mValidRegion, tmp);
     }
   }
 
+  if (mOGLManager->CompositingDisabled()) {
+    mBuffer->EndUpdate();
+    return;
+  }
+
   // Drawing thebes layers can change the current context, reset it.
   gl()->MakeCurrent();
 
   gl()->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, aPreviousFrameBuffer);
   mBuffer->RenderTo(aOffset, mOGLManager, flags);
 }
 
 Layer*
@@ -1094,17 +1106,17 @@ ShadowThebesLayerOGL::IsEmpty()
 {
   return !mBuffer;
 }
 
 void
 ShadowThebesLayerOGL::RenderLayer(int aPreviousFrameBuffer,
                                   const nsIntPoint& aOffset)
 {
-  if (!mBuffer) {
+  if (!mBuffer || mOGLManager->CompositingDisabled()) {
     return;
   }
   NS_ABORT_IF_FALSE(mBuffer, "should have a buffer here");
 
   mOGLManager->MakeCurrent();
 
   gl()->fActiveTexture(LOCAL_GL_TEXTURE0);
 
--- a/js/src/builtin/Eval.cpp
+++ b/js/src/builtin/Eval.cpp
@@ -81,35 +81,39 @@ class EvalScriptGuard
 {
     JSContext *cx_;
     Rooted<JSScript*> script_;
 
     /* These fields are only valid if lookup_.str is non-NULL. */
     EvalCacheLookup lookup_;
     EvalCache::AddPtr p_;
 
+    Rooted<JSLinearString*> lookupStr_;
+
   public:
     EvalScriptGuard(JSContext *cx)
-      : cx_(cx), script_(cx)
+      : cx_(cx), script_(cx), lookupStr_(cx)
     {
         lookup_.str = NULL;
     }
 
     ~EvalScriptGuard() {
         if (script_) {
             CallDestroyScriptHook(cx_->runtime->defaultFreeOp(), script_);
             script_->isActiveEval = false;
             script_->isCachedEval = true;
+            lookup_.str = lookupStr_;
             if (lookup_.str && IsEvalCacheCandidate(script_))
                 cx_->runtime->evalCache.relookupOrAdd(p_, lookup_, script_);
         }
     }
 
     void lookupInEvalCache(JSLinearString *str, JSFunction *caller, unsigned staticLevel)
     {
+        lookupStr_ = str;
         lookup_.str = str;
         lookup_.caller = caller;
         lookup_.staticLevel = staticLevel;
         lookup_.version = cx_->findVersion();
         lookup_.compartment = cx_->compartment;
         p_ = cx_->runtime->evalCache.lookupForAdd(lookup_);
         if (p_) {
             script_ = *p_;
--- a/js/src/builtin/MapObject.cpp
+++ b/js/src/builtin/MapObject.cpp
@@ -818,16 +818,18 @@ MapIteratorObject::next_impl(JSContext *
         return js_ThrowStopIteration(cx);
     if (range->empty()) {
         cx->delete_(range);
         thisobj.setReservedSlot(RangeSlot, PrivateValue(NULL));
         return js_ThrowStopIteration(cx);
     }
 
     Value pair[2] = { range->front().key.get(), range->front().value };
+    AutoValueArray root(cx, pair, 2);
+
     JSObject *pairobj = NewDenseCopiedArray(cx, 2, pair);
     if (!pairobj)
         return false;
     range->popFront();
     args.rval().setObject(*pairobj);
     return true;
 }
 
@@ -965,17 +967,17 @@ MapObject::construct(JSContext *cx, unsi
         return false;
     }
     obj->setPrivate(map);
 
     CallArgs args = CallArgsFromVp(argc, vp);
     if (args.hasDefined(0)) {
         ForOfIterator iter(cx, args[0]);
         while (iter.next()) {
-            JSObject *pairobj = js_ValueToNonNullObject(cx, iter.value());
+            RootedObject pairobj(cx, js_ValueToNonNullObject(cx, iter.value()));
             if (!pairobj)
                 return false;
 
             RootedValue key(cx);
             if (!pairobj->getElement(cx, 0, &key))
                 return false;
             HashableValue hkey;
             if (!hkey.setValue(cx, key))
--- a/js/src/config/config.mk
+++ b/js/src/config/config.mk
@@ -82,30 +82,22 @@ BUILD_TOOLS	= $(WIN_TOP_SRC)/build/unix
 else
 win_srcdir	:= $(srcdir)
 BUILD_TOOLS	= $(topsrcdir)/build/unix
 endif
 
 CONFIG_TOOLS	= $(MOZ_BUILD_ROOT)/config
 AUTOCONF_TOOLS	= $(topsrcdir)/build/autoconf
 
-ifeq ($(OS_ARCH),QNX)
-ifeq ($(OS_TARGET),NTO)
-LD		:= qcc -Vgcc_ntox86 -nostdlib
-else
-LD		:= $(CC)
-endif
-endif
-
 #
 # Strip off the excessively long version numbers on these platforms,
 # but save the version to allow multiple versions of the same base
 # platform to be built in the same tree.
 #
-ifneq (,$(filter FreeBSD HP-UX Linux NetBSD OpenBSD OSF1 SunOS,$(OS_ARCH)))
+ifneq (,$(filter FreeBSD HP-UX Linux NetBSD OpenBSD SunOS,$(OS_ARCH)))
 OS_RELEASE	:= $(basename $(OS_RELEASE))
 
 # Allow the user to ignore the OS_VERSION, which is usually irrelevant.
 ifdef WANT_MOZILLA_CONFIG_OS_VERSION
 OS_VERS		:= $(suffix $(OS_RELEASE))
 OS_VERSION	:= $(shell echo $(OS_VERS) | sed 's/-.*//')
 endif
 
--- a/js/src/config/rules.mk
+++ b/js/src/config/rules.mk
@@ -496,27 +496,16 @@ ifdef IS_COMPONENT
 ifneq ($(HAS_EXTRAEXPORTS),1)
 MKSHLIB += -bE:$(MOZILLA_DIR)/build/unix/aix.exp -bnoexpall
 MKCSHLIB += -bE:$(MOZILLA_DIR)/build/unix/aix.exp -bnoexpall
 endif # HAS_EXTRAEXPORTS
 endif # IS_COMPONENT
 endif # AIX
 
 #
-# OSF1: add -B symbolic flag for components
-#
-ifeq ($(OS_ARCH),OSF1)
-ifdef IS_COMPONENT
-ifeq ($(GNU_CC)$(GNU_CXX),)
-EXTRA_DSO_LDOPTS += -B symbolic
-endif
-endif
-endif
-
-#
 # Linux: add -Bsymbolic flag for components
 #
 ifeq ($(OS_ARCH),Linux)
 ifdef IS_COMPONENT
 EXTRA_DSO_LDOPTS += -Wl,-Bsymbolic
 endif
 endif
 
--- a/js/src/frontend/BytecodeCompiler.cpp
+++ b/js/src/frontend/BytecodeCompiler.cpp
@@ -298,18 +298,20 @@ frontend::CompileFunctionBody(JSContext 
         /*
          * NB: do not use AutoLocalNameArray because it will release space
          * allocated from cx->tempLifoAlloc by DefineArg.
          */
         BindingVector names(cx);
         if (!GetOrderedBindings(cx, funsc.bindings, &names))
             return false;
 
+        RootedPropertyName name(cx);
         for (unsigned i = 0; i < nargs; i++) {
-            if (!DefineArg(fn, names[i].maybeName, i, &parser))
+            name = names[i].maybeName;
+            if (!DefineArg(fn, name, i, &parser))
                 return false;
         }
     }
 
     /*
      * After we're done parsing, we must fold constants, analyze any nested
      * functions, and generate code for this function, including a stop opcode
      * at the end.
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -464,17 +464,17 @@ CheckStrictAssignment(JSContext *cx, Par
 
 /*
  * Check that it is permitted to introduce a binding for atom.  Strict mode
  * forbids introducing new definitions for 'eval', 'arguments', or for any
  * strict mode reserved keyword.  Use pn for reporting error locations, or use
  * tc's token stream if pn is NULL.
  */
 bool
-CheckStrictBinding(JSContext *cx, Parser *parser, PropertyName *name, ParseNode *pn)
+CheckStrictBinding(JSContext *cx, Parser *parser, HandlePropertyName name, ParseNode *pn)
 {
     if (!parser->tc->sc->needStrictChecks())
         return true;
 
     JSAtomState *atomState = &cx->runtime->atomState;
     if (name == atomState->evalAtom ||
         name == atomState->argumentsAtom ||
         FindKeyword(name->charsZ(), name->length()))
@@ -484,17 +484,17 @@ CheckStrictBinding(JSContext *cx, Parser
             return false;
         return parser->reportStrictModeError(pn, JSMSG_BAD_BINDING, bytes.ptr());
     }
 
     return true;
 }
 
 static bool
-ReportBadParameter(JSContext *cx, Parser *parser, JSAtom *name, unsigned errorNumber)
+ReportBadParameter(JSContext *cx, Parser *parser, HandlePropertyName name, unsigned errorNumber)
 {
     Definition *dn = parser->tc->decls.lookupFirst(name);
     JSAutoByteString bytes;
     return js_AtomToPrintableString(cx, name, &bytes) &&
            parser->reportStrictModeError(dn, errorNumber, bytes.ptr());
 }
 
 static bool
@@ -873,23 +873,23 @@ MakeDefIntoUse(Definition *dn, ParseNode
 /*
  * Parameter block types for the several Binder functions.  We use a common
  * helper function signature in order to share code among destructuring and
  * simple variable declaration parsers.  In the destructuring case, the binder
  * function is called indirectly from the variable declaration parser by way
  * of CheckDestructuring and its friends.
  */
 typedef bool
-(*Binder)(JSContext *cx, BindData *data, JSAtom *atom, Parser *parser);
+(*Binder)(JSContext *cx, BindData *data, HandlePropertyName name, Parser *parser);
 
 static bool
-BindLet(JSContext *cx, BindData *data, JSAtom *atom, Parser *parser);
+BindLet(JSContext *cx, BindData *data, HandlePropertyName name, Parser *parser);
 
 static bool
-BindVarOrConst(JSContext *cx, BindData *data, JSAtom *atom, Parser *parser);
+BindVarOrConst(JSContext *cx, BindData *data, HandlePropertyName name, Parser *parser);
 
 struct frontend::BindData {
     BindData(JSContext *cx) : let(cx) {}
 
     ParseNode       *pn;        /* name node for definition processing and
                                    error source coordinates */
     JSOp            op;         /* prolog bytecode or nop */
     Binder          binder;     /* binder, discriminates u */
@@ -1134,17 +1134,17 @@ LeaveFunction(ParseNode *fn, Parser *par
     return true;
 }
 
 /*
  * DefineArg is called for both the formals of a regular function definition
  * and the formals specified by the Function constructor.
  */
 bool
-frontend::DefineArg(ParseNode *pn, PropertyName *name, unsigned i, Parser *parser)
+frontend::DefineArg(ParseNode *pn, HandlePropertyName name, unsigned i, Parser *parser)
 {
     JSContext *cx = parser->context;
     TreeContext *tc = parser->tc;
     SharedContext *sc = tc->sc;
 
     /*
      * Make an argument definition node, distinguished by being in
      * parser->tc->decls but having PNK_NAME kind and JSOP_NOP op. Insert it in
@@ -1174,33 +1174,33 @@ frontend::DefineArg(ParseNode *pn, Prope
     if (!argpn->pn_cookie.set(cx, tc->staticLevel, i))
         return false;
     argpn->pn_dflags |= PND_BOUND;
     return true;
 }
 
 #if JS_HAS_DESTRUCTURING
 static bool
-BindDestructuringArg(JSContext *cx, BindData *data, JSAtom *atom, Parser *parser)
+BindDestructuringArg(JSContext *cx, BindData *data, HandlePropertyName name, Parser *parser)
 {
     TreeContext *tc = parser->tc;
     JS_ASSERT(tc->sc->inFunction());
 
     /*
      * NB: Check tc->decls rather than tc->sc->bindings, because destructuring
      *     bindings aren't added to tc->sc->bindings until after all arguments have
      *     been parsed.
      */
-    if (tc->decls.lookupFirst(atom)) {
+    if (tc->decls.lookupFirst(name)) {
         parser->reportError(NULL, JSMSG_DESTRUCT_DUP_ARG);
         return false;
     }
 
     ParseNode *pn = data->pn;
-    if (!CheckStrictBinding(cx, parser, atom->asPropertyName(), pn))
+    if (!CheckStrictBinding(cx, parser, name, pn))
         return false;
 
     /*
      * Distinguish destructured-to binding nodes as vars, not args, by setting
      * pn_op to JSOP_SETLOCAL. Parser::functionDef checks for this pn_op value
      * when processing the destructuring-assignment AST prelude induced by such
      * destructuring args in Parser::functionArguments.
      *
@@ -1215,17 +1215,17 @@ BindDestructuringArg(JSContext *cx, Bind
      * destructured, and zero or more VARs (as in named local variables) for
      * the destructured-to identifiers in the property value positions within
      * the object or array destructuring pattern, and all ARGs for the formal
      * parameter list bound as locals before any VAR for a destructured name.
      */
     pn->setOp(JSOP_SETLOCAL);
     pn->pn_dflags |= PND_BOUND;
 
-    return Define(pn, atom, tc);
+    return Define(pn, name, tc);
 }
 #endif /* JS_HAS_DESTRUCTURING */
 
 bool
 Parser::functionArguments(ParseNode **listp, bool &hasRest)
 {
     if (tokenStream.getToken() != TOK_LP) {
         reportError(NULL, JSMSG_PAREN_BEFORE_FORMAL);
@@ -2015,40 +2015,40 @@ ReportRedeclaration(JSContext *cx, Parse
  * must already be in such a scope.
  *
  * Throw a SyntaxError if 'atom' is an invalid name. Otherwise create a
  * property for the new variable on the block object, tc->blockChain;
  * populate data->pn->pn_{op,cookie,defn,dflags}; and stash a pointer to
  * data->pn in a slot of the block object.
  */
 static bool
-BindLet(JSContext *cx, BindData *data, JSAtom *atom, Parser *parser)
+BindLet(JSContext *cx, BindData *data, HandlePropertyName name, Parser *parser)
 {
     TreeContext *tc = parser->tc;
     ParseNode *pn = data->pn;
-    if (!CheckStrictBinding(cx, parser, atom->asPropertyName(), pn))
+    if (!CheckStrictBinding(cx, parser, name, pn))
         return false;
 
     Rooted<StaticBlockObject *> blockObj(cx, data->let.blockObj);
     unsigned blockCount = blockObj->slotCount();
     if (blockCount == JS_BIT(16)) {
         parser->reportError(pn, data->let.overflow);
         return false;
     }
 
     /*
      * For bindings that are hoisted to the beginning of the block/function,
      * Define() right now. For the rest, delay Define() until PushLetScope.
      */
     if (data->let.varContext == HoistVars) {
         JS_ASSERT(!tc->atBodyLevel());
-        Definition *dn = tc->decls.lookupFirst(atom);
+        Definition *dn = tc->decls.lookupFirst(name);
         if (dn && dn->pn_blockid == tc->blockid())
-            return ReportRedeclaration(cx, parser, pn, dn->isConst(), atom);
-        if (!Define(pn, atom, tc, true))
+            return ReportRedeclaration(cx, parser, pn, dn->isConst(), name);
+        if (!Define(pn, name, tc, true))
             return false;
     }
 
     /*
      * Assign block-local index to pn->pn_cookie right away, encoding it as an
      * upvar cookie whose skip tells the current static level. The emitter will
      * adjust the node's slot based on its stack depth model -- and, for global
      * and eval code, js::frontend::CompileScript will adjust the slot
@@ -2059,21 +2059,21 @@ BindLet(JSContext *cx, BindData *data, J
         return false;
     pn->pn_dflags |= PND_LET | PND_BOUND;
 
     /*
      * Define the let binding's property before storing pn in the the binding's
      * slot indexed by blockCount off the class-reserved slot base.
      */
     bool redeclared;
-    RootedId id(cx, AtomToId(atom));
+    RootedId id(cx, NameToId(name));
     Shape *shape = StaticBlockObject::addVar(cx, blockObj, id, blockCount, &redeclared);
     if (!shape) {
         if (redeclared)
-            ReportRedeclaration(cx, parser, pn, false, atom);
+            ReportRedeclaration(cx, parser, pn, false, name);
         return false;
     }
 
     /* Store pn in the static block object. */
     blockObj->setDefinitionParseNode(blockCount, reinterpret_cast<Definition *>(pn));
     return true;
 }
 
@@ -2158,42 +2158,40 @@ BindFunctionLocal(JSContext *cx, BindDat
     } else {
         JS_ASSERT(bi->kind == VARIABLE || bi->kind == CONSTANT);
     }
 
     return true;
 }
 
 static bool
-BindVarOrConst(JSContext *cx, BindData *data, JSAtom *atom_, Parser *parser)
+BindVarOrConst(JSContext *cx, BindData *data, HandlePropertyName name, Parser *parser)
 {
-    RootedAtom atom(cx, atom_);
-
     TreeContext *tc = parser->tc;
     ParseNode *pn = data->pn;
 
     /* Default best op for pn is JSOP_NAME; we'll try to improve below. */
     pn->setOp(JSOP_NAME);
 
-    if (!CheckStrictBinding(cx, parser, atom->asPropertyName(), pn))
+    if (!CheckStrictBinding(cx, parser, name, pn))
         return false;
 
-    StmtInfoTC *stmt = LexicalLookup(tc, atom, NULL, (StmtInfoTC *)NULL);
+    StmtInfoTC *stmt = LexicalLookup(tc, name, NULL, (StmtInfoTC *)NULL);
 
     if (stmt && stmt->type == STMT_WITH) {
         pn->pn_dflags |= PND_DEOPTIMIZED;
         tc->sc->setFunMightAliasLocals();
         return true;
     }
 
-    DefinitionList::Range defs = tc->decls.lookupMulti(atom);
+    DefinitionList::Range defs = tc->decls.lookupMulti(name);
     JS_ASSERT_IF(stmt, !defs.empty());
 
     if (defs.empty()) {
-        if (!Define(pn, atom, tc))
+        if (!Define(pn, name, tc))
             return false;
 
         if (data->op == JSOP_DEFCONST)
             pn->pn_dflags |= PND_CONST;
 
         if (tc->sc->inFunction())
             return BindFunctionLocal(cx, data, defs, tc);
 
@@ -2205,42 +2203,42 @@ BindVarOrConst(JSContext *cx, BindData *
      * disallows several forms of redeclaration. Critically,
      *   let (x) { var x; } // error
      * is not allowed which allows us to turn any non-error redeclaration
      * into a use of the initial declaration.
      */
     Definition *dn = defs.front();
     Definition::Kind dn_kind = dn->kind();
     if (dn_kind == Definition::ARG) {
-        JSAutoByteString name;
-        if (!js_AtomToPrintableString(cx, atom, &name))
+        JSAutoByteString bytes;
+        if (!js_AtomToPrintableString(cx, name, &bytes))
             return false;
 
         if (data->op == JSOP_DEFCONST) {
-            parser->reportError(pn, JSMSG_REDECLARED_PARAM, name.ptr());
+            parser->reportError(pn, JSMSG_REDECLARED_PARAM, bytes.ptr());
             return false;
         }
-        if (!parser->reportStrictWarning(pn, JSMSG_VAR_HIDES_ARG, name.ptr()))
+        if (!parser->reportStrictWarning(pn, JSMSG_VAR_HIDES_ARG, bytes.ptr()))
             return false;
     } else {
         bool error = (data->op == JSOP_DEFCONST ||
                       dn_kind == Definition::CONST ||
                       (dn_kind == Definition::LET &&
-                       (stmt->type != STMT_CATCH || OuterLet(tc, stmt, atom))));
+                       (stmt->type != STMT_CATCH || OuterLet(tc, stmt, name))));
 
         if (cx->hasStrictOption()
             ? data->op != JSOP_DEFVAR || dn_kind != Definition::VAR
             : error)
         {
-            JSAutoByteString name;
+            JSAutoByteString bytes;
             Parser::Reporter reporter =
                 error ? &Parser::reportError : &Parser::reportStrictWarning;
-            if (!js_AtomToPrintableString(cx, atom, &name) ||
+            if (!js_AtomToPrintableString(cx, name, &bytes) ||
                 !(parser->*reporter)(pn, JSMSG_REDECLARED_VAR,
-                                     Definition::kindString(dn_kind), name.ptr()))
+                                     Definition::kindString(dn_kind), bytes.ptr()))
             {
                 return false;
             }
         }
     }
 
     LinkUseToDef(pn, dn);
     return true;
@@ -2324,18 +2322,20 @@ NoteNameUse(ParseNode *pn, Parser *parse
 
 #if JS_HAS_DESTRUCTURING
 
 static bool
 BindDestructuringVar(JSContext *cx, BindData *data, ParseNode *pn, Parser *parser)
 {
     JS_ASSERT(pn->isKind(PNK_NAME));
 
+    RootedPropertyName name(cx, pn->pn_atom->asPropertyName());
+
     data->pn = pn;
-    if (!data->binder(cx, data, pn->pn_atom, parser))
+    if (!data->binder(cx, data, name, parser))
         return false;
 
     /*
      * Select the appropriate name-setting opcode, respecting eager selection
      * done by the data->binder function.
      */
     if (pn->pn_dflags & PND_BOUND)
         pn->setOp(JSOP_SETLOCAL);
@@ -3432,17 +3432,17 @@ Parser::tryStatement()
                 pn3 = destructuringExpr(&data, tt);
                 if (!pn3)
                     return NULL;
                 break;
 #endif
 
               case TOK_NAME:
               {
-                JSAtom *label = tokenStream.currentToken().name();
+                RootedPropertyName label(context, tokenStream.currentToken().name());
                 pn3 = NewBindingNode(label, this);
                 if (!pn3)
                     return NULL;
                 data.pn = pn3;
                 if (!data.binder(context, &data, label, this))
                     return NULL;
                 break;
               }
@@ -4143,17 +4143,17 @@ Parser::variables(ParseNodeKind kind, St
 #endif /* JS_HAS_DESTRUCTURING */
 
         if (tt != TOK_NAME) {
             if (tt != TOK_ERROR)
                 reportError(NULL, JSMSG_NO_VARIABLE_NAME);
             return NULL;
         }
 
-        PropertyName *name = tokenStream.currentToken().name();
+        RootedPropertyName name(context, tokenStream.currentToken().name());
         pn2 = NewBindingNode(name, this, varContext);
         if (!pn2)
             return NULL;
         if (data.op == JSOP_DEFCONST)
             pn2->pn_dflags |= PND_CONST;
         data.pn = pn2;
         if (!data.binder(context, &data, name, this))
             return NULL;
--- a/js/src/frontend/Parser.h
+++ b/js/src/frontend/Parser.h
@@ -322,17 +322,17 @@ Parser::reportStrictModeError(ParseNode 
     va_list args;
     va_start(args, errorNumber);
     bool result = tokenStream.reportStrictModeErrorNumberVA(pn, errorNumber, args);
     va_end(args);
     return result;
 }
 
 bool
-DefineArg(ParseNode *pn, PropertyName *name, unsigned i, Parser *parser);
+DefineArg(ParseNode *pn, HandlePropertyName name, unsigned i, Parser *parser);
 
 } /* namespace frontend */
 } /* namespace js */
 
 /*
  * Convenience macro to access Parser.tokenStream as a pointer.
  */
 #define TS(p) (&(p)->tokenStream)
--- a/js/src/jit-test/tests/sunspider/check-crypto-md5.js
+++ b/js/src/jit-test/tests/sunspider/check-crypto-md5.js
@@ -278,10 +278,15 @@ And, Montague, come you this afternoon,\
 To know our further pleasure in this case,\n\
 To old Free-town, our common judgment-place.\n\
 Once more, on pain of death, all men depart."
 
 for (var i = 0; i <4; i++) {
     plainText += plainText;
 }
 
+// root checks performed during integer conversion operations can poison
+// crypto integers in this test.
+if (relaxRootChecks)
+  relaxRootChecks();
+
 var md5Output = hex_md5(plainText);
 assertEq(md5Output, "a831e91e0f70eddcb70dc61c6f82f6cd")
--- a/js/src/jit-test/tests/sunspider/check-crypto-sha1.js
+++ b/js/src/jit-test/tests/sunspider/check-crypto-sha1.js
@@ -216,10 +216,15 @@ Which, but their children's end, nought 
 Is now the two hours' traffic of our stage;\n\
 The which if you with patient ears attend,\n\
 What here shall miss, our toil shall strive to mend.";
 
 for (var i = 0; i <4; i++) {
     plainText += plainText;
 }
 
+// root checks performed during integer conversion operations can poison
+// crypto integers in this test.
+if (relaxRootChecks)
+  relaxRootChecks();
+
 var sha1Output = hex_sha1(plainText);
 assertEq(sha1Output, "2524d264def74cce2498bf112bedf00e6c0b796d")
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -591,37 +591,39 @@ JS_ValueToInt64(JSContext *cx, jsval v, 
 JS_PUBLIC_API(JSBool)
 JS_ValueToUint64(JSContext *cx, jsval v, uint64_t *ip)
 {
     RootedValue value(cx, v);
     return JS::ToUint64(cx, value, ip);
 }
 
 JS_PUBLIC_API(JSBool)
-JS_ValueToInt32(JSContext *cx, jsval v, int32_t *ip)
-{
-    AssertHeapIsIdle(cx);
-    CHECK_REQUEST(cx);
+JS_ValueToInt32(JSContext *cx, jsval vArg, int32_t *ip)
+{
+    AssertHeapIsIdle(cx);
+    CHECK_REQUEST(cx);
+
+    RootedValue v(cx, vArg);
     assertSameCompartment(cx, v);
 
     if (v.isInt32()) {
         *ip = v.toInt32();
         return true;
     }
 
     double d;
     if (v.isDouble()) {
         d = v.toDouble();
     } else if (!ToNumberSlow(cx, v, &d)) {
         return false;
     }
 
     if (MOZ_DOUBLE_IS_NaN(d) || d <= -2147483649.0 || 2147483648.0 <= d) {
         js_ReportValueError(cx, JSMSG_CANT_CONVERT,
-                            JSDVG_SEARCH_STACK, v, NULL);
+                            JSDVG_SEARCH_STACK, v, NullPtr());
         return false;
     }
 
     *ip = (int32_t) floor(d + 0.5);  /* Round to nearest */
     return true;
 }
 
 JS_PUBLIC_API(JSBool)
@@ -4952,22 +4954,24 @@ JS_BindCallable(JSContext *cx, JSObject 
     RootedObject target(cx, targetArg);
     RootedValue thisArg(cx, ObjectValue(*newThis));
     return js_fun_bind(cx, target, thisArg, NULL, 0);
 }
 
 JSBool
 js_generic_native_method_dispatcher(JSContext *cx, unsigned argc, Value *vp)
 {
+    CallArgs args = CallArgsFromVp(argc, vp);
+
     JSFunctionSpec *fs = (JSFunctionSpec *)
         vp->toObject().toFunction()->getExtendedSlot(0).toPrivate();
     JS_ASSERT((fs->flags & JSFUN_GENERIC_NATIVE) != 0);
 
     if (argc < 1) {
-        js_ReportMissingArg(cx, *vp, 0);
+        js_ReportMissingArg(cx, args.calleev(), 0);
         return JS_FALSE;
     }
 
     /*
      * Copy all actual (argc) arguments down over our |this| parameter, vp[1],
      * which is almost always the class constructor object, e.g. Array.  Then
      * call the corresponding prototype native method with our first argument
      * passed as |this|.
@@ -5913,18 +5917,18 @@ JS_New(JSContext *cx, JSObject *ctorArg,
     // This is not a simple variation of JS_CallFunctionValue because JSOP_NEW
     // is not a simple variation of JSOP_CALL. We have to determine what class
     // of object to create, create it, and clamp the return value to an object,
     // among other details. InvokeConstructor does the hard work.
     InvokeArgsGuard args;
     if (!cx->stack.pushInvokeArgs(cx, argc, &args))
         return NULL;
 
-    args.calleev().setObject(*ctor);
-    args.thisv().setNull();
+    args.setCallee(ObjectValue(*ctor));
+    args.setThis(NullValue());
     PodCopy(args.array(), argv, argc);
 
     if (!InvokeConstructor(cx, args))
         return NULL;
 
     if (!args.rval().isObject()) {
         /*
          * Although constructors may return primitives (via proxies), this
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -1048,25 +1048,26 @@ class JS_PUBLIC_API(AutoGCRooter) {
         XML =          -9, /* js::AutoXMLRooter */
         OBJECT =      -10, /* js::AutoObjectRooter */
         ID =          -11, /* js::AutoIdRooter */
         VALVECTOR =   -12, /* js::AutoValueVector */
         DESCRIPTOR =  -13, /* js::AutoPropertyDescriptorRooter */
         STRING =      -14, /* js::AutoStringRooter */
         IDVECTOR =    -15, /* js::AutoIdVector */
         OBJVECTOR =   -16, /* js::AutoObjectVector */
-        SCRIPTVECTOR =-17, /* js::AutoScriptVector */
-        PROPDESC =    -18, /* js::PropDesc::AutoRooter */
-        SHAPERANGE =  -19, /* js::Shape::Range::AutoRooter */
-        STACKSHAPE =  -20, /* js::StackShape::AutoRooter */
-        STACKBASESHAPE=-21,/* js::StackBaseShape::AutoRooter */
-        BINDINGS =    -22, /* js::Bindings::AutoRooter */
-        GETTERSETTER =-23, /* js::AutoRooterGetterSetter */
-        REGEXPSTATICS=-24, /* js::RegExpStatics::AutoRooter */
-        HASHABLEVALUE=-25
+        STRINGVECTOR =-17, /* js::AutoStringVector */
+        SCRIPTVECTOR =-18, /* js::AutoScriptVector */
+        PROPDESC =    -19, /* js::PropDesc::AutoRooter */
+        SHAPERANGE =  -20, /* js::Shape::Range::AutoRooter */
+        STACKSHAPE =  -21, /* js::StackShape::AutoRooter */
+        STACKBASESHAPE=-22,/* js::StackBaseShape::AutoRooter */
+        BINDINGS =    -23, /* js::Bindings::AutoRooter */
+        GETTERSETTER =-24, /* js::AutoRooterGetterSetter */
+        REGEXPSTATICS=-25, /* js::RegExpStatics::AutoRooter */
+        HASHABLEVALUE=-26
     };
 
   private:
     AutoGCRooter ** const stackTop;
 
     /* No copy or assignment semantics. */
     AutoGCRooter(AutoGCRooter &ida) MOZ_DELETE;
     void operator=(AutoGCRooter &ida) MOZ_DELETE;
@@ -1250,16 +1251,17 @@ class AutoVectorRooter : protected AutoG
     explicit AutoVectorRooter(JSContext *cx, ptrdiff_t tag
                               JS_GUARD_OBJECT_NOTIFIER_PARAM)
       : AutoGCRooter(cx, tag), vector(cx), vectorRoot(cx, &vector)
     {
         JS_GUARD_OBJECT_NOTIFIER_INIT;
     }
 
     size_t length() const { return vector.length(); }
+    bool empty() const { return vector.empty(); }
 
     bool append(const T &v) { return vector.append(v); }
     bool append(const AutoVectorRooter<T> &other) {
         return vector.append(other.vector);
     }
 
     /* For use when space has already been reserved. */
     void infallibleAppend(const T &v) { vector.infallibleAppend(v); }
@@ -1376,32 +1378,43 @@ class CallReceiver
     void clearUsedRval() const {}
 #endif
     Value *argv_;
   public:
     friend CallReceiver CallReceiverFromVp(Value *);
     friend CallReceiver CallReceiverFromArgv(Value *);
     Value *base() const { return argv_ - 2; }
     JSObject &callee() const { JS_ASSERT(!usedRval_); return argv_[-2].toObject(); }
-    Value &calleev() const { JS_ASSERT(!usedRval_); return argv_[-2]; }
-    Value &thisv() const { return argv_[-1]; }
+
+    JS::HandleValue calleev() const {
+        JS_ASSERT(!usedRval_);
+        return JS::HandleValue::fromMarkedLocation(&argv_[-2]);
+    }
+
+    JS::HandleValue thisv() const {
+        return JS::HandleValue::fromMarkedLocation(&argv_[-1]);
+    }
 
     JS::MutableHandleValue rval() const {
         setUsedRval();
         return JS::MutableHandleValue::fromMarkedLocation(&argv_[-2]);
     }
 
     Value *spAfterCall() const {
         setUsedRval();
         return argv_ - 1;
     }
 
-    void setCallee(Value calleev) {
+    void setCallee(Value calleev) const {
         clearUsedRval();
-        this->calleev() = calleev;
+        argv_[-2] = calleev;
+    }
+
+    void setThis(Value thisv) const {
+        argv_[-1] = thisv;
     }
 };
 
 JS_ALWAYS_INLINE CallReceiver
 CallReceiverFromArgv(Value *argv)
 {
     CallReceiver receiver;
     receiver.clearUsedRval();
--- a/js/src/jsarray.cpp
+++ b/js/src/jsarray.cpp
@@ -1530,17 +1530,17 @@ class AutoArrayCycleDetector
 static bool
 array_join_sub(JSContext *cx, CallArgs &args, bool locale)
 {
     // This method is shared by Array.prototype.join and
     // Array.prototype.toLocaleString. The steps in ES5 are nearly the same, so
     // the annotations in this function apply to both toLocaleString and join.
 
     // Step 1
-    RootedObject obj(cx, ToObject(cx, &args.thisv()));
+    RootedObject obj(cx, ToObject(cx, args.thisv()));
     if (!obj)
         return false;
 
     AutoArrayCycleDetector detector(cx, obj);
     if (!detector.init())
         return false;
 
     if (detector.foundCycle()) {
@@ -1618,17 +1618,17 @@ array_join_sub(JSContext *cx, CallArgs &
                 return false;
 
             JSBool hole;
             if (!GetElement(cx, obj, index, &hole, &elt))
                 return false;
 
             if (!hole && !elt.isNullOrUndefined()) {
                 if (locale) {
-                    JSObject *robj = ToObject(cx, elt.address());
+                    JSObject *robj = ToObject(cx, elt);
                     if (!robj)
                         return false;
                     RootedId id(cx, NameToId(cx->runtime->atomState.toLocaleStringAtom));
                     if (!robj->callMethod(cx, id, 0, NULL, &elt))
                         return false;
                 }
                 if (!ValueToStringBuffer(cx, elt, sb))
                     return false;
@@ -1652,17 +1652,17 @@ array_join_sub(JSContext *cx, CallArgs &
 
 /* ES5 15.4.4.2. NB: The algorithm here differs from the one in ES3. */
 static JSBool
 array_toString(JSContext *cx, unsigned argc, Value *vp)
 {
     JS_CHECK_RECURSION(cx, return false);
 
     CallArgs args = CallArgsFromVp(argc, vp);
-    RootedObject obj(cx, ToObject(cx, &args.thisv()));
+    RootedObject obj(cx, ToObject(cx, args.thisv()));
     if (!obj)
         return false;
 
     RootedValue join(cx, args.calleev());
     if (!obj->getProperty(cx, cx->runtime->atomState.joinAtom, &join))
         return false;
 
     if (!js_IsCallable(join)) {
@@ -1672,18 +1672,18 @@ array_toString(JSContext *cx, unsigned a
         args.rval().setString(str);
         return true;
     }
 
     InvokeArgsGuard ag;
     if (!cx->stack.pushInvokeArgs(cx, 0, &ag))
         return false;
 
-    ag.calleev() = join;
-    ag.thisv().setObject(*obj);
+    ag.setCallee(join);
+    ag.setThis(ObjectValue(*obj));
 
     /* Do the call. */
     if (!Invoke(cx, ag))
         return false;
     args.rval().set(ag.rval());
     return true;
 }
 
@@ -1803,17 +1803,17 @@ InitArrayElements(JSContext *cx, HandleO
 
     return true;
 }
 
 static JSBool
 array_reverse(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
-    RootedObject obj(cx, ToObject(cx, &args.thisv()));
+    RootedObject obj(cx, ToObject(cx, args.thisv()));
     if (!obj)
         return false;
 
     uint32_t len;
     if (!js_GetLengthProperty(cx, obj, &len))
         return false;
 
     do {
@@ -2073,17 +2073,17 @@ SortComparatorFunction::operator()(const
 
     if (!JS_CHECK_OPERATION_LIMIT(cx))
         return false;
 
     if (!ag.pushed() && !cx->stack.pushInvokeArgs(cx, 2, &ag))
         return false;
 
     ag.setCallee(fval);
-    ag.thisv() = UndefinedValue();
+    ag.setThis(UndefinedValue());
     ag[0] = a;
     ag[1] = b;
 
     if (!Invoke(cx, ag))
         return false;
 
     double cmp;
     if (!ToNumber(cx, ag.rval(), &cmp))
@@ -2113,17 +2113,17 @@ js::array_sort(JSContext *cx, unsigned a
             JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_SORT_ARG);
             return false;
         }
         fval = args[0];     /* non-default compare function */
     } else {
         fval.setNull();
     }
 
-    RootedObject obj(cx, ToObject(cx, &args.thisv()));
+    RootedObject obj(cx, ToObject(cx, args.thisv()));
     if (!obj)
         return false;
 
     uint32_t len;
     if (!js_GetLengthProperty(cx, obj, &len))
         return false;
     if (len == 0) {
         args.rval().setObject(*obj);
@@ -2353,17 +2353,17 @@ js_NewbornArrayPush(JSContext *cx, Handl
 {
     return NewbornArrayPushImpl(cx, obj, vp);
 }
 
 JSBool
 js::array_push(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
-    RootedObject obj(cx, ToObject(cx, &args.thisv()));
+    RootedObject obj(cx, ToObject(cx, args.thisv()));
     if (!obj)
         return false;
 
     /* Insist on one argument and obj of the expected class. */
     if (args.length() != 1 || !obj->isDenseArray())
         return array_push_slowly(cx, obj, args);
 
     return array_push1_dense(cx, obj, args);
@@ -2428,17 +2428,17 @@ array_pop_dense(JSContext *cx, HandleObj
 
     return js_SetLengthProperty(cx, obj, index);
 }
 
 JSBool
 js::array_pop(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
-    RootedObject obj(cx, ToObject(cx, &args.thisv()));
+    RootedObject obj(cx, ToObject(cx, args.thisv()));
     if (!obj)
         return false;
     if (obj->isDenseArray())
         return array_pop_dense(cx, obj, args);
     return array_pop_slowly(cx, obj, args);
 }
 
 #ifdef JS_METHODJIT
@@ -2457,17 +2457,17 @@ mjit::stubs::ArrayShift(VMFrame &f)
     obj->moveDenseArrayElementsUnbarriered(0, 1, initlen);
 }
 #endif /* JS_METHODJIT */
 
 JSBool
 js::array_shift(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
-    RootedObject obj(cx, ToObject(cx, &args.thisv()));
+    RootedObject obj(cx, ToObject(cx, args.thisv()));
     if (!obj)
         return JS_FALSE;
 
     uint32_t length;
     if (!js_GetLengthProperty(cx, obj, &length))
         return JS_FALSE;
 
     if (length == 0) {
@@ -2509,17 +2509,17 @@ js::array_shift(JSContext *cx, unsigned 
     }
     return js_SetLengthProperty(cx, obj, length);
 }
 
 static JSBool
 array_unshift(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
-    RootedObject obj(cx, ToObject(cx, &args.thisv()));
+    RootedObject obj(cx, ToObject(cx, args.thisv()));
     if (!obj)
         return false;
 
     uint32_t length;
     if (!js_GetLengthProperty(cx, obj, &length))
         return JS_FALSE;
 
     double newlen = length;
@@ -2631,17 +2631,17 @@ CanOptimizeForDenseStorage(JSObject *arr
 
 /* ES5 15.4.4.12. */
 static JSBool
 array_splice(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
     /* Step 1. */
-    RootedObject obj(cx, ToObject(cx, &args.thisv()));
+    RootedObject obj(cx, ToObject(cx, args.thisv()));
     if (!obj)
         return false;
 
     /* Steps 3-4. */
     uint32_t len;
     if (!js_GetLengthProperty(cx, obj, &len))
         return false;
 
@@ -2850,45 +2850,47 @@ mjit::stubs::ArrayConcatTwoArrays(VMFram
 #endif /* JS_METHODJIT */
 
 /*
  * Python-esque sequence operations.
  */
 JSBool
 js::array_concat(JSContext *cx, unsigned argc, Value *vp)
 {
+    CallArgs args = CallArgsFromVp(argc, vp);
+
     /* Treat our |this| object as the first argument; see ECMA 15.4.4.4. */
-    Value *p = JS_ARGV(cx, vp) - 1;
+    Value *p = args.array() - 1;
 
     /* Create a new Array object and root it using *vp. */
-    RootedObject aobj(cx, ToObject(cx, &vp[1]));
+    RootedObject aobj(cx, ToObject(cx, args.thisv()));
     if (!aobj)
         return false;
 
     RootedObject nobj(cx);
     uint32_t length;
     if (aobj->isDenseArray()) {
         length = aobj->getArrayLength();
         const Value *vector = aobj->getDenseArrayElements();
         uint32_t initlen = aobj->getDenseArrayInitializedLength();
         nobj = NewDenseCopiedArray(cx, initlen, vector);
         if (!nobj)
             return JS_FALSE;
         TryReuseArrayType(aobj, nobj);
         nobj->setArrayLength(cx, length);
-        vp->setObject(*nobj);
+        args.rval().setObject(*nobj);
         if (argc == 0)
             return JS_TRUE;
         argc--;
         p++;
     } else {
         nobj = NewDenseEmptyArray(cx);
         if (!nobj)
             return JS_FALSE;
-        vp->setObject(*nobj);
+        args.rval().setObject(*nobj);
         length = 0;
     }
 
     /* Loop over [0, argc] to concat args into nobj, expanding all Arrays. */
     for (unsigned i = 0; i <= argc; i++) {
         if (!JS_CHECK_OPERATION_LIMIT(cx))
             return false;
         HandleValue v = HandleValue::fromMarkedLocation(&p[i]);
@@ -2927,17 +2929,17 @@ js::array_concat(JSContext *cx, unsigned
 static JSBool
 array_slice(JSContext *cx, unsigned argc, Value *vp)
 {
     uint32_t length, begin, end, slot;
     JSBool hole;
 
     CallArgs args = CallArgsFromVp(argc, vp);
 
-    RootedObject obj(cx, ToObject(cx, &args.thisv()));
+    RootedObject obj(cx, ToObject(cx, args.thisv()));
     if (!obj)
         return false;
 
     if (!js_GetLengthProperty(cx, obj, &length))
         return JS_FALSE;
     begin = 0;
     end = length;
 
@@ -3006,23 +3008,22 @@ enum IndexOfKind {
     IndexOf,
     LastIndexOf
 };
 
 static JSBool
 array_indexOfHelper(JSContext *cx, IndexOfKind mode, CallArgs &args)
 {
     uint32_t length, i, stop;
-    Value tosearch;
     int direction;
     JSBool hole;
 
-    RootedValue elt(cx);
-
-    RootedObject obj(cx, ToObject(cx, &args.thisv()));
+    RootedValue tosearch(cx), elt(cx);
+
+    RootedObject obj(cx, ToObject(cx, args.thisv()));
     if (!obj)
         return false;
     if (!js_GetLengthProperty(cx, obj, &length))
         return JS_FALSE;
     if (length == 0)
         goto not_found;
 
     if (args.length() <= 1) {
@@ -3134,17 +3135,17 @@ class ArraySomeBehavior
     static Value lateExitValue() { return BooleanValue(false); }
 };
 
 template <class Behavior>
 static inline bool
 array_readonlyCommon(JSContext *cx, CallArgs &args)
 {
     /* Step 1. */
-    RootedObject obj(cx, ToObject(cx, &args.thisv()));
+    RootedObject obj(cx, ToObject(cx, args.thisv()));
     if (!obj)
         return false;
 
     /* Step 2-3. */
     uint32_t len;
     if (!js_GetLengthProperty(cx, obj, &len))
         return false;
 
@@ -3175,17 +3176,17 @@ array_readonlyCommon(JSContext *cx, Call
         if (!GetElement(cx, obj, k, &kNotPresent, &kValue))
             return false;
 
         /* Step c.ii-iii. */
         if (!kNotPresent) {
             if (!ag.pushed() && !cx->stack.pushInvokeArgs(cx, 3, &ag))
                 return false;
             ag.setCallee(ObjectValue(*callable));
-            ag.thisv() = thisv;
+            ag.setThis(thisv);
             ag[0] = kValue;
             ag[1] = NumberValue(k);
             ag[2] = ObjectValue(*obj);
             if (!Invoke(cx, ag))
                 return false;
 
             if (Behavior::shouldExit(ag.rval(), args.rval()))
                 return true;
@@ -3226,17 +3227,17 @@ array_forEach(JSContext *cx, unsigned ar
 
 /* ES5 15.4.4.19. */
 static JSBool
 array_map(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
     /* Step 1. */
-    RootedObject obj(cx, ToObject(cx, &args.thisv()));
+    RootedObject obj(cx, ToObject(cx, args.thisv()));
     if (!obj)
         return false;
 
     /* Step 2-3. */
     uint32_t len;
     if (!js_GetLengthProperty(cx, obj, &len))
         return false;
 
@@ -3276,17 +3277,17 @@ array_map(JSContext *cx, unsigned argc, 
         if (!GetElement(cx, obj, k, &kNotPresent, &kValue))
             return false;
 
         /* Step c.ii-iii. */
         if (!kNotPresent) {
             if (!ag.pushed() && !cx->stack.pushInvokeArgs(cx, 3, &ag))
                 return false;
             ag.setCallee(ObjectValue(*callable));
-            ag.thisv() = thisv;
+            ag.setThis(thisv);
             ag[0] = kValue;
             ag[1] = NumberValue(k);
             ag[2] = ObjectValue(*obj);
             if (!Invoke(cx, ag))
                 return false;
             kValue = ag.rval();
             if (!SetArrayElement(cx, arr, k, kValue))
                 return false;
@@ -3303,17 +3304,17 @@ array_map(JSContext *cx, unsigned argc, 
 
 /* ES5 15.4.4.20. */
 static JSBool
 array_filter(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
     /* Step 1. */
-    RootedObject obj(cx, ToObject(cx, &args.thisv()));
+    RootedObject obj(cx, ToObject(cx, args.thisv()));
     if (!obj)
         return false;
 
     /* Step 2-3. */
     uint32_t len;
     if (!js_GetLengthProperty(cx, obj, &len))
         return false;
 
@@ -3356,17 +3357,17 @@ array_filter(JSContext *cx, unsigned arg
         if (!GetElement(cx, obj, k, &kNotPresent, &kValue))
             return false;
 
         /* Step c.ii-iii. */
         if (!kNotPresent) {
             if (!ag.pushed() && !cx->stack.pushInvokeArgs(cx, 3, &ag))
                 return false;
             ag.setCallee(ObjectValue(*callable));
-            ag.thisv() = thisv;
+            ag.setThis(thisv);
             ag[0] = kValue;
             ag[1] = NumberValue(k);
             ag[2] = ObjectValue(*obj);
             if (!Invoke(cx, ag))
                 return false;
 
             if (ToBoolean(ag.rval())) {
                 if(!SetArrayElement(cx, arr, to, kValue))
@@ -3411,31 +3412,31 @@ class ArrayReduceRightBehavior
     }
 };
 
 template<class Behavior>
 static inline bool
 array_reduceCommon(JSContext *cx, CallArgs &args)
 {
     /* Step 1. */
-    RootedObject obj(cx, ToObject(cx, &args.thisv()));
+    RootedObject obj(cx, ToObject(cx, args.thisv()));
     if (!obj)
         return false;
 
     /* Step 2-3. */
     uint32_t len;
     if (!js_GetLengthProperty(cx, obj, &len))
         return false;
 
     /* Step 4. */
     if (args.length() == 0) {
         js_ReportMissingArg(cx, args.calleev(), 0);
         return false;
     }
-    JSObject *callable = ValueToCallable(cx, &args[0]);
+    RootedObject callable(cx, ValueToCallable(cx, &args[0]));
     if (!callable)
         return false;
 
     /* Step 5. */
     if (len == 0 && args.length() < 2) {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_EMPTY_ARRAY_REDUCE);
         return false;
     }
@@ -3474,17 +3475,17 @@ array_reduceCommon(JSContext *cx, CallAr
         if (!GetElement(cx, obj, k, &kNotPresent, &kValue))
             return false;
 
         /* Step c.ii. */
         if (!kNotPresent) {
             if (!ag.pushed() && !cx->stack.pushInvokeArgs(cx, 4, &ag))
                 return false;
             ag.setCallee(ObjectValue(*callable));
-            ag.thisv() = UndefinedValue();
+            ag.setThis(UndefinedValue());
             ag[0] = accumulator;
             ag[1] = kValue;
             ag[2] = NumberValue(k);
             ag[3] = ObjectValue(*obj);
             if (!Invoke(cx, ag))
                 return false;
             accumulator = ag.rval();
         }
@@ -3806,19 +3807,19 @@ NewSlowEmptyArray(JSContext *cx)
 #ifdef DEBUG
 JSBool
 js_ArrayInfo(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     JSObject *array;
 
     for (unsigned i = 0; i < args.length(); i++) {
-        Value arg = args[i];
-
-        char *bytes = DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, arg, NULL);
+        RootedValue arg(cx, args[i]);
+
+        char *bytes = DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, arg, NullPtr());
         if (!bytes)
             return JS_FALSE;
         if (arg.isPrimitive() ||
             !(array = arg.toObjectOrNull())->isArray()) {
             fprintf(stderr, "%s: not array\n", bytes);
             cx->free_(bytes);
             continue;
         }
--- a/js/src/jsatom.cpp
+++ b/js/src/jsatom.cpp
@@ -293,16 +293,19 @@ AtomizeInline(JSContext *cx, const jscha
     }
 
     SwitchToCompartment sc(cx, cx->runtime->atomsCompartment);
 
     JSFixedString *key;
 
     SkipRoot skip(cx, &chars);
 
+    /* Workaround for hash values in AddPtr being inadvertently poisoned. */
+    SkipRoot skip2(cx, &p);
+
     if (ocb == TakeCharOwnership) {
         key = js_NewString(cx, const_cast<jschar *>(chars), length);
         if (!key)
             return NULL;
         *pchars = NULL; /* Called should not free *pchars. */
     } else {
         JS_ASSERT(ocb == CopyChars);
         key = js_NewStringCopyN(cx, chars, length);
--- a/js/src/jsbool.cpp
+++ b/js/src/jsbool.cpp
@@ -200,18 +200,18 @@ ToBooleanSlow(const Value &v)
 }
 
 bool
 BooleanGetPrimitiveValueSlow(JSContext *cx, JSObject &obj, Value *vp)
 {
     InvokeArgsGuard ag;
     if (!cx->stack.pushInvokeArgs(cx, 0, &ag))
         return false;
-    ag.calleev() = cx->compartment->maybeGlobal()->booleanValueOf();
-    ag.thisv().setObject(obj);
+    ag.setCallee(cx->compartment->maybeGlobal()->booleanValueOf());
+    ag.setThis(ObjectValue(obj));
     if (!Invoke(cx, ag))
         return false;
     *vp = ag.rval();
     return true;
 }
 
 }  /* namespace js */
 
--- a/js/src/jscntxt.cpp
+++ b/js/src/jscntxt.cpp
@@ -805,18 +805,18 @@ js_ReportErrorAgain(JSContext *cx, const
 
 void
 js_ReportIsNotDefined(JSContext *cx, const char *name)
 {
     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NOT_DEFINED, name);
 }
 
 JSBool
-js_ReportIsNullOrUndefined(JSContext *cx, int spindex, const Value &v,
-                           JSString *fallback)
+js_ReportIsNullOrUndefined(JSContext *cx, int spindex, HandleValue v,
+                           HandleString fallback)
 {
     char *bytes;
     JSBool ok;
 
     bytes = DecompileValueGenerator(cx, spindex, v, fallback);
     if (!bytes)
         return JS_FALSE;
 
@@ -839,21 +839,21 @@ js_ReportIsNullOrUndefined(JSContext *cx
                                           js_null_str, NULL);
     }
 
     cx->free_(bytes);
     return ok;
 }
 
 void
-js_ReportMissingArg(JSContext *cx, const Value &v, unsigned arg)
+js_ReportMissingArg(JSContext *cx, HandleValue v, unsigned arg)
 {
     char argbuf[11];
     char *bytes;
-    JSAtom *atom;
+    RootedAtom atom(cx);
 
     JS_snprintf(argbuf, sizeof argbuf, "%u", arg);
     bytes = NULL;
     if (IsFunctionObject(v)) {
         atom = v.toObject().toFunction()->atom;
         bytes = DecompileValueGenerator(cx, JSDVG_SEARCH_STACK,
                                         v, atom);
         if (!bytes)
@@ -862,17 +862,17 @@ js_ReportMissingArg(JSContext *cx, const
     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
                          JSMSG_MISSING_FUN_ARG, argbuf,
                          bytes ? bytes : "");
     cx->free_(bytes);
 }
 
 JSBool
 js_ReportValueErrorFlags(JSContext *cx, unsigned flags, const unsigned errorNumber,
-                         int spindex, const Value &v, JSString *fallback,
+                         int spindex, HandleValue v, HandleString fallback,
                          const char *arg1, const char *arg2)
 {
     char *bytes;
     JSBool ok;
 
     JS_ASSERT(js_ErrorFormatString[errorNumber].argCount >= 1);
     JS_ASSERT(js_ErrorFormatString[errorNumber].argCount <= 3);
     bytes = DecompileValueGenerator(cx, spindex, v, fallback);
--- a/js/src/jscntxt.h
+++ b/js/src/jscntxt.h
@@ -1723,30 +1723,30 @@ js_ReportErrorAgain(JSContext *cx, const
 
 extern void
 js_ReportIsNotDefined(JSContext *cx, const char *name);
 
 /*
  * Report an attempt to access the property of a null or undefined value (v).
  */
 extern JSBool
-js_ReportIsNullOrUndefined(JSContext *cx, int spindex, const js::Value &v,
-                           JSString *fallback);
+js_ReportIsNullOrUndefined(JSContext *cx, int spindex, js::HandleValue v,
+                           js::HandleString fallback);
 
 extern void
-js_ReportMissingArg(JSContext *cx, const js::Value &v, unsigned arg);
+js_ReportMissingArg(JSContext *cx, js::HandleValue v, unsigned arg);
 
 /*
  * Report error using js_DecompileValueGenerator(cx, spindex, v, fallback) as
  * the first argument for the error message. If the error message has less
  * then 3 arguments, use null for arg1 or arg2.
  */
 extern JSBool
 js_ReportValueErrorFlags(JSContext *cx, unsigned flags, const unsigned errorNumber,
-                         int spindex, const js::Value &v, JSString *fallback,
+                         int spindex, js::HandleValue v, js::HandleString fallback,
                          const char *arg1, const char *arg2);
 
 #define js_ReportValueError(cx,errorNumber,spindex,v,fallback)                \
     ((void)js_ReportValueErrorFlags(cx, JSREPORT_ERROR, errorNumber,          \
                                     spindex, v, fallback, NULL, NULL))
 
 #define js_ReportValueError2(cx,errorNumber,spindex,v,fallback,arg1)          \
     ((void)js_ReportValueErrorFlags(cx, JSREPORT_ERROR, errorNumber,          \
@@ -1883,16 +1883,29 @@ class AutoObjectVector : public AutoVect
         : AutoVectorRooter<JSObject *>(cx, OBJVECTOR)
     {
         JS_GUARD_OBJECT_NOTIFIER_INIT;
     }
 
     JS_DECL_USE_GUARD_OBJECT_NOTIFIER
 };
 
+class AutoStringVector : public AutoVectorRooter<JSString *>
+{
+  public:
+    explicit AutoStringVector(JSContext *cx
+                              JS_GUARD_OBJECT_NOTIFIER_PARAM)
+        : AutoVectorRooter<JSString *>(cx, STRINGVECTOR)
+    {
+        JS_GUARD_OBJECT_NOTIFIER_INIT;
+    }
+
+    JS_DECL_USE_GUARD_OBJECT_NOTIFIER
+};
+
 class AutoShapeVector : public AutoVectorRooter<Shape *>
 {
   public:
     explicit AutoShapeVector(JSContext *cx
                              JS_GUARD_OBJECT_NOTIFIER_PARAM)
         : AutoVectorRooter<Shape *>(cx, SHAPEVECTOR)
     {
         JS_GUARD_OBJECT_NOTIFIER_INIT;
--- a/js/src/jsdate.cpp
+++ b/js/src/jsdate.cpp
@@ -2584,55 +2584,57 @@ date_toISOString(JSContext *cx, unsigned
     CallArgs args = CallArgsFromVp(argc, vp);
     return CallNonGenericMethod(cx, IsDate, date_toISOString_impl, args);
 }
 
 /* ES5 15.9.5.44. */
 static JSBool
 date_toJSON(JSContext *cx, unsigned argc, Value *vp)
 {
+    CallArgs args = CallArgsFromVp(argc, vp);
+
     /* Step 1. */
-    RootedObject obj(cx, ToObject(cx, &vp[1]));
+    RootedObject obj(cx, ToObject(cx, args.thisv()));
     if (!obj)
         return false;
 
     /* Step 2. */
     Value tv = ObjectValue(*obj);
     if (!ToPrimitive(cx, JSTYPE_NUMBER, &tv))
         return false;
 
     /* Step 3. */
     if (tv.isDouble() && !MOZ_DOUBLE_IS_FINITE(tv.toDouble())) {
-        vp->setNull();
+        args.rval().setNull();
         return true;
     }
 
     /* Step 4. */
     RootedValue toISO(cx);
     if (!obj->getProperty(cx, cx->runtime->atomState.toISOStringAtom, &toISO))
         return false;
 
     /* Step 5. */
     if (!js_IsCallable(toISO)) {
         JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR, js_GetErrorMessage, NULL,
                                      JSMSG_BAD_TOISOSTRING_PROP);
         return false;
     }
 
     /* Step 6. */
-    InvokeArgsGuard args;
-    if (!cx->stack.pushInvokeArgs(cx, 0, &args))
+    InvokeArgsGuard ag;
+    if (!cx->stack.pushInvokeArgs(cx, 0, &ag))
         return false;
 
-    args.calleev() = toISO;
-    args.thisv().setObject(*obj);
-
-    if (!Invoke(cx, args))
+    ag.setCallee(toISO);
+    ag.setThis(ObjectValue(*obj));
+
+    if (!Invoke(cx, ag))
         return false;
-    *vp = args.rval();
+    args.rval().set(ag.rval());
     return true;
 }
 
 /* for Date.toLocaleString; interface to PRMJTime date struct.
  */
 static void
 new_explode(double timeval, PRMJTime *split, JSContext *cx)
 {
--- a/js/src/jsexn.cpp
+++ b/js/src/jsexn.cpp
@@ -681,17 +681,17 @@ exn_toString(JSContext *cx, unsigned arg
  * Return a string that may eval to something similar to the original object.
  */
 static JSBool
 exn_toSource(JSContext *cx, unsigned argc, Value *vp)
 {
     JS_CHECK_RECURSION(cx, return false);
     CallArgs args = CallArgsFromVp(argc, vp);
 
-    RootedObject obj(cx, ToObject(cx, &args.thisv()));
+    RootedObject obj(cx, ToObject(cx, args.thisv()));
     if (!obj)
         return false;
 
     RootedValue nameVal(cx);
     RootedString name(cx);
     if (!obj->getProperty(cx, cx->runtime->atomState.nameAtom, &nameVal) ||
         !(name = ToString(cx, nameVal)))
     {
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -464,17 +464,18 @@ fun_hasInstance(JSContext *cx, HandleObj
     if (!obj->getProperty(cx, cx->runtime->atomState.classPrototypeAtom, &pval))
         return JS_FALSE;
 
     if (pval.isPrimitive()) {
         /*
          * Throw a runtime error if instanceof is called on a function that
          * has a non-object as its .prototype value.
          */
-        js_ReportValueError(cx, JSMSG_BAD_PROTOTYPE, -1, ObjectValue(*obj), NULL);
+        RootedValue val(cx, ObjectValue(*obj));
+        js_ReportValueError(cx, JSMSG_BAD_PROTOTYPE, -1, val, NullPtr());
         return JS_FALSE;
     }
 
     *bp = js_IsDelegate(cx, &pval.toObject(), *v);
     return JS_TRUE;
 }
 
 inline void
@@ -740,49 +741,52 @@ fun_toStringHelper(JSContext *cx, JSObje
 
     RootedFunction fun(cx, obj->toFunction());
     return FunctionToString(cx, fun, false, indent != JS_DONT_PRETTY_PRINT);
 }
 
 static JSBool
 fun_toString(JSContext *cx, unsigned argc, Value *vp)
 {
-    JS_ASSERT(IsFunctionObject(vp[0]));
+    CallArgs args = CallArgsFromVp(argc, vp);
+    JS_ASSERT(IsFunctionObject(args.calleev()));
+
     uint32_t indent = 0;
 
-    if (argc != 0 && !ToUint32(cx, vp[2], &indent))
+    if (args.length() != 0 && !ToUint32(cx, args[0], &indent))
         return false;
 
-    JSObject *obj = ToObject(cx, &vp[1]);
+    JSObject *obj = ToObject(cx, args.thisv());
     if (!obj)
         return false;
 
     JSString *str = fun_toStringHelper(cx, obj, indent);
     if (!str)
         return false;
 
-    vp->setString(str);
+    args.rval().setString(str);
     return true;
 }
 
 #if JS_HAS_TOSOURCE
 static JSBool
 fun_toSource(JSContext *cx, unsigned argc, Value *vp)
 {
-    JS_ASSERT(IsFunctionObject(vp[0]));
+    CallArgs args = CallArgsFromVp(argc, vp);
+    JS_ASSERT(IsFunctionObject(args.calleev()));
 
-    JSObject *obj = ToObject(cx, &vp[1]);
+    JSObject *obj = ToObject(cx, args.thisv());
     if (!obj)
         return false;
 
     JSString *str = fun_toStringHelper(cx, obj, JS_DONT_PRETTY_PRINT);
     if (!str)
         return false;
 
-    vp->setString(str);
+    args.rval().setString(str);
     return true;
 }
 #endif
 
 JSBool
 js_fun_call(JSContext *cx, unsigned argc, Value *vp)
 {
     Value fval = vp[1];
@@ -804,18 +808,18 @@ js_fun_call(JSContext *cx, unsigned argc
     }
 
     /* Allocate stack space for fval, obj, and the args. */
     InvokeArgsGuard args;
     if (!cx->stack.pushInvokeArgs(cx, argc, &args))
         return JS_FALSE;
 
     /* Push fval, thisv, and the args. */
-    args.calleev() = fval;
-    args.thisv() = thisv;
+    args.setCallee(fval);
+    args.setThis(thisv);
     PodCopy(args.array(), argv, argc);
 
     bool ok = Invoke(cx, args);
     *vp = args.rval();
     return ok;
 }
 
 /* ES5 15.3.4.3 */
@@ -850,18 +854,18 @@ js_fun_apply(JSContext *cx, unsigned arg
         /* Steps 4-6. */
         unsigned length = cx->fp()->numActualArgs();
         JS_ASSERT(length <= StackSpace::ARGS_LENGTH_MAX);
 
         if (!cx->stack.pushInvokeArgs(cx, length, &args))
             return false;
 
         /* Push fval, obj, and aobj's elements as args. */
-        args.calleev() = fval;
-        args.thisv() = vp[2];
+        args.setCallee(fval);
+        args.setThis(vp[2]);
 
         /* Steps 7-8. */
         cx->fp()->forEachUnaliasedActual(CopyTo(args.array()));
     } else {
         /* Step 3. */
         if (!vp[3].isObject()) {
             JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_APPLY_ARGS, js_apply_str);
             return false;
@@ -881,18 +885,18 @@ js_fun_apply(JSContext *cx, unsigned arg
             JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_TOO_MANY_FUN_APPLY_ARGS);
             return false;
         }
 
         if (!cx->stack.pushInvokeArgs(cx, length, &args))
             return false;
 
         /* Push fval, obj, and aobj's elements as args. */
-        args.calleev() = fval;
-        args.thisv() = vp[2];
+        args.setCallee(fval);
+        args.setThis(vp[2]);
 
         /* Steps 7-8. */
         if (!GetElements(cx, aobj, length, args.array()))
             return false;
     }
 
     /* Step 9. */
     if (!Invoke(cx, args))
@@ -1012,20 +1016,20 @@ CallOrConstructBoundFunction(JSContext *
         return false;
 
     /* 15.3.4.5.1, 15.3.4.5.2 step 4. */
     for (unsigned i = 0; i < argslen; i++)
         args[i] = fun->getBoundFunctionArgument(i);
     PodCopy(args.array() + argslen, vp + 2, argc);
 
     /* 15.3.4.5.1, 15.3.4.5.2 step 5. */
-    args.calleev().setObject(*target);
+    args.setCallee(ObjectValue(*target));
 
     if (!constructing)
-        args.thisv() = boundThis;
+        args.setThis(boundThis);
 
     if (constructing ? !InvokeConstructor(cx, args) : !Invoke(cx, args))
         return false;
 
     *vp = args.rval();
     return true;
 }
 
@@ -1055,17 +1059,17 @@ fun_isGenerator(JSContext *cx, unsigned 
 
 /* ES5 15.3.4.5. */
 static JSBool
 fun_bind(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
     /* Step 1. */
-    Value &thisv = args.thisv();
+    Value thisv = args.thisv();
 
     /* Step 2. */
     if (!js_IsCallable(thisv)) {
         ReportIncompatibleMethod(cx, args, &FunctionClass);
         return false;
     }
 
     /* Step 3. */
@@ -1512,17 +1516,17 @@ js_DefineFunction(JSContext *cx, HandleO
         return NULL;
 
     return fun;
 }
 
 void
 js::ReportIncompatibleMethod(JSContext *cx, CallReceiver call, Class *clasp)
 {
-    Value &thisv = call.thisv();
+    Value thisv = call.thisv();
 
 #ifdef DEBUG
     if (thisv.isObject()) {
         JS_ASSERT(thisv.toObject().getClass() != clasp ||
                   !thisv.toObject().getProto() ||
                   thisv.toObject().getProto()->getClass() != clasp);
     } else if (thisv.isString()) {
         JS_ASSERT(clasp != &StringClass);
--- a/js/src/jsinterp.cpp
+++ b/js/src/jsinterp.cpp
@@ -105,35 +105,37 @@ CallThisObjectHook(JSContext *cx, JSObje
  */
 bool
 js::BoxNonStrictThis(JSContext *cx, const CallReceiver &call)
 {
     /*
      * Check for SynthesizeFrame poisoning and fast constructors which
      * didn't check their callee properly.
      */
-    Value &thisv = call.thisv();
+    Value thisv = call.thisv();
     JS_ASSERT(!thisv.isMagic());
 
 #ifdef DEBUG
     JSFunction *fun = call.callee().isFunction() ? call.callee().toFunction() : NULL;
     JS_ASSERT_IF(fun && fun->isInterpreted(), !fun->inStrictMode());
 #endif
 
     if (thisv.isNullOrUndefined()) {
         JSObject *thisp = call.callee().global().thisObject(cx);
-        JS_ASSERT(!IsPoisonedPtr(thisp));
         if (!thisp)
             return false;
-        call.thisv().setObject(*thisp);
+        call.setThis(ObjectValue(*thisp));
         return true;
     }
 
-    if (!thisv.isObject())
-        return !!js_PrimitiveToObject(cx, &thisv);
+    if (!thisv.isObject()) {
+        if (!js_PrimitiveToObject(cx, &thisv))
+            return false;
+        call.setThis(thisv);
+    }
 
     return true;
 }
 
 #if JS_HAS_NO_SUCH_METHOD
 
 const uint32_t JSSLOT_FOUND_FUNCTION  = 0;
 const uint32_t JSSLOT_SAVED_ID        = 1;
@@ -200,44 +202,48 @@ NoSuchMethod(JSContext *cx, unsigned arg
     if (!cx->stack.pushInvokeArgs(cx, 2, &args))
         return JS_FALSE;
 
     JS_ASSERT(vp[0].isObject());
     JS_ASSERT(vp[1].isObject());
     JSObject *obj = &vp[0].toObject();
     JS_ASSERT(obj->getClass() == &js_NoSuchMethodClass);
 
-    args.calleev() = obj->getSlot(JSSLOT_FOUND_FUNCTION);
-    args.thisv() = vp[1];
+    args.setCallee(obj->getSlot(JSSLOT_FOUND_FUNCTION));
+    args.setThis(vp[1]);
     args[0] = obj->getSlot(JSSLOT_SAVED_ID);
     JSObject *argsobj = NewDenseCopiedArray(cx, argc, vp + 2);
     if (!argsobj)
         return JS_FALSE;
     args[1].setObject(*argsobj);
     JSBool ok = Invoke(cx, args);
     vp[0] = args.rval();
     return ok;
 }
 
 #endif /* JS_HAS_NO_SUCH_METHOD */
 
 bool
 js::ReportIsNotFunction(JSContext *cx, const Value &v, MaybeConstruct construct)
 {
     unsigned error = construct ? JSMSG_NOT_CONSTRUCTOR : JSMSG_NOT_FUNCTION;
-    js_ReportValueError3(cx, error, JSDVG_SEARCH_STACK, v, NULL, NULL, NULL);
+
+    RootedValue val(cx, v);
+    js_ReportValueError3(cx, error, JSDVG_SEARCH_STACK, val, NullPtr(), NULL, NULL);
     return false;
 }
 
 bool
 js::ReportIsNotFunction(JSContext *cx, const Value *vp, MaybeConstruct construct)
 {
     ptrdiff_t spIndex = cx->stack.spIndexOf(vp);
     unsigned error = construct ? JSMSG_NOT_CONSTRUCTOR : JSMSG_NOT_FUNCTION;
-    js_ReportValueError3(cx, error, spIndex, *vp, NULL, NULL, NULL);
+
+    RootedValue val(cx, *vp);
+    js_ReportValueError3(cx, error, spIndex, val, NullPtr(), NULL, NULL);
     return false;
 }
 
 JSObject *
 js::ValueToCallable(JSContext *cx, const Value *vp, MaybeConstruct construct)
 {
     if (vp->isObject()) {
         JSObject *callable = &vp->toObject();
@@ -316,30 +322,30 @@ js::InvokeKernel(JSContext *cx, CallArgs
 
     /* We should never enter a new script while cx->iterValue is live. */
     JS_ASSERT(cx->iterValue.isMagic(JS_NO_ITER_VALUE));
 
     /* MaybeConstruct is a subset of InitialFrameFlags */
     InitialFrameFlags initial = (InitialFrameFlags) construct;
 
     if (args.calleev().isPrimitive())
-        return ReportIsNotFunction(cx, &args.calleev(), construct);
+        return ReportIsNotFunction(cx, args.calleev().address(), construct);
 
     JSObject &callee = args.callee();
     Class *clasp = callee.getClass();
 
     /* Invoke non-functions. */
     if (JS_UNLIKELY(clasp != &FunctionClass)) {
 #if JS_HAS_NO_SUCH_METHOD
         if (JS_UNLIKELY(clasp == &js_NoSuchMethodClass))
             return NoSuchMethod(cx, args.length(), args.base());
 #endif
         JS_ASSERT_IF(construct, !clasp->construct);
         if (!clasp->call)
-            return ReportIsNotFunction(cx, &args.calleev(), construct);
+            return ReportIsNotFunction(cx, args.calleev().address(), construct);
         return CallJSNative(cx, clasp->call, args);
     }
 
     /* Invoke native functions. */
     RootedFunction fun(cx, callee.toFunction());
     JS_ASSERT_IF(construct, !fun->isNativeConstructor());
     if (fun->isNative())
         return CallJSNative(cx, fun->native(), args);
@@ -364,86 +370,86 @@ js::InvokeKernel(JSContext *cx, CallArgs
 bool
 js::Invoke(JSContext *cx, const Value &thisv, const Value &fval, unsigned argc, Value *argv,
            Value *rval)
 {
     InvokeArgsGuard args;
     if (!cx->stack.pushInvokeArgs(cx, argc, &args))
         return false;
 
-    args.calleev() = fval;
-    args.thisv() = thisv;
+    args.setCallee(fval);
+    args.setThis(thisv);
     PodCopy(args.array(), argv, argc);
 
     if (args.thisv().isObject()) {
         /*
          * We must call the thisObject hook in case we are not called from the
          * interpreter, where a prior bytecode has computed an appropriate
          * |this| already.
          */
         JSObject *thisp = args.thisv().toObject().thisObject(cx);
         if (!thisp)
              return false;
-        args.thisv().setObject(*thisp);
+        args.setThis(ObjectValue(*thisp));
     }
 
     if (!Invoke(cx, args))
         return false;
 
     *rval = args.rval();
     return true;
 }
 
 bool
 js::InvokeConstructorKernel(JSContext *cx, CallArgs args)
 {
     JS_ASSERT(!FunctionClass.construct);
 
-    args.thisv().setMagic(JS_IS_CONSTRUCTING);
+    args.setThis(MagicValue(JS_IS_CONSTRUCTING));
 
     if (!args.calleev().isObject())
-        return ReportIsNotFunction(cx, &args.calleev(), CONSTRUCT);
+        return ReportIsNotFunction(cx, args.calleev().address(), CONSTRUCT);
 
     JSObject &callee = args.callee();
     if (callee.isFunction()) {
         JSFunction *fun = callee.toFunction();
 
         if (fun->isNativeConstructor()) {
             Probes::calloutBegin(cx, fun);
             bool ok = CallJSNativeConstructor(cx, fun->native(), args);
             Probes::calloutEnd(cx, fun);
             return ok;
         }
 
         if (!fun->isInterpretedConstructor())
-            return ReportIsNotFunction(cx, &args.calleev(), CONSTRUCT);
+            return ReportIsNotFunction(cx, args.calleev().address(), CONSTRUCT);
 
         if (!InvokeKernel(cx, args, CONSTRUCT))
             return false;
 
         JS_ASSERT(args.rval().isObject());
         return true;
     }
 
     Class *clasp = callee.getClass();
     if (!clasp->construct)
-        return ReportIsNotFunction(cx, &args.calleev(), CONSTRUCT);
+        return ReportIsNotFunction(cx, args.calleev().address(), CONSTRUCT);
 
     return CallJSNativeConstructor(cx, clasp->construct, args);
 }
 
 bool
 js::InvokeConstructor(JSContext *cx, const Value &fval, unsigned argc, Value *argv, Value *rval)
 {
     InvokeArgsGuard args;
     if (!cx->stack.pushInvokeArgs(cx, argc, &args))
         return false;
 
-    args.calleev() = fval;
-    args.thisv().setMagic(JS_THIS_POISON);
+    args.setCallee(fval);
+    args.setThis(MagicValue(JS_THIS_POISON));
     PodCopy(args.array(), argv, argc);
 
     if (!InvokeConstructor(cx, args))
         return false;
 
     *rval = args.rval();
     return true;
 }
@@ -525,18 +531,20 @@ js::Execute(JSContext *cx, HandleScript 
 }
 
 JSBool
 js::HasInstance(JSContext *cx, HandleObject obj, const Value *v, JSBool *bp)
 {
     Class *clasp = obj->getClass();
     if (clasp->hasInstance)
         return clasp->hasInstance(cx, obj, v, bp);
+
+    RootedValue val(cx, ObjectValue(*obj));
     js_ReportValueError(cx, JSMSG_BAD_INSTANCEOF_RHS,
-                        JSDVG_SEARCH_STACK, ObjectValue(*obj), NULL);
+                        JSDVG_SEARCH_STACK, val, NullPtr());
     return JS_FALSE;
 }
 
 bool
 js::LooselyEqual(JSContext *cx, const Value &lval, const Value &rval, bool *result)
 {
 #if JS_HAS_XML_SUPPORT
     if (JS_UNLIKELY(lval.isObject() && lval.toObject().isXML()) ||
@@ -875,18 +883,18 @@ DoIncDec(JSContext *cx, HandleScript scr
 #define PUSH_OBJECT(obj)         do { regs.sp++->setObject(obj); assertSameCompartment(cx, regs.sp[-1]); } while (0)
 #define PUSH_OBJECT_OR_NULL(obj) do { regs.sp++->setObjectOrNull(obj); assertSameCompartment(cx, regs.sp[-1]); } while (0)
 #define PUSH_HOLE()              regs.sp++->setMagic(JS_ARRAY_HOLE)
 #define POP_COPY_TO(v)           v = *--regs.sp
 #define POP_RETURN_VALUE()       regs.fp()->setReturnValue(*--regs.sp)
 
 #define FETCH_OBJECT(cx, n, obj)                                              \
     JS_BEGIN_MACRO                                                            \
-        Value *vp_ = &regs.sp[n];                                             \
-        obj = ToObject(cx, (vp_));                                            \
+        HandleValue val = HandleValue::fromMarkedLocation(&regs.sp[n]);       \
+        obj = ToObject(cx, (val));                                            \
         if (!obj)                                                             \
             goto error;                                                       \
     JS_END_MACRO
 
 /*
  * Threaded interpretation via computed goto appears to be well-supported by
  * GCC 3 and higher.  IBM's C compiler when run with the right options (e.g.,
  * -qlanglvl=extended) also supports threading.  Ditto the SunPro C compiler.
@@ -1670,19 +1678,19 @@ END_CASE(JSOP_AND)
             }                                                                 \
             len = 1 + JSOP_IFEQ_LENGTH;                                       \
             DO_NEXT_OP(len);                                                  \
         }                                                                     \
     JS_END_MACRO
 
 BEGIN_CASE(JSOP_IN)
 {
-    const Value &rref = regs.sp[-1];
+    HandleValue rref = HandleValue::fromMarkedLocation(&regs.sp[-1]);
     if (!rref.isObject()) {
-        js_ReportValueError(cx, JSMSG_IN_NOT_OBJECT, -1, rref, NULL);
+        js_ReportValueError(cx, JSMSG_IN_NOT_OBJECT, -1, rref, NullPtr());
         goto error;
     }
     RootedObject &obj = rootObject0;
     obj = &rref.toObject();
     RootedId &id = rootId0;
     FETCH_ELEMENT_ID(obj, -2, id);
     RootedObject &obj2 = rootObject1;
     RootedShape &prop = rootShape0;
@@ -2199,18 +2207,19 @@ END_CASE(JSOP_DELELEM)
 BEGIN_CASE(JSOP_TOID)
 {
     /*
      * Increment or decrement requires use to lookup the same property twice, but we need to avoid
      * the oberservable stringification the second time.
      * There must be an object value below the id, which will not be popped
      * but is necessary in interning the id for XML.
      */
-    Value objval = regs.sp[-2];
-    Value idval = regs.sp[-1];
+    RootedValue &objval = rootValue0, &idval = rootValue1;
+    objval = regs.sp[-2];
+    idval = regs.sp[-1];
 
     MutableHandleValue res = MutableHandleValue::fromMarkedLocation(&regs.sp[-1]);
     if (!ToIdOperation(cx, objval, idval, res))
         goto error;
 }
 END_CASE(JSOP_TOID)
 
 BEGIN_CASE(JSOP_TYPEOFEXPR)
@@ -2295,49 +2304,53 @@ BEGIN_CASE(JSOP_THIS)
     PUSH_COPY(regs.fp()->thisValue());
 END_CASE(JSOP_THIS)
 
 BEGIN_CASE(JSOP_GETPROP)
 BEGIN_CASE(JSOP_GETXPROP)
 BEGIN_CASE(JSOP_LENGTH)
 BEGIN_CASE(JSOP_CALLPROP)
 {
+    RootedValue &lval = rootValue0;
+    lval = regs.sp[-1];
+
     RootedValue rval(cx);
-    if (!GetPropertyOperation(cx, script, regs.pc, regs.sp[-1], rval.address()))
+    if (!GetPropertyOperation(cx, regs.pc, &lval, &rval))
         goto error;
 
     TypeScript::Monitor(cx, script, regs.pc, rval);
 
     regs.sp[-1] = rval;
     assertSameCompartment(cx, regs.sp[-1]);
 }
 END_CASE(JSOP_GETPROP)
 
 BEGIN_CASE(JSOP_SETGNAME)
 BEGIN_CASE(JSOP_SETNAME)
 BEGIN_CASE(JSOP_SETPROP)
 {
-    const Value &rval = regs.sp[-1];
-    const Value &lval = regs.sp[-2];
+    HandleValue lval = HandleValue::fromMarkedLocation(&regs.sp[-2]);
+    HandleValue rval = HandleValue::fromMarkedLocation(&regs.sp[-1]);
 
     if (!SetPropertyOperation(cx, regs.pc, lval, rval))
         goto error;
 
     regs.sp[-2] = regs.sp[-1];
     regs.sp--;
 }
 END_CASE(JSOP_SETPROP)
 
 BEGIN_CASE(JSOP_GETELEM)
 BEGIN_CASE(JSOP_CALLELEM)
 {
-    Value &lref = regs.sp[-2];
-    Value &rref = regs.sp[-1];
+    MutableHandleValue lval = MutableHandleValue::fromMarkedLocation(&regs.sp[-2]);
+    HandleValue rval = HandleValue::fromMarkedLocation(&regs.sp[-1]);
+
     MutableHandleValue res = MutableHandleValue::fromMarkedLocation(&regs.sp[-2]);
-    if (!GetElementOperation(cx, op, lref, rref, res))
+    if (!GetElementOperation(cx, op, lval, rval, res))
         goto error;
     TypeScript::Monitor(cx, script, regs.pc, res);
     regs.sp--;
 }
 END_CASE(JSOP_GETELEM)
 
 BEGIN_CASE(JSOP_SETELEM)
 {
@@ -3258,19 +3271,20 @@ BEGIN_CASE(JSOP_THROW)
     POP_COPY_TO(v);
     cx->setPendingException(v);
     /* let the code at error try to catch the exception. */
     goto error;
 }
 
 BEGIN_CASE(JSOP_INSTANCEOF)
 {
-    const Value &rref = regs.sp[-1];
+    RootedValue &rref = rootValue0;
+    rref = regs.sp[-1];
     if (rref.isPrimitive()) {
-        js_ReportValueError(cx, JSMSG_BAD_INSTANCEOF_RHS, -1, rref, NULL);
+        js_ReportValueError(cx, JSMSG_BAD_INSTANCEOF_RHS, -1, rref, NullPtr());
         goto error;
     }
     RootedObject &obj = rootObject0;
     obj = &rref.toObject();
     const Value &lref = regs.sp[-2];
     JSBool cond = JS_FALSE;
     if (!HasInstance(cx, obj, &lref, &cond))
         goto error;
@@ -3698,18 +3712,19 @@ BEGIN_CASE(JSOP_GENERATOR)
         goto inline_return;
     goto exit;
 }
 
 BEGIN_CASE(JSOP_YIELD)
     JS_ASSERT(!cx->isExceptionPending());
     JS_ASSERT(regs.fp()->isNonEvalFunctionFrame());
     if (cx->innermostGenerator()->state == JSGEN_CLOSING) {
-        js_ReportValueError(cx, JSMSG_BAD_GENERATOR_YIELD, JSDVG_SEARCH_STACK,
-                            ObjectValue(regs.fp()->callee()), NULL);
+        RootedValue &val = rootValue0;
+        val.setObject(regs.fp()->callee());
+        js_ReportValueError(cx, JSMSG_BAD_GENERATOR_YIELD, JSDVG_SEARCH_STACK, val, NullPtr());
         goto error;
     }
     regs.fp()->setReturnValue(regs.sp[-1]);
     regs.fp()->setYielding();
     regs.pc += JSOP_YIELD_LENGTH;
     interpReturnOK = true;
     goto exit;
 
--- a/js/src/jsinterpinlines.h
+++ b/js/src/jsinterpinlines.h
@@ -139,32 +139,32 @@ GuardFunApplyArgumentsOptimization(JSCon
  * temporary object that the specification does.
  *
  * For objects, return the object itself. For string, boolean, and number
  * primitive values, return the appropriate constructor's prototype. For
  * undefined and null, throw an error and return NULL, attributing the
  * problem to the value at |spindex| on the stack.
  */
 JS_ALWAYS_INLINE JSObject *
-ValuePropertyBearer(JSContext *cx, StackFrame *fp, const Value &v, int spindex)
+ValuePropertyBearer(JSContext *cx, StackFrame *fp, HandleValue v, int spindex)
 {
     if (v.isObject())
         return &v.toObject();
 
     GlobalObject &global = fp->global();
 
     if (v.isString())
         return global.getOrCreateStringPrototype(cx);
     if (v.isNumber())
         return global.getOrCreateNumberPrototype(cx);
     if (v.isBoolean())
         return global.getOrCreateBooleanPrototype(cx);
 
     JS_ASSERT(v.isNull() || v.isUndefined());
-    js_ReportIsNullOrUndefined(cx, spindex, v, NULL);
+    js_ReportIsNullOrUndefined(cx, spindex, v, NullPtr());
     return NULL;
 }
 
 inline bool
 NativeGet(JSContext *cx, Handle<JSObject*> obj, Handle<JSObject*> pobj, Shape *shape,
           unsigned getHow, Value *vp)
 {
     if (shape->isDataDescriptor() && shape->hasDefaultGetter()) {
@@ -200,101 +200,99 @@ GetPropertyGenericMaybeCallXML(JSContext
     if (op == JSOP_CALLPROP && obj->isXML())
         return js_GetXMLMethod(cx, obj, id, vp);
 #endif
 
     return obj->getGeneric(cx, id, vp);
 }
 
 inline bool
-GetPropertyOperation(JSContext *cx, JSScript *script, jsbytecode *pc, Value &lval, Value *vp)
+GetPropertyOperation(JSContext *cx, jsbytecode *pc, MutableHandleValue lval, MutableHandleValue vp)
 {
-    JS_ASSERT(vp != &lval);
+    JS_ASSERT(vp.address() != lval.address());
 
     JSOp op = JSOp(*pc);
 
     if (op == JSOP_LENGTH) {
         /* Optimize length accesses on strings, arrays, and arguments. */
         if (lval.isString()) {
-            *vp = Int32Value(lval.toString()->length());
+            vp.setInt32(lval.toString()->length());
             return true;
         }
-        if (IsOptimizedArguments(cx->fp(), &lval)) {
-            *vp = Int32Value(cx->fp()->numActualArgs());
+        if (IsOptimizedArguments(cx->fp(), lval.address())) {
+            vp.setInt32(cx->fp()->numActualArgs());
             return true;
         }
         if (lval.isObject()) {
             JSObject *obj = &lval.toObject();
             if (obj->isArray()) {
                 uint32_t length = obj->getArrayLength();
-                *vp = NumberValue(length);
+                vp.setNumber(length);
                 return true;
             }
 
             if (obj->isArguments()) {
                 ArgumentsObject *argsobj = &obj->asArguments();
                 if (!argsobj->hasOverriddenLength()) {
                     uint32_t length = argsobj->initialLength();
                     JS_ASSERT(length < INT32_MAX);
-                    *vp = Int32Value(int32_t(length));
+                    vp.setInt32(int32_t(length));
                     return true;
                 }
             }
 
             if (obj->isTypedArray()) {
-                *vp = Int32Value(TypedArray::length(obj));
+                vp.setInt32(TypedArray::length(obj));
                 return true;
             }
         }
     }
 
-    RootedObject obj(cx, ValueToObject(cx, lval));
+    RootedObject obj(cx, ToObjectFromStack(cx, lval));
     if (!obj)
         return false;
 
     PropertyCacheEntry *entry;
     Rooted<JSObject*> obj2(cx);
     PropertyName *name;
     JS_PROPERTY_CACHE(cx).test(cx, pc, obj.get(), obj2.get(), entry, name);
     if (!name) {
         AssertValidPropertyCacheHit(cx, obj, obj2, entry);
-        if (!NativeGet(cx, obj, obj2, entry->prop, JSGET_CACHE_RESULT, vp))
+        if (!NativeGet(cx, obj, obj2, entry->prop, JSGET_CACHE_RESULT, vp.address()))
             return false;
         return true;
     }
 
     RootedId id(cx, NameToId(name));
-    RootedValue value(cx);
 
     if (obj->getOps()->getProperty) {
-        if (!GetPropertyGenericMaybeCallXML(cx, op, obj, id, &value))
+        if (!GetPropertyGenericMaybeCallXML(cx, op, obj, id, vp))
             return false;
     } else {
-        if (!GetPropertyHelper(cx, obj, id, JSGET_CACHE_RESULT, &value))
+        if (!GetPropertyHelper(cx, obj, id, JSGET_CACHE_RESULT, vp))
             return false;
     }
 
 #if JS_HAS_NO_SUCH_METHOD
     if (op == JSOP_CALLPROP &&
-        JS_UNLIKELY(value.isPrimitive()) &&
+        JS_UNLIKELY(vp.isPrimitive()) &&
         lval.isObject())
     {
-        if (!OnUnknownMethod(cx, obj, IdToValue(id), &value))
+        if (!OnUnknownMethod(cx, obj, IdToValue(id), vp))
             return false;
     }
 #endif
 
-    *vp = value;
     return true;
 }
 
 inline bool
-SetPropertyOperation(JSContext *cx, jsbytecode *pc, const Value &lval, const Value &rval)
+SetPropertyOperation(JSContext *cx, jsbytecode *pc, HandleValue lval, HandleValue rval)
 {
-    RootedObject obj(cx, ValueToObject(cx, lval));
+    RootedObject obj(cx, ToObjectFromStack(cx, lval));
     if (!obj)
         return false;
 
     JS_ASSERT_IF(*pc == JSOP_SETNAME || *pc == JSOP_SETGNAME, lval.isObject());
     JS_ASSERT_IF(*pc == JSOP_SETGNAME, obj == &cx->fp()->global());
 
     PropertyCacheEntry *entry;
     JSObject *obj2;
@@ -500,30 +498,28 @@ AddOperation(JSContext *cx, const Value 
 #if JS_HAS_XML_SUPPORT
     if (IsXML(lhs) && IsXML(rhs)) {
         if (!js_ConcatenateXML(cx, &lhs.toObject(), &rhs.toObject(), res))
             return false;
         types::TypeScript::MonitorUnknown(cx);
     } else
 #endif
     {
-        RootedValue lval_(cx, lhs);
-        RootedValue rval_(cx, rhs);
-        Value &lval = lval_.get();
-        Value &rval = rval_.get();
+        RootedValue lval(cx, lhs);
+        RootedValue rval(cx, rhs);
 
         /*
          * If either operand is an object, any non-integer result must be
          * reported to inference.
          */
         bool lIsObject = lval.isObject(), rIsObject = rval.isObject();
 
-        if (!ToPrimitive(cx, &lval))
+        if (!ToPrimitive(cx, lval.address()))
             return false;
-        if (!ToPrimitive(cx, &rval))
+        if (!ToPrimitive(cx, rval.address()))
             return false;
         bool lIsString, rIsString;
         if ((lIsString = lval.isString()) | (rIsString = rval.isString())) {
             RootedString lstr(cx), rstr(cx);
             if (lIsString) {
                 lstr = lval.toString();
             } else {
                 lstr = ToString(cx, lval);
@@ -624,24 +620,24 @@ FetchElementId(JSContext *cx, JSObject *
     if (ValueFitsInInt32(idval, &i_) && INT_FITS_IN_JSID(i_)) {
         *idp = INT_TO_JSID(i_);
         return true;
     }
     return !!InternNonIntElementId(cx, obj, idval, idp, vp);
 }
 
 static JS_ALWAYS_INLINE bool
-ToIdOperation(JSContext *cx, const Value &objval, const Value &idval, MutableHandleValue res)
+ToIdOperation(JSContext *cx, HandleValue objval, HandleValue idval, MutableHandleValue res)
 {
     if (idval.isInt32()) {
         res.set(idval);
         return true;
     }
 
-    JSObject *obj = ValueToObject(cx, objval);
+    JSObject *obj = ToObjectFromStack(cx, objval);
     if (!obj)
         return false;
 
     jsid dummy;
     if (!InternNonIntElementId(cx, obj, idval, &dummy, res))
         return false;
 
     if (!res.isInt32())
@@ -705,50 +701,51 @@ GetObjectElementOperation(JSContext *cx,
         }
     }
 
     assertSameCompartment(cx, res);
     return true;
 }
 
 static JS_ALWAYS_INLINE bool
-GetElementOperation(JSContext *cx, JSOp op, Value &lref, const Value &rref, MutableHandleValue res)
+GetElementOperation(JSContext *cx, JSOp op, MutableHandleValue lref, HandleValue rref,
+                    MutableHandleValue res)
 {
     JS_ASSERT(op == JSOP_GETELEM || op == JSOP_CALLELEM);
 
     if (lref.isString() && rref.isInt32()) {
         JSString *str = lref.toString();
         int32_t i = rref.toInt32();
         if (size_t(i) < str->length()) {
             str = cx->runtime->staticStrings.getUnitStringForElement(cx, str, size_t(i));
             if (!str)
                 return false;
             res.setString(str);
             return true;
         }
     }
 
     StackFrame *fp = cx->fp();
-    if (IsOptimizedArguments(fp, &lref)) {
+    if (IsOptimizedArguments(fp, lref.address())) {
         if (rref.isInt32()) {
             int32_t i = rref.toInt32();
             if (i >= 0 && uint32_t(i) < fp->numActualArgs()) {
                 res.set(fp->unaliasedActual(i));
                 return true;
             }
         }
 
         if (!JSScript::argumentsOptimizationFailed(cx, fp->script()))
             return false;
 
-        lref = ObjectValue(fp->argsObj());
+        lref.set(ObjectValue(fp->argsObj()));
     }
 
     bool isObject = lref.isObject();
-    RootedObject obj(cx, ValueToObject(cx, lref));
+    RootedObject obj(cx, ToObjectFromStack(cx, lref));
     if (!obj)
         return false;
     if (!GetObjectElementOperation(cx, op, obj, rref, res))
         return false;
 
 #if JS_HAS_NO_SUCH_METHOD
     if (op == JSOP_CALLELEM && JS_UNLIKELY(res.isPrimitive()) && isObject) {
         if (!OnUnknownMethod(cx, obj, rref, res))
--- a/js/src/jsiter.cpp
+++ b/js/src/jsiter.cpp
@@ -338,17 +338,17 @@ js::GetPropertyNames(JSContext *cx, JSOb
 size_t sCustomIteratorCount = 0;
 
 static inline bool
 GetCustomIterator(JSContext *cx, HandleObject obj, unsigned flags, MutableHandleValue vp)
 {
     JS_CHECK_RECURSION(cx, return false);
 
     /* Check whether we have a valid __iterator__ method. */
-    PropertyName *name = cx->runtime->atomState.iteratorIntrinsicAtom;
+    RootedPropertyName name(cx, cx->runtime->atomState.iteratorIntrinsicAtom);
     if (!GetMethod(cx, obj, name, 0, vp))
         return false;
 
     /* If there is no custom __iterator__ method, we are done here. */
     if (!vp.isObject()) {
         vp.setUndefined();
         return true;
     }
@@ -363,18 +363,19 @@ GetCustomIterator(JSContext *cx, HandleO
     if (vp.isPrimitive()) {
         /*
          * We are always coming from js::ValueToIterator, and we are no longer on
          * trace, so the object we are iterating over is on top of the stack (-1).
          */
         JSAutoByteString bytes;
         if (!js_AtomToPrintableString(cx, name, &bytes))
             return false;
+        RootedValue val(cx, ObjectValue(*obj));
         js_ReportValueError2(cx, JSMSG_BAD_TRAP_RETURN_VALUE,
-                             -1, ObjectValue(*obj), NULL, bytes.ptr());
+                             -1, val, NullPtr(), bytes.ptr());
         return false;
     }
     return true;
 }
 
 template <typename T>
 static inline bool
 Compare(T *a, T *b, size_t c)
@@ -573,29 +574,32 @@ GetIterator(JSContext *cx, HandleObject 
         RootedValue method(cx);
         if (!obj->getProperty(cx, obj, cx->runtime->atomState.iteratorAtom, &method))
             return false;
 
         // Throw if obj.iterator isn't callable. js::Invoke is about to check
         // for this kind of error anyway, but it would throw an inscrutable
         // error message about |method| rather than this nice one about |obj|.
         if (!method.isObject() || !method.toObject().isCallable()) {
-            char *bytes = DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, ObjectOrNullValue(obj), NULL);
+            RootedValue val(cx, ObjectOrNullValue(obj));
+            char *bytes = DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, val, NullPtr());
             if (!bytes)
                 return false;
             JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NOT_ITERABLE, bytes);
             cx->free_(bytes);
             return false;
         }
 
         if (!Invoke(cx, ObjectOrNullValue(obj), method, 0, NULL, vp.address()))
             return false;
 
-        if (!ToObject(cx, vp.address()))
+        JSObject *obj = ToObject(cx, vp);
+        if (!obj)
             return false;
+        vp.setObject(*obj);
         return true;
     }
 
     Vector<Shape *, 8> shapes(cx);
     uint32_t key = 0;
 
     bool keysOnly = (flags == JSITER_ENUMERATE);
 
@@ -841,17 +845,17 @@ Class PropertyIteratorObject::class_ = {
     }
 };
 
 const uint32_t CLOSED_INDEX = UINT32_MAX;
 
 JSObject *
 ElementIteratorObject::create(JSContext *cx, Handle<Value> target)
 {
-    GlobalObject *global = GetCurrentGlobal(cx);
+    Rooted<GlobalObject*> global(cx, GetCurrentGlobal(cx));
     Rooted<JSObject*> proto(cx, global->getOrCreateElementIteratorPrototype(cx));
     if (!proto)
         return NULL;
     JSObject *iterobj = NewObjectWithGivenProto(cx, &ElementIteratorClass, proto, global);
     if (iterobj) {
         iterobj->setReservedSlot(TargetSlot, target);
         iterobj->setReservedSlot(IndexSlot, Int32Value(0));
     }
@@ -869,26 +873,26 @@ ElementIteratorObject::next(JSContext *c
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     return CallNonGenericMethod(cx, IsElementIterator, next_impl, args);
 }
 
 bool
 ElementIteratorObject::next_impl(JSContext *cx, CallArgs args)
 {
-    JSObject *iterobj = &args.thisv().toObject();
+    RootedObject iterobj(cx, &args.thisv().toObject());
     uint32_t i, length;
-    Value target = iterobj->getReservedSlot(TargetSlot);
+    RootedValue target(cx, iterobj->getReservedSlot(TargetSlot));
     Rooted<JSObject*> obj(cx);
 
     // Get target.length.
     if (target.isString()) {
         length = uint32_t(target.toString()->length());
     } else {
-        obj = ValueToObject(cx, target);
+        obj = ToObjectFromStack(cx, target);
         if (!obj)
             goto close;
         if (!js_GetLengthProperty(cx, obj, &length))
             goto close;
     }
 
     // Check target.length.
     i = uint32_t(iterobj->getReservedSlot(IndexSlot).toInt32());
@@ -1600,18 +1604,19 @@ generator_send_impl(JSContext *cx, CallA
 
     JSGenerator *gen = (JSGenerator *) thisObj->getPrivate();
     if (!gen || gen->state == JSGEN_CLOSED) {
         /* This happens when obj is the generator prototype. See bug 352885. */
         return js_ThrowStopIteration(cx);
     }
 
     if (gen->state == JSGEN_NEWBORN && args.hasDefined(0)) {
+        RootedValue val(cx, args[0]);
         js_ReportValueError(cx, JSMSG_BAD_GENERATOR_SEND,
-                            JSDVG_SEARCH_STACK, args[0], NULL);
+                            JSDVG_SEARCH_STACK, val, NullPtr());
         return false;
     }
 
     if (!SendToGenerator(cx, JSGENOP_SEND, thisObj, gen,
                          args.length() > 0 ? args[0] : UndefinedValue()))
     {
         return false;
     }
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -324,33 +324,35 @@ js_TraceSharpMap(JSTracer *trc, JSSharpO
         JS_ASSERT(tmp == r.front().key);
     }
 }
 
 #if JS_HAS_TOSOURCE
 static JSBool
 obj_toSource(JSContext *cx, unsigned argc, Value *vp)
 {
+    CallArgs args = CallArgsFromVp(argc, vp);
+
     bool comma = false;
     const jschar *vchars;
     size_t vlength;
     Value *val;
     JSString *gsop[2];
     SkipRoot skipGsop(cx, &gsop, 2);
 
     JS_CHECK_RECURSION(cx, return JS_FALSE);
 
     Value localroot[4];
     PodArrayZero(localroot);
     AutoArrayRooter tvr(cx, ArrayLength(localroot), localroot);
 
     /* If outermost, we need parentheses to be an expression, not a block. */
     bool outermost = (cx->sharpObjectMap.depth == 0);
 
-    RootedObject obj(cx, ToObject(cx, &vp[1]));
+    RootedObject obj(cx, ToObject(cx, args.thisv()));
     if (!obj)
         return false;
 
     JSIdArray *ida;
     bool alreadySeen = false;
     bool isSharp = false;
     if (!js_EnterSharpObject(cx, obj, &ida, &alreadySeen, &isSharp))
         return false;
@@ -359,17 +361,17 @@ obj_toSource(JSContext *cx, unsigned arg
         /*
          * We've already seen obj, so don't serialize it again (particularly as
          * we might recur in the process): just serialize an empty object.
          */
         JS_ASSERT(alreadySeen);
         JSString *str = js_NewStringCopyZ(cx, "{}");
         if (!str)
             return false;
-        vp->setString(str);
+        args.rval().setString(str);
         return true;
     }
 
     JS_ASSERT(!isSharp);
     if (alreadySeen) {
         JSSharpTable::Ptr p = cx->sharpObjectMap.table.lookup(obj);
         JS_ASSERT(p);
         JS_ASSERT(!p->value.isSharp);
@@ -532,17 +534,17 @@ obj_toSource(JSContext *cx, unsigned arg
     if (!buf.append('}'))
         return false;
     if (outermost && !buf.append(')'))
         return false;
 
     JSString *str = buf.finishString();
     if (!str)
         return false;
-    vp->setString(str);
+    args.rval().setString(str);
     return true;
 }
 #endif /* JS_HAS_TOSOURCE */
 
 namespace js {
 
 JSString *
 obj_toStringHelper(JSContext *cx, JSObject *obj)
@@ -589,68 +591,69 @@ InformalValueTypeName(const Value &v)
 }
 
 } /* namespace js */
 
 /* ES5 15.2.4.2.  Note steps 1 and 2 are errata. */
 static JSBool
 obj_toString(JSContext *cx, unsigned argc, Value *vp)
 {
-    Value &thisv = vp[1];
+    CallArgs args = CallArgsFromVp(argc, vp);
 
     /* Step 1. */
-    if (thisv.isUndefined()) {
-        vp->setString(cx->runtime->atomState.objectUndefinedAtom);
+    if (args.thisv().isUndefined()) {
+        args.rval().setString(cx->runtime->atomState.objectUndefinedAtom);
         return true;
     }
 
     /* Step 2. */
-    if (thisv.isNull()) {
-        vp->setString(cx->runtime->atomState.objectNullAtom);
+    if (args.thisv().isNull()) {
+        args.rval().setString(cx->runtime->atomState.objectNullAtom);
         return true;
     }
 
     /* Step 3. */
-    JSObject *obj = ToObject(cx, &thisv);
+    JSObject *obj = ToObject(cx, args.thisv());
     if (!obj)
         return false;
 
     /* Steps 4-5. */
     JSString *str = js::obj_toStringHelper(cx, obj);
     if (!str)
         return false;
-    vp->setString(str);
+    args.rval().setString(str);
     return true;
 }
 
 /* ES5 15.2.4.3. */
 static JSBool
 obj_toLocaleString(JSContext *cx, unsigned argc, Value *vp)
 {
     JS_CHECK_RECURSION(cx, return false);
 
     CallArgs args = CallArgsFromVp(argc, vp);
 
     /* Step 1. */
-    JSObject *obj = ToObject(cx, &args.thisv());
+    JSObject *obj = ToObject(cx, args.thisv());
     if (!obj)
         return false;
 
     /* Steps 2-4. */
     RootedId id(cx, NameToId(cx->runtime->atomState.toStringAtom));
     return obj->callMethod(cx, id, 0, NULL, args.rval());
 }
 
 static JSBool
 obj_valueOf(JSContext *cx, unsigned argc, Value *vp)
 {
-    JSObject *obj = ToObject(cx, &vp[1]);
+    CallArgs args = CallArgsFromVp(argc, vp);
+    JSObject *obj = ToObject(cx, args.thisv());
     if (!obj)
         return false;
-    vp->setObject(*obj);
+    args.rval().setObject(*obj);
     return true;
 }
 
 #if JS_HAS_OBJ_WATCHPOINT
 
 static JSBool
 obj_watch_handler(JSContext *cx, JSObject *obj_, jsid id_, jsval old,
                   jsval *nvp, void *closure)
@@ -679,55 +682,59 @@ obj_watch_handler(JSContext *cx, JSObjec
 
     Value argv[] = { IdToValue(id), old, *nvp };
     return Invoke(cx, ObjectValue(*obj), ObjectOrNullValue(callable), ArrayLength(argv), argv, nvp);
 }
 
 static JSBool
 obj_watch(JSContext *cx, unsigned argc, Value *vp)
 {
+    CallArgs args = CallArgsFromVp(argc, vp);
+
     if (argc <= 1) {
-        js_ReportMissingArg(cx, *vp, 1);
+        js_ReportMissingArg(cx, args.calleev(), 1);
         return false;
     }
 
-    RootedObject callable(cx, ValueToCallable(cx, &vp[3]));
+    RootedObject callable(cx, ValueToCallable(cx, &args[1]));
     if (!callable)
         return false;
 
     RootedId propid(cx);
-    if (!ValueToId(cx, vp[2], propid.address()))
+    if (!ValueToId(cx, args[0], propid.address()))
         return false;
 
-    RootedObject obj(cx, ToObject(cx, &vp[1]));
+    RootedObject obj(cx, ToObject(cx, args.thisv()));
     if (!obj)
         return false;
 
     Value tmp;
     unsigned attrs;
     if (!CheckAccess(cx, obj, propid, JSACC_WATCH, &tmp, &attrs))
         return false;
 
-    vp->setUndefined();
+    args.rval().setUndefined();
 
     if (obj->isDenseArray() && !JSObject::makeDenseArraySlow(cx, obj))
         return false;
     return JS_SetWatchPoint(cx, obj, propid, obj_watch_handler, callable);
 }
 
 static JSBool
 obj_unwatch(JSContext *cx, unsigned argc, Value *vp)
 {
-    JSObject *obj = ToObject(cx, &vp[1]);
+    CallArgs args = CallArgsFromVp(argc, vp);
+
+    RootedObject obj(cx, ToObject(cx, args.thisv()));
     if (!obj)
         return false;
-    vp->setUndefined();
+    args.rval().setUndefined();
     jsid id;
     if (argc != 0) {
-        if (!ValueToId(cx, vp[2], &id))
+        if (!ValueToId(cx, args[0], &id))
             return false;
     } else {
         id = JSID_VOID;
     }
     return JS_ClearWatchPoint(cx, obj, id, NULL, NULL);
 }
 
 #endif /* JS_HAS_OBJ_WATCHPOINT */
@@ -736,45 +743,49 @@ obj_unwatch(JSContext *cx, unsigned argc
  * Prototype and property query methods, to complement the 'in' and
  * 'instanceof' operators.
  */
 
 /* Proposed ECMA 15.2.4.5. */
 static JSBool
 obj_hasOwnProperty(JSContext *cx, unsigned argc, Value *vp)
 {
-    JSObject *obj = ToObject(cx, &vp[1]);
+    CallArgs args = CallArgsFromVp(argc, vp);
+
+    RootedObject obj(cx, ToObject(cx, args.thisv()));
     if (!obj)
         return false;
-    return js_HasOwnPropertyHelper(cx, obj->getOps()->lookupGeneric, argc, vp);
+    return js_HasOwnPropertyHelper(cx, obj->getOps()->lookupGeneric, argc, args.rval().address());
 }
 
 JSBool
 js_HasOwnPropertyHelper(JSContext *cx, LookupGenericOp lookup, unsigned argc,
                         Value *vp)
 {
+    CallArgs args = CallArgsFromVp(argc, vp);
+
     RootedId id(cx);
-    if (!ValueToId(cx, argc != 0 ? vp[2] : UndefinedValue(), id.address()))
+    if (!ValueToId(cx, args.length() ? args[0] : UndefinedValue(), id.address()))
         return JS_FALSE;
 
-    RootedObject obj(cx, ToObject(cx, &vp[1]));
+    RootedObject obj(cx, ToObject(cx, args.thisv()));
     if (!obj)
         return false;
     RootedObject obj2(cx);
     RootedShape prop(cx);
     if (obj->isProxy()) {
         bool has;
         if (!Proxy::hasOwn(cx, obj, id, &has))
             return false;
-        vp->setBoolean(has);
+        args.rval().setBoolean(has);
         return true;
     }
     if (!js_HasOwnProperty(cx, lookup, obj, id, &obj2, &prop))
         return JS_FALSE;
-    vp->setBoolean(!!prop);
+    args.rval().setBoolean(!!prop);
     return JS_TRUE;
 }
 
 JSBool
 js_HasOwnProperty(JSContext *cx, LookupGenericOp lookup, HandleObject obj, HandleId id,
                   MutableHandleObject objp, MutableHandleShape propp)
 {
     JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED | JSRESOLVE_DETECTING);
@@ -803,48 +814,52 @@ js_HasOwnProperty(JSContext *cx, LookupG
         propp.set(NULL);
     return true;
 }
 
 /* ES5 15.2.4.6. */
 static JSBool
 obj_isPrototypeOf(JSContext *cx, unsigned argc, Value *vp)
 {
+    CallArgs args = CallArgsFromVp(argc, vp);
+
     /* Step 1. */
-    if (argc < 1 || !vp[2].isObject()) {
-        vp->setBoolean(false);
+    if (args.length() < 1 || !args[0].isObject()) {
+        args.rval().setBoolean(false);
         return true;
     }
 
     /* Step 2. */
-    JSObject *obj = ToObject(cx, &vp[1]);
+    RootedObject obj(cx, ToObject(cx, args.thisv()));
     if (!obj)
         return false;
 
     /* Step 3. */
-    vp->setBoolean(js_IsDelegate(cx, obj, vp[2]));
+    args.rval().setBoolean(js_IsDelegate(cx, obj, args[0]));
     return true;
 }
 
 /* ES5 15.2.4.7. */
 static JSBool
 obj_propertyIsEnumerable(JSContext *cx, unsigned argc, Value *vp)
 {
+    CallArgs args = CallArgsFromVp(argc, vp);
+
     /* Step 1. */
     RootedId id(cx);
-    if (!ValueToId(cx, argc != 0 ? vp[2] : UndefinedValue(), id.address()))
+    if (!ValueToId(cx, args.length() ? args[0] : UndefinedValue(), id.address()))
         return false;
 
     /* Step 2. */
-    RootedObject obj(cx, ToObject(cx, &vp[1]));
+    RootedObject obj(cx, ToObject(cx, args.thisv()));
     if (!obj)
         return false;
 
     /* Steps 3-5. */
-    return js_PropertyIsEnumerable(cx, obj, id, vp);
+    return js_PropertyIsEnumerable(cx, obj, id, args.rval().address());
 }
 
 JSBool
 js_PropertyIsEnumerable(JSContext *cx, HandleObject obj, HandleId id, Value *vp)
 {
     RootedObject pobj(cx);
     RootedShape prop(cx);
     if (!obj->lookupGeneric(cx, id, &pobj, &prop))
@@ -936,76 +951,80 @@ JS_FRIEND_API(JSBool)
 js::obj_defineSetter(JSContext *cx, unsigned argc, Value *vp)
 {
     return DefineAccessor<Setter>(cx, argc, vp);
 }
 
 static JSBool
 obj_lookupGetter(JSContext *cx, unsigned argc, Value *vp)
 {
+    CallArgs args = CallArgsFromVp(argc, vp);
+
     RootedId id(cx);
-    if (!ValueToId(cx, argc != 0 ? vp[2] : UndefinedValue(), id.address()))
+    if (!ValueToId(cx, args.length() ? args[0] : UndefinedValue(), id.address()))
         return JS_FALSE;
-    RootedObject obj(cx, ToObject(cx, &vp[1]));
+    RootedObject obj(cx, ToObject(cx, args.thisv()));
     if (!obj)
         return JS_FALSE;
     if (obj->isProxy()) {
         // The vanilla getter lookup code below requires that the object is
         // native. Handle proxies separately.
-        vp->setUndefined();
+        args.rval().setUndefined();
         AutoPropertyDescriptorRooter desc(cx);
         if (!Proxy::getPropertyDescriptor(cx, obj, id, false, &desc))
             return JS_FALSE;
         if (desc.obj && (desc.attrs & JSPROP_GETTER) && desc.getter)
-            *vp = CastAsObjectJsval(desc.getter);
+            args.rval().set(CastAsObjectJsval(desc.getter));
         return JS_TRUE;
     }
     RootedObject pobj(cx);
     RootedShape shape(cx);
     if (!obj->lookupGeneric(cx, id, &pobj, &shape))
         return JS_FALSE;
-    vp->setUndefined();
+    args.rval().setUndefined();
     if (shape) {
         if (pobj->isNative()) {
             if (shape->hasGetterValue())
-                *vp = shape->getterValue();
+                args.rval().set(shape->getterValue());
         }
     }
     return JS_TRUE;
 }
 
 static JSBool
 obj_lookupSetter(JSContext *cx, unsigned argc, Value *vp)
 {
+    CallArgs args = CallArgsFromVp(argc, vp);
+
     RootedId id(cx);
-    if (!ValueToId(cx, argc != 0 ? vp[2] : UndefinedValue(), id.address()))
+    if (!ValueToId(cx, args.length() ? args[0] : UndefinedValue(), id.address()))
         return JS_FALSE;
-    RootedObject obj(cx, ToObject(cx, &vp[1]));
+    RootedObject obj(cx, ToObject(cx, args.thisv()));
     if (!obj)
         return JS_FALSE;
     if (obj->isProxy()) {
         // The vanilla setter lookup code below requires that the object is
         // native. Handle proxies separately.
-        vp->setUndefined();
+        args.rval().setUndefined();
         AutoPropertyDescriptorRooter desc(cx);
         if (!Proxy::getPropertyDescriptor(cx, obj, id, false, &desc))
             return JS_FALSE;
         if (desc.obj && (desc.attrs & JSPROP_SETTER) && desc.setter)
-            *vp = CastAsObjectJsval(desc.setter);
+            args.rval().set(CastAsObjectJsval(desc.setter));
         return JS_TRUE;
     }
     RootedObject pobj(cx);
     RootedShape shape(cx);
     if (!obj->lookupGeneric(cx, id, &pobj, &shape))
         return JS_FALSE;
-    vp->setUndefined();
+    args.rval().setUndefined();
     if (shape) {
         if (pobj->isNative()) {
             if (shape->hasSetterValue())
-                *vp = shape->setterValue();
+                args.rval().set(shape->setterValue());
         }
     }
     return JS_TRUE;
 }
 #endif /* OLD_GETTER_SETTER_METHODS */
 
 /* ES5 15.2.3.2. */
 JSBool
@@ -1015,17 +1034,18 @@ obj_getPrototypeOf(JSContext *cx, unsign
 
     /* Step 1. */
     if (args.length() == 0) {
         js_ReportMissingArg(cx, args.calleev(), 0);
         return false;
     }
 
     if (args[0].isPrimitive()) {
-        char *bytes = DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, vp[2], NULL);
+        RootedValue val(cx, args[0]);
+        char *bytes = DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, val, NullPtr());
         if (!bytes)
             return false;
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
                              JSMSG_UNEXPECTED_TYPE, bytes, "not an object");
         JS_free(cx, bytes);
         return false;
     }
 
@@ -1033,18 +1053,18 @@ obj_getPrototypeOf(JSContext *cx, unsign
 
     /*
      * Implement [[Prototype]]-getting -- particularly across compartment
      * boundaries -- by calling a cached __proto__ getter function.
      */
     InvokeArgsGuard nested;
     if (!cx->stack.pushInvokeArgs(cx, 0, &nested))
         return false;
-    nested.calleev() = cx->global()->protoGetter();
-    nested.thisv() = args[0];
+    nested.setCallee(cx->global()->protoGetter());
+    nested.setThis(args[0]);
     if (!Invoke(cx, nested))
         return false;
     args.rval().set(nested.rval());
     return true;
 }
 
 namespace js {
 
@@ -1184,19 +1204,19 @@ GetFirstArgumentAsObject(JSContext *cx, 
                          MutableHandleObject objp)
 {
     if (argc == 0) {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_MORE_ARGS_NEEDED,
                              method, "0", "s");
         return false;
     }
 
-    const Value &v = vp[2];
+    RootedValue v(cx, vp[2]);
     if (!v.isObject()) {
-        char *bytes = DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, v, NULL);
+        char *bytes = DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, v, NullPtr());
         if (!bytes)
             return false;
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_UNEXPECTED_TYPE,
                              bytes, "not an object");
         JS_free(cx, bytes);
         return false;
     }
 
@@ -1392,19 +1412,20 @@ Throw(JSContext *cx, jsid id, unsigned e
     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, errorNumber, bytes.ptr());
     return false;
 }
 
 bool
 Throw(JSContext *cx, JSObject *obj, unsigned errorNumber)
 {
     if (js_ErrorFormatString[errorNumber].argCount == 1) {
+        RootedValue val(cx, ObjectValue(*obj));
         js_ReportValueErrorFlags(cx, JSREPORT_ERROR, errorNumber,
-                                 JSDVG_IGNORE_STACK, ObjectValue(*obj),
-                                 NULL, NULL, NULL);
+                                 JSDVG_IGNORE_STACK, val, NullPtr(),
+                                 NULL, NULL);
     } else {
         JS_ASSERT(js_ErrorFormatString[errorNumber].argCount == 0);
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, errorNumber);
     }
     return false;
 }
 
 } /* namespace js */
@@ -1919,29 +1940,32 @@ js_PopulateObject(JSContext *cx, HandleO
 {
     return DefineProperties(cx, newborn, props);
 }
 
 /* ES5 15.2.3.7: Object.defineProperties(O, Properties) */
 static JSBool
 obj_defineProperties(JSContext *cx, unsigned argc, Value *vp)
 {
+    CallArgs args = CallArgsFromVp(argc, vp);
+
     /* Steps 1 and 7. */
     RootedObject obj(cx);
-    if (!GetFirstArgumentAsObject(cx, argc, vp, "Object.defineProperties", &obj))
+    if (!GetFirstArgumentAsObject(cx, args.length(), vp, "Object.defineProperties", &obj))
         return false;
-    vp->setObject(*obj);
+    args.rval().setObject(*obj);
 
     /* Step 2. */
-    if (argc < 2) {
+    if (args.length() < 2) {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_MORE_ARGS_NEEDED,
                              "Object.defineProperties", "0", "s");
         return false;
     }
-    RootedObject props(cx, ToObject(cx, &vp[3]));
+    RootedValue val(cx, args[1]);
+    RootedObject props(cx, ToObject(cx, val));
     if (!props)
         return false;
 
     /* Steps 3-6. */
     return DefineProperties(cx, obj, props);
 }
 
 /* ES5 15.2.3.5: Object.create(O [, Properties]) */
@@ -1950,19 +1974,19 @@ obj_create(JSContext *cx, unsigned argc,
 {
     if (argc == 0) {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_MORE_ARGS_NEEDED,
                              "Object.create", "0", "s");
         return false;
     }
 
     CallArgs args = CallArgsFromVp(argc, vp);
-    const Value &v = args[0];
+    RootedValue v(cx, args[0]);
     if (!v.isObjectOrNull()) {
-        char *bytes = DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, v, NULL);
+        char *bytes = DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, v, NullPtr());
         if (!bytes)
             return false;
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_UNEXPECTED_TYPE,
                              bytes, "not an object or null");
         JS_free(cx, bytes);
         return false;
     }
 
@@ -4692,19 +4716,20 @@ js_GetPropertyHelperInline(JSContext *cx
             } else if (cx->resolveFlags & JSRESOLVE_DETECTING) {
                 return JS_TRUE;
             }
 
             unsigned flags = JSREPORT_WARNING | JSREPORT_STRICT;
             cx->stack.currentScript()->warnedAboutUndefinedProp = true;
 
             /* Ok, bad undefined property reference: whine about it. */
+            RootedValue val(cx, IdToValue(id));
             if (!js_ReportValueErrorFlags(cx, flags, JSMSG_UNDEFINED_PROP,
-                                          JSDVG_IGNORE_STACK, IdToValue(id),
-                                          NULL, NULL, NULL))
+                                          JSDVG_IGNORE_STACK, val, NullPtr(),
+                                          NULL, NULL))
             {
                 return false;
             }
         }
         return JS_TRUE;
     }
 
     if (!obj2->isNative()) {
@@ -4804,35 +4829,38 @@ js::CheckUndeclaredVarAssignment(JSConte
                                          | JSREPORT_STRICT_MODE_ERROR),
                                         js_GetErrorMessage, NULL,
                                         JSMSG_UNDECLARED_VAR, bytes.ptr());
 }
 
 bool
 JSObject::reportReadOnly(JSContext *cx, jsid id, unsigned report)
 {
+    RootedValue val(cx, IdToValue(id));
     return js_ReportValueErrorFlags(cx, report, JSMSG_READ_ONLY,
-                                    JSDVG_IGNORE_STACK, IdToValue(id), NULL,
+                                    JSDVG_IGNORE_STACK, val, NullPtr(),
                                     NULL, NULL);
 }
 
 bool
 JSObject::reportNotConfigurable(JSContext *cx, jsid id, unsigned report)
 {
+    RootedValue val(cx, IdToValue(id));
     return js_ReportValueErrorFlags(cx, report, JSMSG_CANT_DELETE,
-                                    JSDVG_IGNORE_STACK, IdToValue(id), NULL,
+                                    JSDVG_IGNORE_STACK, val, NullPtr(),
                                     NULL, NULL);
 }
 
 bool
 JSObject::reportNotExtensible(JSContext *cx, unsigned report)
 {
+    RootedValue val(cx, ObjectValue(*this));
     return js_ReportValueErrorFlags(cx, report, JSMSG_OBJECT_NOT_EXTENSIBLE,
-                                    JSDVG_IGNORE_STACK, ObjectValue(*this),
-                                    NULL, NULL, NULL);
+                                    JSDVG_IGNORE_STACK, val, NullPtr(),
+                                    NULL, NULL);
 }
 
 bool
 JSObject::callMethod(JSContext *cx, HandleId id, unsigned argc, Value *argv, MutableHandleValue vp)
 {
     RootedValue fval(cx);
     Rooted<JSObject*> obj(cx, this);
     return GetMethod(cx, obj, id, 0, &fval) &&
@@ -5260,26 +5288,27 @@ DefaultValue(JSContext *cx, HandleObject
         id = NameToId(cx->runtime->atomState.toStringAtom);
         if (!MaybeCallMethod(cx, obj, id, vp))
             return false;
         if (vp.isPrimitive())
             return true;
     }
 
     /* Avoid recursive death when decompiling in js_ReportValueError. */
-    JSString *str;
+    RootedString str(cx);
     if (hint == JSTYPE_STRING) {
         str = JS_InternString(cx, clasp->name);
         if (!str)
             return false;
     } else {
         str = NULL;
     }
 
-    js_ReportValueError2(cx, JSMSG_CANT_CONVERT_TO, JSDVG_SEARCH_STACK, ObjectValue(*obj), str,
+    RootedValue val(cx, ObjectValue(*obj));
+    js_ReportValueError2(cx, JSMSG_CANT_CONVERT_TO, JSDVG_SEARCH_STACK, val, str,
                          (hint == JSTYPE_VOID) ? "primitive type" : JS_TYPE_STR(hint));
     return false;
 }
 
 } /* namespace js */
 
 JS_FRIEND_API(JSBool)
 JS_EnumerateState(JSContext *cx, JSHandleObject obj, JSIterateOp enum_op, Value *statep, jsid *idp)
@@ -5484,44 +5513,47 @@ js_ValueToObjectOrNull(JSContext *cx, co
     objp.set(obj);
     return true;
 }
 
 namespace js {
 
 /* Callers must handle the already-object case . */
 JSObject *
-ToObjectSlow(JSContext *cx, Value *vp)
-{
-    JS_ASSERT(!vp->isMagic());
-    JS_ASSERT(!vp->isObject());
-
-    if (vp->isNullOrUndefined()) {
-        JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_CONVERT_TO,
-                            vp->isNull() ? "null" : "undefined", "object");
+ToObjectSlow(JSContext *cx, HandleValue val, bool reportScanStack)
+{
+    JS_ASSERT(!val.isMagic());
+    JS_ASSERT(!val.isObject());
+
+    if (val.isNullOrUndefined()) {
+        if (reportScanStack) {
+            js_ReportIsNullOrUndefined(cx, JSDVG_SEARCH_STACK, val, NullPtr());
+        } else {
+            JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_CONVERT_TO,
+                                 val.isNull() ? "null" : "undefined", "object");
+        }
         return NULL;
     }
 
-    JSObject *obj = PrimitiveToObject(cx, *vp);
-    if (obj)
-        vp->setObject(*obj);
-    return obj;
+    return PrimitiveToObject(cx, val);
 }
 
 }
 
 JSObject *
 js_ValueToNonNullObject(JSContext *cx, const Value &v)
 {
     RootedObject obj(cx);
 
     if (!js_ValueToObjectOrNull(cx, v, &obj))
         return NULL;
-    if (!obj)
-        js_ReportIsNullOrUndefined(cx, JSDVG_SEARCH_STACK, v, NULL);
+    if (!obj) {
+        RootedValue val(cx, v);
+        js_ReportIsNullOrUndefined(cx, JSDVG_SEARCH_STACK, val, NullPtr());
+    }
     return obj;
 }
 
 void
 js_GetObjectSlotName(JSTracer *trc, char *buf, size_t bufsize)
 {
     JS_ASSERT(trc->debugPrinter == js_GetObjectSlotName);
 
--- a/js/src/jsobj.h
+++ b/js/src/jsobj.h
@@ -1329,37 +1329,39 @@ js_ValueToObjectOrNull(JSContext *cx, co
 
 /* Throws if v could not be converted to an object. */
 extern JSObject *
 js_ValueToNonNullObject(JSContext *cx, const js::Value &v);
 
 namespace js {
 
 /*
- * Invokes the ES5 ToObject algorithm on *vp, writing back the object to vp.
- * If *vp might already be an object, use ToObject.
+ * Invokes the ES5 ToObject algorithm on vp, returning the result. If vp might
+ * already be an object, use ToObject. reportCantConvert controls how null and
+ * undefined errors are reported.
  */
 extern JSObject *
-ToObjectSlow(JSContext *cx, Value *vp);
+ToObjectSlow(JSContext *cx, HandleValue vp, bool reportScanStack);
 
+/* For object conversion in e.g. native functions. */
 JS_ALWAYS_INLINE JSObject *
-ToObject(JSContext *cx, Value *vp)
+ToObject(JSContext *cx, HandleValue vp)
 {
-    if (vp->isObject())
-        return &vp->toObject();
-    return ToObjectSlow(cx, vp);
+    if (vp.isObject())
+        return &vp.toObject();
+    return ToObjectSlow(cx, vp, false);
 }
 
-/* As for ToObject, but preserves the original value. */
-inline JSObject *
-ValueToObject(JSContext *cx, const Value &v)
+/* For converting stack values to objects. */
+JS_ALWAYS_INLINE JSObject *
+ToObjectFromStack(JSContext *cx, HandleValue vp)
 {
-    if (v.isObject())
-        return &v.toObject();
-    return js_ValueToNonNullObject(cx, v);
+    if (vp.isObject())
+        return &vp.toObject();
+    return ToObjectSlow(cx, vp, true);
 }
 
 } /* namespace js */
 
 extern void
 js_GetObjectSlotName(JSTracer *trc, char *buf, size_t bufsize);
 
 extern bool
--- a/js/src/json.cpp
+++ b/js/src/json.cpp
@@ -290,18 +290,18 @@ PreprocessValue(JSContext *cx, HandleObj
             keyStr = KeyStringifier<KeyType>::toString(cx, key);
             if (!keyStr)
                 return false;
 
             InvokeArgsGuard args;
             if (!cx->stack.pushInvokeArgs(cx, 1, &args))
                 return false;
 
-            args.calleev() = toJSON;
-            args.thisv() = vp;
+            args.setCallee(toJSON);
+            args.setThis(vp);
             args[0] = StringValue(keyStr);
 
             if (!Invoke(cx, args))
                 return false;
             vp.set(args.rval());
         }
     }
 
@@ -312,18 +312,18 @@ PreprocessValue(JSContext *cx, HandleObj
             if (!keyStr)
                 return false;
         }
 
         InvokeArgsGuard args;
         if (!cx->stack.pushInvokeArgs(cx, 2, &args))
             return false;
 
-        args.calleev() = ObjectValue(*scx->replacer);
-        args.thisv() = ObjectValue(*holder);
+        args.setCallee(ObjectValue(*scx->replacer));
+        args.setThis(ObjectValue(*holder));
         args[0] = StringValue(keyStr);
         args[1] = vp;
 
         if (!Invoke(cx, args))
             return false;
         vp.set(args.rval());
     }
 
@@ -833,18 +833,18 @@ Walk(JSContext *cx, HandleObject holder,
     RootedString key(cx, IdToString(cx, name));
     if (!key)
         return false;
 
     InvokeArgsGuard args;
     if (!cx->stack.pushInvokeArgs(cx, 2, &args))
         return false;
 
-    args.calleev() = reviver;
-    args.thisv() = ObjectValue(*holder);
+    args.setCallee(reviver);
+    args.setThis(ObjectValue(*holder));
     args[0] = StringValue(key);
     args[1] = val;
 
     if (!Invoke(cx, args))
         return false;
     vp.set(args.rval());
     return true;
 }
--- a/js/src/jsopcode.cpp
+++ b/js/src/jsopcode.cpp
@@ -6195,19 +6195,20 @@ DecompileExpressionFromStack(JSContext *
         return false;
     if (!ea.decompilePC(valuepc))
         return false;
 
     return ea.getOutput(res);
 }
 
 char *
-js_DecompileValueGenerator(JSContext *cx, int spindex, jsval v,
-                           JSString *fallback)
+js::DecompileValueGenerator(JSContext *cx, int spindex, HandleValue v,
+                            HandleString fallbackArg)
 {
+    RootedString fallback(cx, fallbackArg);
     {
         char *result;
         if (!DecompileExpressionFromStack(cx, spindex, v, &result))
             return NULL;
         if (result) {
             if (strcmp(result, "(intermediate value)"))
                 return result;
             cx->free_(result);
--- a/js/src/jsopcode.h
+++ b/js/src/jsopcode.h
@@ -317,32 +317,16 @@ js_DecompileFunction(JSPrinter *jp);
 typedef JSBool (* JSDecompilerPtr)(JSPrinter *);
 
 extern JSString *
 js_DecompileToString(JSContext *cx, const char *name, JSFunction *fun,
                      unsigned indent, JSBool pretty, JSBool grouped, JSBool strict,
                      JSDecompilerPtr decompiler);
 
 /*
- * Find the source expression that resulted in v, and return a newly allocated
- * C-string containing it.  Fall back on v's string conversion (fallback) if we
- * can't find the bytecode that generated and pushed v on the operand stack.
- *
- * Search the current stack frame if spindex is JSDVG_SEARCH_STACK.  Don't
- * look for v on the stack if spindex is JSDVG_IGNORE_STACK.  Otherwise,
- * spindex is the negative index of v, measured from cx->fp->sp, or from a
- * lower frame's sp if cx->fp is native.
- *
- * The caller must call JS_free on the result after a succsesful call.
- */
-extern char *
-js_DecompileValueGenerator(JSContext *cx, int spindex, jsval v,
-                           JSString *fallback);
-
-/*
  * Given bytecode address pc in script's main program code, return the operand
  * stack depth just before (JSOp) *pc executes.
  */
 extern unsigned
 js_ReconstructStackDepth(JSContext *cx, JSScript *script, jsbytecode *pc);
 
 #ifdef _MSC_VER
 #pragma warning(pop)
@@ -356,22 +340,30 @@ JS_END_EXTERN_C
 /*
  * Get the length of variable-length bytecode like JSOP_TABLESWITCH.
  */
 extern size_t
 js_GetVariableBytecodeLength(jsbytecode *pc);
 
 namespace js {
 
-static inline char *
-DecompileValueGenerator(JSContext *cx, int spindex, const Value &v,
-                        JSString *fallback)
-{
-    return js_DecompileValueGenerator(cx, spindex, v, fallback);
-}
+/*
+ * Find the source expression that resulted in v, and return a newly allocated
+ * C-string containing it.  Fall back on v's string conversion (fallback) if we
+ * can't find the bytecode that generated and pushed v on the operand stack.
+ *
+ * Search the current stack frame if spindex is JSDVG_SEARCH_STACK.  Don't
+ * look for v on the stack if spindex is JSDVG_IGNORE_STACK.  Otherwise,
+ * spindex is the negative index of v, measured from cx->fp->sp, or from a
+ * lower frame's sp if cx->fp is native.
+ *
+ * The caller must call JS_free on the result after a succsesful call.
+ */
+char *
+DecompileValueGenerator(JSContext *cx, int spindex, HandleValue v, HandleString fallback);
 
 /*
  * Sprintf, but with unlimited and automatically allocated buffering.
  */
 class Sprinter
 {
   public:
     struct InvariantChecker
--- a/js/src/jsproxy.cpp
+++ b/js/src/jsproxy.cpp
@@ -347,18 +347,20 @@ BaseProxyHandler::nativeCall(JSContext *
     ReportIncompatible(cx, args);
     return false;
 }
 
 bool
 BaseProxyHandler::hasInstance(JSContext *cx, JSObject *proxy, const Value *vp, bool *bp)
 {
     JS_ASSERT(OperationInProgress(cx, proxy));
+
+    RootedValue val(cx, ObjectValue(*proxy));
     js_ReportValueError(cx, JSMSG_BAD_INSTANCEOF_RHS,
-                        JSDVG_SEARCH_STACK, ObjectValue(*proxy), NULL);
+                        JSDVG_SEARCH_STACK, val, NullPtr());
     return false;
 }
 
 JSType
 BaseProxyHandler::typeOf(JSContext *cx, JSObject *proxy)
 {
     JS_ASSERT(OperationInProgress(cx, proxy));
     return IsFunctionProxy(proxy) ? JSTYPE_FUNCTION : JSTYPE_OBJECT;
@@ -488,17 +490,17 @@ IndirectProxyHandler::construct(JSContex
         fval = GetCall(proxy);
     return InvokeConstructor(cx, fval, argc, argv, rval);
 }
 
 bool
 IndirectProxyHandler::nativeCall(JSContext *cx, IsAcceptableThis test, NativeImpl impl,
                                     CallArgs args)
 {
-    args.thisv() = ObjectValue(*GetProxyTargetObject(&args.thisv().toObject()));
+    args.setThis(ObjectValue(*GetProxyTargetObject(&args.thisv().toObject())));
     if (!test(args.thisv())) {
         ReportIncompatible(cx, args);
         return false;
     }
 
     return CallNativeImpl(cx, impl, args);
 }
 
@@ -820,18 +822,19 @@ ScriptedProxyHandler::~ScriptedProxyHand
 }
 
 static bool
 ReturnedValueMustNotBePrimitive(JSContext *cx, JSObject *proxy, JSAtom *atom, const Value &v)
 {
     if (v.isPrimitive()) {
         JSAutoByteString bytes;
         if (js_AtomToPrintableString(cx, atom, &bytes)) {
+            RootedValue val(cx, ObjectOrNullValue(proxy));
             js_ReportValueError2(cx, JSMSG_BAD_TRAP_RETURN_VALUE,
-                                 JSDVG_SEARCH_STACK, ObjectOrNullValue(proxy), NULL, bytes.ptr());
+                                 JSDVG_SEARCH_STACK, val, NullPtr(), bytes.ptr());
         }
         return false;
     }
     return true;
 }
 
 static JSObject *
 GetProxyHandlerObject(JSContext *cx, JSObject *proxy)
@@ -1069,20 +1072,22 @@ class AutoPendingProxyOperation {
         if (!proto)                                                          \
             return true;                                                     \
         assertSameCompartment(cx, proxy, proto);                             \
         return protoCall;                                                    \
     JS_END_MACRO                                                             \
 
 
 bool
-Proxy::getPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, bool set,
+Proxy::getPropertyDescriptor(JSContext *cx, JSObject *proxy_, jsid id_, bool set,
                              PropertyDescriptor *desc)
 {
     JS_CHECK_RECURSION(cx, return false);
+    RootedObject proxy(cx, proxy_);
+    RootedId id(cx, id_);
     AutoPendingProxyOperation pending(cx, proxy);
     BaseProxyHandler *handler = GetProxyHandler(proxy);
     if (!handler->hasPrototype())
         return handler->getPropertyDescriptor(cx, proxy, id, set, desc);
     if (!handler->getOwnPropertyDescriptor(cx, proxy, id, set, desc))
         return false;
     if (desc->obj)
         return true;
@@ -1188,19 +1193,21 @@ Proxy::enumerate(JSContext *cx, JSObject
         return false;
     AutoIdVector protoProps(cx);
     INVOKE_ON_PROTOTYPE(cx, handler, proxy,
                         GetPropertyNames(cx, proto, 0, &protoProps) &&
                         AppendUnique(cx, props, protoProps));
 }
 
 bool
-Proxy::has(JSContext *cx, JSObject *proxy, jsid id, bool *bp)
+Proxy::has(JSContext *cx, JSObject *proxy_, jsid id_, bool *bp)
 {
     JS_CHECK_RECURSION(cx, return false);
+    RootedObject proxy(cx, proxy_);
+    RootedId id(cx, id_);
     AutoPendingProxyOperation pending(cx, proxy);
     BaseProxyHandler *handler = GetProxyHandler(proxy);
     if (!handler->hasPrototype())
         return handler->has(cx, proxy, id, bp);
     if (!handler->hasOwn(cx, proxy, id, bp))
         return false;
     if (*bp)
         return true;
@@ -1253,24 +1260,24 @@ Proxy::getElementIfPresent(JSContext *cx
 
 bool
 Proxy::set(JSContext *cx, HandleObject proxy, HandleObject receiver, HandleId id, bool strict,
            MutableHandleValue vp)
 {
     JS_CHECK_RECURSION(cx, return false);
     AutoPendingProxyOperation pending(cx, proxy);
     BaseProxyHandler *handler = GetProxyHandler(proxy);
-    JSObject *proto;
+    RootedObject proto(cx);
     if (handler->hasPrototype()) {
         // If we're using a prototype, we still want to use the proxy trap unless
         // we have a non-own property with a setter.
         bool hasOwn;
         AutoPropertyDescriptorRooter desc(cx);
         if (handler->hasOwn(cx, proxy, id, &hasOwn) && !hasOwn &&
-            handler->getPrototypeOf(cx, proxy, &proto) && proto &&
+            handler->getPrototypeOf(cx, proxy, proto.address()) && proto &&
             JS_GetPropertyDescriptorById(cx, proto, id, JSRESOLVE_QUALIFIED, &desc) &&
             desc.obj && desc.setter)
         {
             return proto->setGeneric(cx, receiver, id, vp, strict);
         } else if (cx->isExceptionPending()) {
             return false;
         }
     }
--- a/js/src/jsreflect.cpp
+++ b/js/src/jsreflect.cpp
@@ -181,17 +181,17 @@ class NodeBuilder
 
             if (funv.isNullOrUndefined()) {
                 callbacks[i].setNull();
                 continue;
             }
 
             if (!funv.isObject() || !funv.toObject().isFunction()) {
                 js_ReportValueErrorFlags(cx, JSREPORT_ERROR, JSMSG_NOT_FUNCTION,
-                                         JSDVG_SEARCH_STACK, funv, NULL, NULL, NULL);
+                                         JSDVG_SEARCH_STACK, funv, NullPtr(), NULL, NULL);
                 return false;
             }
 
             callbacks[i] = funv;
         }
 
         return true;
     }
@@ -3178,22 +3178,22 @@ reflect_parse(JSContext *cx, uint32_t ar
 
     char *filename = NULL;
     AutoReleaseNullablePtr filenamep(cx, filename);
     uint32_t lineno = 1;
     bool loc = true;
 
     JSObject *builder = NULL;
 
-    Value arg = argc > 1 ? JS_ARGV(cx, vp)[1] : UndefinedValue();
+    RootedValue arg(cx, argc > 1 ? JS_ARGV(cx, vp)[1] : UndefinedValue());
 
     if (!arg.isNullOrUndefined()) {
         if (!arg.isObject()) {
             js_ReportValueErrorFlags(cx, JSREPORT_ERROR, JSMSG_UNEXPECTED_TYPE,
-                                     JSDVG_SEARCH_STACK, arg, NULL, "not an object", NULL);
+                                     JSDVG_SEARCH_STACK, arg, NullPtr(), "not an object", NULL);
             return JS_FALSE;
         }
 
         RootedObject config(cx, &arg.toObject());
 
         RootedValue prop(cx);
 
         /* config.loc */
@@ -3240,17 +3240,17 @@ reflect_parse(JSContext *cx, uint32_t ar
         RootedId builderId(cx, NameToId(cx->runtime->atomState.builderAtom));
         RootedValue nullValue(cx, NullValue());
         if (!baseops::GetPropertyDefault(cx, config, builderId, nullValue, &prop))
             return JS_FALSE;
 
         if (!prop.isNullOrUndefined()) {
             if (!prop.isObject()) {
                 js_ReportValueErrorFlags(cx, JSREPORT_ERROR, JSMSG_UNEXPECTED_TYPE,
-                                         JSDVG_SEARCH_STACK, prop, NULL, "not an object", NULL);
+                                         JSDVG_SEARCH_STACK, prop, NullPtr(), "not an object", NULL);
                 return JS_FALSE;
             }
             builder = &prop.toObject();
         }
     }
 
     /* Extract the builder methods first to report errors before parsing. */
     ASTSerializer serialize(cx, loc, filename, lineno);
--- a/js/src/jsstr.cpp
+++ b/js/src/jsstr.cpp
@@ -435,31 +435,31 @@ ThisToStringForStringProto(JSContext *cx
         return call.thisv().toString();
 
     if (call.thisv().isObject()) {
         RootedObject obj(cx, &call.thisv().toObject());
         if (obj->isString()) {
             Rooted<jsid> id(cx, NameToId(cx->runtime->atomState.toStringAtom));
             if (ClassMethodIsNative(cx, obj, &StringClass, id, js_str_toString)) {
                 JSString *str = obj->asString().unbox();
-                call.thisv().setString(str);
+                call.setThis(StringValue(str));
                 return str;
             }
         }
     } else if (call.thisv().isNullOrUndefined()) {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_CONVERT_TO,
                              call.thisv().isNull() ? "null" : "undefined", "object");
         return NULL;
     }
 
     JSString *str = ToStringSlow(cx, call.thisv());
     if (!str)
         return NULL;
 
-    call.thisv().setString(str);
+    call.setThis(StringValue(str));
     return str;
 }
 
 static bool
 IsString(const Value &v)
 {
     return v.isString() || (v.isObject() && v.toObject().hasClass(&StringClass));
 }
@@ -1017,17 +1017,17 @@ StringMatch(const jschar *text, uint32_t
                         :
 #endif
                           UnrolledMatch<ManualCmp>(text, textlen, pat, patlen);
 }
 
 static const size_t sRopeMatchThresholdRatioLog2 = 5;
 
 /*
- * RopeMatch takes the text to search, the patern to search for in the text.
+ * RopeMatch takes the text to search and the pattern to search for in the text.
  * RopeMatch returns false on OOM and otherwise returns the match index through
  * the 'match' outparam (-1 for not found).
  */
 static bool
 RopeMatch(JSContext *cx, JSString *textstr, const jschar *pat, uint32_t patlen, int *match)
 {
     JS_ASSERT(textstr->isRope());
 
@@ -1143,16 +1143,19 @@ str_contains(JSContext *cx, unsigned arg
         return false;
 
     // Step 5
     uint32_t textlen = str->length();
     const jschar *text = str->getChars(cx);
     if (!text)
         return false;
 
+    // XXX fix for moving GC.
+    SkipRoot skip(cx, &text);
+
     if (args.hasDefined(1)) {
         // Step 4
         double posDouble;
         if (!ToInteger(cx, args[1], &posDouble))
             return false;
 
         // Step 6
         text += uint32_t(Min(double(textlen), Max(0.0, posDouble)));
@@ -1320,16 +1323,19 @@ str_startsWith(JSContext *cx, unsigned a
         return false;
 
     // Step 5
     uint32_t textlen = str->length();
     const jschar *text = str->getChars(cx);
     if (!text)
         return false;
 
+    // XXX fix for moving GC.
+    SkipRoot skip(cx, &text);
+
     if (args.hasDefined(1)) {
         // Step 4
         double posDouble;
         if (!ToInteger(cx, args[1], &posDouble))
             return false;
 
         // Step 6
         uint32_t position = Min(double(textlen), Max(0.0, posDouble));
@@ -1363,16 +1369,19 @@ str_endsWith(JSContext *cx, unsigned arg
         return false;
 
     // Step 4
     uint32_t textlen = str->length();
     const jschar *text = str->getChars(cx);
     if (!text)
         return false;
 
+    // XXX fix for moving GC.
+    SkipRoot skip(cx, &text);
+
     if (args.hasDefined(1)) {
         // Step 5
         double endPosDouble;
         if (!ToInteger(cx, args[1], &endPosDouble))
             return false;
 
         // Step 6
         textlen = Min(double(textlen), Max(0.0, endPosDouble));
@@ -1973,17 +1982,17 @@ FindReplaceLength(JSContext *cx, RegExpS
         unsigned p = res->parenCount();
         unsigned argc = 1 + p + 2;
 
         InvokeArgsGuard &args = rdata.args;
         if (!args.pushed() && !cx->stack.pushInvokeArgs(cx, argc, &args))
             return false;
 
         args.setCallee(ObjectValue(*lambda));
-        args.thisv() = UndefinedValue();
+        args.setThis(UndefinedValue());
 
         /* Push $&, $1, $2, ... */
         unsigned argi = 0;
         if (!res->createLastMatch(cx, &args[argi++]))
             return false;
 
         for (size_t i = 0; i < res->parenCount(); ++i) {
             if (!res->createParen(cx, i + 1, &args[argi++]))
@@ -2291,18 +2300,18 @@ str_replace_flat_lambda(JSContext *cx, C
         return false;
 
     /* lambda(matchStr, matchStart, textstr) */
     static const uint32_t lambdaArgc = 3;
     if (!cx->stack.pushInvokeArgs(cx, lambdaArgc, &rdata.args))
         return false;
 
     CallArgs &args = rdata.args;
-    args.calleev().setObject(*rdata.lambda);
-    args.thisv().setUndefined();
+    args.setCallee(ObjectValue(*rdata.lambda));
+    args.setThis(UndefinedValue());
 
     Value *sp = args.array();
     sp[0].setString(matchStr);
     sp[1].setInt32(fm.match());
     sp[2].setString(rdata.str);
 
     if (!Invoke(cx, rdata.args))
         return false;
@@ -2764,17 +2773,17 @@ js::str_split(JSContext *cx, unsigned ar
     args.rval().setObject(*aobj);
     return true;
 }
 
 static JSBool
 str_substr(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
-    JSString *str = ThisToStringForStringProto(cx, args);
+    RootedString str(cx, ThisToStringForStringProto(cx, args));
     if (!str)
         return false;
 
     int32_t length, len, begin;
     if (args.length() > 0) {
         length = int32_t(str->length());
         if (!ValueToIntegerRange(cx, args[0], &begin))
             return false;
--- a/js/src/jsstrinlines.h
+++ b/js/src/jsstrinlines.h
@@ -41,33 +41,33 @@ class RopeBuilder {
 };
 
 class StringSegmentRange
 {
     /*
      * If malloc() shows up in any profiles from this vector, we can add a new
      * StackAllocPolicy which stashes a reusable freed-at-gc buffer in the cx.
      */
-    Vector<JSString *, 32> stack;
-    JSLinearString *cur;
+    AutoStringVector stack;
+    Rooted<JSLinearString*> cur;
 
     bool settle(JSString *str) {
         while (str->isRope()) {
             JSRope &rope = str->asRope();
             if (!stack.append(rope.rightChild()))
                 return false;
             str = rope.leftChild();
         }
         cur = &str->asLinear();
         return true;
     }
 
   public:
     StringSegmentRange(JSContext *cx)
-      : stack(cx), cur(NULL)
+      : stack(cx), cur(cx)
     {}
 
     JS_WARN_UNUSED_RESULT bool init(JSString *str) {
         JS_ASSERT(stack.empty());
         return settle(str);
     }
 
     bool empty() const {
--- a/js/src/jstypedarray.cpp
+++ b/js/src/jstypedarray.cpp
@@ -138,36 +138,35 @@ ArrayBufferObject::byteLengthGetter(JSCo
 }
 
 bool
 ArrayBufferObject::fun_slice_impl(JSContext *cx, CallArgs args)
 {
     JS_ASSERT(IsArrayBuffer(args.thisv()));
 
     Rooted<JSObject*> thisObj(cx, &args.thisv().toObject());
-    ArrayBufferObject &arrayBuffer = thisObj->asArrayBuffer();
 
     // these are the default values
-    uint32_t length = arrayBuffer.byteLength();
+    uint32_t length = thisObj->asArrayBuffer().byteLength();
     uint32_t begin = 0, end = length;
 
     if (args.length() > 0) {
         if (!ToClampedIndex(cx, args[0], length, &begin))
             return false;
 
         if (args.length() > 1) {
             if (!ToClampedIndex(cx, args[1], length, &end))
                 return false;
         }
     }
 
     if (begin > end)
         begin = end;
 
-    JSObject *nobj = createSlice(cx, arrayBuffer, begin, end);
+    JSObject *nobj = createSlice(cx, thisObj->asArrayBuffer(), begin, end);
     if (!nobj)
         return false;
     args.rval().setObject(*nobj);
     return true;
 }
 
 JSBool
 ArrayBufferObject::fun_slice(JSContext *cx, unsigned argc, Value *vp)
@@ -1673,18 +1672,18 @@ class TypedArrayTemplate
                 Rooted<JSObject*> proto(cx, GetProtoForClass(cx, fastClass()));
                 if (!proto)
                     return NULL;
 
                 InvokeArgsGuard ag;
                 if (!cx->stack.pushInvokeArgs(cx, 3, &ag))
                     return NULL;
 
-                ag.calleev() = cx->compartment->maybeGlobal()->createArrayFromBuffer<NativeType>();
-                ag.thisv() = ObjectValue(*bufobj);
+                ag.setCallee(cx->compartment->maybeGlobal()->createArrayFromBuffer<NativeType>());
+                ag.setThis(ObjectValue(*bufobj));
                 ag[0] = Int32Value(byteOffsetInt);
                 ag[1] = Int32Value(lengthInt);
                 ag[2] = ObjectValue(*proto);
 
                 if (!Invoke(cx, ag))
                     return NULL;
                 return &ag.rval().toObject();
             }
@@ -2257,18 +2256,18 @@ DataViewObject::class_constructor(JSCont
         Rooted<GlobalObject*> global(cx, cx->compartment->maybeGlobal());
         Rooted<JSObject*> proto(cx, global->getOrCreateDataViewPrototype(cx));
         if (!proto)
             return false;
 
         InvokeArgsGuard ag;
         if (!cx->stack.pushInvokeArgs(cx, argc + 1, &ag))
             return false;
-        ag.calleev() = global->createDataViewForThis();
-        ag.thisv() = ObjectValue(*bufobj);
+        ag.setCallee(global->createDataViewForThis());
+        ag.setThis(ObjectValue(*bufobj));
         PodCopy(ag.array(), args.array(), args.length());
         ag[argc] = ObjectValue(*proto);
         if (!Invoke(cx, ag))
             return false;
         args.rval().set(ag.rval());
         return true;
     }
 
--- a/js/src/jsxml.cpp
+++ b/js/src/jsxml.cpp
@@ -200,17 +200,17 @@ static JSPropertySpec namespace_props[] 
     {js_prefix_str, 0, NAMESPACE_ATTRS, JSOP_WRAPPER(NamePrefix_getter), JSOP_NULLWRAPPER},
     {js_uri_str,    0, NAMESPACE_ATTRS, JSOP_WRAPPER(NameURI_getter), JSOP_NULLWRAPPER},
     {0,0,0,JSOP_NULLWRAPPER, JSOP_NULLWRAPPER}
 };
 
 static JSBool
 namespace_toString(JSContext *cx, unsigned argc, Value *vp)
 {
-    JSObject *obj = ToObject(cx, &vp[1]);
+    JSObject *obj = ToObject(cx, HandleValue::fromMarkedLocation(&vp[1]));
     if (!obj)
         return JS_FALSE;
     if (!obj->isNamespace()) {
         ReportIncompatibleMethod(cx, CallReceiverFromVp(vp), &NamespaceClass);
         return JS_FALSE;
     }
     *vp = obj->getNameURIVal();
     return JS_TRUE;
@@ -390,17 +390,17 @@ ConvertQNameToString(JSContext *cx, JSOb
         }
     }
     return str;
 }
 
 static JSBool
 qname_toString(JSContext *cx, unsigned argc, Value *vp)
 {
-    JSObject *obj = ToObject(cx, &vp[1]);
+    JSObject *obj = ToObject(cx, HandleValue::fromMarkedLocation(&vp[1]));
     if (!obj)
         return false;
 
     if (!obj->isQName()) {
         ReportIncompatibleMethod(cx, CallReceiverFromVp(vp), &QNameClass);
         return false;
     }
 
@@ -1892,18 +1892,19 @@ ToXML(JSContext *cx, jsval v)
             return NULL;
     } else {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_SYNTAX_ERROR);
         return NULL;
     }
     return obj;
 
 bad:
+    RootedValue val(cx, v);
     js_ReportValueError(cx, JSMSG_BAD_XML_CONVERSION,
-                        JSDVG_IGNORE_STACK, v, NULL);
+                        JSDVG_IGNORE_STACK, val, NullPtr());
     return NULL;
 }
 
 static JSBool
 Append(JSContext *cx, JSXML *list, JSXML *kid);
 
 static JSObject *
 ToXMLList(JSContext *cx, jsval v)
@@ -1968,18 +1969,19 @@ ToXMLList(JSContext *cx, jsval v)
                 break;
             }
         }
     }
 
     return listobj;
 
 bad:
+    RootedValue val(cx, v);
     js_ReportValueError(cx, JSMSG_BAD_XMLLIST_CONVERSION,
-                        JSDVG_IGNORE_STACK, v, NULL);
+                        JSDVG_IGNORE_STACK, val, NullPtr());
     return NULL;
 }
 
 /*
  * ECMA-357 10.2.1 Steps 5-7 pulled out as common subroutines of XMLToXMLString
  * and their library-public js_* counterparts.  The guts of MakeXMLCDataString,
  * MakeXMLCommentString, and MakeXMLPIString are further factored into a common
  * MakeXMLSpecialString subroutine.
@@ -2784,18 +2786,19 @@ ToAttributeName(JSContext *cx, jsval v)
     JSAtom *name;
     if (JSVAL_IS_STRING(v)) {
         name = ToAtom(cx, v);
         if (!name)
             return NULL;
         uri = prefix = cx->runtime->emptyString;
     } else {
         if (JSVAL_IS_PRIMITIVE(v)) {
+            RootedValue val(cx, v);
             js_ReportValueError(cx, JSMSG_BAD_XML_ATTR_NAME,
-                                JSDVG_IGNORE_STACK, v, NULL);
+                                JSDVG_IGNORE_STACK, val, NullPtr());
             return NULL;
         }
 
         obj = JSVAL_TO_OBJECT(v);
         clasp = obj->getClass();
         if (clasp == &AttributeNameClass)
             return obj;
 
@@ -2820,17 +2823,18 @@ ToAttributeName(JSContext *cx, jsval v)
     if (!qn)
         return NULL;
     return qn;
 }
 
 static void
 ReportBadXMLName(JSContext *cx, const Value &idval)
 {
-    js_ReportValueError(cx, JSMSG_BAD_XML_NAME, JSDVG_IGNORE_STACK, idval, NULL);
+    RootedValue val(cx, idval);
+    js_ReportValueError(cx, JSMSG_BAD_XML_NAME, JSDVG_IGNORE_STACK, val, NullPtr());
 }
 
 namespace js {
 
 bool
 GetLocalNameFromFunctionQName(JSObject *qn, JSAtom **namep, JSContext *cx)
 {
     JSAtom *atom = cx->runtime->atomState.functionNamespaceURIAtom;
@@ -5367,17 +5371,17 @@ StartNonListXMLMethod(JSContext *cx, jsv
 {
     JSXML *xml;
     JSFunction *fun;
     char numBuf[12];
 
     JS_ASSERT(!JSVAL_IS_PRIMITIVE(*vp));
     JS_ASSERT(JSVAL_TO_OBJECT(*vp)->isFunction());
 
-    objp.set(ToObject(cx, &vp[1]));
+    objp.set(ToObject(cx, HandleValue::fromMarkedLocation(&vp[1])));
     if (!objp)
         return NULL;
     if (!objp->isXML()) {
         ReportIncompatibleMethod(cx, CallReceiverFromVp(vp), &XMLClass);
         return NULL;
     }
     xml = (JSXML *) objp->getPrivate();
     if (!xml || xml->xml_class != JSXML_CLASS_LIST)
@@ -5401,17 +5405,17 @@ StartNonListXMLMethod(JSContext *cx, jsv
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NON_LIST_XML_METHOD,
                              funName, numBuf);
     }
     return NULL;
 }
 
 /* Beware: these two are not bracketed by JS_BEGIN/END_MACRO. */
 #define XML_METHOD_PROLOG                                                     \
-    JSObject *obj = ToObject(cx, &vp[1]);                                     \
+    JSObject *obj = ToObject(cx, HandleValue::fromMarkedLocation(&vp[1]));                                     \
     if (!obj)                                                                 \
         return JS_FALSE;                                                      \
     if (!obj->isXML()) {                                                      \
         ReportIncompatibleMethod(cx, CallReceiverFromVp(vp), &XMLClass);      \
         return JS_FALSE;                                                      \
     }                                                                         \
     JSXML *xml = (JSXML *)obj->getPrivate();                                  \
     if (!xml)                                                                 \
@@ -5485,43 +5489,44 @@ xml_appendChild(JSContext *cx, unsigned 
 
 /* XML and XMLList */
 static JSBool
 xml_attribute(JSContext *cx, unsigned argc, jsval *vp)
 {
     JSObject *qn;
 
     if (argc == 0) {
-        js_ReportMissingArg(cx, *vp, 0);
+        RootedValue val(cx, *vp);
+        js_ReportMissingArg(cx, val, 0);
         return JS_FALSE;
     }
 
     qn = ToAttributeName(cx, vp[2]);
     if (!qn)
         return JS_FALSE;
     vp[2] = OBJECT_TO_JSVAL(qn);        /* local root */
 
     RootedId id(cx, OBJECT_TO_JSID(qn));
-    RootedObject obj(cx, ToObject(cx, &vp[1]));
+    RootedObject obj(cx, ToObject(cx, HandleValue::fromMarkedLocation(&vp[1])));
     if (!obj)
         return JS_FALSE;
     return GetProperty(cx, obj, id, MutableHandleValue::fromMarkedLocation(vp));
 }
 
 /* XML and XMLList */
 static JSBool
 xml_attributes(JSContext *cx, unsigned argc, jsval *vp)
 {
     jsval name = STRING_TO_JSVAL(cx->runtime->atomState.starAtom);
     JSObject *qn = ToAttributeName(cx, name);
     if (!qn)
         return JS_FALSE;
 
     RootedId id(cx, OBJECT_TO_JSID(qn));
-    RootedObject obj(cx, ToObject(cx, &vp[1]));
+    RootedObject obj(cx, ToObject(cx, HandleValue::fromMarkedLocation(&vp[1])));
     if (!obj)
         return JS_FALSE;
     return GetProperty(cx, obj, id, MutableHandleValue::fromMarkedLocation(vp));
 }
 
 static JSXML *
 xml_list_helper(JSContext *cx, JSXML *xml, jsval *rval)
 {
@@ -5671,17 +5676,17 @@ xml_childIndex(JSContext *cx, unsigned a
         *vp = DOUBLE_TO_JSVAL(i);
     return JS_TRUE;
 }
 
 /* XML and XMLList */
 static JSBool
 xml_children(JSContext *cx, unsigned argc, jsval *vp)
 {
-    RootedObject obj(cx, ToObject(cx, &vp[1]));
+    RootedObject obj(cx, ToObject(cx, HandleValue::fromMarkedLocation(&vp[1])));
     if (!obj)
         return false;
     RootedId name(cx, NameToId(cx->runtime->atomState.starAtom));
     return GetProperty(cx, obj, name, MutableHandleValue::fromMarkedLocation(vp));
 }
 
 /* XML and XMLList */
 static JSBool
@@ -5878,17 +5883,17 @@ xml_elements(JSContext *cx, unsigned arg
 
 /* XML and XMLList */
 static JSBool
 xml_hasOwnProperty(JSContext *cx, unsigned argc, jsval *vp)
 {
     jsval name;
     JSBool found;
 
-    JSObject *obj = ToObject(cx, &vp[1]);
+    JSObject *obj = ToObject(cx, HandleValue::fromMarkedLocation(&vp[1]));
     if (!obj)
         return JS_FALSE;
     if (!obj->isXML()) {
         ReportIncompatibleMethod(cx, CallReceiverFromVp(vp), &XMLClass);
         return JS_FALSE;
     }
 
     name = argc != 0 ? vp[2] : JSVAL_VOID;
@@ -6920,17 +6925,17 @@ xml_toString_helper(JSContext *cx, JSXML
         }
     }
     return str;
 }
 
 static JSBool
 xml_toSource(JSContext *cx, unsigned argc, jsval *vp)
 {
-    JSObject *obj = ToObject(cx, &vp[1]);
+    JSObject *obj = ToObject(cx, HandleValue::fromMarkedLocation(&vp[1]));
     if (!obj)
         return JS_FALSE;
     JSString *str = ToXMLString(cx, OBJECT_TO_JSVAL(obj), TO_SOURCE_FLAG);
     if (!str)
         return JS_FALSE;
     *vp = STRING_TO_JSVAL(str);
     return JS_TRUE;
 }
@@ -6947,31 +6952,31 @@ xml_toString(JSContext *cx, unsigned arg
     *vp = STRING_TO_JSVAL(str);
     return JS_TRUE;
 }
 
 /* XML and XMLList */
 static JSBool
 xml_toXMLString(JSContext *cx, unsigned argc, jsval *vp)
 {
-    JSObject *obj = ToObject(cx, &vp[1]);
+    JSObject *obj = ToObject(cx, HandleValue::fromMarkedLocation(&vp[1]));
     if (!obj)
         return JS_FALSE;
     JSString *str = ToXMLString(cx, OBJECT_TO_JSVAL(obj), 0);
     if (!str)
         return JS_FALSE;
     *vp = STRING_TO_JSVAL(str);
     return JS_TRUE;
 }
 
 /* XML and XMLList */
 static JSBool
 xml_valueOf(JSContext *cx, unsigned argc, jsval *vp)
 {
-    JSObject *obj = ToObject(cx, &vp[1]);
+    JSObject *obj = ToObject(cx, HandleValue::fromMarkedLocation(&vp[1]));
     if (!obj)
         return false;
     *vp = OBJECT_TO_JSVAL(obj);
     return true;
 }
 
 static JSFunctionSpec xml_methods[] = {
     JS_FN("addNamespace",          xml_addNamespace,          1,0),
@@ -7061,29 +7066,29 @@ SetDefaultXMLSettings(JSContext *cx, Han
 
 static JSBool
 xml_settings(JSContext *cx, unsigned argc, jsval *vp)
 {
     RootedObject settings(cx, JS_NewObject(cx, NULL, NULL, NULL));
     if (!settings)
         return false;
     *vp = OBJECT_TO_JSVAL(settings);
-    RootedObject obj(cx, ToObject(cx, &vp[1]));
+    RootedObject obj(cx, ToObject(cx, HandleValue::fromMarkedLocation(&vp[1])));
     if (!obj)
         return false;
     return CopyXMLSettings(cx, obj, settings);
 }
 
 static JSBool
 xml_setSettings(JSContext *cx, unsigned argc, jsval *vp)
 {
     jsval v;
     JSBool ok;
 
-    RootedObject obj(cx, ToObject(cx, &vp[1]));
+    RootedObject obj(cx, ToObject(cx, HandleValue::fromMarkedLocation(&vp[1])));
     if (!obj)
         return JS_FALSE;
     v = (argc == 0) ? JSVAL_VOID : vp[2];
     if (JSVAL_IS_NULL(v) || JSVAL_IS_VOID(v)) {
         ok = SetDefaultXMLSettings(cx, obj);
     } else {
         if (JSVAL_IS_PRIMITIVE(v)) {
             vp[0] = JSVAL_VOID;
@@ -7877,17 +7882,18 @@ js_StepXMLListFilter(JSContext *cx, JSBo
 
     sp = cx->regs().sp;
     if (!initialized) {
         /*
          * We haven't iterated yet, so initialize the filter based on the
          * value stored in sp[-2].
          */
         if (!VALUE_IS_XML(sp[-2])) {
-            js_ReportValueError(cx, JSMSG_NON_XML_FILTER, -2, sp[-2], NULL);
+            RootedValue val(cx, sp[-2]);
+            js_ReportValueError(cx, JSMSG_NON_XML_FILTER, -2, val, NullPtr());
             return JS_FALSE;
         }
         obj = JSVAL_TO_OBJECT(sp[-2]);
         xml = (JSXML *) obj->getPrivate();
 
         if (xml->xml_class == JSXML_CLASS_LIST) {
             list = xml;
         } else {
--- a/js/src/methodjit/InvokeHelpers.cpp
+++ b/js/src/methodjit/InvokeHelpers.cpp
@@ -1000,17 +1000,18 @@ js_InternalInterpret(void *returnData, v
         switch (op) {
           case JSOP_INSTANCEOF: {
             /*
              * If we recompiled from a getprop used within JSOP_INSTANCEOF,
              * the stack looks like 'LHS RHS protov'. Inline the remaining
              * portion of fun_hasInstance.
              */
             if (f.regs.sp[0].isPrimitive()) {
-                js_ReportValueError(cx, JSMSG_BAD_PROTOTYPE, -1, f.regs.sp[-1], NULL);
+                RootedValue val(cx, f.regs.sp[-1]);
+                js_ReportValueError(cx, JSMSG_BAD_PROTOTYPE, -1, val, NullPtr());
                 return js_InternalThrow(f);
             }
             nextsp[-1].setBoolean(js_IsDelegate(cx, &f.regs.sp[0].toObject(), f.regs.sp[-2]));
             f.regs.pc = nextpc;
             break;
           }
 
           default:
--- a/js/src/methodjit/MonoIC.cpp
+++ b/js/src/methodjit/MonoIC.cpp
@@ -766,17 +766,17 @@ class CallCompiler : public BaseCompiler
         RootedFunction fun(cx);
         if (!IsFunctionObject(args.calleev(), fun.address()))
             return false;
 
         if ((!callingNew && !fun->isNative()) || (callingNew && !fun->isNativeConstructor()))
             return false;
 
         if (callingNew)
-            args.thisv().setMagic(JS_IS_CONSTRUCTING);
+            args.setThis(MagicValue(JS_IS_CONSTRUCTING));
 
         RecompilationMonitor monitor(cx);
 
         if (!CallJSNative(cx, fun->native(), args))
             THROWV(true);
 
         types::TypeScript::Monitor(f.cx, f.script(), f.pc(), args.rval());
 
--- a/js/src/methodjit/PolyIC.cpp
+++ b/js/src/methodjit/PolyIC.cpp
@@ -1943,52 +1943,54 @@ ic::GetProp(VMFrame &f, ic::PICInfo *pic
                     JSString *str = obj->asString().unbox();
                     f.regs.sp[-1].setInt32(str->length());
                 }
                 return;
             }
         }
     }
 
+    RootedValue objval(f.cx, f.regs.sp[-1]);
+
     if (f.regs.sp[-1].isString()) {
         GetPropCompiler cc(f, NULL, *pic, name, stub);
         if (name == f.cx->runtime->atomState.lengthAtom) {
             LookupStatus status = cc.generateStringLengthStub();
             if (status == Lookup_Error)
                 THROW();
             JSString *str = f.regs.sp[-1].toString();
             f.regs.sp[-1].setInt32(str->length());
         } else {
             LookupStatus status = cc.generateStringPropertyStub();
             if (status == Lookup_Error)
                 THROW();
-            JSObject *obj = ValueToObject(f.cx, f.regs.sp[-1]);
+            JSObject *obj = ToObjectFromStack(f.cx, objval);
             if (!obj)
                 THROW();
             if (!obj->getProperty(f.cx, name, MutableHandleValue::fromMarkedLocation(&f.regs.sp[-1])))
                 THROW();
         }
         return;
     }
 
     RecompilationMonitor monitor(f.cx);
 
-    RootedObject obj(f.cx, ValueToObject(f.cx, f.regs.sp[-1]));
+    RootedObject obj(f.cx, ToObjectFromStack(f.cx, objval));
     if (!obj)
         THROW();
 
     if (!monitor.recompiled() && pic->shouldUpdate(f)) {
         GetPropCompiler cc(f, obj, *pic, name, stub);
         if (!cc.update())
             THROW();
     }
 
     RootedValue v(f.cx);
     if (cached) {
-        if (!GetPropertyOperation(f.cx, f.script(), f.pc(), f.regs.sp[-1], v.address()))
+        if (!GetPropertyOperation(f.cx, f.pc(), &objval, &v))
             THROW();
     } else {
         if (!obj->getProperty(f.cx, name, &v))
             THROW();
     }
 
     f.regs.sp[-1] = v;
 }
@@ -2008,17 +2010,18 @@ ic::SetProp(VMFrame &f, ic::PICInfo *pic
     VoidStubPIC stub = STRICT_VARIANT(f.script(), DisabledSetPropIC);
 
     // Save this in case the compiler triggers a recompilation of this script.
     RootedPropertyName name(f.cx, pic->name);
     VoidStubName nstub = STRICT_VARIANT(f.script(), stubs::SetName);
 
     RecompilationMonitor monitor(f.cx);
 
-    JSObject *obj = ValueToObject(f.cx, f.regs.sp[-2]);
+    RootedValue objval(f.cx, f.regs.sp[-2]);
+    JSObject *obj = ToObjectFromStack(f.cx, objval);
     if (!obj)
         THROW();
 
     // Note, we can't use SetName for PROPINC PICs because the property
     // cache can't handle a GET and SET from the same scripted PC.
     if (!monitor.recompiled() && pic->shouldUpdate(f)) {
         SetPropCompiler cc(f, obj, *pic, name, stub);
         LookupStatus status = cc.update();
@@ -2545,22 +2548,22 @@ ic::GetElement(VMFrame &f, ic::GetElemen
 
     // Right now, we don't optimize for strings or lazy arguments.
     if (!f.regs.sp[-2].isObject()) {
         ic->disable(f, "non-object");
         stubs::GetElem(f);
         return;
     }
 
-    RootedValue idval_(cx, f.regs.sp[-1]);
-    Value &idval = idval_.get();
+    RootedValue idval(cx, f.regs.sp[-1]);
 
     RecompilationMonitor monitor(cx);
 
-    RootedObject obj(cx, ValueToObject(cx, f.regs.sp[-2]));
+    RootedValue objval(f.cx, f.regs.sp[-2]);
+    RootedObject obj(cx, ToObjectFromStack(cx, objval));
     if (!obj)
         THROW();
 
 #if JS_HAS_XML_SUPPORT
     // Some XML properties behave differently when accessed in a call vs. normal
     // context, so we fall back to stubs::GetElem.
     if (obj->isXML()) {
         ic->disable(f, "XML object");
@@ -2578,17 +2581,17 @@ ic::GetElement(VMFrame &f, ic::GetElemen
     }
 
     MutableHandleValue res = MutableHandleValue::fromMarkedLocation(&f.regs.sp[-2]);
 
     if (!monitor.recompiled() && ic->shouldUpdate(f)) {
 #ifdef DEBUG
         f.regs.sp[-2] = MagicValue(JS_GENERIC_MAGIC);
 #endif
-        LookupStatus status = ic->update(f, obj, idval_, id, res);
+        LookupStatus status = ic->update(f, obj, idval, id, res);
         if (status != Lookup_Uncacheable && status != Lookup_NoProperty) {
             if (status == Lookup_Error)
                 THROW();
 
             // If the result can be cached, the value was already retrieved.
             JS_ASSERT(!f.regs.sp[-2].isMagic());
             return;
         }
--- a/js/src/methodjit/StubCalls.cpp
+++ b/js/src/methodjit/StubCalls.cpp
@@ -67,18 +67,18 @@ stubs::BindGlobalName(VMFrame &f)
     return &f.fp()->global();
 }
 
 template<JSBool strict>
 void JS_FASTCALL
 stubs::SetName(VMFrame &f, PropertyName *name)
 {
     JSContext *cx = f.cx;
-    const Value &rval = f.regs.sp[-1];
-    const Value &lval = f.regs.sp[-2];
+    HandleValue rval = HandleValue::fromMarkedLocation(&f.regs.sp[-1]);
+    HandleValue lval = HandleValue::fromMarkedLocation(&f.regs.sp[-2]);
 
     if (!SetPropertyOperation(cx, f.pc(), lval, rval))
         THROW();
 
     f.regs.sp[-2] = f.regs.sp[-1];
 }
 
 template void JS_FASTCALL stubs::SetName<true>(VMFrame &f, PropertyName *origName);
@@ -101,38 +101,38 @@ stubs::Name(VMFrame &f)
     if (!NameOperation(f.cx, f.script(), f.pc(), &rval))
         THROW();
     f.regs.sp[0] = rval;
 }
 
 void JS_FASTCALL
 stubs::GetElem(VMFrame &f)
 {
-    Value &lref = f.regs.sp[-2];
-    Value &rref = f.regs.sp[-1];
+    MutableHandleValue lval = MutableHandleValue::fromMarkedLocation(&f.regs.sp[-2]);
+    HandleValue rval = HandleValue::fromMarkedLocation(&f.regs.sp[-1]);
     MutableHandleValue res = MutableHandleValue::fromMarkedLocation(&f.regs.sp[-2]);
 
-    if (!GetElementOperation(f.cx, JSOp(*f.pc()), lref, rref, res))
+    if (!GetElementOperation(f.cx, JSOp(*f.pc()), lval, rval, res))
         THROW();
 }
 
 template<JSBool strict>
 void JS_FASTCALL
 stubs::SetElem(VMFrame &f)
 {
     JSContext *cx = f.cx;
     FrameRegs &regs = f.regs;
 
-    Value &objval = regs.sp[-3];
+    HandleValue objval = HandleValue::fromMarkedLocation(&regs.sp[-3]);
     Value &idval  = regs.sp[-2];
     RootedValue rval(cx, regs.sp[-1]);
 
     RootedId id(cx);
 
-    Rooted<JSObject*> obj(cx, ValueToObject(cx, objval));
+    Rooted<JSObject*> obj(cx, ToObjectFromStack(cx, objval));
     if (!obj)
         THROW();
 
     if (!FetchElementId(f.cx, obj, idval, id.address(),
                         MutableHandleValue::fromMarkedLocation(&regs.sp[-2])))
     {
         THROW();
     }
@@ -169,20 +169,20 @@ stubs::SetElem(VMFrame &f)
 }
 
 template void JS_FASTCALL stubs::SetElem<true>(VMFrame &f);
 template void JS_FASTCALL stubs::SetElem<false>(VMFrame &f);
 
 void JS_FASTCALL
 stubs::ToId(VMFrame &f)
 {
-    Value &objval = f.regs.sp[-2];
+    HandleValue objval = HandleValue::fromMarkedLocation(&f.regs.sp[-2]);
     MutableHandleValue idval = MutableHandleValue::fromMarkedLocation(&f.regs.sp[-1]);
 
-    JSObject *obj = ValueToObject(f.cx, objval);
+    JSObject *obj = ToObjectFromStack(f.cx, objval);
     if (!obj)
         THROW();
 
     RootedId id(f.cx);
     if (!FetchElementId(f.cx, obj, idval, id.address(), idval))
         THROW();
 
     if (!idval.isInt32())
@@ -978,18 +978,20 @@ stubs::Lambda(VMFrame &f, JSFunction *fu
 }
 
 void JS_FASTCALL
 stubs::GetProp(VMFrame &f, PropertyName *name)
 {
     JSContext *cx = f.cx;
     FrameRegs &regs = f.regs;
 
+    MutableHandleValue objval = MutableHandleValue::fromMarkedLocation(&f.regs.sp[-1]);
+
     RootedValue rval(cx);
-    if (!GetPropertyOperation(cx, f.script(), f.pc(), f.regs.sp[-1], rval.address()))
+    if (!GetPropertyOperation(cx, f.pc(), objval, &rval))
         THROW();
 
     regs.sp[-1] = rval;
 }
 
 void JS_FASTCALL
 stubs::GetPropNoCache(VMFrame &f, PropertyName *name)
 {
@@ -1137,20 +1139,20 @@ stubs::Arguments(VMFrame &f)
 }
 
 JSBool JS_FASTCALL
 stubs::InstanceOf(VMFrame &f)
 {
     JSContext *cx = f.cx;
     FrameRegs &regs = f.regs;
 
-    const Value &rref = regs.sp[-1];
+    RootedValue rref(cx, regs.sp[-1]);
     if (rref.isPrimitive()) {
         js_ReportValueError(cx, JSMSG_BAD_INSTANCEOF_RHS,
-                            -1, rref, NULL);
+                            -1, rref, NullPtr());
         THROWV(JS_FALSE);
     }
     RootedObject obj(cx, &rref.toObject());
     const Value &lref = regs.sp[-2];
     JSBool cond = JS_FALSE;
     if (!HasInstance(cx, obj, &lref, &cond))
         THROWV(JS_FALSE);
     f.regs.sp[-2].setBoolean(cond);
@@ -1162,17 +1164,18 @@ stubs::FastInstanceOf(VMFrame &f)
 {
     const Value &lref = f.regs.sp[-1];
 
     if (lref.isPrimitive()) {
         /*
          * Throw a runtime error if instanceof is called on a function that
          * has a non-object as its .prototype value.
          */
-        js_ReportValueError(f.cx, JSMSG_BAD_PROTOTYPE, -1, f.regs.sp[-2], NULL);
+        RootedValue val(f.cx, f.regs.sp[-2]);
+        js_ReportValueError(f.cx, JSMSG_BAD_PROTOTYPE, -1, val, NullPtr());
         THROW();
     }
 
     f.regs.sp[-3].setBoolean(js_IsDelegate(f.cx, &lref.toObject(), f.regs.sp[-3]));
 }
 
 void JS_FASTCALL
 stubs::EnterBlock(VMFrame &f, JSObject *obj)
@@ -1360,17 +1363,18 @@ stubs::DelName(VMFrame &f, PropertyName 
 
 template<JSBool strict>
 void JS_FASTCALL
 stubs::DelProp(VMFrame &f, PropertyName *name_)
 {
     JSContext *cx = f.cx;
     RootedPropertyName name(cx, name_);
 
-    JSObject *obj = ValueToObject(cx, f.regs.sp[-1]);
+    RootedValue objval(cx, f.regs.sp[-1]);
+    JSObject *obj = ToObjectFromStack(cx, objval);
     if (!obj)
         THROW();
 
     RootedValue rval(cx);
     if (!obj->deleteProperty(cx, name, &rval, strict))
         THROW();
 
     f.regs.sp[-1] = rval;
@@ -1380,17 +1384,18 @@ template void JS_FASTCALL stubs::DelProp
 template void JS_FASTCALL stubs::DelProp<false>(VMFrame &f, PropertyName *name);
 
 template<JSBool strict>
 void JS_FASTCALL
 stubs::DelElem(VMFrame &f)
 {
     JSContext *cx = f.cx;
 
-    JSObject *obj = ValueToObject(cx, f.regs.sp[-2]);
+    RootedValue objval(cx, f.regs.sp[-2]);
+    JSObject *obj = ToObjectFromStack(cx, objval);
     if (!obj)
         THROW();
 
     const Value &propval = f.regs.sp[-1];
     MutableHandleValue rval = MutableHandleValue::fromMarkedLocation(&f.regs.sp[-2]);
 
     if (!obj->deleteByValue(cx, propval, rval, strict))
         THROW();
@@ -1429,17 +1434,18 @@ stubs::SetConst(VMFrame &f, PropertyName
 
 JSBool JS_FASTCALL
 stubs::In(VMFrame &f)
 {
     JSContext *cx = f.cx;
 
     const Value &rref = f.regs.sp[-1];
     if (!rref.isObject()) {
-        js_ReportValueError(cx, JSMSG_IN_NOT_OBJECT, -1, rref, NULL);
+        RootedValue val(cx, rref);
+        js_ReportValueError(cx, JSMSG_IN_NOT_OBJECT, -1, val, NullPtr());
         THROWV(JS_FALSE);
     }
 
     RootedObject obj(cx, &rref.toObject());
     RootedId id(cx);
     if (!FetchElementId(f.cx, obj, f.regs.sp[-2], id.address(),
                         MutableHandleValue::fromMarkedLocation(&f.regs.sp[-2])))
     {
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -2529,19 +2529,19 @@ NewSandbox(JSContext *cx, bool lazy)
     if (!cx->compartment->wrap(cx, obj.address()))
         return NULL;
     return obj;
 }
 
 static JSBool
 EvalInContext(JSContext *cx, unsigned argc, jsval *vp)
 {
-    JSString *str;
+    RootedString str(cx);
     RootedObject sobj(cx);
-    if (!JS_ConvertArguments(cx, argc, JS_ARGV(cx, vp), "S / o", &str, sobj.address()))
+    if (!JS_ConvertArguments(cx, argc, JS_ARGV(cx, vp), "S / o", str.address(), sobj.address()))
         return false;
 
     size_t srclen;
     const jschar *src = JS_GetStringCharsAndLength(cx, str, &srclen);
     if (!src)
         return false;
 
     SkipRoot skip(cx, &src);
--- a/js/src/vm/Debugger.cpp
+++ b/js/src/vm/Debugger.cpp
@@ -100,18 +100,19 @@ ReportObjectRequired(JSContext *cx)
 
 bool
 ValueToIdentifier(JSContext *cx, const Value &v, jsid *idp)
 {
     jsid id;
     if (!ValueToId(cx, v, &id))
         return false;
     if (!JSID_IS_ATOM(id) || !IsIdentifier(JSID_TO_ATOM(id))) {
+        RootedValue val(cx, v);
         js_ReportValueErrorFlags(cx, JSREPORT_ERROR, JSMSG_UNEXPECTED_TYPE,
-                                 JSDVG_SEARCH_STACK, v, NULL, "not an identifier", NULL);
+                                 JSDVG_SEARCH_STACK, val, NullPtr(), "not an identifier", NULL);
         return false;
     }
     *idp = id;
     return true;
 }
 
 /*
  * A range of all the Debugger.Frame objects for a particular StackFrame.
@@ -1467,17 +1468,16 @@ Debugger::sweepAll(FreeOp *fop)
             /*
              * dbg is being GC'd. Detach it from its debuggees. The debuggee
              * might be GC'd too. Since detaching requires access to both
              * objects, this must be done before finalize time.
              */
             for (GlobalObjectSet::Enum e(dbg->debuggees); !e.empty(); e.popFront())
                 dbg->removeDebuggeeGlobal(fop, e.front(), NULL, &e);
         }
-
     }
 
     for (JSCompartment **c = rt->compartments.begin(); c != rt->compartments.end(); c++) {
         /* For each debuggee being GC'd, detach it from all its debuggers. */
         GlobalObjectSet &debuggees = (*c)->getDebuggees();
         for (GlobalObjectSet::Enum e(debuggees); !e.empty(); e.popFront()) {
             GlobalObject *global = e.front();
             if (!IsObjectMarked(&global))
@@ -1966,22 +1966,28 @@ Debugger::removeDebuggeeGlobal(FreeOp *f
     }
     JS_ASSERT(p != v->end());
 
     /*
      * The relation must be removed from up to three places: *v and debuggees
      * for sure, and possibly the compartment's debuggee set.
      */
     v->erase(p);
-    if (v->empty())
-        global->compartment()->removeDebuggee(fop, global, compartmentEnum);
     if (debugEnum)
         debugEnum->removeFront();
     else
         debuggees.remove(global);
+
+    /*
+     * The debuggee needs to be removed from the compartment last, as this can
+     * trigger GCs if the compartment's debug mode is being changed, and the
+     * global cannot be rooted on the stack without a cx.
+     */
+    if (v->empty())
+        global->compartment()->removeDebuggee(fop, global, compartmentEnum);
 }
 
 /*
  * A class for parsing 'findScripts' query arguments and searching for
  * scripts that match the criteria they represent.
  */
 class Debugger::ScriptQuery {
   public:
@@ -3166,17 +3172,17 @@ DebuggerArguments_getArg(JSContext *cx, 
                              "Arguments", "getArgument", argsobj->getClass()->name);
         return false;
     }
 
     /*
      * Put the Debugger.Frame into the this-value slot, then use THIS_FRAME
      * to check that it is still live and get the fp.
      */
-    args.thisv() = argsobj->getReservedSlot(JSSLOT_DEBUGARGUMENTS_FRAME);
+    args.setThis(argsobj->getReservedSlot(JSSLOT_DEBUGARGUMENTS_FRAME));
     THIS_FRAME(cx, argc, vp, "get argument", ca2, thisobj, fp);
 
     /*
      * Since getters can be extracted and applied to other objects,
      * there is no guarantee this object has an ith argument.
      */
     JS_ASSERT(i >= 0);
     Value arg;
@@ -3902,17 +3908,19 @@ DebuggerObject_defineProperty(JSContext 
     return true;
 }
 
 static JSBool
 DebuggerObject_defineProperties(JSContext *cx, unsigned argc, Value *vp)
 {
     THIS_DEBUGOBJECT_OWNER_REFERENT(cx, argc, vp, "defineProperties", args, dbg, obj);
     REQUIRE_ARGC("Debugger.Object.defineProperties", 1);
-    RootedObject props(cx, ToObject(cx, &args[0]));
+
+    RootedValue arg(cx, args[0]);
+    RootedObject props(cx, ToObject(cx, arg));
     if (!props)
         return false;
 
     AutoIdVector ids(cx);
     AutoPropDescArrayRooter descs(cx);
     if (!ReadPropertyDescriptors(cx, props, false, &ids, &descs))
         return false;
     size_t n = ids.length();
--- a/js/src/vm/ObjectImpl.cpp
+++ b/js/src/vm/ObjectImpl.cpp
@@ -413,20 +413,21 @@ DenseElementsHeader::defineElement(JSCon
     /*
      * If the element doesn't exist, we can only add it if the object is
      * extensible.
      */
     if (!obj->isExtensible()) {
         *succeeded = false;
         if (!shouldThrow)
             return true;
+        RootedValue val(cx, ObjectValue(*obj));
         MOZ_ALWAYS_FALSE(js_ReportValueErrorFlags(cx, JSREPORT_ERROR, JSMSG_OBJECT_NOT_EXTENSIBLE,
                                                   JSDVG_IGNORE_STACK,
-                                                  ObjectValue(*obj),
-                                                  NULL, NULL, NULL));
+                                                  val, NullPtr(),
+                                                  NULL, NULL));
         return false;
     }
 
     /* Otherwise we ensure space for it exists and that it's initialized. */
     ObjectImpl::DenseElementsResult res = obj->ensureDenseElementsInitialized(cx, index, 0);
 
     /* Propagate any error. */
     if (res == ObjectImpl::Failure)
@@ -461,20 +462,21 @@ js::ArrayBufferDelegate(JSContext *cx, H
 template <typename T>
 bool
 TypedElementsHeader<T>::defineElement(JSContext *cx, Handle<ObjectImpl*> obj,
                                       uint32_t index, const PropDesc &desc, bool shouldThrow,
                                       unsigned resolveFlags, bool *succeeded)
 {
     /* XXX jwalden This probably isn't how typed arrays should behave... */
     *succeeded = false;
+
+    RootedValue val(cx, ObjectValue(*obj));
     js_ReportValueErrorFlags(cx, JSREPORT_ERROR, JSMSG_OBJECT_NOT_EXTENSIBLE,
                              JSDVG_IGNORE_STACK,
-                             ObjectValue(*obj),
-                             NULL, NULL, NULL);
+                             val, NullPtr(), NULL, NULL);
     return false;
 }
 
 bool
 ArrayBufferElementsHeader::defineElement(JSContext *cx, Handle<ObjectImpl*> obj,
                                          uint32_t index, const PropDesc &desc, bool shouldThrow,
                                          unsigned resolveFlags, bool *succeeded)
 {
@@ -624,18 +626,18 @@ js::GetElement(JSContext *cx, Handle<Obj
                 return true;
             }
 
             InvokeArgsGuard args;
             if (!cx->stack.pushInvokeArgs(cx, 0, &args))
                 return false;
 
             /* Push get, receiver, and no args. */
-            args.calleev() = get;
-            args.thisv() = ObjectValue(*current);
+            args.setCallee(get);
+            args.setThis(ObjectValue(*current));
 
             bool ok = Invoke(cx, args);
             *vp = args.rval();
             return ok;
         }
 
         /* Otherwise it's a PropertyOp-based property.  XXX handle this! */
         MOZ_NOT_REACHED("NYI: handle PropertyOp'd properties here");
@@ -856,18 +858,18 @@ js::SetElement(JSContext *cx, Handle<Obj
                     return true;
                 }
 
                 InvokeArgsGuard args;
                 if (!cx->stack.pushInvokeArgs(cx, 1, &args))
                     return false;
 
                 /* Push set, receiver, and v as the sole argument. */
-                args.calleev() = setter;
-                args.thisv() = ObjectValue(*current);
+                args.setCallee(setter);
+                args.setThis(ObjectValue(*current));
                 args[0] = v;
 
                 *succeeded = true;
                 return Invoke(cx, args);
             }
 
             MOZ_NOT_REACHED("NYI: setting PropertyOp-based property");
             return false;
--- a/js/src/vm/ScopeObject.cpp
+++ b/js/src/vm/ScopeObject.cpp
@@ -1364,18 +1364,19 @@ class DebugScopeProxy : public BaseProxy
         }
 
         RootedObject scopeObj(cx, &scope);
         return GetPropertyNames(cx, scopeObj, JSITER_OWNONLY, &props);
     }
 
     bool delete_(JSContext *cx, JSObject *proxy, jsid id, bool *bp) MOZ_OVERRIDE
     {
+        RootedValue val(cx, IdToValue(id));
         return js_ReportValueErrorFlags(cx, JSREPORT_ERROR, JSMSG_CANT_DELETE,
-                                        JSDVG_IGNORE_STACK, IdToValue(id), NULL,
+                                        JSDVG_IGNORE_STACK, val, NullPtr(),
                                         NULL, NULL);
     }
 
     bool enumerate(JSContext *cx, JSObject *proxy, AutoIdVector &props) MOZ_OVERRIDE
     {
         ScopeObject &scope = proxy->asDebugScope().scope();
 
         if (isMissingArgumentsBinding(scope) &&
--- a/layout/base/FrameLayerBuilder.cpp
+++ b/layout/base/FrameLayerBuilder.cpp
@@ -3104,17 +3104,17 @@ ContainerState::SetupMaskLayer(Layer *aL
     roundedRects.AppendElement(
       MaskLayerImageCache::PixelRoundedRect(newData.mRoundedClipRects[i],
                                             mContainerFrame->PresContext()));
     roundedRects[i].ScaleAndTranslate(imageTransform);
   }
  
   // check to see if we can reuse a mask image
   const MaskLayerImageCache::MaskLayerImageKey* key =
-    new MaskLayerImageCache::MaskLayerImageKey(roundedRects);
+    new MaskLayerImageCache::MaskLayerImageKey(roundedRects, aLayer->Manager()->GetBackendType());
   const MaskLayerImageCache::MaskLayerImageKey* lookupKey = key;
 
   nsRefPtr<ImageContainer> container =
     GetMaskLayerImageCache()->FindImageFor(&lookupKey);
 
   if (container) {
     // track the returned key for the mask image
     delete key;
--- a/layout/base/MaskLayerImageCache.h
+++ b/layout/base/MaskLayerImageCache.h
@@ -108,18 +108,19 @@ public:
    * MaskLayerImageEntry::mContainer; it is maintained by MaskLayerUserData,
    * which keeps a reference to the key. There will usually be mLayerCount + 1
    * pointers to a key object (the +1 being from the hashtable entry), but this
    * invariant may be temporarily broken.
    */
   class MaskLayerImageKey
   {
   public:
-    MaskLayerImageKey(const nsTArray<PixelRoundedRect>& aRoundedClipRects)
-      : mLayerCount(0)
+    MaskLayerImageKey(const nsTArray<PixelRoundedRect>& aRoundedClipRects, layers::LayersBackend aBackend)
+      : mBackend(aBackend)
+      , mLayerCount(0)
       , mRoundedClipRects(aRoundedClipRects)
     {}
 
     void AddRef() const { ++mLayerCount; }
     void Release() const
     {
       NS_ASSERTION(mLayerCount > 0, "Inconsistent layer count");
       --mLayerCount;
@@ -127,25 +128,27 @@ public:
 
     PLDHashNumber Hash() const
     {
       PLDHashNumber hash = 0;
 
       for (PRUint32 i = 0; i < mRoundedClipRects.Length(); ++i) {
         hash = AddToHash(hash, mRoundedClipRects[i].Hash());
       }
+      hash = AddToHash(hash, mBackend);
 
       return hash;
     }
 
     bool operator==(const MaskLayerImageKey& aOther) const
     {
       return mRoundedClipRects == aOther.mRoundedClipRects;
     }
 
+    layers::LayersBackend mBackend;
     mutable PRUint32 mLayerCount;
     nsTArray<PixelRoundedRect> mRoundedClipRects;
   };
 
   
   // Find an image container for aKey, returns nullptr if there is no suitable
   // cached image. If there is an image, then aKey is set to point at the stored
   // key for the image.
--- a/layout/base/nsCSSFrameConstructor.cpp
+++ b/layout/base/nsCSSFrameConstructor.cpp
@@ -7971,16 +7971,41 @@ nsCSSFrameConstructor::CharacterDataChan
     }
   }
 
   return rv;
 }
 
 NS_DECLARE_FRAME_PROPERTY(ChangeListProperty, nullptr)
 
+/**
+ * Return true if aFrame's subtree has placeholders for abs-pos or fixed-pos
+ * content.
+ */
+static bool
+FrameHasAbsPosPlaceholderDescendants(nsIFrame* aFrame)
+{
+  const nsIFrame::ChildListIDs skip(nsIFrame::kAbsoluteList |
+                                    nsIFrame::kFixedList);
+  for (nsIFrame::ChildListIterator lists(aFrame); !lists.IsDone(); lists.Next()) {
+    if (!skip.Contains(lists.CurrentID())) {
+      for (nsFrameList::Enumerator childFrames(lists.CurrentList());
+           !childFrames.AtEnd(); childFrames.Next()) {
+        nsIFrame* f = childFrames.get();
+        if ((f->GetType() == nsGkAtoms::placeholderFrame &&
+             nsPlaceholderFrame::GetRealFrameForPlaceholder(f)->IsAbsolutelyPositioned()) ||
+            FrameHasAbsPosPlaceholderDescendants(f)) {
+          return true;
+        }
+      }
+    }
+  }
+  return false;
+}
+
 nsresult
 nsCSSFrameConstructor::ProcessRestyledFrames(nsStyleChangeList& aChangeList)
 {
   NS_ASSERTION(!nsContentUtils::IsSafeToRunScript(),
                "Someone forgot a script blocker");
   PRInt32 count = aChangeList.Count();
   if (!count)
     return NS_OK;
@@ -8031,16 +8056,30 @@ nsCSSFrameConstructor::ProcessRestyledFr
     }
 
     // skip any frame that has been destroyed due to a ripple effect
     if (frame) {
       if (!propTable->Get(frame, ChangeListProperty()))
         continue;
     }
 
+    if ((hint & nsChangeHint_AddOrRemoveTransform) && frame &&
+        !(hint & nsChangeHint_ReconstructFrame)) {
+      if (FrameHasAbsPosPlaceholderDescendants(frame)) {
+        NS_UpdateHint(hint, nsChangeHint_ReconstructFrame);
+      } else {
+        // We can just add this state bit unconditionally, since it's
+        // conservative. Normally frame construction would set this if needed,
+        // but we're not going to reconstruct the frame so we need to set it.
+        // It's because we need to set this bit on each affected frame
+        // that we can't coalesce nsChangeHint_AddOrRemoveTransform hints up
+        // to ancestors (i.e. it can't be an inherited change hint).
+        frame->AddStateBits(NS_FRAME_MAY_BE_TRANSFORMED);
+      }
+    }
     if (hint & nsChangeHint_ReconstructFrame) {
       // If we ever start passing true here, be careful of restyles
       // that involve a reframe and animations.  In particular, if the
       // restyle we're processing here is an animation restyle, but
       // the style resolution we will do for the frame construction
       // happens async when we're not in an animation restyle already,
       // problems could arise.
       RecreateFramesForContent(content, false);
--- a/layout/base/nsChangeHint.h
+++ b/layout/base/nsChangeHint.h
@@ -97,31 +97,40 @@ enum nsChangeHint {
    *
    * Note that this should probably be used in combination with
    * nsChangeHint_UpdateOverflow in order to get the overflow areas of
    * the ancestors updated as well.
    */
   nsChangeHint_RecomputePosition = 0x2000,
 
   /**
+   * Behaves like ReconstructFrame, but only if the frame has descendants
+   * that are absolutely or fixed position. Use this hint when a style change
+   * has changed whether the frame is a container for fixed-pos or abs-pos
+   * elements, but reframing is otherwise not needed.
+   */
+  nsChangeHint_AddOrRemoveTransform = 0x4000,
+
+  /**
    * We have an optimization when processing change hints which prevents
    * us from visiting the descendants of a node when a hint on that node
    * is being processed.  This optimization does not apply in some of the
    * cases where applying a hint to an element does not necessarily result
    * in the same hint being handled on the descendants.
    *
    * If you're adding such a hint, you should add your hint to this list.
    */
   nsChangeHint_NonInherited_Hints =
     nsChangeHint_UpdateTransformLayer |
     nsChangeHint_UpdateEffects |
     nsChangeHint_UpdateOpacityLayer |
     nsChangeHint_UpdateOverflow |
     nsChangeHint_ChildrenOnlyTransform |
-    nsChangeHint_RecomputePosition
+    nsChangeHint_RecomputePosition |
+    nsChangeHint_AddOrRemoveTransform
 };
 
 // Redefine these operators to return nothing. This will catch any use
 // of these operators on hints. We should not be using these operators
 // on nsChangeHints
 inline void operator<(nsChangeHint s1, nsChangeHint s2) {}
 inline void operator>(nsChangeHint s1, nsChangeHint s2) {}
 inline void operator!=(nsChangeHint s1, nsChangeHint s2) {}
--- a/layout/base/nsDisplayList.cpp
+++ b/layout/base/nsDisplayList.cpp
@@ -1032,17 +1032,17 @@ void nsDisplayList::PaintForFrame(nsDisp
     NS_WARNING("We don't support transparent content with displayports, force it to be opqaue");
     root->SetContentFlags(Layer::CONTENT_OPAQUE);
   }
 
   layerManager->SetRoot(root);
   layerBuilder->WillEndTransaction(layerManager);
   bool temp = aBuilder->SetIsCompositingCheap(layerManager->IsCompositingCheap());
   layerManager->EndTransaction(FrameLayerBuilder::DrawThebesLayer,
-                               aBuilder);
+                               aBuilder, (aFlags & PAINT_NO_COMPOSITE) ? LayerManager::END_NO_COMPOSITE : LayerManager::END_DEFAULT);
   aBuilder->SetIsCompositingCheap(temp);
   layerBuilder->DidEndTransaction(layerManager);
 
   if (aFlags & PAINT_FLUSH_LAYERS) {
     FrameLayerBuilder::InvalidateAllLayers(layerManager);
   }
 
   nsCSSRendering::DidPaint();
--- a/layout/base/nsDisplayList.h
+++ b/layout/base/nsDisplayList.h
@@ -19,16 +19,17 @@
 #include "nsRect.h"
 #include "nsISelection.h"
 #include "nsCaret.h"
 #include "plarena.h"
 #include "nsRegion.h"
 #include "FrameLayerBuilder.h"
 #include "nsThemeConstants.h"
 #include "ImageLayers.h"
+#include "nsLayoutUtils.h"
 
 #include "mozilla/StandardInteger.h"
 
 #include <stdlib.h>
 
 class nsIPresShell;
 class nsIContent;
 class nsRenderingContext;
@@ -1172,17 +1173,18 @@ public:
    * 
    * This must only be called on the root display list of the display list
    * tree.
    */
   enum {
     PAINT_DEFAULT = 0,
     PAINT_USE_WIDGET_LAYERS = 0x01,
     PAINT_FLUSH_LAYERS = 0x02,
-    PAINT_EXISTING_TRANSACTION = 0x04
+    PAINT_EXISTING_TRANSACTION = 0x04,
+    PAINT_NO_COMPOSITE = 0x08
   };
   void PaintRoot(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx,
                  PRUint32 aFlags) const;
   /**
    * Like PaintRoot, but used for internal display sublists.
    * aForFrame is the frame that the list is associated with.
    */
   void PaintForFrame(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx,
--- a/layout/base/nsIPresShell.h
+++ b/layout/base/nsIPresShell.h
@@ -1212,19 +1212,23 @@ public:
 
   /**
    * Dispatch a mouse move event based on the most recent mouse position if
    * this PresShell is visible. This is used when the contents of the page
    * moved (aFromScroll is false) or scrolled (aFromScroll is true).
    */
   virtual void SynthesizeMouseMove(bool aFromScroll) = 0;
 
-  virtual void Paint(nsIView* aViewToPaint, nsIWidget* aWidget,
-                     const nsRegion& aDirtyRegion, const nsIntRegion& aIntDirtyRegion,
-                     bool aWillSendDidPaint) = 0;
+  enum PaintType {
+    PaintType_Composite, /* Just composite the layers, don't do ThebesLayer painting. */
+    PaintType_NoComposite, /* Only paint ThebesLayers, don't composite. */
+    PaintType_Full /* Do a full transaction. */
+  };
+  virtual void Paint(nsIView* aViewToPaint, const nsRegion& aDirtyRegion,
+                     PaintType aType, bool aWillSendDidPaint) = 0;
   virtual nsresult HandleEvent(nsIFrame*       aFrame,
                                nsGUIEvent*     aEvent,
                                bool            aDontRetargetEvents,
                                nsEventStatus*  aEventStatus) = 0;
   virtual bool ShouldIgnoreInvalidation() = 0;
   /**
    * Notify that the NS_WILL_PAINT event was received. Fires on every
    * visible presshell in the document tree.
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -1856,16 +1856,19 @@ nsLayoutUtils::PaintFrame(nsRenderingCon
         // pres shell, notify the widget about any toolbars we've encountered.
         widget->UpdateThemeGeometries(builder.GetThemeGeometries());
       }
     }
   }
   if (aFlags & PAINT_EXISTING_TRANSACTION) {
     flags |= nsDisplayList::PAINT_EXISTING_TRANSACTION;
   }
+  if (aFlags & PAINT_NO_COMPOSITE) {
+    flags |= nsDisplayList::PAINT_NO_COMPOSITE;
+  }
 
   list.PaintRoot(&builder, aRenderingContext, flags);
 
   // Update the widget's opaque region information. This sets
   // glass boundaries on Windows.
   if ((aFlags & PAINT_WIDGET_LAYERS) &&
       !willFlushRetainedLayers &&
       !(aFlags & PAINT_DOCUMENT_RELATIVE)) {
--- a/layout/base/nsLayoutUtils.h
+++ b/layout/base/nsLayoutUtils.h
@@ -593,17 +593,18 @@ public:
     PAINT_IN_TRANSFORM = 0x01,
     PAINT_SYNC_DECODE_IMAGES = 0x02,
     PAINT_WIDGET_LAYERS = 0x04,
     PAINT_IGNORE_SUPPRESSION = 0x08,
     PAINT_DOCUMENT_RELATIVE = 0x10,
     PAINT_HIDE_CARET = 0x20,
     PAINT_ALL_CONTINUATIONS = 0x40,
     PAINT_TO_WINDOW = 0x80,
-    PAINT_EXISTING_TRANSACTION = 0x100
+    PAINT_EXISTING_TRANSACTION = 0x100,
+    PAINT_NO_COMPOSITE = 0x200
   };
 
   /**
    * Given aFrame, the root frame of a stacking context, paint it and its
    * descendants to aRenderingContext.
    * @param aRenderingContext a rendering context translated so that (0,0)
    * is the origin of aFrame; for best results, (0,0) should transform
    * to pixel-aligned coordinates. This can be null, in which case
--- a/layout/base/nsPresShell.cpp
+++ b/layout/base/nsPresShell.cpp
@@ -5244,108 +5244,127 @@ public:
   }
 
 private:
   bool mWillSendDidPaint;
 };
 
 void
 PresShell::Paint(nsIView*           aViewToPaint,
-                 nsIWidget*         aWidgetToPaint,
                  const nsRegion&    aDirtyRegion,
-                 const nsIntRegion& aIntDirtyRegion,
+                 PaintType          aType,
                  bool               aWillSendDidPaint)
 {
 #ifdef NS_FUNCTION_TIMER
   NS_TIME_FUNCTION_DECLARE_DOCURL;
   const nsRect& bounds__ = aDirtyRegion.GetBounds();
   NS_TIME_FUNCTION_MIN_FMT(1.0, "%s (line %d) (document: %s, dirty rect: (<%f, %f>, <%f, %f>)",
                            MOZ_FUNCTION_NAME, __LINE__, docURL__.get(),
                            NSCoordToFloat(bounds__.x),
                            NSCoordToFloat(bounds__.y),
                            NSCoordToFloat(bounds__.XMost()),
                            NSCoordToFloat(bounds__.YMost()));
 #endif
 
   SAMPLE_LABEL("Paint", "PresShell::Paint");
   NS_ASSERTION(!mIsDestroying, "painting a destroyed PresShell");
   NS_ASSERTION(aViewToPaint, "null view");
-  NS_ASSERTION(aWidgetToPaint, "Can't paint without a widget");
 
   nsAutoNotifyDidPaint notifyDidPaint(aWillSendDidPaint);
 
   nsPresContext* presContext = GetPresContext();
   AUTO_LAYOUT_PHASE_ENTRY_POINT(presContext, Paint);
 
   nsIFrame* frame = aViewToPaint->GetFrame();
 
   bool isRetainingManager;
   LayerManager* layerManager =
-    aWidgetToPaint->GetLayerManager(&isRetainingManager);
+    aViewToPaint->GetWidget()->GetLayerManager(&isRetainingManager);
   NS_ASSERTION(layerManager, "Must be in paint event");
 
   if (mIsFirstPaint) {
     layerManager->SetIsFirstPaint();
     mIsFirstPaint = false;
   }
-  layerManager->BeginTransaction();
 
   if (frame && isRetainingManager) {
     // Try to do an empty transaction, if the frame tree does not
     // need to be updated. Do not try to do an empty transaction on
     // a non-retained layer manager (like the BasicLayerManager that
     // draws the window title bar on Mac), because a) it won't work
     // and b) below we don't want to clear NS_FRAME_UPDATE_LAYER_TREE,
     // that will cause us to forget to update the real layer manager!
-    if (!(frame->GetStateBits() & NS_FRAME_UPDATE_LAYER_TREE)) {
+    if (aType == PaintType_Composite) {
+      if (layerManager->HasShadowManager()) {
+        return;
+      }
+      layerManager->BeginTransaction();
       if (layerManager->EndEmptyTransaction()) {
+        return;
+      }
+      NS_WARNING("Must complete empty transaction when compositing!");
+    } else  if (!(frame->GetStateBits() & NS_FRAME_UPDATE_LAYER_TREE)) {
+      layerManager->BeginTransaction();
+      if (layerManager->EndEmptyTransaction(LayerManager::END_NO_COMPOSITE)) {
         frame->UpdatePaintCountForPaintedPresShells();
         presContext->NotifyDidPaintForSubtree();
         return;
       }
+    } else {
+      layerManager->BeginTransaction();
     }
 
     frame->RemoveStateBits(NS_FRAME_UPDATE_LAYER_TREE);
+  } else {
+    layerManager->BeginTransaction();
   }
   if (frame) {
     frame->ClearPresShellsFromLastPaint();
   }
 
   nscolor bgcolor = ComputeBackstopColor(aViewToPaint);
+  PRUint32 flags = nsLayoutUtils::PAINT_WIDGET_LAYERS | nsLayoutUtils::PAINT_EXISTING_TRANSACTION;
+  if (aType == PaintType_NoComposite) {
+    flags |= nsLayoutUtils::PAINT_NO_COMPOSITE;
+  }
 
   if (frame) {
     // Defer invalidates that are triggered during painting, and discard
     // invalidates of areas that are already being repainted.
     // The layer system can trigger invalidates during painting
     // (see FrameLayerBuilder).
     frame->BeginDeferringInvalidatesForDisplayRoot(aDirtyRegion);
 
     // We can paint directly into the widget using its layer manager.
-    nsLayoutUtils::PaintFrame(nullptr, frame, aDirtyRegion, bgcolor,
-                              nsLayoutUtils::PAINT_WIDGET_LAYERS |
-                              nsLayoutUtils::PAINT_EXISTING_TRANSACTION);
+    nsLayoutUtils::PaintFrame(nullptr, frame, aDirtyRegion, bgcolor, flags);
 
     frame->EndDeferringInvalidatesForDisplayRoot();
-    presContext->NotifyDidPaintForSubtree();
+    if (aType != PaintType_Composite) {
+      presContext->NotifyDidPaintForSubtree();
+    }
     return;
   }
 
   nsRefPtr<ColorLayer> root = layerManager->CreateColorLayer();
   if (root) {
     nsPresContext* pc = GetPresContext();
     nsIntRect bounds =
       pc->GetVisibleArea().ToOutsidePixels(pc->AppUnitsPerDevPixel());
     bgcolor = NS_ComposeColors(bgcolor, mCanvasBackgroundColor);
     root->SetColor(bgcolor);
     root->SetVisibleRegion(bounds);
     layerManager->SetRoot(root);
   }
-  layerManager->EndTransaction(NULL, NULL);
-
-  presContext->NotifyDidPaintForSubtree();
+  layerManager->EndTransaction(NULL, NULL, aType == PaintType_NoComposite ?
+                                             LayerManager::END_NO_COMPOSITE :
+                                             LayerManager::END_DEFAULT);
+
+  if (aType != PaintType_Composite) {
+    presContext->NotifyDidPaintForSubtree();
+  }
 }
 
 // static
 void
 nsIPresShell::SetCapturingContent(nsIContent* aContent, PRUint8 aFlags)
 {
   // If capture was set for pointer lock, don't unlock unless we are coming
   // out of pointer lock explicitly.
--- a/layout/base/nsPresShell.h
+++ b/layout/base/nsPresShell.h
@@ -179,19 +179,18 @@ public:
   virtual void SetIgnoreViewportScrolling(bool aIgnore);
 
   virtual void SetDisplayPort(const nsRect& aDisplayPort);
 
   virtual nsresult SetResolution(float aXResolution, float aYResolution);
 
   //nsIViewObserver interface
 
-  virtual void Paint(nsIView* aViewToPaint, nsIWidget* aWidget,
-                     const nsRegion& aDirtyRegion, const nsIntRegion& aIntDirtyRegion,
-                     bool aWillSendDidPaint);
+  virtual void Paint(nsIView* aViewToPaint, const nsRegion& aDirtyRegion,
+                     PaintType aType, bool aWillSendDidPaint);
   virtual nsresult HandleEvent(nsIFrame*       aFrame,
                                nsGUIEvent*     aEvent,
                                bool            aDontRetargetEvents,
                                nsEventStatus*  aEventStatus);
   virtual NS_HIDDEN_(nsresult) HandleDOMEventWithTarget(nsIContent* aTargetContent,
                                                         nsEvent* aEvent,
                                                         nsEventStatus* aStatus);
   virtual NS_HIDDEN_(nsresult) HandleDOMEventWithTarget(nsIContent* aTargetContent,
--- a/layout/base/nsRefreshDriver.cpp
+++ b/layout/base/nsRefreshDriver.cpp
@@ -409,18 +409,24 @@ nsRefreshDriver::Notify(nsITimer *aTimer
 
   ImageRequestParameters parms = {mMostRecentRefresh};
   if (mRequests.Count()) {
     mRequests.EnumerateEntries(nsRefreshDriver::ImageRequestEnumerator, &parms);
     EnsureTimerStarted(false);
   }
 
   if (mViewManagerFlushIsPending) {
+#ifdef DEBUG_INVALIDATIONS
+    printf("Starting ProcessPendingUpdates\n");
+#endif
     mViewManagerFlushIsPending = false;
     mPresContext->GetPresShell()->GetViewManager()->ProcessPendingUpdates();
+#ifdef DEBUG_INVALIDATIONS
+    printf("Ending ProcessPendingUpdates\n");
+#endif
   }
 
   if (mThrottled ||
       (mTimerIsPrecise !=
        (GetRefreshTimerType() == nsITimer::TYPE_REPEATING_PRECISE_CAN_SKIP))) {
     // Stop the timer now and restart it here.  Stopping is in the mThrottled
     // case ok because either it's already one-shot, and it just fired, and all
     // we need to do is null it out, or it's repeating and we need to reset it
--- a/layout/generic/nsGfxScrollFrame.cpp
+++ b/layout/generic/nsGfxScrollFrame.cpp
@@ -1678,37 +1678,46 @@ nsGfxScrollFrameInner::AsyncScrollCallba
   // up scrolling to.
   self->mDestination = self->GetScrollPosition();
 }
 
 void
 nsGfxScrollFrameInner::ScrollToCSSPixels(nsIntPoint aScrollPosition)
 {
   nsPoint current = GetScrollPosition();
+  nsIntPoint currentCSSPixels = GetScrollPositionCSSPixels();
   nsPoint pt(nsPresContext::CSSPixelsToAppUnits(aScrollPosition.x),
              nsPresContext::CSSPixelsToAppUnits(aScrollPosition.y));
   nscoord halfPixel = nsPresContext::CSSPixelsToAppUnits(0.5f);
   nsRect range(pt.x - halfPixel, pt.y - halfPixel, 2*halfPixel - 1, 2*halfPixel - 1);
-  if (nsPresContext::AppUnitsToIntCSSPixels(current.x) == aScrollPosition.x) {
+  if (currentCSSPixels.x == aScrollPosition.x) {
     pt.x = current.x;
     range.x = pt.x;
     range.width = 0;
   } else {
     // current.x must be outside 'range', so we must move in the correct direction.
   }
-  if (nsPresContext::AppUnitsToIntCSSPixels(current.y) == aScrollPosition.y) {
+  if (currentCSSPixels.y == aScrollPosition.y) {
     pt.y = current.y;
     range.y = pt.y;
     range.height = 0;
   } else {
     // current.y must be outside 'range', so we must move in the correct direction.
   }
   ScrollTo(pt, nsIScrollableFrame::INSTANT, &range);
 }
 
+nsIntPoint
+nsGfxScrollFrameInner::GetScrollPositionCSSPixels()
+{
+  nsPoint pt = GetScrollPosition();
+  return nsIntPoint(nsPresContext::AppUnitsToIntCSSPixels(pt.x),
+                    nsPresContext::AppUnitsToIntCSSPixels(pt.y));
+}
+
 /*
  * this method wraps calls to ScrollToImpl(), either in one shot or incrementally,
  *  based on the setting of the smoothness scroll pref
  */
 void
 nsGfxScrollFrameInner::ScrollToWithOrigin(nsPoint aScrollPosition,
                                           nsIScrollableFrame::ScrollMode aMode,
                                           nsIAtom *aOrigin,
@@ -2542,25 +2551,72 @@ nsGfxScrollFrameInner::GetLineScrollAmou
   nscoord fontHeight = 1;
   if (fm) {
     fontHeight = fm->MaxHeight();
   }
 
   return nsSize(fontHeight, fontHeight);
 }
 
+/**
+ * Compute the scrollport size excluding any fixed-pos headers and
+ * footers. A header or footer is an box that spans that entire width
+ * of the viewport and touches the top (or bottom, respectively) of the
+ * viewport. Headers and footers that cover more than a quarter of the
+ * the viewport are ignored since they probably aren't true headers and
+ * footers and we don't want to restrict scrolling too much in such cases.
+ * This is a bit conservative --- some pages use elements as headers or
+ * footers that don't span the entire width of the viewport --- but it
+ * should be a good start.
+ */
+static nsSize
+GetScrollPortSizeExcludingHeadersAndFooters(nsIFrame* aViewportFrame,
+                                            const nsRect& aScrollPort)
+{
+  nsFrameList fixedFrames = aViewportFrame->GetChildList(nsIFrame::kFixedList);
+  nscoord headerBottom = 0;
+  nscoord footerTop = aScrollPort.height;
+  for (nsFrameList::Enumerator iterator(fixedFrames); !iterator.AtEnd();
+       iterator.Next()) {
+    nsIFrame* f = iterator.get();
+    nsRect r = f->GetRect().Intersect(aScrollPort);
+    if (r.x == 0 && r.width == aScrollPort.width &&
+        r.height <= aScrollPort.height/3) {
+      if (r.y == 0) {
+        headerBottom = NS_MAX(headerBottom, r.height);
+      }
+      if (r.YMost() == aScrollPort.height) {
+        footerTop = NS_MIN(footerTop, r.y);
+      }
+    }
+  }
+  return nsSize(aScrollPort.width, footerTop - headerBottom);
+}
+
 nsSize
 nsGfxScrollFrameInner::GetPageScrollAmount() const
 {
   nsSize lineScrollAmount = GetLineScrollAmount();
+  nsSize effectiveScrollPortSize;
+  if (mIsRoot) {
+    // Reduce effective scrollport height by the height of any fixed-pos
+    // headers or footers
+    nsIFrame* root = mOuter->PresContext()->PresShell()->GetRootFrame();
+    effectiveScrollPortSize =
+      GetScrollPortSizeExcludingHeadersAndFooters(root, mScrollPort);
+  } else {
+    effectiveScrollPortSize = mScrollPort.Size();
+  }
   // The page increment is the size of the page, minus the smaller of
   // 10% of the size or 2 lines.
   return nsSize(
-    mScrollPort.width - NS_MIN(mScrollPort.width/10, 2*lineScrollAmount.width),
-    mScrollPort.height - NS_MIN(mScrollPort.height/10, 2*lineScrollAmount.height));
+    effectiveScrollPortSize.width -
+      NS_MIN(effectiveScrollPortSize.width/10, 2*lineScrollAmount.width),
+    effectiveScrollPortSize.height -
+      NS_MIN(effectiveScrollPortSize.height/10, 2*lineScrollAmount.height));
 }
 
   /**
    * this code is resposible for restoring the scroll position back to some
    * saved position. if the user has not moved the scroll position manually
    * we keep scrolling down until we get to our original position. keep in
    * mind that content could incrementally be coming in. we only want to stop
    * when we reach our new position.
--- a/layout/generic/nsGfxScrollFrame.h
+++ b/layout/generic/nsGfxScrollFrame.h
@@ -161,16 +161,17 @@ public:
    * aScrollPosition. Null means only aScrollPosition is allowed.
    * This is a closed-ended range --- aRange.XMost()/aRange.YMost() are allowed.
    */
   void ScrollTo(nsPoint aScrollPosition, nsIScrollableFrame::ScrollMode aMode,
                 const nsRect* aRange = nullptr) {
     ScrollToWithOrigin(aScrollPosition, aMode, nsGkAtoms::other, aRange);
   }
   void ScrollToCSSPixels(nsIntPoint aScrollPosition);
+  nsIntPoint GetScrollPositionCSSPixels();
   void ScrollToImpl(nsPoint aScrollPosition, const nsRect& aRange);
   void ScrollVisual(nsPoint aOldScrolledFramePosition);
   void ScrollBy(nsIntPoint aDelta, nsIScrollableFrame::ScrollUnit aUnit,
                 nsIScrollableFrame::ScrollMode aMode, nsIntPoint* aOverflow, nsIAtom *aOrigin = nullptr);
   void ScrollToRestoredPosition();
   nsSize GetLineScrollAmount() const;
   nsSize GetPageScrollAmount() const;
 
@@ -475,16 +476,19 @@ public:
   }
   virtual void ScrollTo(nsPoint aScrollPosition, ScrollMode aMode,
                         const nsRect* aRange = nullptr) {
     mInner.ScrollTo(aScrollPosition, aMode, aRange);
   }
   virtual void ScrollToCSSPixels(nsIntPoint aScrollPosition) {
     mInner.ScrollToCSSPixels(aScrollPosition);
   }
+  virtual nsIntPoint GetScrollPositionCSSPixels() {
+    return mInner.GetScrollPositionCSSPixels();
+  }
   virtual void ScrollBy(nsIntPoint aDelta, ScrollUnit aUnit, ScrollMode aMode,
                         nsIntPoint* aOverflow, nsIAtom *aOrigin = nullptr) {
     mInner.ScrollBy(aDelta, aUnit, aMode, aOverflow, aOrigin);
   }
   virtual void ScrollToRestoredPosition() {
     mInner.ScrollToRestoredPosition();
   }
   virtual void AddScrollPositionListener(nsIScrollPositionListener* aListener) {
@@ -720,16 +724,19 @@ public:
   }
   virtual void ScrollTo(nsPoint aScrollPosition, ScrollMode aMode,
                         const nsRect* aRange = nullptr) {
     mInner.ScrollTo(aScrollPosition, aMode, aRange);
   }
   virtual void ScrollToCSSPixels(nsIntPoint aScrollPosition) {
     mInner.ScrollToCSSPixels(aScrollPosition);
   }
+  virtual nsIntPoint GetScrollPositionCSSPixels() {
+    return mInner.GetScrollPositionCSSPixels();
+  }
   virtual void ScrollBy(nsIntPoint aDelta, ScrollUnit aUnit, ScrollMode aMode,
                         nsIntPoint* aOverflow, nsIAtom *aOrigin = nullptr) {
     mInner.ScrollBy(aDelta, aUnit, aMode, aOverflow, aOrigin);
   }
   virtual void ScrollToRestoredPosition() {
     mInner.ScrollToRestoredPosition();
   }
   virtual void AddScrollPositionListener(nsIScrollPositionListener* aListener) {
--- a/layout/generic/nsIScrollableFrame.h
+++ b/layout/generic/nsIScrollableFrame.h
@@ -134,16 +134,21 @@ public:
    * Keeps the exact current horizontal or vertical position if the current
    * position, rounded to CSS pixels, matches aScrollPosition. If
    * aScrollPosition.x/y is different from the current CSS pixel position,
    * makes sure we only move in the direction given by the difference.
    * The scroll mode is INSTANT.
    */
   virtual void ScrollToCSSPixels(nsIntPoint aScrollPosition) = 0;
   /**
+   * Returns the scroll position in integer CSS pixels, rounded to the nearest
+   * pixel.
+   */
+  virtual nsIntPoint GetScrollPositionCSSPixels() = 0;
+  /**
    * When scrolling by a relative amount, we can choose various units.
    */
   enum ScrollUnit { DEVICE_PIXELS, LINES, PAGES, WHOLE };
   /**
    * Modifies the current scroll position by aDelta units given by aUnit,
    * clamping it to GetScrollRange. If WHOLE is specified as the unit,
    * content is scrolled all the way in the direction(s) given by aDelta.
    * @param aOverflow if non-null, returns the amount that scrolling
--- a/layout/generic/test/Makefile.in
+++ b/layout/generic/test/Makefile.in
@@ -60,16 +60,18 @@ MOCHITEST_FILES = \
   test_bug579767.html \
   test_bug597333.html \
   test_bug666225.html \
   test_image_selection.html \
   test_image_selection_2.html \
   test_invalidate_during_plugin_paint.html \
   test_movement_by_characters.html \
   test_movement_by_words.html \
+  test_page_scroll_with_fixed_pos.html \
+    page_scroll_with_fixed_pos_window.html \
   test_plugin_clipping.xhtml \
   test_plugin_clipping2.xhtml \
   test_plugin_clipping_transformed.xhtml \
   test_plugin_clipping_table.xhtml \
   test_plugin_focus.html \
   test_plugin_mouse_coords.html \
   test_plugin_position.xhtml \
   test_selection_expanding.html \
new file mode 100644
--- /dev/null
+++ b/layout/generic/test/page_scroll_with_fixed_pos_window.html
@@ -0,0 +1,81 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Scrolling by pages with fixed-pos headers and footers</title>
+  <style>
+  .fp { position:fixed; left:0; width:100%; }
+  </style>
+</head>
+<body onscroll="didScroll()" onload="test()">
+<div class="fp" id="top" style="top:0; height:10px; background:yellow;"></div>
+<div class="fp" style="top:50%; height:7px; background:cyan;"></div>
+<div class="fp" id="bottom" style="bottom:0; height:13px; background:yellow;"></div>
+<p id="target">Something to click on to get focus
+<div style="height:3000px;"></div>
+<pre id="test">
+<script class="testbody">
+var SimpleTest = window.opener.SimpleTest;
+var SpecialPowers = window.opener.SpecialPowers;
+var is = window.opener.is;
+
+function showFixedPosElements(show) {
+  var elements = document.getElementsByClassName("fp");
+  for (var i = 0; i < elements.length; ++i) {
+    elements[i].style.display = show ? '' : 'none';
+  }
+}
+
+var nextCont;
+function didScroll() {
+  var c = nextCont;
+  nextCont = null;
+  if (c) {
+    c();
+  }
+}
+
+function scrollDownOnePageWithContinuation(cont) {
+  document.documentElement.scrollTop = 0;
+  nextCont = cont;
+  window.scrollByPages(1);
+}
+
+function test() {
+  var smoothScrollPref = "general.smoothScroll";
+  SpecialPowers.setBoolPref(smoothScrollPref, false);
+
+  showFixedPosElements(false);
+  scrollDownOnePageWithContinuation(function() {
+    var fullPageScrollDown = document.documentElement.scrollTop;
+
+    showFixedPosElements(true);
+    scrollDownOnePageWithContinuation(function() {
+      var fullPageScrollDownWithHeaderAndFooter = document.documentElement.scrollTop;
+      is(fullPageScrollDownWithHeaderAndFooter, fullPageScrollDown - (10 + 13),
+         "Reduce scroll distance by size of small header and footer");
+
+      document.getElementById("bottom").style.height = (window.innerHeight - 20) + "px";
+      scrollDownOnePageWithContinuation(function() {
+        is(document.documentElement.scrollTop, fullPageScrollDown - 10,
+           "Ignore really big elements when reducing scroll size");   
+        document.getElementById("bottom").style.height = "13px";
+
+        document.getElementById("top").style.width = "100px";
+        scrollDownOnePageWithContinuation(function() {
+          is(document.documentElement.scrollTop, fullPageScrollDown - 13,
+             "Ignore elements that don't span the entire viewport side");
+        
+          // Scroll back up so test results are visible
+          document.documentElement.scrollTop = 0;
+          SpecialPowers.clearUserPref(smoothScrollPref);
+          SimpleTest.finish();
+          window.close();
+        });
+      });
+    });
+  });
+}
+</script>
+</pre>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/generic/test/test_page_scroll_with_fixed_pos.html
@@ -0,0 +1,16 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Scrolling by pages with fixed-pos headers and footers</title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<p id="display"></p>
+<script class="testbody">
+SimpleTest.waitForExplicitFinish();
+window.open("./page_scroll_with_fixed_pos_window.html", "", "width=600,height=600");
+</script>
+</pre>
+</body>
+</html>
--- a/layout/reftests/svg/smil/container/deferred-anim-1.xhtml
+++ b/layout/reftests/svg/smil/container/deferred-anim-1.xhtml
@@ -46,16 +46,17 @@
           document.documentElement.removeAttribute('class');
         }
 
         function addAnimation()
         {
           const svgns="http://www.w3.org/2000/svg";
           var anim = document.createElementNS(svgns,'animate');
           anim.setAttribute('attributeName','fill');
+          anim.setAttribute('from', 'red');
           anim.setAttribute('to','green');
           anim.setAttribute('begin','0s');
           anim.setAttribute('dur','0.001s');
           anim.setAttribute('fill','freeze');
           var target = document.getElementById('target');
           target.appendChild(anim);
         }
     </script>
--- a/layout/reftests/svg/smil/container/deferred-tree-1.xhtml
+++ b/layout/reftests/svg/smil/container/deferred-tree-1.xhtml
@@ -64,16 +64,17 @@
           var rect = document.createElementNS(svgns, 'rect');
           rect.setAttribute('x', '0');
           rect.setAttribute('y', '0');
           rect.setAttribute('width', '199');
           rect.setAttribute('height', '199');
           var anim = document.createElementNS(svgns, 'animate');
           anim.setAttribute('attributeName', 'fill');
           anim.setAttribute('begin', '0s');
+          anim.setAttribute('from', 'red');
           anim.setAttribute('to', 'green');
           anim.setAttribute('dur', '0.001s');
           anim.setAttribute('fill', 'freeze');
           rect.appendChild(anim);
           svg.appendChild(rect);
           var target = document.getElementById('tree-container');
           target.appendChild(svg);
         }
--- a/layout/reftests/svg/smil/motion/animateMotion-by-1.svg
+++ b/layout/reftests/svg/smil/motion/animateMotion-by-1.svg
@@ -1,41 +1,41 @@
 <svg xmlns="http://www.w3.org/2000/svg"
      xmlns:xlink="http://www.w3.org/1999/xlink"
      class="reftest-wait">
   <script xlink:href="../smil-util.js" type="text/javascript"/>
   <script type="text/javascript">
     function doTest() {
-      setTimeAndSnapshot(1, true);
+      setTimeAndSnapshot(101, true);
     }
     window.addEventListener("MozReftestInvalidate", doTest, false);
   </script>
 
   <!-- Big green background to match lime.svg -->
   <rect width="100%" height="100%" fill="lime"/>
   <!-- Red "workspace" (should be covered up, if tests pass) -->
   <rect x="100" y="100" width="100" height="100" fill="red"/>
 
   <!-- FIRST ROW -->
   <!-- Check that 'by' works at all -->
   <rect fill="lime" x="0" y="0" width="50" height="50">
-    <animateMotion by="100, 100" begin="0" dur="1" fill="freeze"/>
+    <animateMotion by="100, 100" begin="100" dur="1" fill="freeze"/>
   </rect>
 
   <!-- Check that 'by' is additive w/ 'by' -->
   <rect fill="lime" x="50" y="50" width="50" height="50">
-    <animateMotion by="60, 75" begin="0" dur="1" fill="freeze"/>
-    <animateMotion by="40, -25" begin="0" dur="1" fill="freeze"/>
+    <animateMotion by="60, 75" begin="100" dur="1" fill="freeze"/>
+    <animateMotion by="40, -25" begin="100" dur="1" fill="freeze"/>
   </rect>
 
   <!-- SECOND ROW -->
   <!-- Check that 'by' is additive w/ 'to' -->
   <rect fill="lime" width="50" height="50">
-    <animateMotion to="50,100" begin="0" dur="1" fill="freeze"/>
-    <animateMotion by="50, 50" begin="0" dur="1" fill="freeze"/>
+    <animateMotion to="50,100" begin="100" dur="1" fill="freeze"/>
+    <animateMotion by="50, 50" begin="100" dur="1" fill="freeze"/>
   </rect>
 
   <!-- Check that 'from-to' replaces 'by' -->
   <rect fill="lime" width="50" height="50">
-    <animateMotion by="500, 500" begin="0" dur="1" fill="freeze"/>
-    <animateMotion from="300,300" to="150,150" begin="0" dur="1" fill="freeze"/>
+    <animateMotion by="500, 500" begin="100" dur="1" fill="freeze"/>
+    <animateMotion from="300,300" to="150,150" begin="100" dur="1" fill="freeze"/>
   </rect>
 </svg>
--- a/layout/reftests/svg/smil/motion/animateMotion-from-to-1.svg
+++ b/layout/reftests/svg/smil/motion/animateMotion-from-to-1.svg
@@ -1,44 +1,44 @@
 <svg xmlns="http://www.w3.org/2000/svg"
      xmlns:xlink="http://www.w3.org/1999/xlink"
      class="reftest-wait">
   <script xlink:href="../smil-util.js" type="text/javascript"/>
   <script type="text/javascript">
     function doTest() {
-      setTimeAndSnapshot(1, true);
+      setTimeAndSnapshot(101, true);
     }
     window.addEventListener("MozReftestInvalidate", doTest, false);
   </script>
 
   <!-- Big green background to match lime.svg -->
   <rect width="100%" height="100%" fill="lime"/>
   <!-- Red "workspace" (should be covered up, if tests pass) -->
   <rect x="100" y="100" width="100" height="100" fill="red"/>
 
   <!-- FIRST ROW -->
   <!-- Check that 'from' gets applied at begin time -->
   <rect fill="lime" x="0" y="0" width="50" height="50">
-    <animateMotion from="100, 100" to="500, 500" begin="1" dur="1"/>
+    <animateMotion from="100, 100" to="500, 500" begin="101" dur="1"/>
   </rect>
 
   <!-- Check that 'to' gets hit at end time -->
   <rect fill="lime" x="0" y="0" width="50" height="50">
-    <animateMotion from="200,200" to="150,100" begin="0" dur="1" fill="freeze"/>
+    <animateMotion from="200,200" to="150,100" begin="100" dur="1" fill="freeze"/>
   </rect>
 
   <!-- SECOND ROW -->
   <!-- Check that animation effects are removed after end time
        (note that fill="remove" is default; just specifying it for clarity -->
   <rect fill="lime" x="100" y="150" width="50" height="50">
-    <animateMotion from="500,500" to="600,600" begin="0" dur="1" fill="remove"/>
+    <animateMotion from="500,500" to="600,600" begin="1000" dur="1" fill="remove"/>
   </rect>
   <rect fill="purple" x="-25" y="-25" width="25" height="25">
     <!-- With the purple rect's x/y offsets, this animateMotion path moves us
          around the 2nd row, 1st col -->
-    <animateMotion from="125,175" to="150,175" begin="0" dur="1" fill="remove"/>
+    <animateMotion from="125,175" to="150,175" begin="100" dur="1" fill="remove"/>
   </rect>
 
   <!-- Check interpolation halfway through animation -->
   <rect fill="lime" width="50" height="50">
-    <animateMotion from="200,100" to="100,200" begin="0.5" dur="1"/>
+    <animateMotion from="200,100" to="100,200" begin="100.5" dur="1"/>
   </rect>
 </svg>
--- a/layout/reftests/svg/smil/motion/animateMotion-rotate-1a.svg
+++ b/layout/reftests/svg/smil/motion/animateMotion-rotate-1a.svg
@@ -6,58 +6,58 @@
     .workspace  { fill: red  }
     .test       { fill: lime }
     .filler     { fill: lime }
   </style>
 
   <script xlink:href="../smil-util.js" type="text/javascript"/>
   <script type="text/javascript">
     function doTest() {
-      setTimeAndSnapshot(1, true);
+      setTimeAndSnapshot(101, true);
     }
     window.addEventListener("MozReftestInvalidate", doTest, false);
   </script>
 
   <!-- Big green background to match lime.svg -->
   <rect class="background" width="100%" height="100%" />
   <!-- Red "workspace" (should be covered up, if tests pass) -->
   <rect class="workspace" x="100" y="100" width="100" height="100"/>
 
   <!-- FIRST ROW -->
   <!-- Check that 'rotate' gets applied at begin time -->
   <g>
     <animateMotion from="150, 100" to="500, 500" rotate="90"
-                   begin="1" dur="1"/>
+                   begin="101" dur="1"/>
     <rect class="test" x="0" y="0" width="20" height="50"/>
     <rect class="test" x="0" y="0" width="50" height="20"/>
   </g>
   <rect class="filler" x="100" y="120" width="30" height="30"/>
 
   <!-- Check that 'rotate' gets applied at end time -->
   <g>
-    <animateMotion from="600, 700" to="200, 150" rotate="180" begin="0"
+    <animateMotion from="600, 700" to="200, 150" rotate="180" begin="100"
                    dur="1" fill="freeze"/>
     <rect class="test" x="0" y="0" width="20" height="50"/>
     <rect class="test" x="0" y="0" width="50" height="20"/>
   </g>
   <rect class="filler" x="150" y="100" width="30" height="30"/>
 
   <!-- SECOND ROW -->
   <!-- Check that rotate combines with existing rotate -->
   <g transform="rotate(90)">
     <animateMotion from="150,200" to="600,600" rotate="90"
-                   begin="1" dur="1"/>
+                   begin="101" dur="1"/>
     <rect class="test" x="0" y="0" width="20" height="50"/>
     <rect class="test" x="0" y="0" width="50" height="20"/>
   </g>
   <rect class="filler" x="100" y="150" width="30" height="30"/>
 
   <!-- Check additivity of <animateMotion> "rotate" adds -->
   <g>
     <animateMotion from="100,100" to="100,200" rotate="90"
-                   begin="0.5" dur="1"/>
+                   begin="100.5" dur="1"/>
     <animateMotion by="100,-200" rotate="90"
-                   begin="0.5" dur="1"/>
+                   begin="100.5" dur="1"/>
     <rect class="test" x="0" y="0" width="20" height="50"/>
     <rect class="test" x="0" y="0" width="50" height="20"/>
   </g>
   <rect class="filler" x="150" y="150" width="30" height="30"/>
 </svg>
--- a/layout/reftests/svg/smil/motion/animateMotion-rotate-1b.svg
+++ b/layout/reftests/svg/smil/motion/animateMotion-rotate-1b.svg
@@ -6,58 +6,58 @@
     .workspace  { fill: red  }
     .test       { fill: lime }
     .filler     { fill: lime }
   </style>
 
   <script xlink:href="../smil-util.js" type="text/javascript"/>
   <script type="text/javascript">
     function doTest() {
-      setTimeAndSnapshot(1, true);
+      setTimeAndSnapshot(101, true);
     }
     window.addEventListener("MozReftestInvalidate", doTest, false);
   </script>
 
   <!-- Big green background to match lime.svg -->
   <rect class="background" width="100%" height="100%" />
   <!-- Red "workspace" (should be covered up, if tests pass) -->
   <rect class="workspace" x="100" y="100" width="100" height="100"/>
 
   <!-- FIRST ROW -->
   <!-- Check that 'rotate' gets applied at begin time -->
   <g>
     <animateMotion from="150, 100" to="500, 500" rotate="100grad"
-                   begin="1" dur="1"/>
+                   begin="101" dur="1"/>
     <rect class="test" x="0" y="0" width="20" height="50"/>
     <rect class="test" x="0" y="0" width="50" height="20"/>
   </g>
   <rect class="filler" x="100" y="120" width="30" height="30"/>
 
   <!-- Check that 'rotate' gets applied at end time -->
   <g>
-    <animateMotion from="600, 700" to="200, 150" rotate="200grad" begin="0"
+    <animateMotion from="600, 700" to="200, 150" rotate="200grad" begin="100"
                    dur="1" fill="freeze"/>
     <rect class="test" x="0" y="0" width="20" height="50"/>
     <rect class="test" x="0" y="0" width="50" height="20"/>
   </g>
   <rect class="filler" x="150" y="100" width="30" height="30"/>
 
   <!-- SECOND ROW -->
   <!-- Check that rotate combines with existing rotate -->
   <g transform="rotate(90)">
     <animateMotion from="150,200" to="600,600" rotate="100grad"
-                   begin="1" dur="1"/>
+                   begin="101" dur="1"/>
     <rect class="test" x="0" y="0" width="20" height="50"/>
     <rect class="test" x="0" y="0" width="50" height="20"/>
   </g>
   <rect class="filler" x="100" y="150" width="30" height="30"/>
 
   <!-- Check additivity of <animateMotion> "rotate" adds -->
   <g>
     <animateMotion from="100,100" to="100,200" rotate="100grad"
-                   begin="0.5" dur="1"/>
+                   begin="100.5" dur="1"/>
     <animateMotion by="100,-200" rotate="100grad"
-                   begin="0.5" dur="1"/>
+                   begin="100.5" dur="1"/>
     <rect class="test" x="0" y="0" width="20" height="50"/>
     <rect class="test" x="0" y="0" width="50" height="20"/>
   </g>
   <rect class="filler" x="150" y="150" width="30" height="30"/>
 </svg>
--- a/layout/reftests/svg/smil/motion/animateMotion-rotate-2.svg
+++ b/layout/reftests/svg/smil/motion/animateMotion-rotate-2.svg
@@ -20,33 +20,33 @@
          maximum distance from a path that antialiasing of square pixels can
          cause the path to affect. -->
     <path id="marker" d="m0,0 l-10,-30  c-5,-20 25,-20 20,0 z"
           style="fill: currentColor; stroke: lime; stroke-width: 2.83px"/>
   </defs>
   <script xlink:href="../smil-util.js" type="text/javascript"/>
   <script type="text/javascript">
     function doTest() {
-      setTimeAndSnapshot(1, true);
+      setTimeAndSnapshot(101, true);
     }
     window.addEventListener("MozReftestInvalidate", doTest, false);
   </script>
 
   <!-- Big green background to match lime.svg -->
   <rect class="background" width="100%" height="100%" />
   <g transform="translate(50,50)">
     <!-- Here's the hole -->
     <use xlink:href="#marker" class="hole"
          transform="translate(20,20) rotate(45)"/>
 
     <!-- And here's a stack of elements animated with 'animateMotion' that
          should end up there. -->
     <use xlink:href="#marker" class="testBegin">
-      <animateMotion from="20,20" to="40,40" rotate="auto" begin="1s" dur="1s"/>
+      <animateMotion from="20,20" to="40,40" rotate="auto" begin="101s" dur="1s"/>
     </use>
     <use xlink:href="#marker" class="testEnd">
-      <animateMotion by="20,20" rotate="auto" dur="1s" fill="freeze"/>
+      <animateMotion by="20,20" rotate="auto" begin="100" dur="1s" fill="freeze"/>
     </use>
     <use xlink:href="#marker" class="mask">
-      <animateMotion by="40,40" rotate="auto" dur="2s"/>
+      <animateMotion by="40,40" rotate="auto" begin="100s" dur="2s"/>
     </use>
   </g>
 </svg>
--- a/layout/reftests/svg/smil/motion/animateMotion-to-overridden-1.svg
+++ b/layout/reftests/svg/smil/motion/animateMotion-to-overridden-1.svg
@@ -1,61 +1,61 @@
 <svg xmlns="http://www.w3.org/2000/svg"
      xmlns:xlink="http://www.w3.org/1999/xlink"
      class="reftest-wait">
   <script xlink:href="../smil-util.js" type="text/javascript"/>
   <script type="text/javascript">
     function doTest() {
-      setTimeAndSnapshot(1, true);
+      setTimeAndSnapshot(101, true);
     }
     window.addEventListener("MozReftestInvalidate", doTest, false);
   </script>
 
   <!-- Big green background to match lime.svg -->
   <rect fill="lime" width="100%" height="100%" />
 
   <!-- In the following pairs of rects, the only pairwise differences are the
        fill-color and the presence of the "to" attribute on the animateMotion
        element.  "to" shouldn't have any effect in these cases, since it has
        lower priority than "values," "path," and "mpath". So in each case, the
        lime rect should cover up the red rect at all times. -->
 
   <!-- Single-point path specified with "values" attribute: -->
   <g transform="translate(0,0)">
     <rect width="20" height="20" fill="red">
-      <animateMotion values="20,0" dur="2"/>
+      <animateMotion values="20,0" dur="2" begin="100"/>
     </rect>
     <rect width="20" height="20" fill="lime">
-      <animateMotion values="20,0" dur="2" to="-50,0"/>
+      <animateMotion values="20,0" dur="2" to="-50,0" begin="100"/>
     </rect>
   </g>
 
   <!-- Multi-point path specified with "values" attribute: -->
   <g transform="translate(0,30)">
     <rect width="20" height="20" fill="red">
-      <animateMotion values="20,0; 80,0" dur="2"/>
+      <animateMotion values="20,0; 80,0" dur="2" begin="100"/>
     </rect>
     <rect width="20" height="20" fill="lime">
-      <animateMotion values="20,0; 80,0" dur="2" to="-50,0"/>
+      <animateMotion values="20,0; 80,0" dur="2" to="-50,0" begin="100"/>
     </rect>
   </g>
 
   <!-- Path specified with "path" attribute: -->
   <g transform="translate(0,60)">
     <rect width="20" height="20" fill="red">
-      <animateMotion path="m0,0 h100" dur="2"/>
+      <animateMotion path="m0,0 h100" dur="2" begin="100"/>
     </rect>
     <rect width="20" height="20" fill="lime">
-      <animateMotion path="m0,0 h100" dur="2" to="-50,0"/>
+      <animateMotion path="m0,0 h100" dur="2" to="-50,0" begin="100"/>
     </rect>
   </g>
 
   <!-- Path specified with "mpath" subelement: -->
   <path id="p" d="m0,0 h100"/>
   <g transform="translate(0,90)">
     <rect width="20" height="20" fill="red">
-      <animateMotion dur="2"><mpath xlink:href="#p"/></animateMotion>
+      <animateMotion dur="2" begin="100"><mpath xlink:href="#p"/></animateMotion>
     </rect>
     <rect width="20" height="20" fill="lime">
-      <animateMotion dur="2" to="-50,0"><mpath xlink:href="#p"/></animateMotion>
+      <animateMotion dur="2" to="-50,0" begin="100"><mpath xlink:href="#p"/></animateMotion>
     </rect>
   </g>
 </svg>
--- a/layout/reftests/svg/smil/sort/sort-additive-1.svg
+++ b/layout/reftests/svg/smil/sort/sort-additive-1.svg
@@ -5,17 +5,17 @@
   <script type="text/ecmascript"><![CDATA[
     function swapAnimations() {
       var high = document.getElementById("high");
       high.parentNode.insertBefore(high, null);
 
       var low = document.getElementById("low");
       low.parentNode.insertBefore(low, low.parentNode.firstChild);
 
-      setTimeAndSnapshot(3.1, true);
+      setTimeAndSnapshot(103.1, true);
     }
     window.addEventListener("MozReftestInvalidate", swapAnimations, false);
   ]]></script>
   <script xlink:href="../smil-util.js" type="text/javascript"/>
   <!-- start line -->
   <line x1="5" x2="5" y1="0" y2="330" stroke="grey" stroke-width="2"
     stroke-dasharray="5,5"/>
   <!-- non-additive line -->
@@ -24,94 +24,93 @@
   <!-- additive line -->
   <line x1="205" x2="205" y1="0" y2="330" stroke="grey" stroke-width="2"
     stroke-dasharray="5,5"/>
   <!-- Not additive group -->
   <!-- additive behaviour defaults to replace so this shouldn't add -->
   <g transform="translate(5, 5)">
     <rect style="stroke: black; fill: lightskyblue" x="0" y="0" width="30"
     height="30">
-     <animate attributeName="x" from="0" to="100" dur="3s" fill="freeze"/>
-     <animate attributeName="x" from="0" to="100" dur="3s" fill="freeze"/>
+     <animate attributeName="x" from="0" to="100" begin="100s" dur="3s" fill="freeze"/>
+     <animate attributeName="x" from="0" to="100" begin="100s" dur="3s" fill="freeze"/>
     </rect>
   </g>
   <!-- Additive group -->
   <!-- We only need to specify additive behaviour on the second animation as
        it will be higher in the animation sandwich -->
   <g transform="translate(5, 45)">
     <rect style="stroke: black; fill: lightskyblue" x="0" y="0" width="30"
     height="30">
-      <animate attributeName="x" from="0" to="100" dur="3s" fill="freeze"/>
-      <animate attributeName="x" from="0" to="100" dur="3s" fill="freeze"
+      <animate attributeName="x" from="0" to="100" begin="100s" dur="3s" fill="freeze"/>
+      <animate attributeName="x" from="0" to="100" begin="100s" dur="3s" fill="freeze"
         additive="sum"/>
     </rect>
   </g>
   <!-- Not additive group -->
   <!-- Specifying additive behaviour on the first animation has no effect
        as it is lower in the animation sandwich (begin times are the same
        so the order in the document takes precedence). -->
   <g transform="translate(5, 85)">
     <rect style="stroke: black; fill: lightskyblue" x="0" y="0" width="30"
       height="30">
-      <animate attributeName="x" from="0" to="100" dur="3s" fill="freeze"
+      <animate attributeName="x" from="0" to="100" begin="100s" dur="3s" fill="freeze"
         additive="sum"/>
-     <animate attributeName="x" from="0" to="100" dur="3s" fill="freeze"/>
+     <animate attributeName="x" from="0" to="100" begin="100s" dur="3s" fill="freeze"/>
     </rect>
   </g>
   <!-- Additive group -->
   <!-- The first animation should be composed second as it has a later begin
        time so its additive attribute should apply even though it appears
        first in the document -->
   <g transform="translate(5, 125)">
     <rect style="stroke: black; fill: lightskyblue" x="0" y="0" width="30"
       height="30">
-      <animate attributeName="x" from="0" to="100" dur="3s" fill="freeze"
-        additive="sum" begin="1ms"/>
-      <animate attributeName="x" from="0" to="100" dur="3s" fill="freeze"/>
+      <animate attributeName="x" from="0" to="100" begin="100.001s" dur="3s" fill="freeze"
+        additive="sum"/>
+      <animate attributeName="x" from="0" to="100" begin="100s" dur="3s" fill="freeze"/>
     </rect>
   </g>
   <!-- Not additive group -->
   <!-- The first animation overrides the second animation because of its
        later begin time. -->
   <g transform="translate(5, 165)">
     <rect style="stroke: black; fill: lightskyblue" x="0" y="0" width="30"
       height="30">
-      <animate attributeName="x" from="0" to="100" dur="3s" fill="freeze"
-        begin="1ms"/>
-      <animate attributeName="x" from="0" to="100" dur="3s" fill="freeze"
+      <animate attributeName="x" from="0" to="100" begin="100.001s" dur="3s" fill="freeze"/>
+      <animate attributeName="x" from="0" to="100" begin="100s" dur="3s" fill="freeze"
         additive="sum"/>
     </rect>
   </g>
   <!-- Additive group -->
   <!-- Even though additive is replace, by animation is always additive -->
   <g transform="translate(5, 205)">
     <rect style="stroke: black; fill: lightskyblue" x="0" y="0" width="30"
       height="30">
-      <animate attributeName="x" from="0" to="100" dur="3s" fill="freeze"/>
-      <animate attributeName="x" by="100" dur="3s" fill="freeze"
+      <animate attributeName="x" from="0" to="100" begin="100s" dur="3s" fill="freeze"/>
+      <animate attributeName="x" by="100" dur="3s" begin="100s" fill="freeze"
         additive="replace"/>
     </rect>
   </g>
   <!-- Not additive group -->
   <!-- This begins as additive, but after the document loads the two animations
        will be swapped giving them the opposite priority and making this not
        additive. -->
   <g transform="translate(5, 245)">
     <rect style="stroke: black; fill: lightskyblue" x="0" y="0" width="30"
       height="30">
-      <animate attributeName="x" from="0" to="100" dur="3s" fill="freeze"/>
-      <animate attributeName="x" from="0" to="100" dur="3s" fill="freeze"
+      <animate attributeName="x" from="0" to="100" begin="100s" dur="3s" fill="freeze"/>
+      <animate attributeName="x" from="0" to="100" begin="100s" dur="3s" fill="freeze"
         additive="sum" id="low"/>
     </rect>
   </g>
   <!-- Additive group -->
   <!-- This is the inverse of the above. The animations will have their
        positions in the document swapped effectively making this not additive.
        -->
   <g transform="translate(5, 285)">
     <rect style="stroke: black; fill: lightskyblue" x="0" y="0" width="30"
       height="30">
-      <animate attributeName="x" from="0" to="100" dur="3s" fill="freeze"
+      <animate attributeName="x" from="0" to="100" begin="100s" dur="3s" fill="freeze"
         additive="sum" id="high"/>
-      <animate attributeName="x" from="0" to="100" dur="3s" fill="freeze"/>
+      <animate attributeName="x" from="0" to="100" begin="100s" dur="3s" fill="freeze"/>
     </rect>
   </g>
 </svg>
--- a/layout/reftests/text-overflow/single-value-ref.html
+++ b/layout/reftests/text-overflow/single-value-ref.html
@@ -53,19 +53,20 @@ function scrolldivs() {
       if (window.getComputedStyle(elm).direction == 'ltr')
         elm.scrollLeft = 8;
       else
         elm.scrollLeft = -8;
     }
   }
   document.documentElement.removeAttribute('class');
 }
+window.addEventListener("MozReftestInvalidate", scrolldivs, false);
 </script>
 </head>
-<body onload="scrolldivs()">
+<body>
 
     <div class="ltr start p hidden">A long line that does not break (overflow:hidden)</div>
     <div class="ltr start p auto">A long line that does not break (overflow:auto)</div>
     <div class="ltr start p autolong">A long line that does not break (overflow:auto)</div>
     <div class="ltr start p scroll">A long line that does not break (overflow:scroll)</div>
     <div class="ltr start s hidden">A long line that does not break (overflow:hidden)</div>
     <div class="ltr start s auto">A long line that does not break (overflow:auto)</div>
     <div class="ltr start s autolong">A long line that does not break (overflow:auto)</div>
--- a/layout/reftests/text-overflow/single-value.html
+++ b/layout/reftests/text-overflow/single-value.html
@@ -46,19 +46,20 @@ function scrolldivs() {
       if (window.getComputedStyle(elm).direction == 'ltr')
         elm.scrollLeft = 8;
       else
         elm.scrollLeft = -8;
     }
   }
   document.documentElement.removeAttribute('class');
 }
+window.addEventListener("MozReftestInvalidate", scrolldivs, false);
 </script>
 </head>
-<body onload="scrolldivs()">
+<body>
 
     <div class="ltr start p hidden">A long line that does not break (overflow:hidden)</div>
     <div class="ltr start p auto">A long line that does not break (overflow:auto)</div>
     <div class="ltr start p autolong">A long line that does not break (overflow:auto)</div>
     <div class="ltr start p scroll">A long line that does not break (overflow:scroll)</div>
     <div class="ltr start s hidden">A long line that does not break (overflow:hidden)</div>
     <div class="ltr start s auto">A long line that does not break (overflow:auto)</div>
     <div class="ltr start s autolong">A long line that does not break (overflow:auto)</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/transform/dynamic-addremove-1-ref.html
@@ -0,0 +1,8 @@
+<!DOCTYPE HTML>
+<html>
+<body>
+<div style="position:absolute; left:80px; top:20px; width:100px; height:100px; background:yellow">
+  <div style="position:absolute; left:50px; top:50px; width:100px; height:100px; background:orange"></div>
+</div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/transform/dynamic-addremove-1a.html
@@ -0,0 +1,15 @@
+<!DOCTYPE HTML>
+<html class="reftest-wait">
+<body style="margin:0;">
+<div id="t" style="width:100px; height:100px; background:yellow;">
+  <div style="position:absolute; left:50px; top:50px; width:100px; height:100px; background:orange;"></div>
+</div>
+<script>
+function doTest() {
+  document.getElementById("t").style.transform = "translate(80px,20px)";
+  document.documentElement.removeAttribute("class");
+}
+window.addEventListener("MozReftestInvalidate", doTest, false);
+</script>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/transform/dynamic-addremove-1b.html
@@ -0,0 +1,15 @@
+<!DOCTYPE HTML>
+<html class="reftest-wait">
+<body style="margin:0;">
+<div id="t" style="width:100px; height:100px; background:yellow;">
+  <div style="position:fixed; left:50px; top:50px; width:100px; height:100px; background:orange;"></div>
+</div>
+<script>
+function doTest() {
+  document.getElementById("t").style.transform = "translate(80px,20px)";
+  document.documentElement.removeAttribute("class");
+}
+window.addEventListener("MozReftestInvalidate", doTest, false);
+</script>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/transform/dynamic-addremove-1c.html
@@ -0,0 +1,17 @@
+<!DOCTYPE HTML>
+<html class="reftest-wait">
+<body style="margin:0;">
+<div id="t" style="width:100px; height:100px; background:yellow;">
+  <div style="float:left;">
+    <div style="position:fixed; left:50px; top:50px; width:100px; height:100px; background:orange;"></div>
+  </div>
+</div>
+<script>
+function doTest() {
+  document.getElementById("t").style.transform = "translate(80px,20px)";
+  document.documentElement.removeAttribute("class");
+}
+window.addEventListener("MozReftestInvalidate", doTest, false);
+</script>
+</body>
+</html>
--- a/layout/reftests/transform/reftest.list
+++ b/layout/reftests/transform/reftest.list
@@ -1,16 +1,19 @@
 # Transforms specifying singular matrices shouldn't display at all.
 # NOTE: Regressions might manifest themselves as reftest timeouts on
 # this test.
 == singular-1a.html about:blank
 # Multiple transforms should act identically to nested divs.
 == compound-1a.html compound-1-ref.html
 != compound-1a.html compound-1-fail.html
 == dynamic-inherit-1.html dynamic-inherit-1-ref.html
+== dynamic-addremove-1a.html dynamic-addremove-1-ref.html
+== dynamic-addremove-1b.html dynamic-addremove-1-ref.html
+== dynamic-addremove-1c.html dynamic-addremove-1-ref.html
 # translatex should act like position: relative
 == translatex-1a.html translatex-1-ref.html
 == translatex-1b.html translatex-1-ref.html
 == translatex-1c.html translatex-1-ref.html
 == translatex-1d.html translatex-1-ref.html
 == translatex-1e.html translatex-1-ref.html
 == translatex-1a.html translatex-1-ref-2.html
 # translatey should act like position: relative
--- a/layout/style/nsStyleContext.cpp
+++ b/layout/style/nsStyleContext.cpp
@@ -410,17 +410,17 @@ nsStyleContext::CalcStyleDifference(nsSt
   PR_END_MACRO
 
   // We begin by examining those style structs that are capable of
   // causing the maximal difference, a FRAMECHANGE.
   // FRAMECHANGE Structs: Display, XUL, Content, UserInterface,
   // Visibility, Outline, TableBorder, Table, Text, UIReset, Quotes
   nsChangeHint maxHint = nsChangeHint(NS_STYLE_HINT_FRAMECHANGE |
       nsChangeHint_UpdateTransformLayer | nsChangeHint_UpdateOpacityLayer |
-      nsChangeHint_UpdateOverflow);
+      nsChangeHint_UpdateOverflow | nsChangeHint_AddOrRemoveTransform);
   DO_STRUCT_DIFFERENCE(Display);
 
   maxHint = nsChangeHint(NS_STYLE_HINT_FRAMECHANGE |
       nsChangeHint_UpdateCursor);
   DO_STRUCT_DIFFERENCE(XUL);
   DO_STRUCT_DIFFERENCE(Column);
   DO_STRUCT_DIFFERENCE(Content);
   DO_STRUCT_DIFFERENCE(UserInterface);
--- a/layout/style/nsStyleStruct.cpp
+++ b/layout/style/nsStyleStruct.cpp
@@ -2271,17 +2271,22 @@ nsChangeHint nsStyleDisplay::CalcDiffere
   if (mOpacity != aOther.mOpacity) {
     NS_UpdateHint(hint, nsChangeHint_UpdateOpacityLayer);
   }
 
   /* If we've added or removed the transform property, we need to reconstruct the frame to add
    * or remove the view object, and also to handle abs-pos and fixed-pos containers.
    */
   if (HasTransform() != aOther.HasTransform()) {
-    NS_UpdateHint(hint, nsChangeHint_ReconstructFrame);
+    // We do not need to apply nsChangeHint_UpdateTransformLayer since
+    // nsChangeHint_RepaintFrame will forcibly invalidate the frame area and
+    // ensure layers are rebuilt (or removed).
+    NS_UpdateHint(hint, NS_CombineHint(nsChangeHint_AddOrRemoveTransform,
+                          NS_CombineHint(nsChangeHint_UpdateOverflow,
+                                         nsChangeHint_RepaintFrame)));
   }
   else if (HasTransform()) {
     /* Otherwise, if we've kept the property lying around and we already had a
      * transform, we need to see whether or not we've changed the transform.
      * If so, we need to recompute its overflow rect (which probably changed
      * if the transform changed) and to redraw within the bounds of that new
      * overflow rect.
      */
@@ -2334,17 +2339,18 @@ nsChangeHint nsStyleDisplay::CalcDiffere
 #ifdef DEBUG
 /* static */
 nsChangeHint nsStyleDisplay::MaxDifference()
 {
   // All the parts of FRAMECHANGE are present above in CalcDifference.
   return nsChangeHint(NS_STYLE_HINT_FRAMECHANGE |
                       nsChangeHint_UpdateOpacityLayer |
                       nsChangeHint_UpdateTransformLayer |
-                      nsChangeHint_UpdateOverflow);
+                      nsChangeHint_UpdateOverflow |
+                      nsChangeHint_AddOrRemoveTransform);
 }
 #endif
 
 // --------------------
 // nsStyleVisibility
 //
 
 nsStyleVisibility::nsStyleVisibility(nsPresContext* aPresContext)
--- a/layout/xul/base/src/nsScrollBoxObject.cpp
+++ b/layout/xul/base/src/nsScrollBoxObject.cpp
@@ -258,19 +258,19 @@ NS_IMETHODIMP nsScrollBoxObject::ScrollT
 
 /* void getPosition (out long x, out long y); */
 NS_IMETHODIMP nsScrollBoxObject::GetPosition(PRInt32 *x, PRInt32 *y)
 {
   nsIScrollableFrame* sf = GetScrollFrame();
   if (!sf)
      return NS_ERROR_FAILURE;
 
-  nsPoint pt = sf->GetScrollPosition();
-  *x = nsPresContext::AppUnitsToIntCSSPixels(pt.x);
-  *y = nsPresContext::AppUnitsToIntCSSPixels(pt.y);
+  nsIntPoint pt = sf->GetScrollPositionCSSPixels();
+  *x = pt.x;
+  *y = pt.y;
 
   return NS_OK;  
 }
 
 /* void getScrolledSize (out long width, out long height); */
 NS_IMETHODIMP nsScrollBoxObject::GetScrolledSize(PRInt32 *width, PRInt32 *height)
 {
     nsIFrame* scrolledBox = GetScrolledBox(this);
copy from security/manager/Makefile.in
copy to security/build/Makefile.in
--- a/security/manager/Makefile.in
+++ b/security/build/Makefile.in
@@ -8,18 +8,16 @@ topsrcdir	= @top_srcdir@
 srcdir		= @srcdir@
 VPATH		= @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 CC_WRAPPER =
 CXX_WRAPPER =
 include $(topsrcdir)/config/config.mk
 
-MODULE = psm
-
 ifndef MOZ_NATIVE_NSS
 LOADABLE_ROOT_MODULE = $(DLL_PREFIX)nssckbi$(DLL_SUFFIX)
 endif
 
 NSS3_LIB = $(DLL_PREFIX)nss3$(DLL_SUFFIX)
 NSSUTIL3_LIB = $(DLL_PREFIX)nssutil3$(DLL_SUFFIX)
 SMIME3_LIB = $(DLL_PREFIX)smime3$(DLL_SUFFIX)
 SSL3_LIB =  $(DLL_PREFIX)ssl3$(DLL_SUFFIX)
@@ -337,19 +335,9 @@ libs::
 	$(INSTALL) -m 755 $(SDK_LIBS) $(DIST)/sdk/lib
 # NSS installs headers to dist/public and we want them in dist/include
 	$(NSINSTALL) -D $(DIST)/include/nss
 	(cd $(DIST)/public/nss && tar $(TAR_CREATE_FLAGS) - .) | \
 	  (cd $(DIST)/include && tar -xf -)
 
 endif # MOZ_NATIVE_NSS
 
-DIRS = \
-  boot \
-  ssl \
-  locales \
-  $(NULL)
-
-ifdef MOZ_XUL
-DIRS += pki
-endif
-
 include $(topsrcdir)/config/rules.mk
--- a/security/manager/Makefile.in
+++ b/security/manager/Makefile.in
@@ -4,348 +4,16 @@
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 DEPTH		= @DEPTH@
 topsrcdir	= @top_srcdir@
 srcdir		= @srcdir@
 VPATH		= @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
-CC_WRAPPER =
-CXX_WRAPPER =
-include $(topsrcdir)/config/config.mk
-
-MODULE = psm
-
-ifndef MOZ_NATIVE_NSS
-LOADABLE_ROOT_MODULE = $(DLL_PREFIX)nssckbi$(DLL_SUFFIX)
-endif
-
-NSS3_LIB = $(DLL_PREFIX)nss3$(DLL_SUFFIX)
-NSSUTIL3_LIB = $(DLL_PREFIX)nssutil3$(DLL_SUFFIX)
-SMIME3_LIB = $(DLL_PREFIX)smime3$(DLL_SUFFIX)
-SSL3_LIB =  $(DLL_PREFIX)ssl3$(DLL_SUFFIX)
-SOFTOKEN3_LIB = $(DLL_PREFIX)softokn3$(DLL_SUFFIX)
-
-ifndef NSS_DISABLE_DBM
-NSSDBM3_LIB = $(DLL_PREFIX)nssdbm3$(DLL_SUFFIX)
-else
-NSSDBM3_LIB = 
-endif
-
-ifndef MOZ_NATIVE_NSS
-ifneq (,$(filter OS2 WINNT,$(OS_ARCH)))
-SDK_LIBS = \
-  $(DIST)/lib/$(LIB_PREFIX)crmf.$(LIB_SUFFIX) \
-  $(DIST)/lib/$(LIB_PREFIX)smime3.$(LIB_SUFFIX) \
-  $(DIST)/lib/$(LIB_PREFIX)ssl3.$(LIB_SUFFIX) \
-  $(DIST)/lib/$(LIB_PREFIX)nss3.$(LIB_SUFFIX) \
-  $(DIST)/lib/$(LIB_PREFIX)nssutil3.$(LIB_SUFFIX) \
-  $(NULL)
-else
-SDK_LIBS = \
-  $(DIST)/lib/$(LIB_PREFIX)crmf.$(LIB_SUFFIX) \
-  $(DIST)/lib/$(LIB_PREFIX)smime.$(LIB_SUFFIX) \
-  $(DIST)/lib/$(LIB_PREFIX)ssl.$(LIB_SUFFIX) \
-  $(DIST)/lib/$(LIB_PREFIX)nss.$(LIB_SUFFIX) \
-  $(DIST)/lib/$(LIB_PREFIX)nssutil.$(LIB_SUFFIX) \
-  $(NULL)
-endif
-endif
-
-# Default
-HAVE_FREEBL_LIBS = 1
-
-# 32-bit HP-UX PA-RISC
-ifeq ($(OS_ARCH), HP-UX)
-ifneq ($(OS_TEST), ia64)
-ifndef HAVE_64BIT_OS
-HAVE_FREEBL_LIBS =
-HAVE_FREEBL_LIBS_32 = 1
-endif
-endif
-endif
-
-# SunOS SPARC
-ifeq ($(OS_ARCH), SunOS)
-ifneq (86,$(findstring 86,$(OS_TEST)))
-ifdef HAVE_64BIT_OS
-HAVE_FREEBL_LIBS =
-HAVE_FREEBL_LIBS_64 = 1
-else
-HAVE_FREEBL_LIBS =
-HAVE_FREEBL_LIBS_32 = 1
-HAVE_FREEBL_LIBS_32INT64 = 1
-endif
-endif
-endif
-
-ifdef HAVE_FREEBL_LIBS
-FREEBL_LIB = $(DLL_PREFIX)freebl3$(DLL_SUFFIX)
-endif
-ifdef HAVE_FREEBL_LIBS_32
-FREEBL_32INT_LIB = libfreebl_32int_3$(DLL_SUFFIX)
-FREEBL_32FPU_LIB = libfreebl_32fpu_3$(DLL_SUFFIX)
-endif
-ifdef HAVE_FREEBL_LIBS_32INT64
-FREEBL_32INT64_LIB = libfreebl_32int64_3$(DLL_SUFFIX)
-endif
-ifdef HAVE_FREEBL_LIBS_64
-FREEBL_64INT_LIB = libfreebl_64int_3$(DLL_SUFFIX)
-FREEBL_64FPU_LIB = libfreebl_64fpu_3$(DLL_SUFFIX)
-endif
-
-ABS_DIST := $(call core_abspath,$(DIST))
-ifeq ($(HOST_OS_ARCH),WINNT)
-ifdef CYGDRIVE_MOUNT
-ABS_DIST := $(shell cygpath -w $(ABS_DIST) | sed -e 's|\\|/|g')
-endif
-ifneq (,$(filter mingw%,$(host_os)))
-ABS_DIST := $(shell cd $(DIST) && pwd -W)
-endif
-endif
-# For all variables such as DLLFLAGS, that may contain $(DIST)
-DIST := $(ABS_DIST)
-NSPR_INCLUDE_DIR = $(firstword $(filter -I%,$(NSPR_CFLAGS)))
-ifneq (,$(strip $(NSPR_INCLUDE_DIR)))
-NSPR_INCLUDE_DIR := $(subst -I,,$(subst -I$(DIST),-I$(ABS_DIST),$(NSPR_INCLUDE_DIR)))
-else
-NSPR_INCLUDE_DIR = $(ABS_DIST)/include/nspr
-endif
-NSPR_LIB_DIR = $(firstword $(filter -L%,$(NSPR_LIBS)))
-ifneq (,$(strip $(NSPR_LIB_DIR)))
-NSPR_LIB_DIR := $(subst -L,,$(subst -L$(DIST),-L$(ABS_DIST),$(NSPR_LIB_DIR)))
-else
-NSPR_LIB_DIR = $(ABS_DIST)/lib
-endif
-# Can't pass this in DEFAULT_GMAKE_FLAGS because that overrides
-# definitions in NSS, so just export it into the sub-make's environment.
-ifeq (WINNT_1,$(OS_TARGET)_$(MOZ_MEMORY))
-export DLLFLAGS
-endif
-
-# To get debug symbols from NSS
-export MOZ_DEBUG_SYMBOLS
-
-ifdef .PYMAKE
-NSSMAKE = $(GMAKE)
-else
-NSSMAKE = $(MAKE)
-endif
-
-# NSS makefiles are not safe for parallel execution.
-DEFAULT_GMAKE_FLAGS = MAKE="$(NSSMAKE) -j1" -j1
-DEFAULT_GMAKE_FLAGS += CC="$(CC)"
-DEFAULT_GMAKE_FLAGS += SOURCE_MD_DIR=$(ABS_DIST)
-DEFAULT_GMAKE_FLAGS += SOURCE_MDHEADERS_DIR=$(NSPR_INCLUDE_DIR)
-DEFAULT_GMAKE_FLAGS += DIST=$(ABS_DIST)
-DEFAULT_GMAKE_FLAGS += NSPR_INCLUDE_DIR=$(NSPR_INCLUDE_DIR)
-DEFAULT_GMAKE_FLAGS += NSPR_LIB_DIR=$(NSPR_LIB_DIR)
-DEFAULT_GMAKE_FLAGS += MOZILLA_CLIENT=1
-DEFAULT_GMAKE_FLAGS += NO_MDUPDATE=1
-DEFAULT_GMAKE_FLAGS += NSS_ENABLE_ECC=1
-DEFAULT_GMAKE_FLAGS += NSINSTALL="$(NSINSTALL)"
-ifndef MOZ_NATIVE_SQLITE
-DEFAULT_GMAKE_FLAGS += SQLITE_LIB_NAME=mozsqlite3
-DEFAULT_GMAKE_FLAGS += SQLITE_INCLUDE_DIR=$(ABS_DIST)/include
-endif
-ifdef NSS_DISABLE_DBM 
-DEFAULT_GMAKE_FLAGS += NSS_DISABLE_DBM=1
-endif
-ABS_topsrcdir   := $(call core_abspath,$(topsrcdir))
-# Hack to force NSS build system to use "normal" object directories
-DEFAULT_GMAKE_FLAGS += BUILD='$(MOZ_BUILD_ROOT)/security/$$(subst $(shell cd $(topsrcdir); pwd)/security/,,$$(CURDIR))'
-DEFAULT_GMAKE_FLAGS += BUILD_TREE='$$(BUILD)' OBJDIR='$$(BUILD)' DEPENDENCIES='$$(BUILD)/.deps' SINGLE_SHLIB_DIR='$$(BUILD)'
-DEFAULT_GMAKE_FLAGS += SOURCE_XP_DIR=$(ABS_DIST)
-ifndef MOZ_DEBUG
-DEFAULT_GMAKE_FLAGS += BUILD_OPT=1 OPT_CODE_SIZE=1
-endif
-ifdef GNU_CC
-DEFAULT_GMAKE_FLAGS += NS_USE_GCC=1
-else
-DEFAULT_GMAKE_FLAGS += NS_USE_GCC=
-endif
-ifdef USE_N32
-# It is not really necessary to specify USE_PTHREADS=1.  USE_PTHREADS
-# merely adds _PTH to coreconf's OBJDIR name.
-DEFAULT_GMAKE_FLAGS += USE_N32=1 USE_PTHREADS=1
-endif
-ifdef HAVE_64BIT_OS
-DEFAULT_GMAKE_FLAGS += USE_64=1
-endif
-ifeq ($(OS_ARCH),WINNT)
-DEFAULT_GMAKE_FLAGS += OS_TARGET=WIN95
-ifdef MOZ_DEBUG
-ifndef MOZ_NO_DEBUG_RTL
-DEFAULT_GMAKE_FLAGS += USE_DEBUG_RTL=1
-endif
-endif
-endif # WINNT
-ifeq ($(OS_ARCH),OS2)
-ifdef MOZ_OS2_HIGH_MEMORY
-DEFAULT_GMAKE_FLAGS += MOZ_OS2_HIGH_MEMORY=1
-endif
-endif # OS2
-ifeq ($(OS_ARCH),Darwin)
-# Make nsinstall use absolute symlinks by default when building NSS
-# for Mozilla on Mac OS X. (Bugzilla bug 193164)
-ifndef NSDISTMODE
-DEFAULT_GMAKE_FLAGS += NSDISTMODE=absolute_symlink
-endif
-ifdef MACOS_SDK_DIR
-DEFAULT_GMAKE_FLAGS += MACOS_SDK_DIR=$(MACOS_SDK_DIR)
-endif
-endif
-
-# Turn off TLS compression support because it requires system zlib.
-# See bug 580679 comment 18.
-DEFAULT_GMAKE_FLAGS += NSS_ENABLE_ZLIB=
-
-# Disable building of the test programs in security/nss/lib/zlib
-DEFAULT_GMAKE_FLAGS += PROGRAMS=
-
-# Disable creating .chk files. They will be generated from packager.mk
-# When bug 681624 lands, we can replace CHECKLOC= with SKIP_SHLIBSIGN=1
-DEFAULT_GMAKE_FLAGS += CHECKLOC=
-
-ifdef CROSS_COMPILE
-
-DEFAULT_GMAKE_FLAGS += \
-	NATIVE_CC="$(HOST_CC)" \
-	CC="$(CC)" \
-	CCC="$(CXX)" \
-	LINK="$(LD)" \
-	AS="$(AS)" \
-	AR='$(AR) $(AR_FLAGS:$@=$$@)' \
-	RANLIB="$(RANLIB)" \
-	RC="$(RC) $(RCFLAGS)" \
-	OS_ARCH="$(OS_ARCH)" \
-	OS_TEST="$(OS_TEST)" \
-	CPU_ARCH="$(TARGET_CPU)" \
-	$(NULL)
-
-# Android has pthreads integrated into -lc, so OS_PTHREAD is set to nothing
-ifeq ($(OS_TARGET), Android)
-DEFAULT_GMAKE_FLAGS += \
-	OS_RELEASE="2.6" \
-	OS_PTHREAD= \
-	STANDARDS_CFLAGS="-std=gnu89" \
-	$(NULL)
-
-DEFAULT_GMAKE_FLAGS += ARCHFLAG="$(CFLAGS) -DCHECK_FORK_GETPID -DRTLD_NOLOAD=0 -include $(ABS_topsrcdir)/security/manager/android_stub.h"
-endif
-endif
-
-ifdef WRAP_LDFLAGS
-DEFAULT_GMAKE_FLAGS += \
-	LDFLAGS="$(LDFLAGS) $(WRAP_LDFLAGS)" \
-	DSO_LDOPTS="$(DSO_LDOPTS) $(LDFLAGS) $(WRAP_LDFLAGS)" \
-	$(NULL)
-endif
-
-DEFAULT_GMAKE_FLAGS += FREEBL_NO_DEPEND=0
-ifeq ($(OS_TARGET),Linux)
-DEFAULT_GMAKE_FLAGS += FREEBL_LOWHASH=1
-endif
-
-ifdef MOZ_NO_WLZDEFS
-DEFAULT_GMAKE_FLAGS += ZDEFS_FLAG=
-endif
-ifdef MOZ_CFLAGS_NSS
-DEFAULT_GMAKE_FLAGS += XCFLAGS="$(CFLAGS)"
-DEFAULT_GMAKE_FLAGS += DARWIN_DYLIB_VERSIONS="-compatibility_version 1 -current_version 1 $(LDFLAGS)"
-endif
-
-ifdef MOZ_NSS_PATCH
-# If we're applying a patch, we'll copy the NSS source to the objdir
-# and build it from there.
-NSS_SRCDIR = $(CURDIR)/nss
-
-# This will copy and patch the NSS source for every build.
-# Since we "cp -p", it won't force rebuilds for most files, just
-# for patched files, but that's easier than trying to track
-# dependencies for patched files.
-export::
-	rm -rf $(NSS_SRCDIR)
-	$(NSINSTALL) -D $(NSS_SRCDIR)/security
-	cp -Rp $(topsrcdir)/security/nss $(NSS_SRCDIR)/security
-	cp -Rp $(topsrcdir)/security/coreconf $(NSS_SRCDIR)/security
-	cp -Rp $(topsrcdir)/security/dbm $(NSS_SRCDIR)/security
-	cp -Rp $(topsrcdir)/dbm $(NSS_SRCDIR)
-	(cd $(NSS_SRCDIR) && patch -p1 < $(call core_abspath,$(MOZ_NSS_PATCH)))
-else
-NSS_SRCDIR = $(topsrcdir)
-endif
-
-NSS_DIRS =
-ifndef NSS_DISABLE_DBM
-NSS_DIRS += dbm
-endif
-NSS_DIRS += \
-  nss/lib \
-  nss/cmd/lib \
-  nss/cmd/shlibsign \
-  $(NULL)
-
-ifdef ENABLE_TESTS
-NSS_DIRS += \
-  nss/cmd/certutil \
-  nss/cmd/pk12util \
-  nss/cmd/modutil \
-  $(NULL)
-endif
-
-ifndef MOZ_NATIVE_NSS
-define build_rules
-libs::
-	$$(NSSMAKE) -C $$(NSS_SRCDIR)/security/$(1) $$(DEFAULT_GMAKE_FLAGS)
-
-clean clobber clobber_all realclean distclean depend::
-	$$(NSSMAKE) -C $$(NSS_SRCDIR)/security/$(1) $$(DEFAULT_GMAKE_FLAGS) clean
-endef
-$(foreach dir,$(NSS_DIRS),$(eval $(call build_rules,$(dir))))
-
-NSS_LIBS = \
-  $(LOADABLE_ROOT_MODULE) \
-  $(SOFTOKEN3_LIB) \
-  $(NSSDBM3_LIB) \
-  $(NSS3_LIB) \
-  $(NSSUTIL3_LIB) \
-  $(SSL3_LIB) \
-  $(SMIME3_LIB) \
-  $(FREEBL_LIB) \
-  $(FREEBL_32INT_LIB) \
-  $(FREEBL_32FPU_LIB) \
-  $(FREEBL_32INT64_LIB) \
-  $(FREEBL_64INT_LIB) \
-  $(FREEBL_64FPU_LIB) \
-  $(NULL)
-
-define install_rules
-libs::
-ifeq ($(OS_ARCH)_$(1), SunOS_$(SOFTOKEN3_LIB))
-# has to use copy mode on Solaris, see #665509
-	$$(NSINSTALL) -t -m 755 $$(DIST)/lib/$(1) $$(DIST)/bin
-else
-	$$(INSTALL) -m 755 $$(DIST)/lib/$(1) $$(DIST)/bin
-endif
-
-install::
-	$$(SYSINSTALL) -m 755 $$(DIST)/lib/$(1) $$(DESTDIR)$$(mozappdir)
-endef
-$(foreach lib,$(NSS_LIBS),$(eval $(call install_rules,$(lib))))
-
-libs::
-	$(INSTALL) -m 755 $(SDK_LIBS) $(DIST)/sdk/lib
-# NSS installs headers to dist/public and we want them in dist/include
-	$(NSINSTALL) -D $(DIST)/include/nss
-	(cd $(DIST)/public/nss && tar $(TAR_CREATE_FLAGS) - .) | \
-	  (cd $(DIST)/include && tar -xf -)
-
-endif # MOZ_NATIVE_NSS
 
 DIRS = \
   boot \
   ssl \
   locales \
   $(NULL)
 
 ifdef MOZ_XUL
--- a/testing/mochitest/android.json
+++ b/testing/mochitest/android.json
@@ -136,16 +136,17 @@
  "dom/imptests/webapps/DOMCore/tests/approved/test_Range-cloneContents.html": "bug 775227", 
  "dom/imptests/webapps/DOMCore/tests/approved/test_Range-compareBoundaryPoints.html": "bug 775227",
  "dom/imptests/webapps/DOMCore/tests/approved/test_Range-deleteContents.html": "bug 775227",
  "dom/imptests/webapps/DOMCore/tests/approved/test_Range-extractContents.html": "bug 775227",
  "dom/imptests/webapps/DOMCore/tests/approved/test_Range-insertNode.html": "bug 775227",
  "dom/imptests/webapps/DOMCore/tests/approved/test_Range-mutations.html": "bug 775227",
  "dom/imptests/webapps/DOMCore/tests/approved/test_Range-set.html": "bug 775227",
  "dom/imptests/webapps/DOMCore/tests/approved/test_Range-surroundContents.html": "bug 775227",
+ "dom/imptests/webapps/DOMCore/tests/submissions": "bug 782254",
  "dom/imptests/webapps/WebStorage/tests/submissions": "bug 781837 & bug 775227",
  "dom/indexedDB/test/test_third_party.html": "TIMED_OUT",
  "dom/indexedDB/test/test_event_propagation.html": "TIMED_OUT, bug 780855",
  "dom/network/tests/test_network_basics.html": "",
  "dom/settings/tests/test_settings_events.html": "",
  "dom/settings/tests/test_settings_basics.html": "",
  "dom/contacts/tests/test_contacts_blobs.html": "",
  "dom/contacts/tests/test_contacts_basics.html": "",
--- a/toolkit/content/tests/chrome/test_bug624329.xul
+++ b/toolkit/content/tests/chrome/test_bug624329.xul
@@ -50,26 +50,25 @@ function childFocused() {
     // the right edge of the screen.
 
     listenOnce("resize", childResized);
     win.maximize();
 }
 
 function childResized() {
     const isOSXLion = navigator.userAgent.indexOf("Mac OS X 10.7") != -1;
+
+    is(win.windowState, win.STATE_MAXIMIZED,
+       "window should be maximized");
+
     if (isOSXLion) {
-        todo_is(win.windowState, win.STATE_MAXIMIZED,
-                "A resize before being maximized breaks this test on 10.7");
         finish();
         return;
     }
 
-    is(win.windowState, win.STATE_MAXIMIZED,
-       "window should be maximized");
-
     isnot(win.innerWidth, 300,
          "window inner width should have changed");
 
     openContextMenu();
 }
 
 function openContextMenu() {
     var mouseX = win.innerWidth - 10;
--- a/toolkit/toolkit-makefiles.sh
+++ b/toolkit/toolkit-makefiles.sh
@@ -1526,16 +1526,17 @@ fi
 if [ "$MOZ_AUTH_EXTENSION" ]; then
   add_makefiles "
     extensions/auth/Makefile
   "
 fi
 
 if [ "$MOZ_PSM" ]; then
   add_makefiles "
+    security/build/Makefile
     security/manager/Makefile
     security/manager/boot/Makefile
     security/manager/boot/src/Makefile
     security/manager/ssl/Makefile
     security/manager/ssl/src/Makefile
     security/manager/pki/Makefile
     security/manager/pki/resources/Makefile
     security/manager/pki/src/Makefile
--- a/toolkit/toolkit-tiers.mk
+++ b/toolkit/toolkit-tiers.mk
@@ -120,16 +120,22 @@ tier_platform_dirs += \
 endif
 
 ifdef MOZ_SYDNEYAUDIO
 tier_platform_dirs += \
 		media/libsydneyaudio \
 		$(NULL)
 endif
 
+ifdef MOZ_PSM
+tier_platform_dirs += \
+  security/build \
+  $(NULL)
+endif
+
 ifdef MOZ_WEBRTC
 tier_platform_dirs += \
   media/webrtc \
   $(NULL)
 endif
 
 ifdef MOZ_SPEEX_RESAMPLER
 tier_platform_dirs += \
--- a/view/src/Makefile.in
+++ b/view/src/Makefile.in
@@ -12,16 +12,18 @@ include $(DEPTH)/config/autoconf.mk
 
 MODULE		= view
 LIBRARY_NAME	= gkview_s
 FORCE_STATIC_LIB = 1
 MODULE_NAME	= nsViewModule
 GRE_MODULE	= 1
 LIBXUL_LIBRARY	= 1
 
+DEFINES += -D_IMPL_NS_LAYOUT
+
 CPPSRCS		= \
 		nsView.cpp \
 		nsViewManager.cpp \
 		$(NULL)
 
 include $(topsrcdir)/config/rules.mk
 
 LOCAL_INCLUDES  = \
--- a/view/src/nsViewManager.cpp
+++ b/view/src/nsViewManager.cpp
@@ -18,16 +18,18 @@
 #include "nsCOMArray.h"
 #include "nsIPluginWidget.h"
 #include "nsXULPopupManager.h"
 #include "nsIPresShell.h"
 #include "nsPresContext.h"
 #include "nsEventStateManager.h"
 #include "mozilla/StartupTimeline.h"
 #include "sampler.h"
+#include "nsRefreshDriver.h"
+#include "mozilla/Preferences.h"
 
 /**
    XXX TODO XXX
 
    DeCOMify newly private methods
    Optimize view storage
 */
 
@@ -39,16 +41,32 @@
    We do NOT assume anything about the relative z-ordering of sibling widgets. Even though
    we ask for a specific z-order, we don't assume that widget z-ordering actually works.
 */
 
 #define NSCOORD_NONE      PR_INT32_MIN
 
 #undef DEBUG_MOUSE_LOCATION
 
+static bool
+IsRefreshDriverPaintingEnabled()
+{
+  static bool sRefreshDriverPaintingEnabled;
+  static bool sRefreshDriverPaintingPrefCached = false;
+
+  if (!sRefreshDriverPaintingPrefCached) {
+    sRefreshDriverPaintingPrefCached = true;
+    mozilla::Preferences::AddBoolVarCache(&sRefreshDriverPaintingEnabled,
+                                          "viewmanager.refresh-driver-painting.enabled",
+                                          true);
+  }
+
+  return sRefreshDriverPaintingEnabled;
+}
+
 PRInt32 nsViewManager::mVMCount = 0;
 
 // Weakly held references to all of the view managers
 nsVoidArray* nsViewManager::gViewManagers = nullptr;
 PRUint32 nsViewManager::gLastUserEventTime = 0;
 
 nsViewManager::nsViewManager()
   : mDelayedResize(NSCOORD_NONE, NSCOORD_NONE)
@@ -293,21 +311,19 @@ nsIView* nsIViewManager::GetDisplayRootF
   }
 }
 
 /**
    aRegion is given in device coordinates!!
    aContext may be null, in which case layers should be used for
    rendering.
 */
-void nsViewManager::Refresh(nsView *aView, nsIWidget *aWidget,
-                            const nsIntRegion& aRegion,
+void nsViewManager::Refresh(nsView *aView, const nsIntRegion& aRegion,
                             bool aWillSendDidPaint)
 {
-  NS_ASSERTION(aView == nsView::GetViewFor(aWidget), "view widget mismatch");
   NS_ASSERTION(aView->GetViewManager() == this, "wrong view manager");
 
   // damageRegion is the damaged area, in twips, relative to the view origin
   nsRegion damageRegion = aRegion.ToAppUnits(AppUnitsPerDevPixel());
   // move region from widget coordinates into view coordinates
   damageRegion.MoveBy(-aView->ViewToWidgetOffset());
 
   if (damageRegion.IsEmpty()) {
@@ -330,18 +346,29 @@ void nsViewManager::Refresh(nsView *aVie
   {
     nsAutoScriptBlocker scriptBlocker;
     SetPainting(true);
 
     NS_ASSERTION(GetDisplayRootFor(aView) == aView,
                  "Widgets that we paint must all be display roots");
 
     if (mPresShell) {
-      mPresShell->Paint(aView, aWidget, damageRegion, aRegion,
-                        aWillSendDidPaint);
+#ifdef DEBUG_INVALIDATIONS
+      printf("--COMPOSITE-- %p\n", mPresShell);
+#endif
+      if (IsRefreshDriverPaintingEnabled()) {
+        mPresShell->Paint(aView, damageRegion, nsIPresShell::PaintType_Composite,
+                          false);
+      } else {
+        mPresShell->Paint(aView, damageRegion, nsIPresShell::PaintType_Full,
+                          aWillSendDidPaint);
+      }
+#ifdef DEBUG_INVALIDATIONS
+      printf("--ENDCOMPOSITE--\n");
+#endif
       mozilla::StartupTimeline::RecordOnce(mozilla::StartupTimeline::FIRST_PAINT);
     }
 
     SetPainting(false);
   }
 
   if (RootViewManager()->mRecursiveRefreshPending) {
     RootViewManager()->mRecursiveRefreshPending = false;
@@ -367,17 +394,51 @@ void nsViewManager::ProcessPendingUpdate
   for (nsView* childView = aView->GetFirstChild(); childView;
        childView = childView->GetNextSibling()) {
     ProcessPendingUpdatesForView(childView, aFlushDirtyRegion);
   }
 
   // Push out updates after we've processed the children; ensures that
   // damage is applied based on the final widget geometry
   if (aFlushDirtyRegion) {
-    FlushDirtyRegionToWidget(aView);
+    if (IsRefreshDriverPaintingEnabled()) {
+      nsIWidget *widget = aView->GetWidget();
+      if (widget && widget->NeedsPaint() && aView->HasNonEmptyDirtyRegion()) {
+        FlushDirtyRegionToWidget(aView);
+        // If an ancestor widget was hidden and then shown, we could
+        // have a delayed resize to handle.
+        for (nsViewManager *vm = this; vm;
+             vm = vm->mRootView->GetParent()
+                    ? vm->mRootView->GetParent()->GetViewManager()
+                    : nullptr) {
+          if (vm->mDelayedResize != nsSize(NSCOORD_NONE, NSCOORD_NONE) &&
+              vm->mRootView->IsEffectivelyVisible() &&
+              mPresShell && mPresShell->IsVisible()) {
+            vm->FlushDelayedResize(true);
+            vm->InvalidateView(vm->mRootView);
+          }
+        }
+
+        NS_ASSERTION(aView->HasWidget(), "Must have a widget!");
+
+        SetPainting(true);
+#ifdef DEBUG_INVALIDATIONS
+        printf("---- PAINT START ----PresShell(%p), nsView(%p), nsIWidget(%p)\n", mPresShell, aView, widget);
+#endif
+        nsAutoScriptBlocker scriptBlocker;
+        NS_ASSERTION(aView->HasWidget(), "Must have a widget!");
+        mPresShell->Paint(aView, nsRegion(), nsIPresShell::PaintType_NoComposite, true);
+#ifdef DEBUG_INVALIDATIONS
+        printf("---- PAINT END ----\n");
+#endif
+        SetPainting(false);
+      }
+    } else {
+      FlushDirtyRegionToWidget(aView);
+    }
   }
 }
 
 void nsViewManager::FlushDirtyRegionToWidget(nsView* aView)
 {
   if (!aView->HasNonEmptyDirtyRegion())
     return;
 
@@ -694,45 +755,48 @@ NS_IMETHODIMP nsViewManager::DispatchEve
       break;
 
     case NS_WILL_PAINT:
       {
         if (!aView || !mContext)
           break;
 
         *aStatus = nsEventStatus_eConsumeNoDefault;
-
-        nsPaintEvent *event = static_cast<nsPaintEvent*>(aEvent);
+    
+        if (!IsRefreshDriverPaintingEnabled()) {
 
-        NS_ASSERTION(static_cast<nsView*>(aView) ==
-                       nsView::GetViewFor(event->widget),
-                     "view/widget mismatch");
+          nsPaintEvent *event = static_cast<nsPaintEvent*>(aEvent);
+
+          NS_ASSERTION(static_cast<nsView*>(aView) ==
+                         nsView::GetViewFor(event->widget),
+                       "view/widget mismatch");
 
-        // If an ancestor widget was hidden and then shown, we could
-        // have a delayed resize to handle.
-        for (nsViewManager *vm = this; vm;
-             vm = vm->mRootView->GetParent()
-                    ? vm->mRootView->GetParent()->GetViewManager()
-                    : nullptr) {
-          if (vm->mDelayedResize != nsSize(NSCOORD_NONE, NSCOORD_NONE) &&
-              vm->mRootView->IsEffectivelyVisible() &&
-              mPresShell && mPresShell->IsVisible()) {
-            vm->FlushDelayedResize(true);
-            vm->InvalidateView(vm->mRootView);
+          // If an ancestor widget was hidden and then shown, we could
+          // have a delayed resize to handle.
+          for (nsViewManager *vm = this; vm;
+               vm = vm->mRootView->GetParent()
+                      ? vm->mRootView->GetParent()->GetViewManager()
+                      : nullptr) {
+            if (vm->mDelayedResize != nsSize(NSCOORD_NONE, NSCOORD_NONE) &&
+                vm->mRootView->IsEffectivelyVisible() &&
+                mPresShell && mPresShell->IsVisible()) {
+              vm->FlushDelayedResize(true);
+              vm->InvalidateView(vm->mRootView);
+            }
           }
+
+          // Flush things like reflows and plugin widget geometry updates by
+          // calling WillPaint on observer presShells.
+          nsRefPtr<nsViewManager> rootVM = RootViewManager();
+          if (mPresShell) {
+            rootVM->CallWillPaintOnObservers(event->willSendDidPaint);
+          }
+          // Flush view widget geometry updates and invalidations.
+          rootVM->ProcessPendingUpdates();
         }
-
-        // Flush things like reflows and plugin widget geometry updates by
-        // calling WillPaint on observer presShells.
-        nsRefPtr<nsViewManager> rootVM = RootViewManager();
-        if (mPresShell) {
-          rootVM->CallWillPaintOnObservers(event->willSendDidPaint);
-        }
-        // Flush view widget geometry updates and invalidations.
-        rootVM->ProcessPendingUpdates();
       }
       break;
 
     case NS_PAINT:
       {
         if (!aView || !mContext)
           break;
 
@@ -740,39 +804,41 @@ NS_IMETHODIMP nsViewManager::DispatchEve
         nsPaintEvent *event = static_cast<nsPaintEvent*>(aEvent);
         nsView* view = static_cast<nsView*>(aView);
         NS_ASSERTION(view == nsView::GetViewFor(event->widget),
                      "view/widget mismatch");
         NS_ASSERTION(IsPaintingAllowed(),
                      "shouldn't be receiving paint events while painting is "
                      "disallowed!");
 
-        if (!event->didSendWillPaint) {
+        if (!event->didSendWillPaint && !IsRefreshDriverPaintingEnabled()) {
           // Send NS_WILL_PAINT event ourselves.
           nsPaintEvent willPaintEvent(true, NS_WILL_PAINT, event->widget);
           willPaintEvent.willSendDidPaint = event->willSendDidPaint;
           DispatchEvent(&willPaintEvent, view, aStatus);
 
           // Get the view pointer again since NS_WILL_PAINT might have
           // destroyed it during CallWillPaintOnObservers (bug 378273).
           view = nsView::GetViewFor(event->widget);
         }
 
         if (!view || event->region.IsEmpty())
           break;
 
         // Paint.
-        Refresh(view, event->widget, event->region, event->willSendDidPaint);
+        Refresh(view, event->region, event->willSendDidPaint);
 
         break;
       }
 
     case NS_DID_PAINT: {
-      nsRefPtr<nsViewManager> rootVM = RootViewManager();
-      rootVM->CallDidPaintOnObserver();
+      if (!IsRefreshDriverPaintingEnabled()) {
+        nsRefPtr<nsViewManager> rootVM = RootViewManager();
+        rootVM->CallDidPaintOnObserver();
+      }
       break;
     }
 
     case NS_CREATE:
     case NS_DESTROY:
     case NS_SETZLEVEL:
       /* Don't pass these events through. Passing them through
          causes performance problems on pages with lots of views/frames 
@@ -1287,33 +1353,46 @@ nsViewManager::IsPainting(bool& aIsPaint
 void
 nsViewManager::ProcessPendingUpdates()
 {
   if (!IsRootVM()) {
     RootViewManager()->ProcessPendingUpdates();
     return;
   }
 
-  if (mHasPendingUpdates) {
+  if (IsRefreshDriverPaintingEnabled()) {
+    mPresShell->GetPresContext()->RefreshDriver()->RevokeViewManagerFlush();
+    if (mHasPendingUpdates) {
+      mHasPendingUpdates = false;
+      
+      // Flush things like reflows and plugin widget geometry updates by
+      // calling WillPaint on observer presShells.
+      if (mPresShell) {
+        CallWillPaintOnObservers(true);
+      }
+      ProcessPendingUpdatesForView(mRootView, true);
+      CallDidPaintOnObserver();
+    }
+  } else if (mHasPendingUpdates) {
     ProcessPendingUpdatesForView(mRootView, true);
     mHasPendingUpdates = false;
   }
 }
 
 void
 nsViewManager::UpdateWidgetGeometry()
 {
   if (!IsRootVM()) {
     RootViewManager()->UpdateWidgetGeometry();
     return;
   }
 
   if (mHasPendingWidgetGeometryChanges) {
+    mHasPendingWidgetGeometryChanges = false;
     ProcessPendingUpdatesForView(mRootView, false);
-    mHasPendingWidgetGeometryChanges = false;
   }
 }
 
 void
 nsViewManager::CallWillPaintOnObservers(bool aWillSendDidPaint)
 {
   NS_PRECONDITION(IsRootVM(), "Must be root VM for this to be called!");
 
--- a/view/src/nsViewManager.h
+++ b/view/src/nsViewManager.h
@@ -124,18 +124,17 @@ private:
   void CallDidPaintOnObserver();
   void ReparentChildWidgets(nsIView* aView, nsIWidget *aNewWidget);
   void ReparentWidgets(nsIView* aView, nsIView *aParent);
   void InvalidateWidgetArea(nsView *aWidgetView, const nsRegion &aDamagedRegion);
 
   void InvalidateViews(nsView *aView);
 
   // aView is the view for aWidget and aRegion is relative to aWidget.
-  void Refresh(nsView *aView, nsIWidget *aWidget, const nsIntRegion& aRegion,
-               bool aWillSendDidPaint);
+  void Refresh(nsView *aView, const nsIntRegion& aRegion, bool aWillSendDidPaint);
 
   void InvalidateRectDifference(nsView *aView, const nsRect& aRect, const nsRect& aCutOut);
   void InvalidateHorizontalBandDifference(nsView *aView, const nsRect& aRect, const nsRect& aCutOut,
                                           nscoord aY1, nscoord aY2, bool aInCutOut);
 
   // Utilities
 
   bool IsViewInserted(nsView *aView);
--- a/widget/android/nsWindow.cpp
+++ b/widget/android/nsWindow.cpp
@@ -2307,10 +2307,19 @@ nsWindow::SchedulePauseComposition()
 void
 nsWindow::ScheduleResumeComposition(int width, int height)
 {
     if (sCompositorParent) {
         sCompositorParent->ScheduleResumeOnCompositorThread(width, height);
     }
 }
 
+bool
+nsWindow::NeedsPaint()
+{
+  if (sCompositorPaused || FindTopLevel() != nsWindow::TopWindow()) {
+    return false;
+  }
+  return nsIWidget::NeedsPaint();
+}
+
 #endif
 
--- a/widget/android/nsWindow.h
+++ b/widget/android/nsWindow.h
@@ -143,16 +143,17 @@ public:
     LayerManager* GetLayerManager (PLayersChild* aShadowManager = nullptr,
                                    LayersBackend aBackendHint = mozilla::layers::LAYERS_NONE,
                                    LayerManagerPersistence aPersistence = LAYER_MANAGER_CURRENT,
                                    bool* aAllowRetaining = nullptr);
 
     NS_IMETHOD ReparentNativeWidget(nsIWidget* aNewParent);
 
 #ifdef MOZ_JAVA_COMPOSITOR
+    virtual bool NeedsPaint();
     virtual void DrawWindowUnderlay(LayerManager* aManager, nsIntRect aRect);
     virtual void DrawWindowOverlay(LayerManager* aManager, nsIntRect aRect);
 
     static void SetCompositor(mozilla::layers::CompositorParent* aCompositorParent,
                               mozilla::layers::CompositorChild* aCompositorChild);
     static void ScheduleComposite();
     static void SchedulePauseComposition();
     static void ScheduleResumeComposition(int width, int height);
--- a/widget/cocoa/nsChildView.mm
+++ b/widget/cocoa/nsChildView.mm
@@ -2551,16 +2551,19 @@ NSEvent* gLastDragMouseDownEvent = nil;
     LayerManagerOGL *manager = static_cast<LayerManagerOGL*>(layerManager);
     manager->SetClippingRegion(paintEvent.region);
     glContext = (NSOpenGLContext *)manager->gl()->GetNativeData(mozilla::gl::GLContext::NativeGLContext);
 
     if (!mGLContext) {
       [self setGLContext:glContext];
     }
 
+    [glContext setView:self];
+    [glContext update];
+
     mGeckoChild->DispatchWindowEvent(paintEvent);
 
     // Force OpenGL to refresh the very first time we draw. This works around a
     // Mac OS X bug that stops windows updating on OS X when we use OpenGL.
     if (!mDidForceRefreshOpenGL) {
       [self performSelector:@selector(forceRefreshOpenGL) withObject:nil afterDelay:0];
       mDidForceRefreshOpenGL = YES;
     }
--- a/widget/nsIWidget.h
+++ b/widget/nsIWidget.h
@@ -1588,16 +1588,25 @@ class nsIWidget : public nsISupports {
 
     /**
      * Returns true to indicate that this widget paints an opaque background
      * that we want to be visible under the page, so layout should not force
      * a default background.
      */
     virtual bool WidgetPaintsBackground() { return false; }
 
+    virtual bool NeedsPaint() { 
+      if (!IsVisible()) {
+        return false;
+      }
+      nsIntRect bounds;
+      nsresult rv = GetBounds(bounds);
+      NS_ENSURE_SUCCESS(rv, false);
+      return !bounds.IsEmpty();
+    }
     /**
      * Get the natural bounds of this widget.  This method is only
      * meaningful for widgets for which Gecko implements screen
      * rotation natively.  When this is the case, GetBounds() returns
      * the widget bounds taking rotation into account, and
      * GetNaturalBounds() returns the bounds *not* taking rotation
      * into account.
      *