merge m-c to inbound
authorTim Taubert <ttaubert@mozilla.com>
Thu, 29 May 2014 08:32:31 +0200
changeset 204755 1e712b724d177265b703777d10c0e56e8913838d
parent 204663 c8252fd40ba7a913e05152731237e92d48579b07 (current diff)
parent 204754 ef053c67aac2c2363e3ea40b1e25bded81795ec2 (diff)
child 204762 b35bab926e472dae4c9e99c74c35d66e04810b5c
child 204819 a1c900052e2c5725e64097d34e1d5328e995fa66
push id3741
push userasasaki@mozilla.com
push dateMon, 21 Jul 2014 20:25:18 +0000
treeherdermozilla-beta@4d6f46f5af68 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone32.0a1
first release with
nightly linux32
1e712b724d17 / 32.0a1 / 20140529030207 / files
nightly linux64
1e712b724d17 / 32.0a1 / 20140529030207 / files
nightly mac
1e712b724d17 / 32.0a1 / 20140529030207 / files
nightly win32
1e712b724d17 / 32.0a1 / 20140529030207 / files
nightly win64
1e712b724d17 / 32.0a1 / 20140529030207 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
merge m-c to inbound
gfx/gl/VBOArena.cpp
gfx/gl/VBOArena.h
--- a/browser/base/content/test/general/browser_aboutHome.js
+++ b/browser/base/content/test/general/browser_aboutHome.js
@@ -459,16 +459,17 @@ function promiseSetupSnippetsMap(aTab, a
   info("Waiting for snippets map");
   aTab.linkedBrowser.addEventListener("AboutHomeLoadSnippets", function load(event) {
     aTab.linkedBrowser.removeEventListener("AboutHomeLoadSnippets", load, true);
 
     let cw = aTab.linkedBrowser.contentWindow.wrappedJSObject;
     // The snippets should already be ready by this point. Here we're
     // just obtaining a reference to the snippets map.
     cw.ensureSnippetsMapThen(function (aSnippetsMap) {
+      aSnippetsMap = Cu.waiveXrays(aSnippetsMap);
       info("Got snippets map: " +
            "{ last-update: " + aSnippetsMap.get("snippets-last-update") +
            ", cached-version: " + aSnippetsMap.get("snippets-cached-version") +
            " }");
       // Don't try to update.
       aSnippetsMap.set("snippets-last-update", Date.now());
       aSnippetsMap.set("snippets-cached-version", AboutHomeUtils.snippetsVersion);
       // Clear snippets.
--- a/browser/components/sessionstore/test/browser_500328.js
+++ b/browser/components/sessionstore/test/browser_500328.js
@@ -31,17 +31,23 @@ function checkState(tab) {
       let elem = doc.createElement("div");
       elem.id = "new-elem";
       doc.body.appendChild(elem);
 
       contentWindow.history.forward();
     }
     else if (popStateCount == 1) {
       popStateCount++;
-      is(aEvent.state.obj3.toString(), '/^a$/', "second popstate object.");
+      // When content fires a PopStateEvent and we observe it from a chrome event
+      // listener (as we do here, and, thankfully, nowhere else in the tree), the
+      // state object will be a cross-compartment wrapper to an object that was
+      // deserialized in the content scope. And in this case, since RegExps are
+      // not currently Xrayable (see bug 1014991), trying to pull |obj3| (a RegExp)
+      // off of an Xrayed Object won't work. So we need to waive.
+      is(Cu.waiveXrays(aEvent.state).obj3.toString(), '/^a$/', "second popstate object.");
 
       // Make sure that the new-elem node is present in the document.  If it's
       // not, then this history entry has a different doc identifier than the
       // previous entry, which is bad.
       let doc = contentWindow.document;
       let newElem = doc.getElementById("new-elem");
       ok(newElem, "doc should contain new-elem.");
       newElem.parentNode.removeChild(newElem);
--- a/browser/modules/UITour.jsm
+++ b/browser/modules/UITour.jsm
@@ -630,27 +630,19 @@ this.UITour = {
 
       return uri.spec;
     } catch (e) {}
 
     return null;
   },
 
   sendPageCallback: function(aDocument, aCallbackID, aData = {}) {
-    let detail = Cu.createObjectIn(aDocument.defaultView);
-    detail.data = Cu.createObjectIn(detail);
 
-    for (let key of Object.keys(aData))
-      detail.data[key] = aData[key];
-
-    Cu.makeObjectPropsNormal(detail.data);
-    Cu.makeObjectPropsNormal(detail);
-
-    detail.callbackID = aCallbackID;
-
+    let detail = {data: aData, callbackID: aCallbackID};
+    detail = Cu.cloneInto(detail, aDocument.defaultView);
     let event = new aDocument.defaultView.CustomEvent("mozUITourResponse", {
       bubbles: true,
       detail: detail
     });
 
     aDocument.dispatchEvent(event);
   },
 
--- a/content/base/src/WebSocket.cpp
+++ b/content/base/src/WebSocket.cpp
@@ -6,23 +6,23 @@
 
 #include "WebSocket.h"
 #include "mozilla/dom/WebSocketBinding.h"
 
 #include "jsapi.h"
 #include "jsfriendapi.h"
 #include "js/OldDebugAPI.h"
 #include "mozilla/DOMEventTargetHelper.h"
+#include "mozilla/dom/ScriptSettings.h"
 #include "nsIScriptGlobalObject.h"
 #include "nsIDOMWindow.h"
 #include "nsIDocument.h"
 #include "nsXPCOM.h"
 #include "nsIXPConnect.h"
 #include "nsContentUtils.h"
-#include "nsCxPusher.h"
 #include "nsError.h"
 #include "nsIScriptObjectPrincipal.h"
 #include "nsIURL.h"
 #include "nsIUnicodeEncoder.h"
 #include "nsThreadUtils.h"
 #include "nsIDOMMessageEvent.h"
 #include "nsIPromptFactory.h"
 #include "nsIWindowWatcher.h"
@@ -860,25 +860,24 @@ WebSocket::CreateAndDispatchMessageEvent
                                          bool isBinary)
 {
   NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread");
 
   nsresult rv = CheckInnerWindowCorrectness();
   if (NS_FAILED(rv))
     return NS_OK;
 
-  // Get the JSContext
-  nsCOMPtr<nsIScriptGlobalObject> sgo = do_QueryInterface(GetOwner());
-  NS_ENSURE_TRUE(sgo, NS_ERROR_FAILURE);
+  nsCOMPtr<nsIGlobalObject> globalObject = do_QueryInterface(GetOwner());
+  if (NS_WARN_IF(!globalObject)) {
+    return NS_ERROR_FAILURE;
+  }
 
-  nsIScriptContext* scriptContext = sgo->GetContext();
-  NS_ENSURE_TRUE(scriptContext, NS_ERROR_FAILURE);
-
-  AutoPushJSContext cx(scriptContext->GetNativeContext());
-  NS_ENSURE_TRUE(cx, NS_ERROR_FAILURE);
+  AutoJSAPI jsapi;
+  JSContext* cx = jsapi.cx();
+  JSAutoCompartment ac(cx, globalObject->GetGlobalJSObject());
 
   // Create appropriate JS object for message
   JS::Rooted<JS::Value> jsData(cx);
   if (isBinary) {
     if (mBinaryType == dom::BinaryType::Blob) {
       rv = nsContentUtils::CreateBlobBuffer(cx, aData, &jsData);
       NS_ENSURE_SUCCESS(rv, rv);
     } else if (mBinaryType == dom::BinaryType::Arraybuffer) {
--- a/content/base/src/nsContentUtils.cpp
+++ b/content/base/src/nsContentUtils.cpp
@@ -34,16 +34,17 @@
 #include "mozilla/AutoRestore.h"
 #include "mozilla/Base64.h"
 #include "mozilla/DebugOnly.h"
 #include "mozilla/dom/DocumentFragment.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/HTMLMediaElement.h"
 #include "mozilla/dom/HTMLTemplateElement.h"
 #include "mozilla/dom/HTMLContentElement.h"
+#include "mozilla/dom/ScriptSettings.h"
 #include "mozilla/dom/TextDecoder.h"
 #include "mozilla/dom/TouchEvent.h"
 #include "mozilla/dom/ShadowRoot.h"
 #include "mozilla/EventDispatcher.h"
 #include "mozilla/EventListenerManager.h"
 #include "mozilla/EventStateManager.h"
 #include "mozilla/IMEStateManager.h"
 #include "mozilla/InternalMutationEvent.h"
@@ -5624,16 +5625,18 @@ nsContentUtils::DispatchXULCommand(nsICo
 }
 
 // static
 nsresult
 nsContentUtils::WrapNative(JSContext *cx, nsISupports *native,
                            nsWrapperCache *cache, const nsIID* aIID,
                            JS::MutableHandle<JS::Value> vp, bool aAllowWrapping)
 {
+  MOZ_ASSERT(cx == GetCurrentJSContext());
+
   if (!native) {
     vp.setNull();
 
     return NS_OK;
   }
 
   JSObject *wrapper = xpc_FastGetCachedWrapper(cx, cache, vp);
   if (wrapper) {
@@ -5643,18 +5646,17 @@ nsContentUtils::WrapNative(JSContext *cx
   NS_ENSURE_TRUE(sXPConnect, NS_ERROR_UNEXPECTED);
 
   if (!NS_IsMainThread()) {
     MOZ_CRASH();
   }
 
   nsresult rv = NS_OK;
   JS::Rooted<JSObject*> scope(cx, JS::CurrentGlobalOrNull(cx));
-  AutoPushJSContext context(cx);
-  rv = sXPConnect->WrapNativeToJSVal(context, scope, native, cache, aIID,
+  rv = sXPConnect->WrapNativeToJSVal(cx, scope, native, cache, aIID,
                                      aAllowWrapping, vp);
   return rv;
 }
 
 nsresult
 nsContentUtils::CreateArrayBuffer(JSContext *aCx, const nsACString& aData,
                                   JSObject** aResult)
 {
@@ -6106,21 +6108,25 @@ nsContentUtils::GetContentSecurityPolicy
 }
 
 // static
 bool
 nsContentUtils::IsPatternMatching(nsAString& aValue, nsAString& aPattern,
                                   nsIDocument* aDocument)
 {
   NS_ASSERTION(aDocument, "aDocument should be a valid pointer (not null)");
-  nsCOMPtr<nsIScriptGlobalObject> sgo = do_QueryInterface(aDocument->GetWindow());
-  NS_ENSURE_TRUE(sgo, true);
-
-  AutoPushJSContext cx(sgo->GetContext()->GetNativeContext());
-  NS_ENSURE_TRUE(cx, true);
+  nsCOMPtr<nsIGlobalObject> globalObject =
+    do_QueryInterface(aDocument->GetWindow());
+  if (NS_WARN_IF(!globalObject)) {
+    return true;
+  }
+
+  AutoJSAPI jsapi;
+  JSContext* cx = jsapi.cx();
+  JSAutoCompartment ac(cx, globalObject->GetGlobalJSObject());
 
   // The pattern has to match the entire value.
   aPattern.Insert(NS_LITERAL_STRING("^(?:"), 0);
   aPattern.AppendLiteral(")$");
 
   JS::Rooted<JSObject*> re(cx,
     JS_NewUCRegExpObjectNoStatics(cx,
                                   static_cast<jschar*>(aPattern.BeginWriting()),
--- a/content/base/src/nsDOMDataChannel.cpp
+++ b/content/base/src/nsDOMDataChannel.cpp
@@ -21,21 +21,21 @@ extern PRLogModuleInfo* GetDataChannelLo
 
 
 #include "nsDOMDataChannelDeclarations.h"
 #include "nsDOMDataChannel.h"
 #include "nsIDOMFile.h"
 #include "nsIDOMDataChannel.h"
 #include "nsIDOMMessageEvent.h"
 #include "mozilla/DOMEventTargetHelper.h"
+#include "mozilla/dom/ScriptSettings.h"
 
 #include "nsError.h"
 #include "nsAutoPtr.h"
 #include "nsContentUtils.h"
-#include "nsCxPusher.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsIScriptObjectPrincipal.h"
 #include "nsNetUtil.h"
 #include "nsDOMFile.h"
 
 #include "DataChannel.h"
 
 // Since we've moved the windows.h include down here, we have to explicitly
@@ -377,24 +377,25 @@ nsDOMDataChannel::DoOnMessageAvailable(c
   MOZ_ASSERT(NS_IsMainThread());
 
   LOG(("DoOnMessageAvailable%s\n",aBinary ? ((mBinaryType == DC_BINARY_TYPE_BLOB) ? " (blob)" : " (binary)") : ""));
 
   nsresult rv = CheckInnerWindowCorrectness();
   if (NS_FAILED(rv)) {
     return NS_OK;
   }
-  nsCOMPtr<nsIScriptGlobalObject> sgo = do_QueryInterface(GetOwner());
-  NS_ENSURE_TRUE(sgo, NS_ERROR_FAILURE);
 
-  nsIScriptContext* sc = sgo->GetContext();
-  NS_ENSURE_TRUE(sc, NS_ERROR_FAILURE);
+  nsCOMPtr<nsIGlobalObject> globalObject = do_QueryInterface(GetOwner());
+  if (NS_WARN_IF(!globalObject)) {
+    return NS_ERROR_FAILURE;
+  }
 
-  AutoPushJSContext cx(sc->GetNativeContext());
-  NS_ENSURE_TRUE(cx, NS_ERROR_FAILURE);
+  AutoJSAPI jsapi;
+  JSContext* cx = jsapi.cx();
+  JSAutoCompartment ac(cx, globalObject->GetGlobalJSObject());
 
   JS::Rooted<JS::Value> jsData(cx);
 
   if (aBinary) {
     if (mBinaryType == DC_BINARY_TYPE_BLOB) {
       rv = nsContentUtils::CreateBlobBuffer(cx, aData, &jsData);
       NS_ENSURE_SUCCESS(rv, rv);
     } else if (mBinaryType == DC_BINARY_TYPE_ARRAYBUFFER) {
--- a/content/base/src/nsScriptLoader.cpp
+++ b/content/base/src/nsScriptLoader.cpp
@@ -887,18 +887,20 @@ nsScriptLoader::AttemptAsyncScriptParse(
     return NS_ERROR_FAILURE;
   }
 
   nsCOMPtr<nsIScriptContext> context = globalObject->GetScriptContext();
   if (!context) {
     return NS_ERROR_FAILURE;
   }
 
-  AutoPushJSContext cx(context->GetNativeContext());
+  AutoJSAPIWithErrorsReportedToWindow jsapi(context);
+  JSContext* cx = jsapi.cx();
   JS::Rooted<JSObject*> global(cx, globalObject->GetGlobalJSObject());
+  JSAutoCompartment ac(cx, global);
 
   JS::CompileOptions options(cx);
   FillCompileOptionsForRequest(aRequest, global, &options);
 
   if (!JS::CanCompileOffThread(cx, options, aRequest->mScriptTextLength)) {
     return NS_ERROR_FAILURE;
   }
 
--- a/content/base/test/chrome/cpows_parent.xul
+++ b/content/base/test/chrome/cpows_parent.xul
@@ -30,18 +30,24 @@
     // Make sure that an error in this file actually causes the test to fail.
     window.onerror = function (msg, url, line) {
       ok(false, "Error while executing: \n" + msg + "\n" + url + ":" + line);
     };
 
     function testCpowMessage(message) {
       ok(message.json.check == "ok", "correct json");
 
+      ok(!Components.utils.isCrossProcessWrapper(message.json), "not everything is a CPOW");
+
       let data = message.objects.data;
       let document = message.objects.document;
+      if (test_state == "remote") {
+        ok(Components.utils.isCrossProcessWrapper(data), "got a CPOW");
+        ok(Components.utils.isCrossProcessWrapper(document), "got a CPOW");
+      }
       ok(data.i === 5, "integer property");
       ok(data.b === true, "boolean property");
       ok(data.s === "hello", "string property");
       ok(data.x.i === 10, "nested property");
       ok(data.f() === 99, "function call");
       ok(document.title === "Hello, Kitty", "document node");
 
       data.i = 6;
--- a/content/canvas/src/WebGLContext.cpp
+++ b/content/canvas/src/WebGLContext.cpp
@@ -978,16 +978,17 @@ void
 WebGLContext::ForceClearFramebufferWithDefaultValues(GLbitfield mask, const bool colorAttachmentsMask[kMaxColorAttachments])
 {
     MakeContextCurrent();
 
     bool initializeColorBuffer = 0 != (mask & LOCAL_GL_COLOR_BUFFER_BIT);
     bool initializeDepthBuffer = 0 != (mask & LOCAL_GL_DEPTH_BUFFER_BIT);
     bool initializeStencilBuffer = 0 != (mask & LOCAL_GL_STENCIL_BUFFER_BIT);
     bool drawBuffersIsEnabled = IsExtensionEnabled(WebGLExtensionID::WEBGL_draw_buffers);
+    bool shouldOverrideDrawBuffers = false;
 
     GLenum currentDrawBuffers[WebGLContext::kMaxColorAttachments];
 
     // Fun GL fact: No need to worry about the viewport here, glViewport is just
     // setting up a coordinates transformation, it doesn't affect glClear at all.
     AssertCachedState(); // Can't check cached bindings, as we could
                          // have a different FB bound temporarily.
 
@@ -1003,19 +1004,23 @@ WebGLContext::ForceClearFramebufferWithD
             for(int32_t i = 0; i < mGLMaxDrawBuffers; i++) {
                 GLint temp;
                 gl->fGetIntegerv(LOCAL_GL_DRAW_BUFFER0 + i, &temp);
                 currentDrawBuffers[i] = temp;
 
                 if (colorAttachmentsMask[i]) {
                     drawBuffersCommand[i] = LOCAL_GL_COLOR_ATTACHMENT0 + i;
                 }
+                if (currentDrawBuffers[i] != drawBuffersCommand[i])
+                    shouldOverrideDrawBuffers = true;
             }
-
-            gl->fDrawBuffers(mGLMaxDrawBuffers, drawBuffersCommand);
+            // calling draw buffers can cause resolves on adreno drivers so
+            // we try to avoid calling it
+            if (shouldOverrideDrawBuffers)
+                gl->fDrawBuffers(mGLMaxDrawBuffers, drawBuffersCommand);
         }
 
         gl->fColorMask(1, 1, 1, 1);
         gl->fClearColor(0.0f, 0.0f, 0.0f, 0.0f);
     }
 
     if (initializeDepthBuffer) {
         gl->fDepthMask(1);
@@ -1042,17 +1047,17 @@ WebGLContext::ForceClearFramebufferWithD
         gl->fEnable(LOCAL_GL_SCISSOR_TEST);
 
     if (mRasterizerDiscardEnabled) {
         gl->fEnable(LOCAL_GL_RASTERIZER_DISCARD);
     }
 
     // Restore GL state after clearing.
     if (initializeColorBuffer) {
-        if (drawBuffersIsEnabled) {
+        if (shouldOverrideDrawBuffers) {
             gl->fDrawBuffers(mGLMaxDrawBuffers, currentDrawBuffers);
         }
 
         gl->fColorMask(mColorWriteMask[0],
                        mColorWriteMask[1],
                        mColorWriteMask[2],
                        mColorWriteMask[3]);
         gl->fClearColor(mColorClearValue[0],
--- a/content/canvas/src/WebGLElementArrayCache.cpp
+++ b/content/canvas/src/WebGLElementArrayCache.cpp
@@ -1,16 +1,15 @@
 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /* 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 "WebGLElementArrayCache.h"
 
-#include "nsTArray.h"
 #include "mozilla/Assertions.h"
 #include "mozilla/MemoryReporting.h"
 
 #include <cstdlib>
 #include <cstring>
 #include <limits>
 #include <algorithm>
 
@@ -83,19 +82,19 @@ UpdateUpperBound(uint32_t* out_upperBoun
  *
  *   sElementsPerLeaf = 2 ^ sSkippedBottomTreeLevels.
  *
  * *** Storage layout of the binary tree ***
  *
  * We take advantage of the specifics of the situation to avoid generalist tree storage and instead
  * store the tree entries in a vector, mTreeData.
  *
- * The number of leaves is given by mNumLeaves, and mTreeData is always a vector of length
+ * TreeData is always a vector of length
  *
- *    2 * mNumLeaves.
+ *    2 * (number of leaves).
  *
  * Its data layout is as follows: mTreeData[0] is unused, mTreeData[1] is the root node,
  * then at offsets 2..3 is the tree level immediately below the root node, then at offsets 4..7
  * is the tree level below that, etc.
  *
  * The figure below illustrates this by writing at each tree node the offset into mTreeData at
  * which it is stored:
  *
@@ -138,30 +137,31 @@ struct WebGLElementArrayCacheTree
   // A too-high sSkippedBottomTreeLevels would harm the performance of small drawElements calls
   // A too-low sSkippedBottomTreeLevels would cause undue memory usage.
   // The current value has been validated by some benchmarking. See bug 732660.
   static const size_t sSkippedBottomTreeLevels = 3;
   static const size_t sElementsPerLeaf = 1 << sSkippedBottomTreeLevels;
   static const size_t sElementsPerLeafMask = sElementsPerLeaf - 1; // sElementsPerLeaf is POT
 
 private:
+
+  // The WebGLElementArrayCache that owns this tree
   WebGLElementArrayCache& mParent;
+
+  // The tree's internal data storage. Its length is 2 * (number of leaves)
+  // because of its data layout explained in the above class comment.
   FallibleTArray<T> mTreeData;
-  size_t mNumLeaves;
-  size_t mParentByteSize;
 
 public:
+  // Constructor. Takes a reference to the WebGLElementArrayCache that is to be
+  // the parent. Does not initialize the tree. Should be followed by a call
+  // to Update() to attempt initializing the tree.
   WebGLElementArrayCacheTree(WebGLElementArrayCache& p)
     : mParent(p)
-    , mNumLeaves(0)
-    , mParentByteSize(0)
   {
-    if (mParent.ByteSize()) {
-      Update(0, mParent.ByteSize() - 1);
-    }
   }
 
   T GlobalMaximum() const {
     return mTreeData[1];
   }
 
   // returns the index of the parent node; if treeIndex=1 (the root node),
   // the return value is 0.
@@ -200,31 +200,36 @@ public:
     return treeIndex - distance;
   }
 
   static size_t RightNeighborNode(size_t treeIndex, size_t distance = 1) {
     MOZ_ASSERT(treeIndex > 1);
     return treeIndex + distance;
   }
 
-  size_t LeafForElement(size_t element) {
+  size_t NumLeaves() const {
+    // see class comment for why we the tree storage size is 2 * numLeaves
+    return mTreeData.Length() >> 1;
+  }
+
+  size_t LeafForElement(size_t element) const {
     size_t leaf = element / sElementsPerLeaf;
-    MOZ_ASSERT(leaf < mNumLeaves);
+    MOZ_ASSERT(leaf < NumLeaves());
     return leaf;
   }
 
-  size_t LeafForByte(size_t byte) {
+  size_t LeafForByte(size_t byte) const {
     return LeafForElement(byte / sizeof(T));
   }
 
   // Returns the index, into the tree storage, where a given leaf is stored
-  size_t TreeIndexForLeaf(size_t leaf) {
-    // See above class comment. The tree storage is an array of length 2*mNumLeaves.
+  size_t TreeIndexForLeaf(size_t leaf) const {
+    // See above class comment. The tree storage is an array of length 2 * numLeaves.
     // The leaves are stored in its second half.
-    return leaf + mNumLeaves;
+    return leaf + NumLeaves();
   }
 
   static size_t LastElementUnderSameLeaf(size_t element) {
     return element | sElementsPerLeafMask;
   }
 
   static size_t FirstElementUnderSameLeaf(size_t element) {
     return element & ~sElementsPerLeafMask;
@@ -293,105 +298,125 @@ public:
     U result = 1;
     while (result < x)
       result <<= 1;
     MOZ_ASSERT(result >= x);
     MOZ_ASSERT((result & (result - 1)) == 0);
     return result;
   }
 
+  // Updates the tree from the parent's buffer contents. Fallible, as it
+  // may have to resize the tree storage.
   bool Update(size_t firstByte, size_t lastByte);
 
   size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
   {
     return aMallocSizeOf(this) + mTreeData.SizeOfExcludingThis(aMallocSizeOf);
   }
 };
 
 // TreeForType: just a template helper to select the right tree object for a given
 // element type.
 template<typename T>
 struct TreeForType {};
 
 template<>
 struct TreeForType<uint8_t>
 {
-  static WebGLElementArrayCacheTree<uint8_t>*& Run(WebGLElementArrayCache *b) { return b->mUint8Tree; }
+  static ScopedDeletePtr<WebGLElementArrayCacheTree<uint8_t>>&
+  Value(WebGLElementArrayCache *b) {
+    return b->mUint8Tree;
+  }
 };
 
 template<>
 struct TreeForType<uint16_t>
 {
-  static WebGLElementArrayCacheTree<uint16_t>*& Run(WebGLElementArrayCache *b) { return b->mUint16Tree; }
+  static ScopedDeletePtr<WebGLElementArrayCacheTree<uint16_t>>&
+  Value(WebGLElementArrayCache *b) {
+    return b->mUint16Tree;
+  }
 };
 
 template<>
 struct TreeForType<uint32_t>
 {
-  static WebGLElementArrayCacheTree<uint32_t>*& Run(WebGLElementArrayCache *b) { return b->mUint32Tree; }
+  static ScopedDeletePtr<WebGLElementArrayCacheTree<uint32_t>>&
+  Value(WebGLElementArrayCache *b) {
+    return b->mUint32Tree;
+  }
 };
 
 // Calling this method will 1) update the leaves in this interval
 // from the raw buffer data, and 2) propagate this update up the tree
 template<typename T>
 bool WebGLElementArrayCacheTree<T>::Update(size_t firstByte, size_t lastByte)
 {
   MOZ_ASSERT(firstByte <= lastByte);
-  MOZ_ASSERT(lastByte < mParent.ByteSize());
+  MOZ_ASSERT(lastByte < mParent.mBytes.Length());
+
+  size_t numberOfElements = mParent.mBytes.Length() / sizeof(T);
+  size_t requiredNumLeaves = 0;
+  if (numberOfElements > 0) {
+    // If we didn't require the number of leaves to be a power of two, then
+    // it would just be equal to
+    //
+    //    ceil(numberOfElements / sElementsPerLeaf)
+    //
+    // The way we implement this (division+ceil) operation in integer arithmetic
+    // is as follows:
+    size_t numLeavesNonPOT = (numberOfElements + sElementsPerLeaf - 1) / sElementsPerLeaf;
+    // It only remains to round that up to the next power of two:
+    requiredNumLeaves = NextPowerOfTwo(numLeavesNonPOT);
+  }
 
   // Step #0: if needed, resize our tree data storage.
-  if (mParentByteSize != mParent.ByteSize())
-  {
-    size_t numberOfElements = mParent.ByteSize() / sizeof(T);
-    if (numberOfElements == 0) {
-      mParentByteSize = mParent.ByteSize();
-      return true;
+  if (requiredNumLeaves != NumLeaves()) {
+    // see class comment for why we the tree storage size is 2 * numLeaves
+    if (!mTreeData.SetLength(2 * requiredNumLeaves)) {
+      mTreeData.SetLength(0);
+      return false;
     }
+    MOZ_ASSERT(NumLeaves() == requiredNumLeaves);
 
-    size_t requiredNumLeaves = (numberOfElements + sElementsPerLeaf - 1) / sElementsPerLeaf;
-    size_t oldNumLeaves = mNumLeaves;
-    mNumLeaves = NextPowerOfTwo(requiredNumLeaves);
-    if (mNumLeaves != oldNumLeaves) {
-      // see class comment for why we the tree storage size is 2 * mNumLeaves
-      if (!mTreeData.SetLength(2 * mNumLeaves)) {
-        return false;
-      }
+    if (NumLeaves()) {
       // when resizing, update the whole tree, not just the subset corresponding
       // to the part of the buffer being updated.
       memset(mTreeData.Elements(), 0, mTreeData.Length() * sizeof(T));
       firstByte = 0;
-      lastByte = mParent.ByteSize() - 1;
+      lastByte = mParent.mBytes.Length() - 1;
     }
-
-    mParentByteSize = mParent.ByteSize();
   }
 
-  lastByte = std::min(lastByte, mNumLeaves * sElementsPerLeaf * sizeof(T) - 1);
+  if (NumLeaves() == 0) {
+    return true;
+  }
+
+  lastByte = std::min(lastByte, NumLeaves() * sElementsPerLeaf * sizeof(T) - 1);
   if (firstByte > lastByte) {
     return true;
   }
 
   size_t firstLeaf = LeafForByte(firstByte);
   size_t lastLeaf = LeafForByte(lastByte);
 
-  MOZ_ASSERT(firstLeaf <= lastLeaf && lastLeaf < mNumLeaves);
+  MOZ_ASSERT(firstLeaf <= lastLeaf && lastLeaf < NumLeaves());
 
   size_t firstTreeIndex = TreeIndexForLeaf(firstLeaf);
   size_t lastTreeIndex = TreeIndexForLeaf(lastLeaf);
 
   // Step #1: initialize the tree leaves from plain buffer data.
   // That is, each tree leaf must be set to the max of the |sElementsPerLeaf| corresponding
   // buffer entries.
   // condition-less scope to prevent leaking this scope's variables into the code below
   {
     // treeIndex is the index of the tree leaf we're writing, i.e. the destination index
     size_t treeIndex = firstTreeIndex;
     // srcIndex is the index in the source buffer
     size_t srcIndex = firstLeaf * sElementsPerLeaf;
-    size_t numberOfElements = mParentByteSize / sizeof(T);
     while (treeIndex <= lastTreeIndex) {
       T m = 0;
       size_t a = srcIndex;
       size_t srcIndexNextLeaf = std::min(a + sElementsPerLeaf, numberOfElements);
       for (; srcIndex < srcIndexNextLeaf; srcIndex++) {
         m = std::max(m, mParent.Element<T>(srcIndex));
       }
       mTreeData[treeIndex] = m;
@@ -407,83 +432,58 @@ bool WebGLElementArrayCacheTree<T>::Upda
     lastTreeIndex = ParentNode(lastTreeIndex);
 
     // fast-exit case where only one node is updated at the current level
     if (firstTreeIndex == lastTreeIndex) {
       mTreeData[firstTreeIndex] = std::max(mTreeData[LeftChildNode(firstTreeIndex)], mTreeData[RightChildNode(firstTreeIndex)]);
       continue;
     }
 
-    // initialize local iteration variables: child and parent.
     size_t child = LeftChildNode(firstTreeIndex);
     size_t parent = firstTreeIndex;
-
-    // the unrolling makes this look more complicated than it is; the plain non-unrolled
-    // version is in the second while loop below
-    const int unrollSize = 8;
-    while (RightNeighborNode(parent, unrollSize - 1) <= lastTreeIndex)
-    {
-      for (int unroll = 0; unroll < unrollSize; unroll++)
-      {
-        T a = mTreeData[child];
-        child = RightNeighborNode(child);
-        T b = mTreeData[child];
-        child = RightNeighborNode(child);
-        mTreeData[parent] = std::max(a, b);
-        parent = RightNeighborNode(parent);
-      }
-    }
-    // plain non-unrolled version, used to terminate the job after the last unrolled iteration
     while (parent <= lastTreeIndex)
     {
       T a = mTreeData[child];
       child = RightNeighborNode(child);
       T b = mTreeData[child];
       child = RightNeighborNode(child);
       mTreeData[parent] = std::max(a, b);
       parent = RightNeighborNode(parent);
     }
   }
 
   return true;
 }
 
+WebGLElementArrayCache::WebGLElementArrayCache() {
+}
+
 WebGLElementArrayCache::~WebGLElementArrayCache() {
-  delete mUint8Tree;
-  delete mUint16Tree;
-  delete mUint32Tree;
-  free(mUntypedData);
 }
 
-bool WebGLElementArrayCache::BufferData(const void* ptr, size_t byteSize) {
-  if (byteSize == 0) {
-    mByteSize = 0;
-    free(mUntypedData);
-    mUntypedData = nullptr;
-    return true;
+bool WebGLElementArrayCache::BufferData(const void* ptr, size_t byteLength) {
+  if (mBytes.Length() != byteLength) {
+    if (!mBytes.SetLength(byteLength)) {
+      mBytes.SetLength(0);
+      return false;
+    }
   }
-  if (byteSize != mByteSize) {
-    void* newUntypedData = realloc(mUntypedData, byteSize);
-    if (!newUntypedData)
-      return false;
-    mByteSize = byteSize;
-    mUntypedData = newUntypedData;
-  }
-
-  BufferSubData(0, ptr, byteSize);
-  return true;
+  MOZ_ASSERT(mBytes.Length() == byteLength);
+  return BufferSubData(0, ptr, byteLength);
 }
 
-bool WebGLElementArrayCache::BufferSubData(size_t pos, const void* ptr, size_t updateByteSize) {
-  if (!updateByteSize) return true;
+bool WebGLElementArrayCache::BufferSubData(size_t pos, const void* ptr, size_t updateByteLength) {
+  MOZ_ASSERT(pos + updateByteLength <= mBytes.Length());
+  if (!updateByteLength)
+    return true;
   if (ptr)
-      memcpy(static_cast<uint8_t*>(mUntypedData) + pos, ptr, updateByteSize);
+    memcpy(mBytes.Elements() + pos, ptr, updateByteLength);
   else
-      memset(static_cast<uint8_t*>(mUntypedData) + pos, 0, updateByteSize);
-  return UpdateTrees(pos, pos + updateByteSize - 1);
+    memset(mBytes.Elements() + pos, 0, updateByteLength);
+  return UpdateTrees(pos, pos + updateByteLength - 1);
 }
 
 bool WebGLElementArrayCache::UpdateTrees(size_t firstByte, size_t lastByte)
 {
   bool result = true;
   if (mUint8Tree)
     result &= mUint8Tree->Update(firstByte, lastByte);
   if (mUint16Tree)
@@ -508,22 +508,31 @@ WebGLElementArrayCache::Validate(uint32_
   }
 
   T maxAllowedT(maxAllowed);
 
   // integer overflow must have been handled earlier, so we assert that maxAllowedT
   // is exactly the max allowed value.
   MOZ_ASSERT(uint32_t(maxAllowedT) == maxAllowed);
 
-  if (!mByteSize || !countElements)
+  if (!mBytes.Length() || !countElements)
     return true;
 
-  WebGLElementArrayCacheTree<T>*& tree = TreeForType<T>::Run(this);
+  ScopedDeletePtr<WebGLElementArrayCacheTree<T>>& tree = TreeForType<T>::Value(this);
   if (!tree) {
     tree = new WebGLElementArrayCacheTree<T>(*this);
+    if (mBytes.Length()) {
+      bool valid = tree->Update(0, mBytes.Length() - 1);
+      if (!valid) {
+        // Do not assert here. This case would happen if an allocation failed.
+        // We've already settled on fallible allocations around here.
+        tree = nullptr;
+        return false;
+      }
+    }
   }
 
   size_t lastElement = firstElement + countElements - 1;
 
   // fast exit path when the global maximum for the whole element array buffer
   // falls in the allowed range
   T globalMax = tree->GlobalMaximum();
   if (globalMax <= maxAllowedT)
@@ -532,26 +541,26 @@ WebGLElementArrayCache::Validate(uint32_
     return true;
   }
 
   const T* elements = Elements<T>();
 
   // before calling tree->Validate, we have to validate ourselves the boundaries of the elements span,
   // to round them to the nearest multiple of sElementsPerLeaf.
   size_t firstElementAdjustmentEnd = std::min(lastElement,
-                                            tree->LastElementUnderSameLeaf(firstElement));
+                                              tree->LastElementUnderSameLeaf(firstElement));
   while (firstElement <= firstElementAdjustmentEnd) {
     const T& curData = elements[firstElement];
     UpdateUpperBound(out_upperBound, curData);
     if (curData > maxAllowedT)
       return false;
     firstElement++;
   }
   size_t lastElementAdjustmentEnd = std::max(firstElement,
-                                           tree->FirstElementUnderSameLeaf(lastElement));
+                                             tree->FirstElementUnderSameLeaf(lastElement));
   while (lastElement >= lastElementAdjustmentEnd) {
     const T& curData = elements[lastElement];
     UpdateUpperBound(out_upperBound, curData);
     if (curData > maxAllowedT)
       return false;
     lastElement--;
   }
 
@@ -584,15 +593,15 @@ WebGLElementArrayCache::Validate(GLenum 
 
 size_t
 WebGLElementArrayCache::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
 {
   size_t uint8TreeSize  = mUint8Tree  ? mUint8Tree->SizeOfIncludingThis(aMallocSizeOf) : 0;
   size_t uint16TreeSize = mUint16Tree ? mUint16Tree->SizeOfIncludingThis(aMallocSizeOf) : 0;
   size_t uint32TreeSize = mUint32Tree ? mUint32Tree->SizeOfIncludingThis(aMallocSizeOf) : 0;
   return aMallocSizeOf(this) +
-          mByteSize +
+          mBytes.SizeOfExcludingThis(aMallocSizeOf) +
           uint8TreeSize +
           uint16TreeSize +
           uint32TreeSize;
 }
 
 } // end namespace mozilla
--- a/content/canvas/src/WebGLElementArrayCache.h
+++ b/content/canvas/src/WebGLElementArrayCache.h
@@ -2,16 +2,18 @@
 /* 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/. */
 
 #ifndef WEBGLELEMENTARRAYCACHE_H
 #define WEBGLELEMENTARRAYCACHE_H
 
 #include "mozilla/MemoryReporting.h"
+#include "mozilla/Scoped.h"
+#include "nsTArray.h"
 #include <stdint.h>
 #include "nscore.h"
 #include "GLDefs.h"
 
 namespace mozilla {
 
 template<typename T>
 struct WebGLElementArrayCacheTree;
@@ -25,62 +27,51 @@ struct WebGLElementArrayCacheTree;
  *    data is fed into the cache
  *
  * Most of the implementation is hidden in the auxilary class template, WebGLElementArrayCacheTree.
  * Refer to its code for design comments.
  */
 class WebGLElementArrayCache {
 
 public:
-  bool BufferData(const void* ptr, size_t byteSize);
+  bool BufferData(const void* ptr, size_t byteLength);
   bool BufferSubData(size_t pos, const void* ptr, size_t updateByteSize);
 
   bool Validate(GLenum type, uint32_t maxAllowed, size_t first, size_t count,
                 uint32_t* out_upperBound = nullptr);
 
   template<typename T>
   T Element(size_t i) const { return Elements<T>()[i]; }
 
-  WebGLElementArrayCache()
-    : mUntypedData(nullptr)
-    , mByteSize(0)
-    , mUint8Tree(nullptr)
-    , mUint16Tree(nullptr)
-    , mUint32Tree(nullptr)
-  {}
+  WebGLElementArrayCache();
 
   ~WebGLElementArrayCache();
 
   size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
 
 private:
 
   template<typename T>
   bool Validate(uint32_t maxAllowed, size_t first, size_t count,
                 uint32_t* out_upperBound);
 
-  size_t ByteSize() const {
-    return mByteSize;
-  }
-
   template<typename T>
-  const T* Elements() const { return static_cast<const T*>(mUntypedData); }
+  const T* Elements() const { return reinterpret_cast<const T*>(mBytes.Elements()); }
   template<typename T>
-  T* Elements() { return static_cast<T*>(mUntypedData); }
+  T* Elements() { return reinterpret_cast<T*>(mBytes.Elements()); }
 
   bool UpdateTrees(size_t firstByte, size_t lastByte);
 
   template<typename T>
   friend struct WebGLElementArrayCacheTree;
   template<typename T>
   friend struct TreeForType;
 
-  void* mUntypedData;
-  size_t mByteSize;
-  WebGLElementArrayCacheTree<uint8_t>* mUint8Tree;
-  WebGLElementArrayCacheTree<uint16_t>* mUint16Tree;
-  WebGLElementArrayCacheTree<uint32_t>* mUint32Tree;
+  FallibleTArray<uint8_t> mBytes;
+  ScopedDeletePtr<WebGLElementArrayCacheTree<uint8_t>> mUint8Tree;
+  ScopedDeletePtr<WebGLElementArrayCacheTree<uint16_t>> mUint16Tree;
+  ScopedDeletePtr<WebGLElementArrayCacheTree<uint32_t>> mUint32Tree;
 };
 
 
 } // end namespace mozilla
 
 #endif // WEBGLELEMENTARRAYCACHE_H
--- a/content/svg/content/src/SVGPathData.cpp
+++ b/content/svg/content/src/SVGPathData.cpp
@@ -33,16 +33,17 @@ static bool IsMoveto(uint16_t aSegType)
 
 nsresult
 SVGPathData::CopyFrom(const SVGPathData& rhs)
 {
   if (!mData.SetCapacity(rhs.mData.Length())) {
     // Yes, we do want fallible alloc here
     return NS_ERROR_OUT_OF_MEMORY;
   }
+  mCachedPath = nullptr;
   mData = rhs.mData;
   return NS_OK;
 }
 
 void
 SVGPathData::GetValueAsString(nsAString& aValue) const
 {
   // we need this function in DidChangePathSegList
@@ -67,28 +68,31 @@ SVGPathData::GetValueAsString(nsAString&
 
 nsresult
 SVGPathData::SetValueFromString(const nsAString& aValue)
 {
   // We don't use a temp variable since the spec says to parse everything up to
   // the first error. We still return any error though so that callers know if
   // there's a problem.
 
+  mCachedPath = nullptr;
   nsSVGPathDataParser pathParser(aValue, this);
   return pathParser.Parse() ? NS_OK : NS_ERROR_DOM_SYNTAX_ERR;
 }
 
 nsresult
 SVGPathData::AppendSeg(uint32_t aType, ...)
 {
   uint32_t oldLength = mData.Length();
   uint32_t newLength = oldLength + 1 + SVGPathSegUtils::ArgCountForType(aType);
   if (!mData.SetLength(newLength)) {
     return NS_ERROR_OUT_OF_MEMORY;
   }
+  mCachedPath = nullptr;
+
   mData[oldLength] = SVGPathSegUtils::EncodeType(aType);
   va_list args;
   va_start(args, aType);
   for (uint32_t i = oldLength + 1; i < newLength; ++i) {
     // NOTE! 'float' is promoted to 'double' when passed through '...'!
     mData[i] = float(va_arg(args, double));
   }
   va_end(args);
@@ -812,17 +816,21 @@ SVGPathData::ToPathForLengthOrPositionMe
   // Since the path that we return will not be used for painting it doesn't
   // matter what we pass to BuildPath as aFillRule. Hawever, we do want to
   // pass something other than NS_STYLE_STROKE_LINECAP_SQUARE as aStrokeLineCap
   // to avoid the insertion of extra little lines (by
   // ApproximateZeroLengthSubpathSquareCaps), in which case the value that we
   // pass as aStrokeWidth doesn't matter (since it's only used to determine the
   // length of those extra little lines).
 
-  return BuildPath(FillRule::FILL_WINDING, NS_STYLE_STROKE_LINECAP_BUTT, 0);
+  if (!mCachedPath) {
+    mCachedPath = BuildPath(FillRule::FILL_WINDING, NS_STYLE_STROKE_LINECAP_BUTT, 0);
+  }
+
+  return mCachedPath;
 }
 
 static double
 AngleOfVector(const Point& aVector)
 {
   // C99 says about atan2 "A domain error may occur if both arguments are
   // zero" and "On a domain error, the function returns an implementation-
   // defined value". In the case of atan2 the implementation-defined value
--- a/content/svg/content/src/SVGPathData.h
+++ b/content/svg/content/src/SVGPathData.h
@@ -190,47 +190,51 @@ protected:
 
   /**
    * This may fail on OOM if the internal capacity needs to be increased, in
    * which case the list will be left unmodified.
    */
   nsresult CopyFrom(const SVGPathData& rhs);
 
   float& operator[](uint32_t aIndex) {
+    mCachedPath = nullptr;
     return mData[aIndex];
   }
 
   /**
    * This may fail (return false) on OOM if the internal capacity is being
    * increased, in which case the list will be left unmodified.
    */
   bool SetLength(uint32_t aLength) {
+    mCachedPath = nullptr;
     return mData.SetLength(aLength);
   }
 
   nsresult SetValueFromString(const nsAString& aValue);
 
   void Clear() {
+    mCachedPath = nullptr;
     mData.Clear();
   }
 
   // Our DOM wrappers have direct access to our mData, so they directly
   // manipulate it rather than us implementing:
   //
   // * InsertItem(uint32_t aDataIndex, uint32_t aType, const float *aArgs);
   // * ReplaceItem(uint32_t aDataIndex, uint32_t aType, const float *aArgs);
   // * RemoveItem(uint32_t aDataIndex);
   // * bool AppendItem(uint32_t aType, const float *aArgs);
 
   nsresult AppendSeg(uint32_t aType, ...); // variable number of float args
 
-  iterator begin() { return mData.Elements(); }
-  iterator end() { return mData.Elements() + mData.Length(); }
+  iterator begin() { mCachedPath = nullptr; return mData.Elements(); }
+  iterator end() { mCachedPath = nullptr; return mData.Elements() + mData.Length(); }
 
   FallibleTArray<float> mData;
+  mutable RefPtr<gfx::Path> mCachedPath;
 };
 
 
 /**
  * This SVGPathData subclass is for SVGPathSegListSMILType which needs to
  * have write access to the lists it works with.
  *
  * Instances of this class do not have DOM wrappers that need to be kept in
--- a/content/xul/document/src/nsXULPrototypeDocument.cpp
+++ b/content/xul/document/src/nsXULPrototypeDocument.cpp
@@ -21,25 +21,22 @@
 #include "jsfriendapi.h"
 #include "nsString.h"
 #include "nsIConsoleService.h"
 #include "nsIScriptError.h"
 #include "nsIDOMScriptObjectFactory.h"
 #include "nsDOMCID.h"
 #include "nsNodeInfoManager.h"
 #include "nsContentUtils.h"
-#include "nsCxPusher.h"
 #include "nsCCUncollectableMarker.h"
 #include "nsDOMJSUtils.h" // for GetScriptContextFromJSContext
 #include "xpcpublic.h"
 #include "mozilla/dom/BindingUtils.h"
 
 using mozilla::dom::DestroyProtoAndIfaceCache;
-using mozilla::AutoPushJSContext;
-using mozilla::AutoSafeJSContext;
 using mozilla::dom::XULDocument;
 
 uint32_t nsXULPrototypeDocument::gRefCnt;
 
 //----------------------------------------------------------------------
 //
 // ctors, dtors, n' stuff
 //
--- a/dom/apps/src/PermissionsInstaller.jsm
+++ b/dom/apps/src/PermissionsInstaller.jsm
@@ -140,18 +140,31 @@ this.PermissionsInstaller = {
                " is not a valid Webapps permission name.");
           continue;
         }
 
         let expandedPermNames =
           expandPermissions(permName,
                             newManifest.permissions[permName].access);
         for (let idx in expandedPermNames) {
+          // We silently upgrade the permission to whatever the permission
+          // is for certified apps (ALLOW or PROMPT) only if the
+          // following holds true:
+          // * The app is preinstalled
+          // * The permission that would be granted is PROMPT
+          // * The app is privileged
+          let permission =
+            aApp.isPreinstalled &&
+            PermissionsTable[permName][appStatus] === PROMPT_ACTION &&
+            appStatus === "privileged"
+                ? PermissionsTable[permName]["certified"]
+                : PermissionsTable[permName][appStatus];
+
           this._setPermission(expandedPermNames[idx],
-                              PERM_TO_STRING[PermissionsTable[permName][appStatus]],
+                              PERM_TO_STRING[permission],
                               aApp);
         }
       }
     }
     catch (ex) {
       dump("Caught webapps install permissions error for " + aApp.origin);
       Cu.reportError(ex);
       if (aOnError) {
--- a/dom/apps/src/Webapps.jsm
+++ b/dom/apps/src/Webapps.jsm
@@ -348,31 +348,32 @@ this.DOMApplicationRegistry = {
     // Create or Update the DataStore for this app
     this._readManifests([{ id: aId }]).then((aResult) => {
       let app = this.webapps[aId];
       this.updateDataStore(app.localId, app.origin, app.manifestURL,
                            aResult[0].manifest, app.appStatus);
     });
   },
 
-  updatePermissionsForApp: function(aId) {
+  updatePermissionsForApp: function(aId, aIsPreinstalled) {
     if (!this.webapps[aId]) {
       return;
     }
 
     // Install the permissions for this app, as if we were updating
     // to cleanup the old ones if needed.
     // TODO It's not clear what this should do when there are multiple profiles.
     if (supportUseCurrentProfile()) {
       this._readManifests([{ id: aId }]).then((aResult) => {
         let data = aResult[0];
         PermissionsInstaller.installPermissions({
           manifest: data.manifest,
           manifestURL: this.webapps[aId].manifestURL,
-          origin: this.webapps[aId].origin
+          origin: this.webapps[aId].origin,
+          isPreinstalled: aIsPreinstalled
         }, true, function() {
           debug("Error installing permissions for " + aId);
         });
       });
     }
   },
 
   updateOfflineCacheForApp: function(aId) {
@@ -388,42 +389,45 @@ this.DOMApplicationRegistry = {
       });
     });
   },
 
   // Installs a 3rd party app.
   installPreinstalledApp: function installPreinstalledApp(aId) {
 #ifdef MOZ_WIDGET_GONK
     let app = this.webapps[aId];
-    let baseDir;
+    let baseDir, isPreinstalled = false;
     try {
       baseDir = FileUtils.getDir("coreAppsDir", ["webapps", aId], false);
       if (!baseDir.exists()) {
-        return;
+        return isPreinstalled;
       } else if (!baseDir.directoryEntries.hasMoreElements()) {
         debug("Error: Core app in " + baseDir.path + " is empty");
-        return;
+        return isPreinstalled;
       }
     } catch(e) {
       // In ENG builds, we don't have apps in coreAppsDir.
-      return;
+      return isPreinstalled;
     }
 
+    // Beyond this point we know it's really a preinstalled app.
+    isPreinstalled = true;
+
     let filesToMove;
     let isPackage;
 
     let updateFile = baseDir.clone();
     updateFile.append("update.webapp");
     if (!updateFile.exists()) {
       // The update manifest is missing, this is a hosted app only if there is
       // no application.zip
       let appFile = baseDir.clone();
       appFile.append("application.zip");
       if (appFile.exists()) {
-        return;
+        return isPreinstalled;
       }
 
       isPackage = false;
       filesToMove = ["manifest.webapp"];
     } else {
       isPackage = true;
       filesToMove = ["application.zip", "update.webapp"];
     }
@@ -444,17 +448,17 @@ this.DOMApplicationRegistry = {
         }
       });
 
     app.installState = "installed";
     app.cachePath = app.basePath;
     app.basePath = OS.Path.dirname(this.appsFile);
 
     if (!isPackage) {
-      return;
+      return isPreinstalled;
     }
 
     app.origin = "app://" + aId;
 
     // Do this for all preinstalled apps... we can't know at this
     // point if the updates will be signed or not and it doesn't
     // hurt to have it always.
     app.storeId = STORE_ID_PENDING_PREFIX + app.installOrigin;
@@ -476,16 +480,17 @@ this.DOMApplicationRegistry = {
     } catch(e) {
       // If we are unable to extract the manifest, cleanup and remove this app.
       debug("Cleaning up: " + e);
       destDir.remove(true);
       delete this.webapps[aId];
     } finally {
       zipReader.close();
     }
+    return isPreinstalled;
 #endif
   },
 
   // For hosted apps, uninstall an app served from http:// if we have
   // one installed from the same url with an https:// scheme.
   removeIfHttpsDuplicate: function(aId) {
 #ifdef MOZ_WIDGET_GONK
     let app = this.webapps[aId];
@@ -584,23 +589,23 @@ this.DOMApplicationRegistry = {
 
       if (runUpdate) {
 #ifdef MOZ_WIDGET_GONK
         yield this.installSystemApps();
 #endif
 
         // At first run, install preloaded apps and set up their permissions.
         for (let id in this.webapps) {
-          this.installPreinstalledApp(id);
+          let isPreinstalled = this.installPreinstalledApp(id);
           this.removeIfHttpsDuplicate(id);
           if (!this.webapps[id]) {
             continue;
           }
           this.updateOfflineCacheForApp(id);
-          this.updatePermissionsForApp(id);
+          this.updatePermissionsForApp(id, isPreinstalled);
         }
         // Need to update the persisted list of apps since
         // installPreinstalledApp() removes the ones failing to install.
         this._saveApps();
       }
 
       // DataStores must be initialized at startup.
       for (let id in this.webapps) {
--- a/dom/archivereader/ArchiveRequest.cpp
+++ b/dom/archivereader/ArchiveRequest.cpp
@@ -3,18 +3,18 @@
 /* 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 "ArchiveRequest.h"
 
 #include "mozilla/EventDispatcher.h"
 #include "mozilla/dom/ArchiveRequestBinding.h"
+#include "mozilla/dom/ScriptSettings.h"
 #include "nsContentUtils.h"
-#include "nsCxPusher.h"
 
 using namespace mozilla;
 
 USING_ARCHIVEREADER_NAMESPACE
 
 /**
  * Class used to make asynchronous the ArchiveRequest.
  */
@@ -126,23 +126,25 @@ ArchiveRequest::ReaderReady(nsTArray<nsC
 {
   if (NS_FAILED(aStatus)) {
     FireError(aStatus);
     return NS_OK;
   }
 
   nsresult rv;
 
-  nsIScriptContext* sc = GetContextForEventHandlers(&rv);
-  NS_ENSURE_STATE(sc);
+  nsCOMPtr<nsIGlobalObject> globalObject = do_QueryInterface(GetOwner());
+  if (NS_WARN_IF(!globalObject)) {
+    return NS_ERROR_UNEXPECTED;
+  }
 
-  AutoPushJSContext cx(sc->GetNativeContext());
-  NS_ASSERTION(cx, "Failed to get a context!");
+  AutoJSAPI jsapi;
+  JSContext* cx = jsapi.cx();
 
-  JS::Rooted<JSObject*> global(cx, sc->GetWindowProxy());
+  JS::Rooted<JSObject*> global(cx, globalObject->GetGlobalJSObject());
   NS_ASSERTION(global, "Failed to get global object!");
 
   JSAutoCompartment ac(cx, global);
 
   JS::Rooted<JS::Value> result(cx);
   switch (mOperation) {
     case GetFilenames:
       rv = GetFilenamesResult(cx, result.address(), aFileList);
--- a/dom/base/test/chrome.ini
+++ b/dom/base/test/chrome.ini
@@ -1,11 +1,13 @@
 [DEFAULT]
 support-files =
   file_url.jsm
+  file_empty.html
 
 [test_bug715041.xul]
 [test_bug715041_removal.xul]
 [test_domrequesthelper.xul]
 [test_url.xul]
 [test_console.xul]
 [test_navigator_resolve_identity_xrays.xul]
 [test_sendQueryContentAndSelectionSetEvent.html]
+[test_bug1016960.html]
new file mode 100644
--- /dev/null
+++ b/dom/base/test/test_bug1016960.html
@@ -0,0 +1,30 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1016960
+-->
+<head>
+  <meta charset="utf-8">
+  <title>Test for Bug 1016960</title>
+  <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
+  <script type="application/javascript">
+
+  /** Test for Bug 1016960 **/
+
+  var chromeWindow = window.open("chrome://mochitests/content/chrome/dom/base/test/file_empty.html", "1016960", "chrome");
+  ok(chromeWindow instanceof ChromeWindow, "A chrome window should return true for |instanceof ChromeWindow|.");
+  chromeWindow.close();
+
+  </script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1016960">Mozilla Bug 1016960</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+</pre>
+</body>
+</html>
--- a/dom/bindings/BindingUtils.cpp
+++ b/dom/bindings/BindingUtils.cpp
@@ -1886,17 +1886,17 @@ GlobalObject::GetAsSupports() const
 bool
 InterfaceHasInstance(JSContext* cx, JS::Handle<JSObject*> obj,
                      JS::Handle<JSObject*> instance,
                      bool* bp)
 {
   const DOMIfaceAndProtoJSClass* clasp =
     DOMIfaceAndProtoJSClass::FromJSClass(js::GetObjectClass(obj));
 
-  const DOMClass* domClass = GetDOMClass(js::UncheckedUnwrap(instance));
+  const DOMClass* domClass = GetDOMClass(js::UncheckedUnwrap(instance, /* stopAtOuter = */ false));
 
   MOZ_ASSERT(!domClass || clasp->mPrototypeID != prototypes::id::_ID_Count,
              "Why do we have a hasInstance hook if we don't have a prototype "
              "ID?");
 
   if (domClass &&
       domClass->mInterfaceChain[clasp->mDepth] == clasp->mPrototypeID) {
     *bp = true;
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -1730,36 +1730,36 @@ class CGClassHasInstanceHook(CGAbstractS
                     bool ok = InterfaceHasInstance(cx, obj, instance, bp);
                     if (!ok || *bp) {
                       return ok;
                     }
 
                     // FIXME Limit this to chrome by checking xpc::AccessCheck::isChrome(obj).
                     nsISupports* native =
                       nsContentUtils::XPConnect()->GetNativeOfWrapper(cx,
-                                                                      js::UncheckedUnwrap(instance));
+                                                                      js::UncheckedUnwrap(instance, /* stopAtOuter = */ false));
                     nsCOMPtr<nsIDOM${name}> qiResult = do_QueryInterface(native);
                     *bp = !!qiResult;
                     return true;
 
                     """,  # BOGUS extra blank line at end of function
                     nativeType=self.descriptor.nativeType,
                     name=self.descriptor.interface.identifier.name))
 
         hasInstanceCode = dedent("""
 
-            const DOMClass* domClass = GetDOMClass(js::UncheckedUnwrap(instance));
+            const DOMClass* domClass = GetDOMClass(js::UncheckedUnwrap(instance, /* stopAtOuter = */ false));
             *bp = false;
             if (!domClass) {
               // Not a DOM object, so certainly not an instance of this interface
               return true;
             }
             """)
         if self.descriptor.interface.identifier.name == "ChromeWindow":
-            setBp = "*bp = UnwrapDOMObject<nsGlobalWindow>(js::UncheckedUnwrap(instance))->IsChromeWindow()"
+            setBp = "*bp = UnwrapDOMObject<nsGlobalWindow>(js::UncheckedUnwrap(instance, /* stopAtOuter = */ false))->IsChromeWindow()"
         else:
             setBp = "*bp = true"
         # Sort interaces implementing self by name so we get stable output.
         for iface in sorted(self.descriptor.interface.interfacesImplementingSelf,
                             key=lambda iface: iface.identifier.name):
             hasInstanceCode += fill(
                 """
 
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -2494,16 +2494,17 @@ TabChild::InitRenderingState()
     lf->IdentifyTextureHost(mTextureFactoryIdentifier);
     ImageBridgeChild::IdentifyCompositorTextureHost(mTextureFactoryIdentifier);
 
     mRemoteFrame = remoteFrame;
     if (id != 0) {
       if (!sTabChildren) {
         sTabChildren = new TabChildMap;
       }
+      MOZ_ASSERT(!sTabChildren->Get(id));
       sTabChildren->Put(id, this);
       mLayersId = id;
     }
 
     nsCOMPtr<nsIObserverService> observerService =
         mozilla::services::GetObserverService();
 
     if (observerService) {
@@ -2703,24 +2704,24 @@ TabChild::GetFrom(uint64_t aLayersId)
 {
   if (!sTabChildren) {
     return nullptr;
   }
   return sTabChildren->Get(aLayersId);
 }
 
 void
-TabChild::DidComposite()
+TabChild::DidComposite(uint64_t aTransactionId)
 {
   MOZ_ASSERT(mWidget);
   MOZ_ASSERT(mWidget->GetLayerManager());
   MOZ_ASSERT(mWidget->GetLayerManager()->GetBackendType() == LayersBackend::LAYERS_CLIENT);
 
   ClientLayerManager *manager = static_cast<ClientLayerManager*>(mWidget->GetLayerManager());
-  manager->DidComposite();
+  manager->DidComposite(aTransactionId);
 }
 
 NS_IMETHODIMP
 TabChild::OnShowTooltip(int32_t aXCoords, int32_t aYCoords, const char16_t *aTipText)
 {
     nsString str(aTipText);
     SendShowTooltip(aXCoords, aYCoords, str);
     return NS_OK;
--- a/dom/ipc/TabChild.h
+++ b/dom/ipc/TabChild.h
@@ -441,17 +441,17 @@ public:
     {
       nsCOMPtr<nsITabChild> tc = do_GetInterface(aDocShell);
       return static_cast<TabChild*>(tc.get());
     }
 
     static TabChild* GetFrom(nsIPresShell* aPresShell);
     static TabChild* GetFrom(uint64_t aLayersId);
 
-    void DidComposite();
+    void DidComposite(uint64_t aTransactionId);
 
     static inline TabChild*
     GetFrom(nsIDOMWindow* aWindow)
     {
       nsCOMPtr<nsIWebNavigation> webNav = do_GetInterface(aWindow);
       nsCOMPtr<nsIDocShell> docShell = do_QueryInterface(webNav);
       return GetFrom(docShell);
     }
--- a/dom/media/MediaManager.cpp
+++ b/dom/media/MediaManager.cpp
@@ -1772,17 +1772,23 @@ MediaManager::Observe(nsISupports* aSubj
 
     // Close off any remaining active windows.
     {
       MutexAutoLock lock(mMutex);
       GetActiveWindows()->Clear();
       mActiveCallbacks.Clear();
       mCallIds.Clear();
       LOG(("Releasing MediaManager singleton and thread"));
+      // Note: won't be released immediately as the Observer has a ref to us
       sSingleton = nullptr;
+      if (mMediaThread) {
+        mMediaThread->Shutdown();
+        mMediaThread = nullptr;
+      }
+      mBackend = nullptr;
     }
 
     return NS_OK;
 
   } else if (!strcmp(aTopic, "getUserMedia:response:allow")) {
     nsString key(aData);
     nsRefPtr<GetUserMediaRunnable> runnable;
     if (!mActiveCallbacks.Get(key, getter_AddRefs(runnable))) {
--- a/dom/settings/SettingsDB.jsm
+++ b/dom/settings/SettingsDB.jsm
@@ -187,19 +187,20 @@ SettingsDB.prototype = {
       return res;
     } else if (kind == "file" || kind == "blob" || kind == "date") {
       return aObject;
     } else if (kind == "primitive") {
       return this.convertDataURIToBlob(aObject);
     }
 
     // Fall-through, we now have a dictionary object.
+    let res = {};
     for (let prop in aObject) {
-      aObject[prop] = this.prepareValue(aObject[prop]);
+      res[prop] = this.prepareValue(aObject[prop]);
     }
-    return aObject;
+    return res;
   },
 
   init: function init() {
     this.initDBHelper(SETTINGSDB_NAME, SETTINGSDB_VERSION,
                       [SETTINGSSTORE_NAME]);
   }
 }
--- a/dom/src/notification/Notification.cpp
+++ b/dom/src/notification/Notification.cpp
@@ -767,35 +767,32 @@ Notification::Close()
     new NotificationTask(this, NotificationTask::eClose);
   NS_DispatchToMainThread(closeNotificationTask);
 }
 
 void
 Notification::CloseInternal()
 {
   if (!mIsClosed) {
-    nsresult rv;
     // Don't bail out if notification storage fails, since we still
     // want to send the close event through the alert service.
     nsCOMPtr<nsINotificationStorage> notificationStorage =
       do_GetService(NS_NOTIFICATION_STORAGE_CONTRACTID);
     if (notificationStorage) {
       nsString origin;
-      rv = GetOrigin(GetOwner(), origin);
+      nsresult rv = GetOrigin(GetOwner(), origin);
       if (NS_SUCCEEDED(rv)) {
         notificationStorage->Delete(origin, mID);
       }
     }
 
     nsCOMPtr<nsIAlertsService> alertService =
       do_GetService(NS_ALERTSERVICE_CONTRACTID);
     if (alertService) {
-      if (NS_SUCCEEDED(rv)) {
-        alertService->CloseAlert(mAlertName, GetPrincipal());
-      }
+      alertService->CloseAlert(mAlertName, GetPrincipal());
     }
   }
 }
 
 nsresult
 Notification::GetOrigin(nsPIDOMWindow* aWindow, nsString& aOrigin)
 {
   if (!aWindow) {
--- a/dom/xbl/test/file_bug821850.xhtml
+++ b/dom/xbl/test/file_bug821850.xhtml
@@ -164,19 +164,24 @@ https://bugzilla.mozilla.org/show_bug.cg
     // Inspect the bound element.
     var bound = document.getElementById('bound');
     is(bound.primitiveField, 2, "Can see primitive fields");
     is(bound.method("foo"), "method:foo", "Can invoke XBL method from content");
     is(bound.prop, "propVal", "Can access properties from content");
     bound.prop = "someOtherVal";
     is(bound.prop, "set:someOtherVal", "Can set properties from content");
 
-    // Make sure we can't pass JS objects to the XBL scope.
+    // Make sure that XBL scopes get opaque wrappers.
+    //
+    // Note: Now that we have object Xrays, we have to pass in a more obscure
+    // ES type that we don't Xray to test this.
     var proto = bound.__proto__;
-    proto.passMeAJSObject({prop: 2});
+    var nonXrayableObject = new WeakMap();
+    nonXrayableObject.prop = 2;
+    proto.passMeAJSObject(nonXrayableObject);
 
     //
     // Try sticking a bunch of stuff on the prototype object.
     //
 
     proto.someExpando = 201;
     is(bound.someExpando, 201, "Can stick non-XBL properties on the proto");
 
deleted file mode 100644
--- a/gfx/gl/VBOArena.cpp
+++ /dev/null
@@ -1,37 +0,0 @@
-/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
- * 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 "VBOArena.h"
-#include "GLContext.h"
-
-using namespace mozilla::gl;
-
-GLuint VBOArena::Allocate(GLContext *aGLContext)
-{
-    if (!mAvailableVBOs.size()) {
-        GLuint vbo;
-        aGLContext->fGenBuffers(1, &vbo);
-        mAllocatedVBOs.push_back(vbo);
-        return vbo;
-    }
-    GLuint vbo = mAvailableVBOs.back();
-    mAvailableVBOs.pop_back();
-    return vbo;
-}
-
-void VBOArena::Reset()
-{
-    mAvailableVBOs = mAllocatedVBOs;
-}
-
-void VBOArena::Flush(GLContext *aGLContext)
-{
-    if (mAvailableVBOs.size()) {
-#ifdef DEBUG
-        printf_stderr("VBOArena::Flush for %u VBOs\n", mAvailableVBOs.size());
-#endif
-        aGLContext->fDeleteBuffers(mAvailableVBOs.size(), &mAvailableVBOs[0]);
-    }
-}
deleted file mode 100644
--- a/gfx/gl/VBOArena.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
- * 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/. */
-
-#ifndef VBOARENA_H_
-#define VBOARENA_H_
-
-#include "GLTypes.h"
-#include <vector>
-
-namespace mozilla {
-namespace gl {
-
-class GLContext;
-
-class VBOArena {
-public:
-    // Allocate a new VBO.
-    GLuint Allocate(GLContext *aGLContext);
-
-    // Re-use previously allocated VBOs.
-    void Reset();
-
-    // Throw away all allocated VBOs.
-    void Flush(GLContext *aGLContext);
-private:
-    std::vector<GLuint> mAllocatedVBOs;
-    std::vector<GLuint> mAvailableVBOs;
-};
-
-}
-}
-
-#endif
--- a/gfx/gl/moz.build
+++ b/gfx/gl/moz.build
@@ -50,17 +50,16 @@ EXPORTS += [
     'ScopedGLHelpers.h',
     'SharedSurface.h',
     'SharedSurfaceEGL.h',
     'SharedSurfaceGL.h',
     'SurfaceFactory.h',
     'SurfaceStream.h',
     'SurfaceTypes.h',
     'TextureGarbageBin.h',
-    'VBOArena.h',
 ]
 
 if CONFIG['MOZ_X11']:
     EXPORTS += [
         'GLContextGLX.h',
         'GLXLibrary.h',
     ]
 
@@ -135,17 +134,16 @@ UNIFIED_SOURCES += [
     'SharedSurface.cpp',
     'SharedSurfaceEGL.cpp',
     'SharedSurfaceGL.cpp',
     'SurfaceFactory.cpp',
     'SurfaceStream.cpp',
     'SurfaceTypes.cpp',
     'TextureGarbageBin.cpp',
     'TextureImageEGL.cpp',
-    'VBOArena.cpp',
 ]
 
 FAIL_ON_WARNINGS = True
 
 MSVC_ENABLE_PGO = True
 
 include('/ipc/chromium/chromium-config.mozbuild')
 
new file mode 100644
--- /dev/null
+++ b/gfx/layers/TransactionIdAllocator.h
@@ -0,0 +1,52 @@
+/* -*- 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/. */
+
+#ifndef GFX_TRANSACTION_ID_ALLOCATOR_H
+#define GFX_TRANSACTION_ID_ALLOCATOR_H
+
+#include "nsISupportsImpl.h"
+
+namespace mozilla {
+namespace layers {
+
+class TransactionIdAllocator {
+public:
+  NS_INLINE_DECL_REFCOUNTING(TransactionIdAllocator)
+
+  virtual ~TransactionIdAllocator() {}
+
+  /**
+   * Allocate a unique id number for the current refresh tick, can
+   * only be called while IsInRefresh().
+   *
+   * If too many id's are allocated without being returned then
+   * the refresh driver will suspend until they catch up.
+   */
+  virtual uint64_t GetTransactionId() = 0;
+
+  /**
+   * Notify that all work (including asynchronous composites)
+   * for a given transaction id has been completed.
+   *
+   * If the refresh driver has been suspended because
+   * of having too many outstanding id's, then this may
+   * resume it.
+   */
+  virtual void NotifyTransactionCompleted(uint64_t aTransactionId) = 0;
+
+  /**
+   * Revoke a transaction id that isn't needed to track
+   * completion of asynchronous work. This is similar
+   * to NotifyTransactionCompleted except avoids
+   * return ordering issues.
+   */
+  virtual void RevokeTransactionId(uint64_t aTransactionId) = 0;
+};
+
+}
+}
+
+
+#endif /* GFX_TRANSACTION_ID_ALLOCATOR_H */
--- a/gfx/layers/client/ClientLayerManager.cpp
+++ b/gfx/layers/client/ClientLayerManager.cpp
@@ -35,30 +35,34 @@
 namespace mozilla {
 namespace layers {
 
 using namespace mozilla::gfx;
 
 ClientLayerManager::ClientLayerManager(nsIWidget* aWidget)
   : mPhase(PHASE_NONE)
   , mWidget(aWidget)
+  , mLatestTransactionId(0)
   , mTargetRotation(ROTATION_0)
   , mRepeatTransaction(false)
   , mIsRepeatTransaction(false)
   , mTransactionIncomplete(false)
   , mCompositorMightResample(false)
   , mNeedsComposite(false)
   , mPaintSequenceNumber(0)
   , mForwarder(new ShadowLayerForwarder)
 {
   MOZ_COUNT_CTOR(ClientLayerManager);
 }
 
 ClientLayerManager::~ClientLayerManager()
 {
+  if (mTransactionIdAllocator) {
+    DidComposite(mLatestTransactionId);
+  }
   ClearCachedResources();
   // Stop receiveing AsyncParentMessage at Forwarder.
   // After the call, the message is directly handled by LayerTransactionChild. 
   // Basically this function should be called in ShadowLayerForwarder's
   // destructor. But when the destructor is triggered by 
   // CompositorChild::Destroy(), the destructor can not handle it correctly.
   // See Bug 1000525.
   mForwarder->StopReceiveAsyncParentMessge();
@@ -280,27 +284,28 @@ ClientLayerManager::GetRemoteRenderer()
 
 void
 ClientLayerManager::Composite()
 {
   mForwarder->Composite();
 }
 
 void
-ClientLayerManager::DidComposite()
+ClientLayerManager::DidComposite(uint64_t aTransactionId)
 {
   MOZ_ASSERT(mWidget);
   nsIWidgetListener *listener = mWidget->GetWidgetListener();
   if (listener) {
     listener->DidCompositeWindow();
   }
   listener = mWidget->GetAttachedWidgetListener();
   if (listener) {
     listener->DidCompositeWindow();
   }
+  mTransactionIdAllocator->NotifyTransactionCompleted(aTransactionId);
 }
 
 void
 ClientLayerManager::GetCompositorSideAPZTestData(APZTestData* aData) const
 {
   if (mForwarder->HasShadowManager()) {
     if (!mForwarder->GetShadowManager()->SendGetAPZTestData(aData)) {
       NS_WARNING("Call to PLayerTransactionChild::SendGetAPZTestData() failed");
@@ -416,21 +421,23 @@ ClientLayerManager::StopFrameTimeRecordi
   }
 }
 
 void
 ClientLayerManager::ForwardTransaction(bool aScheduleComposite)
 {
   mPhase = PHASE_FORWARD;
 
+  mLatestTransactionId = mTransactionIdAllocator->GetTransactionId();
+
   // forward this transaction's changeset to our LayerManagerComposite
   bool sent;
   AutoInfallibleTArray<EditReply, 10> replies;
   if (HasShadowManager() && mForwarder->EndTransaction(&replies, mRegionToClear,
-        aScheduleComposite, mPaintSequenceNumber, &sent)) {
+        mLatestTransactionId, aScheduleComposite, mPaintSequenceNumber, &sent)) {
     for (nsTArray<EditReply>::size_type i = 0; i < replies.Length(); ++i) {
       const EditReply& reply = replies[i];
 
       switch (reply.type()) {
       case EditReply::TOpContentBufferSwap: {
         MOZ_LAYERS_LOG(("[LayersForwarder] DoubleBufferSwap"));
 
         const OpContentBufferSwap& obs = reply.get_OpContentBufferSwap();
@@ -474,16 +481,22 @@ ClientLayerManager::ForwardTransaction(b
       default:
         NS_RUNTIMEABORT("not reached");
       }
     }
 
     if (sent) {
       mNeedsComposite = false;
     }
+    if (!sent || mForwarder->GetShadowManager()->HasNoCompositor()) {
+      // Clear the transaction id so that it doesn't get returned
+      // unless we forwarded to somewhere that doesn't actually
+      // have a compositor.
+      mTransactionIdAllocator->RevokeTransactionId(mLatestTransactionId);
+    }
   } else if (HasShadowManager()) {
     NS_WARNING("failed to forward Layers transaction");
   }
 
   mForwarder->RemoveTexturesIfNecessary();
   mForwarder->SendPendingAsyncMessge();
   mPhase = PHASE_NONE;
 
--- a/gfx/layers/client/ClientLayerManager.h
+++ b/gfx/layers/client/ClientLayerManager.h
@@ -19,16 +19,17 @@
 #include "mozilla/layers/APZTestData.h" // for APZTestData
 #include "nsAutoPtr.h"                  // for nsRefPtr
 #include "nsCOMPtr.h"                   // for already_AddRefed
 #include "nsDebug.h"                    // for NS_ABORT_IF_FALSE
 #include "nsISupportsImpl.h"            // for Layer::Release, etc
 #include "nsRect.h"                     // for nsIntRect
 #include "nsTArray.h"                   // for nsTArray
 #include "nscore.h"                     // for nsAString
+#include "mozilla/layers/TransactionIdAllocator.h"
 
 class nsIWidget;
 
 namespace mozilla {
 namespace layers {
 
 class ClientThebesLayer;
 class CompositorChild;
@@ -161,17 +162,17 @@ public:
     mNeedsComposite = aNeedsComposite;
   }
   bool NeedsComposite() const { return mNeedsComposite; }
 
   virtual void Composite() MOZ_OVERRIDE;
   virtual bool RequestOverfill(mozilla::dom::OverfillCallback* aCallback) MOZ_OVERRIDE;
   virtual void RunOverfillCallback(const uint32_t aOverfill) MOZ_OVERRIDE;
 
-  virtual void DidComposite();
+  virtual void DidComposite(uint64_t aTransactionId);
 
   virtual bool SupportsMixBlendModes(EnumSet<gfx::CompositionOp>& aMixBlendModes) MOZ_OVERRIDE
   {
    return (GetTextureFactoryIdentifier().mSupportedBlendModes & aMixBlendModes) == aMixBlendModes;
   }
 
   // Log APZ test data for the current paint. We supply the paint sequence
   // number ourselves, and take care of calling APZTestData::StartNewPaint()
@@ -202,16 +203,18 @@ public:
   // LogTestData...() functions.
   const APZTestData& GetAPZTestData() const {
     return mApzTestData;
   }
 
   // Get a copy of the compositor-side APZ test data for our layers ID.
   void GetCompositorSideAPZTestData(APZTestData* aData) const;
 
+  void SetTransactionIdAllocator(TransactionIdAllocator* aAllocator) { mTransactionIdAllocator = aAllocator; }
+
 protected:
   enum TransactionPhase {
     PHASE_NONE, PHASE_CONSTRUCTION, PHASE_DRAWING, PHASE_FORWARD
   };
   TransactionPhase mPhase;
 
 private:
   /**
@@ -248,16 +251,19 @@ private:
   // a PLayers:Update.  We save the original non-default target to
   // mShadowTarget, and then perform the transaction using
   // mDummyTarget as the render target.  After the transaction ends,
   // we send a message to our remote side to capture the actual pixels
   // being drawn to the default target, and then copy those pixels
   // back to mShadowTarget.
   nsRefPtr<gfxContext> mShadowTarget;
 
+  nsRefPtr<TransactionIdAllocator> mTransactionIdAllocator;
+  uint64_t mLatestTransactionId;
+
   // Sometimes we draw to targets that don't natively support
   // landscape/portrait orientation.  When we need to implement that
   // ourselves, |mTargetRotation| describes the induced transform we
   // need to apply when compositing content to our target.
   ScreenRotation mTargetRotation;
 
   // Used to repeat the transaction right away (to avoid rebuilding
   // a display list) to support progressive drawing.
--- a/gfx/layers/client/TextureClient.cpp
+++ b/gfx/layers/client/TextureClient.cpp
@@ -413,19 +413,20 @@ TextureClient::Finalize()
 bool
 TextureClient::ShouldDeallocateInDestructor() const
 {
   if (!IsAllocated()) {
     return false;
   }
 
   // If we're meant to be deallocated by the host,
-  // but we haven't been shared yet, then we should
+  // but we haven't been shared yet or
+  // TextureFlags::DEALLOCATE_CLIENT is set, then we should
   // deallocate on the client instead.
-  return !IsSharedWithCompositor();
+  return !IsSharedWithCompositor() || (GetFlags() & TextureFlags::DEALLOCATE_CLIENT);
 }
 
 bool
 ShmemTextureClient::ToSurfaceDescriptor(SurfaceDescriptor& aDescriptor)
 {
   MOZ_ASSERT(IsValid());
   if (!IsAllocated() || GetFormat() == gfx::SurfaceFormat::UNKNOWN) {
     return false;
--- a/gfx/layers/composite/FPSCounter.h
+++ b/gfx/layers/composite/FPSCounter.h
@@ -8,17 +8,16 @@
 
 #include <algorithm>                    // for min
 #include <stddef.h>                     // for size_t
 #include <map>                          // for std::map
 #include "GLDefs.h"                     // for GLuint
 #include "mozilla/RefPtr.h"             // for TemporaryRef, RefCounted
 #include "mozilla/TimeStamp.h"          // for TimeStamp, TimeDuration
 #include "nsTArray.h"                   // for nsAutoTArray, nsTArray_Impl, etc
-#include "VBOArena.h"                   // for gl::VBOArena
 #include "prio.h"                       // for NSPR file i/o
 
 namespace mozilla {
 namespace gl {
 class GLContext;
 }
 namespace layers {
 
--- a/gfx/layers/ipc/CompositorChild.cpp
+++ b/gfx/layers/ipc/CompositorChild.cpp
@@ -119,25 +119,25 @@ CompositorChild::RecvInvalidateAll()
 {
   if (mLayerManager) {
     FrameLayerBuilder::InvalidateAllLayers(mLayerManager);
   }
   return true;
 }
 
 bool
-CompositorChild::RecvDidComposite(const uint64_t& aId)
+CompositorChild::RecvDidComposite(const uint64_t& aId, const uint64_t& aTransactionId)
 {
   if (mLayerManager) {
     MOZ_ASSERT(aId == 0);
-    mLayerManager->DidComposite();
+    mLayerManager->DidComposite(aTransactionId);
   } else if (aId != 0) {
     dom::TabChild *child = dom::TabChild::GetFrom(aId);
     if (child) {
-      child->DidComposite();
+      child->DidComposite(aTransactionId);
     }
   }
   return true;
 }
 
 bool
 CompositorChild::RecvOverfill(const uint32_t &aOverfill)
 {
--- a/gfx/layers/ipc/CompositorChild.h
+++ b/gfx/layers/ipc/CompositorChild.h
@@ -53,17 +53,17 @@ public:
   static CompositorChild* Get();
 
   static bool ChildProcessHasCompositor() { return sCompositor != nullptr; }
 
   virtual bool RecvInvalidateAll() MOZ_OVERRIDE;
   virtual bool RecvOverfill(const uint32_t &aOverfill) MOZ_OVERRIDE;
   void AddOverfillObserver(ClientLayerManager* aLayerManager);
 
-  virtual bool RecvDidComposite(const uint64_t& aId) MOZ_OVERRIDE;
+  virtual bool RecvDidComposite(const uint64_t& aId, const uint64_t& aTransactionId) MOZ_OVERRIDE;
 
 private:
   // Private destructor, to discourage deletion outside of Release():
   virtual ~CompositorChild();
 
   virtual PLayerTransactionChild*
     AllocPLayerTransactionChild(const nsTArray<LayersBackend>& aBackendHints,
                                 const uint64_t& aId,
--- a/gfx/layers/ipc/CompositorParent.cpp
+++ b/gfx/layers/ipc/CompositorParent.cpp
@@ -61,16 +61,17 @@ using namespace base;
 using namespace mozilla::ipc;
 using namespace mozilla::gfx;
 using namespace std;
 
 CompositorParent::LayerTreeState::LayerTreeState()
   : mParent(nullptr)
   , mLayerManager(nullptr)
   , mCrossProcessParent(nullptr)
+  , mLayerTree(nullptr)
 {
 }
 
 typedef map<uint64_t, CompositorParent::LayerTreeState> LayerTreeMap;
 static LayerTreeMap sIndirectLayerTrees;
 
 // FIXME/bug 774386: we're assuming that there's only one
 // CompositorParent, but that's not always true.  This assumption only
@@ -188,24 +189,24 @@ MessageLoop* CompositorParent::Composito
 }
 
 CompositorParent::CompositorParent(nsIWidget* aWidget,
                                    bool aUseExternalSurfaceSize,
                                    int aSurfaceWidth, int aSurfaceHeight)
   : mWidget(aWidget)
   , mCurrentCompositeTask(nullptr)
   , mIsTesting(false)
+  , mPendingTransaction(0)
   , mPaused(false)
   , mUseExternalSurfaceSize(aUseExternalSurfaceSize)
   , mEGLSurfaceSize(aSurfaceWidth, aSurfaceHeight)
   , mPauseCompositionMonitor("PauseCompositionMonitor")
   , mResumeCompositionMonitor("ResumeCompositionMonitor")
   , mOverrideComposeReadiness(false)
   , mForceCompositionTask(nullptr)
-  , mWantDidCompositeEvent(false)
 {
   NS_ABORT_IF_FALSE(sCompositorThread != nullptr || sCompositorThreadID,
                     "The compositor thread must be Initialized before instanciating a COmpositorParent.");
   MOZ_COUNT_CTOR(CompositorParent);
   mCompositorID = 0;
   // FIXME: This holds on the the fact that right now the only thing that
   // can destroy this instance is initialized on the compositor thread after
   // this task has been processed.
@@ -412,16 +413,17 @@ CompositorParent::PauseComposition()
                     "PauseComposition() can only be called on the compositor thread");
 
   MonitorAutoLock lock(mPauseCompositionMonitor);
 
   if (!mPaused) {
     mPaused = true;
 
     mCompositor->Pause();
+    DidComposite();
   }
 
   // if anyone's waiting to make sure that composition really got paused, tell them
   lock.NotifyAll();
 }
 
 void
 CompositorParent::ResumeComposition()
@@ -438,17 +440,17 @@ CompositorParent::ResumeComposition()
     __android_log_print(ANDROID_LOG_INFO, "CompositorParent", "Unable to renew compositor surface; remaining in paused state");
 #endif
     lock.NotifyAll();
     return;
   }
 
   mPaused = false;
 
-  Composite();
+  CompositeToTarget(nullptr);
 
   // if anyone's waiting to make sure that composition really got resumed, tell them
   lock.NotifyAll();
 }
 
 void
 CompositorParent::ForceComposition()
 {
@@ -536,18 +538,16 @@ CompositorParent::NotifyShadowTreeTransa
     mApzcTreeManager->UpdatePanZoomControllerTree(this, mLayerManager->GetRoot(),
         aIsFirstPaint, aId, aPaintSequenceNumber);
 
     mLayerManager->NotifyShadowTreeTransaction();
   }
   if (aScheduleComposite) {
     ScheduleComposition();
   }
-
-  mWantDidCompositeEvent = true;
 }
 
 // Used when layout.frame_rate is -1. Needs to be kept in sync with
 // DEFAULT_FRAME_RATE in nsRefreshDriver.cpp.
 static const int32_t kDefaultFrameRate = 60;
 
 static int32_t
 CalculateCompositionFrameRate()
@@ -580,35 +580,36 @@ CompositorParent::ScheduleComposition()
 
   int32_t rate = CalculateCompositionFrameRate();
 
   // If rate == 0 (ASAP mode), minFrameDelta must be 0 so there's no delay.
   TimeDuration minFrameDelta = TimeDuration::FromMilliseconds(
     rate == 0 ? 0.0 : std::max(0.0, 1000.0 / rate));
 
 
-  mCurrentCompositeTask = NewRunnableMethod(this, &CompositorParent::Composite);
+  mCurrentCompositeTask = NewRunnableMethod(this, &CompositorParent::CompositeCallback);
 
   if (!initialComposition && delta < minFrameDelta) {
     TimeDuration delay = minFrameDelta - delta;
 #ifdef COMPOSITOR_PERFORMANCE_WARNING
     mExpectedComposeStartTime = TimeStamp::Now() + delay;
 #endif
     ScheduleTask(mCurrentCompositeTask, delay.ToMilliseconds());
   } else {
 #ifdef COMPOSITOR_PERFORMANCE_WARNING
     mExpectedComposeStartTime = TimeStamp::Now();
 #endif
     ScheduleTask(mCurrentCompositeTask, 0);
   }
 }
 
 void
-CompositorParent::Composite()
+CompositorParent::CompositeCallback()
 {
+  mCurrentCompositeTask = nullptr;
   CompositeToTarget(nullptr);
 }
 
 void
 CompositorParent::CompositeToTarget(DrawTarget* aTarget, const nsIntRect* aRect)
 {
   profiler_tracing("Paint", "Composite", TRACING_INTERVAL_START);
   PROFILER_LABEL("CompositorParent", "Composite");
@@ -619,24 +620,20 @@ CompositorParent::CompositeToTarget(Draw
   TimeDuration scheduleDelta = TimeStamp::Now() - mExpectedComposeStartTime;
   if (scheduleDelta > TimeDuration::FromMilliseconds(2) ||
       scheduleDelta < TimeDuration::FromMilliseconds(-2)) {
     printf_stderr("Compositor: Compose starting off schedule by %4.1f ms\n",
                   scheduleDelta.ToMilliseconds());
   }
 #endif
 
-  if (mCurrentCompositeTask) {
-    mCurrentCompositeTask->Cancel();
-    mCurrentCompositeTask = nullptr;
-  }
-
   mLastCompose = TimeStamp::Now();
 
   if (!CanComposite()) {
+    DidComposite();
     return;
   }
 
   AutoResolveRefLayers resolve(mCompositionManager);
 
   if (aTarget) {
     mLayerManager->BeginTransactionWithDrawTarget(aTarget, *aRect);
   } else {
@@ -667,19 +664,18 @@ CompositorParent::CompositeToTarget(Draw
   if (gDumpCompositorTree) {
     printf_stderr("Painting --- compositing layer tree:\n");
     mLayerManager->Dump();
   }
 #endif
   mLayerManager->SetDebugOverlayWantsNextFrame(false);
   mLayerManager->EndEmptyTransaction();
 
-  if (!aTarget && mWantDidCompositeEvent) {
+  if (!aTarget) {
     DidComposite();
-    mWantDidCompositeEvent = false;
   }
 
   if (mLayerManager->DebugOverlayWantsNextFrame()) {
     ScheduleComposition();
   }
 
 #ifdef COMPOSITOR_PERFORMANCE_WARNING
   TimeDuration executionTime = TimeStamp::Now() - mLastCompose;
@@ -700,30 +696,16 @@ CompositorParent::CompositeToTarget(Draw
     // Special full-tilt composite mode for performance testing
     ScheduleComposition();
   }
 
   profiler_tracing("Paint", "Composite", TRACING_INTERVAL_END);
 }
 
 void
-CompositorParent::DidComposite()
-{
-  unused << SendDidComposite(0);
-
-  for (LayerTreeMap::iterator it = sIndirectLayerTrees.begin();
-       it != sIndirectLayerTrees.end(); it++) {
-    LayerTreeState* lts = &it->second;
-    if (lts->mParent == this && lts->mCrossProcessParent) {
-      unused << lts->mCrossProcessParent->SendDidComposite(it->first);
-    }
-  }
-}
-
-void
 CompositorParent::ForceComposeToTarget(DrawTarget* aTarget, const nsIntRect* aRect)
 {
   PROFILER_LABEL("CompositorParent", "ForceComposeToTarget");
   AutoRestore<bool> override(mOverrideComposeReadiness);
   mOverrideComposeReadiness = true;
 
   CompositeToTarget(aTarget, aRect);
 }
@@ -768,16 +750,17 @@ CompositorParent::ScheduleRotationOnComp
     }
     mForceCompositionTask = NewRunnableMethod(this, &CompositorParent::ForceComposition);
     ScheduleTask(mForceCompositionTask, gfxPrefs::OrientationSyncMillis());
   }
 }
 
 void
 CompositorParent::ShadowLayersUpdated(LayerTransactionParent* aLayerTree,
+                                      const uint64_t& aTransactionId,
                                       const TargetConfig& aTargetConfig,
                                       bool aIsFirstPaint,
                                       bool aScheduleComposite,
                                       uint32_t aPaintSequenceNumber)
 {
   ScheduleRotationOnCompositorThread(aTargetConfig, aIsFirstPaint);
 
   // Instruct the LayerManager to update its render bounds now. Since all the orientation
@@ -791,38 +774,45 @@ CompositorParent::ShadowLayersUpdated(La
   mLayerManager->SetRoot(root);
 
   if (mApzcTreeManager) {
     AutoResolveRefLayers resolve(mCompositionManager);
     mApzcTreeManager->UpdatePanZoomControllerTree(this, root, aIsFirstPaint,
         mRootLayerTreeID, aPaintSequenceNumber);
   }
 
+  MOZ_ASSERT(aTransactionId > mPendingTransaction);
+  mPendingTransaction = aTransactionId;
+
   if (root) {
     SetShadowProperties(root);
   }
   if (aScheduleComposite) {
     ScheduleComposition();
+    if (mPaused) {
+      DidComposite();
+    }
     // When testing we synchronously update the shadow tree with the animated
     // values to avoid race conditions when calling GetAnimationTransform etc.
     // (since the above SetShadowProperties will remove animation effects).
     // However, we only do this update when a composite operation is already
     // scheduled in order to better match the behavior under regular sampling
     // conditions.
     if (mIsTesting && root && mCurrentCompositeTask) {
       AutoResolveRefLayers resolve(mCompositionManager);
       bool requestNextFrame =
         mCompositionManager->TransformShadowTree(mTestTime);
       if (!requestNextFrame) {
         CancelCurrentCompositeTask();
+        // Pretend we composited in case someone is wating for this event.
+        DidComposite();
       }
     }
   }
   mLayerManager->NotifyShadowTreeTransaction();
-  mWantDidCompositeEvent = true;
 }
 
 void
 CompositorParent::ForceComposite(LayerTransactionParent* aLayerTree)
 {
   ScheduleComposition();
 }
 
@@ -838,16 +828,18 @@ CompositorParent::SetTestSampleTime(Laye
   mTestTime = aTime;
 
   // Update but only if we were already scheduled to animate
   if (mCompositionManager && mCurrentCompositeTask) {
     AutoResolveRefLayers resolve(mCompositionManager);
     bool requestNextFrame = mCompositionManager->TransformShadowTree(aTime);
     if (!requestNextFrame) {
       CancelCurrentCompositeTask();
+      // Pretend we composited in case someone is wating for this event.
+      DidComposite();
     }
   }
 
   return true;
 }
 
 void
 CompositorParent::LeaveTestMode(LayerTransactionParent* aLayerTree)
@@ -1146,44 +1138,63 @@ public:
     AllocPLayerTransactionParent(const nsTArray<LayersBackend>& aBackendHints,
                                  const uint64_t& aId,
                                  TextureFactoryIdentifier* aTextureFactoryIdentifier,
                                  bool *aSuccess) MOZ_OVERRIDE;
 
   virtual bool DeallocPLayerTransactionParent(PLayerTransactionParent* aLayers) MOZ_OVERRIDE;
 
   virtual void ShadowLayersUpdated(LayerTransactionParent* aLayerTree,
+                                   const uint64_t& aTransactionId,
                                    const TargetConfig& aTargetConfig,
                                    bool aIsFirstPaint,
                                    bool aScheduleComposite,
                                    uint32_t aPaintSequenceNumber) MOZ_OVERRIDE;
   virtual void ForceComposite(LayerTransactionParent* aLayerTree) MOZ_OVERRIDE;
   virtual bool SetTestSampleTime(LayerTransactionParent* aLayerTree,
                                  const TimeStamp& aTime) MOZ_OVERRIDE;
   virtual void LeaveTestMode(LayerTransactionParent* aLayerTree) MOZ_OVERRIDE;
   virtual void GetAPZTestData(const LayerTransactionParent* aLayerTree,
                               APZTestData* aOutData) MOZ_OVERRIDE;
 
   virtual AsyncCompositionManager* GetCompositionManager(LayerTransactionParent* aParent) MOZ_OVERRIDE;
 
+  void DidComposite(uint64_t aId);
 private:
   // Private destructor, to discourage deletion outside of Release():
   virtual ~CrossProcessCompositorParent();
 
   void DeferredDestroy();
 
   // There can be many CPCPs, and IPDL-generated code doesn't hold a
   // reference to top-level actors.  So we hold a reference to
   // ourself.  This is released (deferred) in ActorDestroy().
   nsRefPtr<CrossProcessCompositorParent> mSelfRef;
   Transport* mTransport;
   // Child side's process Id.
   base::ProcessId mChildProcessId;
 };
 
+void
+CompositorParent::DidComposite()
+{
+  if (mPendingTransaction) {
+    unused << SendDidComposite(0, mPendingTransaction);
+    mPendingTransaction = 0;
+  }
+
+  for (LayerTreeMap::iterator it = sIndirectLayerTrees.begin();
+       it != sIndirectLayerTrees.end(); it++) {
+    LayerTreeState* lts = &it->second;
+    if (lts->mParent == this && lts->mCrossProcessParent) {
+      static_cast<CrossProcessCompositorParent*>(lts->mCrossProcessParent)->DidComposite(it->first);
+    }
+  }
+}
+
 static void
 OpenCompositor(CrossProcessCompositorParent* aCompositor,
                Transport* aTransport, ProcessHandle aHandle,
                MessageLoop* aIOLoop)
 {
   DebugOnly<bool> ok = aCompositor->Open(aTransport, aHandle, aIOLoop);
   MOZ_ASSERT(ok);
 }
@@ -1275,16 +1286,17 @@ CrossProcessCompositorParent::AllocPLaye
 
   if (state && state->mLayerManager) {
     state->mCrossProcessParent = this;
     LayerManagerComposite* lm = state->mLayerManager;
     *aTextureFactoryIdentifier = lm->GetCompositor()->GetTextureFactoryIdentifier();
     *aSuccess = true;
     LayerTransactionParent* p = new LayerTransactionParent(lm, this, aId, mChildProcessId);
     p->AddIPDLReference();
+    sIndirectLayerTrees[aId].mLayerTree = p;
     return p;
   }
 
   NS_WARNING("Created child without a matching parent?");
   // XXX: should be false, but that causes us to fail some tests on Mac w/ OMTC.
   // Bug 900745. change *aSuccess to false to see test failures.
   *aSuccess = true;
   LayerTransactionParent* p = new LayerTransactionParent(nullptr, this, aId, mChildProcessId);
@@ -1312,16 +1324,17 @@ CrossProcessCompositorParent::RecvNotify
   MOZ_ASSERT(state->mParent);
   state->mParent->NotifyChildCreated(child);
   return true;
 }
 
 void
 CrossProcessCompositorParent::ShadowLayersUpdated(
   LayerTransactionParent* aLayerTree,
+  const uint64_t& aTransactionId,
   const TargetConfig& aTargetConfig,
   bool aIsFirstPaint,
   bool aScheduleComposite,
   uint32_t aPaintSequenceNumber)
 {
   uint64_t id = aLayerTree->GetId();
 
   MOZ_ASSERT(id != 0);
@@ -1336,16 +1349,27 @@ CrossProcessCompositorParent::ShadowLaye
   Layer* shadowRoot = aLayerTree->GetRoot();
   if (shadowRoot) {
     SetShadowProperties(shadowRoot);
   }
   UpdateIndirectTree(id, shadowRoot, aTargetConfig);
 
   state->mParent->NotifyShadowTreeTransaction(id, aIsFirstPaint, aScheduleComposite,
       aPaintSequenceNumber);
+  aLayerTree->SetPendingTransactionId(aTransactionId);
+}
+
+void
+CrossProcessCompositorParent::DidComposite(uint64_t aId)
+{
+  LayerTransactionParent *layerTree = sIndirectLayerTrees[aId].mLayerTree;
+  if (layerTree && layerTree->GetPendingTransactionId()) {
+    unused << SendDidComposite(aId, layerTree->GetPendingTransactionId());
+    layerTree->SetPendingTransactionId(0);
+  }
 }
 
 void
 CrossProcessCompositorParent::ForceComposite(LayerTransactionParent* aLayerTree)
 {
   uint64_t id = aLayerTree->GetId();
   MOZ_ASSERT(id != 0);
   sIndirectLayerTrees[id].mParent->ForceComposite(aLayerTree);
--- a/gfx/layers/ipc/CompositorParent.h
+++ b/gfx/layers/ipc/CompositorParent.h
@@ -91,16 +91,17 @@ public:
 
   virtual bool RecvNotifyRegionInvalidated(const nsIntRegion& aRegion) MOZ_OVERRIDE;
   virtual bool RecvStartFrameTimeRecording(const int32_t& aBufferSize, uint32_t* aOutStartIndex) MOZ_OVERRIDE;
   virtual bool RecvStopFrameTimeRecording(const uint32_t& aStartIndex, InfallibleTArray<float>* intervals) MOZ_OVERRIDE;
 
   virtual void ActorDestroy(ActorDestroyReason why) MOZ_OVERRIDE;
 
   virtual void ShadowLayersUpdated(LayerTransactionParent* aLayerTree,
+                                   const uint64_t& aTransactionId,
                                    const TargetConfig& aTargetConfig,
                                    bool aIsFirstPaint,
                                    bool aScheduleComposite,
                                    uint32_t aPaintSequenceNumber) MOZ_OVERRIDE;
   virtual void ForceComposite(LayerTransactionParent* aLayerTree) MOZ_OVERRIDE;
   virtual bool SetTestSampleTime(LayerTransactionParent* aLayerTree,
                                  const TimeStamp& aTime) MOZ_OVERRIDE;
   virtual void LeaveTestMode(LayerTransactionParent* aLayerTree) MOZ_OVERRIDE;
@@ -221,16 +222,17 @@ public:
     CompositorParent* mParent;
     LayerManagerComposite* mLayerManager;
     // Pointer to the CrossProcessCompositorParent. Used by APZCs to share
     // their FrameMetrics with the corresponding child process that holds
     // the PCompositorChild
     PCompositorParent* mCrossProcessParent;
     TargetConfig mTargetConfig;
     APZTestData mApzTestData;
+    LayerTransactionParent* mLayerTree;
   };
 
   /**
    * Lookup the indirect shadow tree for |aId| and return it if it
    * exists.  Otherwise null is returned.  This must only be called on
    * the compositor thread.
    */
   static LayerTreeState* GetIndirectShadowTree(uint64_t aId);
@@ -248,17 +250,17 @@ private:
 
   virtual PLayerTransactionParent*
     AllocPLayerTransactionParent(const nsTArray<LayersBackend>& aBackendHints,
                                  const uint64_t& aId,
                                  TextureFactoryIdentifier* aTextureFactoryIdentifier,
                                  bool* aSuccess) MOZ_OVERRIDE;
   virtual bool DeallocPLayerTransactionParent(PLayerTransactionParent* aLayers) MOZ_OVERRIDE;
   virtual void ScheduleTask(CancelableTask*, int);
-  void Composite();
+  void CompositeCallback();
   void CompositeToTarget(gfx::DrawTarget* aTarget, const nsIntRect* aRect = nullptr);
   void ForceComposeToTarget(gfx::DrawTarget* aTarget, const nsIntRect* aRect = nullptr);
 
   void SetEGLSurfaceSize(int width, int height);
 
   void InitializeLayerManager(const nsTArray<LayersBackend>& aBackendHints);
   void PauseComposition();
   void ResumeComposition();
@@ -322,33 +324,33 @@ private:
   CancelableTask *mCurrentCompositeTask;
   TimeStamp mLastCompose;
   TimeStamp mTestTime;
   bool mIsTesting;
 #ifdef COMPOSITOR_PERFORMANCE_WARNING
   TimeStamp mExpectedComposeStartTime;
 #endif
 
+  uint64_t mPendingTransaction;
+
   bool mPaused;
 
   bool mUseExternalSurfaceSize;
   nsIntSize mEGLSurfaceSize;
 
   mozilla::Monitor mPauseCompositionMonitor;
   mozilla::Monitor mResumeCompositionMonitor;
 
   uint64_t mCompositorID;
   uint64_t mRootLayerTreeID;
 
   bool mOverrideComposeReadiness;
   CancelableTask* mForceCompositionTask;
 
   nsRefPtr<APZCTreeManager> mApzcTreeManager;
 
-  bool mWantDidCompositeEvent;
-
   DISALLOW_EVIL_CONSTRUCTORS(CompositorParent);
 };
 
 } // layers
 } // mozilla
 
 #endif // mozilla_layers_CompositorParent_h
--- a/gfx/layers/ipc/LayerTransactionChild.h
+++ b/gfx/layers/ipc/LayerTransactionChild.h
@@ -34,26 +34,30 @@ public:
    * It is expected (checked with an assert) that all shadow layers
    * created by this have already been destroyed and
    * Send__delete__()d by the time this method is called.
    */
   void Destroy();
 
   bool IPCOpen() const { return mIPCOpen; }
 
+  void SetHasNoCompositor() { mHasNoCompositor = true; }
+  bool HasNoCompositor() { return mHasNoCompositor; }
+
   void SetForwarder(ShadowLayerForwarder* aForwarder)
   {
     mForwarder = aForwarder;
   }
 
 protected:
   LayerTransactionChild()
-    : mIPCOpen(false)
+    : mForwarder(nullptr)
+    , mIPCOpen(false)
     , mDestroyed(false)
-    , mForwarder(nullptr)
+    , mHasNoCompositor(false)
   {}
   ~LayerTransactionChild() { }
 
   virtual PLayerChild* AllocPLayerChild() MOZ_OVERRIDE;
   virtual bool DeallocPLayerChild(PLayerChild* actor) MOZ_OVERRIDE;
 
   virtual PCompositableChild* AllocPCompositableChild(const TextureInfo& aInfo) MOZ_OVERRIDE;
   virtual bool DeallocPCompositableChild(PCompositableChild* actor) MOZ_OVERRIDE;
@@ -75,17 +79,18 @@ protected:
   void ReleaseIPDLReference() {
     MOZ_ASSERT(mIPCOpen == true);
     mIPCOpen = false;
     Release();
   }
   friend class CompositorChild;
   friend class layout::RenderFrameChild;
 
+  ShadowLayerForwarder* mForwarder;
   bool mIPCOpen;
   bool mDestroyed;
-  ShadowLayerForwarder* mForwarder;
+  bool mHasNoCompositor;
 };
 
 } // namespace layers
 } // namespace mozilla
 
 #endif // MOZILLA_LAYERS_LAYERTRANSACTIONCHILD_H
--- a/gfx/layers/ipc/LayerTransactionParent.cpp
+++ b/gfx/layers/ipc/LayerTransactionParent.cpp
@@ -143,16 +143,17 @@ ShadowChild(const OpRaiseToTopChild& op)
 // LayerTransactionParent
 LayerTransactionParent::LayerTransactionParent(LayerManagerComposite* aManager,
                                                ShadowLayersManager* aLayersManager,
                                                uint64_t aId,
                                                ProcessId aOtherProcess)
   : mLayerManager(aManager)
   , mShadowLayersManager(aLayersManager)
   , mId(aId)
+  , mPendingTransaction(0)
   , mChildProcessId(aOtherProcess)
   , mDestroyed(false)
   , mIPCOpen(false)
 {
   MOZ_COUNT_CTOR(LayerTransactionParent);
 }
 
 LayerTransactionParent::~LayerTransactionParent()
@@ -174,27 +175,29 @@ LayerTransactionParent::Destroy()
 LayersBackend
 LayerTransactionParent::GetCompositorBackendType() const
 {
   return mLayerManager->GetBackendType();
 }
 
 bool
 LayerTransactionParent::RecvUpdateNoSwap(const InfallibleTArray<Edit>& cset,
+                                         const uint64_t& aTransactionId,
                                          const TargetConfig& targetConfig,
                                          const bool& isFirstPaint,
                                          const bool& scheduleComposite,
                                          const uint32_t& paintSequenceNumber)
 {
-  return RecvUpdate(cset, targetConfig, isFirstPaint, scheduleComposite,
-      paintSequenceNumber, nullptr);
+  return RecvUpdate(cset, aTransactionId, targetConfig, isFirstPaint,
+                    scheduleComposite, paintSequenceNumber, nullptr);
 }
 
 bool
 LayerTransactionParent::RecvUpdate(const InfallibleTArray<Edit>& cset,
+                                   const uint64_t& aTransactionId,
                                    const TargetConfig& targetConfig,
                                    const bool& isFirstPaint,
                                    const bool& scheduleComposite,
                                    const uint32_t& paintSequenceNumber,
                                    InfallibleTArray<EditReply>* reply)
 {
   profiler_tracing("Paint", "Composite", TRACING_INTERVAL_START);
   PROFILER_LABEL("LayerTransactionParent", "RecvUpdate");
@@ -544,18 +547,18 @@ LayerTransactionParent::RecvUpdate(const
     }
   }
 
   // Ensure that any pending operations involving back and front
   // buffers have completed, so that neither process stomps on the
   // other's buffer contents.
   LayerManagerComposite::PlatformSyncBeforeReplyUpdate();
 
-  mShadowLayersManager->ShadowLayersUpdated(this, targetConfig, isFirstPaint,
-      scheduleComposite, paintSequenceNumber);
+  mShadowLayersManager->ShadowLayersUpdated(this, aTransactionId, targetConfig,
+                                            isFirstPaint, scheduleComposite, paintSequenceNumber);
 
 #ifdef COMPOSITOR_PERFORMANCE_WARNING
   int compositeTime = (int)(mozilla::TimeStamp::Now() - updateStart).ToMilliseconds();
   if (compositeTime > 15) {
     printf_stderr("Compositor: Layers update took %i ms (blocking gecko).\n", compositeTime);
   }
 #endif
 
--- a/gfx/layers/ipc/LayerTransactionParent.h
+++ b/gfx/layers/ipc/LayerTransactionParent.h
@@ -76,37 +76,42 @@ public:
   {
     PLayerTransactionParent::DeallocShmem(aShmem);
   }
 
   virtual LayersBackend GetCompositorBackendType() const MOZ_OVERRIDE;
 
   virtual bool IsSameProcess() const MOZ_OVERRIDE;
 
+  const uint64_t& GetPendingTransactionId() { return mPendingTransaction; }
+  void SetPendingTransactionId(uint64_t aId) { mPendingTransaction = aId; }
+
   // CompositableParentManager
   virtual void SendFenceHandle(AsyncTransactionTracker* aTracker,
                                PTextureParent* aTexture,
                                const FenceHandle& aFence) MOZ_OVERRIDE;
 
   virtual void SendAsyncMessage(const InfallibleTArray<AsyncParentMessageData>& aMessage) MOZ_OVERRIDE;
 
   virtual base::ProcessId GetChildProcessId() MOZ_OVERRIDE
   {
     return mChildProcessId;
   }
 
 protected:
   virtual bool RecvUpdate(const EditArray& cset,
+                          const uint64_t& aTransactionId,
                           const TargetConfig& targetConfig,
                           const bool& isFirstPaint,
                           const bool& scheduleComposite,
                           const uint32_t& paintSequenceNumber,
                           EditReplyArray* reply) MOZ_OVERRIDE;
 
   virtual bool RecvUpdateNoSwap(const EditArray& cset,
+                                const uint64_t& aTransactionId,
                                 const TargetConfig& targetConfig,
                                 const bool& isFirstPaint,
                                 const bool& scheduleComposite,
                                 const uint32_t& paintSequenceNumber) MOZ_OVERRIDE;
 
   virtual bool RecvClearCachedResources() MOZ_OVERRIDE;
   virtual bool RecvForceComposite() MOZ_OVERRIDE;
   virtual bool RecvSetTestSampleTime(const TimeStamp& aTime) MOZ_OVERRIDE;
@@ -159,16 +164,18 @@ private:
   // Hold the root because it might be grafted under various
   // containers in the "real" layer tree
   nsRefPtr<Layer> mRoot;
   // When this is nonzero, it refers to a layer tree owned by the
   // compositor thread.  It is always true that
   //   mId != 0 => mRoot == null
   // because the "real tree" is owned by the compositor.
   uint64_t mId;
+
+  uint64_t mPendingTransaction;
   // When the widget/frame/browser stuff in this process begins its
   // destruction process, we need to Disconnect() all the currently
   // live shadow layers, because some of them might be orphaned from
   // the layer tree.  This happens in Destroy() above.  After we
   // Destroy() ourself, there's a window in which that information
   // hasn't yet propagated back to the child side and it might still
   // send us layer transactions.  We want to ignore those transactions
   // because they refer to "zombie layers" on this side.  So, we track
--- a/gfx/layers/ipc/PCompositor.ipdl
+++ b/gfx/layers/ipc/PCompositor.ipdl
@@ -37,17 +37,17 @@ intr protocol PCompositor
 
 child:
   // The child should invalidate everything so that the whole window is redrawn.
   async InvalidateAll();
 
   // The compositor completed a layers transaction. id is the layers id
   // of the child layer tree that was composited (or 0 when notifying
   // the root layer tree).
-  async DidComposite(uint64_t id);
+  async DidComposite(uint64_t id, uint64_t transactionId);
 
   // The parent sends the child the requested fill ratio numbers.
   async Overfill(uint32_t aOverfill);
 
 parent:
 
   // Child sends the parent a request for fill ratio numbers.
   async RequestOverfill();
--- a/gfx/layers/ipc/PLayerTransaction.ipdl
+++ b/gfx/layers/ipc/PLayerTransaction.ipdl
@@ -47,19 +47,24 @@ child:
 
 parent:
   async PLayer();
   async PCompositable(TextureInfo aTextureInfo);
   async PTexture(SurfaceDescriptor aSharedData, TextureFlags aTextureFlags);
 
   // The isFirstPaint flag can be used to indicate that this is the first update
   // for a particular document.
-  sync Update(Edit[] cset, TargetConfig targetConfig, bool isFirstPaint,
+  sync Update(Edit[] cset, uint64_t id, TargetConfig targetConfig, bool isFirstPaint,
               bool scheduleComposite, uint32_t paintSequenceNumber)
     returns (EditReply[] reply);
+  
+  // We don't need to send a sync transaction if
+  // no transaction operate require a swap.
+  async UpdateNoSwap(Edit[] cset, uint64_t id, TargetConfig targetConfig, bool isFirstPaint,
+                     bool scheduleComposite, uint32_t paintSequenceNumber);
 
   // Testing APIs
 
   // Enter test mode, set the sample time to sampleTime, and resample
   // animations. sampleTime must not be null.
   sync SetTestSampleTime(TimeStamp sampleTime);
   // Leave test mode and resume normal compositing
   sync LeaveTestMode();
@@ -73,21 +78,16 @@ parent:
   // be void_t.
   sync GetAnimationTransform(PLayer layer) returns (MaybeTransform transform);
 
   // The next time this layer is composited, add this async scroll offset in
   // CSS pixels.
   // Useful for testing rendering of async scrolling.
   async SetAsyncScrollOffset(PLayer layer, int32_t x, int32_t y);
 
-  // We don't need to send a sync transaction if
-  // no transaction operate require a swap.
-  async UpdateNoSwap(Edit[] cset, TargetConfig targetConfig, bool isFirstPaint,
-                     bool scheduleComposite, uint32_t paintSequenceNumber);
-
   // Drop any front buffers that might be retained on the compositor
   // side.
   async ClearCachedResources();
 
   // Schedule a composite if one isn't already scheduled.
   async ForceComposite();
 
   // Get a copy of the compositor-side APZ test data instance for this
--- a/gfx/layers/ipc/ShadowLayers.cpp
+++ b/gfx/layers/ipc/ShadowLayers.cpp
@@ -446,22 +446,25 @@ ShadowLayerForwarder::RemoveTexture(Text
 {
   MOZ_ASSERT(aTexture);
   aTexture->ForceRemove();
 }
 
 bool
 ShadowLayerForwarder::EndTransaction(InfallibleTArray<EditReply>* aReplies,
                                      const nsIntRegion& aRegionToClear,
+                                     uint64_t aId,
                                      bool aScheduleComposite,
                                      uint32_t aPaintSequenceNumber,
                                      bool* aSent)
 {
   *aSent = false;
 
+  MOZ_ASSERT(aId);
+
   PROFILER_LABEL("ShadowLayerForwarder", "EndTranscation");
   RenderTraceScope rendertrace("Foward Transaction", "000091");
   NS_ABORT_IF_FALSE(HasShadowManager(), "no manager to forward to");
   NS_ABORT_IF_FALSE(!mTxn->Finished(), "forgot BeginTransaction?");
 
   DiagnosticTypes diagnostics = gfxPlatform::GetPlatform()->GetLayerDiagnosticTypes();
   if (mDiagnosticTypes != diagnostics) {
     mDiagnosticTypes = diagnostics;
@@ -557,30 +560,30 @@ ShadowLayerForwarder::EndTransaction(Inf
   PlatformSyncBeforeUpdate();
 
   profiler_tracing("Paint", "Rasterize", TRACING_INTERVAL_END);
   if (mTxn->mSwapRequired) {
     MOZ_LAYERS_LOG(("[LayersForwarder] sending transaction..."));
     RenderTraceScope rendertrace3("Forward Transaction", "000093");
     if (!HasShadowManager() ||
         !mShadowManager->IPCOpen() ||
-        !mShadowManager->SendUpdate(cset, targetConfig, mIsFirstPaint,
+        !mShadowManager->SendUpdate(cset, aId, targetConfig, mIsFirstPaint,
                                     aScheduleComposite, aPaintSequenceNumber,
                                     aReplies)) {
       MOZ_LAYERS_LOG(("[LayersForwarder] WARNING: sending transaction failed!"));
       return false;
     }
   } else {
     // If we don't require a swap we can call SendUpdateNoSwap which
     // assumes that aReplies is empty (DEBUG assertion)
     MOZ_LAYERS_LOG(("[LayersForwarder] sending no swap transaction..."));
     RenderTraceScope rendertrace3("Forward NoSwap Transaction", "000093");
     if (!HasShadowManager() ||
         !mShadowManager->IPCOpen() ||
-        !mShadowManager->SendUpdateNoSwap(cset, targetConfig, mIsFirstPaint,
+        !mShadowManager->SendUpdateNoSwap(cset, aId, targetConfig, mIsFirstPaint,
                                           aPaintSequenceNumber, aScheduleComposite)) {
       MOZ_LAYERS_LOG(("[LayersForwarder] WARNING: sending transaction failed!"));
       return false;
     }
   }
 
   *aSent = true;
   mIsFirstPaint = false;
--- a/gfx/layers/ipc/ShadowLayers.h
+++ b/gfx/layers/ipc/ShadowLayers.h
@@ -290,16 +290,17 @@ public:
 
   /**
    * End the current transaction and forward it to LayerManagerComposite.
    * |aReplies| are directions from the LayerManagerComposite to the
    * caller of EndTransaction().
    */
   bool EndTransaction(InfallibleTArray<EditReply>* aReplies,
                       const nsIntRegion& aRegionToClear,
+                      uint64_t aId,
                       bool aScheduleComposite,
                       uint32_t aPaintSequenceNumber,
                       bool* aSent);
 
   /**
    * Set an actor through which layer updates will be pushed.
    */
   void SetShadowManager(PLayerTransactionChild* aShadowManager);
--- a/gfx/layers/ipc/ShadowLayersManager.h
+++ b/gfx/layers/ipc/ShadowLayersManager.h
@@ -14,16 +14,17 @@ class TargetConfig;
 class LayerTransactionParent;
 class AsyncCompositionManager;
 class APZTestData;
 
 class ShadowLayersManager
 {
 public:
     virtual void ShadowLayersUpdated(LayerTransactionParent* aLayerTree,
+                                     const uint64_t& aTransactionId,
                                      const TargetConfig& aTargetConfig,
                                      bool aIsFirstPaint,
                                      bool aScheduleComposite,
                                      uint32_t aPaintSequenceNumber) = 0;
 
     virtual AsyncCompositionManager* GetCompositionManager(LayerTransactionParent* aLayerTree) { return nullptr; }
 
     virtual void ForceComposite(LayerTransactionParent* aLayerTree) { }
--- a/gfx/layers/moz.build
+++ b/gfx/layers/moz.build
@@ -158,16 +158,17 @@ EXPORTS.mozilla.layers += [
     'opengl/CompositorOGL.h',
     'opengl/GrallocTextureClient.h',
     'opengl/GrallocTextureHost.h',
     'opengl/MacIOSurfaceTextureClientOGL.h',
     'opengl/MacIOSurfaceTextureHostOGL.h',
     'opengl/TextureClientOGL.h',
     'opengl/TextureHostOGL.h',
     'RenderTrace.h',
+    'TransactionIdAllocator.h',
     'YCbCrImageDataSerializer.h',
 ]
 
 if CONFIG['MOZ_X11']:
     EXPORTS.mozilla.layers += [
         'basic/TextureClientX11.h',
         'basic/X11TextureSourceBasic.h',
         'composite/X11TextureHost.h',
--- a/gfx/layers/opengl/CompositorOGL.cpp
+++ b/gfx/layers/opengl/CompositorOGL.cpp
@@ -122,20 +122,16 @@ CompositorOGL::CreateContext()
   }
 
   return context.forget();
 }
 
 void
 CompositorOGL::Destroy()
 {
-  if (gl() && gl()->MakeCurrent()) {
-    mVBOs.Flush(gl());
-  }
-
   if (mTexturePool) {
     mTexturePool->Clear();
     mTexturePool = nullptr;
   }
 
   if (!mDestroyed) {
     mDestroyed = true;
     CleanupResources();
@@ -678,18 +674,16 @@ CompositorOGL::BeginFrame(const nsIntReg
                           Rect *aClipRectOut,
                           Rect *aRenderBoundsOut)
 {
   PROFILER_LABEL("CompositorOGL", "BeginFrame");
   MOZ_ASSERT(!mFrameInProgress, "frame still in progress (should have called EndFrame or AbortFrame");
 
   LayerScope::BeginFrame(mGLContext, PR_Now());
 
-  mVBOs.Reset();
-
   mFrameInProgress = true;
   gfx::Rect rect;
   if (mUseExternalSurfaceSize) {
     rect = gfx::Rect(0, 0, mSurfaceSize.width, mSurfaceSize.height);
   } else {
     rect = gfx::Rect(aRenderBounds.x, aRenderBounds.y, aRenderBounds.width, aRenderBounds.height);
     // If render bounds is not updated explicitly, try to infer it from widget
     if (rect.width == 0 || rect.height == 0) {
--- a/gfx/layers/opengl/CompositorOGL.h
+++ b/gfx/layers/opengl/CompositorOGL.h
@@ -26,17 +26,16 @@
 #include "nsCOMPtr.h"                   // for already_AddRefed
 #include "nsDebug.h"                    // for NS_ASSERTION, NS_WARNING
 #include "nsISupportsImpl.h"            // for MOZ_COUNT_CTOR, etc
 #include "nsSize.h"                     // for nsIntSize
 #include "nsTArray.h"                   // for nsAutoTArray, nsTArray, etc
 #include "nsThreadUtils.h"              // for nsRunnable
 #include "nsXULAppAPI.h"                // for XRE_GetProcessType
 #include "nscore.h"                     // for NS_IMETHOD
-#include "VBOArena.h"                   // for gl::VBOArena
 #ifdef MOZ_WIDGET_GONK
 #include <ui/GraphicBuffer.h>
 #endif
 
 class gfx3DMatrix;
 class nsIWidget;
 
 namespace mozilla {
@@ -297,21 +296,16 @@ private:
 #endif
 
   /**
    * VBO that has some basics in it for a textured quad, including vertex
    * coords and texcoords.
    */
   GLuint mQuadVBO;
 
-  /**
-   * When we can't use mQuadVBO, we allocate VBOs from this arena instead.
-   */
-  gl::VBOArena mVBOs;
-
   bool mHasBGRA;
 
   /**
    * When rendering to some EGL surfaces (e.g. on Android), we rely on being told
    * about size changes (via SetSurfaceSize) rather than pulling this information
    * from the widget.
    */
   bool mUseExternalSurfaceSize;
--- a/gfx/layers/opengl/TextureHostOGL.cpp
+++ b/gfx/layers/opengl/TextureHostOGL.cpp
@@ -111,28 +111,16 @@ FlagsToGLFlags(TextureFlags aFlags)
   if (aFlags & TextureFlags::NEEDS_Y_FLIP)
     result |= TextureImage::NeedsYFlip;
   if (aFlags & TextureFlags::DISALLOW_BIGIMAGE)
     result |= TextureImage::DisallowBigImage;
 
   return static_cast<gl::TextureImage::Flags>(result);
 }
 
-static GLenum
-WrapMode(gl::GLContext *aGl, TextureFlags aFlags)
-{
-  if ((aFlags & TextureFlags::ALLOW_REPEAT) &&
-      (aGl->IsExtensionSupported(GLContext::ARB_texture_non_power_of_two) ||
-       aGl->IsExtensionSupported(GLContext::OES_texture_npot) ||
-       aGl->IsExtensionSupported(GLContext::IMG_texture_npot))) {
-    return LOCAL_GL_REPEAT;
-  }
-  return LOCAL_GL_CLAMP_TO_EDGE;
-}
-
 CompositableDataGonkOGL::CompositableDataGonkOGL()
  : mTexture(0)
  , mBoundEGLImage(EGL_NO_IMAGE)
 {
 }
 CompositableDataGonkOGL::~CompositableDataGonkOGL()
 {
   DeleteTextureIfPresent();
@@ -257,28 +245,28 @@ TextureImageTextureSourceOGL::Update(gfx
         NS_WARNING("Texture exceeds maximum texture size, refusing upload");
         return false;
       }
       // Explicitly use CreateBasicTextureImage instead of CreateTextureImage,
       // because CreateTextureImage might still choose to create a tiled
       // texture image.
       mTexImage = CreateBasicTextureImage(mGL, size,
                                           gfx::ContentForFormat(aSurface->GetFormat()),
-                                          WrapMode(mGL, mFlags),
+                                          LOCAL_GL_CLAMP_TO_EDGE,
                                           FlagsToGLFlags(mFlags),
                                           SurfaceFormatToImageFormat(aSurface->GetFormat()));
     } else {
       // XXX - clarify which size we want to use. IncrementalContentHost will
       // require the size of the destination surface to be different from
       // the size of aSurface.
       // See bug 893300 (tracks the implementation of ContentHost for new textures).
       mTexImage = CreateTextureImage(mGL,
                                      size,
                                      gfx::ContentForFormat(aSurface->GetFormat()),
-                                     WrapMode(mGL, mFlags),
+                                     LOCAL_GL_CLAMP_TO_EDGE,
                                      FlagsToGLFlags(mFlags),
                                      SurfaceFormatToImageFormat(aSurface->GetFormat()));
     }
     ClearCachedFilter();
   }
 
   mTexImage->UpdateFromDataSource(aSurface, aDestRegion, aSrcOffset);
 
@@ -293,17 +281,17 @@ TextureImageTextureSourceOGL::EnsureBuff
                                            gfxContentType aContentType)
 {
   if (!mTexImage ||
       mTexImage->GetSize() != aSize.ToIntSize() ||
       mTexImage->GetContentType() != aContentType) {
     mTexImage = CreateTextureImage(mGL,
                                    aSize.ToIntSize(),
                                    aContentType,
-                                   WrapMode(mGL, mFlags),
+                                   LOCAL_GL_CLAMP_TO_EDGE,
                                    FlagsToGLFlags(mFlags));
   }
   mTexImage->Resize(aSize.ToIntSize());
 }
 
 void
 TextureImageTextureSourceOGL::CopyTo(const nsIntRect& aSourceRect,
                                      DataTextureSource *aDest,
--- a/js/ipc/JavaScriptChild.h
+++ b/js/ipc/JavaScriptChild.h
@@ -20,16 +20,19 @@ class JavaScriptChild : public JavaScrip
     JavaScriptChild(JSRuntime *rt);
     virtual ~JavaScriptChild();
 
     bool init();
     void finalize(JSFreeOp *fop);
 
     void drop(JSObject *obj);
 
+  protected:
+    virtual bool isParent() { return false; }
+
   private:
     bool fail(JSContext *cx, ReturnStatus *rs);
     bool ok(ReturnStatus *rs);
 };
 
 } // mozilla
 } // jsipc
 
new file mode 100644
--- /dev/null
+++ b/js/ipc/JavaScriptLogging.h
@@ -0,0 +1,195 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sw=4 et tw=80:
+ *
+ * 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/. */
+
+#ifndef mozilla_jsipc_JavaScriptLogging__
+#define mozilla_jsipc_JavaScriptLogging__
+
+#include "nsString.h"
+#include "nsPrintfCString.h"
+#include "jsfriendapi.h"
+#include "js/OldDebugAPI.h"
+
+namespace mozilla {
+namespace jsipc {
+
+#define LOG(...)						               \
+    PR_BEGIN_MACRO                                                             \
+    if (LoggingEnabled()) {                                                    \
+	Logging log(this, cx);					               \
+	log.print(__VA_ARGS__);					               \
+    }                                                                          \
+    PR_END_MACRO
+
+#define LOG_STACK()		                                               \
+    PR_BEGIN_MACRO                                                             \
+    if (StackLoggingEnabled()) {                                               \
+        js_DumpBacktrace(cx);	                                               \
+    }                                                                          \
+    PR_END_MACRO
+
+struct ReceiverObj
+{
+    ObjectId id;
+    ReceiverObj(ObjectId id) : id(id) {}
+};
+
+struct InVariant
+{
+    JSVariant variant;
+    InVariant(const JSVariant &variant) : variant(variant) {}
+};
+
+struct OutVariant
+{
+    JSVariant variant;
+    OutVariant(const JSVariant &variant) : variant(variant) {}
+};
+
+class Logging
+{
+  public:
+    Logging(JavaScriptShared *shared, JSContext *cx) : shared(shared), cx(cx) {}
+
+    void print(const nsCString &str) {
+        const char *side = shared->isParent() ? "from child" : "from parent";
+        printf("CPOW %s: %s\n", side, str.get());
+    }
+
+    void print(const char *str) {
+        print(nsCString(str));
+    }
+    template<typename T1>
+    void print(const char *fmt, const T1 &a1) {
+        nsAutoCString tmp1;
+        format(a1, tmp1);
+        print(nsPrintfCString(fmt, tmp1.get()));
+    }
+    template<typename T1, typename T2>
+    void print(const char *fmt, const T1 &a1, const T2 &a2) {
+        nsAutoCString tmp1;
+        nsAutoCString tmp2;
+        format(a1, tmp1);
+        format(a2, tmp2);
+        print(nsPrintfCString(fmt, tmp1.get(), tmp2.get()));
+    }
+    template<typename T1, typename T2, typename T3>
+    void print(const char *fmt, const T1 &a1, const T2 &a2, const T3 &a3) {
+        nsAutoCString tmp1;
+        nsAutoCString tmp2;
+        nsAutoCString tmp3;
+        format(a1, tmp1);
+        format(a2, tmp2);
+        format(a3, tmp3);
+        print(nsPrintfCString(fmt, tmp1.get(), tmp2.get(), tmp3.get()));
+    }
+
+    void format(const nsString &str, nsCString &out) {
+        out = NS_ConvertUTF16toUTF8(str);
+    }
+
+    void formatObject(bool incoming, bool local, ObjectId id, nsCString &out) {
+        const char *side, *objDesc;
+
+        if (local == incoming) {
+            JS::RootedObject obj(cx);
+            obj = shared->findObjectById(id);
+            if (obj) {
+                JSAutoCompartment ac(cx, obj);
+                objDesc = js_ObjectClassName(cx, obj);
+            } else {
+                objDesc = "<dead object>";
+            }
+
+            side = shared->isParent() ? "parent" : "child";
+        } else {
+            objDesc = "<cpow>";
+            side = shared->isParent() ? "child" : "parent";
+        }
+
+        out = nsPrintfCString("<%s %s:%d>", side, objDesc, id);
+    }
+
+
+    void format(const ReceiverObj &obj, nsCString &out) {
+        formatObject(true, true, obj.id, out);
+    }
+
+    void format(const nsTArray<JSParam> &values, nsCString &out) {
+        nsAutoCString tmp;
+        out.Truncate();
+        for (size_t i = 0; i < values.Length(); i++) {
+            if (i)
+                out.AppendLiteral(", ");
+            if (values[i].type() == JSParam::Tvoid_t) {
+                out.AppendLiteral("<void>");
+            } else {
+                format(InVariant(values[i].get_JSVariant()), tmp);
+                out += tmp;
+            }
+        }
+    }
+
+    void format(const InVariant &value, nsCString &out) {
+        format(true, value.variant, out);
+    }
+
+    void format(const OutVariant &value, nsCString &out) {
+        format(false, value.variant, out);
+    }
+
+    void format(bool incoming, const JSVariant &value, nsCString &out) {
+        switch (value.type()) {
+          case JSVariant::TUndefinedVariant: {
+              out = "undefined";
+              break;
+          }
+          case JSVariant::TNullVariant: {
+              out = "null";
+              break;
+          }
+          case JSVariant::TnsString: {
+              nsAutoCString tmp;
+              format(value.get_nsString(), tmp);
+              out = nsPrintfCString("\"%s\"", tmp.get());
+              break;
+          }
+          case JSVariant::TObjectVariant: {
+              const ObjectVariant &ovar = value.get_ObjectVariant();
+              if (ovar.type() == ObjectVariant::TLocalObject)
+                  formatObject(incoming, true, ovar.get_LocalObject().id(), out);
+              else
+                  formatObject(incoming, false, ovar.get_RemoteObject().id(), out);
+              break;
+          }
+          case JSVariant::Tdouble: {
+              out = nsPrintfCString("%.0f", value.get_double());
+              break;
+          }
+          case JSVariant::Tbool: {
+              out = value.get_bool() ? "true" : "false";
+              break;
+          }
+          case JSVariant::TJSIID: {
+              out = "<JSIID>";
+              break;
+          }
+          default: {
+              out = "<JSIID>";
+              break;
+          }
+        }
+    }
+
+  private:
+    JavaScriptShared *shared;
+    JSContext *cx;
+};
+
+}
+}
+
+#endif
--- a/js/ipc/JavaScriptParent.h
+++ b/js/ipc/JavaScriptParent.h
@@ -22,15 +22,18 @@ class JavaScriptParent : public JavaScri
 
     bool init();
     void trace(JSTracer *trc);
 
     void drop(JSObject *obj);
 
     mozilla::ipc::IProtocol*
     CloneProtocol(Channel* aChannel, ProtocolCloneContext* aCtx) MOZ_OVERRIDE;
+
+  protected:
+    virtual bool isParent() { return true; }
 };
 
 } // jsipc
 } // mozilla
 
 #endif // mozilla_jsipc_JavaScriptWrapper_h__
 
--- a/js/ipc/JavaScriptShared.cpp
+++ b/js/ipc/JavaScriptShared.cpp
@@ -5,16 +5,17 @@
  * 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 "JavaScriptShared.h"
 #include "mozilla/dom/BindingUtils.h"
 #include "mozilla/dom/TabChild.h"
 #include "jsfriendapi.h"
 #include "xpcprivate.h"
+#include "mozilla/Preferences.h"
 
 using namespace js;
 using namespace JS;
 using namespace mozilla;
 using namespace mozilla::jsipc;
 
 IdToObjectMap::IdToObjectMap()
   : table_(SystemAllocPolicy())
@@ -139,21 +140,32 @@ ObjectToIdMap::keyMarkCallback(JSTracer 
 }
 
 void
 ObjectToIdMap::remove(JSObject *obj)
 {
     table_->remove(obj);
 }
 
+bool JavaScriptShared::sLoggingInitialized;
+bool JavaScriptShared::sLoggingEnabled;
+bool JavaScriptShared::sStackLoggingEnabled;
+
 JavaScriptShared::JavaScriptShared(JSRuntime *rt)
   : rt_(rt),
     refcount_(1),
     lastId_(0)
 {
+    if (!sLoggingInitialized) {
+        sLoggingInitialized = true;
+        Preferences::AddBoolVarCache(&sLoggingEnabled,
+                                     "dom.ipc.cpows.log.enabled", false);
+        Preferences::AddBoolVarCache(&sStackLoggingEnabled,
+                                     "dom.ipc.cpows.log.stack", false);
+    }
 }
 
 bool
 JavaScriptShared::init()
 {
     if (!objects_.init())
         return false;
     if (!cpows_.init())
--- a/js/ipc/JavaScriptShared.h
+++ b/js/ipc/JavaScriptShared.h
@@ -76,16 +76,18 @@ class ObjectToIdMap
     void remove(JSObject *obj);
 
   private:
     static void keyMarkCallback(JSTracer *trc, JSObject *key, void *data);
 
     Table *table_;
 };
 
+class Logging;
+
 class JavaScriptShared
 {
   public:
     JavaScriptShared(JSRuntime *rt);
     virtual ~JavaScriptShared() {}
 
     bool init();
 
@@ -119,25 +121,36 @@ class JavaScriptShared
     JSObject *findCPOWById(uint32_t objId) {
         return cpows_.find(objId);
     }
     JSObject *findObjectById(uint32_t objId) {
         return objects_.find(objId);
     }
     JSObject *findObjectById(JSContext *cx, uint32_t objId);
 
+    static bool LoggingEnabled() { return sLoggingEnabled; }
+    static bool StackLoggingEnabled() { return sStackLoggingEnabled; }
+
+    friend class Logging;
+
+    virtual bool isParent() = 0;
+
   protected:
     JSRuntime *rt_;
     uintptr_t refcount_;
 
     IdToObjectMap objects_;
     IdToObjectMap cpows_;
 
     ObjectId lastId_;
     ObjectToIdMap objectIds_;
+
+    static bool sLoggingInitialized;
+    static bool sLoggingEnabled;
+    static bool sStackLoggingEnabled;
 };
 
 // Use 47 at most, to be safe, since jsval privates are encoded as doubles.
 static const uint64_t MAX_CPOW_IDS = (uint64_t(1) << 47) - 1;
 
 } // namespace jsipc
 } // namespace mozilla
 
--- a/js/ipc/WrapperAnswer.cpp
+++ b/js/ipc/WrapperAnswer.cpp
@@ -1,16 +1,17 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * vim: set ts=4 sw=4 et tw=80:
  *
  * 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 "WrapperAnswer.h"
+#include "JavaScriptLogging.h"
 #include "mozilla/dom/ContentChild.h"
 #include "mozilla/dom/BindingUtils.h"
 #include "nsContentUtils.h"
 #include "xpcprivate.h"
 #include "jsfriendapi.h"
 #include "nsCxPusher.h"
 
 using namespace JS;
@@ -66,16 +67,18 @@ WrapperAnswer::AnswerPreventExtensions(c
     RootedObject obj(cx, findObjectById(cx, objId));
     if (!obj)
         return fail(cx, rs);
 
     JSAutoCompartment comp(cx, obj);
     if (!JS_PreventExtensions(cx, obj))
         return fail(cx, rs);
 
+    LOG("%s.preventExtensions()", ReceiverObj(objId));
+
     return ok(rs);
 }
 
 static void
 EmptyDesc(PPropertyDescriptor *desc)
 {
     desc->obj() = LocalObject(0);
     desc->attrs() = 0;
@@ -94,16 +97,18 @@ WrapperAnswer::AnswerGetPropertyDescript
     EmptyDesc(out);
 
     RootedObject obj(cx, findObjectById(cx, objId));
     if (!obj)
         return fail(cx, rs);
 
     JSAutoCompartment comp(cx, obj);
 
+    LOG("%s.getPropertyDescriptor(%s)", ReceiverObj(objId), id);
+
     RootedId internedId(cx);
     if (!convertGeckoStringToId(cx, id, &internedId))
         return fail(cx, rs);
 
     Rooted<JSPropertyDescriptor> desc(cx);
     if (!JS_GetPropertyDescriptorById(cx, obj, internedId, &desc))
         return fail(cx, rs);
 
@@ -126,16 +131,18 @@ WrapperAnswer::AnswerGetOwnPropertyDescr
     EmptyDesc(out);
 
     RootedObject obj(cx, findObjectById(cx, objId));
     if (!obj)
         return fail(cx, rs);
 
     JSAutoCompartment comp(cx, obj);
 
+    LOG("%s.getOwnPropertyDescriptor(%s)", ReceiverObj(objId), id);
+
     RootedId internedId(cx);
     if (!convertGeckoStringToId(cx, id, &internedId))
         return fail(cx, rs);
 
     Rooted<JSPropertyDescriptor> desc(cx);
     if (!JS_GetPropertyDescriptorById(cx, obj, internedId, &desc))
         return fail(cx, rs);
 
@@ -156,16 +163,18 @@ WrapperAnswer::AnswerDefineProperty(cons
     JSAutoRequest request(cx);
 
     RootedObject obj(cx, findObjectById(cx, objId));
     if (!obj)
         return fail(cx, rs);
 
     JSAutoCompartment comp(cx, obj);
 
+    LOG("define %s[%s]", ReceiverObj(objId), id);
+
     RootedId internedId(cx);
     if (!convertGeckoStringToId(cx, id, &internedId))
         return fail(cx, rs);
 
     Rooted<JSPropertyDescriptor> desc(cx);
     if (!toDescriptor(cx, descriptor, &desc))
         return fail(cx, rs);
 
@@ -194,16 +203,18 @@ WrapperAnswer::AnswerDelete(const Object
     *success = false;
 
     RootedObject obj(cx, findObjectById(cx, objId));
     if (!obj)
         return fail(cx, rs);
 
     JSAutoCompartment comp(cx, obj);
 
+    LOG("delete %s[%s]", ReceiverObj(objId), id);
+
     RootedId internedId(cx);
     if (!convertGeckoStringToId(cx, id, &internedId))
         return fail(cx, rs);
 
     if (!JS_DeletePropertyById2(cx, obj, internedId, success))
         return fail(cx, rs);
 
     return ok(rs);
@@ -218,16 +229,18 @@ WrapperAnswer::AnswerHas(const ObjectId 
     *bp = false;
 
     RootedObject obj(cx, findObjectById(cx, objId));
     if (!obj)
         return fail(cx, rs);
 
     JSAutoCompartment comp(cx, obj);
 
+    LOG("%s.has(%s)", ReceiverObj(objId), id);
+
     RootedId internedId(cx);
     if (!convertGeckoStringToId(cx, id, &internedId))
         return fail(cx, rs);
 
     bool found;
     if (!JS_HasPropertyById(cx, obj, internedId, &found))
         return fail(cx, rs);
     *bp = !!found;
@@ -244,16 +257,18 @@ WrapperAnswer::AnswerHasOwn(const Object
     *bp = false;
 
     RootedObject obj(cx, findObjectById(cx, objId));
     if (!obj)
         return fail(cx, rs);
 
     JSAutoCompartment comp(cx, obj);
 
+    LOG("%s.hasOwn(%s)", ReceiverObj(objId), id);
+
     RootedId internedId(cx);
     if (!convertGeckoStringToId(cx, id, &internedId))
         return fail(cx, rs);
 
     Rooted<JSPropertyDescriptor> desc(cx);
     if (!JS_GetPropertyDescriptorById(cx, obj, internedId, &desc))
         return fail(cx, rs);
     *bp = (desc.object() == obj);
@@ -288,16 +303,18 @@ WrapperAnswer::AnswerGet(const ObjectId 
 
     JS::RootedValue val(cx);
     if (!JS_ForwardGetPropertyTo(cx, obj, internedId, receiver, &val))
         return fail(cx, rs);
 
     if (!toVariant(cx, val, result))
         return fail(cx, rs);
 
+    LOG("get %s.%s = %s", ReceiverObj(objId), id, OutVariant(*result));
+
     return ok(rs);
 }
 
 bool
 WrapperAnswer::AnswerSet(const ObjectId &objId, const ObjectId &receiverId, const nsString &id,
 			 const bool &strict, const JSVariant &value, ReturnStatus *rs,
 			 JSVariant *result)
 {
@@ -313,16 +330,18 @@ WrapperAnswer::AnswerSet(const ObjectId 
         return fail(cx, rs);
 
     RootedObject receiver(cx, findObjectById(cx, receiverId));
     if (!receiver)
         return fail(cx, rs);
 
     JSAutoCompartment comp(cx, obj);
 
+    LOG("set %s[%s] = %s", ReceiverObj(objId), id, InVariant(value));
+
     RootedId internedId(cx);
     if (!convertGeckoStringToId(cx, id, &internedId))
         return fail(cx, rs);
 
     MOZ_ASSERT(obj == receiver);
 
     RootedValue val(cx);
     if (!fromVariant(cx, value, &val))
@@ -346,16 +365,18 @@ WrapperAnswer::AnswerIsExtensible(const 
     *result = false;
 
     RootedObject obj(cx, findObjectById(cx, objId));
     if (!obj)
         return fail(cx, rs);
 
     JSAutoCompartment comp(cx, obj);
 
+    LOG("%s.isExtensible()", ReceiverObj(objId));
+
     bool extensible;
     if (!JS_IsExtensible(cx, obj, &extensible))
         return fail(cx, rs);
 
     *result = !!extensible;
     return ok(rs);
 }
 
@@ -448,16 +469,18 @@ WrapperAnswer::AnswerCall(const ObjectId
     // treat this as the outparam never having been set.
     for (size_t i = 0; i < vals.length(); i++) {
         JSVariant variant;
         if (!toVariant(cx, vals[i], &variant))
             return fail(cx, rs);
         outparams->ReplaceElementAt(i, JSParam(variant));
     }
 
+    LOG("%s.call(%s) = %s", ReceiverObj(objId), argv, OutVariant(*result));
+
     return ok(rs);
 }
 
 bool
 WrapperAnswer::AnswerObjectClassIs(const ObjectId &objId, const uint32_t &classValue,
 				   bool *result)
 {
     AutoSafeJSContext cx;
@@ -467,16 +490,18 @@ WrapperAnswer::AnswerObjectClassIs(const
     if (!obj) {
         // This is very unfortunate, but we have no choice.
         *result = false;
         return true;
     }
 
     JSAutoCompartment comp(cx, obj);
 
+    LOG("%s.objectClassIs()", ReceiverObj(objId));
+
     *result = js_ObjectClassIs(cx, obj, (js::ESClassValue)classValue);
     return true;
 }
 
 bool
 WrapperAnswer::AnswerClassName(const ObjectId &objId, nsString *name)
 {
     AutoSafeJSContext cx;
@@ -485,16 +510,18 @@ WrapperAnswer::AnswerClassName(const Obj
     RootedObject obj(cx, findObjectById(cx, objId));
     if (!obj) {
         // This is very unfortunate, but we have no choice.
         return "<dead CPOW>";
     }
 
     JSAutoCompartment comp(cx, obj);
 
+    LOG("%s.className()", ReceiverObj(objId));
+
     *name = NS_ConvertASCIItoUTF16(js_ObjectClassName(cx, obj));
     return true;
 }
 
 bool
 WrapperAnswer::AnswerGetPropertyNames(const ObjectId &objId, const uint32_t &flags,
 				      ReturnStatus *rs, nsTArray<nsString> *names)
 {
@@ -502,16 +529,18 @@ WrapperAnswer::AnswerGetPropertyNames(co
     JSAutoRequest request(cx);
 
     RootedObject obj(cx, findObjectById(cx, objId));
     if (!obj)
         return fail(cx, rs);
 
     JSAutoCompartment comp(cx, obj);
 
+    LOG("%s.getPropertyNames()", ReceiverObj(objId));
+
     AutoIdVector props(cx);
     if (!js::GetPropertyNames(cx, obj, flags, &props))
         return fail(cx, rs);
 
     for (size_t i = 0; i < props.length(); i++) {
         nsString name;
         if (!convertIdToGeckoString(cx, props[i], &name))
             return fail(cx, rs);
@@ -532,16 +561,18 @@ WrapperAnswer::AnswerInstanceOf(const Ob
     *instanceof = false;
 
     RootedObject obj(cx, findObjectById(cx, objId));
     if (!obj)
         return fail(cx, rs);
 
     JSAutoCompartment comp(cx, obj);
 
+    LOG("%s.instanceOf()", ReceiverObj(objId));
+
     nsID nsiid;
     ConvertID(iid, &nsiid);
 
     nsresult rv = xpc::HasInstance(cx, obj, &nsiid, instanceof);
     if (rv != NS_OK)
         return fail(cx, rs);
 
     return ok(rs);
@@ -558,16 +589,18 @@ WrapperAnswer::AnswerDOMInstanceOf(const
     *instanceof = false;
 
     RootedObject obj(cx, findObjectById(cx, objId));
     if (!obj)
         return fail(cx, rs);
 
     JSAutoCompartment comp(cx, obj);
 
+    LOG("%s.domInstanceOf()", ReceiverObj(objId));
+
     bool tmp;
     if (!mozilla::dom::InterfaceHasInstance(cx, prototypeID, depth, obj, &tmp))
         return fail(cx, rs);
     *instanceof = tmp;
 
     return ok(rs);
 }
 
--- a/js/ipc/WrapperOwner.cpp
+++ b/js/ipc/WrapperOwner.cpp
@@ -1,16 +1,17 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * vim: set ts=4 sw=4 et tw=80:
  *
  * 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 "WrapperOwner.h"
+#include "JavaScriptLogging.h"
 #include "mozilla/unused.h"
 #include "mozilla/dom/BindingUtils.h"
 #include "jsfriendapi.h"
 #include "xpcprivate.h"
 
 using namespace js;
 using namespace JS;
 using namespace mozilla;
@@ -106,16 +107,18 @@ bool
 WrapperOwner::preventExtensions(JSContext *cx, HandleObject proxy)
 {
     ObjectId objId = idOf(proxy);
 
     ReturnStatus status;
     if (!CallPreventExtensions(objId, &status))
         return ipcfail(cx);
 
+    LOG_STACK();
+
     return ok(cx, status);
 }
 
 bool
 CPOWProxyHandler::getPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
                                         MutableHandle<JSPropertyDescriptor> desc)
 {
     FORWARD(getPropertyDescriptor, (cx, proxy, id, desc));
@@ -130,16 +133,19 @@ WrapperOwner::getPropertyDescriptor(JSCo
     nsString idstr;
     if (!convertIdToGeckoString(cx, id, &idstr))
         return false;
 
     ReturnStatus status;
     PPropertyDescriptor result;
     if (!CallGetPropertyDescriptor(objId, idstr, &status, &result))
         return ipcfail(cx);
+
+    LOG_STACK();
+
     if (!ok(cx, status))
         return false;
 
     return toDescriptor(cx, result, desc);
 }
 
 bool
 CPOWProxyHandler::getOwnPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
@@ -157,16 +163,19 @@ WrapperOwner::getOwnPropertyDescriptor(J
     nsString idstr;
     if (!convertIdToGeckoString(cx, id, &idstr))
         return false;
 
     ReturnStatus status;
     PPropertyDescriptor result;
     if (!CallGetOwnPropertyDescriptor(objId, idstr, &status, &result))
         return ipcfail(cx);
+
+    LOG_STACK();
+
     if (!ok(cx, status))
         return false;
 
     return toDescriptor(cx, result, desc);
 }
 
 bool
 CPOWProxyHandler::defineProperty(JSContext *cx, HandleObject proxy, HandleId id,
@@ -188,16 +197,18 @@ WrapperOwner::defineProperty(JSContext *
     PPropertyDescriptor descriptor;
     if (!fromDescriptor(cx, desc, &descriptor))
         return false;
 
     ReturnStatus status;
     if (!CallDefineProperty(objId, idstr, descriptor, &status))
         return ipcfail(cx);
 
+    LOG_STACK();
+
     return ok(cx, status);
 }
 
 bool
 CPOWProxyHandler::getOwnPropertyNames(JSContext *cx, HandleObject proxy, AutoIdVector &props)
 {
     FORWARD(getOwnPropertyNames, (cx, proxy, props));
 }
@@ -222,16 +233,18 @@ WrapperOwner::delete_(JSContext *cx, Han
     nsString idstr;
     if (!convertIdToGeckoString(cx, id, &idstr))
         return false;
 
     ReturnStatus status;
     if (!CallDelete(objId, idstr, &status, bp))
         return ipcfail(cx);
 
+    LOG_STACK();
+
     return ok(cx, status);
 }
 
 bool
 CPOWProxyHandler::enumerate(JSContext *cx, HandleObject proxy, AutoIdVector &props)
 {
     FORWARD(enumerate, (cx, proxy, props));
 }
@@ -256,16 +269,18 @@ WrapperOwner::has(JSContext *cx, HandleO
     nsString idstr;
     if (!convertIdToGeckoString(cx, id, &idstr))
         return false;
 
     ReturnStatus status;
     if (!CallHas(objId, idstr, &status, bp))
         return ipcfail(cx);
 
+    LOG_STACK();
+
     return ok(cx, status);
 }
 
 bool
 CPOWProxyHandler::hasOwn(JSContext *cx, HandleObject proxy, HandleId id, bool *bp)
 {
     FORWARD(hasOwn, (cx, proxy, id, bp));
 }
@@ -278,46 +293,120 @@ WrapperOwner::hasOwn(JSContext *cx, Hand
     nsString idstr;
     if (!convertIdToGeckoString(cx, id, &idstr))
         return false;
 
     ReturnStatus status;
     if (!CallHasOwn(objId, idstr, &status, bp))
         return ipcfail(cx);
 
+    LOG_STACK();
+
     return !!ok(cx, status);
 }
 
 bool
 CPOWProxyHandler::get(JSContext *cx, HandleObject proxy, HandleObject receiver,
                       HandleId id, MutableHandleValue vp)
 {
     FORWARD(get, (cx, proxy, receiver, id, vp));
 }
 
+static bool
+CPOWToString(JSContext *cx, unsigned argc, Value *vp)
+{
+    CallArgs args = CallArgsFromVp(argc, vp);
+    RootedObject callee(cx, &args.callee());
+    RootedValue cpowValue(cx);
+    if (!JS_LookupProperty(cx, callee, "__cpow__", &cpowValue))
+        return false;
+
+    if (!cpowValue.isObject() || !IsCPOW(&cpowValue.toObject())) {
+        JS_ReportError(cx, "CPOWToString called on an incompatible object");
+        return false;
+    }
+
+    RootedObject proxy(cx, &cpowValue.toObject());
+    FORWARD(toString, (cx, proxy, args));
+}
+
+bool
+WrapperOwner::toString(JSContext *cx, HandleObject cpow, JS::CallArgs &args)
+{
+    // Ask the other side to call its toString method. Update the callee so that
+    // it points to the CPOW and not to the synthesized CPOWToString function.
+    args.setCallee(ObjectValue(*cpow));
+    if (!call(cx, cpow, args))
+        return false;
+
+    if (!args.rval().isString())
+        return true;
+
+    RootedString cpowResult(cx, args.rval().toString());
+    nsDependentJSString toStringResult;
+    if (!toStringResult.init(cx, cpowResult))
+        return false;
+
+    // We don't want to wrap toString() results for things like the location
+    // object, where toString() is supposed to return a URL and nothing else.
+    nsAutoString result;
+    if (toStringResult[0] == '[') {
+        result.AppendLiteral("[object CPOW ");
+        result += toStringResult;
+        result.AppendLiteral("]");
+    } else {
+        result += toStringResult;
+    }
+
+    JSString *str = JS_NewUCStringCopyN(cx, result.get(), result.Length());
+    if (!str)
+        return false;
+
+    args.rval().setString(str);
+    return true;
+}
+
 bool
 WrapperOwner::get(JSContext *cx, HandleObject proxy, HandleObject receiver,
 		  HandleId id, MutableHandleValue vp)
 {
     ObjectId objId = idOf(proxy);
     ObjectId receiverId = idOf(receiver);
 
     nsString idstr;
     if (!convertIdToGeckoString(cx, id, &idstr))
         return false;
 
     JSVariant val;
     ReturnStatus status;
     if (!CallGet(objId, receiverId, idstr, &status, &val))
         return ipcfail(cx);
 
+    LOG_STACK();
+
     if (!ok(cx, status))
         return false;
 
-    return fromVariant(cx, val, vp);
+    if (!fromVariant(cx, val, vp))
+        return false;
+
+    if (idstr.EqualsLiteral("toString")) {
+        RootedFunction toString(cx, JS_NewFunction(cx, CPOWToString, 0, 0, proxy, "toString"));
+        if (!toString)
+            return false;
+
+        RootedObject toStringObj(cx, JS_GetFunctionObject(toString));
+
+        if (!JS_DefineProperty(cx, toStringObj, "__cpow__", vp, JSPROP_PERMANENT | JSPROP_READONLY))
+            return false;
+
+        vp.set(ObjectValue(*toStringObj));
+    }
+
+    return true;
 }
 
 bool
 CPOWProxyHandler::set(JSContext *cx, JS::HandleObject proxy, JS::HandleObject receiver,
                       JS::HandleId id, bool strict, JS::MutableHandleValue vp)
 {
     FORWARD(set, (cx, proxy, receiver, id, strict, vp));
 }
@@ -337,16 +426,18 @@ WrapperOwner::set(JSContext *cx, JS::Han
     if (!toVariant(cx, vp, &val))
         return false;
 
     ReturnStatus status;
     JSVariant result;
     if (!CallSet(objId, receiverId, idstr, strict, val, &status, &result))
         return ipcfail(cx);
 
+    LOG_STACK();
+
     if (!ok(cx, status))
         return false;
 
     return fromVariant(cx, result, vp);
 }
 
 bool
 CPOWProxyHandler::keys(JSContext *cx, HandleObject proxy, AutoIdVector &props)
@@ -370,16 +461,18 @@ bool
 WrapperOwner::isExtensible(JSContext *cx, HandleObject proxy, bool *extensible)
 {
     ObjectId objId = idOf(proxy);
 
     ReturnStatus status;
     if (!CallIsExtensible(objId, &status, extensible))
         return ipcfail(cx);
 
+    LOG_STACK();
+
     return ok(cx, status);
 }
 
 bool
 CPOWProxyHandler::call(JSContext *cx, HandleObject proxy, const CallArgs &args)
 {
     FORWARD(call, (cx, proxy, args));
 }
@@ -419,16 +512,19 @@ WrapperOwner::call(JSContext *cx, Handle
         vals.AppendElement(JSParam(val));
     }
 
     JSVariant result;
     ReturnStatus status;
     InfallibleTArray<JSParam> outparams;
     if (!CallCall(objId, vals, &status, &result, &outparams))
         return ipcfail(cx);
+
+    LOG_STACK();
+
     if (!ok(cx, status))
         return false;
 
     if (outparams.Length() != outobjects.length())
         return ipcfail(cx);
 
     RootedObject obj(cx);
     for (size_t i = 0; i < outparams.Length(); i++) {
@@ -465,16 +561,18 @@ WrapperOwner::objectClassIs(JSContext *c
     ObjectId objId = idOf(proxy);
 
     // This function is assumed infallible, so we just return false if the IPC
     // channel fails.
     bool result;
     if (!CallObjectClassIs(objId, classValue, &result))
         return false;
 
+    LOG_STACK();
+
     return result;
 }
 
 const char *
 CPOWProxyHandler::className(JSContext *cx, HandleObject proxy)
 {
     WrapperOwner *parent = OwnerOf(proxy);
     if (!parent->active())
@@ -486,16 +584,18 @@ const char *
 WrapperOwner::className(JSContext *cx, HandleObject proxy)
 {
     ObjectId objId = idOf(proxy);
 
     nsString name;
     if (!CallClassName(objId, &name))
         return "<error>";
 
+    LOG_STACK();
+
     return ToNewCString(name);
 }
 
 void
 CPOWProxyHandler::finalize(JSFreeOp *fop, JSObject *proxy)
 {
     OwnerOf(proxy)->drop(proxy);
 }
@@ -524,16 +624,19 @@ bool
 WrapperOwner::getPropertyNames(JSContext *cx, HandleObject proxy, uint32_t flags, AutoIdVector &props)
 {
     ObjectId objId = idOf(proxy);
 
     ReturnStatus status;
     InfallibleTArray<nsString> names;
     if (!CallGetPropertyNames(objId, flags, &status, &names))
         return ipcfail(cx);
+
+    LOG_STACK();
+
     if (!ok(cx, status))
         return false;
 
     for (size_t i = 0; i < names.Length(); i++) {
         RootedId name(cx);
         if (!convertGeckoStringToId(cx, names[i], &name))
             return false;
         if (!props.append(name))
@@ -592,16 +695,18 @@ bool
 WrapperOwner::domInstanceOf(JSContext *cx, JSObject *obj, int prototypeID, int depth, bool *bp)
 {
     ObjectId objId = idOf(obj);
 
     ReturnStatus status;
     if (!CallDOMInstanceOf(objId, prototypeID, depth, &status, bp))
         return ipcfail(cx);
 
+    LOG_STACK();
+
     return ok(cx, status);
 }
 
 void
 WrapperOwner::ActorDestroy(ActorDestroyReason why)
 {
     inactive_ = true;
 }
--- a/js/ipc/WrapperOwner.h
+++ b/js/ipc/WrapperOwner.h
@@ -56,16 +56,18 @@ class WrapperOwner : public virtual Java
     // SpiderMonkey Extensions.
     bool isExtensible(JSContext *cx, JS::HandleObject proxy, bool *extensible);
     bool call(JSContext *cx, JS::HandleObject proxy, const JS::CallArgs &args);
     bool objectClassIs(JSContext *cx, JS::HandleObject obj, js::ESClassValue classValue);
     const char* className(JSContext *cx, JS::HandleObject proxy);
 
     nsresult instanceOf(JSObject *obj, const nsID *id, bool *bp);
 
+    bool toString(JSContext *cx, JS::HandleObject callee, JS::CallArgs &args);
+
     /*
      * Check that |obj| is a DOM wrapper whose prototype chain contains
      * |prototypeID| at depth |depth|.
      */
     bool domInstanceOf(JSContext *cx, JSObject *obj, int prototypeID, int depth, bool *bp);
 
     bool active() { return !inactive_; }
 
--- a/js/src/gc/GCRuntime.h
+++ b/js/src/gc/GCRuntime.h
@@ -139,28 +139,40 @@ class GCRuntime
 #endif
 
   public:
     // Internal public interface
     void recordNativeStackTop();
 #ifdef JS_THREADSAFE
     void notifyRequestEnd() { conservativeGC.updateForRequestEnd(); }
 #endif
-    bool isBackgroundSweeping() { return helperThread.sweeping(); }
-    void waitBackgroundSweepEnd() { helperThread.waitBackgroundSweepEnd(); }
-    void waitBackgroundSweepOrAllocEnd() { helperThread.waitBackgroundSweepOrAllocEnd(); }
-    void startBackgroundShrink() { helperThread.startBackgroundShrink(); }
-    void freeLater(void *p) { helperThread.freeLater(p); }
+    bool isBackgroundSweeping() { return helperState.isBackgroundSweeping(); }
+    void waitBackgroundSweepEnd() { helperState.waitBackgroundSweepEnd(); }
+    void waitBackgroundSweepOrAllocEnd() { helperState.waitBackgroundSweepOrAllocEnd(); }
+    void startBackgroundShrink() { helperState.startBackgroundShrink(); }
+    void startBackgroundAllocationIfIdle() { helperState.startBackgroundAllocationIfIdle(); }
+    void freeLater(void *p) { helperState.freeLater(p); }
+
 #ifdef DEBUG
-    bool onBackgroundThread() { return helperThread.onBackgroundThread(); }
+
+    bool onBackgroundThread() { return helperState.onBackgroundThread(); }
+
+    bool currentThreadOwnsGCLock() {
+#ifdef JS_THREADSAFE
+        return lockOwner == PR_GetCurrentThread();
+#else
+        return true;
 #endif
+    }
+
+#endif // DEBUG
 
 #ifdef JS_THREADSAFE
     void assertCanLock() {
-        JS_ASSERT(lockOwner != PR_GetCurrentThread());
+        JS_ASSERT(!currentThreadOwnsGCLock());
     }
 #endif
 
     void lockGC() {
 #ifdef JS_THREADSAFE
         PR_Lock(lock);
         JS_ASSERT(!lockOwner);
 #ifdef DEBUG
@@ -198,17 +210,17 @@ class GCRuntime
     void startVerifyPostBarriers();
     bool endVerifyPostBarriers();
     void finishVerifier();
 #endif
 
   private:
     // For ArenaLists::allocateFromArenaInline()
     friend class ArenaLists;
-    Chunk *pickChunk(Zone *zone);
+    Chunk *pickChunk(Zone *zone, AutoMaybeStartBackgroundAllocation &maybeStartBackgroundAllocation);
 
     inline bool wantBackgroundAllocation() const;
 
     bool initGCZeal();
     void requestInterrupt(JS::gcreason::Reason reason);
     bool gcCycle(bool incremental, int64_t budget, JSGCInvocationKind gckind,
                  JS::gcreason::Reason reason);
     void budgetIncrementalGC(int64_t *budget);
@@ -528,25 +540,25 @@ class GCRuntime
   private:
     /* Always preserve JIT code during GCs, for testing. */
     bool                  alwaysPreserveCode;
 
 #ifdef DEBUG
     size_t                noGCOrAllocationCheck;
 #endif
 
-    /* Synchronize GC heap access between main thread and GCHelperThread. */
+    /* Synchronize GC heap access between main thread and GCHelperState. */
     PRLock                *lock;
     mozilla::DebugOnly<PRThread *>   lockOwner;
 
-    js::GCHelperThread helperThread;
+    GCHelperState helperState;
 
     ConservativeGCData conservativeGC;
 
     //friend class js::gc::Chunk; // todo: remove
-    friend class js::GCHelperThread;
+    friend class js::GCHelperState;
     friend class js::gc::MarkingValidator;
 };
 
 } /* namespace gc */
 } /* namespace js */
 
 #endif
--- a/js/src/jit-test/tests/asm.js/testHeapAccess.js
+++ b/js/src/jit-test/tests/asm.js/testHeapAccess.js
@@ -539,104 +539,39 @@ assertEq(asmLink(asmCompile('glob', 'imp
 assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'const i=-2147483648; function f() { return u8[i>>0]|0; } return f'), this, null, buf)(),0);
 
 // GVN checks
 var buf = new ArrayBuffer(8192);
 assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'var i=0; function f() { var x = 0, y = 0; u8[0] = 1; u8[1] = 2; x = 0|u8[i]; i = x; y = 0|u8[i]; return y|0;} return f'), this, null, buf)(),2);
 assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'var i=0; function f() { var x = 0, y = 0; u8[0] = 1; u8[1] = 2; x = 0|u8[i]; y = 0|u8[i]; return (x+y)|0;} return f'), this, null, buf)(),2);
 
 // Heap length constraints
-var buf = new ArrayBuffer(0x0fff);
-assertAsmLinkAlwaysFail(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf);
-var buf = new ArrayBuffer(0x1000);
-assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf)(0),0);
-var buf = new ArrayBuffer(0x1010);
-assertAsmLinkFail(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf);
-var buf = new ArrayBuffer(0x2000);
-assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf)(0),0);
-var buf = new ArrayBuffer(0xfe000);
-new Uint8Array(buf)[0xfdfff] = 0xAA;
-assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf)(0),0);
-assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf)(0xfdfff),0xAA);
-assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf)(0xfe000),0);
-var buf = new ArrayBuffer(0xfe010);
-assertAsmLinkFail(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf);
-var buf = new ArrayBuffer(0xff000);
-new Uint8Array(buf)[0xfefff] = 0xAA;
-assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf)(0),0);
-assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf)(0xfefff),0xAA);
-assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf)(0xff000),0);
-var buf = new ArrayBuffer(0xff800);
-assertAsmLinkFail(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf);
+var m = asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f');
+assertAsmLinkAlwaysFail(m, this, null, new ArrayBuffer(0x0fff));
+assertEq(asmLink(m, this, null, new ArrayBuffer(0x1000))(0),0);
+assertAsmLinkFail(m, this, null, new ArrayBuffer(0x1010));
+assertEq(asmLink(m, this, null, new ArrayBuffer(0x2000))(0),0);
+assertAsmLinkFail(m, this, null, new ArrayBuffer(0xfe000));
+assertAsmLinkFail(m, this, null, new ArrayBuffer(0xfe010));
+assertAsmLinkFail(m, this, null, new ArrayBuffer(0xfe000));
+assertAsmLinkFail(m, this, null, new ArrayBuffer(0xff800));
 var buf = new ArrayBuffer(0x100000);
-new Uint8Array(buf)[0xfffff] = 0xAA;
-assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf)(0),0);
-assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf)(0xfffff),0xAA);
-assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf)(0x100000),0);
-var buf = new ArrayBuffer(0x104000);
-new Uint8Array(buf)[0x103fff] = 0xAA;
-assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f() { return u8[0x103fff]|0; } return f'), this, null, buf)(),0xAA);
-var buf = new ArrayBuffer(0x3f8000);
-new Uint8Array(buf)[0x3f7fff] = 0xAA;
-assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf)(0),0);
-assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf)(0x3f7fff),0xAA);
-assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf)(0x3f8000),0);
-var buf = new ArrayBuffer(0x3fc000); // 4080K
-new Uint8Array(buf)[0x3fbfff] = 0xAA;
-assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf)(0),0);
-assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf)(0x3fbfff),0xAA);
-assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf)(0x3fc000),0);
-var buf = new ArrayBuffer(0x3fe000);
-assertAsmLinkFail(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf);
-var buf = new ArrayBuffer(0x410000);
-new Uint8Array(buf)[0x40ffff] = 0xAA;
-assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f() { return u8[0x40ffff]|0; } return f'), this, null, buf)(),0xAA);
-// The rest are getting too large for regular testing.
-//var buf = new ArrayBuffer(0xfe8000);
-//assertAsmLinkFail(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf);
-//var buf = new ArrayBuffer(0xff0000); // 16302K
-//new Uint8Array(buf)[0xfeffff] = 0xAA;
-//assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf)(0),0);
-//assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf)(0xfeffff),0xAA);
-//assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf)(0xff0000),0);
-//var buf = new ArrayBuffer(0xff8000);
-//assertAsmLinkFail(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf);
-//var buf = new ArrayBuffer(0x3fb0000);
-//assertAsmLinkFail(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf);
-//var buf = new ArrayBuffer(0x3fc0000); // 65280K
-//new Uint8Array(buf)[0x3fbffff] = 0xAA;
-//assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf)(0),0);
-//assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf)(0x3fbffff),0xAA);
-//assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf)(0x3fc0000),0);
-//var buf = new ArrayBuffer(0x3fe0000);
-//assertAsmLinkFail(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf);
-//var buf = new ArrayBuffer(0xfe80000);
-//assertAsmLinkFail(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf);
-//var buf = new ArrayBuffer(0xff00000); // 255M
-//new Uint8Array(buf)[0xfeffff] = 0xAA;
-//assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf)(0),0);
-//assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf)(0xfeffff),0xAA);
-//assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf)(0xff00000),0);
-//var buf = new ArrayBuffer(0xff80000);
-//assertAsmLinkFail(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf);
-//var buf = new ArrayBuffer(0x10400000);
-//new Uint8Array(buf)[0x103fffff] = 0xAA;
-//assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f() { return u8[0x103fffff]|0; } return f'), this, null, buf)(),0xAA);
-//var buf = new ArrayBuffer(0x3fa00000);
-//assertAsmLinkFail(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf);
-//var buf = new ArrayBuffer(0x3fc00000); // 1020M
-//new Uint8Array(buf)[0x3fbfffff] = 0xAA;
-//assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf)(0),0);
-//assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf)(0x3fbfffff),0xAA);
-//assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf)(0x3fc00000),0);
-//var buf = new ArrayBuffer(0x3fe00000);
-//assertAsmLinkFail(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf);
-//var buf = new ArrayBuffer(0x40000000); // 1024M
-//new Uint8Array(buf)[0x3fffffff] = 0xAA;
-//assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf)(0),0);
-//assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf)(0x3fffffff),0xAA);
-//assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf)(0x40000000),0);
-//var buf = new ArrayBuffer(0x4f000000); // 1264M - currently the largest possible heap length.
-//new Uint8Array(buf)[0x4effffff] = 0xAA;
-//assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf)(0),0);
-//assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf)(0x4effffff),0xAA);
-//assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) { i=i|0; return u8[i]|0; } return f'), this, null, buf)(0x4f000000),0);
-
+new Uint8Array(buf)[0x4242] = 0xAA;
+var f = asmLink(m, this, null, buf);
+assertEq(f(0),0);
+assertEq(f(0x4242),0xAA);
+assertEq(f(0x100000),0);
+assertAsmLinkFail(m, this, null, new ArrayBuffer(0x104000));
+assertEq(asmLink(m, this, null, new ArrayBuffer(0x200000))(0),0);
+assertAsmLinkFail(m, this, null, new ArrayBuffer(0x3f8000));
+assertAsmLinkFail(m, this, null, new ArrayBuffer(0x3fe000));
+assertAsmLinkFail(m, this, null, new ArrayBuffer(0x3fc000));
+assertEq(asmLink(m, this, null, new ArrayBuffer(0x400000))(0),0);
+assertAsmLinkFail(m, this, null, new ArrayBuffer(0x410000));
+assertEq(asmLink(m, this, null, new ArrayBuffer(0x800000))(0),0);
+var buf = new ArrayBuffer(0x1000000);
+new Uint8Array(buf)[0x424242] = 0xAA;
+var f = asmLink(m, this, null, buf);
+assertEq(f(0),0);
+assertEq(f(0x424242),0xAA);
+assertEq(f(0x1000000),0);
+assertEq(asmLink(m, this, null, new ArrayBuffer(0x2000000))(0),0);
+assertEq(asmLink(m, this, null, new ArrayBuffer(0x3000000))(0),0);
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/parallel/bug1014973.js
@@ -0,0 +1,5 @@
+if (getBuildConfiguration().parallelJS) {
+    Array.buildPar(6763, function() {
+        return Math.fround(Math.round(Math.fround(-0)));
+    });
+}
--- a/js/src/jit/AsmJS.h
+++ b/js/src/jit/AsmJS.h
@@ -2,18 +2,22 @@
  * vim: set ts=8 sts=4 et sw=4 tw=99:
  * 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/. */
 
 #ifndef jit_AsmJS_h
 #define jit_AsmJS_h
 
+#include "mozilla/MathAlgorithms.h"
+
 #include <stddef.h>
 
+#include "jsutil.h"
+
 #include "js/TypeDecls.h"
 #include "vm/ObjectImpl.h"
 
 namespace js {
 
 class ExclusiveContext;
 namespace frontend {
     template <typename ParseHandler> struct Parser;
@@ -83,84 +87,40 @@ IsAsmJSCompilationAvailable(JSContext *c
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     args.rval().set(BooleanValue(false));
     return true;
 }
 
 #endif // JS_ION
 
-// The Asm.js heap length is constrained by the x64 backend heap access scheme
-// to be a multiple of the page size which is 4096 bytes, and also constrained
-// by the limits of ARM backends 'cmp immediate' instruction which supports a
-// complex range for the immediate argument.
-//
-// ARMv7 mode supports the following immediate constants, and the Thumb T2
-// instruction encoding also supports the subset of immediate constants used.
-//  abcdefgh 00000000 00000000 00000000
-//  00abcdef gh000000 00000000 00000000
-//  0000abcd efgh0000 00000000 00000000
-//  000000ab cdefgh00 00000000 00000000
-//  00000000 abcdefgh 00000000 00000000
-//  00000000 00abcdef gh000000 00000000
-//  00000000 0000abcd efgh0000 00000000
-//  ...
-//
-// The 4096 page size constraint restricts the length to:
-//  xxxxxxxx xxxxxxxx xxxx0000 00000000
-//
-// Intersecting all the above constraints gives:
-//  Heap length 0x40000000 to 0xff000000 quanta 0x01000000
-//  Heap length 0x10000000 to 0x3fc00000 quanta 0x00400000
-//  Heap length 0x04000000 to 0x0ff00000 quanta 0x00100000
-//  Heap length 0x01000000 to 0x03fc0000 quanta 0x00040000
-//  Heap length 0x00400000 to 0x00ff0000 quanta 0x00010000
-//  Heap length 0x00100000 to 0x003fc000 quanta 0x00004000
-//  Heap length 0x00001000 to 0x000ff000 quanta 0x00001000
-//
+// To succesfully link an asm.js module to an ArrayBuffer heap, the
+// ArrayBuffer's byteLength must be:
+//  - greater or equal to 4096
+//  - either a power of 2 OR a multiple of 16MB
+inline bool
+IsValidAsmJSHeapLength(uint32_t length)
+{
+    if (length < 4096)
+        return false;
+
+    if (IsPowerOfTwo(length))
+        return true;
+
+    return (length & 0x00ffffff) == 0;
+}
+
 inline uint32_t
 RoundUpToNextValidAsmJSHeapLength(uint32_t length)
 {
-    if (length < 0x00001000u) // Minimum length is the pages size of 4096.
-        return 0x1000u;
-    if (length < 0x00100000u) // < 1M quanta 4K
-        return (length + 0x00000fff) & ~0x00000fff;
-    if (length < 0x00400000u) // < 4M quanta 16K
-        return (length + 0x00003fff) & ~0x00003fff;
-    if (length < 0x01000000u) // < 16M quanta 64K
-        return (length + 0x0000ffff) & ~0x0000ffff;
-    if (length < 0x04000000u) // < 64M quanta 256K
-        return (length + 0x0003ffff) & ~0x0003ffff;
-    if (length < 0x10000000u) // < 256M quanta 1M
-        return (length + 0x000fffff) & ~0x000fffff;
-    if (length < 0x40000000u) // < 1024M quanta 4M
-        return (length + 0x003fffff) & ~0x003fffff;
-    // < 4096M quanta 16M.  Note zero is returned if over 0xff000000 but such
-    // lengths are not currently valid.
+    if (length < 4096)
+        return 4096;
+
+    if (length < 16 * 1024 * 1024)
+        return mozilla::RoundUpPow2(length);
+
     JS_ASSERT(length <= 0xff000000);
     return (length + 0x00ffffff) & ~0x00ffffff;
 }
 
-inline bool
-IsValidAsmJSHeapLength(uint32_t length)
-{
-    if (length <  AsmJSAllocationGranularity)
-        return false;
-    if (length <= 0x00100000u)
-        return (length & 0x00000fff) == 0;
-    if (length <= 0x00400000u)
-        return (length & 0x00003fff) == 0;
-    if (length <= 0x01000000u)
-        return (length & 0x0000ffff) == 0;
-    if (length <= 0x04000000u)
-        return (length & 0x0003ffff) == 0;
-    if (length <= 0x10000000u)
-        return (length & 0x000fffff) == 0;
-    if (length <= 0x40000000u)
-        return (length & 0x003fffff) == 0;
-    if (length <= 0xff000000u)
-        return (length & 0x00ffffff) == 0;
-    return false;
-}
-
 } // namespace js
 
 #endif // jit_AsmJS_h
--- a/js/src/jit/Lowering.cpp
+++ b/js/src/jit/Lowering.cpp
@@ -1333,18 +1333,17 @@ LIRGenerator::visitRandom(MRandom *ins)
     LRandom *lir = new(alloc()) LRandom(tempFixed(CallTempReg0), tempFixed(CallTempReg1));
     return defineReturn(lir, ins);
 }
 
 bool
 LIRGenerator::visitMathFunction(MMathFunction *ins)
 {
     JS_ASSERT(IsFloatingPointType(ins->type()));
-    JS_ASSERT_IF(ins->type() == MIRType_Double, ins->input()->type() == MIRType_Double);
-    JS_ASSERT_IF(ins->type() == MIRType_Float32, ins->input()->type() == MIRType_Float32);
+    JS_ASSERT(ins->type() == ins->input()->type());
 
     if (ins->type() == MIRType_Double) {
         // Note: useRegisterAtStart is safe here, the temp is not a FP register.
         LMathFunctionD *lir = new(alloc()) LMathFunctionD(useRegisterAtStart(ins->input()),
                                                           tempFixed(CallTempReg0));
         return defineReturn(lir, ins);
     }
 
--- a/js/src/jit/ParallelSafetyAnalysis.cpp
+++ b/js/src/jit/ParallelSafetyAnalysis.cpp
@@ -605,16 +605,29 @@ ParallelSafetyVisitor::replaceWithNewPar
 bool
 ParallelSafetyVisitor::replace(MInstruction *oldInstruction,
                                MInstruction *replacementInstruction)
 {
     MBasicBlock *block = oldInstruction->block();
     block->insertBefore(oldInstruction, replacementInstruction);
     oldInstruction->replaceAllUsesWith(replacementInstruction);
     block->discard(oldInstruction);
+
+    // We may have replaced a specialized Float32 instruction by its
+    // non-specialized version, so just retry to specialize it. This relies on
+    // the fact that Phis' types don't change during the ParallelSafetyAnalysis;
+    // otherwise we'd have to run the entire TypeAnalyzer Float32 analysis once
+    // instructions have been replaced.
+    if (replacementInstruction->isFloat32Commutative() &&
+        replacementInstruction->type() != MIRType_Float32)
+    {
+        replacementInstruction->trySpecializeFloat32(alloc());
+    }
+    JS_ASSERT(oldInstruction->type() == replacementInstruction->type());
+
     return true;
 }
 
 /////////////////////////////////////////////////////////////////////////////
 // Write Guards
 //
 // We only want to permit writes to locally guarded objects.
 // Furthermore, we want to avoid PICs and other non-thread-safe things
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -955,24 +955,50 @@ Chunk::releaseArena(ArenaHeader *aheader
 inline bool
 GCRuntime::wantBackgroundAllocation() const
 {
     /*
      * To minimize memory waste we do not want to run the background chunk
      * allocation if we have empty chunks or when the runtime needs just few
      * of them.
      */
-    return helperThread.canBackgroundAllocate() &&
+    return helperState.canBackgroundAllocate() &&
            chunkPool.getEmptyCount() == 0 &&
            chunkSet.count() >= 4;
 }
 
+class js::gc::AutoMaybeStartBackgroundAllocation
+{
+  private:
+    JSRuntime *runtime;
+    MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
+
+  public:
+    AutoMaybeStartBackgroundAllocation(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM)
+      : runtime(nullptr)
+    {
+        MOZ_GUARD_OBJECT_NOTIFIER_INIT;
+    }
+
+    void tryToStartBackgroundAllocation(JSRuntime *rt) {
+        runtime = rt;
+    }
+
+    ~AutoMaybeStartBackgroundAllocation() {
+        if (runtime && !runtime->currentThreadOwnsInterruptLock()) {
+            AutoLockWorkerThreadState workerLock;
+            AutoLockGC lock(runtime);
+            runtime->gc.startBackgroundAllocationIfIdle();
+        }
+    }
+};
+
 /* The caller must hold the GC lock. */
 Chunk *
-GCRuntime::pickChunk(Zone *zone)
+GCRuntime::pickChunk(Zone *zone, AutoMaybeStartBackgroundAllocation &maybeStartBackgroundAllocation)
 {
     Chunk **listHeadp = GetAvailableChunkList(zone);
     Chunk *chunk = *listHeadp;
     if (chunk)
         return chunk;
 
     chunk = chunkPool.get(rt);
     if (!chunk) {
@@ -981,17 +1007,17 @@ GCRuntime::pickChunk(Zone *zone)
             return nullptr;
         JS_ASSERT(chunk->info.numArenasFreeCommitted == 0);
     }
 
     JS_ASSERT(chunk->unused());
     JS_ASSERT(!chunkSet.has(chunk));
 
     if (wantBackgroundAllocation())
-        helperThread.startBackgroundAllocationIfIdle();
+        maybeStartBackgroundAllocation.tryToStartBackgroundAllocation(rt);
 
     chunkAllocationSinceLastGC = true;
 
     /*
      * FIXME bug 583732 - chunk is newly allocated and cannot be present in
      * the table so using ordinary lookupForAdd is suboptimal here.
      */
     GCChunkSet::AddPtr p = chunkSet.lookupForAdd(chunk);
@@ -1089,17 +1115,17 @@ GCRuntime::GCRuntime(JSRuntime *rt) :
     mallocGCTriggered(false),
     scriptAndCountsVector(nullptr),
     alwaysPreserveCode(false),
 #ifdef DEBUG
     noGCOrAllocationCheck(0),
 #endif
     lock(nullptr),
     lockOwner(nullptr),
-    helperThread(rt)
+    helperState(rt)
 {
 }
 
 #ifdef JS_GC_ZEAL
 
 extern void
 js::SetGCZeal(JSRuntime *rt, uint8_t zeal, uint32_t frequency)
 {
@@ -1186,17 +1212,17 @@ GCRuntime::init(uint32_t maxbytes)
 #endif
 
     if (!chunkSet.init(INITIAL_CHUNK_CAPACITY))
         return false;
 
     if (!rootsHash.init(256))
         return false;
 
-    if (!helperThread.init())
+    if (!helperState.init())
         return false;
 
     /*
      * Separate gcMaxMallocBytes from gcMaxBytes but initialize to maxbytes
      * for default backward API compatibility.
      */
     maxBytes = maxbytes;
     rt->setGCMaxMallocBytes(maxbytes);
@@ -1237,17 +1263,17 @@ GCRuntime::recordNativeStackTop()
 
 void
 GCRuntime::finish()
 {
     /*
      * Wait until the background finalization stops and the helper thread
      * shuts down before we forcefully release any remaining GC memory.
      */
-    helperThread.finish();
+    helperState.finish();
 
 #ifdef JS_GC_ZEAL
     /* Free memory associated with GC verification. */
     finishVerifier();
 #endif
 
     /* Delete all remaining zones. */
     if (rt->gcInitialized) {
@@ -1497,17 +1523,18 @@ ArenaLists::prepareForIncrementalGC(JSRu
 static inline void
 PushArenaAllocatedDuringSweep(JSRuntime *runtime, ArenaHeader *arena)
 {
     arena->setNextAllocDuringSweep(runtime->gc.arenasAllocatedDuringSweep);
     runtime->gc.arenasAllocatedDuringSweep = arena;
 }
 
 inline void *
-ArenaLists::allocateFromArenaInline(Zone *zone, AllocKind thingKind)
+ArenaLists::allocateFromArenaInline(Zone *zone, AllocKind thingKind,
+                                    AutoMaybeStartBackgroundAllocation &maybeStartBackgroundAllocation)
 {
     /*
      * Parallel JS Note:
      *
      * This function can be called from parallel threads all of which
      * are associated with the same compartment. In that case, each
      * thread will have a distinct ArenaLists.  Therefore, whenever we
      * fall through to pickChunk() we must be sure that we are holding
@@ -1570,17 +1597,17 @@ ArenaLists::allocateFromArenaInline(Zone
         JS_ASSERT(thing);   // This allocation is infallible.
         return thing;
     }
 
     /* Make sure we hold the GC lock before we call pickChunk. */
     JSRuntime *rt = zone->runtimeFromAnyThread();
     if (!maybeLock.locked())
         maybeLock.lock(rt);
-    Chunk *chunk = rt->gc.pickChunk(zone);
+    Chunk *chunk = rt->gc.pickChunk(zone, maybeStartBackgroundAllocation);
     if (!chunk)
         return nullptr;
 
     /*
      * While we still hold the GC lock get an arena from some chunk, mark it
      * as full as its single free span is moved to the free lits, and insert
      * it to the list as a fully allocated arena.
      *
@@ -1615,17 +1642,18 @@ ArenaLists::allocateFromArenaInline(Zone
     fullSpan.initFinal(arena->thingsStart(thingKind), arena->thingsEnd() - thingSize, thingSize);
     freeLists[thingKind].setHead(&fullSpan);
     return freeLists[thingKind].allocate(thingSize);
 }
 
 void *
 ArenaLists::allocateFromArena(JS::Zone *zone, AllocKind thingKind)
 {
-    return allocateFromArenaInline(zone, thingKind);
+    AutoMaybeStartBackgroundAllocation maybeStartBackgroundAllocation;
+    return allocateFromArenaInline(zone, thingKind, maybeStartBackgroundAllocation);
 }
 
 void
 ArenaLists::wipeDuringParallelExecution(JSRuntime *rt)
 {
     JS_ASSERT(InParallelSection());
 
     // First, check that we all objects we have allocated are eligible
@@ -1690,17 +1718,17 @@ ArenaLists::queueForForegroundSweep(Free
 }
 
 inline void
 ArenaLists::queueForBackgroundSweep(FreeOp *fop, AllocKind thingKind)
 {
     JS_ASSERT(IsBackgroundFinalized(thingKind));
 
 #ifdef JS_THREADSAFE
-    JS_ASSERT(!fop->runtime()->gc.helperThread.sweeping());
+    JS_ASSERT(!fop->runtime()->gc.isBackgroundSweeping());
 #endif
 
     ArenaList *al = &arenaLists[thingKind];
     if (al->isEmpty()) {
         JS_ASSERT(backgroundFinalizeState[thingKind] == BFS_DONE);
         return;
     }
 
@@ -1862,33 +1890,36 @@ ArenaLists::refillFreeList(ThreadSafeCon
 #endif
 
     for (;;) {
         if (MOZ_UNLIKELY(runGC)) {
             if (void *thing = RunLastDitchGC(cx->asJSContext(), zone, thingKind))
                 return thing;
         }
 
+        AutoMaybeStartBackgroundAllocation maybeStartBackgroundAllocation;
+
         if (cx->isJSContext()) {
             /*
              * allocateFromArena may fail while the background finalization still
              * run. If we are on the main thread, we want to wait for it to finish
              * and restart. However, checking for that is racy as the background
              * finalization could free some things after allocateFromArena decided
              * to fail but at this point it may have already stopped. To avoid
              * this race we always try to allocate twice.
              */
             for (bool secondAttempt = false; ; secondAttempt = true) {
-                void *thing = cx->allocator()->arenas.allocateFromArenaInline(zone, thingKind);
+                void *thing = cx->allocator()->arenas.allocateFromArenaInline(zone, thingKind,
+                                                                              maybeStartBackgroundAllocation);
                 if (MOZ_LIKELY(!!thing))
                     return thing;
                 if (secondAttempt)
                     break;
 
-                cx->asJSContext()->runtime()->gc.helperThread.waitBackgroundSweepEnd();
+                cx->asJSContext()->runtime()->gc.waitBackgroundSweepEnd();
             }
         } else {
 #ifdef JS_THREADSAFE
             /*
              * If we're off the main thread, we try to allocate once and
              * return whatever value we get. If we aren't in a ForkJoin
              * session (i.e. we are in a worker thread async with the main
              * thread), we need to first ensure the main thread is not in a GC
@@ -1897,17 +1928,18 @@ ArenaLists::refillFreeList(ThreadSafeCon
             mozilla::Maybe<AutoLockWorkerThreadState> lock;
             JSRuntime *rt = zone->runtimeFromAnyThread();
             if (rt->exclusiveThreadsPresent()) {
                 lock.construct();
                 while (rt->isHeapBusy())
                     WorkerThreadState().wait(GlobalWorkerThreadState::PRODUCER);
             }
 
-            void *thing = cx->allocator()->arenas.allocateFromArenaInline(zone, thingKind);
+            void *thing = cx->allocator()->arenas.allocateFromArenaInline(zone, thingKind,
+                                                                          maybeStartBackgroundAllocation);
             if (thing)
                 return thing;
 #else
             MOZ_CRASH();
 #endif
         }
 
         if (!cx->allowGC() || !allowGC)
@@ -2097,17 +2129,17 @@ GCRuntime::maybeGC(Zone *zone)
         GCSlice(rt, GC_NORMAL, JS::gcreason::MAYBEGC);
         return;
     }
 
     double factor = highFrequencyGC ? 0.85 : 0.9;
     if (zone->gcBytes > 1024 * 1024 &&
         zone->gcBytes >= factor * zone->gcTriggerBytes &&
         incrementalState == NO_INCREMENTAL &&
-        !helperThread.sweeping())
+        !isBackgroundSweeping())
     {
         PrepareZoneForGC(zone);
         GCSlice(rt, GC_NORMAL, JS::gcreason::MAYBEGC);
         return;
     }
 
 #ifndef JS_MORE_DETERMINISTIC
     /*
@@ -2279,23 +2311,25 @@ SweepBackgroundThings(JSRuntime* rt, boo
 
     rt->gc.sweepingZones = nullptr;
 }
 
 #ifdef JS_THREADSAFE
 static void
 AssertBackgroundSweepingFinished(JSRuntime *rt)
 {
+#ifdef DEBUG
     JS_ASSERT(!rt->gc.sweepingZones);
     for (ZonesIter zone(rt, WithAtoms); !zone.done(); zone.next()) {
         for (unsigned i = 0; i < FINALIZE_LIMIT; ++i) {
             JS_ASSERT(!zone->allocator.arenas.arenaListsToSweep[i]);
             JS_ASSERT(zone->allocator.arenas.doneBackgroundFinalize(AllocKind(i)));
         }
     }
+#endif
 }
 
 unsigned
 js::GetCPUCount()
 {
     static unsigned ncpus = 0;
     if (ncpus == 0) {
 # ifdef XP_WIN
@@ -2307,261 +2341,255 @@ js::GetCPUCount()
         ncpus = (n > 0) ? unsigned(n) : 1;
 # endif
     }
     return ncpus;
 }
 #endif /* JS_THREADSAFE */
 
 bool
-GCHelperThread::init()
+GCHelperState::init()
 {
     if (!rt->useHelperThreads()) {
         backgroundAllocation = false;
         return true;
     }
 
 #ifdef JS_THREADSAFE
-    if (!(wakeup = PR_NewCondVar(rt->gc.lock)))
-        return false;
     if (!(done = PR_NewCondVar(rt->gc.lock)))
         return false;
 
-    thread = PR_CreateThread(PR_USER_THREAD, threadMain, this, PR_PRIORITY_NORMAL,
-                             PR_GLOBAL_THREAD, PR_JOINABLE_THREAD, 0);
-    if (!thread)
-        return false;
-
     backgroundAllocation = (GetCPUCount() >= 2);
+
+    WorkerThreadState().ensureInitialized();
 #endif /* JS_THREADSAFE */
+
     return true;
 }
 
 void
-GCHelperThread::finish()
+GCHelperState::finish()
 {
     if (!rt->useHelperThreads() || !rt->gc.lock) {
-        JS_ASSERT(state == IDLE);
+        JS_ASSERT(state_ == IDLE);
         return;
     }
 
 #ifdef JS_THREADSAFE
-    PRThread *join = nullptr;
-    {
-        AutoLockGC lock(rt);
-        if (thread && state != SHUTDOWN) {
-            /*
-             * We cannot be in the ALLOCATING or CANCEL_ALLOCATION states as
-             * the allocations should have been stopped during the last GC.
-             */
-            JS_ASSERT(state == IDLE || state == SWEEPING);
-            if (state == IDLE)
-                PR_NotifyCondVar(wakeup);
-            state = SHUTDOWN;
-            join = thread;
-        }
-    }
-    if (join) {
-        /* PR_DestroyThread is not necessary. */
-        PR_JoinThread(join);
-    }
-    if (wakeup)
-        PR_DestroyCondVar(wakeup);
+    // Wait for any lingering background sweeping to finish.
+    waitBackgroundSweepEnd();
+
     if (done)
         PR_DestroyCondVar(done);
+#else
+    MOZ_CRASH();
 #endif /* JS_THREADSAFE */
 }
 
-#ifdef JS_THREADSAFE
-#ifdef MOZ_NUWA_PROCESS
-extern "C" {
-MFBT_API bool IsNuwaProcess();
-MFBT_API void NuwaMarkCurrentThread(void (*recreate)(void *), void *arg);
-}
-#endif
-
-/* static */
+GCHelperState::State
+GCHelperState::state()
+{
+    JS_ASSERT(rt->gc.currentThreadOwnsGCLock());
+    return state_;
+}
+
 void
-GCHelperThread::threadMain(void *arg)
-{
-    PR_SetCurrentThreadName("JS GC Helper");
-
-#ifdef MOZ_NUWA_PROCESS
-    if (IsNuwaProcess && IsNuwaProcess()) {
-        JS_ASSERT(NuwaMarkCurrentThread != nullptr);
-        NuwaMarkCurrentThread(nullptr, nullptr);
-    }
-#endif
-
-    static_cast<GCHelperThread *>(arg)->threadLoop();
+GCHelperState::setState(State state)
+{
+    JS_ASSERT(rt->gc.currentThreadOwnsGCLock());
+    state_ = state;
 }
 
 void
-GCHelperThread::wait(PRCondVar *which)
-{
+GCHelperState::startBackgroundThread(State newState)
+{
+#ifdef JS_THREADSAFE
+    JS_ASSERT(!thread && state() == IDLE && newState != IDLE);
+    setState(newState);
+
+    if (!WorkerThreadState().gcHelperWorklist().append(this))
+        CrashAtUnhandlableOOM("Could not add to pending GC helpers list");
+    WorkerThreadState().notifyAll(GlobalWorkerThreadState::PRODUCER);
+#else
+    MOZ_CRASH();
+#endif
+}
+
+void
+GCHelperState::waitForBackgroundThread()
+{
+#ifdef JS_THREADSAFE
+    JS_ASSERT(CurrentThreadCanAccessRuntime(rt));
+
     rt->gc.lockOwner = nullptr;
-    PR_WaitCondVar(which, PR_INTERVAL_NO_TIMEOUT);
+    PR_WaitCondVar(done, PR_INTERVAL_NO_TIMEOUT);
 #ifdef DEBUG
     rt->gc.lockOwner = PR_GetCurrentThread();
 #endif
+#else
+    MOZ_CRASH();
+#endif
 }
 
 void
-GCHelperThread::threadLoop()
-{
+GCHelperState::work()
+{
+#ifdef JS_THREADSAFE
     AutoLockGC lock(rt);
 
-    TraceLogger *logger = TraceLoggerForCurrentThread();
-
-    /*
-     * Even on the first iteration the state can be SHUTDOWN or SWEEPING if
-     * the stop request or the GC and the corresponding startBackgroundSweep call
-     * happen before this thread has a chance to run.
-     */
-    for (;;) {
-        switch (state) {
-          case SHUTDOWN:
-            return;
-          case IDLE:
-            wait(wakeup);
-            break;
-          case SWEEPING: {
-            AutoTraceLog logSweeping(logger, TraceLogger::GCSweeping);
-            doSweep();
-            if (state == SWEEPING)
-                state = IDLE;
-            PR_NotifyAllCondVar(done);
-            break;
-          }
-          case ALLOCATING: {
-            AutoTraceLog logAllocating(logger, TraceLogger::GCAllocation);
-            do {
-                Chunk *chunk;
-                {
-                    AutoUnlockGC unlock(rt);
-                    chunk = Chunk::allocate(rt);
-                }
-
-                /* OOM stops the background allocation. */
-                if (!chunk)
-                    break;
-                JS_ASSERT(chunk->info.numArenasFreeCommitted == 0);
-                rt->gc.chunkPool.put(chunk);
-            } while (state == ALLOCATING && rt->gc.wantBackgroundAllocation());
-            if (state == ALLOCATING)
-                state = IDLE;
-            break;
-          }
-          case CANCEL_ALLOCATION:
-            state = IDLE;
-            PR_NotifyAllCondVar(done);
-            break;
-        }
+    JS_ASSERT(!thread);
+    thread = PR_GetCurrentThread();
+
+    switch (state()) {
+
+      case IDLE:
+        MOZ_ASSUME_UNREACHABLE("GC helper triggered on idle state");
+        break;
+
+      case SWEEPING: {
+#if JS_TRACE_LOGGING
+        AutoTraceLog logger(TraceLogging::getLogger(TraceLogging::GC_BACKGROUND),
+                            TraceLogging::GC_SWEEPING_START,
+                            TraceLogging::GC_SWEEPING_STOP);
+#endif
+        doSweep();
+        JS_ASSERT(state() == SWEEPING);
+        break;
+      }
+
+      case ALLOCATING: {
+#if JS_TRACE_LOGGING
+        AutoTraceLog logger(TraceLogging::getLogger(TraceLogging::GC_BACKGROUND),
+                            TraceLogging::GC_ALLOCATING_START,
+                            TraceLogging::GC_ALLOCATING_STOP);
+#endif
+        do {
+            Chunk *chunk;
+            {
+                AutoUnlockGC unlock(rt);
+                chunk = Chunk::allocate(rt);
+            }
+
+            /* OOM stops the background allocation. */
+            if (!chunk)
+                break;
+            JS_ASSERT(chunk->info.numArenasFreeCommitted == 0);
+            rt->gc.chunkPool.put(chunk);
+        } while (state() == ALLOCATING && rt->gc.wantBackgroundAllocation());
+
+        JS_ASSERT(state() == ALLOCATING || state() == CANCEL_ALLOCATION);
+        break;
+      }
+
+      case CANCEL_ALLOCATION:
+        break;
     }
-}
-#endif /* JS_THREADSAFE */
+
+    setState(IDLE);
+    thread = nullptr;
+
+    PR_NotifyAllCondVar(done);
+#else
+    MOZ_CRASH();
+#endif
+}
 
 void
-GCHelperThread::startBackgroundSweep(bool shouldShrink)
+GCHelperState::startBackgroundSweep(bool shouldShrink)
 {
     JS_ASSERT(rt->useHelperThreads());
 
 #ifdef JS_THREADSAFE
+    AutoLockWorkerThreadState workerLock;
     AutoLockGC lock(rt);
-    JS_ASSERT(state == IDLE);
+    JS_ASSERT(state() == IDLE);
     JS_ASSERT(!sweepFlag);
     sweepFlag = true;
     shrinkFlag = shouldShrink;
-    state = SWEEPING;
-    PR_NotifyCondVar(wakeup);
+    startBackgroundThread(SWEEPING);
 #endif /* JS_THREADSAFE */
 }
 
 /* Must be called with the GC lock taken. */
 void
-GCHelperThread::startBackgroundShrink()
+GCHelperState::startBackgroundShrink()
 {
     JS_ASSERT(rt->useHelperThreads());
 
 #ifdef JS_THREADSAFE
-    switch (state) {
+    switch (state()) {
       case IDLE:
         JS_ASSERT(!sweepFlag);
         shrinkFlag = true;
-        state = SWEEPING;
-        PR_NotifyCondVar(wakeup);
+        startBackgroundThread(SWEEPING);
         break;
       case SWEEPING:
         shrinkFlag = true;
         break;
       case ALLOCATING:
       case CANCEL_ALLOCATION:
         /*
          * If we have started background allocation there is nothing to
          * shrink.
          */
         break;
-      case SHUTDOWN:
-        MOZ_ASSUME_UNREACHABLE("No shrink on shutdown");
     }
 #endif /* JS_THREADSAFE */
 }
 
 void
-GCHelperThread::waitBackgroundSweepEnd()
+GCHelperState::waitBackgroundSweepEnd()
 {
     if (!rt->useHelperThreads()) {
-        JS_ASSERT(state == IDLE);
+        JS_ASSERT(state_ == IDLE);
         return;
     }
 
 #ifdef JS_THREADSAFE
     AutoLockGC lock(rt);
-    while (state == SWEEPING)
-        wait(done);
+    while (state() == SWEEPING)
+        waitForBackgroundThread();
     if (rt->gc.incrementalState == NO_INCREMENTAL)
         AssertBackgroundSweepingFinished(rt);
 #endif /* JS_THREADSAFE */
 }
 
 void
-GCHelperThread::waitBackgroundSweepOrAllocEnd()
+GCHelperState::waitBackgroundSweepOrAllocEnd()
 {
     if (!rt->useHelperThreads()) {
-        JS_ASSERT(state == IDLE);
+        JS_ASSERT(state_ == IDLE);
         return;
     }
 
 #ifdef JS_THREADSAFE
     AutoLockGC lock(rt);
-    if (state == ALLOCATING)
-        state = CANCEL_ALLOCATION;
-    while (state == SWEEPING || state == CANCEL_ALLOCATION)
-        wait(done);
+    if (state() == ALLOCATING)
+        setState(CANCEL_ALLOCATION);
+    while (state() == SWEEPING || state() == CANCEL_ALLOCATION)
+        waitForBackgroundThread();
     if (rt->gc.incrementalState == NO_INCREMENTAL)
         AssertBackgroundSweepingFinished(rt);
 #endif /* JS_THREADSAFE */
 }
 
 /* Must be called with the GC lock taken. */
 inline void
-GCHelperThread::startBackgroundAllocationIfIdle()
+GCHelperState::startBackgroundAllocationIfIdle()
 {
     JS_ASSERT(rt->useHelperThreads());
 
 #ifdef JS_THREADSAFE
-    if (state == IDLE) {
-        state = ALLOCATING;
-        PR_NotifyCondVar(wakeup);
-    }
+    if (state_ == IDLE)
+        startBackgroundThread(ALLOCATING);
 #endif /* JS_THREADSAFE */
 }
 
 void
-GCHelperThread::replenishAndFreeLater(void *ptr)
+GCHelperState::replenishAndFreeLater(void *ptr)
 {
     JS_ASSERT(freeCursor == freeCursorEnd);
     do {
         if (freeCursor && !freeVector.append(freeCursorEnd - FREE_ARRAY_LENGTH))
             break;
         freeCursor = (void **) js_malloc(FREE_ARRAY_SIZE);
         if (!freeCursor) {
             freeCursorEnd = nullptr;
@@ -2572,17 +2600,17 @@ GCHelperThread::replenishAndFreeLater(vo
         return;
     } while (false);
     js_free(ptr);
 }
 
 #ifdef JS_THREADSAFE
 /* Must be called with the GC lock taken. */
 void
-GCHelperThread::doSweep()
+GCHelperState::doSweep()
 {
     if (sweepFlag) {
         sweepFlag = false;
         AutoUnlockGC unlock(rt);
 
         SweepBackgroundThings(rt, true);
 
         if (freeCursor) {
@@ -2612,20 +2640,20 @@ GCHelperThread::doSweep()
     if (!shrinking && shrinkFlag) {
         shrinkFlag = false;
         ExpireChunksAndArenas(rt, true);
     }
 }
 #endif /* JS_THREADSAFE */
 
 bool
-GCHelperThread::onBackgroundThread()
+GCHelperState::onBackgroundThread()
 {
 #ifdef JS_THREADSAFE
-    return PR_GetCurrentThread() == getThread();
+    return PR_GetCurrentThread() == thread;
 #else
     return false;
 #endif
 }
 
 bool
 GCRuntime::releaseObservedTypes()
 {
@@ -4138,17 +4166,17 @@ GCRuntime::endSweepPhase(JSGCInvocationK
          */
         if (!lastGC)
             sweepZones(&fop, lastGC);
 
         if (!sweepOnBackgroundThread) {
             /*
              * Destroy arenas after we finished the sweeping so finalizers can
              * safely use IsAboutToBeFinalized(). This is done on the
-             * GCHelperThread if possible. We acquire the lock only because
+             * GCHelperState if possible. We acquire the lock only because
              * Expire needs to unlock it for other callers.
              */
             AutoLockGC lock(rt);
             ExpireChunksAndArenas(rt, gckind == GC_SHRINK);
         }
     }
 
     {
@@ -4402,17 +4430,17 @@ GCRuntime::resetIncrementalGC(const char
             zone->scheduledForDestruction = false;
 
         /* Finish sweeping the current zone group, then abort. */
         abortSweepAfterCurrentGroup = true;
         incrementalCollectSlice(SliceBudget::Unlimited, JS::gcreason::RESET, GC_NORMAL);
 
         {
             gcstats::AutoPhase ap(stats, gcstats::PHASE_WAIT_BACKGROUND_THREAD);
-            helperThread.waitBackgroundSweepOrAllocEnd();
+            rt->gc.waitBackgroundSweepOrAllocEnd();
         }
         break;
 
       default:
         MOZ_ASSUME_UNREACHABLE("Invalid incremental GC state");
     }
 
     stats.reset(reason);
@@ -4613,17 +4641,17 @@ GCRuntime::incrementalCollectSlice(int64
       case SWEEP: {
         bool finished = sweepPhase(sliceBudget);
         if (!finished)
             break;
 
         endSweepPhase(gckind, lastGC);
 
         if (sweepOnBackgroundThread)
-            helperThread.startBackgroundSweep(gckind == GC_SHRINK);
+            helperState.startBackgroundSweep(gckind == GC_SHRINK);
 
         incrementalState = NO_INCREMENTAL;
         break;
       }
 
       default:
         JS_ASSERT(false);
     }
@@ -4707,17 +4735,17 @@ GCRuntime::gcCycle(bool incremental, int
     /*
      * As we about to purge caches and clear the mark bits we must wait for
      * any background finalization to finish. We must also wait for the
      * background allocation to finish so we can avoid taking the GC lock
      * when manipulating the chunks during the GC.
      */
     {
         gcstats::AutoPhase ap(stats, gcstats::PHASE_WAIT_BACKGROUND_THREAD);
-        helperThread.waitBackgroundSweepOrAllocEnd();
+        waitBackgroundSweepOrAllocEnd();
     }
 
     State prevState = incrementalState;
 
     if (!incremental) {
         /* If non-incremental GC was requested, reset incremental GC. */
         resetIncrementalGC("requested");
         stats.nonincremental("requested");
@@ -4954,16 +4982,17 @@ js::PrepareForDebugGC(JSRuntime *rt)
 {
     if (!ZonesSelected(rt))
         JS::PrepareForFullGC(rt);
 }
 
 JS_FRIEND_API(void)
 JS::ShrinkGCBuffers(JSRuntime *rt)
 {
+    AutoLockWorkerThreadState workerLock;
     AutoLockGC lock(rt);
     JS_ASSERT(!rt->isHeapBusy());
 
     if (!rt->useHelperThreads())
         ExpireChunksAndArenas(rt, true);
     else
         rt->gc.startBackgroundShrink();
 }
--- a/js/src/jsgc.h
+++ b/js/src/jsgc.h
@@ -28,17 +28,16 @@ class JSLinearString;
 namespace js {
 
 class ArgumentsObject;
 class ArrayBufferObject;
 class ArrayBufferViewObject;
 class SharedArrayBufferObject;
 class BaseShape;
 class DebugScopeObject;
-class GCHelperThread;
 class GlobalObject;
 class LazyScript;
 class Nursery;
 class PropertyName;
 class ScopeObject;
 class Shape;
 class UnownedBaseShape;
 
@@ -350,16 +349,22 @@ GetGCKindSlots(AllocKind thingKind, cons
      * space for the extra fields in JSFunction, but have no fixed slots.
      */
     if (clasp == FunctionClassPtr)
         nslots = 0;
 
     return nslots;
 }
 
+// Class to assist in triggering background chunk allocation. This cannot be done
+// while holding the GC or worker thread state lock due to lock ordering issues.
+// As a result, the triggering is delayed using this class until neither of the
+// above locks is held.
+class AutoMaybeStartBackgroundAllocation;
+
 /*
  * Arena lists have a head and a cursor. The cursor conceptually lies on arena
  * boundaries, i.e. before the first arena, between two arenas, or after the
  * last arena.
  *
  * Normally the arena following the cursor is the first arena in the list with
  * some free things and all arenas before the cursor are fully allocated. (And
  * if the cursor is at the end of the list, then all the arenas are full.)
@@ -766,17 +771,18 @@ class ArenaLists
 
   private:
     inline void finalizeNow(FreeOp *fop, AllocKind thingKind);
     inline void forceFinalizeNow(FreeOp *fop, AllocKind thingKind);
     inline void queueForForegroundSweep(FreeOp *fop, AllocKind thingKind);
     inline void queueForBackgroundSweep(FreeOp *fop, AllocKind thingKind);
 
     void *allocateFromArena(JS::Zone *zone, AllocKind thingKind);
-    inline void *allocateFromArenaInline(JS::Zone *zone, AllocKind thingKind);
+    inline void *allocateFromArenaInline(JS::Zone *zone, AllocKind thingKind,
+                                         AutoMaybeStartBackgroundAllocation &maybeStartBackgroundAllocation);
 
     inline void normalizeBackgroundFinalizeState(AllocKind thingKind);
 
     friend class js::Nursery;
 };
 
 /*
  * Initial allocation size for data structures holding chunks is set to hold
@@ -909,52 +915,64 @@ NotifyGCNukeWrapper(JSObject *o);
 
 extern unsigned
 NotifyGCPreSwap(JSObject *a, JSObject *b);
 
 extern void
 NotifyGCPostSwap(JSObject *a, JSObject *b, unsigned preResult);
 
 /*
- * Helper that implements sweeping and allocation for kinds that can be swept
- * and allocated off the main thread.
+ * Helper state for use when JS helper threads sweep and allocate GC thing kinds
+ * that can be swept and allocated off the main thread.
  *
  * In non-threadsafe builds, all actual sweeping and allocation is performed
- * on the main thread, but GCHelperThread encapsulates this from clients as
+ * on the main thread, but GCHelperState encapsulates this from clients as
  * much as possible.
  */
-class GCHelperThread {
+class GCHelperState
+{
     enum State {
         IDLE,
         SWEEPING,
         ALLOCATING,
-        CANCEL_ALLOCATION,
-        SHUTDOWN
+        CANCEL_ALLOCATION
     };
 
     /*
      * During the finalization we do not free immediately. Rather we add the
      * corresponding pointers to a buffer which we later release on a
      * separated thread.
      *
      * The buffer is implemented as a vector of 64K arrays of pointers, not as
      * a simple vector, to avoid realloc calls during the vector growth and to
      * not bloat the binary size of the inlined freeLater method. Any OOM
      * during buffer growth results in the pointer being freed immediately.
      */
     static const size_t FREE_ARRAY_SIZE = size_t(1) << 16;
     static const size_t FREE_ARRAY_LENGTH = FREE_ARRAY_SIZE / sizeof(void *);
 
-    JSRuntime         *const rt;
-    PRThread          *thread;
-    PRCondVar         *wakeup;
-    PRCondVar         *done;
-    volatile State    state;
+    // Associated runtime.
+    JSRuntime *const rt;
+
+    // Condvar for notifying the main thread when work has finished. This is
+    // associated with the runtime's GC lock --- the worker thread state
+    // condvars can't be used here due to lock ordering issues.
+    PRCondVar *done;
 
-    void wait(PRCondVar *which);
+    // Activity for the helper to do, protected by the GC lock.
+    State state_;
+
+    // Thread which work is being performed on, or null.
+    PRThread *thread;
+
+    void startBackgroundThread(State newState);
+    void waitForBackgroundThread();
+
+    State state();
+    void setState(State state);
 
     bool              sweepFlag;
     bool              shrinkFlag;
 
     Vector<void **, 16, js::SystemAllocPolicy> freeVector;
     void            **freeCursor;
     void            **freeCursorEnd;
 
@@ -967,83 +985,77 @@ class GCHelperThread {
 
     static void freeElementsAndArray(void **array, void **end) {
         JS_ASSERT(array <= end);
         for (void **p = array; p != end; ++p)
             js_free(*p);
         js_free(array);
     }
 
-    static void threadMain(void* arg);
-    void threadLoop();
-
     /* Must be called with the GC lock taken. */
     void doSweep();
 
   public:
-    explicit GCHelperThread(JSRuntime *rt)
+    explicit GCHelperState(JSRuntime *rt)
       : rt(rt),
+        done(nullptr),
+        state_(IDLE),
         thread(nullptr),
-        wakeup(nullptr),
-        done(nullptr),
-        state(IDLE),
         sweepFlag(false),
         shrinkFlag(false),
         freeCursor(nullptr),
         freeCursorEnd(nullptr),
         backgroundAllocation(true)
     { }
 
     bool init();
     void finish();
 
+    void work();
+
     /* Must be called with the GC lock taken. */
     void startBackgroundSweep(bool shouldShrink);
 
     /* Must be called with the GC lock taken. */
     void startBackgroundShrink();
 
     /* Must be called without the GC lock taken. */
     void waitBackgroundSweepEnd();
 
     /* Must be called without the GC lock taken. */
     void waitBackgroundSweepOrAllocEnd();
 
     /* Must be called with the GC lock taken. */
-    inline void startBackgroundAllocationIfIdle();
+    void startBackgroundAllocationIfIdle();
 
     bool canBackgroundAllocate() const {
         return backgroundAllocation;
     }
 
     void disableBackgroundAllocation() {
         backgroundAllocation = false;
     }
 
-    PRThread *getThread() const {
-        return thread;
-    }
-
     bool onBackgroundThread();
 
     /*
      * Outside the GC lock may give true answer when in fact the sweeping has
      * been done.
      */
-    bool sweeping() const {
-        return state == SWEEPING;
+    bool isBackgroundSweeping() const {
+        return state_ == SWEEPING;
     }
 
     bool shouldShrink() const {
-        JS_ASSERT(sweeping());
+        JS_ASSERT(isBackgroundSweeping());
         return shrinkFlag;
     }
 
     void freeLater(void *ptr) {
-        JS_ASSERT(!sweeping());
+        JS_ASSERT(!isBackgroundSweeping());
         if (freeCursor != freeCursorEnd)
             *freeCursor++ = ptr;
         else
             replenishAndFreeLater(ptr);
     }
 };
 
 struct GCChunkHasher {
--- a/js/src/jsinferinlines.h
+++ b/js/src/jsinferinlines.h
@@ -728,17 +728,17 @@ TypeScript::MonitorAssign(JSContext *cx,
         uint32_t i;
         if (js_IdIsIndex(id, &i))
             return;
 
         // But if we don't have too many properties yet, don't do anything.  The
         // idea here is that normal object initialization should not trigger
         // deoptimization in most cases, while actual usage as a hashmap should.
         TypeObject* type = obj->type();
-        if (type->getPropertyCount() < 8)
+        if (type->getPropertyCount() < 128)
             return;
         MarkTypeObjectUnknownProperties(cx, type);
     }
 }
 
 /* static */ inline void
 TypeScript::SetThis(JSContext *cx, JSScript *script, Type type)
 {
--- a/js/src/jsworkers.cpp
+++ b/js/src/jsworkers.cpp
@@ -573,16 +573,22 @@ GlobalWorkerThreadState::canStartParseTa
 }
 
 bool
 GlobalWorkerThreadState::canStartCompressionTask()
 {
     return !compressionWorklist().empty();
 }
 
+bool
+GlobalWorkerThreadState::canStartGCHelperTask()
+{
+    return !gcHelperWorklist().empty();
+}
+
 static void
 CallNewScriptHookForAllScripts(JSContext *cx, HandleScript script)
 {
     // We should never hit this, since nested scripts are also constructed via
     // BytecodeEmitter instances on the stack.
     JS_CHECK_RECURSION(cx, return);
 
     // Recurse to any nested scripts.
@@ -1016,16 +1022,34 @@ GlobalWorkerThreadState::compressionTask
         SourceCompressionTask *task = threads[i].compressionTask;
         if (task && task->source() == ss)
             return task;
     }
     return nullptr;
 }
 
 void
+WorkerThread::handleGCHelperWorkload()
+{
+    JS_ASSERT(WorkerThreadState().isLocked());
+    JS_ASSERT(WorkerThreadState().canStartGCHelperTask());
+    JS_ASSERT(idle());
+
+    JS_ASSERT(!gcHelperState);
+    gcHelperState = WorkerThreadState().gcHelperWorklist().popCopy();
+
+    {
+        AutoUnlockWorkerThreadState unlock;
+        gcHelperState->work();
+    }
+
+    gcHelperState = nullptr;
+}
+
+void
 WorkerThread::threadLoop()
 {
     JS::AutoAssertNoGC nogc;
     AutoLockWorkerThreadState lock;
 
     js::TlsPerThreadData.set(threadData.addr());
 
     // Compute the thread's stack limit, for over-recursed checks.
@@ -1043,32 +1067,35 @@ WorkerThread::threadLoop()
 
         // Block until a task is available.
         while (true) {
             if (terminate)
                 return;
             if (WorkerThreadState().canStartIonCompile() ||
                 WorkerThreadState().canStartAsmJSCompile() ||
                 WorkerThreadState().canStartParseTask() ||
-                WorkerThreadState().canStartCompressionTask())
+                WorkerThreadState().canStartCompressionTask() ||
+                WorkerThreadState().canStartGCHelperTask())
             {
                 break;
             }
             WorkerThreadState().wait(GlobalWorkerThreadState::PRODUCER);
         }
 
         // Dispatch tasks, prioritizing AsmJS work.
         if (WorkerThreadState().canStartAsmJSCompile())
             handleAsmJSWorkload();
         else if (WorkerThreadState().canStartIonCompile())
             handleIonWorkload();
         else if (WorkerThreadState().canStartParseTask())
             handleParseWorkload();
         else if (WorkerThreadState().canStartCompressionTask())
             handleCompressionWorkload();
+        else if (WorkerThreadState().canStartGCHelperTask())
+            handleGCHelperWorkload();
         else
             MOZ_ASSUME_UNREACHABLE("No task to perform");
     }
 }
 
 #else /* JS_THREADSAFE */
 
 using namespace js;
--- a/js/src/jsworkers.h
+++ b/js/src/jsworkers.h
@@ -43,16 +43,17 @@ class GlobalWorkerThreadState
 
     // Number of threads to create. May be accessed without locking.
     size_t threadCount;
 
     typedef Vector<jit::IonBuilder*, 0, SystemAllocPolicy> IonBuilderVector;
     typedef Vector<AsmJSParallelTask*, 0, SystemAllocPolicy> AsmJSParallelTaskVector;
     typedef Vector<ParseTask*, 0, SystemAllocPolicy> ParseTaskVector;
     typedef Vector<SourceCompressionTask*, 0, SystemAllocPolicy> SourceCompressionTaskVector;
+    typedef Vector<GCHelperState *, 0, SystemAllocPolicy> GCHelperStateVector;
 
     // List of available threads, or null if the thread state has not been initialized.
     WorkerThread *threads;
 
   private:
     // The lists below are all protected by |lock|.
 
     // Ion compilation worklist and finished jobs.
@@ -76,16 +77,19 @@ class GlobalWorkerThreadState
     ParseTaskVector parseWorklist_, parseFinishedList_;
 
     // Parse tasks waiting for an atoms-zone GC to complete.
     ParseTaskVector parseWaitingOnGC_;
 
     // Source compression worklist.
     SourceCompressionTaskVector compressionWorklist_;
 
+    // Runtimes which have sweeping / allocating work to do.
+    GCHelperStateVector gcHelperWorklist_;
+
   public:
     GlobalWorkerThreadState();
 
     void ensureInitialized();
     void finish();
 
     void lock();
     void unlock();
@@ -145,20 +149,26 @@ class GlobalWorkerThreadState
         return parseWaitingOnGC_;
     }
 
     SourceCompressionTaskVector &compressionWorklist() {
         JS_ASSERT(isLocked());
         return compressionWorklist_;
     }
 
+    GCHelperStateVector &gcHelperWorklist() {
+        JS_ASSERT(isLocked());
+        return gcHelperWorklist_;
+    }
+
     bool canStartAsmJSCompile();
     bool canStartIonCompile();
     bool canStartParseTask();
     bool canStartCompressionTask();
+    bool canStartGCHelperTask();
 
     uint32_t harvestFailedAsmJSJobs() {
         JS_ASSERT(isLocked());
         uint32_t n = numAsmJSFailedJobs;
         numAsmJSFailedJobs = 0;
         return n;
     }
     void noteAsmJSFailure(void *func) {
@@ -235,26 +245,30 @@ struct WorkerThread
     AsmJSParallelTask *asmData;
 
     /* Any source being parsed/emitted on this thread. */
     ParseTask *parseTask;
 
     /* Any source being compressed on this thread. */
     SourceCompressionTask *compressionTask;
 
+    /* Any GC state for background sweeping or allocating being performed. */
+    GCHelperState *gcHelperState;
+
     bool idle() const {
-        return !ionBuilder && !asmData && !parseTask && !compressionTask;
+        return !ionBuilder && !asmData && !parseTask && !compressionTask && !gcHelperState;
     }
 
     void destroy();
 
     void handleAsmJSWorkload();
     void handleIonWorkload();
     void handleParseWorkload();
     void handleCompressionWorkload();
+    void handleGCHelperWorkload();
 
     static void ThreadMain(void *arg);
     void threadLoop();
 };
 
 #endif /* JS_THREADSAFE */
 
 /* Methods for interacting with worker threads. */
--- a/js/src/vm/RegExpObject.cpp
+++ b/js/src/vm/RegExpObject.cpp
@@ -97,24 +97,16 @@ RegExpObject *
 RegExpObjectBuilder::build(HandleAtom source, RegExpFlag flags)
 {
     if (!getOrCreate())
         return nullptr;
 
     return reobj_->init(cx, source, flags) ? reobj_.get() : nullptr;
 }
 
-static inline void
-MaybeTraceRegExpShared(JSContext *cx, RegExpShared *shared)
-{
-    Zone *zone = cx->zone();
-    if (zone->needsBarrier())
-        shared->trace(zone->barrierTracer());
-}
-
 RegExpObject *
 RegExpObjectBuilder::clone(Handle<RegExpObject *> other)
 {
     RootedTypeObject type(cx, other->type());
     if (!getOrCreateClone(type))
         return nullptr;
 
     /*
@@ -133,20 +125,16 @@ RegExpObjectBuilder::clone(Handle<RegExp
         Rooted<JSAtom *> source(cx, other->getSource());
         return build(source, newFlags);
     }
 
     RegExpGuard g(cx);
     if (!other->getShared(cx->asJSContext(), &g))
         return nullptr;
 
-    // Copying a RegExpShared from one object to another requires a read
-    // barrier, as the shared pointer in an object may be weak.
-    MaybeTraceRegExpShared(cx->asJSContext(), g.re());
-
     Rooted<JSAtom *> source(cx, other->getSource());
     return build(source, *g);
 }
 
 /* MatchPairs */
 
 bool
 MatchPairs::initArray(size_t pairCount)
@@ -223,16 +211,39 @@ VectorMatchPairs::allocOrExpandArray(siz
 
     pairs_ = &vec_[0];
     pairCount_ = pairCount;
     return true;
 }
 
 /* RegExpObject */
 
+static inline void
+MaybeTraceRegExpShared(JSContext *cx, RegExpShared *shared)
+{
+    Zone *zone = cx->zone();
+    if (zone->needsBarrier())
+        shared->trace(zone->barrierTracer());
+}
+
+bool
+RegExpObject::getShared(JSContext *cx, RegExpGuard *g)
+{
+    if (RegExpShared *shared = maybeShared()) {
+        // Fetching a RegExpShared from an object requires a read
+        // barrier, as the shared pointer might be weak.
+        MaybeTraceRegExpShared(cx, shared);
+
+        g->init(*shared);
+        return true;
+    }
+
+    return createShared(cx, g);
+}
+
 /* static */ void
 RegExpObject::trace(JSTracer *trc, JSObject *obj)
 {
     RegExpShared *shared = obj->as<RegExpObject>().maybeShared();
     if (!shared)
         return;
 
     // When tracing through the object normally, we have the option of
--- a/js/src/vm/RegExpObject.h
+++ b/js/src/vm/RegExpObject.h
@@ -448,28 +448,17 @@ class RegExpObject : public JSObject
         setSlot(STICKY_FLAG_SLOT, BooleanValue(enabled));
     }
 
     bool ignoreCase() const { return getFixedSlot(IGNORE_CASE_FLAG_SLOT).toBoolean(); }
     bool global() const     { return getFixedSlot(GLOBAL_FLAG_SLOT).toBoolean(); }
     bool multiline() const  { return getFixedSlot(MULTILINE_FLAG_SLOT).toBoolean(); }
     bool sticky() const     { return getFixedSlot(STICKY_FLAG_SLOT).toBoolean(); }
 
-    void shared(RegExpGuard *g) const {
-        JS_ASSERT(maybeShared() != nullptr);
-        g->init(*maybeShared());
-    }
-
-    bool getShared(JSContext *cx, RegExpGuard *g) {
-        if (RegExpShared *shared = maybeShared()) {
-            g->init(*shared);
-            return true;
-        }
-        return createShared(cx, g);
-    }
+    bool getShared(JSContext *cx, RegExpGuard *g);
 
     void setShared(RegExpShared &shared) {
         JS_ASSERT(!maybeShared());
         JSObject::setPrivate(&shared);
     }
 
     static void trace(JSTracer *trc, JSObject *obj);
 
--- a/js/xpconnect/idl/xpccomponents.idl
+++ b/js/xpconnect/idl/xpccomponents.idl
@@ -116,17 +116,17 @@ interface nsIXPCComponents_utils_Sandbox
 interface ScheduledGCCallback : nsISupports
 {
     void callback();
 };
 
 /**
 * interface of Components.utils
 */
-[scriptable, uuid(c9b6f5a0-cfe8-11e3-9c1a-0800200c9a66)]
+[scriptable, uuid(a485ba50-e208-11e3-8b68-0800200c9a66)]
 interface nsIXPCComponents_Utils : nsISupports
 {
 
     /* reportError is designed to be called from JavaScript only.
      *
      * It will report a JS Error object to the JS console, and return. It
      * is meant for use in exception handler blocks which want to "eat"
      * an exception, but still want to report it to the console.
@@ -405,16 +405,21 @@ interface nsIXPCComponents_Utils : nsISu
      * Determines whether this object is backed by a DeadObjectProxy.
      *
      * Dead-wrapper objects hold no other objects alive (they have no outgoing
      * reference edges) and will throw if you touch them (e.g. by
      * reading/writing a property).
      */
     bool isDeadWrapper(in jsval obj);
 
+    /**
+     * Determines whether this object is a cross-process wrapper.
+     */
+    bool isCrossProcessWrapper(in jsval obj);
+
     /*
      * To be called from JS only. This is for Gecko internal use only, and may
      * disappear at any moment.
      *
      * Forces a recomputation of all wrappers in and out of the compartment
      * containing |vobj|. If |vobj| is not an object, all wrappers system-wide
      * are recomputed.
      */
@@ -569,17 +574,17 @@ interface nsIXPCComponents_Utils : nsISu
     PRTime getWatchdogTimestamp(in AString aCategory);
 
     [implicit_jscontext]
     jsval getJSEngineTelemetryValue();
 
     /*
      * Clone an object into a scope.
      * The 3rd argument is an optional options object:
-     * - cloneFunction: boolean. If true, any function in the value is are
+     * - cloneFunctions: boolean. If true, functions in the value are
      *   wrapped in a function forwarder that appears to be a native function in
      *   the content scope.
      */
     [implicit_jscontext]
     jsval cloneInto(in jsval value, in jsval scope, [optional] in jsval options);
 
     /*
      * When C++-Implemented code does security checks, it can generally query
--- a/js/xpconnect/src/XPCComponents.cpp
+++ b/js/xpconnect/src/XPCComponents.cpp
@@ -8,16 +8,17 @@
 
 #include "xpcprivate.h"
 #include "xpcIJSModuleLoader.h"
 #include "XPCJSWeakReference.h"
 #include "WrapperFactory.h"
 #include "nsJSUtils.h"
 #include "mozJSComponentLoader.h"
 #include "nsContentUtils.h"
+#include "JavaScriptParent.h"
 #include "jsfriendapi.h"
 #include "js/StructuredClone.h"
 #include "mozilla/Attributes.h"
 #include "nsJSEnvironment.h"
 #include "mozilla/XPTInterfaceInfoManager.h"
 #include "mozilla/dom/DOMException.h"
 #include "mozilla/dom/DOMExceptionBinding.h"
 #include "mozilla/dom/BindingUtils.h"
@@ -3105,16 +3106,27 @@ nsXPCComponents_Utils::IsDeadWrapper(Han
 
     // Make sure to unwrap first. Once a proxy is nuked, it ceases to be a
     // wrapper, meaning that, if passed to another compartment, we'll generate
     // a CCW for it. Make sure that IsDeadWrapper sees through the confusion.
     *out = JS_IsDeadWrapper(js::CheckedUnwrap(&obj.toObject()));
     return NS_OK;
 }
 
+NS_IMETHODIMP
+nsXPCComponents_Utils::IsCrossProcessWrapper(HandleValue obj, bool *out)
+{
+    *out = false;
+    if (obj.isPrimitive())
+        return NS_ERROR_INVALID_ARG;
+
+    *out = jsipc::IsCPOW(js::CheckedUnwrap(&obj.toObject()));
+    return NS_OK;
+}
+
 /* void recomputerWrappers(jsval vobj); */
 NS_IMETHODIMP
 nsXPCComponents_Utils::RecomputeWrappers(HandleValue vobj, JSContext *cx)
 {
     // Determine the compartment of the given object, if any.
     JSCompartment *c = vobj.isObject()
                        ? js::GetObjectCompartment(js::UncheckedUnwrap(&vobj.toObject()))
                        : nullptr;
--- a/js/xpconnect/src/XPCWrappedNative.cpp
+++ b/js/xpconnect/src/XPCWrappedNative.cpp
@@ -319,41 +319,39 @@ XPCWrappedNative::GetNewOrUsed(xpcObject
     // reflection regardless of the scope into which we are reflecting it.
     // Many DOM objects require this. The scriptable helper specifies this
     // in preCreate by indicating a 'parent' of a particular scope.
     //
     // To handle this we need to get the scriptable helper early and ask it.
     // It is possible that we will then end up forwarding this entire call
     // to this same function but with a different scope.
 
-    // If we are making a wrapper for the nsIClassInfo interface then
+    // If we are making a wrapper for an nsIClassInfo singleton then
     // We *don't* want to have it use the prototype meant for instances
     // of that class.
-    bool iidIsClassInfo = Interface->GetIID()->Equals(NS_GET_IID(nsIClassInfo));
     uint32_t classInfoFlags;
     bool isClassInfoSingleton = helper.GetClassInfo() == helper.Object() &&
                                 NS_SUCCEEDED(helper.GetClassInfo()
                                                    ->GetFlags(&classInfoFlags)) &&
                                 (classInfoFlags & nsIClassInfo::SINGLETON_CLASSINFO);
-    bool isClassInfo = iidIsClassInfo || isClassInfoSingleton;
 
     nsIClassInfo *info = helper.GetClassInfo();
 
     XPCNativeScriptableCreateInfo sciProto;
     XPCNativeScriptableCreateInfo sci;
 
     // Gather scriptable create info if we are wrapping something
     // other than an nsIClassInfo object. We need to not do this for
     // nsIClassInfo objects because often nsIClassInfo implementations
     // are also nsIXPCScriptable helper implementations, but the helper
     // code is obviously intended for the implementation of the class
     // described by the nsIClassInfo, not for the class info object
     // itself.
     const XPCNativeScriptableCreateInfo& sciWrapper =
-        isClassInfo ? sci :
+        isClassInfoSingleton ? sci :
         GatherScriptableCreateInfo(identity, info, sciProto, sci);
 
     RootedObject parent(cx, Scope->GetGlobalJSObject());
 
     RootedValue newParentVal(cx, NullValue());
 
     mozilla::Maybe<JSAutoCompartment> ac;
 
@@ -408,17 +406,17 @@ XPCWrappedNative::GetNewOrUsed(xpcObject
     AutoMarkingWrappedNativeProtoPtr proto(cx);
 
     // If there is ClassInfo (and we are not building a wrapper for the
     // nsIClassInfo interface) then we use a wrapper that needs a prototype.
 
     // Note that the security check happens inside FindTearOff - after the
     // wrapper is actually created, but before JS code can see it.
 
-    if (info && !isClassInfo) {
+    if (info && !isClassInfoSingleton) {
         proto = XPCWrappedNativeProto::GetNewOrUsed(Scope, info, &sciProto);
         if (!proto)
             return NS_ERROR_FAILURE;
 
         wrapper = new XPCWrappedNative(helper.forgetCanonical(), proto);
     } else {
         AutoMarkingNativeInterfacePtr iface(cx, Interface);
         if (!iface)
--- a/js/xpconnect/tests/chrome/test_bug664689.xul
+++ b/js/xpconnect/tests/chrome/test_bug664689.xul
@@ -17,14 +17,14 @@ https://bugzilla.mozilla.org/show_bug.cg
   </body>
 
   <!-- test code goes here -->
   <script type="application/javascript"><![CDATA[
 
       const Cu = Components.utils;
       var sandbox = new Cu.Sandbox("about:blank");
       var contentObj = Cu.evalInSandbox("({ get foo() { return 42 } })", sandbox);
-      var propdesc = Object.getOwnPropertyDescriptor(contentObj, "foo");
+      var propdesc = Object.getOwnPropertyDescriptor(Cu.waiveXrays(contentObj), "foo");
       is(typeof propdesc, "object", "got a property descriptor back");
       ok("get" in propdesc, "getter exists");
 
   ]]></script>
 </window>
--- a/js/xpconnect/tests/chrome/test_cloneInto.xul
+++ b/js/xpconnect/tests/chrome/test_cloneInto.xul
@@ -107,25 +107,33 @@
     wantXrays: true,
     wantExportHelpers: true,
   };
   var sandbox = new Cu.Sandbox(window, sandboxOptions);
   // The second sandbox is for testing the exportHelper version of the cloneInto
   var sandbox2 = new Cu.Sandbox("http://example.com", sandboxOptions);
   sandbox.sandbox2 = sandbox2;
 
-  function cloneAndTest(test, cloneOptions) {
-    var output = sandbox.test = Cu.cloneInto(test, sandbox, cloneOptions);
+  function cloneAndTest(test) {
+    var output = sandbox.test = Cu.cloneInto(test, sandbox);
     compare(test, output);
 
-    sandbox.cloneOptions = cloneOptions;
-    output = Cu.evalInSandbox('cloneInto(test, sandbox2, cloneOptions)', sandbox);
+    output = Cu.evalInSandbox('cloneInto(test, sandbox2)', sandbox);
     compare(test, output);
   }
 
+  function cloneAndTestWithFunctions(test) {
+    var output = sandbox.test = Cu.cloneInto(test, sandbox, { cloneFunctions: true });
+    compare(test, output);
+
+    output = Cu.evalInSandbox('cloneInto(test, sandbox2, { cloneFunctions: true })', sandbox);
+    // Note - We need to waive here, because functions are filtered out by object Xrays.
+    compare(test, Cu.waiveXrays(output));
+  }
+
   var tests = [
     1,
     null,
     true,
     'hello world',
     [1, 2, 3],
     { a: 1, b: 2 },
     { blob: new Blob([]), file: new File(new Blob([])) },
@@ -149,12 +157,12 @@
     Cu.evalInSandbox('cloneInto({}, sandbox)', sandbox2);
     ok(false, 'CloneInto should only work on less privileged target scopes.');
   } catch(e) {
     ok(/denied|insecure/.test(e),
        'CloneInto should only work on less privileged target scopes.');
   }
 
   var test = { a: function() { return 42; } }
-  cloneAndTest(test, { cloneFunctions: true });
+  cloneAndTestWithFunctions(test);
   ]]>
   </script>
 </window>
--- a/js/xpconnect/tests/chrome/test_cows.xul
+++ b/js/xpconnect/tests/chrome/test_cows.xul
@@ -24,16 +24,17 @@ const Cu = Components.utils;
 var sandbox = new Cu.Sandbox("about:blank");
 
 var test_utils = window.QueryInterface(Ci.nsIInterfaceRequestor).
                  getInterface(Ci.nsIDOMWindowUtils);
 
 function getCOW(x) {
   if (typeof x != 'object' && typeof x != 'function')
     return x;
+  x = Cu.waiveXrays(x);
   var rval = {};
   if (typeof x == "function")
     rval = eval(uneval(x));
   for (var i in x) {
     if (x.__lookupGetter__(i))
       rval.__defineGetter__(i, eval(uneval(x.__lookupGetter__(i))))
     else
       rval[i] = getCOW(x[i]);
--- a/js/xpconnect/tests/chrome/test_xrayToJS.xul
+++ b/js/xpconnect/tests/chrome/test_xrayToJS.xul
@@ -50,17 +50,17 @@ https://bugzilla.mozilla.org/show_bug.cg
     // Test Object in more detail.
     var num = new iwin.Object(4);
     is(num.valueOf(), 4, "primitive object construction works");
     is(global(num), iwin, "correct global for num");
     var obj = new iwin.Object();
     obj.foo = 2;
     var withProto = iwin.Object.create(obj);
     is(global(withProto), iwin, "correct global for withProto");
-    is(withProto.foo, 2, "Inherits properly");
+    is(Cu.waiveXrays(withProto).foo, 2, "Inherits properly");
 
     // Test Function.
     var primitiveFun = new iwin.Function('return 2');
     is(global(primitiveFun), iwin, "function construction works");
     is(primitiveFun(), 2, "basic function works");
     var doSetFoo = new iwin.Function('arg', 'arg.foo = 2;');
     is(global(doSetFoo), iwin, "function with args works");
     try {
@@ -94,17 +94,17 @@ https://bugzilla.mozilla.org/show_bug.cg
     is(global(doublingProxy), iwin, "doubling proxy global correct");
     is(doublingProxy[3], 6, "Doubles correctly");
     is(doublingProxy[20], 40, "Doubles correctly");
 
     // Test eval.
     var toEval = "({a: 2, b: {foo: 'bar'}, f: function() { return window; }})";
     is(global(iwin.eval(toEval)), iwin, "eval creates objects in the correct global");
     is(iwin.eval(toEval).b.foo, 'bar', "eval-ed object looks right");
-    is(iwin.eval(toEval).f(), iwin, "evaled function works right");
+    is(Cu.waiveXrays(iwin.eval(toEval)).f(), Cu.waiveXrays(iwin), "evaled function works right");
 
     testDate();
 
     // We could also test DataView and Iterator here for completeness, but it's
     // more trouble than it's worth.
 
 
     SimpleTest.finish();
--- a/layout/base/nsBidiPresUtils.cpp
+++ b/layout/base/nsBidiPresUtils.cpp
@@ -447,27 +447,21 @@ SplitInlineAncestors(nsContainerFrame* a
       // Reparent views as necessary
       nsresult rv;
       rv = nsContainerFrame::ReparentFrameViewList(tail, parent, newParent);
       if (NS_FAILED(rv)) {
         return rv;
       }
 
       // The parent's continuation adopts the siblings after the split.
-      rv = newParent->InsertFrames(nsIFrame::kNoReflowPrincipalList, nullptr, tail);
-      if (NS_FAILED(rv)) {
-        return rv;
-      }
+      newParent->InsertFrames(nsIFrame::kNoReflowPrincipalList, nullptr, tail);
     
       // The list name kNoReflowPrincipalList would indicate we don't want reflow
       nsFrameList temp(newParent, newParent);
-      rv = grandparent->InsertFrames(nsIFrame::kNoReflowPrincipalList, parent, temp);
-      if (NS_FAILED(rv)) {
-        return rv;
-      }
+      grandparent->InsertFrames(nsIFrame::kNoReflowPrincipalList, parent, temp);
     }
     
     frame = parent;
     parent = grandparent;
   }
   
   return NS_OK;
 }
@@ -556,20 +550,17 @@ CreateContinuation(nsIFrame*  aFrame,
   }
 
   *aNewFrame = presShell->FrameConstructor()->
     CreateContinuingFrame(presContext, aFrame, parent, aIsFluid);
 
   // The list name kNoReflowPrincipalList would indicate we don't want reflow
   // XXXbz this needs higher-level framelist love
   nsFrameList temp(*aNewFrame, *aNewFrame);
-  rv = parent->InsertFrames(nsIFrame::kNoReflowPrincipalList, aFrame, temp);
-  if (NS_FAILED(rv)) {
-    return rv;
-  }
+  parent->InsertFrames(nsIFrame::kNoReflowPrincipalList, aFrame, temp);
 
   if (!aIsFluid) {  
     // Split inline ancestor frames
     rv = SplitInlineAncestors(parent, aFrame);
     if (NS_FAILED(rv)) {
       return rv;
     }
   }
--- a/layout/base/nsCSSFrameConstructor.cpp
+++ b/layout/base/nsCSSFrameConstructor.cpp
@@ -314,16 +314,25 @@ static int32_t FFWC_nextInFlows=0;
 static inline bool
 IsAnonymousFlexOrGridItem(const nsIFrame* aFrame)
 {
   const nsIAtom* pseudoType = aFrame->StyleContext()->GetPseudo();
   return pseudoType == nsCSSAnonBoxes::anonymousFlexItem ||
          pseudoType == nsCSSAnonBoxes::anonymousGridItem;
 }
 
+// Returns true if aFrame is a flex/grid container.
+static inline bool
+IsFlexOrGridContainer(const nsIFrame* aFrame)
+{
+  const nsIAtom* t = aFrame->GetType();
+  return t == nsGkAtoms::flexContainerFrame ||
+         t == nsGkAtoms::gridContainerFrame;
+}
+
 #if DEBUG
 static void
 AssertAnonymousFlexOrGridItemParent(const nsIFrame* aChild,
                                     const nsIFrame* aParent)
 {
   MOZ_ASSERT(IsAnonymousFlexOrGridItem(aChild),
              "expected an anonymous flex or grid item child frame");
   MOZ_ASSERT(aParent, "expected a parent frame");
@@ -390,18 +399,17 @@ IsFrameForSVG(const nsIFrame* aFrame)
  * float-containing blocks -- those will manage the floating status of any
  * lower-level descendents inside them, of course).
  */
 static bool
 ShouldSuppressFloatingOfDescendants(nsIFrame* aFrame)
 {
   return aFrame->IsFrameOfType(nsIFrame::eMathML) ||
     aFrame->IsBoxFrame() ||
-    aFrame->GetType() == nsGkAtoms::flexContainerFrame ||
-    aFrame->GetType() == nsGkAtoms::gridContainerFrame;
+    ::IsFlexOrGridContainer(aFrame);
 }
 
 /**
  * If any children require a block parent, return the first such child.
  * Otherwise return null.
  */
 static nsIContent*
 AnyKidsNeedBlockParent(nsIFrame *aFrameList)
@@ -1264,26 +1272,25 @@ nsFrameConstructorState::ProcessFrameIns
     // it has abs-pos children instead of fixed-pos children.
     aChildListID = containingBlock->GetAbsoluteListID();
   }
 
   // Insert the frames hanging out in aItems.  We can use SetInitialChildList()
   // if the containing block hasn't been reflowed yet (so NS_FRAME_FIRST_REFLOW
   // is set) and doesn't have any frames in the aChildListID child list yet.
   const nsFrameList& childList = containingBlock->GetChildList(aChildListID);
-  DebugOnly<nsresult> rv = NS_OK;
   if (childList.IsEmpty() &&
       (containingBlock->GetStateBits() & NS_FRAME_FIRST_REFLOW)) {
     // If we're injecting absolutely positioned frames, inject them on the
     // absolute containing block
     if (aChildListID == containingBlock->GetAbsoluteListID()) {
-      rv = containingBlock->GetAbsoluteContainingBlock()->
-           SetInitialChildList(containingBlock, aChildListID, aFrameItems);
+      containingBlock->GetAbsoluteContainingBlock()->
+        SetInitialChildList(containingBlock, aChildListID, aFrameItems);
     } else {
-      rv = containingBlock->SetInitialChildList(aChildListID, aFrameItems);
+      containingBlock->SetInitialChildList(aChildListID, aFrameItems);
     }
   } else {
     // Note that whether the frame construction context is doing an append or
     // not is not helpful here, since it could be appending to some frame in
     // the middle of the document, which means we're not necessarily
     // appending to the children of the containing block.
     //
     // We need to make sure the 'append to the end of document' case is fast.
@@ -1305,17 +1312,17 @@ nsFrameConstructorState::ProcessFrameIns
     }
 
     if (!lastChild ||
         nsLayoutUtils::CompareTreePosition(lastChild, firstNewFrame,
                                            firstNewFrameAncestors,
                                            notCommonAncestor ?
                                              containingBlock : nullptr) < 0) {
       // no lastChild, or lastChild comes before the new children, so just append
-      rv = mFrameManager->AppendFrames(containingBlock, aChildListID, aFrameItems);
+      mFrameManager->AppendFrames(containingBlock, aChildListID, aFrameItems);
     } else {
       // Try the other children. First collect them to an array so that a
       // reasonable fast binary search can be used to find the insertion point.
       nsAutoTArray<nsIFrame*, 128> children;
       for (nsIFrame* f = childList.FirstChild(); f != lastChild;
            f = f->GetNextSibling()) {
         children.AppendElement(f);
       }
@@ -1351,27 +1358,22 @@ nsFrameConstructorState::ProcessFrameIns
                                                      containingBlock : nullptr) > 0) {
               break;
             }
             insertionPoint = f;
           }
           break;
         }
       }
-      rv = mFrameManager->InsertFrames(containingBlock, aChildListID,
-                                       insertionPoint, aFrameItems);
+      mFrameManager->InsertFrames(containingBlock, aChildListID,
+                                  insertionPoint, aFrameItems);
     }
   }
 
   NS_POSTCONDITION(aFrameItems.IsEmpty(), "How did that happen?");
-
-  // XXXbz And if NS_FAILED(rv), what?  I guess we need to clean up the list
-  // and deal with all the placeholders... but what if the placeholders aren't
-  // in the document yet?  Could that happen?
-  NS_ASSERTION(NS_SUCCEEDED(rv), "Frames getting lost!");
 }
 
 
 nsFrameConstructorSaveState::nsFrameConstructorSaveState()
   : mItems(nullptr),
     mSavedItems(nullptr),
     mChildListID(kPrincipalList),
     mState(nullptr),
@@ -5959,17 +5961,18 @@ nsCSSFrameConstructor::AppendFramesToPar
       return AppendFramesToParent(aState, aParentFrame->GetParent(), ibSiblings,
                                   aParentFrame, true);
     }
 
     return NS_OK;
   }
 
   // Insert the frames after our aPrevSibling
-  return InsertFrames(aParentFrame, kPrincipalList, aPrevSibling, aFrameList);
+  InsertFrames(aParentFrame, kPrincipalList, aPrevSibling, aFrameList);
+  return NS_OK;
 }
 
 #define UNSET_DISPLAY 255
 
 // This gets called to see if the frames corresponding to aSibling and aContent
 // should be siblings in the frame tree. Although (1) rows and cols, (2) row
 // groups and col groups, (3) row groups and captions, (4) legends and content
 // inside fieldsets, (5) popups and other kids of the menu are siblings from a
@@ -7717,19 +7720,17 @@ nsCSSFrameConstructor::ContentRemoved(ns
 
 
     // Notify the parent frame that it should delete the frame
     if (childFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW) {
       childFrame = GetPlaceholderFrameFor(childFrame);
       NS_ASSERTION(childFrame, "Missing placeholder frame for out of flow.");
       parentFrame = childFrame->GetParent();
     }
-    rv = RemoveFrame(nsLayoutUtils::GetChildListNameFor(childFrame),
-                     childFrame);
-    //XXXfr NS_ENSURE_SUCCESS(rv, rv) ?
+    RemoveFrame(nsLayoutUtils::GetChildListNameFor(childFrame), childFrame);
 
     if (isRoot) {
       mRootElementFrame = nullptr;
       mRootElementStyleFrame = nullptr;
       mDocElementContainingBlock = nullptr;
       mPageSequenceFrame = nullptr;
       mGfxScrollFrame = nullptr;
       mHasRootAbsPosContainingBlock = false;
@@ -8928,25 +8929,22 @@ nsCSSFrameConstructor::sPseudoParentData
 };
 
 void
 nsCSSFrameConstructor::CreateNeededAnonFlexOrGridItems(
   nsFrameConstructorState& aState,
   FrameConstructionItemList& aItems,
   nsIFrame* aParentFrame)
 {
-  if (aItems.IsEmpty()) {
+  if (aItems.IsEmpty() ||
+      !::IsFlexOrGridContainer(aParentFrame)) {
     return;
   }
+
   nsIAtom* containerType = aParentFrame->GetType();
-  if (containerType != nsGkAtoms::flexContainerFrame &&
-      containerType != nsGkAtoms::gridContainerFrame) {
-    return;
-  }
-
   FCItemIterator iter(aItems);
   do {
     // Advance iter past children that don't want to be wrapped
     if (iter.SkipItemsThatDontNeedAnonFlexOrGridItem(aState)) {
       // Hit the end of the items without finding any remaining children that
       // need to be wrapped. We're finished!
       return;
     }
@@ -10830,19 +10828,20 @@ nsCSSFrameConstructor::WipeContainingBlo
       !(aFrame->GetStateBits() & NS_STATE_BOX_WRAPS_KIDS_IN_BLOCK) &&
       aItems.AnyItemsNeedBlockParent()) {
     RecreateFramesForContent(aFrame->GetContent(), true);
     return true;
   }
 
   nsIFrame* nextSibling = ::GetInsertNextSibling(aFrame, aPrevSibling);
 
-  // Situation #2 is a flex container frame into which we're inserting new
-  // inline non-replaced children, adjacent to an existing anonymous flex item.
-  if (aFrame->GetType() == nsGkAtoms::flexContainerFrame) {
+  // Situation #2 is a flex or grid container frame into which we're inserting
+  // new inline non-replaced children, adjacent to an existing anonymous
+  // flex or grid item.
+  if (::IsFlexOrGridContainer(aFrame)) {
     FCItemIterator iter(aItems);
 
     // Check if we're adding to-be-wrapped content right *after* an existing
     // anonymous flex or grid item (which would need to absorb this content).
     if (aPrevSibling && IsAnonymousFlexOrGridItem(aPrevSibling) &&
         iter.item().NeedsAnonFlexOrGridItem(aState)) {
       RecreateFramesForContent(aFrame->GetContent(), true);
       return true;
--- a/layout/base/nsDisplayList.cpp
+++ b/layout/base/nsDisplayList.cpp
@@ -57,16 +57,17 @@
 
 #include <stdint.h>
 #include <algorithm>
 
 using namespace mozilla;
 using namespace mozilla::css;
 using namespace mozilla::layers;
 using namespace mozilla::dom;
+using namespace mozilla::layout;
 typedef FrameMetrics::ViewID ViewID;
 
 static inline nsIFrame*
 GetTransformRootFrame(nsIFrame* aFrame)
 {
   return nsLayoutUtils::GetTransformRootFrame(aFrame);
 }
 
@@ -1360,16 +1361,18 @@ void nsDisplayList::PaintForFrame(nsDisp
   } else {
     // Client layer managers never composite directly, so
     // we don't need to worry about END_NO_COMPOSITE.
     if (aBuilder->WillComputePluginGeometry()) {
       flags = LayerManager::END_NO_REMOTE_COMPOSITE;
     }
   }
 
+  MaybeSetupTransactionIdAllocator(layerManager, view);
+
   layerManager->EndTransaction(FrameLayerBuilder::DrawThebesLayer,
                                aBuilder, flags);
   aBuilder->SetIsCompositingCheap(temp);
   layerBuilder->DidEndTransaction();
 
   nsIntRegion invalid;
   if (props) {
     invalid = props->ComputeDifferences(root, computeInvalidFunc);
--- a/layout/base/nsFrameManager.cpp
+++ b/layout/base/nsFrameManager.cpp
@@ -343,51 +343,51 @@ nsFrameManager::ClearAllUndisplayedConte
   for (nsIContent* child = iter.GetNextChild(); child; child = iter.GetNextChild()) {
     if (child->GetParent() != aParentContent) {
       ClearUndisplayedContentIn(child, child->GetParent());
     }
   }
 }
 
 //----------------------------------------------------------------------
-nsresult
+void
 nsFrameManager::AppendFrames(nsContainerFrame* aParentFrame,
                              ChildListID       aListID,
                              nsFrameList&      aFrameList)
 {
   if (aParentFrame->IsAbsoluteContainer() &&
       aListID == aParentFrame->GetAbsoluteListID()) {
-    return aParentFrame->GetAbsoluteContainingBlock()->
-           AppendFrames(aParentFrame, aListID, aFrameList);
+    aParentFrame->GetAbsoluteContainingBlock()->
+      AppendFrames(aParentFrame, aListID, aFrameList);
   } else {
-    return aParentFrame->AppendFrames(aListID, aFrameList);
+    aParentFrame->AppendFrames(aListID, aFrameList);
   }
 }
 
-nsresult
+void
 nsFrameManager::InsertFrames(nsContainerFrame* aParentFrame,
                              ChildListID       aListID,
                              nsIFrame*         aPrevFrame,
                              nsFrameList&      aFrameList)
 {
   NS_PRECONDITION(!aPrevFrame || (!aPrevFrame->GetNextContinuation()
                   || (((aPrevFrame->GetNextContinuation()->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER))
                   && !(aPrevFrame->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER))),
                   "aPrevFrame must be the last continuation in its chain!");
 
   if (aParentFrame->IsAbsoluteContainer() &&
       aListID == aParentFrame->GetAbsoluteListID()) {
-    return aParentFrame->GetAbsoluteContainingBlock()->
-           InsertFrames(aParentFrame, aListID, aPrevFrame, aFrameList);
+    aParentFrame->GetAbsoluteContainingBlock()->
+      InsertFrames(aParentFrame, aListID, aPrevFrame, aFrameList);
   } else {
-    return aParentFrame->InsertFrames(aListID, aPrevFrame, aFrameList);
+    aParentFrame->InsertFrames(aListID, aPrevFrame, aFrameList);
   }
 }
 
-nsresult
+void
 nsFrameManager::RemoveFrame(ChildListID     aListID,
                             nsIFrame*       aOldFrame)
 {
   bool wasDestroyingFrames = mIsDestroyingFrames;
   mIsDestroyingFrames = true;
 
   // In case the reflow doesn't invalidate anything since it just leaves
   // a gap where the old frame was, we invalidate it here.  (This is
@@ -399,29 +399,26 @@ nsFrameManager::RemoveFrame(ChildListID 
 
   NS_ASSERTION(!aOldFrame->GetPrevContinuation() ||
                // exception for nsCSSFrameConstructor::RemoveFloatingFirstLetterFrames
                aOldFrame->GetType() == nsGkAtoms::textFrame,
                "Must remove first continuation.");
   NS_ASSERTION(!(aOldFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW &&
                  GetPlaceholderFrameFor(aOldFrame)),
                "Must call RemoveFrame on placeholder for out-of-flows.");
-  nsresult rv = NS_OK;
   nsContainerFrame* parentFrame = aOldFrame->GetParent();
   if (parentFrame->IsAbsoluteContainer() &&
       aListID == parentFrame->GetAbsoluteListID()) {
     parentFrame->GetAbsoluteContainingBlock()->
       RemoveFrame(parentFrame, aListID, aOldFrame);
   } else {
-    rv = parentFrame->RemoveFrame(aListID, aOldFrame);
+    parentFrame->RemoveFrame(aListID, aOldFrame);
   }
 
   mIsDestroyingFrames = wasDestroyingFrames;
-
-  return rv;
 }
 
 //----------------------------------------------------------------------
 
 void
 nsFrameManager::NotifyDestroyingFrame(nsIFrame* aFrame)
 {
   nsIContent* content = aFrame->GetContent();
--- a/layout/base/nsFrameManager.h
+++ b/layout/base/nsFrameManager.h
@@ -109,27 +109,27 @@ public:
                                          nsStyleContext* aStyleContext);
   NS_HIDDEN_(void) ChangeUndisplayedContent(nsIContent* aContent,
                                             nsStyleContext* aStyleContext);
   NS_HIDDEN_(void) ClearUndisplayedContentIn(nsIContent* aContent,
                                              nsIContent* aParentContent);
   NS_HIDDEN_(void) ClearAllUndisplayedContentIn(nsIContent* aParentContent);
 
   // Functions for manipulating the frame model
-  NS_HIDDEN_(nsresult) AppendFrames(nsContainerFrame* aParentFrame,
-                                    ChildListID       aListID,
-                                    nsFrameList&      aFrameList);
+  NS_HIDDEN_(void) AppendFrames(nsContainerFrame* aParentFrame,
+                                ChildListID       aListID,
+                                nsFrameList&      aFrameList);
 
-  NS_HIDDEN_(nsresult) InsertFrames(nsContainerFrame* aParentFrame,
-                                    ChildListID       aListID,
-                                    nsIFrame*         aPrevFrame,
-                                    nsFrameList&      aFrameList);
+  NS_HIDDEN_(void) InsertFrames(nsContainerFrame* aParentFrame,
+                                ChildListID       aListID,
+                                nsIFrame*         aPrevFrame,
+                                nsFrameList&      aFrameList);
 
-  NS_HIDDEN_(nsresult) RemoveFrame(ChildListID     aListID,
-                                   nsIFrame*       aOldFrame);
+  NS_HIDDEN_(void) RemoveFrame(ChildListID     aListID,
+                               nsIFrame*       aOldFrame);
 
   /*
    * Notification that a frame is about to be destroyed. This allows any
    * outstanding references to the frame to be cleaned up.
    */
   NS_HIDDEN_(void)     NotifyDestroyingFrame(nsIFrame* aFrame);
 
   /*
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -15,16 +15,17 @@
 #include "nsIDOMHTMLElement.h"
 #include "nsFrameList.h"
 #include "nsGkAtoms.h"
 #include "nsIAtom.h"
 #include "nsCSSPseudoElements.h"
 #include "nsCSSAnonBoxes.h"
 #include "nsCSSColorUtils.h"
 #include "nsView.h"
+#include "nsViewManager.h"
 #include "nsPlaceholderFrame.h"
 #include "nsIScrollableFrame.h"
 #include "nsIDOMEvent.h"
 #include "nsDisplayList.h"
 #include "nsRegion.h"
 #include "nsFrameManager.h"
 #include "nsBlockFrame.h"
 #include "nsBidiPresUtils.h"
@@ -73,16 +74,17 @@
 #include "nsComputedDOMStyle.h"
 #include "ActiveLayerTracker.h"
 #include "mozilla/gfx/2D.h"
 #include "gfx2DGlue.h"
 #include "mozilla/LookAndFeel.h"
 #include "UnitTransforms.h"
 #include "TiledLayerBuffer.h" // For TILEDLAYERBUFFER_TILE_SIZE
 #include "ClientLayerManager.h"
+#include "nsRefreshDriver.h"
 
 #include "mozilla/Preferences.h"
 
 #ifdef MOZ_XUL
 #include "nsXULPopupManager.h"
 #endif
 
 #include "GeckoProfiler.h"
@@ -6630,8 +6632,24 @@ AutoMaybeDisableFontInflation::AutoMaybe
 }
 
 AutoMaybeDisableFontInflation::~AutoMaybeDisableFontInflation()
 {
   if (mPresContext) {
     mPresContext->mInflationDisabledForShrinkWrap = mOldValue;
   }
 }
+
+namespace mozilla {
+namespace layout {
+
+void
+MaybeSetupTransactionIdAllocator(layers::LayerManager* aManager, nsView* aView)
+{
+  if (aManager->GetBackendType() == layers::LayersBackend::LAYERS_CLIENT) {
+    layers::ClientLayerManager *manager = static_cast<layers::ClientLayerManager*>(aManager);
+    nsRefreshDriver *refresh = aView->GetViewManager()->GetPresShell()->GetPresContext()->RefreshDriver();
+    manager->SetTransactionIdAllocator(refresh);
+  }
+}
+
+}
+}
--- a/layout/base/nsLayoutUtils.h
+++ b/layout/base/nsLayoutUtils.h
@@ -69,16 +69,17 @@ namespace dom {
 class DOMRectList;
 class Element;
 class HTMLImageElement;
 class HTMLCanvasElement;
 class HTMLVideoElement;
 } // namespace dom
 namespace layers {
 class Layer;
+class ClientLayerManager;
 }
 }
 
 namespace mozilla {
 
 struct DisplayPortPropertyData {
   DisplayPortPropertyData(const nsRect& aRect, uint32_t aPriority)
     : mRect(aRect)
@@ -2290,16 +2291,18 @@ namespace mozilla {
       AutoMaybeDisableFontInflation(nsIFrame *aFrame);
 
       ~AutoMaybeDisableFontInflation();
     private:
       nsPresContext *mPresContext;
       bool mOldValue;
     };
 
+    void MaybeSetupTransactionIdAllocator(layers::LayerManager* aManager, nsView* aView);
+
   }
 }
 
 class nsSetAttrRunnable : public nsRunnable
 {
 public:
   nsSetAttrRunnable(nsIContent* aContent, nsIAtom* aAttrName,
                     const nsAString& aValue);
--- a/layout/base/nsPresShell.cpp
+++ b/layout/base/nsPresShell.cpp
@@ -184,16 +184,17 @@ using namespace mozilla::tasktracer;
   (nsIPresShell::SCROLL_OVERFLOW_HIDDEN | nsIPresShell::SCROLL_NO_PARENT_FRAMES)
 
 using namespace mozilla;
 using namespace mozilla::css;
 using namespace mozilla::dom;
 using namespace mozilla::gfx;
 using namespace mozilla::layers;
 using namespace mozilla::gfx;
+using namespace mozilla::layout;
 
 CapturingContentInfo nsIPresShell::gCaptureInfo =
   { false /* mAllowed */, false /* mPointerLock */, false /* mRetargetToElement */,
     false /* mPreventDrag */, nullptr /* mContent */ };
 nsIContent* nsIPresShell::gKeyDownTarget;
 nsRefPtrHashtable<nsUint32HashKey, dom::Touch>* nsIPresShell::gCaptureTouchList;
 nsRefPtrHashtable<nsUint32HashKey, nsIContent>* nsIPresShell::gPointerCaptureList;
 nsClassHashtable<nsUint32HashKey, nsIPresShell::PointerInfo>* nsIPresShell::gActivePointersIds;
@@ -4032,22 +4033,25 @@ PresShell::FlushPendingNotifications(moz
       mPresContext->FlushUserFontSet();
 
       // Flush any requested SMIL samples.
       if (mDocument->HasAnimationController()) {
         mDocument->GetAnimationController()->FlushResampleRequests();
       }
 
       if (aFlush.mFlushAnimations &&
-          nsLayoutUtils::AreAsyncAnimationsEnabled() &&
           !mPresContext->StyleUpdateForAllAnimationsIsUpToDate()) {
-        mPresContext->AnimationManager()->
-          FlushAnimations(CommonAnimationManager::Cannot_Throttle);
-        mPresContext->TransitionManager()->
-          FlushTransitions(CommonAnimationManager::Cannot_Throttle);
+        if (mPresContext->AnimationManager()) {
+          mPresContext->AnimationManager()->
+            FlushAnimations(CommonAnimationManager::Cannot_Throttle);
+        }
+        if (mPresContext->TransitionManager()) {
+          mPresContext->TransitionManager()->
+            FlushTransitions(CommonAnimationManager::Cannot_Throttle);
+        }
         mPresContext->TickLastStyleUpdateForAllAnimations();
       }
 
       // The FlushResampleRequests() above flushed style changes.
       if (!mIsDestroying) {
         nsAutoScriptBlocker scriptBlocker;
         mPresContext->RestyleManager()->ProcessPendingRestyles();
       }
@@ -5866,16 +5870,18 @@ PresShell::Paint(nsView*        aViewToP
         presContext->MayHavePaintEventListenerInSubDocument() ? nsPresContext::NotifySubDocInvalidation : 0;
       bool computeInvalidRect = computeInvalidFunc ||
                                 (layerManager->GetBackendType() == LayersBackend::LAYERS_BASIC);
 
       nsAutoPtr<LayerProperties> props(computeInvalidRect ?
                                          LayerProperties::CloneFrom(layerManager->GetRoot()) :
                                          nullptr);
 
+      MaybeSetupTransactionIdAllocator(layerManager, aViewToPaint);
+
       if (layerManager->EndEmptyTransaction((aFlags & PAINT_COMPOSITE) ?
             LayerManager::END_DEFAULT : LayerManager::END_NO_COMPOSITE)) {
         nsIntRegion invalid;
         if (props) {
           invalid = props->ComputeDifferences(layerManager->GetRoot(), computeInvalidFunc);
         } else {
           LayerProperties::ClearInvalidations(layerManager->GetRoot());
         }
@@ -5926,16 +5932,17 @@ PresShell::Paint(nsView*        aViewToP
     nsPresContext* pc = GetPresContext();
     nsIntRect bounds =
       pc->GetVisibleArea().ToOutsidePixels(pc->AppUnitsPerDevPixel());
     bgcolor = NS_ComposeColors(bgcolor, mCanvasBackgroundColor);
     root->SetColor(bgcolor);
     root->SetVisibleRegion(bounds);
     layerManager->SetRoot(root);
   }
+  MaybeSetupTransactionIdAllocator(layerManager, aViewToPaint);
   layerManager->EndTransaction(nullptr, nullptr, (aFlags & PAINT_COMPOSITE) ?
     LayerManager::END_DEFAULT : LayerManager::END_NO_COMPOSITE);
 }
 
 // static
 void
 nsIPresShell::SetCapturingContent(nsIContent* aContent, uint8_t aFlags)
 {
--- a/layout/base/nsRefreshDriver.cpp
+++ b/layout/base/nsRefreshDriver.cpp
@@ -681,33 +681,42 @@ nsRefreshDriver::ChooseTimer() const
   return sRegularRateTimer;
 }
 
 nsRefreshDriver::nsRefreshDriver(nsPresContext* aPresContext)
   : mActiveTimer(nullptr),
     mReflowCause(nullptr),
     mStyleCause(nullptr),
     mPresContext(aPresContext),
+    mRootRefresh(nullptr),
+    mPendingTransaction(0),
+    mCompletedTransaction(0),
     mFreezeCount(0),
     mThrottled(false),
     mTestControllingRefreshes(false),
     mViewManagerFlushIsPending(false),
     mRequestedHighPrecision(false),
-    mInRefresh(false)
+    mInRefresh(false),
+    mWaitingForTransaction(false),
+    mSkippedPaints(0)
 {
   mMostRecentRefreshEpochTime = JS_Now();
   mMostRecentRefresh = TimeStamp::Now();
 }
 
 nsRefreshDriver::~nsRefreshDriver()
 {
   NS_ABORT_IF_FALSE(ObserverCount() == 0,
                     "observers should have unregistered");
   NS_ABORT_IF_FALSE(!mActiveTimer, "timer should be gone");
   
+  if (mRootRefresh) {
+    mRootRefresh->RemoveRefreshObserver(this, Flush_Style);
+    mRootRefresh = nullptr;
+  }
   for (uint32_t i = 0; i < mPresShellsToInvalidateIfHidden.Length(); i++) {
     mPresShellsToInvalidateIfHidden[i]->InvalidatePresShellIfHidden();
   }
   mPresShellsToInvalidateIfHidden.Clear();
 
   profiler_free_backtrace(mStyleCause);
   profiler_free_backtrace(mReflowCause);
 }
@@ -720,30 +729,36 @@ nsRefreshDriver::AdvanceTimeAndRefresh(i
   // ensure that we're removed from our driver
   StopTimer();
 
   if (!mTestControllingRefreshes) {
     mMostRecentRefreshEpochTime = JS_Now();
     mMostRecentRefresh = TimeStamp::Now();
 
     mTestControllingRefreshes = true;
+    if (mWaitingForTransaction) {
+      // Disable any refresh driver throttling when entering test mode
+      mWaitingForTransaction = false;
+      mSkippedPaints = 0;
+    }
   }
 
   mMostRecentRefreshEpochTime += aMilliseconds * 1000;
   mMostRecentRefresh += TimeDuration::FromMilliseconds((double) aMilliseconds);
 
   mozilla::dom::AutoNoJSAPI nojsapi;
   DoTick();
 }
 
 void
 nsRefreshDriver::RestoreNormalRefresh()
 {
   mTestControllingRefreshes = false;
   EnsureTimerStarted(false);
+  mCompletedTransaction = mPendingTransaction;
 }
 
 TimeStamp
 nsRefreshDriver::MostRecentRefresh() const
 {
   const_cast<nsRefreshDriver*>(this)->EnsureTimerStarted(false);
 
   return mMostRecentRefresh;
@@ -997,22 +1012,16 @@ nsRefreshDriver::ArrayFor(mozFlushType a
       return mObservers[2];
     default:
       NS_ABORT_IF_FALSE(false, "bad flush type");
       return *static_cast<ObserverArray*>(nullptr);
   }
 }
 
 /*
- * nsISupports implementation
- */
-
-NS_IMPL_ISUPPORTS(nsRefreshDriver, nsISupports)
-
-/*
  * nsITimerCallback implementation
  */
 
 void
 nsRefreshDriver::DoTick()
 {
   NS_PRECONDITION(!IsFrozen(), "Why are we notified while frozen?");
   NS_PRECONDITION(mPresContext, "Why are we notified after disconnection?");
@@ -1056,16 +1065,28 @@ nsRefreshDriver::Tick(int64_t aNowEpoch,
     return;
   }
 
   TimeStamp previousRefresh = mMostRecentRefresh;
 
   mMostRecentRefresh = aNowTime;
   mMostRecentRefreshEpochTime = aNowEpoch;
 
+  if (IsWaitingForPaint()) {
+    // We're currently suspended waiting for earlier Tick's to
+    // be completed (on the Compositor). Mark that we missed the paint
+    // and keep waiting.
+    return;
+  }
+  if (mRootRefresh) {
+    mRootRefresh->RemoveRefreshObserver(this, Flush_Style);
+    mRootRefresh = nullptr;
+  }
+  mSkippedPaints = 0;
+
   nsCOMPtr<nsIPresShell> presShell = mPresContext->GetPresShell();
   if (!presShell || (ObserverCount() == 0 && ImageRequestCount() == 0)) {
     // Things are being destroyed, or we no longer have any observers.
     // We don't want to stop the timer when observers are initially
     // removed, because sometimes observers can be added and removed
     // often depending on what other things are going on and in that
     // situation we don't want to thrash our timer.  So instead we
     // wait until we get a Notify() call when we have no observers
@@ -1091,16 +1112,18 @@ nsRefreshDriver::Tick(int64_t aNowEpoch,
       
       if (!mPresContext || !mPresContext->GetPresShell()) {
         StopTimer();
         return;
       }
     }
 
     if (i == 0) {
+      // This is the Flush_Style case.
+
       // Grab all of our frame request callbacks up front.
       nsTArray<DocumentFrameCallbacks>
         frameRequestCallbacks(mFrameRequestCallbackDocs.Length());
       for (uint32_t i = 0; i < mFrameRequestCallbackDocs.Length(); ++i) {
         frameRequestCallbacks.AppendElement(mFrameRequestCallbackDocs[i]);
         mFrameRequestCallbackDocs[i]->
           TakeFrameRequestCallbacks(frameRequestCallbacks.LastElement().mCallbacks);
       }
@@ -1132,17 +1155,16 @@ nsRefreshDriver::Tick(int64_t aNowEpoch,
             holder.GetWebIDLCallback()->Call(timeStamp, ignored);
           } else {
             holder.GetXPCOMCallback()->Sample(eventTime);
           }
         }
       }
       profiler_tracing("Paint", "Scripts", TRACING_INTERVAL_END);
 
-      // This is the Flush_Style case.
       if (mPresContext && mPresContext->GetPresShell()) {
         bool tracingStyleFlush = false;
         nsAutoTArray<nsIPresShell*, 16> observers;
         observers.AppendElements(mStyleFlushObservers);
         for (uint32_t j = observers.Length();
              j && mPresContext && mPresContext->GetPresShell(); --j) {
           // Make sure to not process observers which might have been removed
           // during previous iterations.
@@ -1162,16 +1184,20 @@ nsRefreshDriver::Tick(int64_t aNowEpoch,
           shell->FlushPendingNotifications(ChangesToFlush(Flush_Style, false));
           NS_RELEASE(shell);
         }
 
         if (tracingStyleFlush) {
           profiler_tracing("Paint", "Styles", TRACING_INTERVAL_END);
         }
       }
+
+      if (!nsLayoutUtils::AreAsyncAnimationsEnabled()) {
+        mPresContext->TickLastStyleUpdateForAllAnimations();
+      }
     } else if  (i == 1) {
       // This is the Flush_Layout case.
       if (mPresContext && mPresContext->GetPresShell()) {
         bool tracingLayoutFlush = false;
         nsAutoTArray<nsIPresShell*, 16> observers;
         observers.AppendElements(mLayoutFlushObservers);
         for (uint32_t j = observers.Length();
              j && mPresContext && mPresContext->GetPresShell(); --j) {
@@ -1351,16 +1377,124 @@ nsRefreshDriver::Thaw()
       // Thus MostRecentRefresh() will lie between now and the DoRefresh.
       NS_DispatchToCurrentThread(NS_NewRunnableMethod(this, &nsRefreshDriver::DoRefresh));
       EnsureTimerStarted(false);
     }
   }
 }
 
 void
+nsRefreshDriver::FinishedWaitingForTransaction()
+{
+  mWaitingForTransaction = false;
+  if (mSkippedPaints &&
+      !IsInRefresh() &&
+      (ObserverCount() || ImageRequestCount())) {
+    DoRefresh();
+  }
+  mSkippedPaints = 0;
+}
+
+uint64_t
+nsRefreshDriver::GetTransactionId()
+{
+  ++mPendingTransaction;
+
+  if (mPendingTransaction == mCompletedTransaction + 2 &&
+      !mWaitingForTransaction &&
+      !mTestControllingRefreshes) {
+    mWaitingForTransaction = true;
+    mSkippedPaints = 0;
+  }
+
+  return mPendingTransaction;
+}
+
+void
+nsRefreshDriver::RevokeTransactionId(uint64_t aTransactionId)
+{
+  MOZ_ASSERT(aTransactionId == mPendingTransaction);
+  if (mPendingTransaction == mCompletedTransaction + 2 &&
+      mWaitingForTransaction) {
+    MOZ_ASSERT(!mSkippedPaints, "How did we skip a paint when we're in the middle of one?");
+    FinishedWaitingForTransaction();
+  }
+  mPendingTransaction--;
+}
+
+void
+nsRefreshDriver::NotifyTransactionCompleted(uint64_t aTransactionId)
+{
+  if (aTransactionId > mCompletedTransaction) {
+    if (mPendingTransaction > mCompletedTransaction + 1 &&
+        mWaitingForTransaction) {
+      mCompletedTransaction = aTransactionId;
+      FinishedWaitingForTransaction();
+    } else {
+      mCompletedTransaction = aTransactionId;
+    }
+  }
+}
+
+void
+nsRefreshDriver::WillRefresh(mozilla::TimeStamp aTime)
+{
+  mRootRefresh->RemoveRefreshObserver(this, Flush_Style);
+  mRootRefresh = nullptr;
+  if (mSkippedPaints) {
+    DoRefresh();
+  }
+}
+
+bool
+nsRefreshDriver::IsWaitingForPaint()
+{
+  if (mTestControllingRefreshes) {
+    return false;
+  }
+  // If we've skipped too many ticks then it's possible
+  // that something went wrong and we're waiting on
+  // a notification that will never arrive.
+  static const uint32_t kMaxSkippedPaints = 10;
+  if (mSkippedPaints > kMaxSkippedPaints) {
+    mSkippedPaints = 0;
+    mWaitingForTransaction = false;
+    if (mRootRefresh) {
+      mRootRefresh->RemoveRefreshObserver(this, Flush_Style);
+    }
+    return false;
+  }
+  if (mWaitingForTransaction) {
+    mSkippedPaints++;
+    return true;
+  }
+
+  // Try find the 'root' refresh driver for the current window and check
+  // if that is waiting for a paint.
+  nsPresContext *displayRoot = PresContext()->GetDisplayRootPresContext();
+  if (displayRoot) {
+    nsRefreshDriver *rootRefresh = displayRoot->GetRootPresContext()->RefreshDriver();
+    if (rootRefresh && rootRefresh != this) {
+      if (rootRefresh->IsWaitingForPaint()) {
+        if (mRootRefresh != rootRefresh) {
+          if (mRootRefresh) {
+            mRootRefresh->RemoveRefreshObserver(this, Flush_Style);
+          }
+          rootRefresh->AddRefreshObserver(this, Flush_Style);
+          mRootRefresh = rootRefresh;
+        }
+        mSkippedPaints++;
+        return true;
+      }
+    }
+  }
+  return false;
+}
+
+void
 nsRefreshDriver::SetThrottled(bool aThrottled)
 {
   if (aThrottled != mThrottled) {
     mThrottled = aThrottled;
     if (mActiveTimer) {
       // We want to switch our timer type here, so just stop and
       // restart the timer.
       EnsureTimerStarted(true);
--- a/layout/base/nsRefreshDriver.h
+++ b/layout/base/nsRefreshDriver.h
@@ -17,16 +17,17 @@
 #include "nsTObserverArray.h"
 #include "nsTArray.h"
 #include "nsTHashtable.h"
 #include "nsClassHashtable.h"
 #include "nsHashKeys.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/Maybe.h"
 #include "GeckoProfiler.h"
+#include "mozilla/layers/TransactionIdAllocator.h"
 
 class nsPresContext;
 class nsIPresShell;
 class nsIDocument;
 class imgIRequest;
 class nsIRunnable;
 
 namespace mozilla {
@@ -57,27 +58,25 @@ public:
  * that a refresh has occurred. Callers must ensure an observer is removed
  * before it is destroyed.
  */
 class nsAPostRefreshObserver {
 public:
   virtual void DidRefresh() = 0;
 };
 
-class nsRefreshDriver MOZ_FINAL : public nsISupports {
+class nsRefreshDriver MOZ_FINAL : public mozilla::layers::TransactionIdAllocator,
+                                  public nsARefreshObserver {
 public:
   nsRefreshDriver(nsPresContext *aPresContext);
   ~nsRefreshDriver();
 
   static void InitializeStatics();
   static void Shutdown();
 
-  // nsISupports implementation
-  NS_DECL_ISUPPORTS
-
   /**
    * Methods for testing, exposed via nsIDOMWindowUtils.  See
    * nsIDOMWindowUtils.advanceTimeAndRefresh for description.
    */
   void AdvanceTimeAndRefresh(int64_t aMilliseconds);
   void RestoreNormalRefresh();
   void DoTick();
   bool IsTestControllingRefreshesEnabled() const
@@ -267,16 +266,27 @@ public:
 
   /**
    * Default interval the refresh driver uses, in ms.
    */
   static int32_t DefaultInterval();
 
   bool IsInRefresh() { return mInRefresh; }
 
+  // mozilla::layers::TransactionIdAllocator
+  virtual uint64_t GetTransactionId() MOZ_OVERRIDE;
+  void NotifyTransactionCompleted(uint64_t aTransactionId) MOZ_OVERRIDE;
+  void RevokeTransactionId(uint64_t aTransactionId) MOZ_OVERRIDE;
+
+  bool IsWaitingForPaint();
+
+  // nsARefreshObserver
+  NS_IMETHOD_(MozExternalRefCountType) AddRef(void) { return TransactionIdAllocator::AddRef(); }
+  NS_IMETHOD_(MozExternalRefCountType) Release(void) { return TransactionIdAllocator::Release(); }
+  virtual void WillRefresh(mozilla::TimeStamp aTime);
 private:
   typedef nsTObserverArray<nsARefreshObserver*> ObserverArray;
   typedef nsTHashtable<nsISupportsHashKey> RequestTable;
   struct ImageStartData {
     ImageStartData()
     {
     }
 
@@ -309,32 +319,49 @@ private:
   double GetRefreshTimerInterval() const;
   double GetRegularTimerInterval(bool *outIsDefault = nullptr) const;
   double GetThrottledTimerInterval() const;
 
   bool HaveFrameRequestCallbacks() const {
     return mFrameRequestCallbackDocs.Length() != 0;
   }
 
+  void FinishedWaitingForTransaction();
+
   mozilla::RefreshDriverTimer* ChooseTimer() const;
   mozilla::RefreshDriverTimer *mActiveTimer;
 
   ProfilerBacktrace* mReflowCause;
   ProfilerBacktrace* mStyleCause;
 
   nsPresContext *mPresContext; // weak; pres context passed in constructor
                                // and unset in Disconnect
 
+  nsRefPtr<nsRefreshDriver> mRootRefresh;
+
+  // The most recently allocated transaction id.
+  uint64_t mPendingTransaction;
+  // The most recently completed transaction id.
+  uint64_t mCompletedTransaction;
+
   uint32_t mFreezeCount;
   bool mThrottled;
   bool mTestControllingRefreshes;
   bool mViewManagerFlushIsPending;
   bool mRequestedHighPrecision;
   bool mInRefresh;
 
+  // True if the refresh driver is suspended waiting for transaction
+  // id's to be returned and shouldn't do any work during Tick().
+  bool mWaitingForTransaction;
+  // True if Tick() was skipped because of mWaitingForTransaction and
+  // we should schedule a new Tick immediately when resumed instead
+  // of waiting until the next interval.
+  uint32_t mSkippedPaints;
+
   int64_t mMostRecentRefreshEpochTime;
   mozilla::TimeStamp mMostRecentRefresh;
 
   // separate arrays for each flush type we support
   ObserverArray mObservers[3];
   RequestTable mRequests;
   ImageStartTable mStartTable;
 
--- a/layout/forms/nsComboboxControlFrame.cpp
+++ b/layout/forms/nsComboboxControlFrame.cpp
@@ -1345,36 +1345,34 @@ nsComboboxControlFrame::GetChildList(Chi
 
 void
 nsComboboxControlFrame::GetChildLists(nsTArray<ChildList>* aLists) const
 {
   nsBlockFrame::GetChildLists(aLists);
   mPopupFrames.AppendIfNonempty(aLists, kSelectPopupList);
 }
 
-nsresult
+void
 nsComboboxControlFrame::SetInitialChildList(ChildListID     aListID,
                                             nsFrameList&    aChildList)
 {
-  nsresult rv = NS_OK;
   if (kSelectPopupList == aListID) {
     mPopupFrames.SetFrames(aChildList);
   } else {
     for (nsFrameList::Enumerator e(aChildList); !e.AtEnd(); e.Next()) {
       nsCOMPtr<nsIFormControl> formControl =
         do_QueryInterface(e.get()->GetContent());
       if (formControl && formControl->GetType() == NS_FORM_BUTTON_BUTTON) {
         mButtonFrame = e.get();
         break;
       }
     }
     NS_ASSERTION(mButtonFrame, "missing button frame in initial child list");
-    rv = nsBlockFrame::SetInitialChildList(aListID, aChildList);
+    nsBlockFrame::SetInitialChildList(aListID, aChildList);
   }
-  return rv;
 }
 
 //----------------------------------------------------------------------
   //nsIRollupListener
 //----------------------------------------------------------------------
 bool
 nsComboboxControlFrame::Rollup(uint32_t aCount, const nsIntPoint* pos, nsIContent** aLastRolledUp)
 {
--- a/layout/forms/nsComboboxControlFrame.h
+++ b/layout/forms/nsComboboxControlFrame.h
@@ -100,18 +100,18 @@ public:
   virtual nsIScrollableFrame* GetScrollTargetFrame() MOZ_OVERRIDE {
     return do_QueryFrame(mDropdownFrame);
   }
 
 #ifdef DEBUG_FRAME_DUMP
   virtual nsresult GetFrameName(nsAString& aResult) const MOZ_OVERRIDE;
 #endif
   virtual void DestroyFrom(nsIFrame* aDestructRoot) MOZ_OVERRIDE;
-  virtual nsresult SetInitialChildList(ChildListID     aListID,
-                                       nsFrameList&    aChildList) MOZ_OVERRIDE;
+  virtual void SetInitialChildList(ChildListID     aListID,
+                                   nsFrameList&    aChildList) MOZ_OVERRIDE;
   virtual const nsFrameList& GetChildList(ChildListID aListID) const MOZ_OVERRIDE;
   virtual void GetChildLists(nsTArray<ChildList>* aLists) const MOZ_OVERRIDE;
 
   virtual nsContainerFrame* GetContentInsertionFrame() MOZ_OVERRIDE;
 
   // nsIFormControlFrame
   virtual nsresult SetFormProperty(nsIAtom* aName, const nsAString& aValue) MOZ_OVERRIDE;
   /**
--- a/layout/forms/nsFieldSetFrame.cpp
+++ b/layout/forms/nsFieldSetFrame.cpp
@@ -38,27 +38,16 @@ nsFieldSetFrame::nsFieldSetFrame(nsStyle
 }
 
 nsIAtom*
 nsFieldSetFrame::GetType() const
 {
   return nsGkAtoms::fieldSetFrame;
 }
 
-#ifdef DEBUG
-nsresult
-nsFieldSetFrame::SetInitialChildList(ChildListID    aListID,
-                                     nsFrameList&   aChildList)
-{
-  nsresult rv = nsContainerFrame::SetInitialChildList(kPrincipalList, aChildList);
-  MOZ_ASSERT(GetInner());
-  return rv;
-}
-#endif
-
 nsRect
 nsFieldSetFrame::VisualBorderRectRelativeToSelf() const
 {
   nscoord topBorder = StyleBorder()->GetComputedBorderWidth(NS_SIDE_TOP);
   nsRect r(nsPoint(0,0), GetSize());
   if (topBorder < mLegendRect.height) {
     nscoord yoff = (mLegendRect.height - topBorder) / 2;
     r.y += yoff;
@@ -551,40 +540,46 @@ nsFieldSetFrame::Reflow(nsPresContext*  
 
   FinishReflowWithAbsoluteFrames(aPresContext, aDesiredSize, aReflowState, aStatus);
 
   InvalidateFrame();
 
   NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
 }
 
-nsresult
+#ifdef DEBUG
+void
+nsFieldSetFrame::SetInitialChildList(ChildListID    aListID,
+                                     nsFrameList&   aChildList)
+{
+  nsContainerFrame::SetInitialChildList(kPrincipalList, aChildList);
+  MOZ_ASSERT(GetInner());
+}
+void
 nsFieldSetFrame::AppendFrames(ChildListID    aListID,
                               nsFrameList&   aFrameList)
 {
   MOZ_CRASH("nsFieldSetFrame::AppendFrames not supported");
-  return NS_ERROR_NOT_IMPLEMENTED;
 }
 
-nsresult
+void
 nsFieldSetFrame::InsertFrames(ChildListID    aListID,
                               nsIFrame*      aPrevFrame,
                               nsFrameList&   aFrameList)
 {
   MOZ_CRASH("nsFieldSetFrame::InsertFrames not supported");
-  return NS_ERROR_NOT_IMPLEMENTED;
 }
 
-nsresult
+void
 nsFieldSetFrame::RemoveFrame(ChildListID    aListID,
                              nsIFrame*      aOldFrame)
 {
   MOZ_CRASH("nsFieldSetFrame::RemoveFrame not supported");
-  return NS_ERROR_NOT_IMPLEMENTED;
 }
+#endif
 
 #ifdef ACCESSIBILITY
 a11y::AccType
 nsFieldSetFrame::AccessibleType()
 {
   return a11y::eHTMLGroupboxType;
 }
 #endif
--- a/layout/forms/nsFieldSetFrame.h
+++ b/layout/forms/nsFieldSetFrame.h
@@ -40,44 +40,43 @@ public:
                                
   virtual void BuildDisplayList(nsDisplayListBuilder*   aBuilder,
                                 const nsRect&           aDirtyRect,
                                 const nsDisplayListSet& aLists) MOZ_OVERRIDE;
 
   void PaintBorderBackground(nsRenderingContext& aRenderingContext,
     nsPoint aPt, const nsRect& aDirtyRect, uint32_t aBGFlags);
 
-  virtual nsresult AppendFrames(ChildListID    aListID,
-                                nsFrameList&   aFrameList) MOZ_OVERRIDE;
-  virtual nsresult InsertFrames(ChildListID    aListID,
-                                nsIFrame*      aPrevFrame,
-                                nsFrameList&   aFrameList) MOZ_OVERRIDE;
-  virtual nsresult RemoveFrame(ChildListID    aListID,
-                               nsIFrame*      aOldFrame) MOZ_OVERRIDE;
+#ifdef DEBUG
+  virtual void SetInitialChildList(ChildListID    aListID,
+                                   nsFrameList&   aChildList) MOZ_OVERRIDE;
+  virtual void AppendFrames(ChildListID    aListID,
+                            nsFrameList&   aFrameList) MOZ_OVERRIDE;
+  virtual void InsertFrames(ChildListID    aListID,
+                            nsIFrame*      aPrevFrame,
+                            nsFrameList&   aFrameList) MOZ_OVERRIDE;
+  virtual void RemoveFrame(ChildListID    aListID,
+                           nsIFrame*      aOldFrame) MOZ_OVERRIDE;
+#endif
 
   virtual nsIAtom* GetType() const MOZ_OVERRIDE;
   virtual bool IsFrameOfType(uint32_t aFlags) const MOZ_OVERRIDE
   {
     return nsContainerFrame::IsFrameOfType(aFlags &
              ~nsIFrame::eCanContainOverflowContainers);
   }
   virtual nsIScrollableFrame* GetScrollTargetFrame() MOZ_OVERRIDE
   {
     return do_QueryFrame(GetInner());
   }
 
 #ifdef ACCESSIBILITY  
   virtual mozilla::a11y::AccType AccessibleType() MOZ_OVERRIDE;
 #endif
 
-#ifdef DEBUG
-  virtual nsresult SetInitialChildList(ChildListID    aListID,
-                                       nsFrameList&   aChildList) MOZ_OVERRIDE;
-#endif
-
 #ifdef DEBUG_FRAME_DUMP
   virtual nsresult GetFrameName(nsAString& aResult) const MOZ_OVERRIDE {
     return MakeFrameName(NS_LITERAL_STRING("FieldSet"), aResult);
   }
 #endif
 
   /**
    * Return the anonymous frame that contains all descendants except
--- a/layout/forms/nsHTMLButtonControlFrame.cpp
+++ b/layout/forms/nsHTMLButtonControlFrame.cpp
@@ -368,32 +368,31 @@ nsHTMLButtonControlFrame::GetAdditionalS
 
 void
 nsHTMLButtonControlFrame::SetAdditionalStyleContext(int32_t aIndex, 
                                                     nsStyleContext* aStyleContext)
 {
   mRenderer.SetStyleContext(aIndex, aStyleContext);
 }
 
-nsresult 
+#ifdef DEBUG
+void
 nsHTMLButtonControlFrame::AppendFrames(ChildListID     aListID,
                                        nsFrameList&    aFrameList)
 {
-  NS_NOTREACHED("unsupported operation");
-  return NS_ERROR_UNEXPECTED;
+  MOZ_CRASH("unsupported operation");
 }
 
-nsresult
+void
 nsHTMLButtonControlFrame::InsertFrames(ChildListID     aListID,
                                        nsIFrame*       aPrevFrame,
                                        nsFrameList&    aFrameList)
 {
-  NS_NOTREACHED("unsupported operation");
-  return NS_ERROR_UNEXPECTED;
+  MOZ_CRASH("unsupported operation");
 }
 
-nsresult
+void
 nsHTMLButtonControlFrame::RemoveFrame(ChildListID     aListID,
                                       nsIFrame*       aOldFrame)
 {
-  NS_NOTREACHED("unsupported operation");
-  return NS_ERROR_UNEXPECTED;
+  MOZ_CRASH("unsupported operation");
 }
+#endif
--- a/layout/forms/nsHTMLButtonControlFrame.h
+++ b/layout/forms/nsHTMLButtonControlFrame.h
@@ -46,25 +46,25 @@ public:
   virtual void Init(nsIContent*       aContent,
                     nsContainerFrame* aParent,
                     nsIFrame*         aPrevInFlow) MOZ_OVERRIDE;
 
   virtual nsStyleContext* GetAdditionalStyleContext(int32_t aIndex) const MOZ_OVERRIDE;
   virtual void SetAdditionalStyleContext(int32_t aIndex, 
                                          nsStyleContext* aStyleContext) MOZ_OVERRIDE;
  
-  virtual nsresult AppendFrames(ChildListID     aListID,
-                                nsFrameList&    aFrameList) MOZ_OVERRIDE;
-
-  virtual nsresult InsertFrames(ChildListID     aListID,
-                                nsIFrame*       aPrevFrame,
-                                nsFrameList&    aFrameList) MOZ_OVERRIDE;
-
-  virtual nsresult RemoveFrame(ChildListID     aListID,
-                               nsIFrame*       aOldFrame) MOZ_OVERRIDE;
+#ifdef DEBUG
+  virtual void AppendFrames(ChildListID     aListID,
+                            nsFrameList&    aFrameList) MOZ_OVERRIDE;
+  virtual void InsertFrames(ChildListID     aListID,
+                            nsIFrame*       aPrevFrame,
+                            nsFrameList&    aFrameList) MOZ_OVERRIDE;
+  virtual void RemoveFrame(ChildListID     aListID,
+                           nsIFrame*       aOldFrame) MOZ_OVERRIDE;
+#endif
 
 #ifdef ACCESSIBILITY
   virtual mozilla::a11y::AccType AccessibleType() MOZ_OVERRIDE;
 #endif
 
   virtual nsIAtom* GetType() const MOZ_OVERRIDE;
   
 #ifdef DEBUG_FRAME_DUMP
--- a/layout/forms/nsListControlFrame.cpp
+++ b/layout/forms/nsListControlFrame.cpp
@@ -890,40 +890,38 @@ nsListControlFrame::HandleEvent(nsPresCo
   if (eventStates.HasState(NS_EVENT_STATE_DISABLED))
     return NS_OK;
 
   return nsHTMLScrollFrame::HandleEvent(aPresContext, aEvent, aEventStatus);
 }
 
 
 //---------------------------------------------------------
-nsresult
+void
 nsListControlFrame::SetInitialChildList(ChildListID    aListID,
                                         nsFrameList&   aChildList)
 {
   // First check to see if all the content has been added
   mIsAllContentHere = mContent->IsDoneAddingChildren();
   if (!mIsAllContentHere) {
     mIsAllFramesHere    = false;
     mHasBeenInitialized = false;
   }
-  nsresult rv = nsHTMLScrollFrame::SetInitialChildList(aListID, aChildList);
+  nsHTMLScrollFrame::SetInitialChildList(aListID, aChildList);
 
   // If all the content is here now check
   // to see if all the frames have been created
   /*if (mIsAllContentHere) {
     // If all content and frames are here
     // the reset/initialize
     if (CheckIfAllFramesHere()) {
       ResetList(aPresContext);
       mHasBeenInitialized = true;
     }
   }*/
-
-  return rv;
 }
 
 //---------------------------------------------------------
 void
 nsListControlFrame::Init(nsIContent*       aContent,
                          nsContainerFrame* aParent,
                          nsIFrame*         aPrevInFlow)
 {
--- a/layout/forms/nsListControlFrame.h
+++ b/layout/forms/nsListControlFrame.h
@@ -58,18 +58,18 @@ public:
   NS_DECL_QUERYFRAME
   NS_DECL_FRAMEARENA_HELPERS
 
     // nsIFrame
   virtual nsresult HandleEvent(nsPresContext* aPresContext,
                                mozilla::WidgetGUIEvent* aEvent,
                                nsEventStatus* aEventStatus) MOZ_OVERRIDE;
   
-  virtual nsresult SetInitialChildList(ChildListID     aListID,
-                                       nsFrameList&    aChildList) MOZ_OVERRIDE;
+  virtual void SetInitialChildList(ChildListID     aListID,
+                                   nsFrameList&    aChildList) MOZ_OVERRIDE;
 
   virtual nscoord GetPrefWidth(nsRenderingContext *aRenderingContext) MOZ_OVERRIDE;
   virtual nscoord GetMinWidth(nsRenderingContext *aRenderingContext) MOZ_OVERRIDE;
 
   virtual void Reflow(nsPresContext*           aCX,
                       nsHTMLReflowMetrics&     aDesiredSize,
                       const nsHTMLReflowState& aReflowState,
                       nsReflowStatus&          aStatus) MOZ_OVERRIDE;
--- a/layout/forms/nsTextControlFrame.cpp
+++ b/layout/forms/nsTextControlFrame.cpp
@@ -1179,21 +1179,21 @@ nsTextControlFrame::GetMaxLength(int32_t
       return true;
     }
   }
   return false;
 }
 
 // END IMPLEMENTING NS_IFORMCONTROLFRAME
 
-nsresult
+void
 nsTextControlFrame::SetInitialChildList(ChildListID     aListID,
                                         nsFrameList&    aChildList)
 {
-  nsresult rv = nsContainerFrame::SetInitialChildList(aListID, aChildList);
+  nsContainerFrame::SetInitialChildList(aListID, aChildList);
 
   nsIFrame* first = GetFirstPrincipalChild();
 
   // Mark the scroll frame as being a reflow root. This will allow
   // incremental reflows to be initiated at the scroll frame, rather
   // than descending from the root frame of the frame hierarchy.
   if (first) {
     first->AddStateBits(NS_FRAME_REFLOW_ROOT);
@@ -1211,17 +1211,16 @@ nsTextControlFrame::SetInitialChildList(
       NS_ASSERTION(statefulFrame, "unexpected type of frame for the anonymous div");
       nsPresState fakePresState;
       fakePresState.SetScrollState(*contentScrollPos);
       statefulFrame->RestoreState(&fakePresState);
       Properties().Remove(ContentScrollPos());
       delete contentScrollPos;
     }
   }
-  return rv;
 }
 
 void
 nsTextControlFrame::SetValueChanged(bool aValueChanged)
 {
   nsCOMPtr<nsITextControlElement> txtCtrl = do_QueryInterface(GetContent());
   NS_ASSERTION(txtCtrl, "Content not a text control element");
 
--- a/layout/forms/nsTextControlFrame.h
+++ b/layout/forms/nsTextControlFrame.h
@@ -80,20 +80,18 @@ public:
       ~(nsIFrame::eReplaced | nsIFrame::eReplacedContainsBlock));
   }
 
   // nsIAnonymousContentCreator
   virtual nsresult CreateAnonymousContent(nsTArray<ContentInfo>& aElements) MOZ_OVERRIDE;
   virtual void AppendAnonymousContentTo(nsBaseContentList& aElements,
                                         uint32_t aFilter) MOZ_OVERRIDE;
 
-  // Utility methods to set current widget state
-
-  virtual nsresult SetInitialChildList(ChildListID     aListID,
-                                       nsFrameList&    aChildList) MOZ_OVERRIDE;
+  virtual void SetInitialChildList(ChildListID     aListID,
+                                   nsFrameList&    aChildList) MOZ_OVERRIDE;
 
   virtual void BuildDisplayList(nsDisplayListBuilder*   aBuilder,
                                 const nsRect&           aDirtyRect,
                                 const nsDisplayListSet& aLists) MOZ_OVERRIDE;
 
   virtual mozilla::dom::Element* GetPseudoElement(nsCSSPseudoElements::Type aType) MOZ_OVERRIDE;
 
 //==== BEGIN NSIFORMCONTROLFRAME
new file mode 100644
--- /dev/null
+++ b/layout/generic/crashtests/1015562.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script>
+
+/*
+user_pref("layout.css.grid.enabled", true);
+*/
+
+function boom()
+{
+    document.getElementById("r").appendChild(document.createTextNode("B"));
+}
+
+</script>
+</head>
+<body onload="boom();">
+<div id="r" style="display: grid;">A</div>
+</body>
+</html>
--- a/layout/generic/crashtests/crashtests.list
+++ b/layout/generic/crashtests/crashtests.list
@@ -525,9 +525,10 @@ load 927558.html
 load 943509-1.html
 asserts(3-6) load 944909-1.html
 test-pref(layout.css.sticky.enabled,true) load 949932.html
 load 973701-1.xhtml
 load 973701-2.xhtml
 load 986899.html
 load 1001233.html
 load 1001258-1.html
+pref(layout.css.grid.enabled,true) load 1015562.html
 load outline-on-frameset.xhtml
--- a/layout/generic/nsAbsoluteContainingBlock.cpp
+++ b/layout/generic/nsAbsoluteContainingBlock.cpp
@@ -29,30 +29,29 @@ static void PrettyUC(nscoord aSize, char
       strcpy(aBuf, "deadbeef");
     } else {
       sprintf(aBuf, "%d", aSize);
     }
   }
 }
 #endif
 
-nsresult
+void
 nsAbsoluteContainingBlock::SetInitialChildList(nsIFrame*       aDelegatingFrame,
                                                ChildListID     aListID,
                                                nsFrameList&    aChildList)
 {
   NS_PRECONDITION(mChildListID == aListID, "unexpected child list name");
 #ifdef DEBUG
   nsFrame::VerifyDirtyBitSet(aChildList);
 #endif
   mAbsoluteFrames.SetFrames(aChildList);
-  return NS_OK;
 }
 
-nsresult
+void
 nsAbsoluteContainingBlock::AppendFrames(nsIFrame*      aDelegatingFrame,
                                         ChildListID    aListID,
                                         nsFrameList&   aFrameList)
 {
   NS_ASSERTION(mChildListID == aListID, "unexpected child list");
 
   // Append the frames to our list of absolutely positioned frames
 #ifdef DEBUG
@@ -60,21 +59,19 @@ nsAbsoluteContainingBlock::AppendFrames(
 #endif
   mAbsoluteFrames.AppendFrames(nullptr, aFrameList);
 
   // no damage to intrinsic widths, since absolutely positioned frames can't
   // change them
   aDelegatingFrame->PresContext()->PresShell()->
     FrameNeedsReflow(aDelegatingFrame, nsIPresShell::eResize,
                      NS_FRAME_HAS_DIRTY_CHILDREN);
-
-  return NS_OK;
 }
 
-nsresult
+void
 nsAbsoluteContainingBlock::InsertFrames(nsIFrame*      aDelegatingFrame,
                                         ChildListID    aListID,
                                         nsIFrame*      aPrevFrame,
                                         nsFrameList&   aFrameList)
 {
   NS_ASSERTION(mChildListID == aListID, "unexpected child list");
   NS_ASSERTION(!aPrevFrame || aPrevFrame->GetParent() == aDelegatingFrame,
                "inserting after sibling frame with different parent");
@@ -84,18 +81,16 @@ nsAbsoluteContainingBlock::InsertFrames(
 #endif
   mAbsoluteFrames.InsertFrames(nullptr, aPrevFrame, aFrameList);
 
   // no damage to intrinsic widths, since absolutely positioned frames can't
   // change them
   aDelegatingFrame->PresContext()->PresShell()->
     FrameNeedsReflow(aDelegatingFrame, nsIPresShell::eResize,
                      NS_FRAME_HAS_DIRTY_CHILDREN);
-
-  return NS_OK;
 }
 
 void
 nsAbsoluteContainingBlock::RemoveFrame(nsIFrame*       aDelegatingFrame,
                                        ChildListID     aListID,
                                        nsIFrame*       aOldFrame)
 {
   NS_ASSERTION(mChildListID == aListID, "unexpected child list");
--- a/layout/generic/nsAbsoluteContainingBlock.h
+++ b/layout/generic/nsAbsoluteContainingBlock.h
@@ -49,26 +49,26 @@ public:
   const nsFrameList& GetChildList() const { return mAbsoluteFrames; }
   void AppendChildList(nsTArray<nsIFrame::ChildList>* aLists,
                        ChildListID aListID) const
   {
     NS_ASSERTION(aListID == mChildListID, "wrong list ID");
     GetChildList().AppendIfNonempty(aLists, aListID);
   }
 
-  nsresult SetInitialChildList(nsIFrame*       aDelegatingFrame,
-                               ChildListID     aListID,
-                               nsFrameList&    aChildList);
-  nsresult AppendFrames(nsIFrame*      aDelegatingFrame,
-                        ChildListID    aListID,
-                        nsFrameList&   aFrameList);
-  nsresult InsertFrames(nsIFrame*      aDelegatingFrame,
-                        ChildListID    aListID,
-                        nsIFrame*      aPrevFrame,
-                        nsFrameList&   aFrameList);
+  void SetInitialChildList(nsIFrame*       aDelegatingFrame,
+                           ChildListID     aListID,
+                           nsFrameList&    aChildList);
+  void AppendFrames(nsIFrame*      aDelegatingFrame,
+                    ChildListID    aListID,
+                    nsFrameList&   aFrameList);
+  void InsertFrames(nsIFrame*      aDelegatingFrame,
+                    ChildListID    aListID,
+                    nsIFrame*      aPrevFrame,
+                    nsFrameList&   aFrameList);
   void RemoveFrame(nsIFrame*      aDelegatingFrame,
                    ChildListID    aListID,
                    nsIFrame*      aOldFrame);
 
   /**
    * Called by the delegating frame after it has done its reflow first. This
    * function will reflow any absolutely positioned child frames that need to
    * be reflowed, e.g., because the absolutely positioned child frame has
--- a/layout/generic/nsBlockFrame.cpp
+++ b/layout/generic/nsBlockFrame.cpp
@@ -58,16 +58,72 @@ static const char16_t kCircleCharacter =
 static const char16_t kSquareCharacter = 0x25aa;
 
 #define DISABLE_FLOAT_BREAKING_IN_COLUMNS
 
 using namespace mozilla;
 using namespace mozilla::css;
 using namespace mozilla::layout;
 
+static void MarkAllDescendantLinesDirty(nsBlockFrame* aBlock)
+{
+  nsLineList::iterator line = aBlock->begin_lines();
+  nsLineList::iterator endLine = aBlock->end_lines();
+  while (line != endLine) {
+    if (line->IsBlock()) {
+      nsIFrame* f = line->mFirstChild;
+      nsBlockFrame* bf = nsLayoutUtils::GetAsBlock(f);
+      if (bf) {
+        MarkAllDescendantLinesDirty(bf);
+      }
+    }
+    line->MarkDirty();
+    ++line;
+  }
+}
+
+static void MarkSameFloatManagerLinesDirty(nsBlockFrame* aBlock)
+{
+  nsBlockFrame* blockWithFloatMgr = aBlock;
+  while (!(blockWithFloatMgr->GetStateBits() & NS_BLOCK_FLOAT_MGR)) {
+    nsBlockFrame* bf = nsLayoutUtils::GetAsBlock(blockWithFloatMgr->GetParent());
+    if (!bf) {
+      break;
+    }
+    blockWithFloatMgr = bf;
+  }
+    
+  // Mark every line at and below the line where the float was
+  // dirty, and mark their lines dirty too. We could probably do
+  // something more efficient --- e.g., just dirty the lines that intersect
+  // the float vertically.
+  MarkAllDescendantLinesDirty(blockWithFloatMgr);
+}
+
+/**
+ * Returns true if aFrame is a block that has one or more float children.
+ */
+static bool BlockHasAnyFloats(nsIFrame* aFrame)
+{
+  nsBlockFrame* block = nsLayoutUtils::GetAsBlock(aFrame);
+  if (!block)
+    return false;
+  if (block->GetFirstChild(nsIFrame::kFloatList))
+    return true;
+    
+  nsLineList::iterator line = block->begin_lines();
+  nsLineList::iterator endLine = block->end_lines();
+  while (line != endLine) {
+    if (line->IsBlock() && BlockHasAnyFloats(line->mFirstChild))
+      return true;
+    ++line;
+  }
+  return false;
+}
+
 #ifdef DEBUG
 #include "nsBlockDebugFlags.h"
 
 bool nsBlockFrame::gLamePaintMetrics;
 bool nsBlockFrame::gLameReflowMetrics;
 bool nsBlockFrame::gNoisy;
 bool nsBlockFrame::gNoisyDamageRepair;
 bool nsBlockFrame::gNoisyIntrinsic;
@@ -2441,33 +2497,16 @@ nsBlockFrame::ReflowDirtyLines(nsBlockRe
     IndentBy(stdout, gNoiseIndent - 1);
     ListTag(stdout);
     printf(": done reflowing dirty lines (status=%x)\n",
            aState.mReflowStatus);
   }
 #endif
 }
 
-static void MarkAllDescendantLinesDirty(nsBlockFrame* aBlock)
-{
-  nsLineList::iterator line = aBlock->begin_lines();
-  nsLineList::iterator endLine = aBlock->end_lines();
-  while (line != endLine) {
-    if (line->IsBlock()) {
-      nsIFrame* f = line->mFirstChild;
-      nsBlockFrame* bf = nsLayoutUtils::GetAsBlock(f);
-      if (bf) {
-        MarkAllDescendantLinesDirty(bf);
-      }
-    }
-    line->MarkDirty();
-    ++line;
-  }
-}
-
 void
 nsBlockFrame::MarkLineDirtyForInterrupt(nsLineBox* aLine)
 {
   aLine->MarkDirty();
 
   // Just checking NS_FRAME_IS_DIRTY is ok, because we've already
   // marked the lines that need to be marked dirty based on our
   // vertical resize stuff.  So we'll definitely reflow all those kids;
@@ -4656,101 +4695,133 @@ nsBlockFrame::RemovePushedFloats()
   RemoveStateBits(NS_BLOCK_HAS_PUSHED_FLOATS);
   NS_ASSERTION(result, "value should always be non-empty when state set");
   return result;
 }
 
 //////////////////////////////////////////////////////////////////////
 // Frame list manipulation routines
 
-nsresult
+void
 nsBlockFrame::AppendFrames(ChildListID  aListID,
                            nsFrameList& aFrameList)
 {
   if (aFrameList.IsEmpty()) {
-    return NS_OK;
+    return;
   }
   if (aListID != kPrincipalList) {
-    if (kAbsoluteList == aListID) {
-      return nsContainerFrame::AppendFrames(aListID, aFrameList);
-    }
-    else if (kFloatList == aListID) {
+    if (kFloatList == aListID) {
       mFloats.AppendFrames(nullptr, aFrameList);
-      return NS_OK;
-    }
-    else {
-      NS_ERROR("unexpected child list");
-      return NS_ERROR_INVALID_ARG;
-    }
+      return;
+    }
+    MOZ_ASSERT(kNoReflowPrincipalList == aListID, "unexpected child list");
   }
 
   // Find the proper last-child for where the append should go
   nsIFrame* lastKid = mFrames.LastChild();
   NS_ASSERTION((mLines.empty() ? nullptr : mLines.back()->LastChild()) ==
                lastKid, "out-of-sync mLines / mFrames");
 
-  // Add frames after the last child
 #ifdef NOISY_REFLOW_REASON
   ListTag(stdout);
   printf(": append ");
   nsFrame::ListTag(stdout, aFrameList);
   if (lastKid) {
     printf(" after ");
     nsFrame::ListTag(stdout, lastKid);
   }
   printf("\n");
 #endif
 
   AddFrames(aFrameList, lastKid);
-  PresContext()->PresShell()->
-    FrameNeedsReflow(this, nsIPresShell::eTreeChange,
-                     NS_FRAME_HAS_DIRTY_CHILDREN); // XXX sufficient?
-  return NS_OK;
-}
-
-nsresult
+  if (aListID != kNoReflowPrincipalList) {
+    PresContext()->PresShell()->
+      FrameNeedsReflow(this, nsIPresShell::eTreeChange,
+                       NS_FRAME_HAS_DIRTY_CHILDREN); // XXX sufficient?
+  }
+}
+
+void
 nsBlockFrame::InsertFrames(ChildListID aListID,
                            nsIFrame* aPrevFrame,
                            nsFrameList& aFrameList)
 {
   NS_ASSERTION(!aPrevFrame || aPrevFrame->GetParent() == this,
                "inserting after sibling frame with different parent");
 
   if (aListID != kPrincipalList) {
-    if (kAbsoluteList == aListID) {
-      return nsContainerFrame::InsertFrames(aListID, aPrevFrame, aFrameList);
-    }
-    else if (kFloatList == aListID) {
+    if (kFloatList == aListID) {
       mFloats.InsertFrames(this, aPrevFrame, aFrameList);
-      return NS_OK;
-    }
-    else if (kNoReflowPrincipalList != aListID) {
-      NS_ERROR("unexpected child list");
-      return NS_ERROR_INVALID_ARG;
-    }
+      return;
+    }
+    MOZ_ASSERT(kNoReflowPrincipalList == aListID, "unexpected child list");
   }
 
 #ifdef NOISY_REFLOW_REASON
   ListTag(stdout);
   printf(": insert ");
   nsFrame::ListTag(stdout, aFrameList);
   if (aPrevFrame) {
     printf(" after ");
     nsFrame::ListTag(stdout, aPrevFrame);
   }
   printf("\n");
 #endif
 
   AddFrames(aFrameList, aPrevFrame);
-
-  if (aListID != kNoReflowPrincipalList)
+  if (aListID != kNoReflowPrincipalList) {
     PresContext()->PresShell()->
       FrameNeedsReflow(this, nsIPresShell::eTreeChange,
                        NS_FRAME_HAS_DIRTY_CHILDREN); // XXX sufficient?
-  return NS_OK;
+  }
+}
+
+void
+nsBlockFrame::RemoveFrame(ChildListID aListID,
+                          nsIFrame* aOldFrame)
+{
+#ifdef NOISY_REFLOW_REASON
+  ListTag(stdout);
+  printf(": remove ");
+  nsFrame::ListTag(stdout, aOldFrame);
+  printf("\n");
+#endif
+
+  if (aListID == kPrincipalList) {
+    bool hasFloats = BlockHasAnyFloats(aOldFrame);
+    DoRemoveFrame(aOldFrame, REMOVE_FIXED_CONTINUATIONS);
+    if (hasFloats) {
+      MarkSameFloatManagerLinesDirty(this);
+    }
+  }
+  else if (kFloatList == aListID) {
+    // Make sure to mark affected lines dirty for the float frame
+    // we are removing; this way is a bit messy, but so is the rest of the code.
+    // See bug 390762.
+    NS_ASSERTION(!aOldFrame->GetPrevContinuation(),
+                 "RemoveFrame should not be called on pushed floats.");
+    for (nsIFrame* f = aOldFrame;
+         f && !(f->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER);
+         f = f->GetNextContinuation()) {
+      MarkSameFloatManagerLinesDirty(static_cast<nsBlockFrame*>(f->GetParent()));
+    }
+    DoRemoveOutOfFlowFrame(aOldFrame);
+  }
+  else if (kNoReflowPrincipalList == aListID) {
+    // Skip the call to |FrameNeedsReflow| below by returning now.
+    DoRemoveFrame(aOldFrame, REMOVE_FIXED_CONTINUATIONS);
+    return;
+  }
+  else {
+    MOZ_CRASH("unexpected child list");
+  }
+
+  PresContext()->PresShell()->
+    FrameNeedsReflow(this, nsIPresShell::eTreeChange,
+                     NS_FRAME_HAS_DIRTY_CHILDREN); // XXX sufficient?
 }
 
 static bool
 ShouldPutNextSiblingOnNewLine(nsIFrame* aLastFrame)
 {
   nsIAtom* type = aLastFrame->GetType();
   if (type == nsGkAtoms::brFrame) {
     return true;
@@ -4943,109 +5014,16 @@ nsBlockFrame::RemoveFloat(nsIFrame* aFlo
   {
     nsAutoOOFFrameList oofs(this);
     if (oofs.mList.ContinueRemoveFrame(aFloat)) {
       return;
     }
   }
 }
 
-static void MarkSameFloatManagerLinesDirty(nsBlockFrame* aBlock)
-{
-  nsBlockFrame* blockWithFloatMgr = aBlock;
-  while (!(blockWithFloatMgr->GetStateBits() & NS_BLOCK_FLOAT_MGR)) {
-    nsBlockFrame* bf = nsLayoutUtils::GetAsBlock(blockWithFloatMgr->GetParent());
-    if (!bf) {
-      break;
-    }
-    blockWithFloatMgr = bf;
-  }
-    
-  // Mark every line at and below the line where the float was
-  // dirty, and mark their lines dirty too. We could probably do
-  // something more efficient --- e.g., just dirty the lines that intersect
-  // the float vertically.
-  MarkAllDescendantLinesDirty(blockWithFloatMgr);
-}
-
-/**
- * Returns true if aFrame is a block that has one or more float children.
- */
-static bool BlockHasAnyFloats(nsIFrame* aFrame)
-{
-  nsBlockFrame* block = nsLayoutUtils::GetAsBlock(aFrame);
-  if (!block)
-    return false;
-  if (block->GetFirstChild(nsIFrame::kFloatList))
-    return true;
-    
-  nsLineList::iterator line = block->begin_lines();
-  nsLineList::iterator endLine = block->end_lines();
-  while (line != endLine) {
-    if (line->IsBlock() && BlockHasAnyFloats(line->mFirstChild))
-      return true;
-    ++line;
-  }
-  return false;
-}
-
-nsresult
-nsBlockFrame::RemoveFrame(ChildListID aListID,
-                          nsIFrame* aOldFrame)
-{
-  nsresult rv = NS_OK;
-
-#ifdef NOISY_REFLOW_REASON
-  ListTag(stdout);
-  printf(": remove ");
-  nsFrame::ListTag(stdout, aOldFrame);
-  printf("\n");
-#endif
-
-  if (aListID == kPrincipalList) {
-    bool hasFloats = BlockHasAnyFloats(aOldFrame);
-    rv = DoRemoveFrame(aOldFrame, REMOVE_FIXED_CONTINUATIONS);
-    if (hasFloats) {
-      MarkSameFloatManagerLinesDirty(this);
-    }
-  }
-  else if (kAbsoluteList == aListID) {
-    nsContainerFrame::RemoveFrame(aListID, aOldFrame);
-    return NS_OK;
-  }
-  else if (kFloatList == aListID) {
-    // Make sure to mark affected lines dirty for the float frame
-    // we are removing; this way is a bit messy, but so is the rest of the code.
-    // See bug 390762.
-    NS_ASSERTION(!aOldFrame->GetPrevContinuation(),
-                 "RemoveFrame should not be called on pushed floats.");
-    for (nsIFrame* f = aOldFrame;
-         f && !(f->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER);
-         f = f->GetNextContinuation()) {
-      MarkSameFloatManagerLinesDirty(static_cast<nsBlockFrame*>(f->GetParent()));
-    }
-    DoRemoveOutOfFlowFrame(aOldFrame);
-  }
-  else if (kNoReflowPrincipalList == aListID) {
-    // Skip the call to |FrameNeedsReflow| below by returning now.
-    return DoRemoveFrame(aOldFrame, REMOVE_FIXED_CONTINUATIONS);
-  }
-  else {
-    NS_ERROR("unexpected child list");
-    rv = NS_ERROR_INVALID_ARG;
-  }
-
-  if (NS_SUCCEEDED(rv)) {
-    PresContext()->PresShell()->
-      FrameNeedsReflow(this, nsIPresShell::eTreeChange,
-                       NS_FRAME_HAS_DIRTY_CHILDREN); // XXX sufficient?
-  }
-  return rv;
-}
-
 void
 nsBlockFrame::DoRemoveOutOfFlowFrame(nsIFrame* aFrame)
 {
   // The containing block is always the parent of aFrame.
   nsBlockFrame* block = (nsBlockFrame*)aFrame->GetParent();
 
   // Remove aFrame from the appropriate list.
   if (aFrame->IsAbsolutelyPositioned()) {
@@ -5287,54 +5265,54 @@ nsBlockInFlowLineIterator::FindValidLine
         NS_ASSERTION(mLine != mLineList->end(), "empty overflow line list?");
         return true;
       }
     }
     currentlyInOverflowLines = !currentlyInOverflowLines;
   }
 }
 
-static nsresult RemoveBlockChild(nsIFrame* aFrame,
-                                 bool      aRemoveOnlyFluidContinuations)
-{
-  if (!aFrame)
-    return NS_OK;
-
+static void RemoveBlockChild(nsIFrame* aFrame,
+                             bool      aRemoveOnlyFluidContinuations)
+{
+  if (!aFrame) {
+    return;
+  }
   nsBlockFrame* nextBlock = nsLayoutUtils::GetAsBlock(aFrame->GetParent());
   NS_ASSERTION(nextBlock,
                "Our child's continuation's parent is not a block?");
-  return nextBlock->DoRemoveFrame(aFrame,
+  nextBlock->DoRemoveFrame(aFrame,
       (aRemoveOnlyFluidContinuations ? 0 : nsBlockFrame::REMOVE_FIXED_CONTINUATIONS));
 }
 
 // This function removes aDeletedFrame and all its continuations.  It
 // is optimized for deleting a whole series of frames. The easy
 // implementation would invoke itself recursively on
 // aDeletedFrame->GetNextContinuation, then locate the line containing
 // aDeletedFrame and remove aDeletedFrame from that line. But here we
 // start by locating aDeletedFrame and then scanning from that point
 // on looking for continuations.
-nsresult
+void
 nsBlockFrame::DoRemoveFrame(nsIFrame* aDeletedFrame, uint32_t aFlags)
 {
   // Clear our line cursor, since our lines may change.
   ClearLineCursor();
 
   if (aDeletedFrame->GetStateBits() &
       (NS_FRAME_OUT_OF_FLOW | NS_FRAME_IS_OVERFLOW_CONTAINER)) {
     if (!aDeletedFrame->GetPrevInFlow()) {
       NS_ASSERTION(aDeletedFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW,
                    "Expected out-of-flow frame");
       DoRemoveOutOfFlowFrame(aDeletedFrame);
     }
     else {
       nsContainerFrame::DeleteNextInFlowChild(aDeletedFrame,
                                               (aFlags & FRAMES_ARE_EMPTY) != 0);
     }
-    return NS_OK;
+    return;
   }
 
   // Find the line that contains deletedFrame
   nsLineList::iterator line_start = mLines.begin(),
                        line_end = mLines.end();
   nsLineList::iterator line = line_start;
   FrameLines* overflowLines = nullptr;
   bool searchingOverflowList = false;
@@ -5348,17 +5326,17 @@ nsBlockFrame::DoRemoveFrame(nsIFrame* aD
     }
     ++line;
     TryAllLines(&line, &line_start, &line_end, &searchingOverflowList,
                 &overflowLines);
   }
 
   if (line == line_end) {
     NS_ERROR("can't find deleted frame in lines");
-    return NS_ERROR_FAILURE;
+    return;
   }
   
   if (!(aFlags & FRAMES_ARE_EMPTY)) {
     if (line != line_start) {
       line.prev()->MarkDirty();
       line.prev()->SetInvalidateTextRuns(true);
     }
     else if (searchingOverflowList && !mLines.empty()) {
@@ -5537,17 +5515,17 @@ nsBlockFrame::DoRemoveFrame(nsIFrame* aD
   }
 
 #ifdef DEBUG
   VerifyLines(true);
   VerifyOverflowSituation();
 #endif
 
   // Advance to next flow block if the frame has more continuations
-  return RemoveBlockChild(aDeletedFrame, !(aFlags & REMOVE_FIXED_CONTINUATIONS));
+  RemoveBlockChild(aDeletedFrame, !(aFlags & REMOVE_FIXED_CONTINUATIONS));
 }
 
 static bool
 FindBlockLineFor(nsIFrame*             aChild,
                  nsLineList::iterator  aBegin,
                  nsLineList::iterator  aEnd,
                  nsLineList::iterator* aResult)
 {
@@ -6432,17 +6410,17 @@ nsBlockFrame::Init(nsIContent*       aCo
 
   if ((GetStateBits() &
        (NS_FRAME_FONT_INFLATION_CONTAINER | NS_BLOCK_FLOAT_MGR)) ==
       (NS_FRAME_FONT_INFLATION_CONTAINER | NS_BLOCK_FLOAT_MGR)) {
     AddStateBits(NS_FRAME_FONT_INFLATION_FLOW_ROOT);
   }
 }
 
-nsresult
+void
 nsBlockFrame::SetInitialChildList(ChildListID     aListID,
                                   nsFrameList&    aChildList)
 {
   NS_ASSERTION(aListID != kPrincipalList ||
                (GetStateBits() & (NS_BLOCK_FRAME_HAS_INSIDE_BULLET |
                                   NS_BLOCK_FRAME_HAS_OUTSIDE_BULLET)) == 0,
                "how can we have a bullet already?");
 
@@ -6540,18 +6518,16 @@ nsBlockFrame::SetInitialChildList(ChildL
         AddStateBits(NS_BLOCK_FRAME_HAS_INSIDE_BULLET);
       } else {
         nsFrameList* bulletList = new (shell) nsFrameList(bullet, bullet);
         Properties().Set(OutsideBulletProperty(), bulletList);
         AddStateBits(NS_BLOCK_FRAME_HAS_OUTSIDE_BULLET);
       }
     }
   }
-
-  return NS_OK;
 }
 
 bool
 nsBlockFrame::BulletIsEmpty() const
 {
   NS_ASSERTION(mContent->GetPrimaryFrame()->StyleDisplay()->mDisplay ==
                  NS_STYLE_DISPLAY_LIST_ITEM && HasOutsideBullet(),
                "should only care when we have an outside bullet");
--- a/layout/generic/nsBlockFrame.h
+++ b/layout/generic/nsBlockFrame.h
@@ -105,25 +105,25 @@ public:
 
   // nsQueryFrame
   NS_DECL_QUERYFRAME
 
   // nsIFrame
   virtual void Init(nsIContent*       aContent,
                     nsContainerFrame* aParent,
                     nsIFrame*         aPrevInFlow) MOZ_OVERRIDE;
-  virtual nsresult SetInitialChildList(ChildListID     aListID,
-                                       nsFrameList&    aChildList) MOZ_OVERRIDE;
-  virtual nsresult  AppendFrames(ChildListID     aListID,
-                                 nsFrameList&    aFrameList) MOZ_OVERRIDE;
-  virtual nsresult  InsertFrames(ChildListID     aListID,
-                                 nsIFrame*       aPrevFrame,
-                                 nsFrameList&    aFrameList) MOZ_OVERRIDE;
-  virtual nsresult  RemoveFrame(ChildListID     aListID,
-                                nsIFrame*       aOldFrame) MOZ_OVERRIDE;
+  virtual void SetInitialChildList(ChildListID     aListID,
+                                   nsFrameList&    aChildList) MOZ_OVERRIDE;
+  virtual void AppendFrames(ChildListID     aListID,
+                            nsFrameList&    aFrameList) MOZ_OVERRIDE;
+  virtual void InsertFrames(ChildListID     aListID,
+                            nsIFrame*       aPrevFrame,
+                            nsFrameList&    aFrameList) MOZ_OVERRIDE;
+  virtual void RemoveFrame(ChildListID     aListID,
+                           nsIFrame*       aOldFrame) MOZ_OVERRIDE;
   virtual const nsFrameList& GetChildList(ChildListID aListID) const MOZ_OVERRIDE;
   virtual void GetChildLists(nsTArray<ChildList>* aLists) const MOZ_OVERRIDE;
   virtual nscoord GetBaseline() const MOZ_OVERRIDE;
   virtual nscoord GetCaretBaseline() const MOZ_OVERRIDE;
   virtual void DestroyFrom(nsIFrame* aDestructRoot) MOZ_OVERRIDE;
   virtual nsSplittableType GetSplittableType() const MOZ_OVERRIDE;
   virtual bool IsFloatContainingBlock() const MOZ_OVERRIDE;
   virtual void BuildDisplayList(nsDisplayListBuilder*   aBuilder,
@@ -461,17 +461,17 @@ public:
    * -- marks textruns dirty (unless FRAMES_ARE_EMPTY is given, in which
    * case textruns do not need to be dirtied)
    * -- destroys all removed frames
    */
   enum {
     REMOVE_FIXED_CONTINUATIONS = 0x02,
     FRAMES_ARE_EMPTY           = 0x04
   };
-  nsresult DoRemoveFrame(nsIFrame* aDeletedFrame, uint32_t aFlags);
+  void DoRemoveFrame(nsIFrame* aDeletedFrame, uint32_t aFlags);
 
   void ReparentFloats(nsIFrame* aFirstFrame, nsBlockFrame* aOldParent,
                       bool aReparentSiblings);
 
   virtual bool UpdateOverflow() MOZ_OVERRIDE;
 
   /** Load all of aFrame's floats into the float manager iff aFrame is not a
    *  block formatting context. Handles all necessary float manager translations;
--- a/layout/generic/nsCanvasFrame.cpp
+++ b/layout/generic/nsCanvasFrame.cpp
@@ -77,95 +77,59 @@ nsCanvasFrame::SetHasFocus(bool aHasFocu
         sf->AddScrollPositionListener(this);
         mAddedScrollPositionListener = true;
       }
     }
   }
   return NS_OK;
 }
 
-nsresult
+#ifdef DEBUG
+void
 nsCanvasFrame::SetInitialChildList(ChildListID     aListID,
                                    nsFrameList&    aChildList)
 {
   NS_ASSERTION(aListID != kPrincipalList ||
                aChildList.IsEmpty() || aChildList.OnlyChild(),
                "Primary child list can have at most one frame in it");
-  return nsContainerFrame::SetInitialChildList(aListID, aChildList);
+  nsContainerFrame::SetInitialChildList(aListID, aChildList);
 }
 
-nsresult
+void
 nsCanvasFrame::AppendFrames(ChildListID     aListID,
                             nsFrameList&    aFrameList)
 {
-  NS_ASSERTION(aListID == kPrincipalList ||
-               aListID == kAbsoluteList, "unexpected child list ID");
-  NS_PRECONDITION(aListID != kAbsoluteList ||
-                  mFrames.IsEmpty(), "already have a child frame");
-  if (aListID != kPrincipalList) {
-    // We only support the Principal and Absolute child lists.
-    return NS_ERROR_INVALID_ARG;
-  }
-
-  if (!mFrames.IsEmpty()) {
-    // We only allow a single principal child frame.
-    return NS_ERROR_INVALID_ARG;
-  }
-
-  // Insert the new frames
-  NS_ASSERTION(aFrameList.FirstChild() == aFrameList.LastChild(),
-               "Only one principal child frame allowed");
-#ifdef DEBUG
+  MOZ_ASSERT(aListID == kPrincipalList, "unexpected child list");
+  MOZ_ASSERT(mFrames.IsEmpty(), "already have a child frame");
+  MOZ_ASSERT(aFrameList.FirstChild() == aFrameList.LastChild(),
+             "Only one principal child frame allowed");
   nsFrame::VerifyDirtyBitSet(aFrameList);
-#endif
-  mFrames.AppendFrames(nullptr, aFrameList);
-
-  PresContext()->PresShell()->
-    FrameNeedsReflow(this, nsIPresShell::eTreeChange,
-                     NS_FRAME_HAS_DIRTY_CHILDREN);
-
-  return NS_OK;
+  nsContainerFrame::AppendFrames(aListID, aFrameList);
 }
 
-nsresult
+void
 nsCanvasFrame::InsertFrames(ChildListID     aListID,
                             nsIFrame*       aPrevFrame,
                             nsFrameList&    aFrameList)
 {
   // Because we only support a single child frame inserting is the same
   // as appending
-  NS_PRECONDITION(!aPrevFrame, "unexpected previous sibling frame");
-  if (aPrevFrame)
-    return NS_ERROR_UNEXPECTED;
-
-  return AppendFrames(aListID, aFrameList);
+  MOZ_ASSERT(!aPrevFrame, "unexpected previous sibling frame");
+  AppendFrames(aListID, aFrameList);
 }
 
-nsresult
+void
 nsCanvasFrame::RemoveFrame(ChildListID     aListID,
                            nsIFrame*       aOldFrame)
 {
-  NS_ASSERTION(aListID == kPrincipalList ||
-               aListID == kAbsoluteList, "unexpected child list ID");
-  if (aListID != kPrincipalList && aListID != kAbsoluteList) {
-    // We only support the Principal and Absolute child lists.
-    return NS_ERROR_INVALID_ARG;
-  }
-
-  if (aOldFrame != mFrames.FirstChild())
-    return NS_ERROR_FAILURE;
-
-  // Remove the frame and destroy it
-  mFrames.DestroyFrame(aOldFrame);
-
-  PresContext()->PresShell()->
-    FrameNeedsReflow(this, nsIPresShell::eTreeChange,
-                     NS_FRAME_HAS_DIRTY_CHILDREN);
-  return NS_OK;
+  MOZ_ASSERT(aListID == kPrincipalList, "unexpected child list");
+  MOZ_ASSERT(aOldFrame == mFrames.FirstChild(), "unknown aOldFrame");
+  nsContainerFrame::RemoveFrame(aListID, aOldFrame);
 }
+#endif
 
 nsRect nsCanvasFrame::CanvasArea() const
 {
   // Not clear which overflow rect we want here, but it probably doesn't
   // matter.
   nsRect result(GetVisualOverflowRect());
 
   nsIScrollableFrame *scrollableFrame = do_QueryFrame(GetParent());
--- a/layout/generic/nsCanvasFrame.h
+++ b/layout/generic/nsCanvasFrame.h
@@ -35,25 +35,27 @@ public:
 
   NS_DECL_QUERYFRAME_TARGET(nsCanvasFrame)
   NS_DECL_QUERYFRAME
   NS_DECL_FRAMEARENA_HELPERS
 
 
   virtual void DestroyFrom(nsIFrame* aDestructRoot) MOZ_OVERRIDE;
 
-  virtual nsresult SetInitialChildList(ChildListID     aListID,
-                                       nsFrameList&    aChildList) MOZ_OVERRIDE;
-  virtual nsresult AppendFrames(ChildListID     aListID,
-                                nsFrameList&    aFrameList) MOZ_OVERRIDE;
-  virtual nsresult InsertFrames(ChildListID     aListID,
-                                nsIFrame*       aPrevFrame,
-                                nsFrameList&    aFrameList) MOZ_OVERRIDE;
-  virtual nsresult RemoveFrame(ChildListID     aListID,
-                               nsIFrame*       aOldFrame) MOZ_OVERRIDE;
+#ifdef DEBUG
+  virtual void SetInitialChildList(ChildListID     aListID,
+                                   nsFrameList&    aChildList) MOZ_OVERRIDE;
+  virtual void AppendFrames(ChildListID     aListID,
+                            nsFrameList&    aFrameList) MOZ_OVERRIDE;
+  virtual void InsertFrames(ChildListID     aListID,
+                            nsIFrame*       aPrevFrame,
+                            nsFrameList&    aFrameList) MOZ_OVERRIDE;
+  virtual void RemoveFrame(ChildListID     aListID,
+                           nsIFrame*       aOldFrame) MOZ_OVERRIDE;
+#endif
 
   virtual nscoord GetMinWidth(nsRenderingContext *aRenderingContext) MOZ_OVERRIDE;
   virtual nscoord GetPrefWidth(nsRenderingContext *aRenderingContext) MOZ_OVERRIDE;
   virtual void Reflow(nsPresContext*           aPresContext,
                       nsHTMLReflowMetrics&     aDesiredSize,
                       const nsHTMLReflowState& aReflowState,
                       nsReflowStatus&          aStatus) MOZ_OVERRIDE;
   virtual bool IsFrameOfType(uint32_t aFlags) const MOZ_OVERRIDE
--- a/layout/generic/nsColumnSetFrame.cpp
+++ b/layout/generic/nsColumnSetFrame.cpp
@@ -115,32 +115,16 @@ nsColumnSetFrame::PaintColumnRule(nsRend
         // Remember, we only have the "left" "border". Skip everything else
         (1 << NS_SIDE_TOP | 1 << NS_SIDE_RIGHT | 1 << NS_SIDE_BOTTOM));
 
     child = nextSibling;
     nextSibling = nextSibling->GetNextSibling();
   }
 }
 
-nsresult
-nsColumnSetFrame::SetInitialChildList(ChildListID     aListID,
-                                      nsFrameList&    aChildList)
-{
-  if (aListID == kAbsoluteList) {
-    return nsContainerFrame::SetInitialChildList(aListID, aChildList);
-  }
-
-  NS_ASSERTION(aListID == kPrincipalList,
-               "Only default child list supported");
-  NS_ASSERTION(aChildList.OnlyChild(),
-               "initial child list must have exaisRevertingctly one child");
-  // Queue up the frames for the content frame
-  return nsContainerFrame::SetInitialChildList(kPrincipalList, aChildList);
-}
-
 static nscoord
 GetAvailableContentWidth(const nsHTMLReflowState& aReflowState)
 {
   if (aReflowState.AvailableWidth() == NS_INTRINSICSIZE) {
     return NS_INTRINSICSIZE;
   }
   nscoord borderPaddingWidth =
     aReflowState.ComputedPhysicalBorderPadding().left +
@@ -1034,44 +1018,41 @@ nsColumnSetFrame::BuildDisplayList(nsDis
   }
 
   // Our children won't have backgrounds so it doesn't matter where we put them.
   for (nsFrameList::Enumerator e(mFrames); !e.AtEnd(); e.Next()) {
     BuildDisplayListForChild(aBuilder, e.get(), aDirtyRect, aLists);
   }
 }
 
-nsresult
+#ifdef DEBUG
+void
+nsColumnSetFrame::SetInitialChildList(ChildListID     aListID,
+                                      nsFrameList&    aChildList)
+{
+  MOZ_ASSERT(aListID == kPrincipalList, "unexpected child list");
+  MOZ_ASSERT(aChildList.OnlyChild(),
+             "initial child list must have exactly one child");
+  nsContainerFrame::SetInitialChildList(kPrincipalList, aChildList);
+}
+
+void
 nsColumnSetFrame::AppendFrames(ChildListID     aListID,
                                nsFrameList&    aFrameList)
 {
-  if (aListID == kAbsoluteList) {
-    return nsContainerFrame::AppendFrames(aListID, aFrameList);
-  }
-
-  NS_ERROR("unexpected child list");
-  return NS_ERROR_INVALID_ARG;
+  MOZ_CRASH("unsupported operation");
 }
 
-nsresult
+void
 nsColumnSetFrame::InsertFrames(ChildListID     aListID,
                                nsIFrame*       aPrevFrame,
                                nsFrameList&    aFrameList)
 {
-  if (aListID == kAbsoluteList) {
-    return nsContainerFrame::InsertFrames(aListID, aPrevFrame, aFrameList);
-  }
-
-  NS_ERROR("unexpected child list");
-  return NS_ERROR_INVALID_ARG;
+  MOZ_CRASH("unsupported operation");
 }
 
-nsresult
+void
 nsColumnSetFrame::RemoveFrame(ChildListID     aListID,
                               nsIFrame*       aOldFrame)
 {
-  if (aListID == kAbsoluteList) {
-    return nsContainerFrame::RemoveFrame(aListID, aOldFrame);
-  }
-
-  NS_ERROR("unexpected child list");
-  return NS_ERROR_INVALID_ARG;
+  MOZ_CRASH("unsupported operation");
 }
+#endif
--- a/layout/generic/nsColumnSetFrame.h
+++ b/layout/generic/nsColumnSetFrame.h
@@ -9,31 +9,32 @@
 #include "nsContainerFrame.h"
 
 class nsColumnSetFrame : public nsContainerFrame {
 public:
   NS_DECL_FRAMEARENA_HELPERS
 
   nsColumnSetFrame(nsStyleContext* aContext);
 
-  virtual nsresult SetInitialChildList(ChildListID     aListID,
-                                       nsFrameList&    aChildList) MOZ_OVERRIDE;
-
   virtual void Reflow(nsPresContext* aPresContext,
                       nsHTMLReflowMetrics& aDesiredSize,
                       const nsHTMLReflowState& aReflowState,
                       nsReflowStatus& aStatus) MOZ_OVERRIDE;
 
-  virtual nsresult  AppendFrames(ChildListID     aListID,
-                                 nsFrameList&    aFrameList) MOZ_OVERRIDE;
-  virtual nsresult  InsertFrames(ChildListID     aListID,
-                                 nsIFrame*       aPrevFrame,
-                                 nsFrameList&    aFrameList) MOZ_OVERRIDE;
-  virtual nsresult  RemoveFrame(ChildListID     aListID,
-                                nsIFrame*       aOldFrame) MOZ_OVERRIDE;
+#ifdef DEBUG
+  virtual void SetInitialChildList(ChildListID     aListID,
+                                   nsFrameList&    aChildList) MOZ_OVERRIDE;
+  virtual void AppendFrames(ChildListID     aListID,
+                            nsFrameList&    aFrameList) MOZ_OVERRIDE;
+  virtual void InsertFrames(ChildListID     aListID,
+                            nsIFrame*       aPrevFrame,
+                            nsFrameList&    aFrameList) MOZ_OVERRIDE;
+  virtual void RemoveFrame(ChildListID     aListID,
+                           nsIFrame*       aOldFrame) MOZ_OVERRIDE;
+#endif
 
   virtual nscoord GetMinWidth(nsRenderingContext *aRenderingContext) MOZ_OVERRIDE;
   virtual nscoord GetPrefWidth(nsRenderingContext *aRenderingContext) MOZ_OVERRIDE;
 
   /**
    * Retrieve the available height for content of this frame. The available content
    * height is the available height for the frame, minus borders and padding.
    */
--- a/layout/generic/nsContainerFrame.cpp
+++ b/layout/generic/nsContainerFrame.cpp
@@ -62,105 +62,77 @@ nsContainerFrame::Init(nsIContent*      
     // Make sure we copy bits from our prev-in-flow that will affect
     // us. A continuation for a container frame needs to know if it
     // has a child with a view so that we'll properly reposition it.
     if (aPrevInFlow->GetStateBits() & NS_FRAME_HAS_CHILD_WITH_VIEW)
       AddStateBits(NS_FRAME_HAS_CHILD_WITH_VIEW);
   }
 }
 
-nsresult
+void
 nsContainerFrame::SetInitialChildList(ChildListID  aListID,
                                       nsFrameList& aChildList)
 {
-  nsresult  result;
-  if (mFrames.NotEmpty()) {
-    // We already have child frames which means we've already been
-    // initialized
-    NS_NOTREACHED("unexpected second call to SetInitialChildList");
-    result = NS_ERROR_UNEXPECTED;
-  } else if (aListID != kPrincipalList) {
-    // All we know about is the principal child list.
-    NS_NOTREACHED("unknown frame list");
-    result = NS_ERROR_INVALID_ARG;
-  } else {
+  MOZ_ASSERT(mFrames.IsEmpty(),
+             "unexpected second call to SetInitialChildList");
+  MOZ_ASSERT(aListID == kPrincipalList, "unexpected child list");
 #ifdef DEBUG
-    nsFrame::VerifyDirtyBitSet(aChildList);
+  nsFrame::VerifyDirtyBitSet(aChildList);
 #endif
-    mFrames.SetFrames(aChildList);
-    result = NS_OK;
-  }
-  return result;
+  mFrames.SetFrames(aChildList);
 }
 
-nsresult
+void
 nsContainerFrame::AppendFrames(ChildListID  aListID,
                                nsFrameList& aFrameList)
 {
-  if (aListID != kPrincipalList) {
-    if (aListID != kNoReflowPrincipalList)
-    {
-      NS_ERROR("unexpected child list");
-      return NS_ERROR_INVALID_ARG;
-    }
-  }
+  MOZ_ASSERT(aListID == kPrincipalList || aListID == kNoReflowPrincipalList,
+             "unexpected child list");
   if (aFrameList.NotEmpty()) {
     mFrames.AppendFrames(this, aFrameList);
 
     // Ask the parent frame to reflow me.
     if (aListID == kPrincipalList)
     {
       PresContext()->PresShell()->
         FrameNeedsReflow(this, nsIPresShell::eTreeChange,
                          NS_FRAME_HAS_DIRTY_CHILDREN);
     }
   }
-  return NS_OK;
 }
 
-nsresult
+void
 nsContainerFrame::InsertFrames(ChildListID aListID,
                                nsIFrame* aPrevFrame,
                                nsFrameList& aFrameList)
 {
+  MOZ_ASSERT(aListID == kPrincipalList || aListID == kNoReflowPrincipalList,
+             "unexpected child list");
   NS_ASSERTION(!aPrevFrame || aPrevFrame->GetParent() == this,
                "inserting after sibling frame with different parent");
 
-  if (aListID != kPrincipalList) {
-    if (aListID != kNoReflowPrincipalList)
-    {
-      NS_ERROR("unexpected child list");
-      return NS_ERROR_INVALID_ARG;
-    }
-  }
   if (aFrameList.NotEmpty()) {
     // Insert frames after aPrevFrame
     mFrames.InsertFrames(this, aPrevFrame, aFrameList);
 
     if (aListID == kPrincipalList)
     {
       PresContext()->PresShell()->
         FrameNeedsReflow(this, nsIPresShell::eTreeChange,
                          NS_FRAME_HAS_DIRTY_CHILDREN);
     }
   }
-  return NS_OK;
 }
 
-nsresult
+void
 nsContainerFrame::RemoveFrame(ChildListID aListID,
                               nsIFrame* aOldFrame)
 {
-  if (aListID != kPrincipalList) {
-    if (kNoReflowPrincipalList != aListID)
-    {
-      NS_ERROR("unexpected child list");
-      return NS_ERROR_INVALID_ARG;
-    }
-  }
+  MOZ_ASSERT(aListID == kPrincipalList || aListID == kNoReflowPrincipalList,
+             "unexpected child list");
 
   // Loop and destroy aOldFrame and all of its continuations.
   // Request a reflow on the parent frames involved unless we were explicitly
   // told not to (kNoReflowPrincipalList).
   bool generateReflowCommand = true;
   if (kNoReflowPrincipalList == aListID) {
     generateReflowCommand = false;
   }
@@ -177,17 +149,16 @@ nsContainerFrame::RemoveFrame(ChildListI
     aOldFrame->Destroy();
     aOldFrame = oldFrameNextContinuation;
     if (parent != lastParent && generateReflowCommand) {
       shell->FrameNeedsReflow(parent, nsIPresShell::eTreeChange,
                               NS_FRAME_HAS_DIRTY_CHILDREN);
       lastParent = parent;
     }
   }
-  return NS_OK;
 }
 
 void
 nsContainerFrame::DestroyAbsoluteFrames(nsIFrame* aDestructRoot)
 {
   if (IsAbsoluteContainer()) {
     GetAbsoluteContainingBlock()->DestroyFrames(this, aDestructRoot);
     MarkAsNotAbsoluteContainingBlock();
--- a/layout/generic/nsContainerFrame.h
+++ b/layout/generic/nsContainerFrame.h
@@ -80,81 +80,56 @@ public:
    * This is only called once for a given child list, and won't be called
    * at all for child lists with no initial list of frames.
    *
    * @param   aListID the child list identifier.
    * @param   aChildList list of child frames. Each of the frames has its
    *            NS_FRAME_IS_DIRTY bit set.  Must not be empty.
    *            This method cannot handle the child list returned by
    *            GetAbsoluteListID().
-   * @return  NS_ERROR_INVALID_ARG if there is no child list with the specified
-   *            name,
-   *          NS_ERROR_UNEXPECTED if the frame is an atomic frame or if the
-   *            initial list of frames has already been set for that child list,
-   *          NS_OK otherwise.  In this case, SetInitialChildList empties out
-   *            aChildList in the process of moving the frames over to its own
-   *            child list.
    * @see     #Init()
    */
-  virtual nsresult SetInitialChildList(ChildListID aListID,
-                                       nsFrameList& aChildList);
+  virtual void SetInitialChildList(ChildListID aListID,
+                                   nsFrameList& aChildList);
 
   /**
    * This method is responsible for appending frames to the frame
    * list.  The implementation should append the frames to the specified
    * child list and then generate a reflow command.
    *
    * @param   aListID the child list identifier.
    * @param   aFrameList list of child frames to append. Each of the frames has
    *            its NS_FRAME_IS_DIRTY bit set.  Must not be empty.
-   * @return  NS_ERROR_INVALID_ARG if there is no child list with the specified
-   *            name,
-   *          NS_ERROR_UNEXPECTED if the frame is an atomic frame,
-   *          NS_OK otherwise.  In this case, AppendFrames empties out
-   *            aFrameList in the process of moving the frames over to its own
-   *            child list.
    */
-  virtual nsresult AppendFrames(ChildListID aListID, nsFrameList& aFrameList);
+  virtual void AppendFrames(ChildListID aListID, nsFrameList& aFrameList);
 
   /**
    * This method is responsible for inserting frames into the frame
    * list.  The implementation should insert the new frames into the specified
    * child list and then generate a reflow command.
    *
    * @param   aListID the child list identifier.
    * @param   aPrevFrame the frame to insert frames <b>after</b>
    * @param   aFrameList list of child frames to insert <b>after</b> aPrevFrame.
    *            Each of the frames has its NS_FRAME_IS_DIRTY bit set
-   * @return  NS_ERROR_INVALID_ARG if there is no child list with the specified
-   *            name,
-   *          NS_ERROR_UNEXPECTED if the frame is an atomic frame,
-   *          NS_OK otherwise.  In this case, InsertFrames empties out
-   *            aFrameList in the process of moving the frames over to its own
-   *            child list.
    */
-  virtual nsresult InsertFrames(ChildListID  aListID,
-                                nsIFrame*    aPrevFrame,
-                                nsFrameList& aFrameList);
+  virtual void InsertFrames(ChildListID  aListID,
+                            nsIFrame*    aPrevFrame,
+                            nsFrameList& aFrameList);
 
   /**
    * This method is responsible for removing a frame in the frame
    * list.  The implementation should do something with the removed frame
    * and then generate a reflow command. The implementation is responsible
    * for destroying aOldFrame (the caller mustn't destroy aOldFrame).
    *
    * @param   aListID the child list identifier.
    * @param   aOldFrame the frame to remove
-   * @return  NS_ERROR_INVALID_ARG if there is no child list with the specified
-   *            name,
-   *          NS_ERROR_FAILURE if the child frame is not in the specified
-   *            child list,
-   *          NS_ERROR_UNEXPECTED if the frame is an atomic frame,
-   *          NS_OK otherwise
    */
-  virtual nsresult RemoveFrame(ChildListID aListID, nsIFrame* aOldFrame);
+  virtual void RemoveFrame(ChildListID aListID, nsIFrame* aOldFrame);
 
   /**
    * Helper method to create next-in-flows if necessary. If aFrame
    * already has a next-in-flow then this method does
    * nothing. Otherwise, a new continuation frame is created and
    * linked into the flow. In addition, the new frame is inserted
    * into the principal child list after aFrame.
    * @note calling this method on a block frame is illegal. Use
--- a/layout/generic/nsFirstLetterFrame.cpp
+++ b/layout/generic/nsFirstLetterFrame.cpp
@@ -71,30 +71,29 @@ nsFirstLetterFrame::Init(nsIContent*    
         ResolveStyleForNonElement(parentStyleContext);
       SetStyleContextWithoutNotification(newSC);
     }
   }
 
   nsContainerFrame::Init(aContent, aParent, aPrevInFlow);
 }
 
-nsresult
+void
 nsFirstLetterFrame::SetInitialChildList(ChildListID  aListID,
                                         nsFrameList& aChildList)
 {
   RestyleManager* restyleManager = PresContext()->RestyleManager();
 
   for (nsFrameList::Enumerator e(aChildList); !e.AtEnd(); e.Next()) {
     NS_ASSERTION(e.get()->GetParent() == this, "Unexpected parent");
     restyleManager->ReparentStyleContext(e.get());
     nsLayoutUtils::MarkDescendantsDirty(e.get());
   }
 
   mFrames.SetFrames(aChildList);
-  return NS_OK;
 }
 
 nsresult
 nsFirstLetterFrame::GetChildFrameContainingOffset(int32_t inContentOffset,
                                                   bool inHint,
                                                   int32_t* outFrameContentOffset,
                                                   nsIFrame **outChildFrame)
 {
@@ -292,17 +291,16 @@ nsFirstLetterFrame::CreateContinuationFo
                                                         nsIFrame** aContinuation,
                                                         bool aIsFluid)
 {
   NS_ASSERTION(IsFloating(),
                "can only call this on floating first letter frames");
   NS_PRECONDITION(aContinuation, "bad args");
 
   *aContinuation = nullptr;
-  nsresult rv = NS_OK;
 
   nsIPresShell* presShell = aPresContext->PresShell();
   nsPlaceholderFrame* placeholderFrame =
     presShell->FrameManager()->GetPlaceholderFrameFor(this);
   nsContainerFrame* parent = placeholderFrame->GetParent();
 
   nsIFrame* continuation = presShell->FrameConstructor()->
     CreateContinuingFrame(aPresContext, aChild, parent, aIsFluid);
@@ -318,20 +316,20 @@ nsFirstLetterFrame::CreateContinuationFo
     nsLayoutUtils::MarkDescendantsDirty(continuation);
   }
 
   //XXX Bidi may not be involved but we have to use the list name
   // kNoReflowPrincipalList because this is just like creating a continuation
   // except we have to insert it in a different place and we don't want a
   // reflow command to try to be issued.
   nsFrameList temp(continuation, continuation);
-  rv = parent->InsertFrames(kNoReflowPrincipalList, placeholderFrame, temp);
+  parent->InsertFrames(kNoReflowPrincipalList, placeholderFrame, temp);
 
   *aContinuation = continuation;
-  return rv;
+  return NS_OK;
 }
 
 void
 nsFirstLetterFrame::DrainOverflowFrames(nsPresContext* aPresContext)
 {
   // Check for an overflow list with our prev-in-flow
   nsFirstLetterFrame* prevInFlow = (nsFirstLetterFrame*)GetPrevInFlow();
   if (prevInFlow) {
--- a/layout/generic/nsFirstLetterFrame.h
+++ b/layout/generic/nsFirstLetterFrame.h
@@ -21,18 +21,18 @@ public:
 
   virtual void BuildDisplayList(nsDisplayListBuilder*   aBuilder,
                                 const nsRect&           aDirtyRect,
                                 const nsDisplayListSet& aLists) MOZ_OVERRIDE;
 
   virtual void Init(nsIContent*       aContent,
                     nsContainerFrame* aParent,
                     nsIFrame*         aPrevInFlow) MOZ_OVERRIDE;
-  virtual nsresult SetInitialChildList(ChildListID     aListID,
-                                       nsFrameList&    aChildList) MOZ_OVERRIDE;
+  virtual void SetInitialChildList(ChildListID     aListID,
+                                   nsFrameList&    aChildList) MOZ_OVERRIDE;
 #ifdef DEBUG_FRAME_DUMP
   virtual nsresult GetFrameName(nsAString& aResult) const MOZ_OVERRIDE;
 #endif
   virtual nsIAtom* GetType() const MOZ_OVERRIDE;
 
   bool IsFloating() const { return GetStateBits() & NS_FRAME_OUT_OF_FLOW; }
 
   virtual bool IsFrameOfType(uint32_t aFlags) const MOZ_OVERRIDE
--- a/layout/generic/nsFrameSetFrame.cpp
+++ b/layout/generic/nsFrameSetFrame.cpp
@@ -387,29 +387,29 @@ nsHTMLFramesetFrame::Init(nsIContent*   
 
     mChildBorderColors[mChildCount].Set(NO_COLOR);
     mChildCount++;
   }
 
   mNonBorderChildCount = mChildCount;
 }
 
-nsresult
+void
 nsHTMLFramesetFrame::SetInitialChildList(ChildListID  aListID,
                                          nsFrameList& aChildList)
 {
   // We do this weirdness where we create our child frames in Init().  On the
   // other hand, we're going to get a SetInitialChildList() with an empty list
   // and null list name after the frame constructor is done creating us.  So
   // just ignore that call.
   if (aListID == kPrincipalList && aChildList.IsEmpty()) {
-    return NS_OK;
+    return;
   }
 
-  return nsContainerFrame::SetInitialChildList(aListID, aChildList);
+  nsContainerFrame::SetInitialChildList(aListID, aChildList);
 }
 
 // XXX should this try to allocate twips based on an even pixel boundary?
 void nsHTMLFramesetFrame::Scale(nscoord  aDesired,
                                 int32_t  aNumIndicies,
                                 int32_t* aIndicies,
                                 int32_t  aNumItems,
                                 int32_t* aItems)
--- a/layout/generic/nsFrameSetFrame.h
+++ b/layout/generic/nsFrameSetFrame.h
@@ -71,18 +71,18 @@ public:
   nsHTMLFramesetFrame(nsStyleContext* aContext);
 
   virtual ~nsHTMLFramesetFrame();
 
   virtual void Init(nsIContent*       aContent,
                     nsContainerFrame* aParent,
                     nsIFrame*         aPrevInFlow) MOZ_OVERRIDE;
 
-  virtual nsresult SetInitialChildList(ChildListID  aListID,
-                                       nsFrameList& aChildList) MOZ_OVERRIDE;
+  virtual void SetInitialChildList(ChildListID  aListID,
+                                   nsFrameList& aChildList) MOZ_OVERRIDE;
 
   static bool    gDragInProgress;
 
   void GetSizeOfChild(nsIFrame* aChild, nsSize& aSize);
 
   void GetSizeOfChildAt(int32_t  aIndexInParent, 
                         nsSize&  aSize, 
                         nsIntPoint& aCellIndex);
--- a/layout/generic/nsGfxScrollFrame.cpp
+++ b/layout/generic/nsGfxScrollFrame.cpp
@@ -111,57 +111,53 @@ nsHTMLScrollFrame::AppendAnonymousConten
 void
 nsHTMLScrollFrame::DestroyFrom(nsIFrame* aDestructRoot)
 {
   DestroyAbsoluteFrames(aDestructRoot);
   mHelper.Destroy();
   nsContainerFrame::DestroyFrom(aDestructRoot);
 }
 
-nsresult
+void
 nsHTMLScrollFrame::SetInitialChildList(ChildListID  aListID,
                                        nsFrameList& aChildList)
 {
-  nsresult rv = nsContainerFrame::SetInitialChildList(aListID, aChildList);
+  nsContainerFrame::SetInitialChildList(aListID, aChildList);
   mHelper.ReloadChildFrames();
-  return rv;
 }
 
 
-nsresult
+void
 nsHTMLScrollFrame::AppendFrames(ChildListID  aListID,
                                 nsFrameList& aFrameList)
 {
   NS_ASSERTION(aListID == kPrincipalList, "Only main list supported");
   mFrames.AppendFrames(nullptr, aFrameList);
   mHelper.ReloadChildFrames();
-  return NS_OK;
 }
 
-nsresult
+void
 nsHTMLScrollFrame::InsertFrames(ChildListID aListID,
                                 nsIFrame* aPrevFrame,
                                 nsFrameList& aFrameList)
 {
   NS_ASSERTION(aListID == kPrincipalList, "Only main list supported");
   NS_ASSERTION(!aPrevFrame || aPrevFrame->GetParent() == this,
                "inserting after sibling frame with different parent");
   mFrames.InsertFrames(nullptr, aPrevFrame, aFrameList);
   mHelper.ReloadChildFrames();
-  return NS_OK;
 }
 
-nsresult
+void
 nsHTMLScrollFrame::RemoveFrame(ChildListID aListID,
                                nsIFrame* aOldFrame)
 {
   NS_ASSERTION(aListID == kPrincipalList, "Only main list supported");
   mFrames.DestroyFrame(aOldFrame);
   mHelper.ReloadChildFrames();
-  return NS_OK;
 }
 
 nsSplittableType
 nsHTMLScrollFrame::GetSplittableType() const
 {
   return NS_FRAME_NOT_SPLITTABLE;
 }
 
@@ -1059,52 +1055,48 @@ nsXULScrollFrame::AppendAnonymousContent
 
 void
 nsXULScrollFrame::DestroyFrom(nsIFrame* aDestructRoot)
 {
   mHelper.Destroy();
   nsBoxFrame::DestroyFrom(aDestructRoot);
 }
 
-nsresult
+void
 nsXULScrollFrame::SetInitialChildList(ChildListID     aListID,
                                       nsFrameList&    aChildList)
 {
-  nsresult rv = nsBoxFrame::SetInitialChildList(aListID, aChildList);
+  nsBoxFrame::SetInitialChildList(aListID, aChildList);
   mHelper.ReloadChildFrames();
-  return rv;
 }
 
 
-nsresult
+void
 nsXULScrollFrame::AppendFrames(ChildListID     aListID,
                                nsFrameList&    aFrameList)
 {
-  nsresult rv = nsBoxFrame::AppendFrames(aListID, aFrameList);
+  nsBoxFrame::AppendFrames(aListID, aFrameList);
   mHelper.ReloadChildFrames();
-  return rv;
 }
 
-nsresult
+void
 nsXULScrollFrame::InsertFrames(ChildListID     aListID,
                                nsIFrame*       aPrevFrame,
                                nsFrameList&    aFrameList)
 {
-  nsresult rv = nsBoxFrame::InsertFrames(aListID, aPrevFrame, aFrameList);
+  nsBoxFrame::InsertFrames(aListID, aPrevFrame, aFrameList);
   mHelper.ReloadChildFrames();
-  return rv;
 }
 
-nsresult
+void
 nsXULScrollFrame::RemoveFrame(ChildListID     aListID,
                               nsIFrame*       aOldFrame)
 {
-  nsresult rv = nsBoxFrame::RemoveFrame(aListID, aOldFrame);
+  nsBoxFrame::RemoveFrame(aListID, aOldFrame);
   mHelper.ReloadChildFrames();
-  return rv;
 }
 
 nsSplittableType
 nsXULScrollFrame::GetSplittableType() const
 {
   return NS_FRAME_NOT_SPLITTABLE;
 }
 
--- a/layout/generic/nsGfxScrollFrame.h
+++ b/layout/generic/nsGfxScrollFrame.h
@@ -452,21 +452,16 @@ public:
   typedef mozilla::CSSIntPoint CSSIntPoint;
   friend nsHTMLScrollFrame* NS_NewHTMLScrollFrame(nsIPresShell* aPresShell,
                                                   nsStyleContext* aContext,
                                                   bool aIsRoot);
 
   NS_DECL_QUERYFRAME
   NS_DECL_FRAMEARENA_HELPERS
 
-  // Called to set the child frames. We typically have three: the scroll area,
-  // the vertical scrollbar, and the horizontal scrollbar.
-  virtual nsresult SetInitialChildList(ChildListID     aListID,
-                                       nsFrameList&    aChildList) MOZ_OVERRIDE;
-
   virtual void BuildDisplayList(nsDisplayListBuilder*   aBuilder,
                                 const nsRect&           aDirtyRect,
                                 const nsDisplayListSet& aLists) MOZ_OVERRIDE {
     mHelper.BuildDisplayList(aBuilder, aDirtyRect, aLists);
   }
 
   bool TryLayout(ScrollReflowState* aState,
                    nsHTMLReflowMetrics* aKidMetrics,
@@ -498,30 +493,30 @@ public:
                       nsHTMLReflowMetrics&     aDesiredSize,
                       const nsHTMLReflowState& aReflowState,
                       nsReflowStatus&          aStatus) MOZ_OVERRIDE;
 
   virtual bool UpdateOverflow() MOZ_OVERRIDE {
     return mHelper.UpdateOverflow();
   }
 
-  // Because there can be only one child frame, these two function return
-  // NS_ERROR_FAILURE
-  virtual nsresult AppendFrames(ChildListID     aListID,
-                                nsFrameList&    aFrameList) MOZ_OVERRIDE;
-  virtual nsresult InsertFrames(ChildListID     aListID,
-                                nsIFrame*       aPrevFrame,
-                                nsFrameList&    aFrameList) MOZ_OVERRIDE;
+  // Called to set the child frames. We typically have three: the scroll area,
+  // the vertical scrollbar, and the horizontal scrollbar.
+  virtual void SetInitialChildList(ChildListID     aListID,
+                                   nsFrameList&    aChildList) MOZ_OVERRIDE;
+  virtual void AppendFrames(ChildListID     aListID,
+                            nsFrameList&    aFrameList) MOZ_OVERRIDE;
+  virtual void InsertFrames(ChildListID     aListID,
+                            nsIFrame*       aPrevFrame,
+                            nsFrameList&    aFrameList) MOZ_OVERRIDE;
+  virtual void RemoveFrame(ChildListID     aListID,
+                           nsIFrame*       aOldFrame) MOZ_OVERRIDE;
 
   virtual void DestroyFrom(nsIFrame* aDestructRoot) MOZ_OVERRIDE;
 
-
-  virtual nsresult RemoveFrame(ChildListID     aListID,
-                               nsIFrame*       aOldFrame) MOZ_OVERRIDE;
-
   virtual nsIScrollableFrame* GetScrollTargetFrame() MOZ_OVERRIDE {
     return this;
   }
 
   virtual nsContainerFrame* GetContentInsertionFrame() MOZ_OVERRIDE {
     return mHelper.GetScrolledFrame()->GetContentInsertionFrame();
   }
 
@@ -764,48 +759,45 @@ public:
   NS_DECL_QUERYFRAME
   NS_DECL_FRAMEARENA_HELPERS
 
   friend nsXULScrollFrame* NS_NewXULScrollFrame(nsIPresShell* aPresShell,
                                                 nsStyleContext* aContext,
                                                 bool aIsRoot,
                                                 bool aClipAllDescendants);
 
-  // Called to set the child frames. We typically have three: the scroll area,
-  // the vertical scrollbar, and the horizontal scrollbar.
-  virtual nsresult SetInitialChildList(ChildListID     aListID,
-                                       nsFrameList&    aChildList) MOZ_OVERRIDE;
-
   virtual void BuildDisplayList(nsDisplayListBuilder*   aBuilder,
                                 const nsRect&           aDirtyRect,
                                 const nsDisplayListSet& aLists) MOZ_OVERRIDE {
     mHelper.BuildDisplayList(aBuilder, aDirtyRect, aLists);
   }
 
   // XXXldb Is this actually used?
 #if 0
   virtual nscoord GetMinWidth(nsRenderingContext *aRenderingContext) MOZ_OVERRIDE;
 #endif
 
   virtual bool UpdateOverflow() MOZ_OVERRIDE {
     return mHelper.UpdateOverflow();
   }
 
-  // Because there can be only one child frame, these two function return
-  // NS_ERROR_FAILURE
-  virtual nsresult AppendFrames(ChildListID     aListID,
-                                nsFrameList&    aFrameList) MOZ_OVERRIDE;
-  virtual nsresult InsertFrames(ChildListID     aListID,
-                                nsIFrame*       aPrevFrame,
-                                nsFrameList&    aFrameList) MOZ_OVERRIDE;
+  // Called to set the child frames. We typically have three: the scroll area,
+  // the vertical scrollbar, and the horizontal scrollbar.
+  virtual void SetInitialChildList(ChildListID     aListID,
+                                   nsFrameList&    aChildList) MOZ_OVERRIDE;
+  virtual void AppendFrames(ChildListID     aListID,
+                            nsFrameList&    aFrameList) MOZ_OVERRIDE;
+  virtual void InsertFrames(ChildListID     aListID,
+                            nsIFrame*       aPrevFrame,
+                            nsFrameList&    aFrameList) MOZ_OVERRIDE;
+  virtual void RemoveFrame(ChildListID     aListID,
+                           nsIFrame*       aOldFrame) MOZ_OVERRIDE;
 
   virtual void DestroyFrom(nsIFrame* aDestructRoot) MOZ_OVERRIDE;
 
-  virtual nsresult RemoveFrame(ChildListID     aListID,
-                               nsIFrame*       aOldFrame) MOZ_OVERRIDE;
 
   virtual nsIScrollableFrame* GetScrollTargetFrame() MOZ_OVERRIDE {
     return this;
   }
 
   virtual nsContainerFrame* GetContentInsertionFrame() MOZ_OVERRIDE {
     return mHelper.GetScrolledFrame()->GetContentInsertionFrame();
   }
--- a/layout/generic/nsViewportFrame.cpp
+++ b/layout/generic/nsViewportFrame.cpp
@@ -38,74 +38,68 @@ ViewportFrame::Init(nsIContent*       aC
   nsIFrame* parent = nsLayoutUtils::GetCrossDocParentFrame(this);
   if (parent) {
     nsFrameState state = parent->GetStateBits();
 
     mState |= state & (NS_FRAME_IN_POPUP);
   }
 }
 
-nsresult
-ViewportFrame::SetInitialChildList(ChildListID     aListID,
-                                   nsFrameList&    aChildList)
-{
-  // See which child list to add the frames to
-#ifdef DEBUG
-  nsFrame::VerifyDirtyBitSet(aChildList);
-#endif
-  return nsContainerFrame::SetInitialChildList(aListID, aChildList);
-}
-
 void
 ViewportFrame::BuildDisplayList(nsDisplayListBuilder*   aBuilder,
                                 const nsRect&           aDirtyRect,
                                 const nsDisplayListSet& aLists)
 {
   PROFILER_LABEL("ViewportFrame", "BuildDisplayList");
   nsIFrame* kid = mFrames.FirstChild();
   if (!kid)
     return;
 
   // make the kid's BorderBackground our own. This ensures that the canvas
   // frame's background becomes our own background and therefore appears
   // below negative z-index elements.
   BuildDisplayListForChild(aBuilder, kid, aDirtyRect, aLists);
 }
 
-nsresult
+#ifdef DEBUG
+void
+ViewportFrame::SetInitialChildList(ChildListID     aListID,
+                                   nsFrameList&    aChildList)
+{
+  nsFrame::VerifyDirtyBitSet(aChildList);
+  nsContainerFrame::SetInitialChildList(aListID, aChildList);
+}
+
+void
 ViewportFrame::AppendFrames(ChildListID     aListID,
                             nsFrameList&    aFrameList)
 {
-  NS_ASSERTION(aListID == kPrincipalList ||
-               aListID == GetAbsoluteListID(), "unexpected child list");
-  NS_ASSERTION(aListID != GetAbsoluteListID() ||
-               GetChildList(aListID).IsEmpty(), "Shouldn't have any kids!");
-  return nsContainerFrame::AppendFrames(aListID, aFrameList);
+  NS_ASSERTION(aListID == kPrincipalList, "unexpected child list");
+  NS_ASSERTION(GetChildList(aListID).IsEmpty(), "Shouldn't have any kids!");
+  nsContainerFrame::AppendFrames(aListID, aFrameList);
 }
 
-nsresult
+void
 ViewportFrame::InsertFrames(ChildListID     aListID,
                             nsIFrame*       aPrevFrame,
                             nsFrameList&    aFrameList)
 {
-  NS_ASSERTION(aListID == kPrincipalList ||
-               aListID == GetAbsoluteListID(), "unexpected child list");
-  NS_ASSERTION(aListID != GetAbsoluteListID() ||
-               GetChildList(aListID).IsEmpty(), "Shouldn't have any kids!");
-  return nsContainerFrame::InsertFrames(aListID, aPrevFrame, aFrameList);
+  NS_ASSERTION(aListID == kPrincipalList, "unexpected child list");
+  NS_ASSERTION(GetChildList(aListID).IsEmpty(), "Shouldn't have any kids!");
+  nsContainerFrame::InsertFrames(aListID, aPrevFrame, aFrameList);
 }
 
-nsresult
+void
 ViewportFrame::RemoveFrame(ChildListID     aListID,
                            nsIFrame*       aOldFrame)
 {
-  NS_ASSERTION(aListID == kPrincipalList ||
-               aListID == GetAbsoluteListID(), "unexpected child list");
-  return nsContainerFrame::RemoveFrame(aListID, aOldFrame);
+  NS_ASSERTION(aListID == kPrincipalList, "unexpected child list");
+  nsContainerFrame::RemoveFrame(aListID, aOldFrame);
 }
+#endif
 
 /* virtual */ nscoord
 ViewportFrame::GetMinWidth(nsRenderingContext *aRenderingContext)
 {
   nscoord result;
   DISPLAY_MIN_WIDTH(this, result);
   if (mFrames.IsEmpty())
     result = 0;
--- a/layout/generic/nsViewportFrame.h
+++ b/layout/generic/nsViewportFrame.h
@@ -33,28 +33,27 @@ public:
     : nsContainerFrame(aContext)
   {}
   virtual ~ViewportFrame() { } // useful for debugging
 
   virtual void Init(nsIContent*       aContent,
                     nsContainerFrame* aParent,
                     nsIFrame*         aPrevInFlow) MOZ_OVERRIDE;
 
-  virtual nsresult SetInitialChildList(ChildListID     aListID,
-                                       nsFrameList&    aChildList) MOZ_OVERRIDE;
-
-  virtual nsresult AppendFrames(ChildListID     aListID,
-                                nsFrameList&    aFrameList) MOZ_OVERRIDE;
-
-  virtual nsresult InsertFrames(ChildListID     aListID,
-                                nsIFrame*       aPrevFrame,
-                                nsFrameList&    aFrameList) MOZ_OVERRIDE;
-
-  virtual nsresult RemoveFrame(ChildListID     aListID,
-                               nsIFrame*       aOldFrame) MOZ_OVERRIDE;
+#ifdef DEBUG
+  virtual void SetInitialChildList(ChildListID     aListID,
+                                   nsFrameList&    aChildList) MOZ_OVERRIDE;
+  virtual void AppendFrames(ChildListID     aListID,
+                            nsFrameList&    aFrameList) MOZ_OVERRIDE;
+  virtual void InsertFrames(ChildListID     aListID,
+                            nsIFrame*       aPrevFrame,
+                            nsFrameList&    aFrameList) MOZ_OVERRIDE;
+  virtual void RemoveFrame(ChildListID     aListID,
+                           nsIFrame*       aOldFrame) MOZ_OVERRIDE;
+#endif
 
   virtual void BuildDisplayList(nsDisplayListBuilder*   aBuilder,
                                 const nsRect&           aDirtyRect,
                                 const nsDisplayListSet& aLists) MOZ_OVERRIDE;
 
   virtual nscoord GetMinWidth(nsRenderingContext *aRenderingContext) MOZ_OVERRIDE;
   virtual nscoord GetPrefWidth(nsRenderingContext *aRenderingContext) MOZ_OVERRIDE;
   virtual void Reflow(nsPresContext*           aPresContext,
--- a/layout/generic/test/test_bug633762.html
+++ b/layout/generic/test/test_bug633762.html
@@ -30,18 +30,18 @@ function runTests() {
   doc.documentElement.offsetLeft;
   // click in middle of iframe document to give it focus
   synthesizeMouseAtCenter(i, {}, win);
   win.focus();
   // record scrolltop
   scrollTopBefore = doc.body.scrollTop;
   // send up arrow key event
   sendKey("UP");
-
-  setTimeout("finish();", 20);
+  
+  window.requestAnimationFrame(finish);
 }
 
 function finish() {
   // assert that scroll top is now less than before
   ok(scrollTopBefore > doc.body.scrollTop, "pressing up arrow should scroll up");
   SpecialPowers.clearUserPref(smoothScrollPref);
   SimpleTest.finish();
 }
--- a/layout/ipc/RenderFrameChild.cpp
+++ b/layout/ipc/RenderFrameChild.cpp
@@ -32,16 +32,21 @@ RenderFrameChild::Destroy()
   // WARNING: |this| is dead, hands off
 }
 
 PLayerTransactionChild*
 RenderFrameChild::AllocPLayerTransactionChild()
 {
   LayerTransactionChild* c = new LayerTransactionChild();
   c->AddIPDLReference();
+  // We only create PLayerTransaction objects through PRenderFrame when we don't
+  // have a PCompositor. This means that the child process content will never
+  // get drawn to the screen, but some tests rely on it pretending to function
+  // for now.
+  c->SetHasNoCompositor();
   return c;
 }
 
 bool
 RenderFrameChild::DeallocPLayerTransactionChild(PLayerTransactionChild* aLayers)
 {
   static_cast<LayerTransactionChild*>(aLayers)->ReleaseIPDLReference();
   return true;
--- a/layout/ipc/RenderFrameParent.cpp
+++ b/layout/ipc/RenderFrameParent.cpp
@@ -804,16 +804,17 @@ RenderFrameParent::ContentViewScaleChang
 {
   // Since the scale has changed for a view, it and its descendents need their
   // shadow-space attributes updated. It's easiest to rebuild the view map.
   BuildViewMap();
 }
 
 void
 RenderFrameParent::ShadowLayersUpdated(LayerTransactionParent* aLayerTree,
+                                       const uint64_t& aTransactionId,
                                        const TargetConfig& aTargetConfig,
                                        bool aIsFirstPaint,
                                        bool aScheduleComposite,
                                        uint32_t aPaintSequenceNumber)
 {
   // View map must only contain views that are associated with the current
   // shadow layer tree. We must always update the map when shadow layers
   // are updated.
--- a/layout/ipc/RenderFrameParent.h
+++ b/layout/ipc/RenderFrameParent.h
@@ -74,16 +74,17 @@ public:
    * @param aId The ID of the frame.
    */
   nsContentView* GetContentView(ViewID aId);
   nsContentView* GetRootContentView();
 
   void ContentViewScaleChanged(nsContentView* aView);
 
   virtual void ShadowLayersUpdated(LayerTransactionParent* aLayerTree,
+                                   const uint64_t& aTransactionId,
                                    const TargetConfig& aTargetConfig,
                                    bool aIsFirstPaint,
                                    bool aScheduleComposite,
                                    uint32_t aPaintSequenceNumber) MOZ_OVERRIDE;
 
   void BuildDisplayList(nsDisplayListBuilder* aBuilder,
                         nsSubDocumentFrame* aFrame,
                         const nsRect& aDirtyRect,
--- a/layout/mathml/nsMathMLContainerFrame.cpp
+++ b/layout/mathml/nsMathMLContainerFrame.cpp
@@ -730,50 +730,42 @@ nsMathMLContainerFrame::ChildListChanged
       GetEmbellishDataFrom(parent, embellishData);
       if (embellishData.coreFrame != mEmbellishData.coreFrame)
         break;
     }
   }
   return ReLayoutChildren(frame);
 }
 
-nsresult
+void
 nsMathMLContainerFrame::AppendFrames(ChildListID     aListID,
                                      nsFrameList&    aFrameList)
 {
-  if (aListID != kPrincipalList) {
-    return NS_ERROR_INVALID_ARG;
-  }
+  MOZ_ASSERT(aListID == kPrincipalList);
   mFrames.AppendFrames(this, aFrameList);
-  return ChildListChanged(nsIDOMMutationEvent::ADDITION);
+  ChildListChanged(nsIDOMMutationEvent::ADDITION);
 }
 
-nsresult
+void
 nsMathMLContainerFrame::InsertFrames(ChildListID     aListID,
                                      nsIFrame*       aPrevFrame,
                                      nsFrameList&    aFrameList)
 {
-  if (aListID != kPrincipalList) {
-    return NS_ERROR_INVALID_ARG;
-  }
-  // Insert frames after aPrevFrame
+  MOZ_ASSERT(aListID == kPrincipalList);
   mFrames.InsertFrames(this, aPrevFrame, aFrameList);
-  return ChildListChanged(nsIDOMMutationEvent::ADDITION);
+  ChildListChanged(nsIDOMMutationEvent::ADDITION);
 }
 
-nsresult
+void
 nsMathMLContainerFrame::RemoveFrame(ChildListID     aListID,
                                     nsIFrame*       aOldFrame)
 {
-  if (aListID != kPrincipalList) {
-    return NS_ERROR_INVALID_ARG;
-  }
-  // remove the child frame
+  MOZ_ASSERT(aListID == kPrincipalList);
   mFrames.DestroyFrame(aOldFrame);
-  return ChildListChanged(nsIDOMMutationEvent::REMOVAL);
+  ChildListChanged(nsIDOMMutationEvent::REMOVAL);
 }
 
 nsresult
 nsMathMLContainerFrame::AttributeChanged(int32_t         aNameSpaceID,
                                          nsIAtom*        aAttribute,
                                          int32_t         aModType)
 {
   // XXX Since they are numerous MathML attributes that affect layout, and
--- a/layout/mathml/nsMathMLContainerFrame.h
+++ b/layout/mathml/nsMathMLContainerFrame.h
@@ -74,26 +74,26 @@ public:
 
   virtual bool IsFrameOfType(uint32_t aFlags) const MOZ_OVERRIDE
   {
     return !(aFlags & nsIFrame::eLineParticipant) &&
       nsContainerFrame::IsFrameOfType(aFlags &
               ~(nsIFrame::eMathML | nsIFrame::eExcludesIgnorableWhitespace));
   }
 
-  virtual nsresult
+  virtual void
   AppendFrames(ChildListID     aListID,
                nsFrameList&    aFrameList) MOZ_OVERRIDE;
 
-  virtual nsresult
+  virtual void
   InsertFrames(ChildListID     aListID,
                nsIFrame*       aPrevFrame,
                nsFrameList&    aFrameList) MOZ_OVERRIDE;
 
-  virtual nsresult
+  virtual void
   RemoveFrame(ChildListID     aListID,
               nsIFrame*       aOldFrame) MOZ_OVERRIDE;
 
   /**
    * Both GetMinWidth and GetPrefWidth use the intrinsic width metrics
    * returned by GetIntrinsicMetrics, including ink overflow.
    */
   virtual nscoord GetMinWidth(nsRenderingContext *aRenderingContext) MOZ_OVERRIDE;
@@ -411,62 +411,58 @@ public:
   NS_DECL_QUERYFRAME
   NS_DECL_FRAMEARENA_HELPERS
 
   friend nsContainerFrame* NS_NewMathMLmathBlockFrame(nsIPresShell* aPresShell,
           nsStyleContext* aContext, nsFrameState aFlags);
 
   // beware, mFrames is not set by nsBlockFrame
   // cannot use mFrames{.FirstChild()|.etc} since the block code doesn't set mFrames
-  virtual nsresult
+  virtual void
   SetInitialChildList(ChildListID     aListID,
                       nsFrameList&    aChildList) MOZ_OVERRIDE
   {
     NS_ASSERTION(aListID == kPrincipalList, "unexpected frame list");
-    nsresult rv = nsBlockFrame::SetInitialChildList(aListID, aChildList);
+    nsBlockFrame::SetInitialChildList(aListID, aChildList);
     // re-resolve our subtree to set any mathml-expected data
     nsMathMLContainerFrame::RebuildAutomaticDataForChildren(this);
-    return rv;
   }
 
-  virtual nsresult
+  virtual void
   AppendFrames(ChildListID     aListID,
                nsFrameList&    aFrameList) MOZ_OVERRIDE
   {
     NS_ASSERTION(aListID == kPrincipalList || aListID == kNoReflowPrincipalList,
                  "unexpected frame list");
-    nsresult rv = nsBlockFrame::AppendFrames(aListID, aFrameList);
+    nsBlockFrame::AppendFrames(aListID, aFrameList);
     if (MOZ_LIKELY(aListID == kPrincipalList))
       nsMathMLContainerFrame::ReLayoutChildren(this);
-    return rv;
   }
 
-  virtual nsresult
+  virtual void
   InsertFrames(ChildListID     aListID,
                nsIFrame*       aPrevFrame,
                nsFrameList&    aFrameList) MOZ_OVERRIDE
   {
     NS_ASSERTION(aListID == kPrincipalList || aListID == kNoReflowPrincipalList,
                  "unexpected frame list");
-    nsresult rv = nsBlockFrame::InsertFrames(aListID, aPrevFrame, aFrameList);
+    nsBlockFrame::InsertFrames(aListID, aPrevFrame, aFrameList);
     if (MOZ_LIKELY(aListID == kPrincipalList))
       nsMathMLContainerFrame::ReLayoutChildren(this);
-    return rv;
   }
 
-  virtual nsresult
+  virtual void
   RemoveFrame(ChildListID     aListID,
               nsIFrame*       aOldFrame) MOZ_OVERRIDE
   {
     NS_ASSERTION(aListID == kPrincipalList || aListID == kNoReflowPrincipalList,
                  "unexpected frame list");
-    nsresult rv = nsBlockFrame::RemoveFrame(aListID, aOldFrame);
+    nsBlockFrame::RemoveFrame(aListID, aOldFrame);
     if (MOZ_LIKELY(aListID == kPrincipalList))
       nsMathMLContainerFrame::ReLayoutChildren(this);
-    return rv;
   }
 
   virtual bool IsFrameOfType(uint32_t aFlags) const MOZ_OVERRIDE {
     return nsBlockFrame::IsFrameOfType(aFlags &
               ~(nsIFrame::eMathML | nsIFrame::eExcludesIgnorableWhitespace));
   }
 
   // See nsIMathMLFrame.h
@@ -491,62 +487,58 @@ class nsMathMLmathInlineFrame : public n
 public:
   NS_DECL_QUERYFRAME_TARGET(nsMathMLmathInlineFrame)
   NS_DECL_QUERYFRAME
   NS_DECL_FRAMEARENA_HELPERS
 
   friend nsContainerFrame* NS_NewMathMLmathInlineFrame(nsIPresShell* aPresShell,
                                                        nsStyleContext* aContext);
 
-  virtual nsresult
+  virtual void
   SetInitialChildList(ChildListID     aListID,
                       nsFrameList&    aChildList) MOZ_OVERRIDE
   {
     NS_ASSERTION(aListID == kPrincipalList, "unexpected frame list");
-    nsresult rv = nsInlineFrame::SetInitialChildList(aListID, aChildList);
+    nsInlineFrame::SetInitialChildList(aListID, aChildList);
     // re-resolve our subtree to set any mathml-expected data
     nsMathMLContainerFrame::RebuildAutomaticDataForChildren(this);
-    return rv;
   }
 
-  virtual nsresult
+  virtual void
   AppendFrames(ChildListID     aListID,
                nsFrameList&    aFrameList) MOZ_OVERRIDE
   {
     NS_ASSERTION(aListID == kPrincipalList || aListID == kNoReflowPrincipalList,
                  "unexpected frame list");
-    nsresult rv = nsInlineFrame::AppendFrames(aListID, aFrameList);
+    nsInlineFrame::AppendFrames(aListID, aFrameList);
     if (MOZ_LIKELY(aListID == kPrincipalList))
       nsMathMLContainerFrame::ReLayoutChildren(this);
-    return rv;
   }
 
-  virtual nsresult
+  virtual void
   InsertFrames(ChildListID     aListID,
                nsIFrame*       aPrevFrame,
                nsFrameList&    aFrameList) MOZ_OVERRIDE
   {
     NS_ASSERTION(aListID == kPrincipalList || aListID == kNoReflowPrincipalList,
                  "unexpected frame list");
-    nsresult rv = nsInlineFrame::InsertFrames(aListID, aPrevFrame, aFrameList);
+    nsInlineFrame::InsertFrames(aListID, aPrevFrame, aFrameList);
     if (MOZ_LIKELY(aListID == kPrincipalList))
       nsMathMLContainerFrame::ReLayoutChildren(this);
-    return rv;
   }
 
-  virtual nsresult
+  virtual void
   RemoveFrame(ChildListID     aListID,
               nsIFrame*       aOldFrame) MOZ_OVERRIDE
   {
     NS_ASSERTION(aListID == kPrincipalList || aListID == kNoReflowPrincipalList,
                  "unexpected frame list");
-    nsresult rv = nsInlineFrame::RemoveFrame(aListID, aOldFrame);
+    nsInlineFrame::RemoveFrame(aListID, aOldFrame);
     if (MOZ_LIKELY(aListID == kPrincipalList))
       nsMathMLContainerFrame::ReLayoutChildren(this);
-    return rv;
   }
 
   virtual bool IsFrameOfType(uint32_t aFlags) const MOZ_OVERRIDE {
       return nsInlineFrame::IsFrameOfType(aFlags &
                 ~(nsIFrame::eMathML | nsIFrame::eExcludesIgnorableWhitespace));
   }
 
   bool
--- a/layout/mathml/nsMathMLSelectedFrame.cpp
+++ b/layout/mathml/nsMathMLSelectedFrame.cpp
@@ -51,26 +51,24 @@ nsMathMLSelectedFrame::TransmitAutomatic
 
 nsresult
 nsMathMLSelectedFrame::ChildListChanged(int32_t aModType)
 {
   GetSelectedFrame();
   return nsMathMLContainerFrame::ChildListChanged(aModType);
 }
 
-nsresult
+void
 nsMathMLSelectedFrame::SetInitialChildList(ChildListID     aListID,
                                            nsFrameList&    aChildList)
 {
-  nsresult rv = nsMathMLContainerFrame::SetInitialChildList(aListID,
-                                                            aChildList);
+  nsMathMLContainerFrame::SetInitialChildList(aListID, aChildList);
   // This very first call to GetSelectedFrame() will cause us to be marked as an
   // embellished operator if the selected child is an embellished operator
   GetSelectedFrame();
-  return rv;
 }
 
 //  Only paint the selected child...
 void
 nsMathMLSelectedFrame::BuildDisplayList(nsDisplayListBuilder*   aBuilder,
                                         const nsRect&           aDirtyRect,
                                         const nsDisplayListSet& aLists)
 {
--- a/layout/mathml/nsMathMLSelectedFrame.h
+++ b/layout/mathml/nsMathMLSelectedFrame.h
@@ -13,17 +13,17 @@ public:
   virtual void
   Init(nsIContent*       aContent,
        nsContainerFrame* aParent,
        nsIFrame*         aPrevInFlow) MOZ_OVERRIDE;
 
   NS_IMETHOD
   TransmitAutomaticData() MOZ_OVERRIDE;
 
-  virtual nsresult
+  virtual void
   SetInitialChildList(ChildListID     aListID,
                       nsFrameList&    aChildList) MOZ_OVERRIDE;
 
   virtual nsresult
   ChildListChanged(int32_t aModType) MOZ_OVERRIDE;
 
   virtual void BuildDisplayList(nsDisplayListBuilder*   aBuilder,
                                 const nsRect&           aDirtyRect,
--- a/layout/mathml/nsMathMLTokenFrame.cpp
+++ b/layout/mathml/nsMathMLTokenFrame.cpp
@@ -87,56 +87,40 @@ nsMathMLTokenFrame::MarkTextFramesAsToke
 
     if (isSingleCharacter) {
       child->AddStateBits(NS_FRAME_IS_IN_SINGLE_CHAR_MI);
       AddStateBits(NS_FRAME_IS_IN_SINGLE_CHAR_MI);
     }
   }
 }
 
-nsresult
+void
 nsMathMLTokenFrame::SetInitialChildList(ChildListID     aListID,
                                         nsFrameList&    aChildList)
 {
   // First, let the base class do its work
-  nsresult rv = nsMathMLContainerFrame::SetInitialChildList(aListID, aChildList);
-  if (NS_FAILED(rv))
-    return rv;
-
+  nsMathMLContainerFrame::SetInitialChildList(aListID, aChildList);
   MarkTextFramesAsTokenMathML();
-
-  return rv;
 }
 
-nsresult
+void
 nsMathMLTokenFrame::AppendFrames(ChildListID aListID,
                                  nsFrameList& aChildList)
 {
-  nsresult rv = nsMathMLContainerFrame::AppendFrames(aListID, aChildList);
-  if (NS_FAILED(rv))
-    return rv;
-
+  nsMathMLContainerFrame::AppendFrames(aListID, aChildList);
   MarkTextFramesAsTokenMathML();
-
-  return rv;
 }
 
-nsresult
+void
 nsMathMLTokenFrame::InsertFrames(ChildListID aListID,
                                  nsIFrame* aPrevFrame,
                                  nsFrameList& aChildList)
 {
-  nsresult rv = nsMathMLContainerFrame::InsertFrames(aListID, aPrevFrame,
-                                                     aChildList);
-  if (NS_FAILED(rv))
-    return rv;
-
+  nsMathMLContainerFrame::InsertFrames(aListID, aPrevFrame, aChildList);
   MarkTextFramesAsTokenMathML();
-
-  return rv;
 }
 
 void
 nsMathMLTokenFrame::Reflow(nsPresContext*          aPresContext,
                            nsHTMLReflowMetrics&     aDesiredSize,
                            const nsHTMLReflowState& aReflowState,
                            nsReflowStatus&          aStatus)
 {
--- a/layout/mathml/nsMathMLTokenFrame.h
+++ b/layout/mathml/nsMathMLTokenFrame.h
@@ -29,25 +29,25 @@ public:
     return NS_OK;
   }
 
   NS_IMETHOD
   InheritAutomaticData(nsIFrame* aParent) MOZ_OVERRIDE;
 
   virtual eMathMLFrameType GetMathMLFrameType() MOZ_OVERRIDE;
 
-  virtual nsresult
+  virtual void
   SetInitialChildList(ChildListID     aListID,
                       nsFrameList&    aChildList) MOZ_OVERRIDE;
 
-  virtual nsresult
+  virtual void
   AppendFrames(ChildListID            aListID,
                nsFrameList&           aChildList) MOZ_OVERRIDE;
 
-  virtual nsresult
+  virtual void
   InsertFrames(ChildListID            aListID,
                nsIFrame*              aPrevFrame,
                nsFrameList&           aChildList) MOZ_OVERRIDE;
 
   virtual void
   Reflow(nsPresContext*          aPresContext,
          nsHTMLReflowMetrics&     aDesiredSize,
          const nsHTMLReflowState& aReflowState,
--- a/layout/mathml/nsMathMLmactionFrame.cpp
+++ b/layout/mathml/nsMathMLmactionFrame.cpp
@@ -167,37 +167,36 @@ nsMathMLmactionFrame::GetSelectedFrame()
   mChildCount = count;
   mSelection = selection;
   mInvalidMarkup = (mSelection == -1);
   TransmitAutomaticData();
 
   return mSelectedFrame;
 }
 
-nsresult
+void
 nsMathMLmactionFrame::SetInitialChildList(ChildListID     aListID,
                                           nsFrameList&    aChildList)
 {
-  nsresult rv = nsMathMLSelectedFrame::SetInitialChildList(aListID, aChildList);
+  nsMathMLSelectedFrame::SetInitialChildList(aListID, aChildList);
 
   if (!mSelectedFrame) {
     mActionType = NS_MATHML_ACTION_TYPE_NONE;
   }
   else {
     // create mouse event listener and register it
     mListener = new nsMathMLmactionFrame::MouseListener(this);
     // printf("maction:%p registering as mouse event listener ...\n", this);
     mContent->AddSystemEventListener(NS_LITERAL_STRING("click"), mListener,
                                      false, false);
     mContent->AddSystemEventListener(NS_LITERAL_STRING("mouseover"), mListener,
                                      false, false);
     mContent->AddSystemEventListener(NS_LITERAL_STRING("mouseout"), mListener,
                                      false, false);
   }
-  return rv;
 }
 
 nsresult
 nsMathMLmactionFrame::AttributeChanged(int32_t  aNameSpaceID,
                                        nsIAtom* aAttribute,
                                        int32_t  aModType)
 {
   bool needsReflow = false;
--- a/layout/mathml/nsMathMLmactionFrame.h
+++ b/layout/mathml/nsMathMLmactionFrame.h
@@ -21,17 +21,17 @@ public:
 
   friend nsIFrame* NS_NewMathMLmactionFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
 
   virtual void
   Init(nsIContent*       aContent,
        nsContainerFrame* aParent,
        nsIFrame*         aPrevInFlow) MOZ_OVERRIDE;
 
-  virtual nsresult
+  virtual void
   SetInitialChildList(ChildListID     aListID,
                       nsFrameList&    aChildList) MOZ_OVERRIDE;
 
   virtual nsresult
   ChildListChanged(int32_t aModType) MOZ_OVERRIDE;
 
   virtual nsresult
   AttributeChanged(int32_t  aNameSpaceID,
--- a/layout/mathml/nsMathMLmfencedFrame.cpp
+++ b/layout/mathml/nsMathMLmfencedFrame.cpp
@@ -35,33 +35,31 @@ nsMathMLmfencedFrame::InheritAutomaticDa
   mPresentationData.flags |= NS_MATHML_STRETCH_ALL_CHILDREN_VERTICALLY;
 
   RemoveFencesAndSeparators();
   CreateFencesAndSeparators(PresContext());
 
   return NS_OK;
 }
 
-nsresult
+void
 nsMathMLmfencedFrame::SetInitialChildList(ChildListID     aListID,
                                           nsFrameList&    aChildList)
 {
   // First, let the base class do its work
-  nsresult rv = nsMathMLContainerFrame::SetInitialChildList(aListID, aChildList);
-  if (NS_FAILED(rv)) return rv;
+  nsMathMLContainerFrame::SetInitialChildList(aListID, aChildList);
 
   // InheritAutomaticData will not get called if our parent is not a mathml
   // frame, so initialize NS_MATHML_STRETCH_ALL_CHILDREN_VERTICALLY for
   // GetPreferredStretchSize() from Reflow().
   mPresentationData.flags |= NS_MATHML_STRETCH_ALL_CHILDREN_VERTICALLY;
   // No need to track the style contexts given to our MathML chars. 
   // The Style System will use Get/SetAdditionalStyleContext() to keep them
   // up-to-date if dynamic changes arise.
   CreateFencesAndSeparators(PresContext());
-  return NS_OK;
 }
 
 nsresult
 nsMathMLmfencedFrame::AttributeChanged(int32_t         aNameSpaceID,
                                        nsIAtom*        aAttribute,
                                        int32_t         aModType)
 {
   RemoveFencesAndSeparators();
--- a/layout/mathml/nsMathMLmfencedFrame.h
+++ b/layout/mathml/nsMathMLmfencedFrame.h
@@ -23,17 +23,17 @@ public:
   SetAdditionalStyleContext(int32_t          aIndex, 
                             nsStyleContext*  aStyleContext) MOZ_OVERRIDE;
   virtual nsStyleContext*
   GetAdditionalStyleContext(int32_t aIndex) const MOZ_OVERRIDE;
 
   NS_IMETHOD
   InheritAutomaticData(nsIFrame* aParent) MOZ_OVERRIDE;
 
-  virtual nsresult
+  virtual void
   SetInitialChildList(ChildListID     aListID,
                       nsFrameList&    aChildList) MOZ_OVERRIDE;
 
   virtual void
   Reflow(nsPresContext*          aPresContext,
          nsHTMLReflowMetrics&     aDesiredSize,
          const nsHTMLReflowState& aReflowState,
          nsReflowStatus&          aStatus) MOZ_OVERRIDE;
--- a/layout/mathml/nsMathMLmoFrame.cpp
+++ b/layout/mathml/nsMathMLmoFrame.cpp
@@ -917,27 +917,23 @@ nsMathMLmoFrame::TransmitAutomaticData()
   // this will cause us to re-sync our flags from scratch
   // but our returned 'form' is still not final (bug 133429), it will
   // be recomputed to its final value during the next call in Reflow()
   mEmbellishData.coreFrame = nullptr;
   ProcessOperatorData();
   return NS_OK;
 }
 
-nsresult
+void
 nsMathMLmoFrame::SetInitialChildList(ChildListID     aListID,
                                      nsFrameList&    aChildList)
 {
   // First, let the parent class do its work
-  nsresult rv = nsMathMLTokenFrame::SetInitialChildList(aListID, aChildList);
-  if (NS_FAILED(rv))
-    return rv;
-
+  nsMathMLTokenFrame::SetInitialChildList(aListID, aChildList);
   ProcessTextData();
-  return rv;
 }
 
 void
 nsMathMLmoFrame::Reflow(nsPresContext*          aPresContext,
                         nsHTMLReflowMetrics&     aDesiredSize,
                         const nsHTMLReflowState& aReflowState,
                         nsReflowStatus&          aStatus)
 {
--- a/layout/mathml/nsMathMLmoFrame.h
+++ b/layout/mathml/nsMathMLmoFrame.h
@@ -33,17 +33,17 @@ public:
                                 const nsDisplayListSet& aLists) MOZ_OVERRIDE;
 
   NS_IMETHOD
   InheritAutomaticData(nsIFrame* aParent) MOZ_OVERRIDE;
 
   NS_IMETHOD
   TransmitAutomaticData() MOZ_OVERRIDE;
 
-  virtual nsresult
+  virtual void
   SetInitialChildList(ChildListID     aListID,
                       nsFrameList&    aChildList) MOZ_OVERRIDE;
 
   virtual void
   Reflow(nsPresContext*          aPresContext,
          nsHTMLReflowMetrics&     aDesiredSize,
          const nsHTMLReflowState& aReflowState,
          nsReflowStatus&          aStatus) MOZ_OVERRIDE;
--- a/layout/mathml/nsMathMLmtableFrame.cpp
+++ b/layout/mathml/nsMathMLmtableFrame.cpp
@@ -654,24 +654,22 @@ NS_NewMathMLmtableFrame(nsIPresShell* aP
 }
 
 NS_IMPL_FRAMEARENA_HELPERS(nsMathMLmtableFrame)
 
 nsMathMLmtableFrame::~nsMathMLmtableFrame()
 {
 }
 
-nsresult
+void
 nsMathMLmtableFrame::SetInitialChildList(ChildListID  aListID,
                                          nsFrameList& aChildList)
 {
-  nsresult rv = nsTableFrame::SetInitialChildList(aListID, aChildList);
-  if (NS_FAILED(rv)) return rv;
+  nsTableFrame::SetInitialChildList(aListID, aChildList);
   MapAllAttributesIntoCSS(this);
-  return rv;
 }
 
 void
 nsMathMLmtableFrame::RestyleTable()
 {
   // re-sync MathML specific style data that may have changed
   MapAllAttributesIntoCSS(this);
 
--- a/layout/mathml/nsMathMLmtableFrame.h
+++ b/layout/mathml/nsMathMLmtableFrame.h
@@ -64,46 +64,43 @@ class nsMathMLmtableFrame : public nsTab
 public:
   NS_DECL_FRAMEARENA_HELPERS
 
   friend nsContainerFrame* NS_NewMathMLmtableFrame(nsIPresShell* aPresShell,
                                                    nsStyleContext* aContext);
 
   // Overloaded nsTableFrame methods
 
-  virtual nsresult
+  virtual void
   SetInitialChildList(ChildListID  aListID,
                       nsFrameList& aChildList) MOZ_OVERRIDE;
 
-  virtual nsresult
+  virtual void
   AppendFrames(ChildListID  aListID,
                nsFrameList& aFrameList) MOZ_OVERRIDE
   {
-    nsresult rv = nsTableFrame::AppendFrames(aListID, aFrameList);
+    nsTableFrame::AppendFrames(aListID, aFrameList);
     RestyleTable();
-    return rv;
   }
 
-  virtual nsresult
+  virtual void
   InsertFrames(ChildListID aListID,
                nsIFrame* aPrevFrame,
                nsFrameList& aFrameList) MOZ_OVERRIDE
   {
-    nsresult rv = nsTableFrame::InsertFrames(aListID, aPrevFrame, aFrameList);
+    nsTableFrame::InsertFrames(aListID, aPrevFrame, aFrameList);
     RestyleTable();
-    return rv;
   }
 
-  virtual nsresult
+  virtual void
   RemoveFrame(ChildListID aListID,
               nsIFrame* aOldFrame) MOZ_OVERRIDE
   {
-    nsresult rv = nsTableFrame::RemoveFrame(aListID, aOldFrame);
+    nsTableFrame::RemoveFrame(aListID, aOldFrame);
     RestyleTable();
-    return rv;
   }
 
   virtual bool IsFrameOfType(uint32_t aFlags) const MOZ_OVERRIDE
   {
     return nsTableFrame::IsFrameOfType(aFlags & ~(nsIFrame::eMathML));
   }
 
   // helper to restyle and reflow the table when a row is changed -- since MathML
@@ -128,42 +125,39 @@ public:
 
   // overloaded nsTableRowFrame methods
 
   virtual nsresult
   AttributeChanged(int32_t  aNameSpaceID,
                    nsIAtom* aAttribute,
                    int32_t  aModType) MOZ_OVERRIDE;
 
-  virtual nsresult
+  virtual void
   AppendFrames(ChildListID  aListID,
                nsFrameList& aFrameList) MOZ_OVERRIDE
   {
-    nsresult rv = nsTableRowFrame::AppendFrames(aListID, aFrameList);
+    nsTableRowFrame::AppendFrames(aListID, aFrameList);
     RestyleTable();
-    return rv;
   }
 
-  virtual nsresult
+  virtual void
   InsertFrames(ChildListID aListID,
                nsIFrame* aPrevFrame,
                nsFrameList& aFrameList) MOZ_OVERRIDE
   {
-    nsresult rv = nsTableRowFrame::InsertFrames(aListID, aPrevFrame, aFrameList);
+    nsTableRowFrame::InsertFrames(aListID, aPrevFrame, aFrameList);
     RestyleTable();
-    return rv;
   }
 
-  virtual nsresult
+  virtual void
   RemoveFrame(ChildListID aListID,
               nsIFrame* aOldFrame) MOZ_OVERRIDE
   {
-    nsresult rv = nsTableRowFrame::RemoveFrame(aListID, aOldFrame);
+    nsTableRowFrame::RemoveFrame(aListID, aOldFrame);
     RestyleTable();
-    return rv;
   }
 
   virtual bool IsFrameOfType(uint32_t aFlags) const MOZ_OVERRIDE
   {
     return nsTableRowFrame::IsFrameOfType(aFlags & ~(nsIFrame::eMathML));
   }
 
   // helper to restyle and reflow the table -- @see nsMathMLmtableFrame.
--- a/layout/svg/nsSVGContainerFrame.cpp
+++ b/layout/svg/nsSVGContainerFrame.cpp
@@ -36,45 +36,42 @@ NS_NewSVGContainerFrame(nsIPresShell* aP
   // from displaying directly.
   frame->AddStateBits(NS_FRAME_IS_NONDISPLAY);
   return frame;
 }
 
 NS_IMPL_FRAMEARENA_HELPERS(nsSVGContainerFrame)
 NS_IMPL_FRAMEARENA_HELPERS(nsSVGDisplayContainerFrame)
 
-nsresult
+void
 nsSVGContainerFrame::AppendFrames(ChildListID  aListID,
                                   nsFrameList& aFrameList)
 {
-  return InsertFrames(aListID, mFrames.LastChild(), aFrameList);  
+  InsertFrames(aListID, mFrames.LastChild(), aFrameList);  
 }
 
-nsresult
+void
 nsSVGContainerFrame::InsertFrames(ChildListID aListID,
                                   nsIFrame* aPrevFrame,
                                   nsFrameList& aFrameList)
 {
   NS_ASSERTION(aListID == kPrincipalList, "unexpected child list");
   NS_ASSERTION(!aPrevFrame || aPrevFrame->GetParent() == this,
                "inserting after sibling frame with different parent");
 
   mFrames.InsertFrames(this, aPrevFrame, aFrameList);
-
-  return NS_OK;
 }
 
-nsresult
+void
 nsSVGContainerFrame::RemoveFrame(ChildListID aListID,
                                  nsIFrame* aOldFrame)
 {
   NS_ASSERTION(aListID == kPrincipalList, "unexpected child list");
 
   mFrames.DestroyFrame(aOldFrame);
-  return NS_OK;
 }
 
 bool
 nsSVGContainerFrame::UpdateOverflow()
 {
   if (mState & NS_FRAME_IS_NONDISPLAY) {
     // We don't maintain overflow rects.
     // XXX It would have be better if the restyle request hadn't even happened.
@@ -149,17 +146,17 @@ nsSVGDisplayContainerFrame::BuildDisplay
   // mContent could be a XUL element so check for an SVG element before casting
   if (mContent->IsSVG() &&
       !static_cast<const nsSVGElement*>(mContent)->HasValidDimensions()) {
     return;
   }
   return BuildDisplayListForNonBlockChildren(aBuilder, aDirtyRect, aLists);
 }
 
-nsresult
+void
 nsSVGDisplayContainerFrame::InsertFrames(ChildListID aListID,
                                          nsIFrame* aPrevFrame,
                                          nsFrameList& aFrameList)
 {
   // memorize first old frame after insertion point
   // XXXbz once again, this would work a lot better if the nsIFrame
   // methods returned framelist iterators....
   nsIFrame* nextFrame = aPrevFrame ?
@@ -189,40 +186,36 @@ nsSVGDisplayContainerFrame::InsertFrames
         nsSVGUtils::ScheduleReflowSVG(kid);
         if (isFirstReflow) {
           // Add back the NS_FRAME_FIRST_REFLOW bit:
           kid->AddStateBits(NS_FRAME_FIRST_REFLOW);
         }
       }
     }
   }
-
-  return NS_OK;
 }
 
-nsresult
+void
 nsSVGDisplayContainerFrame::RemoveFrame(ChildListID aListID,
                                         nsIFrame* aOldFrame)
 {
   nsSVGEffects::InvalidateRenderingObservers(aOldFrame);
 
   // nsSVGContainerFrame::RemoveFrame doesn't call down into
   // nsContainerFrame::RemoveFrame, so it doesn't call FrameNeedsReflow. We
   // need to schedule a repaint and schedule an update to our overflow rects.
   SchedulePaint();
   PresContext()->RestyleManager()->PostRestyleEvent(
     mContent->AsElement(), nsRestyleHint(0), nsChangeHint_UpdateOverflow);
 
-  nsresult rv = nsSVGContainerFrame::RemoveFrame(aListID, aOldFrame);
+  nsSVGContainerFrame::RemoveFrame(aListID, aOldFrame);
 
   if (!(GetStateBits() & (NS_FRAME_IS_NONDISPLAY | NS_STATE_IS_OUTER_SVG))) {
     nsSVGUtils::NotifyAncestorsOfFilterRegionChange(this);
   }
-
-  return rv;
 }
 
 bool
 nsSVGDisplayContainerFrame::IsSVGTransformed(gfx::Matrix *aOwnTransform,
                                              gfx::Matrix *aFromParentTransform) const
 {
   bool foundTransform = false;
 
--- a/layout/svg/nsSVGContainerFrame.h
+++ b/layout/svg/nsSVGContainerFrame.h
@@ -68,23 +68,23 @@ public:
    * due to a root-<svg> having its currentScale/currentTransform properties
    * set. If aTransform is non-null, then it will be set to the transform.
    */
   virtual bool HasChildrenOnlyTransform(Matrix *aTransform) const {
     return false;
   }
 
   // nsIFrame:
-  virtual nsresult AppendFrames(ChildListID     aListID,
-                                nsFrameList&    aFrameList) MOZ_OVERRIDE;
-  virtual nsresult InsertFrames(ChildListID     aListID,
-                                nsIFrame*       aPrevFrame,
-                                nsFrameList&    aFrameList) MOZ_OVERRIDE;
-  virtual nsresult RemoveFrame(ChildListID     aListID,
-                               nsIFrame*       aOldFrame) MOZ_OVERRIDE;
+  virtual void AppendFrames(ChildListID     aListID,
+                            nsFrameList&    aFrameList) MOZ_OVERRIDE;
+  virtual void InsertFrames(ChildListID     aListID,
+                            nsIFrame*       aPrevFrame,
+                            nsFrameList&    aFrameList) MOZ_OVERRIDE;
+  virtual void RemoveFrame(ChildListID     aListID,
+                           nsIFrame*       aOldFrame) MOZ_OVERRIDE;
 
   virtual bool IsFrameOfType(uint32_t aFlags) const MOZ_OVERRIDE
   {
     return nsSVGContainerFrameBase::IsFrameOfType(
             aFlags & ~(nsIFrame::eSVG | nsIFrame::eSVGContainer));
   }
 
   virtual void BuildDisplayList(nsDisplayListBuilder*   aBuilder,
@@ -123,20 +123,20 @@ protected:
   }
 
 public:
   NS_DECL_QUERYFRAME_TARGET(nsSVGDisplayContainerFrame)
   NS_DECL_QUERYFRAME
   NS_DECL_FRAMEARENA_HELPERS
 
   // nsIFrame:
-  virtual nsresult InsertFrames(ChildListID     aListID,
+  virtual void InsertFrames(ChildListID     aListID,
                                 nsIFrame*       aPrevFrame,
                                 nsFrameList&    aFrameList) MOZ_OVERRIDE;
-  virtual nsresult RemoveFrame(ChildListID     aListID,
+  virtual void RemoveFrame(ChildListID     aListID,
                                nsIFrame*       aOldFrame) MOZ_OVERRIDE;
  virtual void Init(nsIContent*       aContent,
                    nsContainerFrame* aParent,
                    nsIFrame*         aPrevInFlow) MOZ_OVERRIDE;
 
   virtual void BuildDisplayList(nsDisplayListBuilder*   aBuilder,
                                 const nsRect&           aDirtyRect,
                                 const nsDisplayListSet& aLists) MOZ_OVERRIDE;
--- a/layout/tables/nsTableCellFrame.cpp
+++ b/layout/tables/nsTableCellFrame.cpp
@@ -235,41 +235,39 @@ nsTableCellFrame::DidSetStyleContext(nsS
     // row span needs to be clamped as we do not create rows in the cellmap
     // which do not have cells originating in them
     nsIntRect damageArea(colIndex, rowIndex, GetColSpan(),
       std::min(GetRowSpan(), tableFrame->GetRowCount() - rowIndex));
     tableFrame->AddBCDamageArea(damageArea);
   }
 }
 
-
-nsresult
+#ifdef DEBUG
+void
 nsTableCellFrame::AppendFrames(ChildListID     aListID,
                                nsFrameList&    aFrameList)
 {
-  NS_PRECONDITION(false, "unsupported operation");
-  return NS_ERROR_NOT_IMPLEMENTED;
+  MOZ_CRASH("unsupported operation");
 }
 
-nsresult
+void
 nsTableCellFrame::InsertFrames(ChildListID     aListID,
                                nsIFrame*       aPrevFrame,
                                nsFrameList&    aFrameList)
 {
-  NS_PRECONDITION(false, "unsupported operation");
-  return NS_ERROR_NOT_IMPLEMENTED;
+  MOZ_CRASH("unsupported operation");
 }
 
-nsresult
+void
 nsTableCellFrame::RemoveFrame(ChildListID     aListID,
                               nsIFrame*       aOldFrame)
 {
-  NS_PRECONDITION(false, "unsupported operation");
-  return NS_ERROR_NOT_IMPLEMENTED;
+  MOZ_CRASH("unsupported operation");
 }
+#endif
 
 void nsTableCellFrame::SetColIndex(int32_t aColIndex)
 {
   mColIndex = aColIndex;
 }
 
 /* virtual */ nsMargin
 nsTableCellFrame::GetUsedMargin() const
--- a/layout/tables/nsTableCellFrame.h
+++ b/layout/tables/nsTableCellFrame.h
@@ -55,26 +55,27 @@ public:
 
   virtual nsresult  AttributeChanged(int32_t         aNameSpaceID,
                                      nsIAtom*        aAttribute,
                                      int32_t         aModType) MOZ_OVERRIDE;
 
   /** @see nsIFrame::DidSetStyleContext */
   virtual void DidSetStyleContext(nsStyleContext* aOldStyleContext) MOZ_OVERRIDE;
 
-  // table cells contain a block frame which does most of the work, and
-  // so these functions should never be called. They assert and return
-  // NS_ERROR_NOT_IMPLEMENTED
-  virtual nsresult AppendFrames(ChildListID     aListID,
-                                nsFrameList&    aFrameList) MOZ_OVERRIDE;
-  virtual nsresult InsertFrames(ChildListID     aListID,
-                                nsIFrame*       aPrevFrame,
-                                nsFrameList&    aFrameList) MOZ_OVERRIDE;
-  virtual nsresult RemoveFrame(ChildListID     aListID,
-                               nsIFrame*       aOldFrame) MOZ_OVERRIDE;
+#ifdef DEBUG
+  // Our anonymous block frame is the content insertion frame so these
+  // methods should never be called:
+  virtual void AppendFrames(ChildListID     aListID,
+                            nsFrameList&    aFrameList) MOZ_OVERRIDE;
+  virtual void InsertFrames(ChildListID     aListID,
+                            nsIFrame*       aPrevFrame,
+                            nsFrameList&    aFrameList) MOZ_OVERRIDE;
+  virtual void RemoveFrame(ChildListID     aListID,
+                           nsIFrame*       aOldFrame) MOZ_OVERRIDE;
+#endif
 
   virtual nsContainerFrame* GetContentInsertionFrame() MOZ_OVERRIDE {
     return GetFirstPrincipalChild()->GetContentInsertionFrame();
   }
 
   virtual nsMargin GetUsedMargin() const MOZ_OVERRIDE;
 
   virtual void NotifyPercentHeight(const nsHTMLReflowState& aReflowState) MOZ_OVERRIDE;
--- a/layout/tables/nsTableColGroupFrame.cpp
+++ b/layout/tables/nsTableColGroupFrame.cpp
@@ -126,40 +126,31 @@ nsTableColGroupFrame::GetLastRealColGrou
   if (eColGroupAnonymousCell == lastColGroupType) {
     return static_cast<nsTableColGroupFrame*>(nextToLastColGroup);
   }
  
   return static_cast<nsTableColGroupFrame*>(link.PrevFrame());
 }
 
 // don't set mColCount here, it is done in AddColsToTable
-nsresult
+void
 nsTableColGroupFrame::SetInitialChildList(ChildListID     aListID,
                                           nsFrameList&    aChildList)
 {
-  if (!mFrames.IsEmpty()) {
-    // We already have child frames which means we've already been
-    // initialized
-    NS_NOTREACHED("unexpected second call to SetInitialChildList");
-    return NS_ERROR_UNEXPECTED;
-  }
-  if (aListID != kPrincipalList) {
-    // All we know about is the principal child list.
-    NS_NOTREACHED("unknown frame list");
-    return NS_ERROR_INVALID_ARG;
-  } 
-  nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(this);
-  if (aChildList.IsEmpty()) {
+  MOZ_ASSERT(mFrames.IsEmpty(),
+             "unexpected second call to SetInitialChildList");
+  MOZ_ASSERT(aListID == kPrincipalList, "unexpected child list");
+  if (aChildList.IsEmpty()) { 
+    nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(this);
     tableFrame->AppendAnonymousColFrames(this, GetSpan(), eColAnonymousColGroup, 
                                          false);
-    return NS_OK; 
+    return; 
   }
 
   mFrames.AppendFrames(this, aChildList);
-  return NS_OK;
 }
 
 /* virtual */ void
 nsTableColGroupFrame::DidSetStyleContext(nsStyleContext* aOldStyleContext)
 {
   nsContainerFrame::DidSetStyleContext(aOldStyleContext);
 
   if (!aOldStyleContext) //avoid this on init
@@ -172,17 +163,17 @@ nsTableColGroupFrame::DidSetStyleContext
     if (!colCount)
       return; // this is a degenerated colgroup 
     nsIntRect damageArea(GetFirstColumn()->GetColIndex(), 0, colCount,
                          tableFrame->GetRowCount());
     tableFrame->AddBCDamageArea(damageArea);
   }
 }
 
-nsresult
+void
 nsTableColGroupFrame::AppendFrames(ChildListID     aListID,
                                    nsFrameList&    aFrameList)
 {
   NS_ASSERTION(aListID == kPrincipalList, "unexpected child list");
 
   nsTableColFrame* col = GetFirstColumn();
   nsTableColFrame* nextCol;
   while (col && col->GetColType() == eColAnonymousColGroup) {
@@ -193,20 +184,19 @@ nsTableColGroupFrame::AppendFrames(Child
     nextCol = col->GetNextCol();
     RemoveFrame(kPrincipalList, col);
     col = nextCol;
   }
 
   const nsFrameList::Slice& newFrames =
     mFrames.AppendFrames(this, aFrameList);
   InsertColsReflow(GetStartColumnIndex() + mColCount, newFrames);
-  return NS_OK;
 }
 
-nsresult
+void
 nsTableColGroupFrame::InsertFrames(ChildListID     aListID,
                                    nsIFrame*       aPrevFrame,
                                    nsFrameList&    aFrameList)
 {
   NS_ASSERTION(aListID == kPrincipalList, "unexpected child list");
   NS_ASSERTION(!aPrevFrame || aPrevFrame->GetParent() == this,
                "inserting after sibling frame with different parent");
 
@@ -237,18 +227,16 @@ nsTableColGroupFrame::InsertFrames(Child
 
   const nsFrameList::Slice& newFrames =
     mFrames.InsertFrames(this, aPrevFrame, aFrameList);
   nsIFrame* prevFrame = nsTableFrame::GetFrameAtOrBefore(this, aPrevFrame,
                                                          nsGkAtoms::tableColFrame);
 
   int32_t colIndex = (prevFrame) ? ((nsTableColFrame*)prevFrame)->GetColIndex() + 1 : GetStartColumnIndex();
   InsertColsReflow(colIndex, newFrames);
-
-  return NS_OK;
 }
 
 void
 nsTableColGroupFrame::InsertColsReflow(int32_t                   aColIndex,
                                        const nsFrameList::Slice& aCols)
 {
   AddColsToTable(aColIndex, true, aCols);
 
@@ -280,23 +268,25 @@ nsTableColGroupFrame::RemoveChild(nsTabl
     }
   }
 
   PresContext()->PresShell()->FrameNeedsReflow(this,
                                                nsIPresShell::eTreeChange,
                                                NS_FRAME_HAS_DIRTY_CHILDREN);
 }
 
-nsresult
+void
 nsTableColGroupFrame::RemoveFrame(ChildListID     aListID,
                                   nsIFrame*       aOldFrame)
 {
   NS_ASSERTION(aListID == kPrincipalList, "unexpected child list");
 
-  if (!aOldFrame) return NS_OK;
+  if (!aOldFrame) {
+    return;
+  }
   bool contentRemoval = false;
   
   if (nsGkAtoms::tableColFrame == aOldFrame->GetType()) {
     nsTableColFrame* colFrame = (nsTableColFrame*)aOldFrame;
     if (colFrame->GetColType() == eColContent) {
       contentRemoval = true;
       // Remove any anonymous column frames this <col> produced via a colspan
       nsTableColFrame* col = colFrame->GetNextCol();
@@ -331,18 +321,16 @@ nsTableColGroupFrame::RemoveFrame(ChildL
         GetColType() == eColGroupContent) {
       tableFrame->AppendAnonymousColFrames(this, GetSpan(),
                                            eColAnonymousColGroup, true);
     }
   }
   else {
     mFrames.DestroyFrame(aOldFrame);
   }
-
-  return NS_OK;
 }
 
 int
 nsTableColGroupFrame::GetLogicalSkipSides(const nsHTMLReflowState* aReflowState) const
 {
   if (MOZ_UNLIKELY(StyleBorder()->mBoxDecorationBreak ==
                      NS_STYLE_BOX_DECORATION_BREAK_CLONE)) {
     return 0;
--- a/layout/tables/nsTableColGroupFrame.h
+++ b/layout/tables/nsTableColGroupFrame.h
@@ -35,22 +35,16 @@ public:
   /** instantiate a new instance of nsTableRowFrame.
     * @param aPresShell the pres shell for this frame
     *
     * @return           the frame that was created
     */
   friend nsTableColGroupFrame* NS_NewTableColGroupFrame(nsIPresShell* aPresShell,
                                                         nsStyleContext* aContext);
 
-  /** Initialize the colgroup frame with a set of children.
-    * @see nsIFrame::SetInitialChildList
-    */
-  virtual nsresult SetInitialChildList(ChildListID     aListID,
-                                       nsFrameList&    aChildList) MOZ_OVERRIDE;
-
   /**
    * ColGroups never paint anything, nor receive events.
    */
   virtual void BuildDisplayList(nsDisplayListBuilder*   aBuilder,
                                 const nsRect&           aDirtyRect,
                                 const nsDisplayListSet& aLists) MOZ_OVERRIDE {}
 
   /** A colgroup can be caused by three things:
@@ -76,25 +70,25 @@ public:
     * @param aTableFrame - the table parent of the colgroups
     * @return the last real colgroup
     */
   static nsTableColGroupFrame* GetLastRealColGroup(nsTableFrame* aTableFrame);
 
   /** @see nsIFrame::DidSetStyleContext */
   virtual void DidSetStyleContext(nsStyleContext* aOldStyleContext) MOZ_OVERRIDE;
 
-  /** @see nsIFrame::AppendFrames, InsertFrames, RemoveFrame
-    */
-  virtual nsresult AppendFrames(ChildListID     aListID,
-                                nsFrameList&    aFrameList) MOZ_OVERRIDE;
-  virtual nsresult InsertFrames(ChildListID     aListID,
-                                nsIFrame*       aPrevFrame,
-                                nsFrameList&    aFrameList) MOZ_OVERRIDE;
-  virtual nsresult RemoveFrame(ChildListID     aListID,
-                               nsIFrame*       aOldFrame) MOZ_OVERRIDE;
+  virtual void SetInitialChildList(ChildListID     aListID,
+                                   nsFrameList&    aChildList) MOZ_OVERRIDE;
+  virtual void AppendFrames(ChildListID     aListID,
+                            nsFrameList&    aFrameList) MOZ_OVERRIDE;
+  virtual void InsertFrames(ChildListID     aListID,
+                            nsIFrame*       aPrevFrame,
+                            nsFrameList&    aFrameList) MOZ_OVERRIDE;
+  virtual void RemoveFrame(ChildListID     aListID,
+                           nsIFrame*       aOldFrame) MOZ_OVERRIDE;
 
   /** remove the column aChild from the column group, if requested renumber
     * the subsequent columns in this column group and all following column
     * groups. see also ResetColIndices for this
     * @param aChild       - the column frame that needs to be removed
     * @param aResetSubsequentColIndices - if true the columns that follow
     *                                     after aChild will be reenumerated
     */
--- a/layout/tables/nsTableFrame.cpp
+++ b/layout/tables/nsTableFrame.cpp
@@ -327,32 +327,23 @@ nsTableFrame::UnregisterPositionedTableP
              "Asked to unregister a positioned table part that wasn't registered");
   if (positionedParts) {
     positionedParts->RemoveElement(aFrame);
   }
 }
 
 // XXX this needs to be cleaned up so that the frame constructor breaks out col group
 // frames into a separate child list, bug 343048.
-nsresult
+void
 nsTableFrame::SetInitialChildList(ChildListID     aListID,
                                   nsFrameList&    aChildList)
 {
-
-  if (!mFrames.IsEmpty() || !mColGroups.IsEmpty()) {
-    // We already have child frames which means we've already been
-    // initialized
-    NS_NOTREACHED("unexpected second call to SetInitialChildList");
-    return NS_ERROR_UNEXPECTED;
-  }
-  if (aListID != kPrincipalList) {
-    // All we know about is the principal child list.
-    NS_NOTREACHED("unknown frame list");
-    return NS_ERROR_INVALID_ARG;
-  }
+  MOZ_ASSERT(mFrames.IsEmpty() && mColGroups.IsEmpty(),
+             "unexpected second call to SetInitialChildList");
+  MOZ_ASSERT(aListID == kPrincipalList, "unexpected child list");
 
   // XXXbz the below code is an icky cesspit that's only needed in its current
   // form for two reasons:
   // 1) Both rowgroups and column groups come in on the principal child list.
   while (aChildList.NotEmpty()) {
     nsIFrame* childFrame = aChildList.FirstChild();
     aChildList.RemoveFirstChild();
     const nsStyleDisplay* childDisplay = childFrame->StyleDisplay();
@@ -374,18 +365,16 @@ nsTableFrame::SetInitialChildList(ChildL
     // anonymous ones due to cells in rows.
     InsertColGroups(0, mColGroups);
     InsertRowGroups(mFrames);
     // calc collapsing borders
     if (IsBorderCollapse()) {
       SetFullBCDamageArea();
     }
   }
-
-  return NS_OK;
 }
 
 void nsTableFrame::AttributeChangedFor(nsIFrame*       aFrame,
                                        nsIContent*     aContent,
                                        nsIAtom*        aAttribute)
 {
   nsTableCellFrame *cellFrame = do_QueryFrame(aFrame);
   if (cellFrame) {
@@ -2201,17 +2190,17 @@ nsTableFrame::DidSetStyleContext(nsStyle
       delete mTableLayoutStrategy;
       mTableLayoutStrategy = temp;
     }
   }
 }
 
 
 
-nsresult
+void
 nsTableFrame::AppendFrames(ChildListID     aListID,
                            nsFrameList&    aFrameList)
 {
   NS_ASSERTION(aListID == kPrincipalList || aListID == kColGroupList,
                "unexpected child list");
 
   // Because we actually have two child lists, one for col group frames and one
   // for everything else, we need to look at each frame individually
@@ -2248,44 +2237,43 @@ nsTableFrame::AppendFrames(ChildListID  
 
 #ifdef DEBUG_TABLE_CELLMAP
   printf("=== TableFrame::AppendFrames\n");
   Dump(true, true, true);
 #endif
   PresContext()->PresShell()->FrameNeedsReflow(this, nsIPresShell::eTreeChange,
                                                NS_FRAME_HAS_DIRTY_CHILDREN);
   SetGeometryDirty();
-
-  return NS_OK;
 }
 
 // Needs to be at file scope or ArrayLength fails to compile.
 struct ChildListInsertions {
   nsIFrame::ChildListID mID;
   nsFrameList mList;
 };
 
-nsresult
+void
 nsTableFrame::InsertFrames(ChildListID     aListID,
                            nsIFrame*       aPrevFrame,
                            nsFrameList&    aFrameList)
 {
   // The frames in aFrameList can be a mix of row group frames and col group
   // frames. The problem is that they should go in separate child lists so
   // we need to deal with that here...
   // XXX The frame construction code should be separating out child frames
   // based on the type, bug 343048.
 
   NS_ASSERTION(!aPrevFrame || aPrevFrame->GetParent() == this,
                "inserting after sibling frame with different parent");
 
   if ((aPrevFrame && !aPrevFrame->GetNextSibling()) ||
       (!aPrevFrame && GetChildList(aListID).IsEmpty())) {
     // Treat this like an append; still a workaround for bug 343048.
-    return AppendFrames(aListID, aFrameList);
+    AppendFrames(aListID, aFrameList);
+    return;
   }
 
   // Collect ColGroupFrames into a separate list and insert those separately
   // from the other frames (bug 759249).
   ChildListInsertions insertions[2]; // ColGroup, other
   const nsStyleDisplay* display = aFrameList.FirstChild()->StyleDisplay();
   nsFrameList::FrameLinkEnumerator e(aFrameList);
   for (; !aFrameList.IsEmpty(); e.Next()) {
@@ -2309,17 +2297,16 @@ nsTableFrame::InsertFrames(ChildListID  
     // We pass aPrevFrame for both ColGroup and other frames since
     // HomogenousInsertFrames will only use it if it's a suit