Merge inbound to m-c.
authorRyan VanderMeulen <ryanvm@gmail.com>
Thu, 17 Apr 2014 22:31:17 -0400
changeset 198738 7fe3ee0cf8be3f598d23d610618b1fee976a8fa7
parent 198656 ec728bfdbb79cb5ef6a847d042bda0cbad1207d0 (current diff)
parent 198737 fdfb11f2cf9cc52df05c86358bb3537d7e5bc4cd (diff)
child 198739 8f2f17f5ab237347fdd46b9ad91220bd1decda7d
child 198756 c75f7df6645b9f55613786e789f344f29307ea86
child 198786 35524db8493a53c3922924b1cda451c58dd996cd
push id486
push userasasaki@mozilla.com
push dateMon, 14 Jul 2014 18:39:42 +0000
treeherdermozilla-release@d33428174ff1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone31.0a1
first release with
nightly linux32
7fe3ee0cf8be / 31.0a1 / 20140418030202 / files
nightly linux64
7fe3ee0cf8be / 31.0a1 / 20140418030202 / files
nightly mac
7fe3ee0cf8be / 31.0a1 / 20140418030202 / files
nightly win32
7fe3ee0cf8be / 31.0a1 / 20140418030202 / files
nightly win64
7fe3ee0cf8be / 31.0a1 / 20140418030202 / 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 inbound to m-c.
b2g/config/tooltool-manifests/ics.manifest
b2g/config/tooltool-manifests/releng.manifest
content/canvas/public/nsICanvasElementExternal.h
gfx/layers/composite/APZCTreeManager.cpp
gfx/layers/composite/APZCTreeManager.h
gfx/layers/ipc/AsyncPanZoomController.cpp
gfx/layers/ipc/AsyncPanZoomController.h
gfx/layers/ipc/Axis.cpp
gfx/layers/ipc/Axis.h
gfx/layers/ipc/GeckoContentController.h
gfx/layers/ipc/GestureEventListener.cpp
gfx/layers/ipc/GestureEventListener.h
gfx/layers/ipc/TaskThrottler.cpp
gfx/layers/ipc/TaskThrottler.h
layout/generic/crashtests/455407.html
layout/reftests/backgrounds/background-size-continuous.html
layout/reftests/backgrounds/background-size-cover-bounding-box.html
layout/reftests/backgrounds/background-size-cover-continuous.html
layout/reftests/backgrounds/background-size-cover-each-box.html
layout/reftests/backgrounds/background-size-each-box.html
layout/reftests/bugs/368020-4-ref.html
layout/reftests/bugs/368020-4.html
testing/profiles/prefs_general.js
widget/xpwidgets/APZCCallbackHelper.cpp
widget/xpwidgets/APZCCallbackHelper.h
widget/xpwidgets/ActiveElementManager.cpp
widget/xpwidgets/ActiveElementManager.h
--- a/CLOBBER
+++ b/CLOBBER
@@ -17,9 +17,9 @@
 #
 # Modifying this file will now automatically clobber the buildbot machines \o/
 #
 
 # Are you updating CLOBBER because you think it's needed for your WebIDL
 # changes to stick? As of bug 928195, this shouldn't be necessary! Please
 # don't change CLOBBER for WebIDL changes any more.
 
-Bug 916012 moves definition from one WEBIDL_FILE to another (Bug 979886)
+Bug 995411 moves some files around in gfx/layers and widget/xpwidget
--- a/b2g/config/mozconfigs/common
+++ b/b2g/config/mozconfigs/common
@@ -1,11 +1,12 @@
 # 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/.
 
 no_tooltool=1
+no_sccache=1
 
 # This file is included at the top of all b2g mozconfigs
 
 . "$topsrcdir/build/mozconfig.common"
 
 ac_add_options --disable-unified-compilation
--- a/b2g/config/mozconfigs/linux32_gecko/nightly
+++ b/b2g/config/mozconfigs/linux32_gecko/nightly
@@ -16,17 +16,18 @@ STRIP_FLAGS="--strip-debug"
 # Needed to enable breakpad in application.ini
 export MOZILLA_OFFICIAL=1
 
 export MOZ_TELEMETRY_REPORTING=1
 
 # Treat warnings as errors in directories with FAIL_ON_WARNINGS.
 # DISABLED WHILE NOT ON TRY ac_add_options --enable-warnings-as-errors
 
-# Use ccache
+# Use sccache
+no_sccache=
 . "$topsrcdir/build/mozconfig.cache"
 
 #B2G options
 ac_add_options --enable-application=b2g
 ac_add_options --disable-elf-hack
 export CXXFLAGS=-DMOZ_ENABLE_JS_DUMP
 
 GAIADIR=$topsrcdir/gaia
--- a/b2g/config/mozconfigs/linux64_gecko/debug
+++ b/b2g/config/mozconfigs/linux64_gecko/debug
@@ -17,17 +17,18 @@ STRIP_FLAGS="--strip-debug"
 # Needed to enable breakpad in application.ini
 export MOZILLA_OFFICIAL=1
 
 export MOZ_TELEMETRY_REPORTING=1
 
 # Treat warnings as errors in directories with FAIL_ON_WARNINGS.
 # DISABLED WHILE NOT ON TRY ac_add_options --enable-warnings-as-errors
 
-# Use ccache
+# Use sccache
+no_sccache=
 . "$topsrcdir/build/mozconfig.cache"
 
 #B2G options
 ac_add_options --enable-application=b2g
 ENABLE_MARIONETTE=1
 ac_add_options --disable-elf-hack
 export CXXFLAGS=-DMOZ_ENABLE_JS_DUMP
 
--- a/b2g/config/mozconfigs/linux64_gecko/nightly
+++ b/b2g/config/mozconfigs/linux64_gecko/nightly
@@ -16,17 +16,18 @@ STRIP_FLAGS="--strip-debug"
 # Needed to enable breakpad in application.ini
 export MOZILLA_OFFICIAL=1
 
 export MOZ_TELEMETRY_REPORTING=1
 
 # Treat warnings as errors in directories with FAIL_ON_WARNINGS.
 # DISABLED WHILE NOT ON TRY ac_add_options --enable-warnings-as-errors
 
-# Use ccache
+# Use sccache
+no_sccache=
 . "$topsrcdir/build/mozconfig.cache"
 
 #B2G options
 ac_add_options --enable-application=b2g
 ac_add_options --disable-elf-hack
 export CXXFLAGS=-DMOZ_ENABLE_JS_DUMP
 
 GAIADIR=$topsrcdir/gaia
deleted file mode 100644
--- a/b2g/config/tooltool-manifests/ics.manifest
+++ /dev/null
@@ -1,14 +0,0 @@
-[
-{
-"size": 195, 
-"digest": "236362c71c433971c36b46d34e8560342435718364bc390df8de6a33249fb1fbf4fc3d0143f1e22bca262a7af7dc1b277a920bfde3ee8197eb07db2e7cef3e1f", 
-"algorithm": "sha512", 
-"filename": "setup.sh"
-}, 
-{
-"size": 63159127, 
-"digest": "fcf629c815b5cbed7858d7697815f355275dcc6b060ae5455b4b31fde0d78ebc176927564a5353ceacdb9f9c9bfc1357f1341bf6ba844c25153a89664e661510", 
-"algorithm": "sha512", 
-"filename": "gonk-toolchain-7.tar.bz2"
-}
-]
new file mode 100644
--- /dev/null
+++ b/b2g/config/tooltool-manifests/linux32/releng.manifest
@@ -0,0 +1,14 @@
+[
+{
+"size": 50,
+"digest": "48f405d8c2712838b9dd3be118951c8b41c63c891576f5287d2e05afa8fd051a08807511259581aa3170a3c4f7d4e77e6c0539b00b8f6845f01562127f6a27fa",
+"algorithm": "sha512",
+"filename": "setup.sh"
+},
+{
+"size": 160232,
+"digest": "8656c3fc2daa66839ec81a0edbd9759040a83c7a41c3e472d7f90508b80eefd008b87305dc8549b4ff6098dc33fe17fedc9b4eb76cf5307d5f22dae925c033db",
+"algorithm": "sha512",
+"filename": "sccache.tar.xz"
+}
+]
new file mode 100644
--- /dev/null
+++ b/b2g/config/tooltool-manifests/linux64/releng.manifest
@@ -0,0 +1,14 @@
+[
+{
+"size": 50,
+"digest": "48f405d8c2712838b9dd3be118951c8b41c63c891576f5287d2e05afa8fd051a08807511259581aa3170a3c4f7d4e77e6c0539b00b8f6845f01562127f6a27fa",
+"algorithm": "sha512",
+"filename": "setup.sh"
+},
+{
+"size": 160232,
+"digest": "8656c3fc2daa66839ec81a0edbd9759040a83c7a41c3e472d7f90508b80eefd008b87305dc8549b4ff6098dc33fe17fedc9b4eb76cf5307d5f22dae925c033db",
+"algorithm": "sha512",
+"filename": "sccache.tar.xz"
+}
+]
deleted file mode 100644
--- a/b2g/config/tooltool-manifests/releng.manifest
+++ /dev/null
@@ -1,14 +0,0 @@
-[
-{
-"size": 195,
-"digest": "da2edcb1ec9b169f6c685d02ebd0bd4ad53ace2df58598f15e1bde43dd74bcb816620601587c97e636bda3327045b43c8f5e973672ebd904e06036f70466908f",
-"algorithm": "sha512",
-"filename": "setup.sh"
-},
-{
-"size": 121166734,
-"digest": "10da1d28d49ff1aa9ad3d84e52235dc8ed7df6721530b896a53424480ec23a2e9f28cadd631f562342325611ecb72152be51f9b62616356f33005f6cc0fb82fe",
-"algorithm": "sha512",
-"filename": "gonk-toolchain-3.tar.bz2"
-}
-]
--- a/browser/base/content/test/general/browser_bug435325.js
+++ b/browser/base/content/test/general/browser_bug435325.js
@@ -46,23 +46,27 @@ function test() {
 function checkPage() {
   ok(Services.io.offline, "Setting Services.io.offline to true.");
   is(gBrowser.contentDocument.documentURI.substring(0,27),
     "about:neterror?e=netOffline", "Loading the Offline mode neterror page.");
 
   // Now press the "Try Again" button
   ok(gBrowser.contentDocument.getElementById("errorTryAgain"),
     "The error page has got a #errorTryAgain element");
+
+  // Re-enable the proxy so example.com is resolved to localhost, rather than
+  // the actual example.com.
+  Services.prefs.setIntPref("network.proxy.type", proxyPrefValue);
+
   gBrowser.contentDocument.getElementById("errorTryAgain").click();
 
   ok(!Services.io.offline, "After clicking the Try Again button, we're back " +
                            "online.");
 
   finish();
 }
 
 registerCleanupFunction(function() {
-  Services.prefs.setIntPref("network.proxy.type", proxyPrefValue);
   Services.prefs.setBoolPref("browser.cache.disk.enable", true);
   Services.prefs.setBoolPref("browser.cache.memory.enable", true);
   Services.io.offline = false;
   gBrowser.removeCurrentTab();
 });
--- a/browser/config/mozconfigs/linux32/l10n-mozconfig
+++ b/browser/config/mozconfigs/linux32/l10n-mozconfig
@@ -1,9 +1,10 @@
 no_tooltool=1
+no_sccache=1
 
 ac_add_options --with-l10n-base=../../l10n
 ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
 ac_add_options --enable-update-packaging
 
 . $topsrcdir/build/unix/mozconfig.linux32
 
 export MOZILLA_OFFICIAL=1
--- a/browser/config/mozconfigs/linux32/valgrind
+++ b/browser/config/mozconfigs/linux32/valgrind
@@ -1,9 +1,10 @@
 no_tooltool=1
+no_sccache=1
 
 . $topsrcdir/browser/config/mozconfigs/linux32/nightly
 
 ac_add_options --enable-valgrind
 ac_add_options --disable-jemalloc
 ac_add_options --disable-elf-hack
 ac_add_options --enable-optimize="-g -O -freorder-blocks"
 ac_add_options --disable-install-strip
--- a/browser/config/mozconfigs/linux64/l10n-mozconfig
+++ b/browser/config/mozconfigs/linux64/l10n-mozconfig
@@ -1,9 +1,10 @@
 no_tooltool=1
+no_sccache=1
 
 ac_add_options --with-l10n-base=../../l10n
 ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
 ac_add_options --enable-update-packaging
 
 . $topsrcdir/build/unix/mozconfig.linux
 
 export MOZILLA_OFFICIAL=1
--- a/browser/config/mozconfigs/linux64/valgrind
+++ b/browser/config/mozconfigs/linux64/valgrind
@@ -1,9 +1,10 @@
 no_tooltool=1
+no_sccache=1
 
 . $topsrcdir/browser/config/mozconfigs/linux64/nightly
 
 ac_add_options --enable-valgrind
 ac_add_options --disable-jemalloc
 ac_add_options --disable-elf-hack
 ac_add_options --enable-optimize="-g -O -freorder-blocks"
 ac_add_options --disable-install-strip
--- a/build/mozconfig.cache
+++ b/build/mozconfig.cache
@@ -4,17 +4,17 @@
 
 # Setup for build cache
 
 read branch platform master <<EOF
 $(python2.7 -c 'import json; p = json.loads(open("'"$topsrcdir"'/../buildprops.json").read())["properties"]; print p["branch"], p["platform"], p["master"]' 2> /dev/null)
 EOF
 
 bucket=
-if test -z "$SCCACHE_DISABLE" -a -z "$no_tooltool"; then
+if test -z "$SCCACHE_DISABLE" -a -z "$no_sccache"; then
     case "${branch}_${master}" in
     try_*scl1.mozilla.com*|try_*.scl3.mozilla.com*)
         bucket=mozilla-releng-ceph-cache-scl3-try
         mk_add_options "export SCCACHE_NO_HTTPS=1"
         ;;
     try_*use1.mozilla.com*)
         bucket=mozilla-releng-s3-cache-us-east-1-try
         ;;
--- a/content/base/src/nsGkAtomList.h
+++ b/content/base/src/nsGkAtomList.h
@@ -993,16 +993,17 @@ GK_ATOM(setcookie, "set-cookie")
 GK_ATOM(setter, "setter")
 GK_ATOM(shape, "shape")
 GK_ATOM(show, "show")
 GK_ATOM(showcaret, "showcaret")
 GK_ATOM(showresizer, "showresizer")
 GK_ATOM(simple, "simple")
 GK_ATOM(single, "single")
 GK_ATOM(size, "size")
+GK_ATOM(sizes, "sizes")
 GK_ATOM(sizemode, "sizemode")
 GK_ATOM(sizetopopup, "sizetopopup")
 GK_ATOM(slider, "slider")
 GK_ATOM(small, "small")
 GK_ATOM(smooth, "smooth")
 GK_ATOM(snap, "snap")
 GK_ATOM(sort, "sort")
 GK_ATOM(sortActive, "sortActive")
--- a/content/canvas/public/moz.build
+++ b/content/canvas/public/moz.build
@@ -6,17 +6,16 @@
 
 XPIDL_SOURCES += [
     'nsICanvasGLPrivate.idl',
 ]
 
 XPIDL_MODULE = 'content_canvas'
 
 EXPORTS += [
-    'nsICanvasElementExternal.h',
     'nsICanvasRenderingContextInternal.h',
 ]
 
 EXPORTS.mozilla.ipc += [
     'DocumentRendererChild.h',
     'DocumentRendererParent.h',
 ]
 
deleted file mode 100644
--- a/content/canvas/public/nsICanvasElementExternal.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/* -*- Mode: C++; tab-width: 40; 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 nsICanvasElementExternal_h___
-#define nsICanvasElementExternal_h___
-
-#include "nsISupports.h"
-#include "GraphicsFilter.h"
-
-class gfxContext;
-class nsIFrame;
-struct gfxRect;
-
-#define NS_ICANVASELEMENTEXTERNAL_IID \
-  { 0x51870f54, 0x6c4c, 0x469a, {0xad, 0x46, 0xf0, 0xa9, 0x8e, 0x32, 0xa7, 0xe2 } }
-
-class nsRenderingContext;
-class nsICanvasRenderingContextInternal;
-
-struct _cairo_surface;
-
-/*
- * This interface contains methods that are needed outside of the content/layout
- * modules, specifically widget.  It should eventually go away when we support
- * libxul builds, and HTMLCanvasElement be used directly.
- *
- * Code internal to content/layout should /never/ use this interface; if the
- * same functionality is needed in both places, two separate methods should be
- * used.
- */
-
-class nsICanvasElementExternal : public nsISupports {
-public:
-  NS_DECLARE_STATIC_IID_ACCESSOR(NS_ICANVASELEMENTEXTERNAL_IID)
-
-  enum {
-    RenderFlagPremultAlpha = 0x1
-  };
-
-  /**
-   * Get the size in pixels of this canvas element
-   */
-  NS_IMETHOD_(nsIntSize) GetSizeExternal() = 0;
-
-  /*
-   * Ask the canvas element to tell the contexts to render themselves
-   * to the given gfxContext at the origin of its coordinate space.
-   */
-  NS_IMETHOD RenderContextsExternal(gfxContext *ctx,
-                                    GraphicsFilter aFilter,
-                                    uint32_t aFlags = RenderFlagPremultAlpha) = 0;
-};
-
-NS_DEFINE_STATIC_IID_ACCESSOR(nsICanvasElementExternal, NS_ICANVASELEMENTEXTERNAL_IID)
-
-#endif /* nsICanvasElementExternal_h___ */
--- a/content/canvas/public/nsICanvasRenderingContextInternal.h
+++ b/content/canvas/public/nsICanvasRenderingContextInternal.h
@@ -1,26 +1,27 @@
 /* -*- Mode: C++; tab-width: 40; 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 nsICanvasRenderingContextInternal_h___
 #define nsICanvasRenderingContextInternal_h___
 
+#include "mozilla/gfx/2D.h"
 #include "nsISupports.h"
 #include "nsIInputStream.h"
 #include "nsIDocShell.h"
 #include "mozilla/dom/HTMLCanvasElement.h"
 #include "GraphicsFilter.h"
 #include "mozilla/RefPtr.h"
 
 #define NS_ICANVASRENDERINGCONTEXTINTERNAL_IID \
-{ 0x9a6a5bdf, 0x1261, 0x4057, \
-  { 0x85, 0xcc, 0xaf, 0x97, 0x6c, 0x36, 0x99, 0xa9 } }
+{ 0x3cc9e801, 0x1806, 0x4ff6, \
+  { 0x86, 0x14, 0xf9, 0xd0, 0xf4, 0xfb, 0x3b, 0x08 } }
 
 class gfxContext;
 class gfxASurface;
 class nsDisplayListBuilder;
 
 namespace mozilla {
 namespace layers {
 class CanvasLayer;
@@ -36,20 +37,16 @@ class SourceSurface;
 
 class nsICanvasRenderingContextInternal : public nsISupports {
 public:
   typedef mozilla::layers::CanvasLayer CanvasLayer;
   typedef mozilla::layers::LayerManager LayerManager;
 
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_ICANVASRENDERINGCONTEXTINTERNAL_IID)
 
-  enum {
-    RenderFlagPremultAlpha = 0x1
-  };
-
   void SetCanvasElement(mozilla::dom::HTMLCanvasElement* aParentCanvas)
   {
     mCanvasElement = aParentCanvas;
   }
   mozilla::dom::HTMLCanvasElement* GetParentObject() const
   {
     return mCanvasElement;
   }
@@ -61,41 +58,35 @@ public:
 #endif
 
   // Sets the dimensions of the canvas, in pixels.  Called
   // whenever the size of the element changes.
   NS_IMETHOD SetDimensions(int32_t width, int32_t height) = 0;
 
   NS_IMETHOD InitializeWithSurface(nsIDocShell *docShell, gfxASurface *surface, int32_t width, int32_t height) = 0;
 
-  // Render the canvas at the origin of the given gfxContext
-  NS_IMETHOD Render(gfxContext *ctx,
-                    GraphicsFilter aFilter,
-                    uint32_t aFlags = RenderFlagPremultAlpha) = 0;
-
   // Creates an image buffer. Returns null on failure.
   virtual void GetImageBuffer(uint8_t** aImageBuffer, int32_t* aFormat) = 0;
 
   // Gives you a stream containing the image represented by this context.
   // The format is given in aMimeTime, for example "image/png".
   //
   // If the image format does not support transparency or aIncludeTransparency
   // is false, alpha will be discarded and the result will be the image
   // composited on black.
   NS_IMETHOD GetInputStream(const char *aMimeType,
                             const char16_t *aEncoderOptions,
                             nsIInputStream **aStream) = 0;
-
-  // If this canvas context can be represented with a simple Thebes surface,
-  // return the surface.  Otherwise returns an error.
-  NS_IMETHOD GetThebesSurface(gfxASurface **surface) = 0;
   
   // This gets an Azure SourceSurface for the canvas, this will be a snapshot
   // of the canvas at the time it was called.
-  virtual mozilla::TemporaryRef<mozilla::gfx::SourceSurface> GetSurfaceSnapshot() = 0;
+  // If aPremultAlpha is provided, then it assumed the callee can handle
+  // un-premultiplied surfaces, and *aPremultAlpha will be set to false
+  // if one is returned.
+  virtual mozilla::TemporaryRef<mozilla::gfx::SourceSurface> GetSurfaceSnapshot(bool* aPremultAlpha = nullptr) = 0;
 
   // If this context is opaque, the backing store of the canvas should
   // be created as opaque; all compositing operators should assume the
   // dst alpha is always 1.0.  If this is never called, the context
   // defaults to false (not opaque).
   NS_IMETHOD SetIsOpaque(bool isOpaque) = 0;
   virtual bool GetIsOpaque() = 0;
 
--- a/content/canvas/src/CanvasRenderingContext2D.cpp
+++ b/content/canvas/src/CanvasRenderingContext2D.cpp
@@ -1049,61 +1049,16 @@ CanvasRenderingContext2D::SetIsIPC(bool 
     mIPC = isIPC;
     ClearTarget();
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
-CanvasRenderingContext2D::Render(gfxContext *ctx, GraphicsFilter aFilter, uint32_t aFlags)
-{
-  nsresult rv = NS_OK;
-
-  EnsureTarget();
-  if (!IsTargetValid()) {
-    return NS_ERROR_FAILURE;
-  }
-
-  nsRefPtr<gfxASurface> surface;
-
-  if (NS_FAILED(GetThebesSurface(getter_AddRefs(surface)))) {
-    return NS_ERROR_FAILURE;
-  }
-
-  nsRefPtr<gfxPattern> pat = new gfxPattern(surface);
-
-  pat->SetFilter(aFilter);
-  pat->SetExtend(gfxPattern::EXTEND_PAD);
-
-  gfxContext::GraphicsOperator op = ctx->CurrentOperator();
-  if (mOpaque)
-      ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
-
-  // XXX I don't want to use PixelSnapped here, but layout doesn't guarantee
-  // pixel alignment for this stuff!
-  ctx->NewPath();
-  ctx->PixelSnappedRectangleAndSetPattern(gfxRect(0, 0, mWidth, mHeight), pat);
-  ctx->Fill();
-
-  if (mOpaque)
-      ctx->SetOperator(op);
-
-  if (!(aFlags & RenderFlagPremultAlpha)) {
-      nsRefPtr<gfxASurface> curSurface = ctx->CurrentSurface();
-      nsRefPtr<gfxImageSurface> gis = curSurface->GetAsImageSurface();
-      MOZ_ASSERT(gis, "If non-premult alpha, must be able to get image surface!");
-
-      gfxUtils::UnpremultiplyImageSurface(gis);
-  }
-
-  return rv;
-}
-
-NS_IMETHODIMP
 CanvasRenderingContext2D::SetContextOptions(JSContext* aCx, JS::Handle<JS::Value> aOptions)
 {
   if (aOptions.isNullOrUndefined()) {
     return NS_OK;
   }
 
   ContextAttributes2D attributes;
   NS_ENSURE_TRUE(attributes.Init(aCx, aOptions), NS_ERROR_UNEXPECTED);
@@ -3261,38 +3216,16 @@ CanvasRenderingContext2D::DrawImage(cons
   if (image.IsHTMLCanvasElement()) {
     HTMLCanvasElement* canvas = &image.GetAsHTMLCanvasElement();
     element = canvas;
     nsIntSize size = canvas->GetSize();
     if (size.width == 0 || size.height == 0) {
       error.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
       return;
     }
-
-    // Special case for Canvas, which could be an Azure canvas!
-    nsICanvasRenderingContextInternal *srcCanvas = canvas->GetContextAtIndex(0);
-    if (srcCanvas == this) {
-      // Self-copy.
-      srcSurf = mTarget->Snapshot();
-      imgSize = gfxIntSize(mWidth, mHeight);
-    } else if (srcCanvas) {
-      // This might not be an Azure canvas!
-      srcSurf = srcCanvas->GetSurfaceSnapshot();
-
-      if (srcSurf) {
-        if (mCanvasElement) {
-          // Do security check here.
-          CanvasUtils::DoDrawImageSecurityCheck(mCanvasElement,
-                                                element->NodePrincipal(),
-                                                canvas->IsWriteOnly(),
-                                                false);
-        }
-        imgSize = gfxIntSize(srcSurf->GetSize().width, srcSurf->GetSize().height);
-      }
-    }
   } else {
     if (image.IsHTMLImageElement()) {
       HTMLImageElement* img = &image.GetAsHTMLImageElement();
       element = img;
     } else {
       HTMLVideoElement* video = &image.GetAsHTMLVideoElement();
       element = video;
     }
@@ -4142,37 +4075,16 @@ CanvasRenderingContext2D::PutImageData_e
                                dirtyRect.width, dirtyRect.height),
                        IntPoint(dirtyRect.x, dirtyRect.y));
 
   Redraw(mgfx::Rect(dirtyRect.x, dirtyRect.y, dirtyRect.width, dirtyRect.height));
 
   return NS_OK;
 }
 
-NS_IMETHODIMP
-CanvasRenderingContext2D::GetThebesSurface(gfxASurface **surface)
-{
-  EnsureTarget();
-  if (!IsTargetValid()) {
-    return NS_ERROR_FAILURE;
-  }
-
-  nsRefPtr<gfxASurface> thebesSurface =
-      gfxPlatform::GetPlatform()->GetThebesSurfaceForDrawTarget(mTarget);
-
-  if (!thebesSurface) {
-    return NS_ERROR_FAILURE;
-  }
-
-  *surface = thebesSurface;
-  NS_ADDREF(*surface);
-
-  return NS_OK;
-}
-
 static already_AddRefed<ImageData>
 CreateImageData(JSContext* cx, CanvasRenderingContext2D* context,
                 uint32_t w, uint32_t h, ErrorResult& error)
 {
   if (w == 0)
       w = 1;
   if (h == 0)
       h = 1;
--- a/content/canvas/src/CanvasRenderingContext2D.h
+++ b/content/canvas/src/CanvasRenderingContext2D.h
@@ -452,26 +452,28 @@ public:
 #ifdef DEBUG
     virtual int32_t GetWidth() const MOZ_OVERRIDE;
     virtual int32_t GetHeight() const MOZ_OVERRIDE;
 #endif
   // nsICanvasRenderingContextInternal
   NS_IMETHOD SetDimensions(int32_t width, int32_t height) MOZ_OVERRIDE;
   NS_IMETHOD InitializeWithSurface(nsIDocShell *shell, gfxASurface *surface, int32_t width, int32_t height) MOZ_OVERRIDE;
 
-  NS_IMETHOD Render(gfxContext *ctx,
-                    GraphicsFilter aFilter,
-                    uint32_t aFlags = RenderFlagPremultAlpha) MOZ_OVERRIDE;
   NS_IMETHOD GetInputStream(const char* aMimeType,
                             const char16_t* aEncoderOptions,
                             nsIInputStream **aStream) MOZ_OVERRIDE;
-  NS_IMETHOD GetThebesSurface(gfxASurface **surface) MOZ_OVERRIDE;
 
-  mozilla::TemporaryRef<mozilla::gfx::SourceSurface> GetSurfaceSnapshot() MOZ_OVERRIDE
-  { EnsureTarget(); return mTarget->Snapshot(); }
+  mozilla::TemporaryRef<mozilla::gfx::SourceSurface> GetSurfaceSnapshot(bool* aPremultAlpha = nullptr) MOZ_OVERRIDE
+  {
+    EnsureTarget();
+    if (aPremultAlpha) {
+      *aPremultAlpha = true;
+    }
+    return mTarget->Snapshot();
+  }
 
   NS_IMETHOD SetIsOpaque(bool isOpaque) MOZ_OVERRIDE;
   bool GetIsOpaque() MOZ_OVERRIDE { return mOpaque; }
   NS_IMETHOD Reset() MOZ_OVERRIDE;
   already_AddRefed<CanvasLayer> GetCanvasLayer(nsDisplayListBuilder* aBuilder,
                                                CanvasLayer *aOldLayer,
                                                LayerManager *aManager) MOZ_OVERRIDE;
   virtual bool ShouldForceInactiveLayer(LayerManager *aManager) MOZ_OVERRIDE;
--- a/content/canvas/src/WebGLContext.cpp
+++ b/content/canvas/src/WebGLContext.cpp
@@ -131,35 +131,16 @@ WebGLContext::WebGLContext()
     mFakeVertexAttrib0BufferObjectVector[0] = 0;
     mFakeVertexAttrib0BufferObjectVector[1] = 0;
     mFakeVertexAttrib0BufferObjectVector[2] = 0;
     mFakeVertexAttrib0BufferObjectVector[3] = 1;
     mFakeVertexAttrib0BufferObjectSize = 0;
     mFakeVertexAttrib0BufferObject = 0;
     mFakeVertexAttrib0BufferStatus = WebGLVertexAttrib0Status::Default;
 
-    // these are de default values, see 6.2 State tables in the OpenGL ES 2.0.25 spec
-    mColorWriteMask[0] = 1;
-    mColorWriteMask[1] = 1;
-    mColorWriteMask[2] = 1;
-    mColorWriteMask[3] = 1;
-    mDepthWriteMask = 1;
-    mColorClearValue[0] = 0.f;
-    mColorClearValue[1] = 0.f;
-    mColorClearValue[2] = 0.f;
-    mColorClearValue[3] = 0.f;
-    mDepthClearValue = 1.f;
-    mStencilClearValue = 0;
-    mStencilRefFront = 0;
-    mStencilRefBack = 0;
-    mStencilValueMaskFront = 0xffffffff;
-    mStencilValueMaskBack  = 0xffffffff;
-    mStencilWriteMaskFront = 0xffffffff;
-    mStencilWriteMaskBack  = 0xffffffff;
-
     mViewportX = 0;
     mViewportY = 0;
     mViewportWidth = 0;
     mViewportHeight = 0;
 
     mScissorTestEnabled = 0;
     mDitherEnabled = 1;
     mRasterizerDiscardEnabled = 0; // OpenGL ES 3.0 spec p244
@@ -204,17 +185,17 @@ WebGLContext::WebGLContext()
         GenerateWarning("webgl.max-warnings-per-context size is too large (seems like a negative value wrapped)");
         mMaxWarnings = 0;
     }
 
     mLastUseIndex = 0;
 
     InvalidateBufferFetching();
 
-    mIsScreenCleared = false;
+    mBackbufferNeedsClear = true;
 
     mDisableFragHighP = false;
 
     mDrawCallsSinceLastFlush = 0;
 }
 
 WebGLContext::~WebGLContext()
 {
@@ -418,17 +399,17 @@ WebGLContext::SetDimensions(int32_t widt
         gl->ResizeOffscreen(gfx::IntSize(width, height)); // Doesn't matter if it succeeds (soft-fail)
         // It's unlikely that we'll get a proper-sized context if we recreate if we didn't on resize
 
         // everything's good, we're done here
         mWidth = gl->OffscreenSize().width;
         mHeight = gl->OffscreenSize().height;
         mResetLayer = true;
 
-        ClearScreen();
+        mBackbufferNeedsClear = true;
 
         return NS_OK;
     }
 
     // End of early return cases.
     // At this point we know that we're not just resizing an existing context,
     // we are initializing a new context.
 
@@ -605,71 +586,52 @@ WebGLContext::SetDimensions(int32_t widt
     // Make sure that we clear this out, otherwise
     // we'll end up displaying random memory
     gl->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, 0);
 
     gl->fClearColor(0.0f, 0.0f, 0.0f, 0.0f);
     gl->fClearDepth(1.0f);
     gl->fClearStencil(0);
 
-    gl->ClearSafely();
+    mBackbufferNeedsClear = true;
+
+    // Clear immediately, because we need to present the cleared initial
+    // buffer.
+    ClearBackbufferIfNeeded();
 
     mShouldPresent = true;
 
     MOZ_ASSERT(gl->Caps().color == caps.color);
     MOZ_ASSERT(gl->Caps().alpha == caps.alpha);
     MOZ_ASSERT(gl->Caps().depth == caps.depth || !gl->Caps().depth);
     MOZ_ASSERT(gl->Caps().stencil == caps.stencil || !gl->Caps().stencil);
     MOZ_ASSERT(gl->Caps().antialias == caps.antialias || !gl->Caps().antialias);
     MOZ_ASSERT(gl->Caps().preserve == caps.preserve);
 
     reporter.SetSuccessful();
     return NS_OK;
 }
 
-NS_IMETHODIMP
-WebGLContext::Render(gfxContext *ctx, GraphicsFilter f, uint32_t aFlags)
+void
+WebGLContext::ClearBackbufferIfNeeded()
 {
-    if (!gl)
-        return NS_OK;
+    if (!mBackbufferNeedsClear)
+        return;
 
-    nsRefPtr<gfxImageSurface> surf = new gfxImageSurface(gfxIntSize(mWidth, mHeight),
-                                                         gfxImageFormat::ARGB32);
-    if (surf->CairoStatus() != 0)
-        return NS_ERROR_FAILURE;
-
+#ifdef DEBUG
     gl->MakeCurrent();
-    ReadScreenIntoImageSurface(gl, surf);
-
-    bool srcPremultAlpha = mOptions.premultipliedAlpha;
-    bool dstPremultAlpha = aFlags & RenderFlagPremultAlpha;
 
-    if (!srcPremultAlpha && dstPremultAlpha) {
-        gfxUtils::PremultiplyImageSurface(surf);
-    } else if (srcPremultAlpha && !dstPremultAlpha) {
-        gfxUtils::UnpremultiplyImageSurface(surf);
-    }
-    surf->MarkDirty();
-
-    nsRefPtr<gfxPattern> pat = new gfxPattern(surf);
-    pat->SetFilter(f);
+    GLuint fb = 0;
+    gl->GetUIntegerv(LOCAL_GL_FRAMEBUFFER_BINDING, &fb);
+    MOZ_ASSERT(fb == 0);
+#endif
 
-    // Pixels from ReadPixels will be "upside down" compared to
-    // what cairo wants, so draw with a y-flip and a translte to
-    // flip them.
-    gfxMatrix m;
-    m.Translate(gfxPoint(0.0, mHeight));
-    m.Scale(1.0, -1.0);
-    pat->SetMatrix(m);
+    ClearScreen();
 
-    ctx->NewPath();
-    ctx->PixelSnappedRectangleAndSetPattern(gfxRect(0, 0, mWidth, mHeight), pat);
-    ctx->Fill();
-
-    return NS_OK;
+    mBackbufferNeedsClear = false;
 }
 
 void WebGLContext::LoseOldestWebGLContextIfLimitExceeded()
 {
 #ifdef MOZ_GFX_OPTIMIZE_MOBILE
     // some mobile devices can't have more than 8 GL contexts overall
     const size_t kMaxWebGLContextsPerPrincipal = 2;
     const size_t kMaxWebGLContexts             = 4;
@@ -753,54 +715,53 @@ void WebGLContext::LoseOldestWebGLContex
 }
 
 void
 WebGLContext::GetImageBuffer(uint8_t** aImageBuffer, int32_t* aFormat)
 {
     *aImageBuffer = nullptr;
     *aFormat = 0;
 
-    nsRefPtr<gfxImageSurface> imgsurf =
-        new gfxImageSurface(gfxIntSize(mWidth, mHeight),
-                            gfxImageFormat::ARGB32);
+    // Use GetSurfaceSnapshot() to make sure that appropriate y-flip gets applied
+    bool premult;
+    RefPtr<SourceSurface> snapshot =
+      GetSurfaceSnapshot(mOptions.premultipliedAlpha ? nullptr : &premult);
+    if (!snapshot) {
+        return;
+    }
+    MOZ_ASSERT(mOptions.premultipliedAlpha || !premult, "We must get unpremult when we ask for it!");
 
-    if (!imgsurf || imgsurf->CairoStatus()) {
+    RefPtr<DataSourceSurface> dataSurface = snapshot->GetDataSurface();
+
+    DataSourceSurface::MappedSurface map;
+    if (!dataSurface->Map(DataSourceSurface::MapType::READ, &map)) {
         return;
     }
 
-    nsRefPtr<gfxContext> ctx = new gfxContext(imgsurf);
-    if (!ctx || ctx->HasError()) {
+    static const fallible_t fallible = fallible_t();
+    uint8_t* imageBuffer = new (fallible) uint8_t[mWidth * mHeight * 4];
+    if (!imageBuffer) {
+        dataSurface->Unmap();
         return;
     }
+    memcpy(imageBuffer, map.mData, mWidth * mHeight * 4);
 
-    // Use Render() to make sure that appropriate y-flip gets applied
-    uint32_t flags = mOptions.premultipliedAlpha ? RenderFlagPremultAlpha : 0;
-    nsresult rv = Render(ctx, GraphicsFilter::FILTER_NEAREST, flags);
-    if (NS_FAILED(rv)) {
-        return;
-    }
+    dataSurface->Unmap();
 
     int32_t format = imgIEncoder::INPUT_FORMAT_HOSTARGB;
     if (!mOptions.premultipliedAlpha) {
         // We need to convert to INPUT_FORMAT_RGBA, otherwise
         // we are automatically considered premult, and unpremult'd.
         // Yes, it is THAT silly.
         // Except for different lossy conversions by color,
         // we could probably just change the label, and not change the data.
-        gfxUtils::ConvertBGRAtoRGBA(imgsurf);
+        gfxUtils::ConvertBGRAtoRGBA(imageBuffer, mWidth * mHeight * 4);
         format = imgIEncoder::INPUT_FORMAT_RGBA;
     }
 
-    static const fallible_t fallible = fallible_t();
-    uint8_t* imageBuffer = new (fallible) uint8_t[mWidth * mHeight * 4];
-    if (!imageBuffer) {
-        return;
-    }
-    memcpy(imageBuffer, imgsurf->Data(), mWidth * mHeight * 4);
-
     *aImageBuffer = imageBuffer;
     *aFormat = format;
 }
 
 NS_IMETHODIMP
 WebGLContext::GetInputStream(const char* aMimeType,
                              const char16_t* aEncoderOptions,
                              nsIInputStream **aStream)
@@ -822,22 +783,16 @@ WebGLContext::GetInputStream(const char*
     if (!imageBuffer) {
         return NS_ERROR_FAILURE;
     }
 
     return ImageEncoder::GetInputStream(mWidth, mHeight, imageBuffer, format,
                                         encoder, aEncoderOptions, aStream);
 }
 
-NS_IMETHODIMP
-WebGLContext::GetThebesSurface(gfxASurface **surface)
-{
-    return NS_ERROR_NOT_AVAILABLE;
-}
-
 void WebGLContext::UpdateLastUseIndex()
 {
     static CheckedInt<uint64_t> sIndex = 0;
 
     sIndex++;
 
     // should never happen with 64-bit; trying to handle this would be riskier than
     // not handling it as the handler code would never get exercised.
@@ -1009,17 +964,16 @@ WebGLContext::ClearScreen()
     if (mOptions.depth)
         clearMask |= LOCAL_GL_DEPTH_BUFFER_BIT;
     if (mOptions.stencil)
         clearMask |= LOCAL_GL_STENCIL_BUFFER_BIT;
 
     colorAttachmentsMask[0] = true;
 
     ForceClearFramebufferWithDefaultValues(clearMask, colorAttachmentsMask);
-    mIsScreenCleared = true;
 }
 
 #ifdef DEBUG
 // For NaNs, etc.
 static bool IsShadowCorrect(float shadow, float actual) {
     if (IsNaN(shadow)) {
         // GL is allowed to do anything it wants for NaNs, so if we're shadowing
         // a NaN, then whatever `actual` is might be correct.
@@ -1197,23 +1151,24 @@ WebGLContext::PresentScreenBuffer()
         return false;
     }
 
     if (!mShouldPresent) {
         return false;
     }
 
     gl->MakeCurrent();
+    MOZ_ASSERT(!mBackbufferNeedsClear);
     if (!gl->PublishFrame()) {
         this->ForceLoseContext();
         return false;
     }
 
     if (!mOptions.preserveDrawingBuffer) {
-        ClearScreen();
+        mBackbufferNeedsClear = true;
     }
 
     mShouldPresent = false;
 
     return true;
 }
 
 void
@@ -1371,19 +1326,71 @@ WebGLContext::ForceRestoreContext()
 {
     mContextStatus = ContextLostAwaitingRestore;
 }
 
 void
 WebGLContext::MakeContextCurrent() const { gl->MakeCurrent(); }
 
 mozilla::TemporaryRef<mozilla::gfx::SourceSurface>
-WebGLContext::GetSurfaceSnapshot()
+WebGLContext::GetSurfaceSnapshot(bool* aPremultAlpha)
 {
-  return nullptr;
+    if (!gl)
+        return nullptr;
+
+    nsRefPtr<gfxImageSurface> surf = new gfxImageSurface(gfxIntSize(mWidth, mHeight),
+                                                         gfxImageFormat::ARGB32,
+                                                         mWidth * 4, 0, false);
+    if (surf->CairoStatus() != 0) {
+        return nullptr;
+    }
+
+    gl->MakeCurrent();
+    {
+        ScopedBindFramebuffer autoFB(gl, 0);
+        ClearBackbufferIfNeeded();
+        ReadPixelsIntoImageSurface(gl, surf);
+    }
+
+    if (aPremultAlpha) {
+        *aPremultAlpha = true;
+    }
+    bool srcPremultAlpha = mOptions.premultipliedAlpha;
+    if (!srcPremultAlpha) {
+        if (aPremultAlpha) {
+            *aPremultAlpha = false;
+        } else {
+            gfxUtils::PremultiplyImageSurface(surf);
+            surf->MarkDirty();
+        }
+    }
+
+    RefPtr<DrawTarget> dt =
+        Factory::CreateDrawTarget(BackendType::CAIRO,
+                                  IntSize(mWidth, mHeight),
+                                  SurfaceFormat::B8G8R8A8);
+
+    if (!dt) {
+        return nullptr;
+    }
+
+    RefPtr<SourceSurface> source = gfxPlatform::GetPlatform()->GetSourceSurfaceForSurface(dt, surf);
+
+    Matrix m;
+    m.Translate(0.0, mHeight);
+    m.Scale(1.0, -1.0);
+    dt->SetTransform(m);
+
+    dt->DrawSurface(source,
+                    Rect(0, 0, mWidth, mHeight),
+                    Rect(0, 0, mWidth, mHeight),
+                    DrawSurfaceOptions(),
+                    DrawOptions(1.0f, CompositionOp::OP_SOURCE));
+
+    return dt->Snapshot();
 }
 
 //
 // XPCOM goop
 //
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(WebGLContext)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(WebGLContext)
--- a/content/canvas/src/WebGLContext.h
+++ b/content/canvas/src/WebGLContext.h
@@ -160,25 +160,21 @@ public:
     virtual int32_t GetWidth() const MOZ_OVERRIDE;
     virtual int32_t GetHeight() const MOZ_OVERRIDE;
 #endif
     NS_IMETHOD SetDimensions(int32_t width, int32_t height) MOZ_OVERRIDE;
     NS_IMETHOD InitializeWithSurface(nsIDocShell *docShell, gfxASurface *surface, int32_t width, int32_t height) MOZ_OVERRIDE
         { return NS_ERROR_NOT_IMPLEMENTED; }
     NS_IMETHOD Reset() MOZ_OVERRIDE
         { /* (InitializeWithSurface) */ return NS_ERROR_NOT_IMPLEMENTED; }
-    NS_IMETHOD Render(gfxContext *ctx,
-                      GraphicsFilter f,
-                      uint32_t aFlags = RenderFlagPremultAlpha) MOZ_OVERRIDE;
     virtual void GetImageBuffer(uint8_t** aImageBuffer, int32_t* aFormat);
     NS_IMETHOD GetInputStream(const char* aMimeType,
                               const char16_t* aEncoderOptions,
                               nsIInputStream **aStream) MOZ_OVERRIDE;
-    NS_IMETHOD GetThebesSurface(gfxASurface **surface) MOZ_OVERRIDE;
-    mozilla::TemporaryRef<mozilla::gfx::SourceSurface> GetSurfaceSnapshot() MOZ_OVERRIDE;
+    mozilla::TemporaryRef<mozilla::gfx::SourceSurface> GetSurfaceSnapshot(bool* aPremultAlpha) MOZ_OVERRIDE;
 
     NS_IMETHOD SetIsOpaque(bool b) MOZ_OVERRIDE { return NS_OK; };
     bool GetIsOpaque() MOZ_OVERRIDE { return false; }
     NS_IMETHOD SetContextOptions(JSContext* aCx,
                                  JS::Handle<JS::Value> aOptions) MOZ_OVERRIDE;
 
     NS_IMETHOD SetIsIPC(bool b) MOZ_OVERRIDE { return NS_ERROR_NOT_IMPLEMENTED; }
     NS_IMETHOD Redraw(const gfxRect&) { return NS_ERROR_NOT_IMPLEMENTED; }
@@ -238,16 +234,17 @@ public:
     // This is similar to GLContext::ClearSafely, but tries to minimize the
     // amount of work it does.
     // It only clears the buffers we specify, and can reset its state without
     // first having to query anything, as WebGL knows its state at all times.
     void ForceClearFramebufferWithDefaultValues(GLbitfield mask, const bool colorAttachmentsMask[sMaxColorAttachments]);
 
     // Calls ForceClearFramebufferWithDefaultValues() for the Context's 'screen'.
     void ClearScreen();
+    void ClearBackbufferIfNeeded();
 
     bool MinCapabilityMode() const { return mMinCapability; }
 
     void RobustnessTimerCallback(nsITimer* timer);
     static void RobustnessTimerCallbackStatic(nsITimer* timer, void *thisPointer);
     void SetupContextLossTimer();
     void TerminateContextLossTimer();
 
@@ -836,17 +833,17 @@ protected:
     bool mOptionsFrozen;
     bool mMinCapability;
     bool mDisableExtensions;
     bool mHasRobustness;
     bool mIsMesa;
     bool mLoseContextOnHeapMinimize;
     bool mCanLoseContextInForeground;
     bool mShouldPresent;
-    bool mIsScreenCleared;
+    bool mBackbufferNeedsClear;
     bool mDisableFragHighP;
 
     template<typename WebGLObjectType>
     void DeleteWebGLObjectsArray(nsTArray<WebGLObjectType>& array);
 
     GLuint mActiveTexture;
 
     // glGetError sources:
@@ -1029,17 +1026,17 @@ protected:
     nsLayoutUtils::SurfaceFromElementResult SurfaceFromElement(ElementType* aElement) {
         MOZ_ASSERT(aElement);
         uint32_t flags =
              nsLayoutUtils::SFE_WANT_IMAGE_SURFACE;
 
         if (mPixelStoreColorspaceConversion == LOCAL_GL_NONE)
             flags |= nsLayoutUtils::SFE_NO_COLORSPACE_CONVERSION;
         if (!mPixelStorePremultiplyAlpha)
-            flags |= nsLayoutUtils::SFE_NO_PREMULTIPLY_ALPHA;
+            flags |= nsLayoutUtils::SFE_PREFER_NO_PREMULTIPLY_ALPHA;
         return nsLayoutUtils::SurfaceFromElement(aElement, flags);
     }
     template<class ElementType>
     nsLayoutUtils::SurfaceFromElementResult SurfaceFromElement(ElementType& aElement)
     {
       return SurfaceFromElement(&aElement);
     }
 
--- a/content/canvas/src/WebGLContextDraw.cpp
+++ b/content/canvas/src/WebGLContextDraw.cpp
@@ -98,16 +98,18 @@ bool WebGLContext::DrawArrays_check(GLin
 
     MakeContextCurrent();
 
     if (mBoundFramebuffer) {
         if (!mBoundFramebuffer->CheckAndInitializeAttachments()) {
             ErrorInvalidFramebufferOperation("%s: incomplete framebuffer", info);
             return false;
         }
+    } else {
+        ClearBackbufferIfNeeded();
     }
 
     if (!DoFakeVertexAttrib0(checked_firstPlusCount.value())) {
         return false;
     }
     BindFakeBlackTextures();
 
     return true;
@@ -259,16 +261,18 @@ WebGLContext::DrawElements_check(GLsizei
 
     MakeContextCurrent();
 
     if (mBoundFramebuffer) {
         if (!mBoundFramebuffer->CheckAndInitializeAttachments()) {
             ErrorInvalidFramebufferOperation("%s: incomplete framebuffer", info);
             return false;
         }
+    } else {
+        ClearBackbufferIfNeeded();
     }
 
     if (!DoFakeVertexAttrib0(mMaxFetchedVertices)) {
         return false;
     }
     BindFakeBlackTextures();
 
     return true;
@@ -328,17 +332,17 @@ WebGLContext::DrawElementsInstanced(GLen
 void WebGLContext::Draw_cleanup()
 {
     UndoFakeVertexAttrib0();
     UnbindFakeBlackTextures();
 
     if (!mBoundFramebuffer) {
         Invalidate();
         mShouldPresent = true;
-        mIsScreenCleared = false;
+        MOZ_ASSERT(!mBackbufferNeedsClear);
     }
 
     if (gl->WorkAroundDriverBugs()) {
         if (gl->Renderer() == gl::GLRenderer::Tegra) {
             mDrawCallsSinceLastFlush++;
 
             if (mDrawCallsSinceLastFlush >= MAX_DRAW_CALLS_SINCE_FLUSH) {
                 gl->fFlush();
--- a/content/canvas/src/WebGLContextFramebufferOperations.cpp
+++ b/content/canvas/src/WebGLContextFramebufferOperations.cpp
@@ -30,53 +30,23 @@ WebGLContext::Clear(GLbitfield mask)
     }
 
     if (mBoundFramebuffer) {
         if (!mBoundFramebuffer->CheckAndInitializeAttachments())
             return ErrorInvalidFramebufferOperation("clear: incomplete framebuffer");
 
         gl->fClear(mask);
         return;
+    } else {
+        ClearBackbufferIfNeeded();
     }
 
     // Ok, we're clearing the default framebuffer/screen.
 
-    bool needsClear = true;
-    if (mIsScreenCleared) {
-        bool isClearRedundant = true;
-        if (mask & LOCAL_GL_COLOR_BUFFER_BIT) {
-            if (mColorClearValue[0] != 0.0f ||
-                mColorClearValue[1] != 0.0f ||
-                mColorClearValue[2] != 0.0f ||
-                mColorClearValue[3] != 0.0f)
-            {
-                isClearRedundant = false;
-            }
-        }
-
-        if (mask & LOCAL_GL_DEPTH_BUFFER_BIT) {
-            if (mDepthClearValue != 1.0f) {
-                isClearRedundant = false;
-            }
-        }
-
-        if (mask & LOCAL_GL_DEPTH_BUFFER_BIT) {
-            if (mStencilClearValue != 0) {
-                isClearRedundant = false;
-            }
-        }
-
-        if (isClearRedundant)
-            needsClear = false;
-    }
-
-    if (needsClear) {
-        gl->fClear(mask);
-        mIsScreenCleared = false;
-    }
+    gl->fClear(mask);
 
     Invalidate();
     mShouldPresent = true;
 }
 
 static GLclampf
 GLClampFloat(GLclampf val)
 {
--- a/content/canvas/src/WebGLContextGL.cpp
+++ b/content/canvas/src/WebGLContextGL.cpp
@@ -24,16 +24,17 @@
 #include "gfxPlatform.h"
 #include "GLContext.h"
 
 #include "nsContentUtils.h"
 #include "nsError.h"
 #include "nsLayoutUtils.h"
 
 #include "CanvasUtils.h"
+#include "gfxUtils.h"
 
 #include "jsfriendapi.h"
 
 #include "WebGLTexelConversions.h"
 #include "WebGLValidateStrings.h"
 #include <algorithm>
 
 // needed to check if current OS is lower than 10.7
@@ -467,16 +468,18 @@ WebGLContext::CopyTexImage2D(GLenum targ
         if (!mBoundFramebuffer->CheckAndInitializeAttachments())
             return ErrorInvalidFramebufferOperation("copyTexImage2D: incomplete framebuffer");
 
         GLenum readPlaneBits = LOCAL_GL_COLOR_BUFFER_BIT;
         if (!mBoundFramebuffer->HasCompletePlanes(readPlaneBits)) {
             return ErrorInvalidOperation("copyTexImage2D: Read source attachment doesn't have the"
                                          " correct color/depth/stencil type.");
         }
+    } else {
+      ClearBackbufferIfNeeded();
     }
 
     bool texFormatRequiresAlpha = internalformat == LOCAL_GL_RGBA ||
                                   internalformat == LOCAL_GL_ALPHA ||
                                   internalformat == LOCAL_GL_LUMINANCE_ALPHA;
     bool fboFormatHasAlpha = mBoundFramebuffer ? mBoundFramebuffer->ColorAttachment(0).HasAlpha()
                                                : bool(gl->GetPixelFormat().alpha > 0);
     if (texFormatRequiresAlpha && !fboFormatHasAlpha)
@@ -579,16 +582,18 @@ WebGLContext::CopyTexSubImage2D(GLenum t
         if (!mBoundFramebuffer->CheckAndInitializeAttachments())
             return ErrorInvalidFramebufferOperation("copyTexSubImage2D: incomplete framebuffer");
 
         GLenum readPlaneBits = LOCAL_GL_COLOR_BUFFER_BIT;
         if (!mBoundFramebuffer->HasCompletePlanes(readPlaneBits)) {
             return ErrorInvalidOperation("copyTexSubImage2D: Read source attachment doesn't have the"
                                          " correct color/depth/stencil type.");
         }
+    } else {
+        ClearBackbufferIfNeeded();
     }
 
     bool texFormatRequiresAlpha = (internalFormat == LOCAL_GL_RGBA ||
                                    internalFormat == LOCAL_GL_ALPHA ||
                                    internalFormat == LOCAL_GL_LUMINANCE_ALPHA);
     bool fboFormatHasAlpha = mBoundFramebuffer ? mBoundFramebuffer->ColorAttachment(0).HasAlpha()
                                                : bool(gl->GetPixelFormat().alpha > 0);
 
@@ -2189,16 +2194,18 @@ WebGLContext::ReadPixels(GLint x, GLint 
         if (!mBoundFramebuffer->CheckAndInitializeAttachments())
             return ErrorInvalidFramebufferOperation("readPixels: incomplete framebuffer");
 
         GLenum readPlaneBits = LOCAL_GL_COLOR_BUFFER_BIT;
         if (!mBoundFramebuffer->HasCompletePlanes(readPlaneBits)) {
             return ErrorInvalidOperation("readPixels: Read source attachment doesn't have the"
                                          " correct color/depth/stencil type.");
         }
+    } else {
+      ClearBackbufferIfNeeded();
     }
     // Now that the errors are out of the way, on to actually reading
 
     // If we won't be reading any pixels anyways, just skip the actual reading
     if (width == 0 || height == 0)
         return DummyFramebufferOperation("readPixels");
 
     if (CanvasUtils::CheckSaneSubrectSize(x, y, width, height, framebufferWidth, framebufferHeight)) {
@@ -2516,16 +2523,20 @@ WebGLContext::SurfaceFromElementResultTo
     if (!res.mSourceSurface)
         return NS_OK;
     RefPtr<DataSourceSurface> data = res.mSourceSurface->GetDataSurface();
     if (!data) {
         // SurfaceFromElement lied!
         return NS_OK;
     }
 
+    if (!mPixelStorePremultiplyAlpha && res.mIsPremultiplied) {
+      data = gfxUtils::UnpremultiplyDataSurface(data);
+    }
+
     // We disallow loading cross-domain images and videos that have not been validated
     // with CORS as WebGL textures. The reason for doing that is that timing
     // attacks on WebGL shaders are able to retrieve approximations of the
     // pixel values in WebGL textures; see bug 655987.
     //
     // To prevent a loophole where a Canvas2D would be used as a proxy to load
     // cross-domain textures, we also disallow loading textures from write-only
     // Canvas2D's.
--- a/content/canvas/src/WebGLContextState.cpp
+++ b/content/canvas/src/WebGLContextState.cpp
@@ -75,19 +75,18 @@ WebGLContext::GetParameter(JSContext* cx
 {
     if (IsContextLost())
         return JS::NullValue();
 
     MakeContextCurrent();
 
     if (MinCapabilityMode()) {
         switch(pname) {
-            //
+            ////////////////////////////
             // Single-value params
-            //
 
             // int
             case LOCAL_GL_MAX_VERTEX_ATTRIBS:
                 return JS::Int32Value(MINVALUE_GL_MAX_VERTEX_ATTRIBS);
 
             case LOCAL_GL_MAX_FRAGMENT_UNIFORM_VECTORS:
                 return JS::Int32Value(MINVALUE_GL_MAX_FRAGMENT_UNIFORM_VECTORS);
 
@@ -113,28 +112,25 @@ WebGLContext::GetParameter(JSContext* cx
                 return JS::Int32Value(MINVALUE_GL_MAX_RENDERBUFFER_SIZE);
 
             default:
                 // Return the real value; we're not overriding this one
                 break;
         }
     }
 
-    if (IsExtensionEnabled(WEBGL_draw_buffers))
-    {
-        if (pname == LOCAL_GL_MAX_COLOR_ATTACHMENTS)
-        {
+    if (IsExtensionEnabled(WEBGL_draw_buffers)) {
+        if (pname == LOCAL_GL_MAX_COLOR_ATTACHMENTS) {
             return JS::Int32Value(mGLMaxColorAttachments);
-        }
-        else if (pname == LOCAL_GL_MAX_DRAW_BUFFERS)
-        {
+
+        } else if (pname == LOCAL_GL_MAX_DRAW_BUFFERS) {
             return JS::Int32Value(mGLMaxDrawBuffers);
-        }
-        else if (pname >= LOCAL_GL_DRAW_BUFFER0 &&
-                 pname < GLenum(LOCAL_GL_DRAW_BUFFER0 + mGLMaxDrawBuffers))
+
+        } else if (pname >= LOCAL_GL_DRAW_BUFFER0 &&
+                   pname < GLenum(LOCAL_GL_DRAW_BUFFER0 + mGLMaxDrawBuffers))
         {
             if (mBoundFramebuffer) {
                 GLint iv = 0;
                 gl->fGetIntegerv(pname, &iv);
                 return JS::Int32Value(iv);
             }
 
             GLint iv = 0;
@@ -144,77 +140,68 @@ WebGLContext::GetParameter(JSContext* cx
                 return JS::Int32Value(LOCAL_GL_BACK);
             }
 
             return JS::Int32Value(LOCAL_GL_NONE);
         }
     }
 
     if (IsExtensionEnabled(OES_vertex_array_object)) {
-        switch (pname) {
-
-            case LOCAL_GL_VERTEX_ARRAY_BINDING:
-            {
-                if (mBoundVertexArray == mDefaultVertexArray){
-                    return WebGLObjectAsJSValue(cx, (WebGLVertexArray *) nullptr, rv);
-                }
-
-                return WebGLObjectAsJSValue(cx, mBoundVertexArray.get(), rv);
+        if (pname == LOCAL_GL_VERTEX_ARRAY_BINDING) {
+            if (mBoundVertexArray == mDefaultVertexArray){
+                return WebGLObjectAsJSValue(cx, (WebGLVertexArray *) nullptr, rv);
             }
 
+            return WebGLObjectAsJSValue(cx, mBoundVertexArray.get(), rv);
         }
     }
 
     switch (pname) {
         //
         // String params
         //
         case LOCAL_GL_VENDOR:
             return StringValue(cx, "Mozilla", rv);
         case LOCAL_GL_RENDERER:
             return StringValue(cx, "Mozilla", rv);
-        case LOCAL_GL_VERSION:
-        {
+        case LOCAL_GL_VERSION: {
             const char* version = 0;
 
             if (IsWebGL2()) {
                 version = "WebGL 2.0";
             } else {
                 version = "WebGL 1.0";
             }
 
             MOZ_ASSERT(version != 0);
             return StringValue(cx, version, rv);
         }
         case LOCAL_GL_SHADING_LANGUAGE_VERSION:
             return StringValue(cx, "WebGL GLSL ES 1.0", rv);
 
             // Privileged string params exposed by WEBGL_debug_renderer_info:
         case UNMASKED_VENDOR_WEBGL:
-        case UNMASKED_RENDERER_WEBGL:
-        {
+        case UNMASKED_RENDERER_WEBGL: {
             // The privilege check is done in WebGLContext::IsExtensionSupported.
             // So here we just have to check that the extension is enabled.
             if (!IsExtensionEnabled(WEBGL_debug_renderer_info)) {
-                ErrorInvalidEnumInfo("getParameter: parameter", pname);
-                return JS::NullValue();
+                break;
             }
             GLenum glstringname = LOCAL_GL_NONE;
             if (pname == UNMASKED_VENDOR_WEBGL) {
                 glstringname = LOCAL_GL_VENDOR;
             } else if (pname == UNMASKED_RENDERER_WEBGL) {
                 glstringname = LOCAL_GL_RENDERER;
             }
             const char* string = reinterpret_cast<const char*>(gl->fGetString(glstringname));
             return StringValue(cx, string, rv);
         }
 
-        //
+        ////////////////////////////////
         // Single-value params
-        //
 
         // unsigned int
         case LOCAL_GL_CULL_FACE_MODE:
         case LOCAL_GL_FRONT_FACE:
         case LOCAL_GL_ACTIVE_TEXTURE:
         case LOCAL_GL_STENCIL_FUNC:
         case LOCAL_GL_STENCIL_FAIL:
         case LOCAL_GL_STENCIL_PASS_DEPTH_FAIL:
@@ -225,18 +212,17 @@ WebGLContext::GetParameter(JSContext* cx
         case LOCAL_GL_STENCIL_BACK_PASS_DEPTH_PASS:
         case LOCAL_GL_DEPTH_FUNC:
         case LOCAL_GL_BLEND_SRC_RGB:
         case LOCAL_GL_BLEND_SRC_ALPHA:
         case LOCAL_GL_BLEND_DST_RGB:
         case LOCAL_GL_BLEND_DST_ALPHA:
         case LOCAL_GL_BLEND_EQUATION_RGB:
         case LOCAL_GL_BLEND_EQUATION_ALPHA:
-        case LOCAL_GL_GENERATE_MIPMAP_HINT:
-        {
+        case LOCAL_GL_GENERATE_MIPMAP_HINT: {
             GLint i = 0;
             gl->fGetIntegerv(pname, &i);
             return JS::NumberValue(uint32_t(i));
         }
         // int
         case LOCAL_GL_STENCIL_CLEAR_VALUE:
         case LOCAL_GL_STENCIL_REF:
         case LOCAL_GL_STENCIL_BACK_REF:
@@ -249,33 +235,30 @@ WebGLContext::GetParameter(JSContext* cx
         case LOCAL_GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS:
         case LOCAL_GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS:
         case LOCAL_GL_MAX_TEXTURE_IMAGE_UNITS:
         case LOCAL_GL_RED_BITS:
         case LOCAL_GL_GREEN_BITS:
         case LOCAL_GL_BLUE_BITS:
         case LOCAL_GL_ALPHA_BITS:
         case LOCAL_GL_DEPTH_BITS:
-        case LOCAL_GL_STENCIL_BITS:
-        {
+        case LOCAL_GL_STENCIL_BITS: {
             GLint i = 0;
             gl->fGetIntegerv(pname, &i);
             return JS::Int32Value(i);
         }
-        case LOCAL_GL_FRAGMENT_SHADER_DERIVATIVE_HINT:
+        case LOCAL_GL_FRAGMENT_SHADER_DERIVATIVE_HINT: {
             if (IsExtensionEnabled(OES_standard_derivatives)) {
                 GLint i = 0;
                 gl->fGetIntegerv(pname, &i);
                 return JS::Int32Value(i);
+            } else {
+                break;
             }
-            else {
-                ErrorInvalidEnum("getParameter: parameter", pname);
-                return JS::NullValue();
-            }
-
+        }
         case LOCAL_GL_MAX_TEXTURE_SIZE:
             return JS::Int32Value(mGLMaxTextureSize);
 
         case LOCAL_GL_MAX_CUBE_MAP_TEXTURE_SIZE:
             return JS::Int32Value(mGLMaxCubeMapTextureSize);
 
         case LOCAL_GL_MAX_RENDERBUFFER_SIZE:
             return JS::Int32Value(mGLMaxRenderbufferSize);
@@ -286,205 +269,193 @@ WebGLContext::GetParameter(JSContext* cx
         case LOCAL_GL_MAX_FRAGMENT_UNIFORM_VECTORS:
             return JS::Int32Value(mGLMaxFragmentUniformVectors);
 
         case LOCAL_GL_MAX_VARYING_VECTORS:
             return JS::Int32Value(mGLMaxVaryingVectors);
 
         case LOCAL_GL_NUM_COMPRESSED_TEXTURE_FORMATS:
             return JS::Int32Value(0);
-        case LOCAL_GL_COMPRESSED_TEXTURE_FORMATS:
-        {
+        case LOCAL_GL_COMPRESSED_TEXTURE_FORMATS: {
             uint32_t length = mCompressedTextureFormats.Length();
             JSObject* obj = Uint32Array::Create(cx, this, length, mCompressedTextureFormats.Elements());
             if (!obj) {
                 rv = NS_ERROR_OUT_OF_MEMORY;
             }
             return JS::ObjectOrNullValue(obj);
         }
-        case LOCAL_GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS:
-        {
+        case LOCAL_GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS: {
             if (!IsWebGL2()) {
                 break;
             }
             return JS::Int32Value(mGLMaxTransformFeedbackSeparateAttribs);
         }
 
         // unsigned int. here we may have to return very large values like 2^32-1 that can't be represented as
         // javascript integer values. We just return them as doubles and javascript doesn't care.
         case LOCAL_GL_STENCIL_BACK_VALUE_MASK:
         case LOCAL_GL_STENCIL_BACK_WRITEMASK:
         case LOCAL_GL_STENCIL_VALUE_MASK:
-        case LOCAL_GL_STENCIL_WRITEMASK:
-        {
+        case LOCAL_GL_STENCIL_WRITEMASK: {
             GLint i = 0; // the GL api (glGetIntegerv) only does signed ints
             gl->fGetIntegerv(pname, &i);
             GLuint i_unsigned(i); // this is where -1 becomes 2^32-1
             double i_double(i_unsigned); // pass as FP value to allow large values such as 2^32-1.
             return JS::DoubleValue(i_double);
         }
 
         // float
-        case LOCAL_GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT:
+        case LOCAL_GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT: {
             if (IsExtensionEnabled(EXT_texture_filter_anisotropic)) {
                 GLfloat f = 0.f;
                 gl->fGetFloatv(pname, &f);
                 return JS::DoubleValue(f);
             } else {
-                ErrorInvalidEnumInfo("getParameter: parameter", pname);
-                return JS::NullValue();
+                break;
             }
+        }
         case LOCAL_GL_DEPTH_CLEAR_VALUE:
         case LOCAL_GL_LINE_WIDTH:
         case LOCAL_GL_POLYGON_OFFSET_FACTOR:
         case LOCAL_GL_POLYGON_OFFSET_UNITS:
-        case LOCAL_GL_SAMPLE_COVERAGE_VALUE:
-        {
+        case LOCAL_GL_SAMPLE_COVERAGE_VALUE: {
             GLfloat f = 0.f;
             gl->fGetFloatv(pname, &f);
             return JS::DoubleValue(f);
         }
 
         // bool
         case LOCAL_GL_BLEND:
         case LOCAL_GL_DEPTH_TEST:
         case LOCAL_GL_STENCIL_TEST:
         case LOCAL_GL_CULL_FACE:
         case LOCAL_GL_DITHER:
         case LOCAL_GL_POLYGON_OFFSET_FILL:
         case LOCAL_GL_SCISSOR_TEST:
         case LOCAL_GL_SAMPLE_COVERAGE_INVERT:
-        case LOCAL_GL_DEPTH_WRITEMASK:
-        {
+        case LOCAL_GL_DEPTH_WRITEMASK: {
             realGLboolean b = 0;
             gl->fGetBooleanv(pname, &b);
             return JS::BooleanValue(bool(b));
         }
 
         // bool, WebGL-specific
         case UNPACK_FLIP_Y_WEBGL:
             return JS::BooleanValue(mPixelStoreFlipY);
         case UNPACK_PREMULTIPLY_ALPHA_WEBGL:
             return JS::BooleanValue(mPixelStorePremultiplyAlpha);
 
         // uint, WebGL-specific
         case UNPACK_COLORSPACE_CONVERSION_WEBGL:
             return JS::NumberValue(uint32_t(mPixelStoreColorspaceConversion));
 
-        //
+        ////////////////////////////////
         // Complex values
-        //
-        case LOCAL_GL_DEPTH_RANGE: // 2 floats
-        case LOCAL_GL_ALIASED_POINT_SIZE_RANGE: // 2 floats
-        case LOCAL_GL_ALIASED_LINE_WIDTH_RANGE: // 2 floats
-        {
+
+        // 2 floats
+        case LOCAL_GL_DEPTH_RANGE:
+        case LOCAL_GL_ALIASED_POINT_SIZE_RANGE:
+        case LOCAL_GL_ALIASED_LINE_WIDTH_RANGE: {
             GLfloat fv[2] = { 0 };
             gl->fGetFloatv(pname, fv);
             JSObject* obj = Float32Array::Create(cx, this, 2, fv);
             if (!obj) {
                 rv = NS_ERROR_OUT_OF_MEMORY;
             }
             return JS::ObjectOrNullValue(obj);
         }
 
-        case LOCAL_GL_COLOR_CLEAR_VALUE: // 4 floats
-        case LOCAL_GL_BLEND_COLOR: // 4 floats
-        {
+        // 4 floats
+        case LOCAL_GL_COLOR_CLEAR_VALUE:
+        case LOCAL_GL_BLEND_COLOR: {
             GLfloat fv[4] = { 0 };
             gl->fGetFloatv(pname, fv);
             JSObject* obj = Float32Array::Create(cx, this, 4, fv);
             if (!obj) {
                 rv = NS_ERROR_OUT_OF_MEMORY;
             }
             return JS::ObjectOrNullValue(obj);
         }
 
-        case LOCAL_GL_MAX_VIEWPORT_DIMS: // 2 ints
-        {
+        // 2 ints
+        case LOCAL_GL_MAX_VIEWPORT_DIMS: {
             GLint iv[2] = { 0 };
             gl->fGetIntegerv(pname, iv);
             JSObject* obj = Int32Array::Create(cx, this, 2, iv);
             if (!obj) {
                 rv = NS_ERROR_OUT_OF_MEMORY;
             }
             return JS::ObjectOrNullValue(obj);
         }
 
-        case LOCAL_GL_SCISSOR_BOX: // 4 ints
-        case LOCAL_GL_VIEWPORT: // 4 ints
-        {
+        // 4 ints
+        case LOCAL_GL_SCISSOR_BOX:
+        case LOCAL_GL_VIEWPORT: {
             GLint iv[4] = { 0 };
             gl->fGetIntegerv(pname, iv);
             JSObject* obj = Int32Array::Create(cx, this, 4, iv);
             if (!obj) {
                 rv = NS_ERROR_OUT_OF_MEMORY;
             }
             return JS::ObjectOrNullValue(obj);
         }
 
-        case LOCAL_GL_COLOR_WRITEMASK: // 4 bools
-        {
+        // 4 bools
+        case LOCAL_GL_COLOR_WRITEMASK: {
             realGLboolean gl_bv[4] = { 0 };
             gl->fGetBooleanv(pname, gl_bv);
             bool vals[4] = { bool(gl_bv[0]), bool(gl_bv[1]),
                              bool(gl_bv[2]), bool(gl_bv[3]) };
             JS::Rooted<JS::Value> arr(cx);
             if (!ToJSValue(cx, vals, &arr)) {
                 rv = NS_ERROR_OUT_OF_MEMORY;
             }
             return arr;
         }
 
-        case LOCAL_GL_ARRAY_BUFFER_BINDING:
-        {
+        case LOCAL_GL_ARRAY_BUFFER_BINDING: {
             return WebGLObjectAsJSValue(cx, mBoundArrayBuffer.get(), rv);
         }
 
-        case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER_BINDING:
-        {
+        case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER_BINDING: {
             if (!IsWebGL2()) {
                 break;
             }
             return WebGLObjectAsJSValue(cx, mBoundTransformFeedbackBuffer.get(), rv);
         }
 
-        case LOCAL_GL_ELEMENT_ARRAY_BUFFER_BINDING:
-        {
+        case LOCAL_GL_ELEMENT_ARRAY_BUFFER_BINDING: {
             return WebGLObjectAsJSValue(cx, mBoundVertexArray->mBoundElementArrayBuffer.get(), rv);
         }
 
-        case LOCAL_GL_RENDERBUFFER_BINDING:
-        {
+        case LOCAL_GL_RENDERBUFFER_BINDING: {
             return WebGLObjectAsJSValue(cx, mBoundRenderbuffer.get(), rv);
         }
 
-        case LOCAL_GL_FRAMEBUFFER_BINDING:
-        {
+        case LOCAL_GL_FRAMEBUFFER_BINDING: {
             return WebGLObjectAsJSValue(cx, mBoundFramebuffer.get(), rv);
         }
 
-        case LOCAL_GL_CURRENT_PROGRAM:
-        {
+        case LOCAL_GL_CURRENT_PROGRAM: {
             return WebGLObjectAsJSValue(cx, mCurrentProgram.get(), rv);
         }
 
-        case LOCAL_GL_TEXTURE_BINDING_2D:
-        {
+        case LOCAL_GL_TEXTURE_BINDING_2D: {
             return WebGLObjectAsJSValue(cx, mBound2DTextures[mActiveTexture].get(), rv);
         }
 
-        case LOCAL_GL_TEXTURE_BINDING_CUBE_MAP:
-        {
+        case LOCAL_GL_TEXTURE_BINDING_CUBE_MAP: {
             return WebGLObjectAsJSValue(cx, mBoundCubeMapTextures[mActiveTexture].get(), rv);
         }
 
         default:
-            ErrorInvalidEnumInfo("getParameter: parameter", pname);
+            break;
     }
 
+    ErrorInvalidEnumInfo("getParameter: parameter", pname);
     return JS::NullValue();
 }
 
 JS::Value
 WebGLContext::GetParameterIndexed(JSContext* cx, GLenum pname, GLuint index)
 {
     if (IsContextLost())
         return JS::NullValue();
--- a/content/canvas/src/WebGLContextValidate.cpp
+++ b/content/canvas/src/WebGLContextValidate.cpp
@@ -1621,16 +1621,37 @@ WebGLContext::InitAndValidateGL()
     mDisableExtensions = Preferences::GetBool("webgl.disable-extensions", false);
     mLoseContextOnHeapMinimize = Preferences::GetBool("webgl.lose-context-on-heap-minimize", false);
     mCanLoseContextInForeground = Preferences::GetBool("webgl.can-lose-context-in-foreground", true);
 
     if (MinCapabilityMode()) {
       mDisableFragHighP = true;
     }
 
+    // These are the default values, see 6.2 State tables in the
+    // OpenGL ES 2.0.25 spec.
+    mColorWriteMask[0] = 1;
+    mColorWriteMask[1] = 1;
+    mColorWriteMask[2] = 1;
+    mColorWriteMask[3] = 1;
+    mDepthWriteMask = 1;
+    mColorClearValue[0] = 0.f;
+    mColorClearValue[1] = 0.f;
+    mColorClearValue[2] = 0.f;
+    mColorClearValue[3] = 0.f;
+    mDepthClearValue = 1.f;
+    mStencilClearValue = 0;
+    mStencilRefFront = 0;
+    mStencilRefBack = 0;
+    mStencilValueMaskFront = 0xffffffff;
+    mStencilValueMaskBack  = 0xffffffff;
+    mStencilWriteMaskFront = 0xffffffff;
+    mStencilWriteMaskBack  = 0xffffffff;
+
+    // Bindings, etc.
     mActiveTexture = 0;
     mEmitContextLostErrorOnce = true;
     mWebGLError = LOCAL_GL_NO_ERROR;
     mUnderlyingGLError = LOCAL_GL_NO_ERROR;
 
     mBound2DTextures.Clear();
     mBoundCubeMapTextures.Clear();
 
--- a/content/html/content/public/HTMLCanvasElement.h
+++ b/content/html/content/public/HTMLCanvasElement.h
@@ -8,38 +8,39 @@
 
 #include "mozilla/Attributes.h"
 #include "nsIDOMHTMLCanvasElement.h"
 #include "nsGenericHTMLElement.h"
 #include "nsGkAtoms.h"
 #include "nsSize.h"
 #include "nsError.h"
 
-#include "nsICanvasElementExternal.h"
 #include "mozilla/gfx/Rect.h"
 
 class nsICanvasRenderingContextInternal;
 class nsIDOMFile;
 class nsITimerCallback;
 
 namespace mozilla {
 
 namespace layers {
 class CanvasLayer;
 class LayerManager;
 }
+namespace gfx {
+class SourceSurface;
+}
 
 namespace dom {
 
 class FileCallback;
 class HTMLCanvasPrintState;
 class PrintCallback;
 
 class HTMLCanvasElement MOZ_FINAL : public nsGenericHTMLElement,
-                                    public nsICanvasElementExternal,
                                     public nsIDOMHTMLCanvasElement
 {
   enum {
     DEFAULT_CANVAS_WIDTH = 300,
     DEFAULT_CANVAS_HEIGHT = 150
   };
 
   typedef layers::CanvasLayer CanvasLayer;
@@ -154,23 +155,17 @@ public:
   nsICanvasRenderingContextInternal *GetContextAtIndex (int32_t index);
 
   /*
    * Returns true if the canvas context content is guaranteed to be opaque
    * across its entire area.
    */
   bool GetIsOpaque();
 
-  /*
-   * nsICanvasElementExternal -- for use outside of content/layout
-   */
-  NS_IMETHOD_(nsIntSize) GetSizeExternal() MOZ_OVERRIDE;
-  NS_IMETHOD RenderContextsExternal(gfxContext *aContext,
-                                    GraphicsFilter aFilter,
-                                    uint32_t aFlags = RenderFlagPremultAlpha) MOZ_OVERRIDE;
+  virtual TemporaryRef<gfx::SourceSurface> GetSurfaceSnapshot(bool* aPremultAlpha = nullptr);
 
   virtual bool ParseAttribute(int32_t aNamespaceID,
                                 nsIAtom* aAttribute,
                                 const nsAString& aValue,
                                 nsAttrValue& aResult) MOZ_OVERRIDE;
   nsChangeHint GetAttributeChangeHint(const nsIAtom* aAttribute, int32_t aModType) const MOZ_OVERRIDE;
 
   // SetAttr override.  C++ is stupid, so have to override both
--- a/content/html/content/src/HTMLCanvasElement.cpp
+++ b/content/html/content/src/HTMLCanvasElement.cpp
@@ -33,16 +33,17 @@
 #include "nsStreamUtils.h"
 #include "ActiveLayerTracker.h"
 
 #ifdef MOZ_WEBGL
 #include "../canvas/src/WebGL2Context.h"
 #endif
 
 using namespace mozilla::layers;
+using namespace mozilla::gfx;
 
 NS_IMPL_NS_NEW_HTML_ELEMENT(Canvas)
 
 namespace {
 
 typedef mozilla::dom::HTMLImageElementOrHTMLCanvasElementOrHTMLVideoElement
 HTMLImageOrCanvasOrVideoElement;
 
@@ -125,19 +126,17 @@ HTMLCanvasElement::~HTMLCanvasElement()
 NS_IMPL_CYCLE_COLLECTION_INHERITED_4(HTMLCanvasElement, nsGenericHTMLElement,
                                      mCurrentContext, mPrintCallback,
                                      mPrintState, mOriginalCanvas)
 
 NS_IMPL_ADDREF_INHERITED(HTMLCanvasElement, Element)
 NS_IMPL_RELEASE_INHERITED(HTMLCanvasElement, Element)
 
 NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION_INHERITED(HTMLCanvasElement)
-  NS_INTERFACE_TABLE_INHERITED2(HTMLCanvasElement,
-                                nsIDOMHTMLCanvasElement,
-                                nsICanvasElementExternal)
+  NS_INTERFACE_TABLE_INHERITED1(HTMLCanvasElement, nsIDOMHTMLCanvasElement)
 NS_INTERFACE_TABLE_TAIL_INHERITING(nsGenericHTMLElement)
 
 NS_IMPL_ELEMENT_CLONE(HTMLCanvasElement)
 
 /* virtual */ JSObject*
 HTMLCanvasElement::WrapNode(JSContext* aCx)
 {
   return HTMLCanvasElementBinding::Wrap(aCx, this);
@@ -929,25 +928,19 @@ void
 HTMLCanvasElement::MarkContextClean()
 {
   if (!mCurrentContext)
     return;
 
   mCurrentContext->MarkContextClean();
 }
 
-NS_IMETHODIMP_(nsIntSize)
-HTMLCanvasElement::GetSizeExternal()
-{
-  return GetWidthHeight();
-}
-
-NS_IMETHODIMP
-HTMLCanvasElement::RenderContextsExternal(gfxContext *aContext, GraphicsFilter aFilter, uint32_t aFlags)
+TemporaryRef<SourceSurface>
+HTMLCanvasElement::GetSurfaceSnapshot(bool* aPremultAlpha)
 {
   if (!mCurrentContext)
-    return NS_OK;
+    return nullptr;
 
-  return mCurrentContext->Render(aContext, aFilter, aFlags);
+  return mCurrentContext->GetSurfaceSnapshot(aPremultAlpha);
 }
 
 } // namespace dom
 } // namespace mozilla
--- a/content/html/content/src/HTMLLinkElement.cpp
+++ b/content/html/content/src/HTMLLinkElement.cpp
@@ -191,20 +191,26 @@ HTMLLinkElement::UnbindFromTree(bool aDe
 }
 
 bool
 HTMLLinkElement::ParseAttribute(int32_t aNamespaceID,
                                 nsIAtom* aAttribute,
                                 const nsAString& aValue,
                                 nsAttrValue& aResult)
 {
-  if (aNamespaceID == kNameSpaceID_None &&
-      aAttribute == nsGkAtoms::crossorigin) {
-    ParseCORSValue(aValue, aResult);
-    return true;
+  if (aNamespaceID == kNameSpaceID_None) {
+    if (aAttribute == nsGkAtoms::crossorigin) {
+      ParseCORSValue(aValue, aResult);
+      return true;
+    }
+
+    if (aAttribute == nsGkAtoms::sizes) {
+      aResult.ParseAtomArray(aValue);
+      return true;
+    }
   }
 
   return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
                                               aResult);
 }
 
 void
 HTMLLinkElement::CreateAndDispatchEvent(nsIDocument* aDoc,
--- a/content/html/content/src/HTMLLinkElement.h
+++ b/content/html/content/src/HTMLLinkElement.h
@@ -104,16 +104,20 @@ public:
   {
     SetHTMLAttr(nsGkAtoms::media, aMedia, aRv);
   }
   // XPCOM GetHreflang is fine.
   void SetHreflang(const nsAString& aHreflang, ErrorResult& aRv)
   {
     SetHTMLAttr(nsGkAtoms::hreflang, aHreflang, aRv);
   }
+  nsDOMSettableTokenList* Sizes()
+  {
+    return GetTokenList(nsGkAtoms::sizes);
+  }
   // XPCOM GetType is fine.
   void SetType(const nsAString& aType, ErrorResult& aRv)
   {
     SetHTMLAttr(nsGkAtoms::type, aType, aRv);
   }
   // XPCOM GetCharset is fine.
   void SetCharset(const nsAString& aCharset, ErrorResult& aRv)
   {
--- a/content/html/content/src/nsGenericHTMLElement.cpp
+++ b/content/html/content/src/nsGenericHTMLElement.cpp
@@ -3149,16 +3149,17 @@ nsDOMSettableTokenListPropertyDestructor
 
 static nsIAtom** sPropertiesToTraverseAndUnlink[] =
   {
     &nsGkAtoms::microdataProperties,
     &nsGkAtoms::itemtype,
     &nsGkAtoms::itemref,
     &nsGkAtoms::itemprop,
     &nsGkAtoms::sandbox,
+    &nsGkAtoms::sizes,
     nullptr
   };
 
 // static
 nsIAtom***
 nsGenericHTMLElement::PropertiesToTraverseAndUnlink()
 {
   return sPropertiesToTraverseAndUnlink;
--- a/content/html/content/test/mochitest.ini
+++ b/content/html/content/test/mochitest.ini
@@ -443,16 +443,17 @@ skip-if = buildapp == 'b2g' # b2g(multip
 [test_iframe_sandbox_popups_inheritance.html]
 skip-if = buildapp == 'b2g' || e10s # b2g(multiple concurrent window.open()s fail on B2G) b2g-debug(multiple concurrent window.open()s fail on B2G) b2g-desktop(Bug 931116, b2g desktop specific, initial triage)
 [test_iframe_sandbox_same_origin.html]
 [test_iframe_sandbox_workers.html]
 [test_img_attributes_reflection.html]
 [test_imageSrcSet.html]
 [test_li_attributes_reflection.html]
 [test_link_attributes_reflection.html]
+[test_link_sizes.html]
 [test_map_attributes_reflection.html]
 [test_meta_attributes_reflection.html]
 [test_mod_attributes_reflection.html]
 [test_mozaudiochannel.html]
 skip-if = (buildapp == 'b2g' && (toolkit != 'gonk' || debug)) # b2g-debug(Perma-orange on debug emulator) b2g-desktop(Bug 931116, b2g desktop specific, initial triage)
 [test_named_options.html]
 [test_nested_invalid_fieldsets.html]
 [test_object_attributes_reflection.html]
new file mode 100644
--- /dev/null
+++ b/content/html/content/test/test_link_sizes.html
@@ -0,0 +1,35 @@
+<!doctype html>
+<html>
+<head>
+<title>Test link.sizes attribute</title>
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<link rel="stylesheet" href="/tests/SimpleTest/test.css"/>
+<link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" sizes="16x16 24x24 32x32 48x48">
+</head>
+<body>
+
+<pre id="test">
+<script>
+
+  var links = document.getElementsByTagName('link');
+  for (var i = 0; i < links.length; ++i) {
+    var link = links[i];
+    ok("sizes" in link, "link.sizes exists");
+
+    if (link.rel == 'shortcut icon') {
+      is(link.sizes.value, "16x16 24x24 32x32 48x48", 'link.sizes.value correct value');
+      is(link.sizes.length, 4, 'link.sizes.length correct value');
+      ok(link.sizes.contains('32x32'), 'link.sizes.contains() works');
+      link.sizes.add('64x64');
+      is(link.sizes.length, 5, 'link.sizes.length correct value');
+      link.sizes.remove('64x64');
+      is(link.sizes.length, 4, 'link.sizes.length correct value');
+      is(link.sizes + "", "16x16 24x24 32x32 48x48", 'link.sizes stringify correct value');
+    } else {
+      is(link.sizes.value, "", 'link.sizes correct value');
+    }
+  }
+</script>
+</pre>
+</body>
+</html>
--- a/content/media/AudioStream.cpp
+++ b/content/media/AudioStream.cpp
@@ -497,16 +497,17 @@ AudioStream::CheckForStart()
               mLatencyRequest == LowLatency ? "low" : "high"));
     }
   }
 }
 
 NS_IMETHODIMP
 AudioInitTask::Run()
 {
+  MOZ_ASSERT(mThread);
   if (NS_IsMainThread()) {
     mThread->Shutdown(); // can't Shutdown from the thread itself, darn
     mThread = nullptr;
     return NS_OK;
   }
 
   nsresult rv = mAudioStream->OpenCubeb(mParams, mLatencyRequest);
 
--- a/content/media/AudioStream.h
+++ b/content/media/AudioStream.h
@@ -428,17 +428,22 @@ public:
                 const cubeb_stream_params &aParams)
     : mAudioStream(aStream)
     , mLatencyRequest(aLatencyRequest)
     , mParams(aParams)
   {}
 
   nsresult Dispatch()
   {
-    return NS_NewNamedThread("CubebInit", getter_AddRefs(mThread), this);
+    // Can't add 'this' as the event to run, since mThread may not be set yet
+    nsresult rv = NS_NewNamedThread("CubebInit", getter_AddRefs(mThread));
+    if (NS_SUCCEEDED(rv)) {
+      rv = mThread->Dispatch(this, NS_DISPATCH_NORMAL);
+    }
+    return rv;
   }
 
 protected:
   virtual ~AudioInitTask() {};
 
 private:
   NS_IMETHOD Run() MOZ_OVERRIDE MOZ_FINAL;
 
--- a/content/media/MediaStreamGraph.cpp
+++ b/content/media/MediaStreamGraph.cpp
@@ -1254,27 +1254,29 @@ MediaStreamGraphImpl::RunThread()
       }
     }
     messageQueue.Clear();
 
     if (mStreamOrderDirty) {
       UpdateStreamOrder();
     }
 
+    TrackRate sampleRate;
     // Find the sampling rate that we need to use for non-realtime graphs.
-    TrackRate sampleRate = IdealAudioRate();
     if (!mRealtime) {
       for (uint32_t i = 0; i < mStreams.Length(); ++i) {
         AudioNodeStream* n = mStreams[i]->AsAudioNodeStream();
         if (n) {
           // We know that the rest of the streams will run at the same rate.
           sampleRate = n->SampleRate();
           break;
         }
       }
+    } else {
+      sampleRate = IdealAudioRate();
     }
 
     GraphTime endBlockingDecisions =
       RoundUpToNextAudioBlock(sampleRate, mCurrentTime + MillisecondsToMediaTime(AUDIO_TARGET_MS));
     bool ensureNextIteration = false;
 
     // Grab pending stream input.
     for (uint32_t i = 0; i < mStreams.Length(); ++i) {
--- a/content/media/gstreamer/GStreamerFormatHelper.cpp
+++ b/content/media/gstreamer/GStreamerFormatHelper.cpp
@@ -25,20 +25,18 @@ GStreamerFormatHelper* GStreamerFormatHe
 
     gInstance = new GStreamerFormatHelper();
   }
 
   return gInstance;
 }
 
 void GStreamerFormatHelper::Shutdown() {
-  if (gInstance) {
-    delete gInstance;
-    gInstance = nullptr;
-  }
+  delete gInstance;
+  gInstance = nullptr;
 }
 
 static char const *const sContainers[6][2] = {
   {"video/mp4", "video/quicktime"},
   {"video/quicktime", "video/quicktime"},
   {"audio/mp4", "audio/x-m4a"},
   {"audio/x-m4a", "audio/x-m4a"},
   {"audio/mpeg", "audio/mpeg, mpegversion=(int)1"},
--- a/content/media/omx/AudioOutput.cpp
+++ b/content/media/omx/AudioOutput.cpp
@@ -175,20 +175,18 @@ void AudioOutput::Pause()
   }
 }
 
 void AudioOutput::Close()
 {
   AUDIO_OFFLOAD_LOG(PR_LOG_DEBUG, ("%s", __PRETTY_FUNCTION__));
   mTrack.clear();
 
-  if (mCallbackData) {
-    delete mCallbackData;
-    mCallbackData = NULL;
-  }
+  delete mCallbackData;
+  mCallbackData = nullptr;
 }
 
 // static
 void AudioOutput::CallbackWrapper(int aEvent, void* aCookie, void* aInfo)
 {
   CallbackData* data = (CallbackData*) aCookie;
   data->Lock();
   AudioOutput* me = data->GetOutput();
--- a/content/media/plugins/MediaPluginHost.cpp
+++ b/content/media/plugins/MediaPluginHost.cpp
@@ -318,15 +318,13 @@ MediaPluginHost *GetMediaPluginHost()
   if (!sMediaPluginHost) {
     sMediaPluginHost = new MediaPluginHost();
   }
   return sMediaPluginHost;
 }
 
 void MediaPluginHost::Shutdown()
 {
-  if (sMediaPluginHost) {
-    delete sMediaPluginHost;
-    sMediaPluginHost = nullptr;
-  }
+  delete sMediaPluginHost;
+  sMediaPluginHost = nullptr;
 }
 
 } // namespace mozilla
--- a/content/media/webaudio/OscillatorNode.cpp
+++ b/content/media/webaudio/OscillatorNode.cpp
@@ -381,19 +381,17 @@ public:
     for (uint32_t i = aStart; i < aEnd; ++i) {
       UpdateParametersIfNeeded(ticks, i);
       mPeriodicWave->waveDataForFundamentalFrequency(mFinalFrequency,
                                                      lowerWaveData,
                                                      higherWaveData,
                                                      tableInterpolationFactor);
       // mPhase runs 0..periodicWaveSize here instead of 0..2*M_PI.
       mPhase += periodicWaveSize * mFinalFrequency * rate;
-      if (mPhase >= periodicWaveSize) {
-        mPhase -= periodicWaveSize;
-      }
+      mPhase = fmod(mPhase, periodicWaveSize);
       // Bilinear interpolation between adjacent samples in each table.
       uint32_t j1 = floor(mPhase);
       uint32_t j2 = j1 + 1;
       if (j2 >= periodicWaveSize) {
         j2 -= periodicWaveSize;
       }
       float sampleInterpolationFactor = mPhase - j1;
       float lower = sampleInterpolationFactor * lowerWaveData[j1] +
--- a/content/media/webrtc/MediaEngineWebRTCAudio.cpp
+++ b/content/media/webrtc/MediaEngineWebRTCAudio.cpp
@@ -463,20 +463,17 @@ void
 MediaEngineWebRTCAudioSource::Shutdown()
 {
   if (!mInitDone) {
     // duplicate these here in case we failed during Init()
     if (mChannel != -1) {
       mVoENetwork->DeRegisterExternalTransport(mChannel);
     }
 
-    if (mNullTransport) {
-      delete mNullTransport;
-    }
-
+    delete mNullTransport;
     return;
   }
 
   if (mState == kStarted) {
     while (!mSources.IsEmpty()) {
       Stop(mSources[0], kAudioTrack); // XXX change to support multiple tracks
     }
     MOZ_ASSERT(mState == kStopped);
@@ -486,19 +483,17 @@ MediaEngineWebRTCAudioSource::Shutdown()
     Deallocate();
   }
 
   mVoEBase->Terminate();
   if (mChannel != -1) {
     mVoENetwork->DeRegisterExternalTransport(mChannel);
   }
 
-  if (mNullTransport) {
-    delete mNullTransport;
-  }
+  delete mNullTransport;
 
   mVoEProcessing = nullptr;
   mVoENetwork = nullptr;
   mVoERender = nullptr;
   mVoEBase = nullptr;
 
   mState = kReleased;
   mInitDone = false;
--- a/dom/base/Console.cpp
+++ b/dom/base/Console.cpp
@@ -2,25 +2,28 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/dom/Console.h"
 #include "mozilla/dom/ConsoleBinding.h"
 
 #include "mozilla/dom/Exceptions.h"
+#include "mozilla/dom/ToJSValue.h"
+#include "mozilla/Maybe.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsDocument.h"
 #include "nsDOMNavigationTiming.h"
 #include "nsGlobalWindow.h"
 #include "nsJSUtils.h"
 #include "nsPerformance.h"
 #include "WorkerPrivate.h"
 #include "WorkerRunnable.h"
 #include "xpcprivate.h"
+#include "nsContentUtils.h"
 
 #include "nsIConsoleAPIStorage.h"
 #include "nsIDOMWindowUtils.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsILoadContext.h"
 #include "nsIServiceManager.h"
 #include "nsISupportsPrimitives.h"
 #include "nsIWebNavigation.h"
@@ -166,17 +169,26 @@ public:
 
   Console::MethodName mMethodName;
   bool mPrivate;
   int64_t mTimeStamp;
   DOMHighResTimeStamp mMonotonicTimer;
 
   nsString mMethodString;
   nsTArray<JS::Heap<JS::Value>> mArguments;
-  Sequence<ConsoleStackEntry> mStack;
+
+  // Stack management is complicated, because we want to do it as
+  // lazily as possible.  Therefore, we have the following behavior:
+  // 1)  mTopStackFrame is initialized whenever we have any JS on the stack
+  // 2)  mReifiedStack is initialized if we're created in a worker.
+  // 3)  mStack is set (possibly to null if there is no JS on the stack) if
+  //     we're created on main thread.
+  Maybe<ConsoleStackEntry> mTopStackFrame;
+  Maybe<nsTArray<ConsoleStackEntry>> mReifiedStack;
+  nsCOMPtr<nsIStackFrame> mStack;
 };
 
 // This class is used to clear any exception at the end of this method.
 class ClearException
 {
 public:
   ClearException(JSContext* aCx)
     : mCx(aCx)
@@ -728,16 +740,68 @@ Console::Assert(JSContext* aCx, bool aCo
 METHOD(Count, "count")
 
 void
 Console::__noSuchMethod__()
 {
   // Nothing to do.
 }
 
+static
+nsresult
+StackFrameToStackEntry(nsIStackFrame* aStackFrame,
+                       ConsoleStackEntry& aStackEntry,
+                       uint32_t aLanguage)
+{
+  MOZ_ASSERT(aStackFrame);
+
+  nsresult rv = aStackFrame->GetFilename(aStackEntry.mFilename);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  int32_t lineNumber;
+  rv = aStackFrame->GetLineNumber(&lineNumber);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  aStackEntry.mLineNumber = lineNumber;
+
+  rv = aStackFrame->GetName(aStackEntry.mFunctionName);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  aStackEntry.mLanguage = aLanguage;
+  return NS_OK;
+}
+
+static
+nsresult
+ReifyStack(nsIStackFrame* aStack, nsTArray<ConsoleStackEntry>& aRefiedStack)
+{
+  nsCOMPtr<nsIStackFrame> stack(aStack);
+
+  while (stack) {
+    uint32_t language;
+    nsresult rv = stack->GetLanguage(&language);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    if (language == nsIProgrammingLanguage::JAVASCRIPT ||
+        language == nsIProgrammingLanguage::JAVASCRIPT2) {
+      ConsoleStackEntry& data = *aRefiedStack.AppendElement();
+      rv = StackFrameToStackEntry(stack, data, language);
+      NS_ENSURE_SUCCESS(rv, rv);
+    }
+
+    nsCOMPtr<nsIStackFrame> caller;
+    rv = stack->GetCaller(getter_AddRefs(caller));
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    stack.swap(caller);
+  }
+
+  return NS_OK;
+}
+
 // Queue a call to a console method. See the CALL_DELAY constant.
 void
 Console::Method(JSContext* aCx, MethodName aMethodName,
                 const nsAString& aMethodString,
                 const Sequence<JS::Value>& aData)
 {
   // This RAII class removes the last element of the mQueuedCalls if something
   // goes wrong.
@@ -792,64 +856,62 @@ Console::Method(JSContext* aCx, MethodNa
                       DEFAULT_MAX_STACKTRACE_DEPTH : 1;
   nsCOMPtr<nsIStackFrame> stack = CreateStack(aCx, maxDepth);
 
   if (!stack) {
     Throw(aCx, NS_ERROR_FAILURE);
     return;
   }
 
-  // nsIStackFrame is not thread-safe so we take what we need and we store in
-  // an array of ConsoleStackEntry objects.
+  // Walk up to the first JS stack frame and save it if we find it.
   do {
     uint32_t language;
     nsresult rv = stack->GetLanguage(&language);
     if (NS_FAILED(rv)) {
       Throw(aCx, rv);
       return;
     }
 
     if (language == nsIProgrammingLanguage::JAVASCRIPT ||
         language == nsIProgrammingLanguage::JAVASCRIPT2) {
-      ConsoleStackEntry& data = *callData->mStack.AppendElement();
-
-      rv = stack->GetFilename(data.mFilename);
+      callData->mTopStackFrame.construct();
+      nsresult rv = StackFrameToStackEntry(stack,
+                                           callData->mTopStackFrame.ref(),
+                                           language);
       if (NS_FAILED(rv)) {
         Throw(aCx, rv);
         return;
       }
 
-      int32_t lineNumber;
-      rv = stack->GetLineNumber(&lineNumber);
-      if (NS_FAILED(rv)) {
-        Throw(aCx, rv);
-        return;
-      }
-
-      data.mLineNumber = lineNumber;
-
-      rv = stack->GetName(data.mFunctionName);
-      if (NS_FAILED(rv)) {
-        Throw(aCx, rv);
-        return;
-      }
-
-      data.mLanguage = language;
+      break;
     }
 
     nsCOMPtr<nsIStackFrame> caller;
     rv = stack->GetCaller(getter_AddRefs(caller));
     if (NS_FAILED(rv)) {
       Throw(aCx, rv);
       return;
     }
 
     stack.swap(caller);
   } while (stack);
 
+  if (NS_IsMainThread()) {
+    callData->mStack = stack;
+  } else {
+    // nsIStackFrame is not threadsafe, so we need to snapshot it now,
+    // before we post our runnable to the main thread.
+    callData->mReifiedStack.construct();
+    nsresult rv = ReifyStack(stack, callData->mReifiedStack.ref());
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      Throw(aCx, rv);
+      return;
+    }
+  }
+
   // Monotonic timer for 'time' and 'timeEnd'
   if ((aMethodName == MethodTime || aMethodName == MethodTimeEnd) && mWindow) {
     nsGlobalWindow *win = static_cast<nsGlobalWindow*>(mWindow.get());
     MOZ_ASSERT(win);
 
     ErrorResult rv;
     nsRefPtr<nsPerformance> performance = win->GetPerformance(rv);
     if (rv.Failed()) {
@@ -913,24 +975,70 @@ Console::Notify(nsITimer *timer)
   if (mQueuedCalls.isEmpty() && mTimer) {
     mTimer->Cancel();
     mTimer = nullptr;
   }
 
   return NS_OK;
 }
 
+// We store information to lazily compute the stack in the reserved slots of
+// LazyStackGetter.  The first slot always stores a JS object: it's either the
+// JS wrapper of the nsIStackFrame or the actual reified stack representation.
+// The second slot is a PrivateValue() holding an nsIStackFrame* when we haven't
+// reified the stack yet, or an UndefinedValue() otherwise.
+enum {
+  SLOT_STACKOBJ,
+  SLOT_RAW_STACK
+};
+
+bool
+LazyStackGetter(JSContext* aCx, unsigned aArgc, JS::Value* aVp)
+{
+  JS::CallArgs args = CallArgsFromVp(aArgc, aVp);
+  JS::Rooted<JSObject*> callee(aCx, &args.callee());
+
+  JS::Value v = js::GetFunctionNativeReserved(&args.callee(), SLOT_RAW_STACK);
+  if (v.isUndefined()) {
+    // Already reified.
+    args.rval().set(js::GetFunctionNativeReserved(callee, SLOT_STACKOBJ));
+    return true;
+  }
+
+  nsIStackFrame* stack = reinterpret_cast<nsIStackFrame*>(v.toPrivate());
+  nsTArray<ConsoleStackEntry> reifiedStack;
+  nsresult rv = ReifyStack(stack, reifiedStack);
+  if (NS_FAILED(rv)) {
+    Throw(aCx, rv);
+    return false;
+  }
+
+  JS::Rooted<JS::Value> stackVal(aCx);
+  if (!ToJSValue(aCx, reifiedStack, &stackVal)) {
+    return false;
+  }
+
+  MOZ_ASSERT(stackVal.isObject());
+
+  js::SetFunctionNativeReserved(callee, SLOT_STACKOBJ, stackVal);
+  js::SetFunctionNativeReserved(callee, SLOT_RAW_STACK, JS::UndefinedValue());
+
+  args.rval().set(stackVal);
+  return true;
+}
+
 void
 Console::ProcessCallData(ConsoleCallData* aData)
 {
   MOZ_ASSERT(aData);
+  MOZ_ASSERT(NS_IsMainThread());
 
   ConsoleStackEntry frame;
-  if (!aData->mStack.IsEmpty()) {
-    frame = aData->mStack[0];
+  if (!aData->mTopStackFrame.empty()) {
+    frame = aData->mTopStackFrame.ref();
   }
 
   AutoSafeJSContext cx;
   ClearException ce(cx);
   RootedDictionary<ConsoleEvent> event(cx);
 
   JSAutoCompartment ac(cx, aData->mGlobal);
 
@@ -966,52 +1074,104 @@ Console::ProcessCallData(ConsoleCallData
                        event.mStyles.Value());
       break;
 
     default:
       event.mArguments.Construct();
       ArgumentsToValueList(aData->mArguments, event.mArguments.Value());
   }
 
-  if (ShouldIncludeStackrace(aData->mMethodName)) {
-    event.mStacktrace.Construct();
-    event.mStacktrace.Value().SwapElements(aData->mStack);
-  }
-
-  else if (aData->mMethodName == MethodGroup ||
-           aData->mMethodName == MethodGroupCollapsed ||
-           aData->mMethodName == MethodGroupEnd) {
+  if (aData->mMethodName == MethodGroup ||
+      aData->mMethodName == MethodGroupCollapsed ||
+      aData->mMethodName == MethodGroupEnd) {
     ComposeGroupName(cx, aData->mArguments, event.mGroupName);
   }
 
   else if (aData->mMethodName == MethodTime && !aData->mArguments.IsEmpty()) {
     event.mTimer = StartTimer(cx, aData->mArguments[0], aData->mMonotonicTimer);
   }
 
   else if (aData->mMethodName == MethodTimeEnd && !aData->mArguments.IsEmpty()) {
     event.mTimer = StopTimer(cx, aData->mArguments[0], aData->mMonotonicTimer);
   }
 
   else if (aData->mMethodName == MethodCount) {
     event.mCounter = IncreaseCounter(cx, frame, aData->mArguments);
   }
 
+  // We want to create a console event object and pass it to our
+  // nsIConsoleAPIStorage implementation.  We want to define some accessor
+  // properties on this object, and those will need to keep an nsIStackFrame
+  // alive.  But nsIStackFrame cannot be wrapped in an untrusted scope.  And
+  // further, passing untrusted objects to system code is likely to run afoul of
+  // Object Xrays.  So we want to wrap in a system-principal scope here.  But
+  // which one?  We could cheat and try to get the underlying JSObject* of
+  // mStorage, but that's a bit fragile.  Instead, we just use the junk scope,
+  // with explicit permission from the XPConnect module owner.  If you're
+  // tempted to do that anywhere else, talk to said module owner first.
+  JSAutoCompartment ac2(cx, xpc::GetJunkScope());
+
   JS::Rooted<JS::Value> eventValue(cx);
   if (!event.ToObject(cx, &eventValue)) {
     Throw(cx, NS_ERROR_FAILURE);
     return;
   }
 
   JS::Rooted<JSObject*> eventObj(cx, &eventValue.toObject());
   MOZ_ASSERT(eventObj);
 
   if (!JS_DefineProperty(cx, eventObj, "wrappedJSObject", eventValue, JSPROP_ENUMERATE)) {
     return;
   }
 
+  if (ShouldIncludeStackrace(aData->mMethodName)) {
+    // Now define the "stacktrace" property on eventObj.  There are two cases
+    // here.  Either we came from a worker and have a reified stack, or we want
+    // to define a getter that will lazily reify the stack.
+    if (!aData->mReifiedStack.empty()) {
+      JS::Rooted<JS::Value> stacktrace(cx);
+      if (!ToJSValue(cx, aData->mReifiedStack.ref(), &stacktrace) ||
+          !JS_DefineProperty(cx, eventObj, "stacktrace", stacktrace,
+                             JSPROP_ENUMERATE)) {
+        return;
+      }
+    } else {
+      JSFunction* fun = js::NewFunctionWithReserved(cx, LazyStackGetter, 0, 0,
+                                                    eventObj, "stacktrace");
+      if (!fun) {
+        return;
+      }
+
+      JS::Rooted<JSObject*> funObj(cx, JS_GetFunctionObject(fun));
+
+      // We want to store our stack in the function and have it stay alive.  But
+      // we also need sane access to the C++ nsIStackFrame.  So store both a JS
+      // wrapper and the raw pointer: the former will keep the latter alive.
+      JS::Rooted<JS::Value> stackVal(cx);
+      nsresult rv = nsContentUtils::WrapNative(cx, aData->mStack,
+                                               &stackVal);
+      if (NS_FAILED(rv)) {
+        return;
+      }
+
+      js::SetFunctionNativeReserved(funObj, SLOT_STACKOBJ, stackVal);
+      js::SetFunctionNativeReserved(funObj, SLOT_RAW_STACK,
+                                    JS::PrivateValue(aData->mStack.get()));
+
+      if (!JS_DefineProperty(cx, eventObj, "stacktrace",
+                             JS::UndefinedHandleValue,
+                             JSPROP_ENUMERATE | JSPROP_SHARED | JSPROP_GETTER |
+                             JSPROP_SETTER,
+                             JS_DATA_TO_FUNC_PTR(JSPropertyOp, funObj.get()),
+                             nullptr)) {
+        return;
+      }
+    }
+  }
+
   if (!mStorage) {
     mStorage = do_GetService("@mozilla.org/consoleAPI-storage;1");
   }
 
   if (!mStorage) {
     NS_WARNING("Failed to get the ConsoleAPIStorage service.");
     return;
   }
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -12454,91 +12454,47 @@ nsGlobalWindow::GetScrollFrame()
   nsCOMPtr<nsIPresShell> presShell = mDocShell->GetPresShell();
   if (presShell) {
     return presShell->GetRootScrollFrameAsScrollable();
   }
   return nullptr;
 }
 
 nsresult
-nsGlobalWindow::BuildURIfromBase(const char *aURL, nsIURI **aBuiltURI,
-                                 JSContext **aCXused)
-{
-  nsIScriptContext *scx = GetContextInternal();
-  JSContext *cx = nullptr;
-
-  *aBuiltURI = nullptr;
-  if (aCXused)
-    *aCXused = nullptr;
-
-  // get JSContext
-  NS_ASSERTION(scx, "opening window missing its context");
-  NS_ASSERTION(mDoc, "opening window missing its document");
-  if (!scx || !mDoc)
-    return NS_ERROR_FAILURE;
-
-  nsCOMPtr<nsIDOMChromeWindow> chrome_win = do_QueryObject(this);
-
-  if (nsContentUtils::IsCallerChrome() && !chrome_win) {
-    // If open() is called from chrome on a non-chrome window, we'll
-    // use the context from the window on which open() is being called
-    // to prevent giving chrome priveleges to new windows opened in
-    // such a way. This also makes us get the appropriate base URI for
-    // the below URI resolution code.
-
-    cx = scx->GetNativeContext();
-  } else {
-    // get the JSContext from the call stack
-    cx = nsContentUtils::GetCurrentJSContext();
-  }
-
-  /* resolve the URI, which could be relative to the calling window
-     (note the algorithm to get the base URI should match the one
-     used to actually kick off the load in nsWindowWatcher.cpp). */
-  nsAutoCString charset(NS_LITERAL_CSTRING("UTF-8")); // default to utf-8
-  nsIURI* baseURI = nullptr;
-  nsCOMPtr<nsIURI> uriToLoad;
+nsGlobalWindow::SecurityCheckURL(const char *aURL)
+{
   nsCOMPtr<nsPIDOMWindow> sourceWindow;
-
-  if (cx) {
-    nsIScriptContext *scriptcx = nsJSUtils::GetDynamicScriptContext(cx);
-    if (scriptcx)
-      sourceWindow = do_QueryInterface(scriptcx->GetGlobalObject());
-  }
-
+  JSContext* topCx = nsContentUtils::GetCurrentJSContext();
+  if (topCx) {
+    sourceWindow = do_QueryInterface(nsJSUtils::GetDynamicScriptGlobal(topCx));
+  }
   if (!sourceWindow) {
     sourceWindow = this;
   }
-
+  AutoJSContext cx;
+  nsGlobalWindow* sourceWin = static_cast<nsGlobalWindow*>(sourceWindow.get());
+  JSAutoCompartment ac(cx, sourceWin->GetGlobalJSObject());
+
+  // Resolve the baseURI, which could be relative to the calling window.
+  //
+  // Note the algorithm to get the base URI should match the one
+  // used to actually kick off the load in nsWindowWatcher.cpp.
   nsCOMPtr<nsIDocument> doc = sourceWindow->GetDoc();
+  nsIURI* baseURI = nullptr;
+  nsAutoCString charset(NS_LITERAL_CSTRING("UTF-8")); // default to utf-8
   if (doc) {
     baseURI = doc->GetDocBaseURI();
     charset = doc->GetDocumentCharacterSet();
   }
-
-  if (aCXused)
-    *aCXused = cx;
-  return NS_NewURI(aBuiltURI, nsDependentCString(aURL), charset.get(), baseURI);
-}
-
-nsresult
-nsGlobalWindow::SecurityCheckURL(const char *aURL)
-{
-  JSContext       *cxUsed;
   nsCOMPtr<nsIURI> uri;
-
-  if (NS_FAILED(BuildURIfromBase(aURL, getter_AddRefs(uri), &cxUsed))) {
-    return NS_ERROR_FAILURE;
-  }
-
-  if (!cxUsed) {
-    return NS_OK;
-  }
-
-  AutoPushJSContext cx(cxUsed);
+  nsresult rv = NS_NewURI(getter_AddRefs(uri), nsDependentCString(aURL),
+                          charset.get(), baseURI);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
 
   if (NS_FAILED(nsContentUtils::GetSecurityManager()->
         CheckLoadURIFromScript(cx, uri))) {
     return NS_ERROR_FAILURE;
   }
 
   return NS_OK;
 }
--- a/dom/base/nsGlobalWindow.h
+++ b/dom/base/nsGlobalWindow.h
@@ -1193,18 +1193,17 @@ protected:
   void InsertTimeoutIntoList(nsTimeout *aTimeout);
   static void TimerCallback(nsITimer *aTimer, void *aClosure);
 
   // Helper Functions
   already_AddRefed<nsIDocShellTreeOwner> GetTreeOwner();
   already_AddRefed<nsIBaseWindow> GetTreeOwnerWindow();
   already_AddRefed<nsIWebBrowserChrome> GetWebBrowserChrome();
   nsresult SecurityCheckURL(const char *aURL);
-  nsresult BuildURIfromBase(const char *aURL, nsIURI **aBuiltURI,
-                            JSContext **aCXused);
+
   bool PopupWhitelisted();
   PopupControlState RevisePopupAbuseLevel(PopupControlState);
   void     FireAbuseEvents(bool aBlocked, bool aWindow,
                            const nsAString &aPopupURL,
                            const nsAString &aPopupWindowName,
                            const nsAString &aPopupWindowFeatures);
   void FireOfflineStatusEvent();
 
--- a/dom/bindings/Exceptions.cpp
+++ b/dom/bindings/Exceptions.cpp
@@ -126,49 +126,51 @@ Throw(JSContext* aCx, nsresult aRv, cons
         // If we weren't able to throw an exception we're
         // most likely out of memory
         JS_ReportOutOfMemory(aCx);
       }
       return false;
     }
   }
 
-  nsRefPtr<Exception> finalException;
-
-  // Do we use DOM exceptions for this error code?
-  switch (NS_ERROR_GET_MODULE(aRv)) {
-  case NS_ERROR_MODULE_DOM:
-  case NS_ERROR_MODULE_SVG:
-  case NS_ERROR_MODULE_DOM_XPATH:
-  case NS_ERROR_MODULE_DOM_INDEXEDDB:
-  case NS_ERROR_MODULE_DOM_FILEHANDLE:
-    finalException = DOMException::Create(aRv);
-    break;
-
-  default:
-      break;
-  }
-
-  // If not, use the default.
-  if (!finalException) {
-    // aMessage can be null.
-    finalException = new Exception(nsCString(aMessage), aRv,
-                                   EmptyCString(), nullptr, nullptr);
-  }
+  nsRefPtr<Exception> finalException = CreateException(aCx, aRv, aMessage);
 
   MOZ_ASSERT(finalException);
   if (!ThrowExceptionObject(aCx, finalException)) {
     // If we weren't able to throw an exception we're
     // most likely out of memory
     JS_ReportOutOfMemory(aCx);
   }
 
   return false;
 }
 
+already_AddRefed<Exception>
+CreateException(JSContext* aCx, nsresult aRv, const char* aMessage)
+{
+  // Do we use DOM exceptions for this error code?
+  switch (NS_ERROR_GET_MODULE(aRv)) {
+  case NS_ERROR_MODULE_DOM:
+  case NS_ERROR_MODULE_SVG:
+  case NS_ERROR_MODULE_DOM_XPATH:
+  case NS_ERROR_MODULE_DOM_INDEXEDDB:
+  case NS_ERROR_MODULE_DOM_FILEHANDLE:
+    return DOMException::Create(aRv);
+  default:
+    break;
+  }
+
+  // If not, use the default.
+  // aMessage can be null, so we can't use nsDependentCString on it.
+  nsRefPtr<Exception> exception =
+    new Exception(nsCString(aMessage), aRv,
+                  EmptyCString(), nullptr, nullptr);
+  return exception.forget();
+}
+
 already_AddRefed<nsIStackFrame>
 GetCurrentJSStack()
 {
   // is there a current context available?
   JSContext* cx = nullptr;
 
   if (NS_IsMainThread()) {
     // Note, in xpcshell nsContentUtils is never initialized, but we still need
--- a/dom/bindings/Exceptions.h
+++ b/dom/bindings/Exceptions.h
@@ -25,16 +25,21 @@ bool
 Throw(JSContext* cx, nsresult rv, const char* sz = nullptr);
 
 bool
 ThrowExceptionObject(JSContext* aCx, Exception* aException);
 
 bool
 ThrowExceptionObject(JSContext* aCx, nsIException* aException);
 
+// Create an exception object for the given nsresult and message but
+// don't set it pending on aCx.  This never returns null.
+already_AddRefed<Exception>
+CreateException(JSContext* aCx, nsresult aRv, const char* aMessage = nullptr);
+
 already_AddRefed<nsIStackFrame>
 GetCurrentJSStack();
 
 // Internal stuff not intended to be widely used.
 namespace exceptions {
 
 // aMaxDepth can be used to define a maximal depth for the stack trace. If the
 // value is -1, a default maximal depth will be selected.
--- a/dom/bindings/ToJSValue.cpp
+++ b/dom/bindings/ToJSValue.cpp
@@ -1,15 +1,17 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/
 /* vim: set ts=2 sw=2 et tw=79: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/dom/ToJSValue.h"
+#include "mozilla/dom/DOMException.h"
+#include "mozilla/dom/Exceptions.h"
 #include "nsAString.h"
 #include "nsContentUtils.h"
 #include "nsStringBuffer.h"
 #include "xpcpublic.h"
 
 namespace mozilla {
 namespace dom {
 
@@ -44,10 +46,19 @@ ISupportsToJSValue(JSContext* aCx,
                    JS::MutableHandle<JS::Value> aValue)
 {
   nsresult rv = nsContentUtils::WrapNative(aCx, aArgument, aValue);
   return NS_SUCCEEDED(rv);
 }
 
 } // namespace tojsvalue_detail
 
+bool
+ToJSValue(JSContext* aCx,
+          nsresult aArgument,
+          JS::MutableHandle<JS::Value> aValue)
+{
+  nsRefPtr<Exception> exception = CreateException(aCx, aArgument);
+  return ToJSValue(aCx, exception, aValue);
+}
+
 } // namespace dom
 } // namespace mozilla
--- a/dom/bindings/ToJSValue.h
+++ b/dom/bindings/ToJSValue.h
@@ -49,27 +49,36 @@ ToJSValue(JSContext* aCx,
 {
   // Make sure we're called in a compartment
   MOZ_ASSERT(JS::CurrentGlobalOrNull(aCx));
 
   aValue.setInt32(aArgument);
   return true;
 }
 
+// The uint32_t version is disabled for now because on the super-old b2g
+// compiler nsresult and uint32_t are the same type.  If someone needs this at
+// some point we'll need to figure out how to make it work (e.g. by switching to
+// traits structs and using the trick IPC's ParamTraits uses, where a traits
+// struct templated on the type inherits from a base traits struct of some sort,
+// templated on the same type, or something).  Maybe b2g will update to a modern
+// compiler before that happens....
+#if 0
 inline bool
 ToJSValue(JSContext* aCx,
           uint32_t aArgument,
           JS::MutableHandle<JS::Value> aValue)
 {
   // Make sure we're called in a compartment
   MOZ_ASSERT(JS::CurrentGlobalOrNull(aCx));
 
   aValue.setNumber(aArgument);
   return true;
 }
+#endif
 
 inline bool
 ToJSValue(JSContext* aCx,
           int64_t aArgument,
           JS::MutableHandle<JS::Value> aValue)
 {
   // Make sure we're called in a compartment
   MOZ_ASSERT(JS::CurrentGlobalOrNull(aCx));
@@ -198,16 +207,32 @@ template <class T>
 typename EnableIf<IsBaseOf<DictionaryBase, T>::value, bool>::Type
 ToJSValue(JSContext* aCx,
           const T& aArgument,
           JS::MutableHandle<JS::Value> aValue)
 {
   return aArgument.ToObject(aCx, aValue);
 }
 
+// Accept existing JS values (which may not be same-compartment with us
+inline bool
+ToJSValue(JSContext* aCx, JS::Handle<JS::Value> aArgument,
+          JS::MutableHandle<JS::Value> aValue)
+{
+  aValue.set(aArgument);
+  return MaybeWrapValue(aCx, aValue);
+}
+
+// Accept nsresult, for use in rejections, and create an XPCOM
+// exception object representing that nsresult.
+bool
+ToJSValue(JSContext* aCx,
+          nsresult aArgument,
+          JS::MutableHandle<JS::Value> aValue);
+
 // Accept arrays of other things we accept
 template <typename T>
 bool
 ToJSValue(JSContext* aCx,
           T* aArguments,
           size_t aLength,
           JS::MutableHandle<JS::Value> aValue)
 {
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -13,16 +13,18 @@
 #include "IndexedDBChild.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/ClearOnShutdown.h"
 #include "mozilla/EventListenerManager.h"
 #include "mozilla/IntentionalCrash.h"
 #include "mozilla/docshell/OfflineCacheUpdateChild.h"
 #include "mozilla/ipc/DocumentRendererChild.h"
 #include "mozilla/ipc/FileDescriptorUtils.h"
+#include "mozilla/layers/ActiveElementManager.h"
+#include "mozilla/layers/APZCCallbackHelper.h"
 #include "mozilla/layers/AsyncPanZoomController.h"
 #include "mozilla/layers/CompositorChild.h"
 #include "mozilla/layers/ImageBridgeChild.h"
 #include "mozilla/layers/ShadowLayers.h"
 #include "mozilla/layout/RenderFrameChild.h"
 #include "mozilla/MouseEvents.h"
 #include "mozilla/Services.h"
 #include "mozilla/StaticPtr.h"
@@ -63,23 +65,21 @@
 #include "nsThreadUtils.h"
 #include "nsWeakReference.h"
 #include "PermissionMessageUtils.h"
 #include "PCOMContentPermissionRequestChild.h"
 #include "PuppetWidget.h"
 #include "StructuredCloneUtils.h"
 #include "nsViewportInfo.h"
 #include "JavaScriptChild.h"
-#include "APZCCallbackHelper.h"
 #include "nsILoadContext.h"
 #include "ipc/nsGUIEventIPC.h"
 #include "mozilla/gfx/Matrix.h"
 #include "UnitTransforms.h"
 #include "ClientLayerManager.h"
-#include "ActiveElementManager.h"
 
 #include "nsColorPickerProxy.h"
 
 #ifdef DEBUG
 #include "PCOMContentPermissionRequestChild.h"
 #endif /* DEBUG */
 
 #define BROWSER_ELEMENT_CHILD_SCRIPT \
--- a/dom/ipc/TabChild.h
+++ b/dom/ipc/TabChild.h
@@ -37,17 +37,17 @@
 class nsICachedFileDescriptorListener;
 class nsIDOMWindowUtils;
 
 namespace mozilla {
 namespace layout {
 class RenderFrameChild;
 }
 
-namespace widget {
+namespace layers {
 class ActiveElementManager;
 }
 
 namespace dom {
 
 class TabChild;
 class ClonedMessageData;
 class TabChildBase;
@@ -227,17 +227,17 @@ class TabChild : public PBrowserChild,
                  public nsIObserver,
                  public TabContext,
                  public nsITooltipListener,
                  public TabChildBase
 {
     typedef mozilla::dom::ClonedMessageData ClonedMessageData;
     typedef mozilla::layout::RenderFrameChild RenderFrameChild;
     typedef mozilla::layout::ScrollingBehavior ScrollingBehavior;
-    typedef mozilla::widget::ActiveElementManager ActiveElementManager;
+    typedef mozilla::layers::ActiveElementManager ActiveElementManager;
 
 public:
     /** 
      * This is expected to be called off the critical path to content
      * startup.  This is an opportunity to load things that are slow
      * on the critical path.
      */
     static void PreloadSlowThings();
--- a/dom/media/tests/mochitest/pc.js
+++ b/dom/media/tests/mochitest/pc.js
@@ -488,22 +488,31 @@ function PeerConnectionTest(options) {
  * Closes the peer connection if it is active
  *
  * @param {Function} onSuccess
  *        Callback to execute when the peer connection has been closed successfully
  */
 PeerConnectionTest.prototype.close = function PCT_close(onSuccess) {
   info("Closing peer connections. Connection state=" + this.connected);
 
+  function signalingstatechangeClose(state) {
+    info("'onsignalingstatechange' event '" + state + "' received");
+    is(state, "closed", "onsignalingstatechange event is closed");
+  }
+
   // There is no onclose event for the remote peer existent yet. So close it
   // side-by-side with the local peer.
-  if (this.pcLocal)
+  if (this.pcLocal) {
+    this.pcLocal.onsignalingstatechange = signalingstatechangeClose;
     this.pcLocal.close();
-  if (this.pcRemote)
+  }
+  if (this.pcRemote) {
+    this.pcRemote.onsignalingstatechange = signalingstatechangeClose;
     this.pcRemote.close();
+  }
   this.connected = false;
 
   onSuccess();
 };
 
 /**
  * Executes the next command.
  */
@@ -580,18 +589,19 @@ function PCT_setLocalDescription(peer, d
   var stateChanged = false;
 
   function check_next_test() {
     if (eventFired && stateChanged) {
       onSuccess();
     }
   }
 
-  peer.onsignalingstatechange = function () {
-    info(peer + ": 'onsignalingstatechange' event registered, signalingState: " + peer.signalingState);
+  peer.onsignalingstatechange = function (state) {
+    //info(peer + ": 'onsignalingstatechange' event registered, signalingState: " + peer.signalingState);
+    info(peer + ": 'onsignalingstatechange' event '" + state + "' received");
 
     eventFired = true;
     check_next_test();
   };
 
   peer.setLocalDescription(desc, function () {
     stateChanged = true;
     check_next_test();
@@ -641,18 +651,18 @@ function PCT_setRemoteDescription(peer, 
   var stateChanged = false;
 
   function check_next_test() {
     if (eventFired && stateChanged) {
       onSuccess();
     }
   }
 
-  peer.onsignalingstatechange = function () {
-    info(peer + ": 'onsignalingstatechange' event registered, signalingState: " + peer.signalingState);
+  peer.onsignalingstatechange = function (state) {
+    info(peer + ": 'onsignalingstatechange' event '" + state + "' received");
 
     eventFired = true;
     check_next_test();
   };
 
   peer.setRemoteDescription(desc, function () {
     stateChanged = true;
     check_next_test();
@@ -1163,17 +1173,19 @@ function PeerConnectionWrapper(label, co
    * failure will be raised if an event of this type is caught.
    *
    * @param {Object} aEvent
    *        Event data which includes the newly created data channel
    */
   this._pc.onsignalingstatechange = function (aEvent) {
     info(self + ": 'onsignalingstatechange' event fired");
 
-    self.onsignalingstatechange();
+    // this calls the eventhandler only once and then overwrites it with the
+    // default unexpectedEvent handler
+    self.onsignalingstatechange(aEvent);
     self.onsignalingstatechange = unexpectedEventAndFinish(self, 'onsignalingstatechange');
   };
 }
 
 PeerConnectionWrapper.prototype = {
 
   /**
    * Returns the local description.
--- a/dom/media/tests/mochitest/test_peerConnection_bug827843.html
+++ b/dom/media/tests/mochitest/test_peerConnection_bug827843.html
@@ -51,26 +51,36 @@
         test.next();
       }
     ], [
       "CHECK_SDP_ON_CLOSED_PC",
       function (test) {
         var description;
         var exception = null;
 
+        // handle the event which the close() triggers
+        test.pcLocal.onsignalingstatechange = function (state) {
+          is(state, "closed", "Received expected onsignalingstatechange event 'closed'");
+        }
+
         test.pcLocal.close();
 
         try { description = test.pcLocal.localDescription; } catch (e) { exception = e; }
         ok(exception, "Attempt to access localDescription of pcLocal after close throws exception");
         exception = null;
 
         try { description = test.pcLocal.remoteDescription; } catch (e) { exception = e; }
         ok(exception, "Attempt to access remoteDescription of pcLocal after close throws exception");
         exception = null;
 
+        // handle the event which the close() triggers
+        test.pcRemote.onsignalingstatechange = function (state) {
+          is(state, "closed", "Received expected onsignalingstatechange event 'closed'");
+        }
+
         test.pcRemote.close();
 
         try  { description = test.pcRemote.localDescription; } catch (e) { exception = e; }
         ok(exception, "Attempt to access localDescription of pcRemote after close throws exception");
         exception = null;
 
         try  { description = test.pcRemote.remoteDescription; } catch (e) { exception = e; }
         ok(exception, "Attempt to access remoteDescription of pcRemote after close throws exception");
--- a/dom/media/tests/mochitest/test_peerConnection_bug835370.html
+++ b/dom/media/tests/mochitest/test_peerConnection_bug835370.html
@@ -44,16 +44,18 @@
     try { pconnect.createOffer(step1, failed, { optional: [1] }); } catch (e) { exception = e; }
     ok(exception, "createOffer(step1, failed, { optional: [1] }) throws");
     exception = null;
     try { pconnect.createOffer(step1, failed, { optional: [{ OfferToReceiveVideo: false, OfferToReceiveAudio: true, }] }); } catch (e) { exception = e; }
     ok(exception, "createOffer(step1, failed, { optional: [{ OfferToReceiveVideo: false, OfferToReceiveAudio: true, }] }) throws");
     exception = null;
     try { pconnects.createOffer(step1, failed, { mandatory: { OfferToReceiveVideo: false, OfferToReceiveAudio: true, MozDontOfferDataChannel: true}, optional: [{ VoiceActivityDetection: true }, { FooBar: "42"  }] }); } catch (e) { exception = e; }
     ok(!exception, "createOffer(step1, failed, { mandatory: { OfferToReceiveVideo: false, OfferToReceiveAudio: true, MozDontOfferDataChannel: true}, optional: [{ VoiceActivityDetection: true }, { FooBar: \"42\"  }] }) succeeds");
+    pconnect.close();
+    pconnects.close();
     pconnect = null;
     pconnects = null;
     SimpleTest.finish();
   });
 </script>
 </pre>
 </body>
 </html>
--- a/dom/promise/Promise.h
+++ b/dom/promise/Promise.h
@@ -73,25 +73,27 @@ public:
                                      JS::Handle<JS::Value> aValue);
 
   void MaybeResolve(JSContext* aCx,
                     JS::Handle<JS::Value> aValue);
   void MaybeReject(JSContext* aCx,
                    JS::Handle<JS::Value> aValue);
 
   // Helpers for using Promise from C++.
-  // Most DOM objects are handled already.  To add a new type T, such as ints,
-  // or dictionaries, add a ToJSValue overload in ToJSValue.h.
+  // Most DOM objects are handled already.  To add a new type T, add a
+  // ToJSValue overload in ToJSValue.h.
+  // aArg is a const reference so we can pass rvalues like integer constants
   template <typename T>
-  void MaybeResolve(T& aArg) {
+  void MaybeResolve(const T& aArg) {
     MaybeSomething(aArg, &Promise::MaybeResolve);
   }
 
+  // aArg is a const reference so we can pass rvalues like NS_ERROR_*
   template <typename T>
-  void MaybeReject(T& aArg) {
+  void MaybeReject(const T& aArg) {
     MaybeSomething(aArg, &Promise::MaybeReject);
   }
 
   // WebIDL
 
   nsIGlobalObject* GetParentObject() const
   {
     return mGlobal;
--- a/dom/webidl/Console.webidl
+++ b/dom/webidl/Console.webidl
@@ -42,17 +42,22 @@ dictionary ConsoleEvent {
   DOMString functionName = "";
   double timeStamp = 0;
   sequence<any> arguments;
 
   // This array will only hold strings or null elements.
   sequence<any> styles;
 
   boolean private = false;
-  sequence<ConsoleStackEntry> stacktrace;
+  // stacktrace is handled via a getter in some cases so we can construct it
+  // lazily.  Note that we're not making this whole thing an interface because
+  // consumers expect to see own properties on it, which would mean making the
+  // props unforgeable, which means lots of JSFunction allocations.  Maybe we
+  // should fix those consumers, of course....
+  // sequence<ConsoleStackEntry> stacktrace;
   DOMString groupName = "";
   any timer = null;
   any counter = null;
 };
 
 // Event for profile operations
 dictionary ConsoleProfileEvent {
   DOMString action = "";
--- a/dom/webidl/HTMLLinkElement.webidl
+++ b/dom/webidl/HTMLLinkElement.webidl
@@ -23,18 +23,17 @@ interface HTMLLinkElement : HTMLElement 
            attribute DOMString rel;
   readonly attribute DOMTokenList relList;
   [SetterThrows, Pure]
            attribute DOMString media;
   [SetterThrows, Pure]
            attribute DOMString hreflang;
   [SetterThrows, Pure]
            attribute DOMString type;
-// Not supported yet:
-//  [PutForwards=value] readonly attribute DOMSettableTokenList sizes;
+  [PutForwards=value] readonly attribute DOMSettableTokenList sizes;
 };
 HTMLLinkElement implements LinkStyle;
 
 // http://www.whatwg.org/specs/web-apps/current-work/#other-elements,-attributes-and-apis
 partial interface HTMLLinkElement {
   [SetterThrows, Pure]
            attribute DOMString charset;
   [SetterThrows, Pure]
rename from gfx/layers/ipc/GeckoContentController.h
rename to gfx/layers/apz/public/GeckoContentController.h
rename from gfx/layers/composite/APZCTreeManager.cpp
rename to gfx/layers/apz/src/APZCTreeManager.cpp
--- a/gfx/layers/composite/APZCTreeManager.cpp
+++ b/gfx/layers/apz/src/APZCTreeManager.cpp
@@ -1,22 +1,22 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "APZCTreeManager.h"
-#include "AsyncCompositionManager.h"    // for ViewTransform
 #include "Compositor.h"                 // for Compositor
 #include "CompositorParent.h"           // for CompositorParent, etc
 #include "InputData.h"                  // for InputData, etc
 #include "Layers.h"                     // for ContainerLayer, Layer, etc
 #include "gfx3DMatrix.h"                // for gfx3DMatrix
 #include "mozilla/dom/Touch.h"          // for Touch
 #include "mozilla/gfx/Point.h"          // for Point
+#include "mozilla/layers/AsyncCompositionManager.h" // for ViewTransform
 #include "mozilla/layers/AsyncPanZoomController.h"
 #include "mozilla/MouseEvents.h"
 #include "mozilla/mozalloc.h"           // for operator new
 #include "mozilla/TouchEvents.h"
 #include "mozilla/Preferences.h"        // for Preferences
 #include "nsDebug.h"                    // for NS_WARNING
 #include "nsPoint.h"                    // for nsIntPoint
 #include "nsThreadUtils.h"              // for NS_IsMainThread
rename from gfx/layers/composite/APZCTreeManager.h
rename to gfx/layers/apz/src/APZCTreeManager.h
rename from gfx/layers/ipc/AsyncPanZoomController.cpp
rename to gfx/layers/apz/src/AsyncPanZoomController.cpp
--- a/gfx/layers/ipc/AsyncPanZoomController.cpp
+++ b/gfx/layers/apz/src/AsyncPanZoomController.cpp
@@ -9,17 +9,16 @@
 #include <sys/types.h>                  // for int32_t
 #include <algorithm>                    // for max, min
 #include "AnimationCommon.h"            // for ComputedTimingFunction
 #include "AsyncPanZoomController.h"     // for AsyncPanZoomController, etc
 #include "CompositorParent.h"           // for CompositorParent
 #include "FrameMetrics.h"               // for FrameMetrics, etc
 #include "GestureEventListener.h"       // for GestureEventListener
 #include "InputData.h"                  // for MultiTouchInput, etc
-#include "LayerTransactionParent.h"     // for LayerTransactionParent
 #include "Units.h"                      // for CSSRect, CSSPoint, etc
 #include "UnitTransforms.h"             // for TransformTo
 #include "base/message_loop.h"          // for MessageLoop
 #include "base/task.h"                  // for NewRunnableMethod, etc
 #include "base/tracked.h"               // for FROM_HERE
 #include "gfxPrefs.h"                   // for gfxPrefs
 #include "gfxTypes.h"                   // for gfxFloat
 #include "mozilla/Assertions.h"         // for MOZ_ASSERT, etc
@@ -35,17 +34,17 @@
 #include "mozilla/gfx/BasePoint.h"      // for BasePoint
 #include "mozilla/gfx/BaseRect.h"       // for BaseRect
 #include "mozilla/gfx/Point.h"          // for Point, RoundedToInt, etc
 #include "mozilla/gfx/Rect.h"           // for RoundedIn
 #include "mozilla/gfx/ScaleFactor.h"    // for ScaleFactor
 #include "mozilla/layers/APZCTreeManager.h"  // for ScrollableLayerGuid
 #include "mozilla/layers/AsyncCompositionManager.h"  // for ViewTransform
 #include "mozilla/layers/Axis.h"        // for AxisX, AxisY, Axis, etc
-#include "mozilla/layers/GeckoContentController.h"
+#include "mozilla/layers/LayerTransactionParent.h" // for LayerTransactionParent
 #include "mozilla/layers/PCompositorParent.h" // for PCompositorParent
 #include "mozilla/layers/TaskThrottler.h"  // for TaskThrottler
 #include "mozilla/mozalloc.h"           // for operator new, etc
 #include "mozilla/unused.h"             // for unused
 #include "mozilla/FloatingPoint.h"      // for FuzzyEqualsMultiplicative
 #include "nsAlgorithm.h"                // for clamped
 #include "nsAutoPtr.h"                  // for nsRefPtr
 #include "nsCOMPtr.h"                   // for already_AddRefed
@@ -614,19 +613,20 @@ nsEventStatus AsyncPanZoomController::On
       // Fall through.
     case FLING:
       CancelAnimation();
       // Fall through.
     case NOTHING: {
       mX.StartTouch(point.x);
       mY.StartTouch(point.y);
       APZCTreeManager* treeManagerLocal = mTreeManager;
-      if (treeManagerLocal) {
+      nsRefPtr<GeckoContentController> controller = GetGeckoContentController();
+      if (treeManagerLocal && controller) {
         bool touchCanBePan = treeManagerLocal->CanBePanned(this);
-        mGeckoContentController->NotifyAPZStateChange(
+        controller->NotifyAPZStateChange(
             GetGuid(), APZStateChange::StartTouch, touchCanBePan);
       }
       SetState(TOUCHING);
       break;
     }
     case TOUCHING:
     case PANNING:
     case PANNING_LOCKED_X:
@@ -957,18 +957,20 @@ nsEventStatus AsyncPanZoomController::Ge
       mTouchBlockState.mSingleTapOccurred = true;
       return nsEventStatus_eConsumeNoDefault;
     }
   }
   return nsEventStatus_eIgnore;
 }
 
 void AsyncPanZoomController::OnTouchEndOrCancel() {
-  mGeckoContentController->NotifyAPZStateChange(
-      GetGuid(), APZStateChange::EndTouch, mTouchBlockState.mSingleTapOccurred);
+  if (nsRefPtr<GeckoContentController> controller = GetGeckoContentController()) {
+    controller->NotifyAPZStateChange(
+        GetGuid(), APZStateChange::EndTouch, mTouchBlockState.mSingleTapOccurred);
+  }
 }
 
 nsEventStatus AsyncPanZoomController::OnSingleTapUp(const TapGestureInput& aEvent) {
   APZC_LOG("%p got a single-tap-up in state %d\n", this, mState);
   // If mZoomConstraints.mAllowDoubleTapZoom is true we wait for a call to OnSingleTapConfirmed before
   // sending event to content
   if (!mZoomConstraints.mAllowDoubleTapZoom) {
     return GenerateSingleTap(aEvent.mPoint, aEvent.modifiers);
@@ -1103,17 +1105,19 @@ nsEventStatus AsyncPanZoomController::St
     if (GetAxisLockMode() == FREE) {
       SetState(PANNING);
     } else {
       HandlePanning(angle);
     }
   }
 
   if (IsPanningState(mState)) {
-    mGeckoContentController->NotifyAPZStateChange(GetGuid(), APZStateChange::StartPanning);
+    if (nsRefPtr<GeckoContentController> controller = GetGeckoContentController()) {
+      controller->NotifyAPZStateChange(GetGuid(), APZStateChange::StartPanning);
+    }
     return nsEventStatus_eConsumeNoDefault;
   }
   // Don't consume an event that didn't trigger a panning.
   return nsEventStatus_eIgnore;
 }
 
 void AsyncPanZoomController::UpdateWithTouchAtDevicePoint(const MultiTouchInput& aEvent) {
   ScreenIntPoint point = GetFirstTouchScreenPoint(aEvent);
@@ -2002,22 +2006,22 @@ void AsyncPanZoomController::SetState(Pa
 
   // Intentional scoping for mutex
   {
     ReentrantMonitorAutoEnter lock(mMonitor);
     oldState = mState;
     mState = aNewState;
   }
 
-  if (mGeckoContentController) {
+  if (nsRefPtr<GeckoContentController> controller = GetGeckoContentController()) {
     if (!IsTransformingState(oldState) && IsTransformingState(aNewState)) {
-      mGeckoContentController->NotifyAPZStateChange(
+      controller->NotifyAPZStateChange(
           GetGuid(), APZStateChange::TransformBegin);
     } else if (IsTransformingState(oldState) && !IsTransformingState(aNewState)) {
-      mGeckoContentController->NotifyAPZStateChange(
+      controller->NotifyAPZStateChange(
           GetGuid(), APZStateChange::TransformEnd);
     }
   }
 }
 
 bool AsyncPanZoomController::IsTransformingState(PanZoomState aState) {
   return !(aState == NOTHING || aState == TOUCHING || aState == WAITING_CONTENT_RESPONSE);
 }
rename from gfx/layers/ipc/AsyncPanZoomController.h
rename to gfx/layers/apz/src/AsyncPanZoomController.h
--- a/gfx/layers/ipc/AsyncPanZoomController.h
+++ b/gfx/layers/apz/src/AsyncPanZoomController.h
@@ -3,17 +3,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_layers_AsyncPanZoomController_h
 #define mozilla_layers_AsyncPanZoomController_h
 
 #include "CrossProcessMutex.h"
-#include "GeckoContentController.h"
+#include "mozilla/layers/GeckoContentController.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/EventForwards.h"
 #include "mozilla/Monitor.h"
 #include "mozilla/ReentrantMonitor.h"
 #include "mozilla/RefPtr.h"
 #include "mozilla/Atomics.h"
 #include "InputData.h"
 #include "Axis.h"
rename from gfx/layers/ipc/Axis.cpp
rename to gfx/layers/apz/src/Axis.cpp
rename from gfx/layers/ipc/Axis.h
rename to gfx/layers/apz/src/Axis.h
rename from gfx/layers/ipc/GestureEventListener.cpp
rename to gfx/layers/apz/src/GestureEventListener.cpp
rename from gfx/layers/ipc/GestureEventListener.h
rename to gfx/layers/apz/src/GestureEventListener.h
rename from gfx/layers/ipc/TaskThrottler.cpp
rename to gfx/layers/apz/src/TaskThrottler.cpp
rename from gfx/layers/ipc/TaskThrottler.h
rename to gfx/layers/apz/src/TaskThrottler.h
rename from widget/xpwidgets/APZCCallbackHelper.cpp
rename to gfx/layers/apz/util/APZCCallbackHelper.cpp
--- a/widget/xpwidgets/APZCCallbackHelper.cpp
+++ b/gfx/layers/apz/util/APZCCallbackHelper.cpp
@@ -7,17 +7,17 @@
 #include "gfxPrefs.h" // For gfxPrefs::LayersTilesEnabled, LayersTileWidth/Height
 #include "mozilla/Preferences.h"
 #include "nsIScrollableFrame.h"
 #include "nsLayoutUtils.h"
 #include "nsIDOMElement.h"
 #include "nsIInterfaceRequestorUtils.h"
 
 namespace mozilla {
-namespace widget {
+namespace layers {
 
 bool
 APZCCallbackHelper::HasValidPresShellId(nsIDOMWindowUtils* aUtils,
                                         const FrameMetrics& aMetrics)
 {
     MOZ_ASSERT(aUtils);
 
     uint32_t presShellId;
rename from widget/xpwidgets/APZCCallbackHelper.h
rename to gfx/layers/apz/util/APZCCallbackHelper.h
--- a/widget/xpwidgets/APZCCallbackHelper.h
+++ b/gfx/layers/apz/util/APZCCallbackHelper.h
@@ -1,23 +1,23 @@
 /* -*- 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 __mozilla_widget_APZCCallbackHelper_h__
-#define __mozilla_widget_APZCCallbackHelper_h__
+#ifndef mozilla_layers_APZCCallbackHelper_h
+#define mozilla_layers_APZCCallbackHelper_h
 
 #include "FrameMetrics.h"
 #include "nsIContent.h"
 #include "nsIDocument.h"
 #include "nsIDOMWindowUtils.h"
 
 namespace mozilla {
-namespace widget {
+namespace layers {
 
 /* This class contains some helper methods that facilitate implementing the
    GeckoContentController callback interface required by the AsyncPanZoomController.
    Since different platforms need to implement this interface in similar-but-
    not-quite-the-same ways, this utility class provides some helpful methods
    to hold code that can be shared across the different platform implementations.
  */
 class APZCCallbackHelper
@@ -95,9 +95,9 @@ public:
     static nsIntPoint ApplyCallbackTransform(const nsIntPoint& aPoint,
                                              const ScrollableLayerGuid& aGuid,
                                              const CSSToLayoutDeviceScale& aScale);
 };
 
 }
 }
 
-#endif /*__mozilla_widget_APZCCallbackHelper_h__ */
+#endif /* mozilla_layers_APZCCallbackHelper_h */
rename from widget/xpwidgets/ActiveElementManager.cpp
rename to gfx/layers/apz/util/ActiveElementManager.cpp
--- a/widget/xpwidgets/ActiveElementManager.cpp
+++ b/gfx/layers/apz/util/ActiveElementManager.cpp
@@ -10,17 +10,17 @@
 #include "inIDOMUtils.h"
 #include "nsIDOMDocument.h"
 #include "nsIDOMElement.h"
 #include "nsIDOMEventTarget.h"
 #include "base/message_loop.h"
 #include "base/task.h"
 
 namespace mozilla {
-namespace widget {
+namespace layers {
 
 static int32_t sActivationDelayMs = 100;
 static bool sActivationDelayMsSet = false;
 
 ActiveElementManager::ActiveElementManager()
   : mDomUtils(services::GetInDOMUtils()),
     mCanBePan(false),
     mCanBePanSet(false),
@@ -143,9 +143,9 @@ ActiveElementManager::CancelTask()
 {
   if (mSetActiveTask) {
     mSetActiveTask->Cancel();
     mSetActiveTask = nullptr;
   }
 }
 
 }
-}
\ No newline at end of file
+}
rename from widget/xpwidgets/ActiveElementManager.h
rename to gfx/layers/apz/util/ActiveElementManager.h
--- a/widget/xpwidgets/ActiveElementManager.h
+++ b/gfx/layers/apz/util/ActiveElementManager.h
@@ -1,26 +1,26 @@
 /* -*- 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 __mozilla_widget_ActiveElementManager_h__
-#define __mozilla_widget_ActiveElementManager_h__
+#ifndef mozilla_layers_ActiveElementManager_h
+#define mozilla_layers_ActiveElementManager_h
 
 #include "nsCOMPtr.h"
 #include "nsISupportsImpl.h"
 
 class inIDOMUtils;
 class nsIDOMEventTarget;
 class nsIDOMElement;
 class CancelableTask;
 
 namespace mozilla {
-namespace widget {
+namespace layers {
 
 /**
  * Manages setting and clearing the ':active' CSS pseudostate in the presence
  * of touch input.
  */
 class ActiveElementManager {
 public:
   NS_INLINE_DECL_REFCOUNTING(ActiveElementManager)
@@ -77,9 +77,9 @@ private:
   void ResetActive();
   void SetActiveTask(nsIDOMElement* aTarget);
   void CancelTask();
 };
 
 }
 }
 
-#endif /*__mozilla_widget_ActiveElementManager_h__ */
+#endif /* mozilla_layers_ActiveElementManager_h */
--- a/gfx/layers/ipc/ImageBridgeParent.cpp
+++ b/gfx/layers/ipc/ImageBridgeParent.cpp
@@ -29,17 +29,16 @@
 #include "nsDebug.h"                    // for NS_RUNTIMEABORT, etc
 #include "nsISupportsImpl.h"            // for ImageBridgeParent::Release, etc
 #include "nsTArray.h"                   // for nsTArray, nsTArray_Impl
 #include "nsTArrayForwardDeclare.h"     // for InfallibleTArray
 #include "nsXULAppAPI.h"                // for XRE_GetIOMessageLoop
 #include "mozilla/layers/TextureHost.h"
 #include "nsThreadUtils.h"
 
-using namespace base;
 using namespace mozilla::ipc;
 using namespace mozilla::gfx;
 
 namespace mozilla {
 namespace layers {
 
 class PGrallocBufferParent;
 
@@ -113,25 +112,25 @@ ImageBridgeParent::RecvUpdateNoSwap(cons
   bool success = RecvUpdate(aEdits, &noReplies);
   NS_ABORT_IF_FALSE(noReplies.Length() == 0, "RecvUpdateNoSwap requires a sync Update to carry Edits");
   return success;
 }
 
 static void
 ConnectImageBridgeInParentProcess(ImageBridgeParent* aBridge,
                                   Transport* aTransport,
-                                  ProcessHandle aOtherProcess)
+                                  base::ProcessHandle aOtherProcess)
 {
   aBridge->Open(aTransport, aOtherProcess, XRE_GetIOMessageLoop(), ipc::ParentSide);
 }
 
 /*static*/ PImageBridgeParent*
 ImageBridgeParent::Create(Transport* aTransport, ProcessId aOtherProcess)
 {
-  ProcessHandle processHandle;
+  base::ProcessHandle processHandle;
   if (!base::OpenProcessHandle(aOtherProcess, &processHandle)) {
     return nullptr;
   }
 
   MessageLoop* loop = CompositorParent::CompositorLoop();
   nsRefPtr<ImageBridgeParent> bridge = new ImageBridgeParent(loop, aTransport);
   bridge->mSelfRef = bridge;
   loop->PostTask(FROM_HERE,
--- a/gfx/layers/ipc/LayerTransactionParent.cpp
+++ b/gfx/layers/ipc/LayerTransactionParent.cpp
@@ -36,17 +36,17 @@
 #include "nsISupportsImpl.h"            // for Layer::Release, etc
 #include "nsLayoutUtils.h"              // for nsLayoutUtils
 #include "nsMathUtils.h"                // for NS_round
 #include "nsPoint.h"                    // for nsPoint
 #include "nsTArray.h"                   // for nsTArray, nsTArray_Impl, etc
 #include "GeckoProfiler.h"
 #include "mozilla/layers/TextureHost.h"
 #include "mozilla/layers/AsyncCompositionManager.h"
-#include "AsyncPanZoomController.h"
+#include "mozilla/layers/AsyncPanZoomController.h"
 
 typedef std::vector<mozilla::layers::EditReply> EditReplyVector;
 
 using mozilla::layout::RenderFrameParent;
 
 namespace mozilla {
 namespace layers {
 
--- a/gfx/layers/moz.build
+++ b/gfx/layers/moz.build
@@ -92,64 +92,68 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'wind
             'd3d11/CompositorD3D11.cpp',
         ]
 
 EXPORTS.gfxipc += [
     'ipc/ShadowLayerUtils.h',
 ]
 
 EXPORTS.mozilla.layers += [
+    'apz/public/GeckoContentController.h',
+    # exporting things from apz/src is temporary until we extract a
+    # proper interface for the code there
+    'apz/src/APZCTreeManager.h',
+    'apz/src/AsyncPanZoomController.h',
+    'apz/src/Axis.h',
+    'apz/src/GestureEventListener.h',
+    'apz/src/TaskThrottler.h',
+    'apz/util/ActiveElementManager.h',
+    'apz/util/APZCCallbackHelper.h',
     'AtomicRefCountedWithFinalize.h',
     'basic/BasicCompositor.h',
     'basic/MacIOSurfaceTextureHostBasic.h',
     'basic/TextureHostBasic.h',
     'client/CanvasClient.h',
     'client/CompositableClient.h',
     'client/ContentClient.h',
     'client/ImageClient.h',
     'client/SimpleTextureClientPool.h',
     'client/SimpleTiledContentClient.h',
     'client/TextureClient.h',
     'client/TextureClientPool.h',
     'client/TiledContentClient.h',
-    'composite/APZCTreeManager.h',
     'composite/AsyncCompositionManager.h',
     'composite/CanvasLayerComposite.h',
     'composite/ColorLayerComposite.h',
     'composite/ContainerLayerComposite.h',
     'composite/ContentHost.h',
     'composite/ImageHost.h',
     'composite/ImageLayerComposite.h',
     'composite/LayerManagerComposite.h',
     'composite/TextureHost.h',
     'composite/ThebesLayerComposite.h',
     'Compositor.h',
     'CompositorTypes.h',
     'D3D9SurfaceImage.h',
     'Effects.h',
     'ImageDataSerializer.h',
-    'ipc/AsyncPanZoomController.h',
-    'ipc/Axis.h',
     'ipc/CompositableForwarder.h',
     'ipc/CompositableTransactionParent.h',
     'ipc/CompositorChild.h',
     'ipc/CompositorParent.h',
     'ipc/FenceUtils.h',
-    'ipc/GeckoContentController.h',
-    'ipc/GestureEventListener.h',
     'ipc/ImageBridgeChild.h',
     'ipc/ImageBridgeParent.h',
     'ipc/ISurfaceAllocator.h',
     'ipc/LayerTransactionChild.h',
     'ipc/LayerTransactionParent.h',
     'ipc/ShadowLayers.h',
     'ipc/ShadowLayersManager.h',
     'ipc/SharedPlanarYCbCrImage.h',
     'ipc/SharedRGBImage.h',
-    'ipc/TaskThrottler.h',
     'LayersTypes.h',
     'opengl/CompositingRenderTargetOGL.h',
     'opengl/CompositorOGL.h',
     'opengl/GrallocTextureClient.h',
     'opengl/GrallocTextureHost.h',
     'opengl/MacIOSurfaceTextureClientOGL.h',
     'opengl/MacIOSurfaceTextureHostOGL.h',
     'opengl/TextureClientOGL.h',
@@ -211,16 +215,23 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk
         EXPORTS.mozilla.layers += [
             'ipc/FenceUtilsGonk.h',
         ]
         SOURCES += [
             'ipc/FenceUtilsGonk.cpp',
         ]
 
 UNIFIED_SOURCES += [
+    'apz/src/APZCTreeManager.cpp',
+    'apz/src/AsyncPanZoomController.cpp',
+    'apz/src/Axis.cpp',
+    'apz/src/GestureEventListener.cpp',
+    'apz/src/TaskThrottler.cpp',
+    'apz/util/ActiveElementManager.cpp',
+    'apz/util/APZCCallbackHelper.cpp',
     'basic/BasicCanvasLayer.cpp',
     'basic/BasicColorLayer.cpp',
     'basic/BasicCompositor.cpp',
     'basic/BasicContainerLayer.cpp',
     'basic/BasicImages.cpp',
     'basic/BasicLayerManager.cpp',
     'basic/BasicLayersImpl.cpp',
     'basic/BasicThebesLayer.cpp',
@@ -237,17 +248,16 @@ UNIFIED_SOURCES += [
     'client/CompositableClient.cpp',
     'client/ContentClient.cpp',
     'client/ImageClient.cpp',
     'client/SimpleTextureClientPool.cpp',
     'client/SimpleTiledContentClient.cpp',
     'client/TextureClient.cpp',
     'client/TextureClientPool.cpp',
     'client/TiledContentClient.cpp',
-    'composite/APZCTreeManager.cpp',
     'composite/AsyncCompositionManager.cpp',
     'composite/CanvasLayerComposite.cpp',
     'composite/ColorLayerComposite.cpp',
     'composite/CompositableHost.cpp',
     'composite/ContainerLayerComposite.cpp',
     'composite/ContentHost.cpp',
     'composite/ImageHost.cpp',
     'composite/ImageLayerComposite.cpp',
@@ -256,33 +266,29 @@ UNIFIED_SOURCES += [
     'composite/TextureHost.cpp',
     'composite/ThebesLayerComposite.cpp',
     'composite/TiledContentHost.cpp',
     'Compositor.cpp',
     'CopyableCanvasLayer.cpp',
     'Effects.cpp',
     'ImageDataSerializer.cpp',
     'ImageLayers.cpp',
-    'ipc/AsyncPanZoomController.cpp',
-    'ipc/Axis.cpp',
     'ipc/CompositableTransactionParent.cpp',
     'ipc/CompositorChild.cpp',
     'ipc/CompositorParent.cpp',
-    'ipc/GestureEventListener.cpp',
     'ipc/ImageBridgeChild.cpp',
     'ipc/ImageBridgeParent.cpp',
     'ipc/ISurfaceAllocator.cpp',
     'ipc/LayerTransactionChild.cpp',
     'ipc/LayerTransactionParent.cpp',
     'ipc/ShadowLayerChild.cpp',
     'ipc/ShadowLayerParent.cpp',
     'ipc/ShadowLayers.cpp',
     'ipc/SharedPlanarYCbCrImage.cpp',
     'ipc/SharedRGBImage.cpp',
-    'ipc/TaskThrottler.cpp',
     'LayerScope.cpp',
     'LayersLogging.cpp',
     'LayerSorter.cpp',
     'LayerUtils.cpp',
     'opengl/CompositingRenderTargetOGL.cpp',
     'opengl/CompositorOGL.cpp',
     'opengl/OGLShaderProgram.cpp',
     'opengl/TextureClientOGL.cpp',
--- a/gfx/thebes/gfxMacPlatformFontList.mm
+++ b/gfx/thebes/gfxMacPlatformFontList.mm
@@ -825,23 +825,23 @@ gfxMacPlatformFontList::RegisteredFontsC
                                                                    CFStringRef name,
                                                                    const void *object,
                                                                    CFDictionaryRef userInfo)
 {
     if (!::CFEqual(name, kCTFontManagerRegisteredFontsChangedNotification)) {
         return;
     }
 
+    gfxMacPlatformFontList* fl = static_cast<gfxMacPlatformFontList*>(observer);
+
     // xxx - should be carefully pruning the list of fonts, not rebuilding it from scratch
-    static_cast<gfxMacPlatformFontList*>(observer)->UpdateFontList();
+    fl->UpdateFontList();
 
     // modify a preference that will trigger reflow everywhere
-    static const char kPrefName[] = "font.internaluseonly.changed";
-    bool fontInternalChange = Preferences::GetBool(kPrefName, false);
-    Preferences::SetBool(kPrefName, !fontInternalChange);
+    fl->ForceGlobalReflow();
 }
 
 gfxFontEntry*
 gfxMacPlatformFontList::GlobalFontFallback(const uint32_t aCh,
                                            int32_t aRunScript,
                                            const gfxFontStyle* aMatchStyle,
                                            uint32_t& aCmapCount,
                                            gfxFontFamily** aMatchedFamily)
--- a/gfx/thebes/gfxPlatformFontList.cpp
+++ b/gfx/thebes/gfxPlatformFontList.cpp
@@ -4,16 +4,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifdef MOZ_LOGGING
 #define FORCE_PR_LOG /* Allow logging in the release build */
 #endif
 #include "prlog.h"
 
 #include "gfxPlatformFontList.h"
+#include "gfxUserFontSet.h"
 
 #include "nsUnicharUtils.h"
 #include "nsUnicodeRange.h"
 #include "nsUnicodeProperties.h"
 
 #include "mozilla/Attributes.h"
 #include "mozilla/Likely.h"
 #include "mozilla/MemoryReporting.h"
@@ -298,16 +299,31 @@ gfxPlatformFontList::ResolveFontName(con
     gfxFontFamily *family = FindFamily(aFontName);
     if (family) {
         aResolvedFontName = family->Name();
         return true;
     }
     return false;
 }
 
+static PLDHashOperator
+RebuildLocalFonts(nsPtrHashKey<gfxUserFontSet>* aKey,
+                  void* aClosure)
+{
+    aKey->GetKey()->RebuildLocalRules();
+    return PL_DHASH_NEXT;
+}
+
+void
+gfxPlatformFontList::UpdateFontList()
+{
+    InitFontList();
+    mUserFontSetList.EnumerateEntries(RebuildLocalFonts, nullptr);
+}
+
 struct FontListData {
     FontListData(nsIAtom *aLangGroup,
                  const nsACString& aGenericFamily,
                  nsTArray<nsString>& aListOfFonts) :
         mLangGroup(aLangGroup), mGenericFamily(aGenericFamily),
         mListOfFonts(aListOfFonts) {}
     nsIAtom *mLangGroup;
     const nsACString& mGenericFamily;
@@ -792,16 +808,21 @@ gfxPlatformFontList::LoadFontInfo()
 #ifdef PR_LOGGING
     if (LOG_FONTINIT_ENABLED()) {
         TimeDuration elapsed = TimeStamp::Now() - start;
         LOG_FONTINIT(("(fontinit) fontloader load pass %8.2f ms done %s\n",
                       elapsed.ToMilliseconds(), (done ? "true" : "false")));
     }
 #endif
 
+    if (done) {
+        mOtherFamilyNamesInitialized = true;
+        mFaceNamesInitialized = true;
+    }
+
     return done;
 }
 
 void 
 gfxPlatformFontList::CleanupLoader()
 {
     mFontFamiliesToLoad.Clear();
     mNumFamilies = 0;
@@ -815,18 +836,16 @@ gfxPlatformFontList::CleanupLoader()
                       mFontInfo->mLoadStats.families,
                       mFontInfo->mLoadStats.fonts,
                       mFontInfo->mLoadStats.cmaps,
                       mFontInfo->mLoadStats.facenames,
                       mFontInfo->mLoadStats.othernames));
     }
 #endif
 
-    mOtherFamilyNamesInitialized = true;
-    mFaceNamesInitialized = true;
     gfxFontInfoLoader::CleanupLoader();
 }
 
 void
 gfxPlatformFontList::GetPrefsAndStartLoader()
 {
     mIncrement =
         std::max(1u, Preferences::GetUint(FONT_LOADER_FAMILIES_PER_SLICE_PREF));
@@ -834,16 +853,25 @@ gfxPlatformFontList::GetPrefsAndStartLoa
     uint32_t delay =
         std::max(1u, Preferences::GetUint(FONT_LOADER_DELAY_PREF));
     uint32_t interval =
         std::max(1u, Preferences::GetUint(FONT_LOADER_INTERVAL_PREF));
 
     StartLoader(delay, interval);
 }
 
+void
+gfxPlatformFontList::ForceGlobalReflow()
+{
+    // modify a preference that will trigger reflow everywhere
+    static const char kPrefName[] = "font.internaluseonly.changed";
+    bool fontInternalChange = Preferences::GetBool(kPrefName, false);
+    Preferences::SetBool(kPrefName, !fontInternalChange);
+}
+
 // Support for memory reporting
 
 static size_t
 SizeOfFamilyEntryExcludingThis(const nsAString&               aKey,
                                const nsRefPtr<gfxFontFamily>& aFamily,
                                MallocSizeOf                   aMallocSizeOf,
                                void*                          aUserArg)
 {
--- a/gfx/thebes/gfxPlatformFontList.h
+++ b/gfx/thebes/gfxPlatformFontList.h
@@ -77,16 +77,18 @@ protected:
 struct FontListSizes {
     uint32_t mFontListSize; // size of the font list and dependent objects
                             // (font family and face names, etc), but NOT
                             // including the font table cache and the cmaps
     uint32_t mFontTableCacheSize; // memory used for the gfxFontEntry table caches
     uint32_t mCharMapsSize; // memory used for cmap coverage info
 };
 
+class gfxUserFontSet;
+
 class gfxPlatformFontList : public gfxFontInfoLoader
 {
 public:
     static gfxPlatformFontList* PlatformFontList() {
         return sPlatformFontList;
     }
 
     static nsresult Init() {
@@ -110,17 +112,17 @@ public:
 
     void GetFontList (nsIAtom *aLangGroup,
                       const nsACString& aGenericFamily,
                       nsTArray<nsString>& aListOfFonts);
 
     virtual bool ResolveFontName(const nsAString& aFontName,
                                    nsAString& aResolvedFontName);
 
-    void UpdateFontList() { InitFontList(); }
+    void UpdateFontList();
 
     void ClearPrefFonts() { mPrefFonts.Clear(); }
 
     virtual void GetFontFamilyList(nsTArray<nsRefPtr<gfxFontFamily> >& aFamilyArray);
 
     virtual gfxFontEntry*
     SystemFindFontForChar(const uint32_t aCh,
                           int32_t aRunScript,
@@ -173,16 +175,25 @@ public:
     gfxCharacterMap* FindCharMap(gfxCharacterMap *aCmap);
 
     // add a cmap to the shared cmap set
     gfxCharacterMap* AddCmap(const gfxCharacterMap *aCharMap);
 
     // remove the cmap from the shared cmap set
     void RemoveCmap(const gfxCharacterMap *aCharMap);
 
+    // keep track of userfont sets to notify when global fontlist changes occur
+    void AddUserFontSet(gfxUserFontSet *aUserFontSet) {
+        mUserFontSetList.PutEntry(aUserFontSet);
+    }
+
+    void RemoveUserFontSet(gfxUserFontSet *aUserFontSet) {
+        mUserFontSetList.RemoveEntry(aUserFontSet);
+    }
+
 protected:
     class MemoryReporter MOZ_FINAL : public nsIMemoryReporter
     {
     public:
         NS_DECL_ISUPPORTS
         NS_DECL_NSIMEMORYREPORTER
     };
 
@@ -249,16 +260,19 @@ protected:
     // gfxFontInfoLoader overrides, used to load in font cmaps
     virtual void InitLoader();
     virtual bool LoadFontInfo();
     virtual void CleanupLoader();
 
     // read the loader initialization prefs, and start it
     void GetPrefsAndStartLoader();
 
+    // for font list changes that affect all documents
+    void ForceGlobalReflow();
+
     // used by memory reporter to accumulate sizes of family names in the hash
     static size_t
     SizeOfFamilyNameEntryExcludingThis(const nsAString&               aKey,
                                        const nsRefPtr<gfxFontFamily>& aFamily,
                                        mozilla::MallocSizeOf          aMallocSizeOf,
                                        void*                          aUserArg);
 
     // canonical family name ==> family entry (unique, one name per family entry)
@@ -300,11 +314,13 @@ protected:
     // contains weak ptrs to cmaps shared by font entry objects
     nsTHashtable<CharMapHashKey> mSharedCmaps;
 
     // data used as part of the font cmap loading process
     nsTArray<nsRefPtr<gfxFontFamily> > mFontFamiliesToLoad;
     uint32_t mStartIndex;
     uint32_t mIncrement;
     uint32_t mNumFamilies;
+
+    nsTHashtable<nsPtrHashKey<gfxUserFontSet> > mUserFontSetList;
 };
 
 #endif /* GFXPLATFORMFONTLIST_H_ */
--- a/gfx/thebes/gfxUserFontSet.cpp
+++ b/gfx/thebes/gfxUserFontSet.cpp
@@ -13,16 +13,17 @@
 #include "nsUnicharUtils.h"
 #include "nsNetUtil.h"
 #include "nsICacheService.h"
 #include "nsIProtocolHandler.h"
 #include "nsIPrincipal.h"
 #include "gfxFontConstants.h"
 #include "mozilla/Services.h"
 #include "mozilla/gfx/2D.h"
+#include "gfxPlatformFontList.h"
 
 #include "opentype-sanitiser.h"
 #include "ots-memory-stream.h"
 
 using namespace mozilla;
 
 #ifdef PR_LOGGING
 PRLogModuleInfo *
@@ -97,23 +98,31 @@ gfxProxyFontEntry::Matches(const nsTArra
 gfxFont*
 gfxProxyFontEntry::CreateFontInstance(const gfxFontStyle *aFontStyle, bool aNeedsBold)
 {
     // cannot create an actual font for a proxy entry
     return nullptr;
 }
 
 gfxUserFontSet::gfxUserFontSet()
-    : mFontFamilies(5)
+    : mFontFamilies(5), mLocalRulesUsed(false)
 {
     IncrementGeneration();
+    gfxPlatformFontList *fp = gfxPlatformFontList::PlatformFontList();
+    if (fp) {
+        fp->AddUserFontSet(this);
+    }
 }
 
 gfxUserFontSet::~gfxUserFontSet()
 {
+    gfxPlatformFontList *fp = gfxPlatformFontList::PlatformFontList();
+    if (fp) {
+        fp->RemoveUserFontSet(this);
+    }
 }
 
 gfxFontEntry*
 gfxUserFontSet::AddFontFace(const nsAString& aFamilyName,
                             const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList,
                             uint32_t aWeight,
                             int32_t aStretch,
                             uint32_t aItalicStyle,
@@ -534,16 +543,17 @@ gfxUserFontSet::LoadNext(gfxMixedFontFam
         const gfxFontFaceSrc& currSrc = aProxyEntry->mSrcList[aProxyEntry->mSrcIndex];
 
         // src local ==> lookup and load immediately
 
         if (currSrc.mIsLocal) {
             gfxFontEntry *fe =
                 gfxPlatform::GetPlatform()->LookupLocalFont(aProxyEntry,
                                                             currSrc.mLocalName);
+            mLocalRulesUsed = true;
             if (fe) {
                 LOG(("userfonts (%p) [src %d] loaded local: (%s) for (%s) gen: %8.8x\n",
                      this, aProxyEntry->mSrcIndex,
                      NS_ConvertUTF16toUTF8(currSrc.mLocalName).get(),
                      NS_ConvertUTF16toUTF8(aFamily->Name()).get(),
                      uint32_t(mGeneration)));
                 fe->mFeatureSettings.AppendElements(aProxyEntry->mFeatureSettings);
                 fe->mLanguageOverride = aProxyEntry->mLanguageOverride;
@@ -659,16 +669,23 @@ gfxUserFontSet::IncrementGeneration()
 {
     // add one, increment again if zero
     ++sFontSetGeneration;
     if (sFontSetGeneration == 0)
        ++sFontSetGeneration;
     mGeneration = sFontSetGeneration;
 }
 
+void
+gfxUserFontSet::RebuildLocalRules()
+{
+    if (mLocalRulesUsed) {
+        DoRebuildUserFontSet();
+    }
+}
 
 gfxFontEntry*
 gfxUserFontSet::LoadFont(gfxMixedFontFamily *aFamily,
                          gfxProxyFontEntry *aProxy,
                          const uint8_t *aFontData, uint32_t &aLength)
 {
     gfxFontEntry *fe = nullptr;
 
--- a/gfx/thebes/gfxUserFontSet.h
+++ b/gfx/thebes/gfxUserFontSet.h
@@ -237,16 +237,19 @@ public:
 
     // generation - each time a face is loaded, generation is
     // incremented so that the change can be recognized 
     uint64_t GetGeneration() { return mGeneration; }
 
     // increment the generation on font load
     void IncrementGeneration();
 
+    // rebuild if local rules have been used
+    void RebuildLocalRules();
+
     class UserFontCache {
     public:
         // Record a loaded user-font in the cache. This requires that the
         // font-entry's userFontData has been set up already, as it relies
         // on the URI and Principal recorded there.
         static void CacheFont(gfxFontEntry *aFontEntry);
 
         // The given gfxFontEntry is being destroyed, so remove any record that
@@ -413,21 +416,27 @@ protected:
                                         gfxProxyFontEntry *aProxy,
                                         const uint8_t* aData,
                                         uint32_t aLength,
                                         uint32_t& aSaneLength,
                                         bool aIsCompressed);
 
     static bool OTSMessage(void *aUserData, const char *format, ...);
 
+    // helper method for performing the actual userfont set rebuild
+    virtual void DoRebuildUserFontSet() = 0;
+
     // font families defined by @font-face rules
     nsRefPtrHashtable<nsStringHashKey, gfxMixedFontFamily> mFontFamilies;
 
     uint64_t        mGeneration;
 
+    // true when local names have been looked up, false otherwise
+    bool mLocalRulesUsed;
+
     static PRLogModuleInfo* GetUserFontsLog();
 
 private:
     static void CopyWOFFMetadata(const uint8_t* aFontData,
                                  uint32_t aLength,
                                  FallibleTArray<uint8_t>* aMetadata,
                                  uint32_t* aMetaOrigLen);
 };
--- a/gfx/thebes/gfxUtils.cpp
+++ b/gfx/thebes/gfxUtils.cpp
@@ -136,16 +136,76 @@ gfxUtils::UnpremultiplyImageSurface(gfxI
           *dstRow++ = UnpremultiplyValue(a, r);
           *dstRow++ = UnpremultiplyValue(a, g);
           *dstRow++ = UnpremultiplyValue(a, b);
 #endif
         }
     }
 }
 
+TemporaryRef<DataSourceSurface>
+gfxUtils::UnpremultiplyDataSurface(DataSourceSurface* aSurface)
+{
+    // Only premultiply ARGB32
+    if (aSurface->GetFormat() != SurfaceFormat::B8G8R8A8) {
+        return aSurface;
+    }
+
+    DataSourceSurface::MappedSurface map;
+    if (!aSurface->Map(DataSourceSurface::MapType::READ, &map)) {
+        return nullptr;
+    }
+
+    RefPtr<DataSourceSurface> dest = Factory::CreateDataSourceSurfaceWithStride(aSurface->GetSize(),
+                                                                                aSurface->GetFormat(),
+                                                                                map.mStride);
+
+    DataSourceSurface::MappedSurface destMap;
+    if (!dest->Map(DataSourceSurface::MapType::WRITE, &destMap)) {
+        aSurface->Unmap();
+        return nullptr;
+    }
+
+    uint8_t *src = map.mData;
+    uint8_t *dst = destMap.mData;
+
+    for (int32_t i = 0; i < aSurface->GetSize().height; ++i) {
+        uint8_t *srcRow = src + (i * map.mStride);
+        uint8_t *dstRow = dst + (i * destMap.mStride);
+
+        for (int32_t j = 0; j < aSurface->GetSize().width; ++j) {
+#ifdef IS_LITTLE_ENDIAN
+          uint8_t b = *srcRow++;
+          uint8_t g = *srcRow++;
+          uint8_t r = *srcRow++;
+          uint8_t a = *srcRow++;
+
+          *dstRow++ = UnpremultiplyValue(a, b);
+          *dstRow++ = UnpremultiplyValue(a, g);
+          *dstRow++ = UnpremultiplyValue(a, r);
+          *dstRow++ = a;
+#else
+          uint8_t a = *srcRow++;
+          uint8_t r = *srcRow++;
+          uint8_t g = *srcRow++;
+          uint8_t b = *srcRow++;
+
+          *dstRow++ = a;
+          *dstRow++ = UnpremultiplyValue(a, r);
+          *dstRow++ = UnpremultiplyValue(a, g);
+          *dstRow++ = UnpremultiplyValue(a, b);
+#endif
+        }
+    }
+
+    aSurface->Unmap();
+    dest->Unmap();
+    return dest;
+}
+
 void
 gfxUtils::ConvertBGRAtoRGBA(gfxImageSurface *aSourceSurface,
                             gfxImageSurface *aDestSurface) {
     if (!aDestSurface)
         aDestSurface = aSourceSurface;
 
     MOZ_ASSERT(aSourceSurface->Format() == aDestSurface->Format() &&
                aSourceSurface->Width()  == aDestSurface->Width() &&
@@ -181,16 +241,34 @@ gfxUtils::ConvertBGRAtoRGBA(gfxImageSurf
             dst[0] = src[2];
             dst[1] = src[1];
             dst[2] = src[0];
             dst[3] = src[3];
         }
     }
 }
 
+void
+gfxUtils::ConvertBGRAtoRGBA(uint8_t* aData, uint32_t aLength)
+{
+    uint8_t *src = aData;
+    uint8_t *srcEnd = src + aLength;
+
+    uint8_t buffer[4];
+    for (; src != srcEnd; src += 4) {
+        buffer[0] = src[2];
+        buffer[1] = src[1];
+        buffer[2] = src[0];
+
+        src[0] = buffer[0];
+        src[1] = buffer[1];
+        src[2] = buffer[2];
+    }
+}
+
 static bool
 IsSafeImageTransformComponent(gfxFloat aValue)
 {
   return aValue >= -32768 && aValue <= 32767;
 }
 
 #ifndef MOZ_GFX_OPTIMIZE_MOBILE
 /**
--- a/gfx/thebes/gfxUtils.h
+++ b/gfx/thebes/gfxUtils.h
@@ -39,19 +39,21 @@ public:
      *
      * If the source is not gfxImageFormat::ARGB32, no operation is performed.  If
      * aDestSurface is given, the data is copied over.
      */
     static void PremultiplyImageSurface(gfxImageSurface *aSourceSurface,
                                         gfxImageSurface *aDestSurface = nullptr);
     static void UnpremultiplyImageSurface(gfxImageSurface *aSurface,
                                           gfxImageSurface *aDestSurface = nullptr);
+    static mozilla::TemporaryRef<DataSourceSurface> UnpremultiplyDataSurface(DataSourceSurface* aSurface);
 
     static void ConvertBGRAtoRGBA(gfxImageSurface *aSourceSurface,
                                   gfxImageSurface *aDestSurface = nullptr);
+    static void ConvertBGRAtoRGBA(uint8_t* aData, uint32_t aLength);
 
     /**
      * Draw something drawable while working around limitations like bad support
      * for EXTEND_PAD, lack of source-clipping, or cairo / pixman bugs with
      * extreme user-space-to-image-space transforms.
      *
      * The input parameters here usually come from the output of our image
      * snapping algorithm in nsLayoutUtils.cpp.
--- a/js/src/builtin/TestingFunctions.cpp
+++ b/js/src/builtin/TestingFunctions.cpp
@@ -18,16 +18,17 @@
 
 #include "jit/AsmJS.h"
 #include "jit/AsmJSLink.h"
 #include "js/StructuredClone.h"
 #include "vm/ForkJoin.h"
 #include "vm/GlobalObject.h"
 #include "vm/Interpreter.h"
 #include "vm/ProxyObject.h"
+#include "vm/TraceLogging.h"
 
 #include "jscntxtinlines.h"
 #include "jsobjinlines.h"
 
 using namespace js;
 using namespace JS;
 
 using mozilla::ArrayLength;
@@ -739,19 +740,19 @@ static const struct TraceKindPair {
 static bool
 CountHeap(JSContext *cx, unsigned argc, jsval *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
     RootedValue startValue(cx, UndefinedValue());
     if (args.length() > 0) {
         jsval v = args[0];
-        if (JSVAL_IS_TRACEABLE(v)) {
+        if (v.isMarkable()) {
             startValue = v;
-        } else if (!JSVAL_IS_NULL(v)) {
+        } else if (!v.isNull()) {
             JS_ReportError(cx,
                            "the first argument is not null or a heap-allocated "
                            "thing");
             return false;
         }
     }
 
     RootedValue traceValue(cx);
@@ -766,21 +767,21 @@ CountHeap(JSContext *cx, unsigned argc, 
             return false;
         if (JS_FlatStringEqualsAscii(flatStr, "specific")) {
             if (args.length() < 3) {
                 JS_ReportError(cx, "tracing of specific value requested "
                                "but no value provided");
                 return false;
             }
             traceValue = args[2];
-            if (!JSVAL_IS_TRACEABLE(traceValue)){
+            if (!traceValue.isMarkable()){
                 JS_ReportError(cx, "cannot trace this kind of value");
                 return false;
             }
-            traceThing = JSVAL_TO_TRACEABLE(traceValue);
+            traceThing = traceValue.toGCThing();
         } else {
             for (size_t i = 0; ;) {
                 if (JS_FlatStringEqualsAscii(flatStr, traceKindNames[i].name)) {
                     traceKind = traceKindNames[i].kind;
                     break;
                 }
                 if (++i == ArrayLength(traceKindNames)) {
                     JSAutoByteString bytes(cx, str);
@@ -1483,16 +1484,36 @@ static bool
 TimesAccessed(JSContext *cx, unsigned argc, jsval *vp)
 {
     static int32_t accessed = 0;
     CallArgs args = CallArgsFromVp(argc, vp);
     args.rval().setInt32(++accessed);
     return true;
 }
 
+static bool
+EnableTraceLogger(JSContext *cx, unsigned argc, jsval *vp)
+{
+    CallArgs args = CallArgsFromVp(argc, vp);
+    TraceLogger *logger = TraceLoggerForMainThread(cx->runtime());
+    args.rval().setBoolean(TraceLoggerEnable(logger));
+
+    return true;
+}
+
+static bool
+DisableTraceLogger(JSContext *cx, unsigned argc, jsval *vp)
+{
+    CallArgs args = CallArgsFromVp(argc, vp);
+    TraceLogger *logger = TraceLoggerForMainThread(cx->runtime());
+    args.rval().setBoolean(TraceLoggerDisable(logger));
+
+    return true;
+}
+
 static const JSFunctionSpecWithHelp TestingFunctions[] = {
     JS_FN_HELP("gc", ::GC, 0, 0,
 "gc([obj] | 'compartment')",
 "  Run the garbage collector. When obj is given, GC only its compartment.\n"
 "  If 'compartment' is given, GC any compartments that were scheduled for\n"
 "  GC via schedulegc."),
 
     JS_FN_HELP("minorgc", ::MinorGC, 0, 0,
@@ -1718,16 +1739,25 @@ static const JSFunctionSpecWithHelp Test
     JS_FN_HELP("neuter", Neuter, 1, 0,
 "neuter(buffer)",
 "  Neuter the given ArrayBuffer object as if it had been transferred to a WebWorker."),
 
     JS_FN_HELP("workerThreadCount", WorkerThreadCount, 0, 0,
 "workerThreadCount()",
 "  Returns the number of worker threads available for off-main-thread tasks."),
 
+    JS_FN_HELP("startTraceLogger", EnableTraceLogger, 0, 0,
+"startTraceLogger()",
+"  Start logging the mainThread.\n"
+"  Note: tracelogging starts automatically. Disable it by setting environment variable\n"
+"  TLOPTIONS=disableMainThread"),
+
+    JS_FN_HELP("stopTraceLogger", DisableTraceLogger, 0, 0,
+"startTraceLogger()",
+"  Stop logging the mainThread."),
     JS_FS_HELP_END
 };
 
 static const JSPropertySpec TestingProperties[] = {
     JS_PSG("timesAccessed", TimesAccessed, 0),
     JS_PS_END
 };
 
--- a/js/src/ds/LifoAlloc.h
+++ b/js/src/ds/LifoAlloc.h
@@ -136,22 +136,16 @@ class BumpChunk
         if (MOZ_UNLIKELY(newBump < bump))
             return nullptr;
 
         JS_ASSERT(canAlloc(n)); // Ensure consistency between "can" and "try".
         setBump(newBump);
         return aligned;
     }
 
-    void *peek(size_t n) {
-        if (bump - bumpBase() < ptrdiff_t(n))
-            return nullptr;
-        return bump - n;
-    }
-
     static BumpChunk *new_(size_t chunkSize);
     static void delete_(BumpChunk *chunk);
 };
 
 } // namespace detail
 
 // LIFO bump allocator: used for phase-oriented and fast LIFO allocations.
 //
@@ -456,26 +450,16 @@ class LifoAlloc
         }
 
         // Return a Mark at the current position of the Enum.
         Mark mark() {
             alloc_->markCount++;
             return Mark(chunk_, position_);
         }
     };
-
-    // Return a modifiable pointer to the most recently allocated bytes. The
-    // type of the thing must be known, so is only applicable to some special-
-    // purpose allocators. Will return a nullptr if nothing has been allocated.
-    template <typename T>
-    T *peek() {
-        if (!latest)
-            return nullptr;
-        return static_cast<T *>(latest->peek(sizeof(T)));
-    }
 };
 
 class LifoAllocScope
 {
     LifoAlloc       *lifoAlloc;
     LifoAlloc::Mark mark;
     bool            shouldRelease;
     MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
--- a/js/src/gc/StoreBuffer.cpp
+++ b/js/src/gc/StoreBuffer.cpp
@@ -347,28 +347,28 @@ JS::HeapCellRelocate(js::gc::Cell **cell
     JS_ASSERT(*cellp);
     JSRuntime *runtime = (*cellp)->runtimeFromMainThread();
     runtime->gcStoreBuffer.removeRelocatableCell(cellp);
 }
 
 JS_PUBLIC_API(void)
 JS::HeapValuePostBarrier(JS::Value *valuep)
 {
-    JS_ASSERT(JSVAL_IS_TRACEABLE(*valuep));
+    JS_ASSERT(valuep->isMarkable());
     if (valuep->isString() && StringIsPermanentAtom(valuep->toString()))
         return;
     JSRuntime *runtime = static_cast<js::gc::Cell *>(valuep->toGCThing())->runtimeFromMainThread();
     runtime->gcStoreBuffer.putRelocatableValue(valuep);
 }
 
 JS_PUBLIC_API(void)
 JS::HeapValueRelocate(JS::Value *valuep)
 {
     /* Called with old contents of *valuep before overwriting. */
-    JS_ASSERT(JSVAL_IS_TRACEABLE(*valuep));
+    JS_ASSERT(valuep->isMarkable());
     if (valuep->isString() && StringIsPermanentAtom(valuep->toString()))
         return;
     JSRuntime *runtime = static_cast<js::gc::Cell *>(valuep->toGCThing())->runtimeFromMainThread();
     runtime->gcStoreBuffer.removeRelocatableValue(valuep);
 }
 
 template class StoreBuffer::MonoTypeBuffer<StoreBuffer::ValueEdge>;
 template class StoreBuffer::MonoTypeBuffer<StoreBuffer::CellPtrEdge>;
--- a/js/src/gc/StoreBuffer.h
+++ b/js/src/gc/StoreBuffer.h
@@ -129,20 +129,16 @@ class StoreBuffer
 
         /* Compacts if any entries have been added since the last compaction. */
         void maybeCompact(StoreBuffer *owner);
 
         /* Add one item to the buffer. */
         void put(StoreBuffer *owner, const T &t) {
             JS_ASSERT(storage_);
 
-            T *tip = storage_->peek<T>();
-            if (tip && tip->canMergeWith(t))
-                return tip->mergeInplace(t);
-
             T *tp = storage_->new_<T>(t);
             if (!tp)
                 CrashAtUnhandlableOOM("Failed to allocate for MonoTypeBuffer::put.");
 
             if (isAboutToOverflow())
                 handleOverflow(owner);
         }
 
@@ -246,19 +242,16 @@ class StoreBuffer
         explicit CellPtrEdge(Cell **v) : edge(v) {}
         bool operator==(const CellPtrEdge &other) const { return edge == other.edge; }
         bool operator!=(const CellPtrEdge &other) const { return edge != other.edge; }
 
         bool maybeInRememberedSet(const Nursery &nursery) const {
             return !nursery.isInside(edge) && nursery.isInside(*edge);
         }
 
-        bool canMergeWith(const CellPtrEdge &other) const { return edge == other.edge; }
-        void mergeInplace(const CellPtrEdge &) {}
-
         void mark(JSTracer *trc);
 
         CellPtrEdge tagged() const { return CellPtrEdge((Cell **)(uintptr_t(edge) | 1)); }
         CellPtrEdge untagged() const { return CellPtrEdge((Cell **)(uintptr_t(edge) & ~1)); }
         bool isTagged() const { return bool(uintptr_t(edge) & 1); }
 
         typedef PointerEdgeHasher<CellPtrEdge> Hasher;
     };
@@ -272,19 +265,16 @@ class StoreBuffer
         bool operator!=(const ValueEdge &other) const { return edge != other.edge; }
 
         void *deref() const { return edge->isGCThing() ? edge->toGCThing() : nullptr; }
 
         bool maybeInRememberedSet(const Nursery &nursery) const {
             return !nursery.isInside(edge) && nursery.isInside(deref());
         }
 
-        bool canMergeWith(const ValueEdge &other) const { return edge == other.edge; }
-        void mergeInplace(const ValueEdge &) {}
-
         void mark(JSTracer *trc);
 
         ValueEdge tagged() const { return ValueEdge((JS::Value *)(uintptr_t(edge) | 1)); }
         ValueEdge untagged() const { return ValueEdge((JS::Value *)(uintptr_t(edge) & ~1)); }
         bool isTagged() const { return bool(uintptr_t(edge) & 1); }
 
         typedef PointerEdgeHasher<ValueEdge> Hasher;
     };
@@ -316,26 +306,16 @@ class StoreBuffer
                    start_ == other.start_ &&
                    count_ == other.count_;
         }
 
         bool operator!=(const SlotsEdge &other) const {
             return !(*this == other);
         }
 
-        bool canMergeWith(const SlotsEdge &other) const {
-            return objectAndKind_ == other.objectAndKind_;
-        }
-
-        void mergeInplace(const SlotsEdge &other) {
-            int32_t end = Max(start_ + count_, other.start_ + other.count_);
-            start_ = Min(start_, other.start_);
-            count_ = end - start_;
-        }
-
         bool maybeInRememberedSet(const Nursery &nursery) const {
             return !nursery.isInside(object());
         }
 
         void mark(JSTracer *trc);
 
         typedef struct {
             typedef SlotsEdge Lookup;
@@ -355,19 +335,16 @@ class StoreBuffer
         bool operator==(const WholeCellEdges &other) const { return edge == other.edge; }
         bool operator!=(const WholeCellEdges &other) const { return edge != other.edge; }
 
         bool maybeInRememberedSet(const Nursery &nursery) const { return true; }
 
         static bool supportsDeduplication() { return true; }
         void *deduplicationKey() const { return (void *)edge; }
 
-        bool canMergeWith(const WholeCellEdges &other) const { return edge == other.edge; }
-        void mergeInplace(const WholeCellEdges &) {}
-
         void mark(JSTracer *trc);
 
         typedef PointerEdgeHasher<WholeCellEdges> Hasher;
     };
 
     template <typename Key>
     struct CallbackRef : public BufferableRef
     {
--- a/js/src/jit-test/tests/asm.js/testSource.js
+++ b/js/src/jit-test/tests/asm.js/testSource.js
@@ -232,16 +232,43 @@ if (isAsmJSCompilationAvailable() && isC
     var m = new Function('glob', 'ffi', 'heap', bodyOnly);
     assertEq(isAsmJSModuleLoadedFromCache(m), true);
     assertEq(m.toString(), "function anonymous(glob, ffi, heap) {\n" + bodyOnly + "\n}");
     assertEq(m.toSource(), "(function anonymous(glob, ffi, heap) {\n" + bodyOnly + "\n})");
 }
 
 })();
 
+/* Implicit "use strict" context */
+(function() {
+
+var funcHeader =  'function (glob, ffi, heap) {',
+    funcBody = '\n"use asm";\n\
+    function g() {}\n\
+    return g;\n\n'
+    funcFooter = '}',
+    funcSource = funcHeader + funcBody + funcFooter
+    useStrict = '\n"use strict";\n';
+
+var f4 = eval("\"use strict\";\n(" + funcSource + ")");
+
+var expectedToString = funcHeader + useStrict + funcBody + funcFooter
+var expectedToSource = '(' + expectedToString + ')'
+
+assertEq(f4.toString(), expectedToString);
+assertEq(f4.toSource(), expectedToSource);
+
+if (isAsmJSCompilationAvailable() && isCachingEnabled()) {
+    var f5 = eval("\"use strict\";\n(" + funcSource + ")");
+    assertEq(isAsmJSModuleLoadedFromCache(f5), true);
+    assertEq(f5.toString(), expectedToString);
+    assertEq(f5.toSource(), expectedToSource);
+}
+})();
+
 /* Functions */
 (function() {
 
 var noSrc = "function noArgument() {\n\
     return 42;\n\
 }"
 var oneSrc = "function oneArgument(x) {\n\
     x = x | 0;\n\
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/ion/bug995675.js
@@ -0,0 +1,5 @@
+function f(x) {
+        return Math.cos(~(~Math.pow(Number.MAX_VALUE, x)))
+}
+f(-0)
+assertEq(f(undefined - undefined), 1)
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/ion/bug995826.js
@@ -0,0 +1,5 @@
+function f(x) {
+        return Math.round(-Math.tan(x > 0))
+}
+f(2)
+assertEq(f(-1), -0);
--- a/js/src/jit/AsmJS.cpp
+++ b/js/src/jit/AsmJS.cpp
@@ -1138,17 +1138,23 @@ class MOZ_STACK_CLASS ModuleCompiler
             !addStandardLibraryMathName("SQRT1_2", M_SQRT1_2) ||
             !addStandardLibraryMathName("SQRT2", M_SQRT2))
         {
             return false;
         }
 
         uint32_t funcStart = parser_.pc->maybeFunction->pn_body->pn_pos.begin;
         uint32_t offsetToEndOfUseAsm = parser_.tokenStream.currentToken().pos.end;
-        module_ = cx_->new_<AsmJSModule>(parser_.ss, funcStart, offsetToEndOfUseAsm);
+
+        // "use strict" should be added to the source if we are in an implicit
+        // strict context, see also comment above addUseStrict in
+        // js::FunctionToString.
+        bool strict = parser_.pc->sc->strict && !parser_.pc->sc->hasExplicitUseStrict();
+
+        module_ = cx_->new_<AsmJSModule>(parser_.ss, funcStart, offsetToEndOfUseAsm, strict);
         if (!module_)
             return false;
 
         return true;
     }
 
     bool failOffset(uint32_t offset, const char *str) {
         JS_ASSERT(!errorString_);
@@ -1509,17 +1515,16 @@ class MOZ_STACK_CLASS ModuleCompiler
                                slowFuns ? slowFuns.get() : ""));
 #endif
     }
 
     bool finish(ScopedJSDeletePtr<AsmJSModule> *module)
     {
         module_->initFuncEnd(parser_.tokenStream.currentToken().pos.end,
                              parser_.tokenStream.peekTokenPos().end);
-
         masm_.finish();
         if (masm_.oom())
             return false;
 
 #if defined(JS_CODEGEN_ARM)
         // Now that compilation has finished, we need to update offsets to
         // reflect actual offsets (an ARM distinction).
         for (unsigned i = 0; i < module_->numHeapAccesses(); i++) {
--- a/js/src/jit/AsmJSLink.cpp
+++ b/js/src/jit/AsmJSLink.cpp
@@ -795,18 +795,41 @@ js::AsmJSModuleToString(JSContext *cx, H
         if (!out.append(") {\n"))
             return nullptr;
     }
 
     Rooted<JSFlatString*> src(cx, source->substring(cx, begin, end));
     if (!src)
         return nullptr;
 
-    if (!out.append(src->chars(), src->length()))
-        return nullptr;
+    if (module.strict()) {
+        // We need to add "use strict" in the body right after the opening
+        // brace.
+        size_t bodyStart = 0, bodyEnd;
+
+        // No need to test for functions created with the Function ctor as
+        // these doesn't implicitly inherit the "use strict" context. Strict mode is
+        // enabled for functions created with the Function ctor only if they begin with
+        // the "use strict" directive, but these functions won't validate as asm.js
+        // modules.
+
+        ConstTwoByteChars chars(src->chars(), src->length());
+        if (!FindBody(cx, fun, chars, src->length(), &bodyStart, &bodyEnd))
+            return nullptr;
+
+        if (!out.append(chars, bodyStart) ||
+            !out.append("\n\"use strict\";\n") ||
+            !out.append(chars + bodyStart, src->length() - bodyStart))
+        {
+            return nullptr;
+        }
+    } else {
+        if (!out.append(src->chars(), src->length()))
+            return nullptr;
+    }
 
     if (funCtor && !out.append("\n}"))
         return nullptr;
 
     if (addParenToLambda && fun->isLambda() && !out.append(")"))
         return nullptr;
 
     return out.finishString();
--- a/js/src/jit/AsmJSModule.cpp
+++ b/js/src/jit/AsmJSModule.cpp
@@ -323,32 +323,34 @@ AsmJSModule::staticallyLink(ExclusiveCon
     // Initialize global data segment
 
     for (size_t i = 0; i < exits_.length(); i++) {
         exitIndexToGlobalDatum(i).exit = interpExitTrampoline(exits_[i]);
         exitIndexToGlobalDatum(i).fun = nullptr;
     }
 }
 
-AsmJSModule::AsmJSModule(ScriptSource *scriptSource, uint32_t funcStart, uint32_t offsetToEndOfUseAsm)
+AsmJSModule::AsmJSModule(ScriptSource *scriptSource, uint32_t funcStart,
+                         uint32_t offsetToEndOfUseAsm, bool strict)
   : globalArgumentName_(nullptr),
     importArgumentName_(nullptr),
     bufferArgumentName_(nullptr),
     code_(nullptr),
     interruptExit_(nullptr),
     dynamicallyLinked_(false),
     loadedFromCache_(false),
     funcStart_(funcStart),
     offsetToEndOfUseAsm_(offsetToEndOfUseAsm),
     scriptSource_(scriptSource),
     codeIsProtected_(false)
 {
     mozilla::PodZero(&pod);
     scriptSource_->incref();
     pod.minHeapLength_ = AsmJSAllocationGranularity;
+    pod.strict_ = strict;
 }
 
 AsmJSModule::~AsmJSModule()
 {
     scriptSource_->decref();
 
     if (code_) {
         for (unsigned i = 0; i < numExits(); i++) {
@@ -871,17 +873,17 @@ class AutoUnprotectCodeForClone
     }
 };
 
 bool
 AsmJSModule::clone(JSContext *cx, ScopedJSDeletePtr<AsmJSModule> *moduleOut) const
 {
     AutoUnprotectCodeForClone cloneGuard(cx, *this);
 
-    *moduleOut = cx->new_<AsmJSModule>(scriptSource_, funcStart_, offsetToEndOfUseAsm_);
+    *moduleOut = cx->new_<AsmJSModule>(scriptSource_, funcStart_, offsetToEndOfUseAsm_, pod.strict_);
     if (!*moduleOut)
         return false;
 
     AsmJSModule &out = **moduleOut;
 
     // Mirror the order of serialize/deserialize in cloning:
 
     out.pod = pod;
@@ -1308,18 +1310,19 @@ js::LookupAsmJSModuleInCache(ExclusiveCo
 
     ModuleCharsForLookup moduleChars;
     cursor = moduleChars.deserialize(cx, cursor);
     if (!moduleChars.match(parser))
         return true;
 
     uint32_t funcStart = parser.pc->maybeFunction->pn_body->pn_pos.begin;
     uint32_t offsetToEndOfUseAsm = parser.tokenStream.currentToken().pos.end;
+    bool strict = parser.pc->sc->strict && !parser.pc->sc->hasExplicitUseStrict();
     ScopedJSDeletePtr<AsmJSModule> module(
-        cx->new_<AsmJSModule>(parser.ss, funcStart, offsetToEndOfUseAsm));
+        cx->new_<AsmJSModule>(parser.ss, funcStart, offsetToEndOfUseAsm, strict));
     if (!module)
         return false;
     cursor = module->deserialize(cx, cursor);
     if (!cursor)
         return false;
 
     bool atEnd = cursor == entry.memory + entry.serializedSize;
     MOZ_ASSERT(atEnd, "Corrupt cache file");
--- a/js/src/jit/AsmJSModule.h
+++ b/js/src/jit/AsmJSModule.h
@@ -426,16 +426,17 @@ class AsmJSModule
 #endif
 #if defined(JS_ION_PERF)
     ProfiledBlocksFunctionVector          perfProfiledBlocksFunctions_;
 #endif
 
     struct Pod {
         uint32_t                          funcLength_;
         uint32_t                          funcLengthWithRightBrace_;
+        bool                              strict_;
         uint32_t                          numGlobalVars_;
         uint32_t                          numFFIs_;
         size_t                            funcPtrTableAndExitBytes_;
         bool                              hasArrayView_;
         size_t                            functionBytes_; // just the function bodies, no stubs
         size_t                            codeBytes_;     // function bodies and stubs
         size_t                            totalBytes_;    // function bodies, stubs, and global data
         uint32_t                          minHeapLength_;
@@ -459,17 +460,18 @@ class AsmJSModule
 
     FunctionCountsVector                  functionCounts_;
 
     // This field is accessed concurrently when requesting an interrupt.
     // Access must be synchronized via the runtime's interrupt lock.
     mutable bool                          codeIsProtected_;
 
   public:
-    explicit AsmJSModule(ScriptSource *scriptSource, uint32_t functStart, uint32_t offsetToEndOfUseAsm);
+    explicit AsmJSModule(ScriptSource *scriptSource, uint32_t functStart,
+                         uint32_t offsetToEndOfUseAsm, bool strict);
     ~AsmJSModule();
 
     void trace(JSTracer *trc) {
         for (unsigned i = 0; i < globals_.length(); i++)
             globals_[i].trace(trc);
         for (unsigned i = 0; i < exports_.length(); i++)
             exports_[i].trace(trc);
         for (unsigned i = 0; i < exits_.length(); i++) {
@@ -519,16 +521,19 @@ class AsmJSModule
         pod.funcLengthWithRightBrace_ = endAfterCurly - funcStart_;
     }
     uint32_t funcEndBeforeCurly() const {
         return funcStart_ + pod.funcLength_;
     }
     uint32_t funcEndAfterCurly() const {
         return funcStart_ + pod.funcLengthWithRightBrace_;
     }
+    bool strict() const {
+        return pod.strict_;
+    }
 
     bool addGlobalVarInit(const Value &v, AsmJSCoercion coercion, uint32_t *globalIndex) {
         JS_ASSERT(pod.funcPtrTableAndExitBytes_ == 0);
         if (pod.numGlobalVars_ == UINT32_MAX)
             return false;
         Global g(Global::Variable, nullptr);
         g.pod.u.var.initKind_ = Global::InitConstant;
         g.pod.u.var.init.constant_ = v;
--- a/js/src/jit/MCallOptimize.cpp
+++ b/js/src/jit/MCallOptimize.cpp
@@ -581,23 +581,16 @@ IonBuilder::inlineMathAbs(CallInfo &call
     callInfo.setImplicitlyUsedUnchecked();
 
     // If the arg is a Float32, we specialize the op as double, it will be specialized
     // as float32 if necessary later.
     MIRType absType = (argType == MIRType_Float32) ? MIRType_Double : argType;
     MInstruction *ins = MAbs::New(alloc(), callInfo.getArg(0), absType);
     current->add(ins);
 
-    if (IsFloatingPointType(argType) && returnType == MIRType_Int32) {
-        MToInt32 *toInt = MToInt32::New(alloc(), ins);
-        toInt->setCanBeNegativeZero(false);
-        current->add(toInt);
-        ins = toInt;
-    }
-
     current->push(ins);
     return InliningStatus_Inlined;
 }
 
 IonBuilder::InliningStatus
 IonBuilder::inlineMathFloor(CallInfo &callInfo)
 {
     if (callInfo.constructing())
--- a/js/src/jit/MIR.cpp
+++ b/js/src/jit/MIR.cpp
@@ -2323,22 +2323,16 @@ MToDouble::foldsTo(TempAllocator &alloc,
     if (in->isConstant()) {
         const Value &v = in->toConstant()->value();
         if (v.isNumber()) {
             double out = v.toNumber();
             return MConstant::New(alloc, DoubleValue(out));
         }
     }
 
-    // Fold unnecessary numeric conversions.
-    if (input()->isToInt32()) {
-        replaceOperand(0, input()->getOperand(0));
-        conversion_ = NonStringPrimitives;
-    }
-
     return this;
 }
 
 MDefinition *
 MToFloat32::foldsTo(TempAllocator &alloc, bool useValueNumbers)
 {
     if (input()->type() == MIRType_Float32)
         return input();
--- a/js/src/jit/TypePolicy.cpp
+++ b/js/src/jit/TypePolicy.cpp
@@ -290,16 +290,17 @@ TypeBarrierPolicy::adjustInputs(TempAllo
     }
 
     // Input is a value. Unbox the input to the requested type.
     if (inputType == MIRType_Value) {
         JS_ASSERT(outputType != MIRType_Value);
 
         // We can't unbox a value to null/undefined. So keep output also a value.
         if (IsNullOrUndefined(outputType) || outputType == MIRType_Magic) {
+            JS_ASSERT(ins->defUseCount() == 0);
             ins->setResultType(MIRType_Value);
             return true;
         }
 
         MUnbox *unbox = MUnbox::New(alloc, ins->getOperand(0), outputType, MUnbox::TypeBarrier);
         ins->block()->insertBefore(ins, unbox);
         ins->replaceOperand(0, unbox);
         return true;
--- a/js/src/jit/shared/CodeGenerator-shared.cpp
+++ b/js/src/jit/shared/CodeGenerator-shared.cpp
@@ -9,16 +9,17 @@
 #include "mozilla/DebugOnly.h"
 
 #include "jit/IonCaches.h"
 #include "jit/IonMacroAssembler.h"
 #include "jit/IonSpewer.h"
 #include "jit/MIR.h"
 #include "jit/MIRGenerator.h"
 #include "jit/ParallelFunctions.h"
+#include "vm/TraceLogging.h"
 
 #include "jit/IonFrames-inl.h"
 
 using namespace js;
 using namespace js::jit;
 
 using mozilla::DebugOnly;
 
@@ -623,16 +624,21 @@ CodeGeneratorShared::callVM(const VMFunc
 #ifdef DEBUG
     if (ins->mirRaw()) {
         JS_ASSERT(ins->mirRaw()->isInstruction());
         MInstruction *mir = ins->mirRaw()->toInstruction();
         JS_ASSERT_IF(mir->isEffectful(), mir->resumePoint());
     }
 #endif
 
+#ifdef JS_TRACE_LOGGING
+    if (!emitTracelogStartEvent(TraceLogger::VM))
+        return false;
+#endif
+
     // Stack is:
     //    ... frame ...
     //    [args]
 #ifdef DEBUG
     JS_ASSERT(pushedArgs_ == fun.explicitArgs);
     pushedArgs_ = 0;
 #endif
 
@@ -662,16 +668,22 @@ CodeGeneratorShared::callVM(const VMFunc
     // Remove rest of the frame left on the stack. We remove the return address
     // which is implicitly poped when returning.
     int framePop = sizeof(IonExitFrameLayout) - sizeof(void*);
 
     // Pop arguments from framePushed.
     masm.implicitPop(fun.explicitStackSlots() * sizeof(void *) + framePop);
     // Stack is:
     //    ... frame ...
+
+#ifdef JS_TRACE_LOGGING
+    if (!emitTracelogStopEvent(TraceLogger::VM))
+        return false;
+#endif
+
     return true;
 }
 
 class OutOfLineTruncateSlow : public OutOfLineCodeBase<CodeGeneratorShared>
 {
     FloatRegister src_;
     Register dest_;
     bool needFloat32Conversion_;
@@ -1023,47 +1035,37 @@ CodeGeneratorShared::emitTracelogScript(
     masm.Pop(script);
     masm.Pop(logger);
     return true;
 }
 
 bool
 CodeGeneratorShared::emitTracelogTree(bool isStart, uint32_t textId)
 {
+    if (!TraceLogTextIdEnabled(textId))
+        return true;
+
     RegisterSet regs = RegisterSet::Volatile();
     Register logger = regs.takeGeneral();
 
     masm.Push(logger);
 
     CodeOffsetLabel patchLocation = masm.movWithPatch(ImmPtr(nullptr), logger);
     if (!patchableTraceLoggers_.append(patchLocation))
         return false;
 
-    if (isStart)
+    if (isStart) {
         masm.tracelogStart(logger, textId);
-    else
+    } else {
+#ifdef DEBUG
         masm.tracelogStop(logger, textId);
-
-    masm.Pop(logger);
-    return true;
-}
-
-bool
-CodeGeneratorShared::emitTracelogStopEvent()
-{
-    RegisterSet regs = RegisterSet::Volatile();
-    Register logger = regs.takeGeneral();
-
-    masm.Push(logger);
-
-    CodeOffsetLabel patchLocation = masm.movWithPatch(ImmPtr(nullptr), logger);
-    if (!patchableTraceLoggers_.append(patchLocation))
-        return false;
-
-    masm.tracelogStop(logger);
+#else
+        masm.tracelogStop(logger);
+#endif
+    }
 
     masm.Pop(logger);
     return true;
 }
 #endif
 
 } // namespace jit
 } // namespace js
--- a/js/src/jit/shared/CodeGenerator-shared.h
+++ b/js/src/jit/shared/CodeGenerator-shared.h
@@ -462,23 +462,18 @@ class CodeGeneratorShared : public LInst
     }
     bool emitTracelogScriptStop() {
         return emitTracelogScript(/* isStart =*/ false);
     }
     bool emitTracelogStartEvent(uint32_t textId) {
         return emitTracelogTree(/* isStart =*/ true, textId);
     }
     bool emitTracelogStopEvent(uint32_t textId) {
-#ifdef DEBUG
         return emitTracelogTree(/* isStart =*/ false, textId);
-#else
-        return emitTracelogScript(/* isStart =*/ false);
-#endif
     }
-    bool emitTracelogStopEvent();
 #endif
 };
 
 // An out-of-line path is generated at the end of the function.
 class OutOfLineCode : public TempObject
 {
     Label entry_;
     Label rejoin_;
--- a/js/src/jit/shared/IonAssemblerBufferWithConstantPools.h
+++ b/js/src/jit/shared/IonAssemblerBufferWithConstantPools.h
@@ -755,16 +755,20 @@ struct AssemblerBufferWithConstantPool :
                     // block, chances are you will have a bad time.
                     // ADDENDUM: this CANNOT happen on ARM, because the only elements that
                     // fall into this case are doubles loaded via vfp, but they will also be
                     // the last pool, which means it cannot affect the alignment of any other
                     // Sub Pools.
                     IonSpew(IonSpew_Pools, "[%d]***Offset was still out of range!***", id, codeOffset - magicAlign);
                     IonSpew(IonSpew_Pools, "[%d] Too complicated; bailingp", id);
                     this->fail_bail();
+                    // only free up to the current offset
+                    for (int pi = poolIdx; pi < numPoolKinds; pi++)
+                        delete[] outcastEntries[pi];
+                    delete[] preservedEntries;
                     return;
                 } else {
                     preservedEntries[idx] = true;
                 }
             }
             // remove the elements of the pool that should not be there (YAY, MEMCPY)
             unsigned int idxDest = 0;
             // If no elements were skipped, no expensive copy is necessary.
@@ -778,37 +782,42 @@ struct AssemblerBufferWithConstantPool :
                         }
                         idxDest++;
                     }
                 }
                 p->numEntries -= numSkips;
             }
             poolOffset += p->numEntries * p->immSize;
             delete[] preservedEntries;
+            preservedEntries = nullptr;
         }
         // bind the current pool to the perforation point.
         Pool **tmp = &perforatedNode->data;
         *tmp = static_cast<Pool*>(this->LifoAlloc_.alloc(sizeof(Pool) * numPoolKinds));
         if (tmp == nullptr) {
             this->fail_oom();
+            for (int pi = 0; pi < numPoolKinds; pi++)
+                delete[] outcastEntries[pi];
             return;
         }
         // The above operations may have changed the size of pools!
         // recalibrate the size of the pool.
         newPoolInfo = getPoolData();
         poolInfo[numDumps] = newPoolInfo;
         poolSize += poolInfo[numDumps].size;
         numDumps++;
 
         memcpy(*tmp, pools, sizeof(Pool) * numPoolKinds);
 
         // reset everything to the state that it was in when we started
         for (int poolIdx = 0; poolIdx < numPoolKinds; poolIdx++) {
             if (!pools[poolIdx].reset(this->LifoAlloc_)) {
                 this->fail_oom();
+                for (int pi = 0; pi < numPoolKinds; pi++)
+                    delete[] outcastEntries[pi];
                 return;
             }
         }
         new (&perforation) BufferOffset();
         perforatedNode = nullptr;
         inBackref = false;
 
         // Now that the backwards pool has been emptied, and a new forward pool
--- a/js/src/jit/x86/MacroAssembler-x86.cpp
+++ b/js/src/jit/x86/MacroAssembler-x86.cpp
@@ -391,26 +391,37 @@ MacroAssemblerX86::testNegativeZero(cons
 {
     // Determines whether the single double contained in the XMM register reg
     // is equal to double-precision -0.
 
     Label nonZero;
 
     // Compare to zero. Lets through {0, -0}.
     xorpd(ScratchFloatReg, ScratchFloatReg);
-    // If reg is non-zero, then a test of Zero is false.
+
+    // If reg is non-zero, jump to nonZero.
+    // Sets ZF=0 and PF=0.
     branchDouble(DoubleNotEqual, reg, ScratchFloatReg, &nonZero);
 
-    // Input register is either zero or negative zero. Test sign bit.
+    // Input register is either zero or negative zero. Retrieve sign of input.
     movmskpd(reg, scratch);
-    // If reg is -0, then a test of Zero is true.
-    cmpl(scratch, Imm32(1));
+
+    // If reg is 1 or 3, input is negative zero.
+    // If reg is 0 or 2, input is a normal zero.
+    // So the following test will set PF=1 for negative zero.
+    orl(Imm32(2), scratch);
 
     bind(&nonZero);
-    return Zero;
+
+    // Here we need to be able to test if the input is a negative zero.
+    // - branchDouble joins here for non-zero values in which case it sets
+    //   ZF=0 and PF=0. In that case the test should fail.
+    // - orl sets PF=1 on negative zero and PF=0 otherwise
+    // => So testing PF=1 will return if input is negative zero or not.
+    return Parity;
 }
 
 Assembler::Condition
 MacroAssemblerX86::testNegativeZeroFloat32(const FloatRegister &reg, const Register &scratch)
 {
     movd(reg, scratch);
     cmpl(scratch, Imm32(1));
     return Overflow;
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -1975,48 +1975,16 @@ RemoveScriptRootRT(JSRuntime *rt, JS::He
  */
 extern JS_PUBLIC_API(bool)
 JS_AddExtraGCRootsTracer(JSRuntime *rt, JSTraceDataOp traceOp, void *data);
 
 /* Undo a call to JS_AddExtraGCRootsTracer. */
 extern JS_PUBLIC_API(void)
 JS_RemoveExtraGCRootsTracer(JSRuntime *rt, JSTraceDataOp traceOp, void *data);
 
-/*
- * JS_CallTracer API and related macros for implementors of JSTraceOp, to
- * enumerate all references to traceable things reachable via a property or
- * other strong ref identified for debugging purposes by name or index or
- * a naming callback.
- *
- * See the JSTraceOp typedef.
- */
-
-/*
- * Use the following macros to check if a particular jsval is a traceable
- * thing and to extract the thing and its kind to pass to JS_CallTracer.
- */
-static MOZ_ALWAYS_INLINE bool
-JSVAL_IS_TRACEABLE(jsval v)
-{
-    return JSVAL_IS_TRACEABLE_IMPL(JSVAL_TO_IMPL(v));
-}
-
-static MOZ_ALWAYS_INLINE void *
-JSVAL_TO_TRACEABLE(jsval v)
-{
-    return JSVAL_TO_GCTHING(v);
-}
-
-static MOZ_ALWAYS_INLINE JSGCTraceKind
-JSVAL_TRACE_KIND(jsval v)
-{
-    JS_ASSERT(JSVAL_IS_GCTHING(v));
-    return (JSGCTraceKind) JSVAL_TRACE_KIND_IMPL(JSVAL_TO_IMPL(v));
-}
-
 #ifdef JS_DEBUG
 
 /*
  * Debug-only method to dump the object graph of heap-allocated things.
  *
  * fp:              file for the dump output.
  * start:           when non-null, dump only things reachable from start
  *                  thing. Otherwise dump all things reachable from the
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -621,24 +621,28 @@ const Class JSFunction::class_ = {
     fun_hasInstance,
     nullptr,                 /* construct   */
     fun_trace
 };
 
 const Class* const js::FunctionClassPtr = &JSFunction::class_;
 
 /* Find the body of a function (not including braces). */
-static bool
-FindBody(JSContext *cx, HandleFunction fun, ConstTwoByteChars chars, size_t length,
+bool
+js::FindBody(JSContext *cx, HandleFunction fun, ConstTwoByteChars chars, size_t length,
          size_t *bodyStart, size_t *bodyEnd)
 {
     // We don't need principals, since those are only used for error reporting.
     CompileOptions options(cx);
-    options.setFileAndLine("internal-findBody", 0)
-           .setVersion(fun->nonLazyScript()->getVersion());
+    options.setFileAndLine("internal-findBody", 0);
+
+    // For asm.js modules, there's no script.
+    if (fun->hasScript())
+        options.setVersion(fun->nonLazyScript()->getVersion());
+
     AutoKeepAtoms keepAtoms(cx->perThreadData);
     TokenStream ts(cx, options, chars.get(), length, nullptr);
     int nest = 0;
     bool onward = true;
     // Skip arguments list.
     do {
         switch (ts.getToken()) {
           case TOK_NAME:
--- a/js/src/jsfun.h
+++ b/js/src/jsfun.h
@@ -549,16 +549,21 @@ class FunctionExtended : public JSFuncti
     HeapValue extendedSlots[NUM_EXTENDED_SLOTS];
 };
 
 extern JSFunction *
 CloneFunctionObject(JSContext *cx, HandleFunction fun, HandleObject parent,
                     gc::AllocKind kind = JSFunction::FinalizeKind,
                     NewObjectKind newKindArg = GenericObject);
 
+
+extern bool
+FindBody(JSContext *cx, HandleFunction fun, ConstTwoByteChars chars, size_t length,
+         size_t *bodyStart, size_t *bodyEnd);
+
 } // namespace js
 
 inline js::FunctionExtended *
 JSFunction::toExtended()
 {
     JS_ASSERT(isExtended());
     return static_cast<js::FunctionExtended *>(this);
 }
--- a/js/src/jspubtd.h
+++ b/js/src/jspubtd.h
@@ -92,17 +92,17 @@ enum JSIterateOp {
 
     /* Iterate once. */
     JSENUMERATE_NEXT,
 
     /* Destroy iterator state. */
     JSENUMERATE_DESTROY
 };
 
-/* See JSVAL_TRACE_KIND and JSTraceCallback in jsapi.h. */
+/* See Value::gcKind() and JSTraceCallback in Tracer.h. */
 enum JSGCTraceKind {
     JSTRACE_OBJECT,
     JSTRACE_STRING,
     JSTRACE_SCRIPT,
 
     /*
      * Trace kinds internal to the engine. The embedding can only see them if
      * it implements JSTraceCallback.
--- a/js/src/vm/Opcodes.h
+++ b/js/src/vm/Opcodes.h
@@ -86,26 +86,53 @@ 1234567890123456789012345678901234567890
      * No operation is performed.
      *   Category: Other
      *   Operands:
      *   Stack: =>
      */ \
     macro(JSOP_NOP,       0,  "nop",        NULL,         1,  0,  0, JOF_BYTE) \
     \
     /* Long-standing JavaScript bytecodes. */ \
+    /*
+     * Pushes 'undefined' onto the stack.
+     *   Category: Literals
+     *   Type: Constants
+     *   Operands:
+     *   Stack: => undefined
+     */ \
     macro(JSOP_UNDEFINED, 1,  js_undefined_str, "",       1,  0,  1, JOF_BYTE) \
     macro(JSOP_UNUSED2,   2,  "unused2",    NULL,         1,  1,  0, JOF_BYTE) \
     macro(JSOP_ENTERWITH, 3,  "enterwith",  NULL,         5,  1,  0, JOF_OBJECT) \
     macro(JSOP_LEAVEWITH, 4,  "leavewith",  NULL,         1,  0,  0, JOF_BYTE) \
+    /*
+     * Pops the top of stack value as 'rval', stops interpretation of current
+     * script and returns 'rval'.
+     *   Category: Statements
+     *   Type: Function
+     *   Operands:
+     *   Stack: rval =>
+     */ \
     macro(JSOP_RETURN,    5,  "return",     NULL,         1,  1,  0, JOF_BYTE) \
     macro(JSOP_GOTO,      6,  "goto",       NULL,         5,  0,  0, JOF_JUMP) \
     macro(JSOP_IFEQ,      7,  "ifeq",       NULL,         5,  1,  0, JOF_JUMP|JOF_DETECTING) \
     macro(JSOP_IFNE,      8,  "ifne",       NULL,         5,  1,  0, JOF_JUMP) \
     \
-    /* Get the arguments object for the current, lightweight function activation. */ \
+    /*
+     * Pushes the 'arguments' object for the current function activation.
+     *
+     * If 'JSScript' is not marked 'needsArgsObj', then a
+     * JS_OPTIMIZED_ARGUMENTS magic value is pushed. Otherwise, a proper
+     * arguments object is constructed and pushed.
+     *
+     * This opcode requires that the function does not have rest parameter.
+     *   Category: Variables and Scopes
+     *   Type: Arguments
+     *   Operands:
+     *   Stack: => arguments
+     */ \
     macro(JSOP_ARGUMENTS, 9,  "arguments",  NULL,         1,  0,  1, JOF_BYTE) \
     \
     /*
      * Swaps the top two values on the stack. This is useful for things like
      * post-increment/decrement.
      *   Category: Operator
      *   Type: Stack Operations
      *   Operands:
@@ -134,16 +161,24 @@ 1234567890123456789012345678901234567890
     /*
      * Duplicates the top two values on the stack.
      *   Category: Operator
      *   Type: Stack Operations
      *   Operands:
      *   Stack: v1, v2 => v1, v2, v1, v2
      */ \
     macro(JSOP_DUP2,      13, "dup2",       NULL,         1,  2,  4, JOF_BYTE) \
+    /*
+     * Defines a readonly property on the frame's current variables-object (the
+     * scope object on the scope chain designated to receive new variables).
+     *   Category: Variables and Scopes
+     *   Type: Variables
+     *   Operands: uint32_t nameIndex
+     *   Stack: val => val
+     */ \
     macro(JSOP_SETCONST,  14, "setconst",   NULL,         5,  1,  1, JOF_ATOM|JOF_NAME|JOF_SET) \
     /*
      * Pops the top two values 'lval' and 'rval' from the stack, then pushes
      * the result of the operation applied to the two operands, converting
      * both to 32-bit signed integers if necessary.
      *   Category: Operator
      *   Type: Bitwise Logical Operators
      *   Operands:
@@ -234,18 +269,46 @@ 1234567890123456789012345678901234567890
      * Pops the value 'val' from the stack, then pushes '+val'.
      * ('+val' is the value converted to a number.)
      *   Category: Operator
      *   Type: Arithmetic Operators
      *   Operands:
      *   Stack: val => (+val)
      */ \
     macro(JSOP_POS,       35, "pos",        "+ ",         1,  1,  1, JOF_BYTE|JOF_ARITH) \
+    /*
+     * Looks up name on the scope chain and deletes it, pushes 'true' onto the
+     * stack if succeeded (if the property was present and deleted or if the
+     * property wasn't present in the first place), 'false' if not.
+     *
+     * Strict mode code should never contain this opcode.
+     *   Category: Variables and Scopes
+     *   Type: Variables
+     *   Operands: uint32_t nameIndex
+     *   Stack: => succeeded
+     */ \
     macro(JSOP_DELNAME,   36, "delname",    NULL,         5,  0,  1, JOF_ATOM|JOF_NAME) \
+    /*
+     * Pops the top of stack value, deletes property from it, pushes 'true' onto
+     * the stack if succeeded, 'false' if not.
+     *   Category: Literals
+     *   Type: Object
+     *   Operands: uint32_t nameIndex
+     *   Stack: obj => succeeded
+     */ \
     macro(JSOP_DELPROP,   37, "delprop",    NULL,         5,  1,  1, JOF_ATOM|JOF_PROP) \
+    /*
+     * Pops the top two values on the stack as 'propval' and 'obj',
+     * deletes 'propval' property from 'obj', pushes 'true'  onto the stack if
+     * succeeded, 'false' if not.
+     *   Category: Literals
+     *   Type: Object
+     *   Operands:
+     *   Stack: obj, propval => succeeded
+     */ \
     macro(JSOP_DELELEM,   38, "delelem",    NULL,         1,  2,  1, JOF_BYTE |JOF_ELEM) \
     /*
      * Pops the value 'val' from the stack, then pushes 'typeof val'.
      *   Category: Operator
      *   Type: Special Operators
      *   Operands:
      *   Stack: val => (typeof val)
      */ \
@@ -254,21 +317,52 @@ 1234567890123456789012345678901234567890
      * Pops the top value on the stack and pushes 'undefined'.
      *   Category: Operator
      *   Type: Special Operators
      *   Operands:
      *   Stack: val => undefined
      */ \
     macro(JSOP_VOID,      40, js_void_str,  NULL,         1,  1,  1, JOF_BYTE) \
     \
-    /* spreadcall variant of JSOP_CALL */ \
+    /*
+     * spreadcall variant of JSOP_CALL.
+     *
+     * Invokes 'callee' with 'this' and 'args', pushes the return value onto
+     * the stack.
+     *
+     * 'args' is an Array object which contains actual arguments.
+     *   Category: Statements
+     *   Type: Function
+     *   Operands:
+     *   Stack: callee, this, args => rval
+     */ \
     macro(JSOP_SPREADCALL,41, "spreadcall", NULL,         1,  3,  1, JOF_BYTE|JOF_INVOKE|JOF_TYPESET) \
-    /* spreadcall variant of JSOP_NEW */ \
+    /*
+     * spreadcall variant of JSOP_NEW
+     *
+     * Invokes 'callee' as a constructor with 'this' and 'args', pushes the
+     * return value onto the stack.
+     *   Category: Statements
+     *   Type: Function
+     *   Operands:
+     *   Stack: callee, this, args => rval
+     */ \
     macro(JSOP_SPREADNEW, 42, "spreadnew",  NULL,         1,  3,  1, JOF_BYTE|JOF_INVOKE|JOF_TYPESET) \
-    /* spreadcall variant of JSOP_EVAL */ \
+    /*
+     * spreadcall variant of JSOP_EVAL
+     *
+     * Invokes 'eval' with 'args' and pushes the return value onto the stack.
+     *
+     * If 'eval' in global scope is not original one, invokes the function
+     * with 'this' and 'args', and pushes return value onto the stack.
+     *   Category: Statements
+     *   Type: Function
+     *   Operands:
+     *   Stack: callee, this, args => rval
+     */ \
     macro(JSOP_SPREADEVAL,43, "spreadeval", NULL,         1,  3,  1, JOF_BYTE|JOF_INVOKE|JOF_TYPESET) \
     \
     /*
      * Duplicates the Nth value from the top onto the stack.
      *   Category: Operator
      *   Type: Stack Operations
      *   Operands: uint24_t n
      *   Stack: v[n], v[n-1], ..., v[1], v[0] =>
@@ -280,40 +374,141 @@ 1234567890123456789012345678901234567890
     macro(JSOP_UNUSED46,  46, "unused46",   NULL,         1,  0,  0,  JOF_BYTE) \
     macro(JSOP_UNUSED47,  47, "unused47",   NULL,         1,  0,  0,  JOF_BYTE) \
     macro(JSOP_UNUSED48,  48, "unused48",   NULL,         1,  0,  0,  JOF_BYTE) \
     macro(JSOP_UNUSED49,  49, "unused49",   NULL,         1,  0,  0,  JOF_BYTE) \
     macro(JSOP_UNUSED50,  50, "unused50",   NULL,         1,  0,  0,  JOF_BYTE) \
     macro(JSOP_UNUSED51,  51, "unused51",   NULL,         1,  0,  0,  JOF_BYTE) \
     macro(JSOP_UNUSED52,  52, "unused52",   NULL,         1,  0,  0,  JOF_BYTE) \
     \
+    /*
+     * Pops the top of stack value, pushes property of it onto the stack.
+     *   Category: Literals
+     *   Type: Object
+     *   Operands: uint32_t nameIndex
+     *   Stack: obj => obj[name]
+     */ \
     macro(JSOP_GETPROP,   53, "getprop",    NULL,         5,  1,  1, JOF_ATOM|JOF_PROP|JOF_TYPESET|JOF_TMPSLOT3) \
+    /*
+     * Pops the top two values on the stack as 'val' and 'obj', sets property of
+     * 'obj' as 'val', pushes 'obj' onto the stack.
+     *   Category: Literals
+     *   Type: Object
+     *   Operands: uint32_t nameIndex
+     *   Stack: obj, val => val
+     */ \
     macro(JSOP_SETPROP,   54, "setprop",    NULL,         5,  2,  1, JOF_ATOM|JOF_PROP|JOF_SET|JOF_DETECTING) \
+    /*
+     * Pops the top two values on the stack as 'propval' and 'obj', pushes
+     * 'propval' property of 'obj' onto the stack.
+     *   Category: Literals
+     *   Type: Object
+     *   Operands:
+     *   Stack: obj, propval => obj[propval]
+     */ \
     macro(JSOP_GETELEM,   55, "getelem",    NULL,         1,  2,  1, JOF_BYTE |JOF_ELEM|JOF_TYPESET|JOF_LEFTASSOC) \
+    /*
+     * Pops the top three values on the stack as 'val', 'propval' and 'obj',
+     * sets 'propval' property of 'obj' as 'val', pushes 'obj' onto the
+     * stack.
+     *   Category: Literals
+     *   Type: Object
+     *   Operands:
+     *   Stack: obj, propval, val => val
+     */ \
     macro(JSOP_SETELEM,   56, "setelem",    NULL,         1,  3,  1, JOF_BYTE |JOF_ELEM|JOF_SET|JOF_DETECTING) \
     macro(JSOP_UNUSED57,  57, "unused57",   NULL,         1,  0,  0, JOF_BYTE) \
+    /*
+     * Invokes 'callee' with 'this' and 'args', pushes return value onto the
+     * stack.
+     *   Category: Statements
+     *   Type: Function
+     *   Operands: uint16_t argc
+     *   Stack: callee, this, args[0], ..., args[argc-1] => rval
+     *   nuses: (argc+2)
+     */ \
     macro(JSOP_CALL,      58, "call",       NULL,         3, -1,  1, JOF_UINT16|JOF_INVOKE|JOF_TYPESET) \
+    /*
+     * Looks up name on the scope chain and pushes its value onto the stack.
+     *   Category: Variables and Scopes
+     *   Type: Variables
+     *   Operands: uint32_t nameIndex
+     *   Stack: => val
+     */ \
     macro(JSOP_NAME,      59, "name",       NULL,         5,  0,  1, JOF_ATOM|JOF_NAME|JOF_TYPESET) \
+    /*
+     * Pushes numeric constant onto the stack.
+     *   Category: Literals
+     *   Type: Constants
+     *   Operands: uint32_t constIndex
+     *   Stack: => val
+     */ \
     macro(JSOP_DOUBLE,    60, "double",     NULL,         5,  0,  1, JOF_DOUBLE) \
+    /*
+     * Pushes string constant onto the stack.
+     *   Category: Literals
+     *   Type: Constants
+     *   Operands: uint32_t atomIndex
+     *   Stack: => string
+     */ \
     macro(JSOP_STRING,    61, "string",     NULL,         5,  0,  1, JOF_ATOM) \
+    /*
+     * Pushes '0' onto the stack.
+     *   Category: Literals
+     *   Type: Constants
+     *   Operands:
+     *   Stack: => 0
+     */ \
     macro(JSOP_ZERO,      62, "zero",       "0",          1,  0,  1, JOF_BYTE) \
+    /*
+     * Pushes '1' onto the stack.
+     *   Category: Literals
+     *   Type: Constants
+     *   Operands:
+     *   Stack: => 1
+     */ \
     macro(JSOP_ONE,       63, "one",        "1",          1,  0,  1, JOF_BYTE) \
+    /*
+     * Pushes 'null' onto the stack.
+     *   Category: Literals
+     *   Type: Constants
+     *   Operands:
+     *   Stack: => null
+     */ \
     macro(JSOP_NULL,      64, js_null_str,  js_null_str,  1,  0,  1, JOF_BYTE) \
+    /*
+     * Pushes 'this' value for current stack frame onto the stack.
+     *   Category: Variables and Scopes
+     *   Type: This
+     *   Operands:
+     *   Stack: => this
+     */ \
     macro(JSOP_THIS,      65, js_this_str,  js_this_str,  1,  0,  1, JOF_BYTE) \
+    /*
+     * Pushes boolean value onto the stack.
+     *   Category: Literals
+     *   Type: Constants
+     *   Operands:
+     *   Stack: => true/false
+     */ \
     macro(JSOP_FALSE,     66, js_false_str, js_false_str, 1,  0,  1, JOF_BYTE) \
     macro(JSOP_TRUE,      67, js_true_str,  js_true_str,  1,  0,  1, JOF_BYTE) \
     macro(JSOP_OR,        68, "or",         NULL,         5,  1,  1, JOF_JUMP|JOF_DETECTING|JOF_LEFTASSOC) \
     macro(JSOP_AND,       69, "and",        NULL,         5,  1,  1, JOF_JUMP|JOF_DETECTING|JOF_LEFTASSOC) \
     \
     /* The switch bytecodes have variable length. */ \
     macro(JSOP_TABLESWITCH, 70, "tableswitch", NULL,     -1,  1,  0,  JOF_TABLESWITCH|JOF_DETECTING) \
     \
     /*
-     * Prologue emitted in scripts expected to run once, which deoptimizes code if
-     * it executes multiple times.
+     * Prologue emitted in scripts expected to run once, which deoptimizes code
+     * if it executes multiple times.
+     *   Category: Statements
+     *   Type: Function
+     *   Operands:
+     *   Stack: =>
      */ \
     macro(JSOP_RUNONCE,   71, "runonce",    NULL,         1,  0,  0,  JOF_BYTE) \
     \
     /* New, infallible/transitive identity ops. */ \
     /*
      * Pops the top two values from the stack, then pushes the result of
      * applying the operator to the two values.
      *   Category: Operator
@@ -321,18 +516,22 @@ 1234567890123456789012345678901234567890
      *   Operands:
      *   Stack: lval, rval => (lval OP rval)
      */ \
     macro(JSOP_STRICTEQ,  72, "stricteq",   "===",        1,  2,  1, JOF_BYTE|JOF_DETECTING|JOF_LEFTASSOC|JOF_ARITH) \
     macro(JSOP_STRICTNE,  73, "strictne",   "!==",        1,  2,  1, JOF_BYTE|JOF_DETECTING|JOF_LEFTASSOC|JOF_ARITH) \
     \
     /*
      * Sometimes web pages do 'o.Item(i) = j'. This is not an early SyntaxError,
-     * for web compatibility. Instead we emit JSOP_SETCALL after the function call,
-     * an opcode that always throws.
+     * for web compatibility. Instead we emit JSOP_SETCALL after the function
+     * call, an opcode that always throws.
+     *   Category: Statements
+     *   Type: Function
+     *   Operands:
+     *   Stack: =>
      */ \
     macro(JSOP_SETCALL,   74, "setcall",    NULL,         1,  0,  0, JOF_BYTE) \
     \
     /*
      * JSOP_ITER sets up a for-in or for-each-in loop using the JSITER_* flag bits
      * in this op's uint8_t immediate operand. It replaces the top of stack value
      * with an iterator for that value.
      *
@@ -343,95 +542,313 @@ 1234567890123456789012345678901234567890
      * JSOP_ENDITER cleans up after the loop. It uses the slot above the iterator
      * for temporary GC rooting.
      */ \
     macro(JSOP_ITER,      75, "iter",       NULL,         2,  1,  1,  JOF_UINT8) \
     macro(JSOP_MOREITER,  76, "moreiter",   NULL,         1,  1,  2,  JOF_BYTE) \
     macro(JSOP_ITERNEXT,  77, "iternext",   "<next>",     1,  0,  1,  JOF_BYTE) \
     macro(JSOP_ENDITER,   78, "enditer",    NULL,         1,  1,  0,  JOF_BYTE) \
     \
+    /*
+     * Invokes 'callee' with 'this' and 'args', pushes return value onto the
+     * stack.
+     *
+     * This is for 'f.apply'.
+     *   Category: Statements
+     *   Type: Function
+     *   Operands: uint16_t argc
+     *   Stack: callee, this, args[0], ..., args[argc-1] => rval
+     *   nuses: (argc+2)
+     */ \
     macro(JSOP_FUNAPPLY,  79, "funapply",   NULL,         3, -1,  1,  JOF_UINT16|JOF_INVOKE|JOF_TYPESET) \
     \
-    /* Push object initializer literal. */ \
+    /*
+     * Pushes deep-cloned object literal or singleton onto the stack.
+     *   Category: Literals
+     *   Type: Object
+     *   Operands: uint32_t objectIndex
+     *   Stack: => obj
+     */ \
     macro(JSOP_OBJECT,    80, "object",     NULL,         5,  0,  1,  JOF_OBJECT) \
     \
     /*
      * Pops the top value off the stack.
      *   Category: Operator
      *   Type: Stack Operations
      *   Operands:
      *   Stack: v =>
      */ \
     macro(JSOP_POP,       81, "pop",        NULL,         1,  1,  0,  JOF_BYTE) \
     \
-    /* Call a function as a constructor; operand is argc. */ \
+    /*
+     * Invokes 'callee' as a constructor with 'this' and 'args', pushes return
+     * value onto the stack.
+     *   Category: Statements
+     *   Type: Function
+     *   Operands: uint16_t argc
+     *   Stack: callee, this, args[0], ..., args[argc-1] => rval
+     *   nuses: (argc+2)
+     */ \
     macro(JSOP_NEW,       82, js_new_str,   NULL,         3, -1,  1,  JOF_UINT16|JOF_INVOKE|JOF_TYPESET) \
-    \
+    /*
+     * Pops the top three values on the stack as 'iterable', 'index' and 'obj',
+     * iterates over 'iterable' and stores the iteration values as 'index + i'
+     * elements of 'obj', pushes 'obj' and 'index + iteration count' onto the
+     * stack.
+     *
+     * This opcode is used in Array literals with spread and spreadcall
+     * arguments.
+     *   Category: Literals
+     *   Type: Array
+     *   Operands:
+     *   Stack: obj, index, iterable => obj, (index + iteration count)
+     */ \
     macro(JSOP_SPREAD,    83, "spread",     NULL,         1,  3,  2,  JOF_BYTE|JOF_ELEM|JOF_SET) \
     \
-    /* Fast get/set ops for function arguments and local variables. */ \
+    /*
+     * Fast get op for function arguments and local variables.
+     *
+     * Pushes 'arguments[argno]' onto the stack.
+     *   Category: Variables and Scopes
+     *   Type: Arguments
+     *   Operands: uint16_t argno
+     *   Stack: => arguments[argno]
+     */ \
     macro(JSOP_GETARG,    84, "getarg",     NULL,         3,  0,  1,  JOF_QARG |JOF_NAME) \
+    /*
+     * Fast set op for function arguments and local variables.
+     *
+     * Sets 'arguments[argno]' as the top of stack value.
+     *   Category: Variables and Scopes
+     *   Type: Arguments
+     *   Operands: uint16_t argno
+     *   Stack: v => v
+     */ \
     macro(JSOP_SETARG,    85, "setarg",     NULL,         3,  1,  1,  JOF_QARG |JOF_NAME|JOF_SET) \
+    /*
+     * Pushes the value of local variable onto the stack.
+     *   Category: Variables and Scopes
+     *   Type: Local Variables
+     *   Operands: uint32_t localno
+     *   Stack: => val
+     */ \
     macro(JSOP_GETLOCAL,  86,"getlocal",    NULL,         4,  0,  1,  JOF_LOCAL|JOF_NAME) \
+    /*
+     * Stores the top stack value to the given local.
+     *   Category: Variables and Scopes
+     *   Type: Local Variables
+     *   Operands: uint32_t localno
+     *   Stack: v => v
+     */ \
     macro(JSOP_SETLOCAL,  87,"setlocal",    NULL,         4,  1,  1,  JOF_LOCAL|JOF_NAME|JOF_SET|JOF_DETECTING) \
     \
-    /* Push unsigned 16-bit int constant. */ \
-    macro(JSOP_UINT16,    88, "uint16",     NULL,         3,  0,  1,  JOF_UINT16) \
-    \
     /*
-     * Object and array literal support.  NEWINIT takes the kind of initializer
-     * (JSProto_Array or JSProto_Object).  NEWARRAY is an array initializer
-     * taking the final length, which can be filled in at the start and initialized
-     * directly.  NEWOBJECT is an object initializer taking an object with the final
-     * shape, which can be set at the start and slots then filled in directly.
-     * NEWINIT has an extra byte so it can be exchanged with NEWOBJECT during emit.
+     * Pushes unsigned 16-bit int immediate integer operand onto the stack.
+     *   Category: Literals
+     *   Type: Constants
+     *   Operands: uint16_t val
+     *   Stack: => val
+     */ \
+    macro(JSOP_UINT16,    88, "uint16",     NULL,         3,  0,  1,  JOF_UINT16) \
+    \
+    /* Object and array literal support. */ \
+    /*
+     * Pushes newly created object onto the stack.
+     *
+     * This opcode takes the kind of initializer (JSProto_Array or
+     * JSProto_Object).
+     *
+     * This opcode has an extra byte so it can be exchanged with JSOP_NEWOBJECT
+     * during emit.
+     *   Category: Literals
+     *   Type: Object
+     *   Operands: uint8_t kind (, uint24_t extra)
+     *   Stack: => obj
      */ \
     macro(JSOP_NEWINIT,   89, "newinit",    NULL,         5,  0,  1, JOF_UINT8) \
+    /*
+     * Pushes newly created array onto the stack.
+     *
+     * This opcode takes the final length, which is preallocated.
+     *   Category: Literals
+     *   Type: Array
+     *   Operands: uint24_t length
+     *   Stack: => obj
+     */ \
     macro(JSOP_NEWARRAY,  90, "newarray",   NULL,         4,  0,  1, JOF_UINT24) \
+    /*
+     * Pushes newly created object onto the stack.
+     *
+     * This opcode takes an object with the final shape, which can be set at
+     * the start and slots then filled in directly.
+     *   Category: Literals
+     *   Type: Object
+     *   Operands: uint32_t baseobjIndex
+     *   Stack: => obj
+     */ \
     macro(JSOP_NEWOBJECT, 91, "newobject",  NULL,         5,  0,  1, JOF_OBJECT) \
+    /*
+     * A no-operation bytecode.
+     *
+     * Indicates the end of object/array initialization, and used for
+     * Type-Inference, decompile, etc.
+     *   Category: Literals
+     *   Type: Object
+     *   Operands:
+     *   Stack: =>
+     */ \
     macro(JSOP_ENDINIT,   92, "endinit",    NULL,         1,  0,  0, JOF_BYTE) \
+    /*
+     * Initialize a named property in an object literal, like '{a: x}'.
+     *
+     * Pops the top two values on the stack as 'val' and 'obj', defines
+     * 'nameIndex' property of 'obj' as 'val', pushes 'obj' onto the stack.
+     *   Category: Literals
+     *   Type: Object
+     *   Operands: uint32_t nameIndex
+     *   Stack: obj, val => obj
+     */ \
     macro(JSOP_INITPROP,  93, "initprop",   NULL,         5,  2,  1, JOF_ATOM|JOF_PROP|JOF_SET|JOF_DETECTING) \
     \
-    /* Initialize a numeric property in an object literal, like {1: x}. */ \
+    /*
+     * Initialize a numeric property in an object literal, like '{1: x}'.
+     *
+     * Pops the top three values on the stack as 'val', 'id' and 'obj', defines
+     * 'id' property of 'obj' as 'val', pushes 'obj' onto the stack.
+     *   Category: Literals
+     *   Type: Object
+     *   Operands:
+     *   Stack: obj, id, val => obj
+     */ \
     macro(JSOP_INITELEM,  94, "initelem",   NULL,         1,  3,  1, JOF_BYTE|JOF_ELEM|JOF_SET|JOF_DETECTING) \
     \
-    /* Used in array literals with spread. */ \
+    /*
+     * Pops the top three values on the stack as 'val', 'index' and 'obj', sets
+     * 'index' property of 'obj' as 'val', pushes 'obj' and 'index + 1' onto
+     * the stack.
+     *
+     * This opcode is used in Array literals with spread and spreadcall
+     * arguments.
+     *   Category: Literals
+     *   Type: Array
+     *   Operands:
+     *   Stack: obj, index, val => obj, (index + 1)
+     */ \
     macro(JSOP_INITELEM_INC,95, "initelem_inc", NULL,     1,  3,  2, JOF_BYTE|JOF_ELEM|JOF_SET) \
     \
-    /* Initialize an array element. */ \
+    /*
+     * Initialize an array element.
+     *
+     * Pops the top two values on the stack as 'val' and 'obj', sets 'index'
+     * property of 'obj' as 'val', pushes 'obj' onto the stack.
+     *   Category: Literals
+     *   Type: Array
+     *   Operands: uint24_t index
+     *   Stack: obj, val => obj
+     */ \
     macro(JSOP_INITELEM_ARRAY,96, "initelem_array", NULL, 4,  2,  1,  JOF_UINT24|JOF_ELEM|JOF_SET|JOF_DETECTING) \
     \
     /*
-     * Initialize a getter/setter in an object literal. The INITELEM* ops are used
-     * for numeric properties like {get 2() {}}.
+     * Initialize a getter in an object literal.
+     *
+     * Pops the top two values on the stack as 'val' and 'obj', defines getter
+     * of 'obj' as 'val', pushes 'obj' onto the stack.
+     *   Category: Literals
+     *   Type: Object
+     *   Operands: uint32_t nameIndex
+     *   Stack: obj, val => obj
      */ \
     macro(JSOP_INITPROP_GETTER,  97, "initprop_getter",   NULL, 5,  2,  1, JOF_ATOM|JOF_PROP|JOF_SET|JOF_DETECTING) \
+    /*
+     * Initialize a setter in an object literal.
+     *
+     * Pops the top two values on the stack as 'val' and 'obj', defines setter
+     * of 'obj' as 'val', pushes 'obj' onto the stack.
+     *   Category: Literals
+     *   Type: Object
+     *   Operands: uint32_t nameIndex
+     *   Stack: obj, val => obj
+     */ \
     macro(JSOP_INITPROP_SETTER,  98, "initprop_setter",   NULL, 5,  2,  1, JOF_ATOM|JOF_PROP|JOF_SET|JOF_DETECTING) \
+    /*
+     * Initialize a numeric getter in an object literal like
+     * '{get 2() {}}'.
+     *
+     * Pops the top three values on the stack as 'val', 'id' and 'obj', defines
+     * 'id' getter of 'obj' as 'val', pushes 'obj' onto the stack.
+     *   Category: Literals
+     *   Type: Object
+     *   Operands:
+     *   Stack: obj, id, val => obj
+     */ \
     macro(JSOP_INITELEM_GETTER,  99, "initelem_getter",   NULL, 1,  3,  1, JOF_BYTE|JOF_ELEM|JOF_SET|JOF_DETECTING) \
+    /*
+     * Initialize a numeric setter in an object literal like
+     * '{set 2(v) {}}'.
+     *
+     * Pops the top three values on the stack as 'val', 'id' and 'obj', defines
+     * 'id' setter of 'obj' as 'val', pushes 'obj' onto the stack.
+     *   Category: Literals
+     *   Type: Object
+     *   Operands:
+     *   Stack: obj, id, val => obj
+     */ \
     macro(JSOP_INITELEM_SETTER, 100, "initelem_setter",   NULL, 1,  3,  1, JOF_BYTE|JOF_ELEM|JOF_SET|JOF_DETECTING) \
     \
     macro(JSOP_UNUSED101,  101, "unused101",   NULL,         1,  0,  0,  JOF_BYTE) \
     macro(JSOP_UNUSED102,  102, "unused102",   NULL,         1,  0,  0,  JOF_BYTE) \
     macro(JSOP_UNUSED103,  103, "unused103",   NULL,         1,  0,  0,  JOF_BYTE) \
     macro(JSOP_UNUSED104,  104, "unused104",   NULL,         1,  0,  0,  JOF_BYTE) \
     macro(JSOP_UNUSED105,  105, "unused105",   NULL,         1,  0,  0,  JOF_BYTE) \
     \
     /* The argument is the offset to the next statement and is used by IonMonkey. */ \
     macro(JSOP_LABEL,     106,"label",     NULL,          5,  0,  0,  JOF_JUMP) \
     \
     macro(JSOP_UNUSED107, 107,"unused107",  NULL,         1,  0,  0,  JOF_BYTE) \
     \
-    /* Like JSOP_FUNAPPLY but for f.call instead of f.apply. */ \
+    /*
+     * Invokes 'callee' with 'this' and 'args', pushes return value onto the
+     * stack.
+     *
+     * If 'callee' is determined to be the canonical 'Function.prototype.call'
+     * function, then this operation is optimized to directly call 'callee'
+     * with 'args[0]' as 'this', and the remaining arguments as formal args
+     * to 'callee'.
+     *
+     * Like JSOP_FUNAPPLY but for 'f.call' instead of 'f.apply'.
+     *   Category: Statements
+     *   Type: Function
+     *   Operands: uint16_t argc
+     *   Stack: callee, this, args[0], ..., args[argc-1] => rval
+     *   nuses: (argc+2)
+     */ \
     macro(JSOP_FUNCALL,   108,"funcall",    NULL,         3, -1,  1, JOF_UINT16|JOF_INVOKE|JOF_TYPESET) \
     \
     /* This opcode is the target of the backwards jump for some loop. */ \
     macro(JSOP_LOOPHEAD,  109,"loophead",   NULL,         1,  0,  0,  JOF_BYTE) \
     \
     /* ECMA-compliant assignment ops. */ \
+    /*
+     * Looks up name on the scope chain and pushes the scope which contains
+     * the name onto the stack. If not found, pushes global scope onto the
+     * stack.
+     *   Category: Variables and Scopes
+     *   Type: Variables
+     *   Operands: uint32_t nameIndex
+     *   Stack: => scope
+     */ \
     macro(JSOP_BINDNAME,  110,"bindname",   NULL,         5,  0,  1,  JOF_ATOM|JOF_NAME|JOF_SET) \
+    /*
+     * Pops a scope and value from the stack, assigns value to the given name,
+     * and pushes the value back on the stack
+     *   Category: Variables and Scopes
+     *   Type: Variables
+     *   Operands: uint32_t nameIndex
+     *   Stack: scope, val => val
+     */ \
     macro(JSOP_SETNAME,   111,"setname",    NULL,         5,  2,  1,  JOF_ATOM|JOF_NAME|JOF_SET|JOF_DETECTING) \
     \
     /* Exception handling ops. */ \
     macro(JSOP_THROW,     112,js_throw_str, NULL,         1,  1,  0,  JOF_BYTE) \
     \
     /*
      * Pops the top two values 'id' and 'obj' from the stack, then pushes
      * 'id in obj'.  This will throw a 'TypeError' if 'obj' is not an object.
@@ -449,57 +866,132 @@ 1234567890123456789012345678901234567890
      * object.
      *   Category: Operator
      *   Type: Special Operators
      *   Operands:
      *   Stack: obj, ctor => (obj instanceof ctor)
      */ \
     macro(JSOP_INSTANCEOF,114,js_instanceof_str,js_instanceof_str,1,2,1,JOF_BYTE|JOF_LEFTASSOC|JOF_TMPSLOT) \
     \
-    /* debugger op */ \
+    /*
+     * Invokes debugger.
+     *   Category: Statements
+     *   Type: Debugger
+     *   Operands:
+     *   Stack: =>
+     */ \
     macro(JSOP_DEBUGGER,  115,"debugger",   NULL,         1,  0,  0, JOF_BYTE) \
     \
     /* gosub/retsub for finally handling */ \
     macro(JSOP_GOSUB,     116,"gosub",      NULL,         5,  0,  0,  JOF_JUMP) \
     macro(JSOP_RETSUB,    117,"retsub",     NULL,         1,  2,  0,  JOF_BYTE) \
     \
     /* More exception handling ops. */ \
     macro(JSOP_EXCEPTION, 118,"exception",  NULL,         1,  0,  1,  JOF_BYTE) \
     \
-    /* Embedded lineno to speedup pc->line mapping. */ \
+    /*
+     * Embedded lineno to speedup 'pc->line' mapping.
+     *   Category: Other
+     *   Operands: uint32_t lineno
+     *   Stack: =>
+     */ \
     macro(JSOP_LINENO,    119,"lineno",     NULL,         3,  0,  0,  JOF_UINT16) \
     \
     /*
      * ECMA-compliant switch statement ops.
      * CONDSWITCH is a decompilable NOP; CASE is ===, POP, jump if true, re-push
      * lval if false; and DEFAULT is POP lval and GOTO.
      */ \
     macro(JSOP_CONDSWITCH,120,"condswitch", NULL,         1,  0,  0,  JOF_BYTE) \
     macro(JSOP_CASE,      121,"case",       NULL,         5,  2,  1,  JOF_JUMP) \
     macro(JSOP_DEFAULT,   122,"default",    NULL,         5,  1,  0,  JOF_JUMP) \
     \
+    /* ECMA-compliant call to eval op. */ \
     /*
-     * ECMA-compliant call to eval op
+     * Invokes 'eval' with 'args' and pushes return value onto the stack.
+     *
+     * If 'eval' in global scope is not original one, invokes the function
+     * with 'this' and 'args', and pushes return value onto the stack.
+     *   Category: Statements
+     *   Type: Function
+     *   Operands: uint16_t argc
+     *   Stack: callee, this, args[0], ..., args[argc-1] => rval
+     *   nuses: (argc+2)
      */ \
     macro(JSOP_EVAL,      123,"eval",       NULL,         3, -1,  1, JOF_UINT16|JOF_INVOKE|JOF_TYPESET) \
     \
     macro(JSOP_UNUSED124,  124, "unused124", NULL,      1,  0,  0,  JOF_BYTE) \
     macro(JSOP_UNUSED125,  125, "unused125", NULL,      1,  0,  0,  JOF_BYTE) \
     macro(JSOP_UNUSED126,  126, "unused126", NULL,      1,  0,  0,  JOF_BYTE) \
     \
-    /* Prolog bytecodes for defining function, var, and const names. */ \
+    /*
+     * Defines the given function on the current scope.
+     *
+     * This is used for global scripts and also in some cases for function
+     * scripts where use of dynamic scoping inhibits optimization.
+     *   Category: Variables and Scopes
+     *   Type: Variables
+     *   Operands: uint32_t funcIndex
+     *   Stack: =>
+     */ \
     macro(JSOP_DEFFUN,    127,"deffun",     NULL,         5,  0,  0,  JOF_OBJECT) \
+    /*
+     * Defines the new binding on the frame's current variables-object (the
+     * scope object on the scope chain designated to receive new variables)
+     * with 'READONLY' attribute.
+     *
+     * This is used for global scripts and also in some cases for function
+     * scripts where use of dynamic scoping inhibits optimization.
+     *   Category: Variables and Scopes
+     *   Type: Variables
+     *   Operands: uint32_t nameIndex
+     *   Stack: =>
+     */ \
     macro(JSOP_DEFCONST,  128,"defconst",   NULL,         5,  0,  0,  JOF_ATOM) \
+    /*
+     * Defines the new binding on the frame's current variables-object (the
+     * scope object on the scope chain designated to receive new variables).
+     *
+     * This is used for global scripts and also in some cases for function
+     * scripts where use of dynamic scoping inhibits optimization.
+     *   Category: Variables and Scopes
+     *   Type: Variables
+     *   Operands: uint32_t nameIndex
+     *   Stack: =>
+     */ \
     macro(JSOP_DEFVAR,    129,"defvar",     NULL,         5,  0,  0,  JOF_ATOM) \
     \
-    /* Push a closure for a named or anonymous function expression. */ \
+    /*
+     * Pushes a closure for a named or anonymous function expression onto the
+     * stack.
+     *   Category: Statements
+     *   Type: Function
+     *   Operands: uint32_t funcIndex
+     *   Stack: => obj
+     */ \
     macro(JSOP_LAMBDA,    130, "lambda",    NULL,         5,  0,  1, JOF_OBJECT) \
+    /*
+     * Pops the top of stack value as 'this', pushes an arrow function with
+     * 'this' onto the stack.
+     *   Category: Statements
+     *   Type: Function
+     *   Operands: uint32_t funcIndex
+     *   Stack: this => obj
+     */ \
     macro(JSOP_LAMBDA_ARROW, 131, "lambda_arrow", NULL,   5,  1,  1, JOF_OBJECT) \
     \
-    /* Used for named function expression self-naming, if lightweight. */ \
+    /*
+     * Pushes current callee onto the stack.
+     *
+     * Used for named function expression self-naming, if lightweight.
+     *   Category: Variables and Scopes
+     *   Type: Arguments
+     *   Operands:
+     *   Stack: => callee
+     */ \
     macro(JSOP_CALLEE,    132, "callee",    NULL,         1,  0,  1, JOF_BYTE) \
     \
     /*
      * Picks the nth element from the stack and moves it to the top of the
      * stack.
      *   Category: Operator
      *   Type: Stack Operations
      *   Operands: uint8_t n
@@ -510,79 +1002,154 @@ 1234567890123456789012345678901234567890
     /*
      * Exception handling no-op, for more economical byte-coding than SRC_TRYFIN
      * srcnote-annotated JSOP_NOPs and to simply stack balance handling.
      */ \
     macro(JSOP_TRY,         134,"try",        NULL,       1,  0,  0,  JOF_BYTE) \
     macro(JSOP_FINALLY,     135,"finally",    NULL,       1,  0,  2,  JOF_BYTE) \
     \
     /*
-     * An "aliased variable" is a var, let, or formal arg that is aliased. Sources
-     * of aliasing include: nested functions accessing the vars of an enclosing
-     * function, function statements that are conditionally executed, 'eval',
-     * 'with', and 'arguments'. All of these cases require creating a CallObject to
-     * own the aliased variable.
+     * Pushes aliased variable onto the stack.
+     *
+     * An "aliased variable" is a var, let, or formal arg that is aliased.
+     * Sources of aliasing include: nested functions accessing the vars of an
+     * enclosing function, function statements that are conditionally executed,
+     * 'eval', 'with', and 'arguments'. All of these cases require creating a
+     * CallObject to own the aliased variable.
      *
      * An ALIASEDVAR opcode contains the following immediates:
      *  uint8 hops:  the number of scope objects to skip to find the ScopeObject
      *               containing the variable being accessed
      *  uint24 slot: the slot containing the variable in the ScopeObject (this
      *               'slot' does not include RESERVED_SLOTS).
+     *   Category: Variables and Scopes
+     *   Type: Aliased Variables
+     *   Operands: uint8_t hops, uint24_t slot
+     *   Stack: => aliasedVar
      */ \
     macro(JSOP_GETALIASEDVAR, 136,"getaliasedvar",NULL,      5,  0,  1,  JOF_SCOPECOORD|JOF_NAME|JOF_TYPESET) \
+    /*
+     * Sets aliased variable as the top of stack value.
+     *   Category: Variables and Scopes
+     *   Type: Aliased Variables
+     *   Operands: uint8_t hops, uint24_t slot
+     *   Stack: v => v
+     */ \
     macro(JSOP_SETALIASEDVAR, 137,"setaliasedvar",NULL,      5,  1,  1,  JOF_SCOPECOORD|JOF_NAME|JOF_SET|JOF_DETECTING) \
     \
     macro(JSOP_UNUSED138,  138, "unused138",   NULL,         1,  0,  0,  JOF_BYTE) \
     macro(JSOP_UNUSED139,  139, "unused139",   NULL,         1,  0,  0,  JOF_BYTE) \
     macro(JSOP_UNUSED140,  140, "unused140",   NULL,         1,  0,  0,  JOF_BYTE) \
     macro(JSOP_UNUSED141,  141, "unused141",   NULL,         1,  0,  0,  JOF_BYTE) \
     macro(JSOP_UNUSED142,  142, "unused142",   NULL,         1,  0,  0,  JOF_BYTE) \
     \
     /*
+     * Pushes the value of the intrinsic onto the stack.
+     *
      * Intrinsic names are emitted instead of JSOP_*NAME ops when the
-     * CompileOptions flag "selfHostingMode" is set.
+     * 'CompileOptions' flag 'selfHostingMode' is set.
      *
      * They are used in self-hosted code to access other self-hosted values and
      * intrinsic functions the runtime doesn't give client JS code access to.
+     *   Category: Variables and Scopes
+     *   Type: Intrinsics
+     *   Operands: uint32_t nameIndex
+     *   Stack: => intrinsic[name]
      */ \
     macro(JSOP_GETINTRINSIC,  143, "getintrinsic",  NULL, 5,  0,  1, JOF_ATOM|JOF_NAME|JOF_TYPESET) \
+    /*
+     * Pops the top two values on the stack as 'val' and 'scope', sets intrinsic
+     * as 'val', and pushes 'val' onto the stack.
+     *
+     * 'scope' is not used.
+     *   Category: Variables and Scopes
+     *   Type: Intrinsics
+     *   Operands: uint32_t nameIndex
+     *   Stack: scope, val => val
+     */ \
     macro(JSOP_SETINTRINSIC,  144, "setintrinsic",  NULL, 5,  2,  1, JOF_ATOM|JOF_NAME|JOF_SET|JOF_DETECTING) \
+    /*
+     * Pushes 'intrinsicHolder' onto the stack.
+     *   Category: Variables and Scopes
+     *   Type: Intrinsics
+     *   Operands: uint32_t nameIndex
+     *   Stack: => intrinsicHolder
+     */ \
     macro(JSOP_BINDINTRINSIC, 145, "bindintrinsic", NULL, 5,  0,  1, JOF_ATOM|JOF_NAME|JOF_SET) \
     \
     /* Unused. */ \
     macro(JSOP_UNUSED146,     146,"unused146", NULL,      1,  0,  0,  JOF_BYTE) \
     macro(JSOP_UNUSED147,     147,"unused147", NULL,      1,  0,  0,  JOF_BYTE) \
     macro(JSOP_UNUSED148,     148,"unused148", NULL,      1,  0,  0,  JOF_BYTE) \
     \
     /* Placeholders for a real jump opcode set during backpatch chain fixup. */ \
     macro(JSOP_BACKPATCH,     149,"backpatch", NULL,      5,  0,  0,  JOF_JUMP) \
     macro(JSOP_UNUSED150,     150,"unused150", NULL,      1,  0,  0,  JOF_BYTE) \
     \
     /* Set pending exception from the stack, to trigger rethrow. */ \
     macro(JSOP_THROWING,      151,"throwing", NULL,       1,  1,  0,  JOF_BYTE) \
     \
-    /* Set the return value pseudo-register in stack frame. */ \
+    /*
+     * Pops the top of stack value as 'rval', sets the return value in stack
+     * frame as 'rval'.
+     *   Category: Statements
+     *   Type: Function
+     *   Operands:
+     *   Stack: rval =>
+     */ \
     macro(JSOP_SETRVAL,       152,"setrval",    NULL,       1,  1,  0,  JOF_BYTE) \
     /*
-     * Stop interpretation and return value set by JSOP_SETRVAL. When not set,
-     * returns UndefinedValue. Also emitted at end of script so interpreter
-     * don't need to check if opcode is still in script range.
+     * Stops interpretation and returns value set by JSOP_SETRVAL. When not set,
+     * returns 'undefined'.
+     *
+     * Also emitted at end of script so interpreter don't need to check if
+     * opcode is still in script range.
+     *   Category: Statements
+     *   Type: Function
+     *   Operands:
+     *   Stack: =>
      */ \
     macro(JSOP_RETRVAL,       153,"retrval",    NULL,       1,  0,  0,  JOF_BYTE) \
     \
-    /* Free variable references that must either be found on the global or a ReferenceError */ \
+    /*
+     * Looks up name on global scope and pushes its value onto the stack.
+     *
+     * Free variable references that must either be found on the global or a
+     * ReferenceError.
+     *   Category: Variables and Scopes
+     *   Type: Free Variables
+     *   Operands: uint32_t nameIndex
+     *   Stack: => val
+     */ \
     macro(JSOP_GETGNAME,      154,"getgname",  NULL,       5,  0,  1, JOF_ATOM|JOF_NAME|JOF_TYPESET|JOF_GNAME) \
+    /*
+     * Pops the top two values on the stack as 'val' and 'scope', sets property
+     * of 'scope' as 'val' and pushes 'val' back on the stack.
+     *
+     * 'scope' should be the global scope.
+     *   Category: Variables and Scopes
+     *   Type: Free Variables
+     *   Operands: uint32_t nameIndex
+     *   Stack: scope, val => val
+     */ \
     macro(JSOP_SETGNAME,      155,"setgname",  NULL,       5,  2,  1, JOF_ATOM|JOF_NAME|JOF_SET|JOF_DETECTING|JOF_GNAME) \
     \
     macro(JSOP_UNUSED156,  156, "unused156",   NULL,         1,  0,  0,  JOF_BYTE) \
     macro(JSOP_UNUSED157,  157, "unused157",   NULL,         1,  0,  0,  JOF_BYTE) \
     macro(JSOP_UNUSED158,  158, "unused158",   NULL,         1,  0,  0,  JOF_BYTE) \
     macro(JSOP_UNUSED159,  159, "unused159",   NULL,         1,  0,  0,  JOF_BYTE) \
     \
-    /* Regular expression literal requiring special "fork on exec" handling. */ \
+    /*
+     * Pushes a regular expression literal onto the stack.
+     * It requires special "clone on exec" handling.
+     *   Category: Literals
+     *   Type: RegExp
+     *   Operands: uint32_t regexpIndex
+     *   Stack: => regexp
+     */ \
     macro(JSOP_REGEXP,        160,"regexp",   NULL,       5,  0,  1, JOF_REGEXP) \
     \
     macro(JSOP_UNUSED161,     161,"unused161",  NULL,     1,  0,  0,  JOF_BYTE) \
     macro(JSOP_UNUSED162,     162,"unused162",  NULL,     1,  0,  0,  JOF_BYTE) \
     macro(JSOP_UNUSED163,     163,"unused163",  NULL,     1,  0,  0,  JOF_BYTE) \
     macro(JSOP_UNUSED164,     164,"unused164",  NULL,     1,  0,  0,  JOF_BYTE) \
     macro(JSOP_UNUSED165,     165,"unused165",  NULL,     1,  0,  0,  JOF_BYTE) \
     macro(JSOP_UNUSED166,     166,"unused166",  NULL,     1,  0,  0,  JOF_BYTE) \
@@ -599,38 +1166,77 @@ 1234567890123456789012345678901234567890
     macro(JSOP_UNUSED177,     177,"unused177",  NULL,     1,  0,  0,  JOF_BYTE) \
     macro(JSOP_UNUSED178,     178,"unused178",  NULL,     1,  0,  0,  JOF_BYTE) \
     macro(JSOP_UNUSED179,     179,"unused179",  NULL,     1,  0,  0,  JOF_BYTE) \
     macro(JSOP_UNUSED180,     180,"unused180",  NULL,     1,  0,  0,  JOF_BYTE) \
     macro(JSOP_UNUSED181,     181,"unused181",  NULL,     1,  0,  0,  JOF_BYTE) \
     macro(JSOP_UNUSED182,     182,"unused182",  NULL,     1,  0,  0,  JOF_BYTE) \
     macro(JSOP_UNUSED183,     183,"unused183",  NULL,     1,  0,  0,  JOF_BYTE) \
     \
+    /*
+     * Pops the top of stack value, pushes property of it onto the stack.
+     *
+     * Like JSOP_GETPROP but for call context.
+     *   Category: Literals
+     *   Type: Object
+     *   Operands: uint32_t nameIndex
+     *   Stack: obj => obj[name]
+     */ \
     macro(JSOP_CALLPROP,      184,"callprop",   NULL,     5,  1,  1, JOF_ATOM|JOF_PROP|JOF_TYPESET|JOF_TMPSLOT3) \
     \
     macro(JSOP_UNUSED185,     185,"unused185",  NULL,     1,  0,  0,  JOF_BYTE) \
     macro(JSOP_UNUSED186,     186,"unused186",  NULL,     1,  0,  0,  JOF_BYTE) \
     macro(JSOP_UNUSED187,     187,"unused187",  NULL,     1,  0,  0,  JOF_BYTE) \
     \
-    /* Opcode to hold 24-bit immediate integer operands. */ \
+    /*
+     * Pushes unsigned 24-bit int immediate integer operand onto the stack.
+     *   Category: Literals
+     *   Type: Constants
+     *   Operands: uint24_t val
+     *   Stack: => val
+     */ \
     macro(JSOP_UINT24,        188,"uint24",     NULL,     4,  0,  1, JOF_UINT24) \
     \
     macro(JSOP_UNUSED189,     189,"unused189",   NULL,    1,  0,  0,  JOF_BYTE) \
     macro(JSOP_UNUSED190,     190,"unused190",   NULL,    1,  0,  0,  JOF_BYTE) \
     macro(JSOP_UNUSED191,     191,"unused191",   NULL,    1,  0,  0,  JOF_BYTE) \
     macro(JSOP_UNUSED192,     192,"unused192",   NULL,    1,  0,  0,  JOF_BYTE) \
     \
+    /*
+     * Pops the top two values on the stack as 'propval' and 'obj', pushes
+     * 'propval' property of 'obj' onto the stack.
+     *
+     * Like JSOP_GETELEM but for call context.
+     *   Category: Literals
+     *   Type: Object
+     *   Operands:
+     *   Stack: obj, propval => obj[propval]
+     */ \
     macro(JSOP_CALLELEM,      193, "callelem",   NULL,    1,  2,  1, JOF_BYTE |JOF_ELEM|JOF_TYPESET|JOF_LEFTASSOC) \
     \
-    /* __proto__: v inside an object initializer. */ \
+    /*
+     * '__proto__: v' inside an object initializer.
+     *
+     * Pops the top two values on the stack as 'newProto' and 'obj', sets
+     * prototype of 'obj' as 'newProto', pushes 'true' onto the stack if
+     * succeeded, 'false' if not.
+     *   Category: Literals
+     *   Type: Object
+     *   Operands:
+     *   Stack: obj, newProto => succeeded
+     */ \
     macro(JSOP_MUTATEPROTO,   194, "mutateproto",NULL,    1,  2,  1, JOF_BYTE) \
     \
     /*
-     * Get an extant property value, throwing ReferenceError if the identified
-     * property does not exist.
+     * Pops the top of stack value, gets an extant property value of it,
+     * throwing ReferenceError if the identified property does not exist.
+     *   Category: Literals
+     *   Type: Object
+     *   Operands: uint32_t nameIndex
+     *   Stack: obj => obj[name]
      */ \
     macro(JSOP_GETXPROP,      195,"getxprop",    NULL,    5,  1,  1, JOF_ATOM|JOF_PROP|JOF_TYPESET) \
     \
     macro(JSOP_UNUSED196,     196,"unused196",   NULL,    1,  0,  0, JOF_BYTE) \
     \
     /*
      * Pops the top stack value as 'val' and pushes 'typeof val'.  Note that
      * this opcode isn't used when, in the original source code, 'val' is a
@@ -639,65 +1245,168 @@ 1234567890123456789012345678901234567890
      *   Category: Operator
      *   Type: Special Operators
      *   Operands:
      *   Stack: val => (typeof val)
      */ \
     macro(JSOP_TYPEOFEXPR,    197,"typeofexpr",  NULL,    1,  1,  1, JOF_BYTE|JOF_DETECTING) \
     \
     /* Block-local scope support. */ \
+    /*
+     * Pushes block onto the scope chain.
+     *   Category: Variables and Scopes
+     *   Type: Block-local Scope
+     *   Operands: uint32_t staticBlockObjectIndex
+     *   Stack: =>
+     */ \
     macro(JSOP_PUSHBLOCKSCOPE,198,"pushblockscope", NULL, 5,  0,  0,  JOF_OBJECT) \
+    /*
+     * Pops block from the scope chain.
+     *   Category: Variables and Scopes
+     *   Type: Block-local Scope
+     *   Operands:
+     *   Stack: =>
+     */ \
     macro(JSOP_POPBLOCKSCOPE, 199,"popblockscope", NULL,  1,  0,  0,  JOF_BYTE) \
+    /*
+     * The opcode to assist the debugger.
+     *   Category: Statements
+     *   Type: Debugger
+     *   Operands:
+     *   Stack: =>
+     */ \
     macro(JSOP_DEBUGLEAVEBLOCK, 200,"debugleaveblock", NULL, 1,  0,  0,  JOF_BYTE) \
     \
     macro(JSOP_UNUSED201,     201,"unused201",  NULL,     1,  0,  0,  JOF_BYTE) \
     \
-    /* Generator and array comprehension support. */ \
+    /*
+     * Initializes generator frame, creates a generator, sets 'YIELDING' flag,
+     * stops interpretation and returns the generator.
+     *   Category: Statements
+     *   Type: Generator
+     *   Operands:
+     *   Stack: =>
+     */ \
     macro(JSOP_GENERATOR,     202,"generator",   NULL,    1,  0,  0,  JOF_BYTE) \
+    /*
+     * Pops the top of stack value as 'rval1', sets 'YIELDING' flag,
+     * stops interpretation and returns 'rval1', pushes sent value from
+     * 'send()' onto the stack.
+     *   Category: Statements
+     *   Type: Generator
+     *   Operands:
+     *   Stack: rval1 => rval2
+     */ \
     macro(JSOP_YIELD,         203,"yield",       NULL,    1,  1,  1,  JOF_BYTE) \
+    /*
+     * Pops the top two values on the stack as 'obj' and 'v', pushes 'v' to
+     * 'obj'.
+     *
+     * This opcode is used for Array Comprehension.
+     *   Category: Literals
+     *   Type: Array
+     *   Operands:
+     *   Stack: v, obj =>
+     */ \
     macro(JSOP_ARRAYPUSH,     204,"arraypush",   NULL,    1,  2,  0,  JOF_BYTE) \
     \
     macro(JSOP_UNUSED205,     205, "unused205",    NULL,  1,  0,  0,  JOF_BYTE) \
     macro(JSOP_UNUSED206,     206, "unused206",    NULL,  1,  0,  0,  JOF_BYTE) \
     \
     macro(JSOP_UNUSED207,     207, "unused207",    NULL,  1,  0,  0,  JOF_BYTE) \
     macro(JSOP_UNUSED208,     208, "unused208",    NULL,  1,  0,  0,  JOF_BYTE) \
     macro(JSOP_UNUSED209,     209, "unused209",    NULL,  1,  0,  0,  JOF_BYTE) \
     macro(JSOP_UNUSED210,     210, "unused210",    NULL,  1,  0,  0,  JOF_BYTE) \
     macro(JSOP_UNUSED211,     211, "unused211",    NULL,  1,  0,  0,  JOF_BYTE) \
     macro(JSOP_UNUSED212,     212, "unused212",    NULL,  1,  0,  0,  JOF_BYTE) \
     macro(JSOP_UNUSED213,     213, "unused213",    NULL,  1,  0,  0,  JOF_BYTE) \
+    /*
+     * Pushes the global scope onto the stack.
+     *
+     * 'nameIndex' is not used.
+     *   Category: Variables and Scopes
+     *   Type: Free Variables
+     *   Operands: uint32_t nameIndex
+     *   Stack: => global
+     */ \
     macro(JSOP_BINDGNAME,     214, "bindgname",    NULL,  5,  0,  1,  JOF_ATOM|JOF_NAME|JOF_SET|JOF_GNAME) \
     \
-    /* Opcodes to hold 8-bit and 32-bit immediate integer operands. */ \
+    /*
+     * Pushes 8-bit int immediate integer operand onto the stack.
+     *   Category: Literals
+     *   Type: Constants
+     *   Operands: int8_t val
+     *   Stack: => val
+     */ \
     macro(JSOP_INT8,          215, "int8",         NULL,  2,  0,  1, JOF_INT8) \
+    /*
+     * Pushes 32-bit int immediate integer operand onto the stack.
+     *   Category: Literals
+     *   Type: Constants
+     *   Operands: int32_t val
+     *   Stack: => val
+     */ \
     macro(JSOP_INT32,         216, "int32",        NULL,  5,  0,  1, JOF_INT32) \
     \
-    /* Get the value of the 'length' property from a stacked value. */ \
+    /*
+     * Pops the top of stack value, pushes the 'length' property of it onto the
+     * stack.
+     *   Category: Literals
+     *   Type: Array
+     *   Operands: uint32_t nameIndex
+     *   Stack: obj => obj['length']
+     */ \
     macro(JSOP_LENGTH,        217, "length",       NULL,  5,  1,  1, JOF_ATOM|JOF_PROP|JOF_TYPESET|JOF_TMPSLOT3) \
     \
     /*
-     * Push a JSVAL_HOLE value onto the stack, representing an omitted property in
-     * an array literal (e.g. property 0 in the array [, 1]).  This opcode is used
-     * with the JSOP_NEWARRAY opcode.
+     * Pushes a JS_ELEMENTS_HOLE value onto the stack, representing an omitted
+     * property in an array literal (e.g. property 0 in the array '[, 1]').
+     *
+     * This opcode is used with the JSOP_NEWARRAY opcode.
+     *   Category: Literals
+     *   Type: Array
+     *   Operands:
+     *   Stack: => hole
      */ \
     macro(JSOP_HOLE,          218, "hole",         NULL,  1,  0,  1,  JOF_BYTE) \
     \
     macro(JSOP_UNUSED219,     219,"unused219",     NULL,  1,  0,  0,  JOF_BYTE) \
     macro(JSOP_UNUSED220,     220,"unused220",     NULL,  1,  0,  0,  JOF_BYTE) \
     macro(JSOP_UNUSED221,     221,"unused221",     NULL,  1,  0,  0,  JOF_BYTE) \
     macro(JSOP_UNUSED222,     222,"unused222",     NULL,  1,  0,  0,  JOF_BYTE) \
     macro(JSOP_UNUSED223,     223,"unused223",     NULL,  1,  0,  0,  JOF_BYTE) \
     \
+    /*
+     * Creates rest parameter array for current function call, and pushes it
+     * onto the stack.
+     *   Category: Variables and Scopes
+     *   Type: Arguments
+     *   Operands:
+     *   Stack: => rest
+     */ \
     macro(JSOP_REST,          224, "rest",         NULL,  1,  0,  1,  JOF_BYTE|JOF_TYPESET) \
     \
-    /* Pop the stack, convert to a jsid (int or string), and push back. */ \
+    /*
+     * Pops the top of stack value, converts it into a jsid (int or string), and
+     * pushes it onto the stack.
+     *   Category: Literals
+     *   Type: Object
+     *   Operands:
+     *   Stack: obj, id => obj, (jsid of id)
+     */ \
     macro(JSOP_TOID,          225, "toid",         NULL,  1,  1,  1,  JOF_BYTE) \
     \
-    /* Push the implicit 'this' value for calls to the associated name. */ \
+    /*
+     * Pushes the implicit 'this' value for calls to the associated name onto
+     * the stack.
+     *   Category: Variables and Scopes
+     *   Type: This
+     *   Operands: uint32_t nameIndex
+     *   Stack: => this
+     */                                                                 \
     macro(JSOP_IMPLICITTHIS,  226, "implicitthis", "",    5,  0,  1,  JOF_ATOM) \
     \
     /*
      * This opcode is the target of the entry jump for some loop. The uint8
      * argument is a bitfield. The lower 7 bits of the argument indicate the
      * loop depth. This value starts at 1 and is just a hint: deeply nested
      * loops all have the same value.  The upper bit is set if Ion should be
      * able to OSR at this point, which is true unless there is non-loop state
--- a/js/src/vm/TraceLogging.cpp
+++ b/js/src/vm/TraceLogging.cpp
@@ -85,16 +85,17 @@ const char* const text[] = {
     "MinorGC",
     "ParserCompileFunction",
     "ParserCompileLazy",
     "ParserCompileScript",
     "TraceLogger",
     "YarrCompile",
     "YarrInterpret",
     "YarrJIT",
+    "VM",
     "SplitCriticalEdges",
     "RenumberBlocks",
     "DominatorTree",
     "PhiAnalysis",
     "ApplyTypes",
     "ParallelSafetyAnalysis",
     "AliasAnalysis",
     "GVN",
@@ -104,16 +105,17 @@ const char* const text[] = {
     "EffectiveAddressAnalysis",
     "EliminateDeadCode",
     "EdgeCaseAnalysis",
     "EliminateRedundantChecks"
 };
 
 TraceLogger::TraceLogger()
  : enabled(false),
+   enabledTimes(0),
    failed(false),
    nextTextId(0),
    treeOffset(0),
    top(nullptr)
 { }
 
 bool
 TraceLogger::init(uint32_t loggerId)
@@ -122,17 +124,17 @@ TraceLogger::init(uint32_t loggerId)
         return false;
     if (!tree.init())
         return false;
     if (!stack.init())
         return false;
     if (!events.init())
         return false;
 
-    JS_ASSERT(loggerId <= 999);
+    MOZ_ASSERT(loggerId <= 999);
 
     char dictFilename[sizeof TRACE_LOG_DIR "tl-dict.100.json"];
     sprintf(dictFilename, TRACE_LOG_DIR "tl-dict.%d.json", loggerId);
     dictFile = fopen(dictFilename, "w");
     if (!dictFile)
         return false;
 
     char treeFilename[sizeof TRACE_LOG_DIR "tl-tree.100.tl"];
@@ -153,45 +155,155 @@ TraceLogger::init(uint32_t loggerId)
         dictFile = nullptr;
         treeFile = nullptr;
         return false;
     }
 
     uint64_t start = rdtsc() - traceLoggers.startupTime;
 
     TreeEntry &treeEntry = tree.pushUninitialized();
-    treeEntry.start = start;
-    treeEntry.stop = 0;
-    treeEntry.u.s.textId = 0;
-    treeEntry.u.s.hasChildren = false;
-    treeEntry.nextId = 0;
+    treeEntry.setStart(start);
+    treeEntry.setStop(0);
+    treeEntry.setTextId(0);
+    treeEntry.setHasChildren(false);
+    treeEntry.setNextId(0);
 
     StackEntry &stackEntry = stack.pushUninitialized();
-    stackEntry.treeId = 0;
-    stackEntry.lastChildId = 0;
-    stackEntry.active = true;
+    stackEntry.setTreeId(0);
+    stackEntry.setLastChildId(0);
+    stackEntry.setActive(true);
 
     int written = fprintf(dictFile, "[");
     if (written < 0)
         fprintf(stderr, "TraceLogging: Error while writing.\n");
 
     // Eagerly create the default textIds, to match their Tracelogger::TextId.
     for (uint32_t i = 0; i < LAST; i++) {
         mozilla::DebugOnly<uint32_t> textId = createTextId(text[i]);
-        JS_ASSERT(textId == i);
+        MOZ_ASSERT(textId == i);
     }
 
     enabled = true;
+    enabledTimes = 1;
+    return true;
+}
+
+bool
+TraceLogger::enable()
+{
+    if (enabled) {
+        enabledTimes++;
+        return true;
+    }
+
+    if (failed)
+        return false;
+
+    if (!tree.ensureSpaceBeforeAdd(stack.size())) {
+        if (!flush()) {
+            fprintf(stderr, "TraceLogging: Couldn't write the data to disk.\n");
+            failed = true;
+            return false;
+        }
+        if (!tree.ensureSpaceBeforeAdd(stack.size())) {
+            fprintf(stderr, "TraceLogging: Couldn't reserve enough space.\n");
+            failed = true;
+            return false;
+        }
+    }
+
+    uint64_t start = rdtsc() - traceLoggers.startupTime;
+    StackEntry *parent = &stack[0];
+    for (uint32_t i = 1; i < stack.size(); i++) {
+        if (!traceLoggers.isTextIdEnabled(stack[i].textId()))
+            continue;
+#ifdef DEBUG
+        TreeEntry entry;
+        if (!getTreeEntry(parent->treeId(), &entry))
+            return false;
+#endif
+
+        if (parent->lastChildId() == 0) {
+            MOZ_ASSERT(!entry.hasChildren());
+            MOZ_ASSERT(parent->treeId() == tree.currentId() + treeOffset);
+            if (!updateHasChildren(parent->treeId())) {
+                fprintf(stderr, "TraceLogging: Couldn't update an entry.\n");
+                failed = true;
+                return false;
+            }
+        } else {
+            MOZ_ASSERT(entry.hasChildren() == 1);
+            if (!updateNextId(parent->lastChildId(), tree.nextId() + treeOffset)) {
+                fprintf(stderr, "TraceLogging: Couldn't update an entry.\n");
+                failed = true;
+                return false;
+            }
+        }
+
+        TreeEntry &treeEntry = tree.pushUninitialized();
+        treeEntry.setStart(start);
+        treeEntry.setStop(0);
+        treeEntry.setTextId(stack[i].textId());
+        treeEntry.setHasChildren(false);
+        treeEntry.setNextId(0);
+
+        stack[i].setActive(true);
+        stack[i].setTreeId(tree.currentId() + treeOffset);
+
+        parent->setLastChildId(tree.currentId() + treeOffset);
+
+        parent = &stack[i];
+    }
+
+    enabled = true;
+    enabledTimes = 1;
+
+    return true;
+}
+
+bool
+TraceLogger::disable()
+{
+    if (failed)
+        return false;
+
+    if (!enabled)
+        return true;
+
+    if (enabledTimes > 1) {
+        enabledTimes--;
+        return true;
+    }
+
+    uint64_t stop = rdtsc() - traceLoggers.startupTime;
+    for (uint32_t i = 1; i < stack.size(); i++) {
+        if (!stack[i].active())
+            continue;
+
+        if (!updateStop(stack[i].treeId(), stop)) {
+            fprintf(stderr, "TraceLogging: Failed to stop an event.\n");
+            failed = true;
+            enabled = false;
+            return false;
+        }
+
+        stack[i].setActive(false);
+    }
+
+
+    enabled = false;
+    enabledTimes = 0;
+
     return true;
 }
 
 bool
 TraceLogger::flush()
 {
-    JS_ASSERT(!failed);
+    MOZ_ASSERT(!failed);
 
     if (treeFile) {
         // Format data in big endian.
         for (size_t i = 0; i < tree.size(); i++)
             entryToBigEndian(&tree[i]);
 
         int success = fseek(treeFile, 0, SEEK_END);
         if (success != 0)
@@ -358,33 +470,33 @@ TraceLogger::logTimestamp(uint32_t id)
     EventEntry &entry = events.pushUninitialized();
     entry.time = time;
     entry.textId = id;
 }
 
 void
 TraceLogger::entryToBigEndian(TreeEntry *entry)
 {
-    entry->start = htobe64(entry->start);
-    entry->stop = htobe64(entry->stop);
-    entry->u.value = htobe32((entry->u.s.textId << 1) + entry->u.s.hasChildren);
-    entry->nextId = htobe32(entry->nextId);
+    entry->start_ = htobe64(entry->start_);
+    entry->stop_ = htobe64(entry->stop_);
+    entry->u.value_ = htobe32((entry->u.s.textId_ << 1) + entry->u.s.hasChildren_);
+    entry->nextId_ = htobe32(entry->nextId_);
 }
 
 void
 TraceLogger::entryToSystemEndian(TreeEntry *entry)
 {
-    entry->start = be64toh(entry->start);
-    entry->stop = be64toh(entry->stop);
+    entry->start_ = be64toh(entry->start_);
+    entry->stop_ = be64toh(entry->stop_);
 
-    uint32_t data = be32toh(entry->u.value);
-    entry->u.s.textId = data >> 1;
-    entry->u.s.hasChildren = data & 0x1;
+    uint32_t data = be32toh(entry->u.value_);
+    entry->u.s.textId_ = data >> 1;
+    entry->u.s.hasChildren_ = data & 0x1;
 
-    entry->nextId = be32toh(entry->nextId);
+    entry->nextId_ = be32toh(entry->nextId_);
 }
 
 bool
 TraceLogger::getTreeEntry(uint32_t treeId, TreeEntry *entry)
 {
     // Entry is still in memory
     if (treeId >= treeOffset) {
         *entry = tree[treeId];
@@ -421,73 +533,82 @@ TraceLogger::saveTreeEntry(uint32_t tree
 
 bool
 TraceLogger::updateHasChildren(uint32_t treeId, bool hasChildren)
 {
     if (treeId < treeOffset) {
         TreeEntry entry;
         if (!getTreeEntry(treeId, &entry))
             return false;
-        entry.u.s.hasChildren = hasChildren;
+        entry.setHasChildren(hasChildren);
         if (!saveTreeEntry(treeId, &entry))
             return false;
         return true;
     }
 
-    tree[treeId - treeOffset].u.s.hasChildren = hasChildren;
+    tree[treeId - treeOffset].setHasChildren(hasChildren);
     return true;
 }
 
 bool
 TraceLogger::updateNextId(uint32_t treeId, uint32_t nextId)
 {
     if (treeId < treeOffset) {
         TreeEntry entry;
         if (!getTreeEntry(treeId, &entry))
             return false;
-        entry.nextId = nextId;
+        entry.setNextId(nextId);
         if (!saveTreeEntry(treeId, &entry))
             return false;
         return true;
     }
 
-    tree[treeId - treeOffset].nextId = nextId;
+    tree[treeId - treeOffset].setNextId(nextId);
     return true;
 }
 
 bool
 TraceLogger::updateStop(uint32_t treeId, uint64_t timestamp)
 {
     if (treeId < treeOffset) {
         TreeEntry entry;
         if (!getTreeEntry(treeId, &entry))
             return false;
-        entry.stop = timestamp;
+        entry.setStop(timestamp);
         if (!saveTreeEntry(treeId, &entry))
             return false;
         return true;
     }
 
-    tree[treeId - treeOffset].stop = timestamp;
+    tree[treeId - treeOffset].setStop(timestamp);
     return true;
 }
 
 void
 TraceLogger::startEvent(uint32_t id)
 {
-    if (!enabled)
+    if (failed)
         return;
 
     if (!stack.ensureSpaceBeforeAdd()) {
         fprintf(stderr, "TraceLogging: Failed to allocate space to keep track of the stack.\n");
         enabled = false;
         failed = true;
         return;
     }
 
+    if (!enabled) {
+        StackEntry &stackEntry = stack.pushUninitialized();
+        stackEntry.setTreeId(tree.currentId() + treeOffset);
+        stackEntry.setLastChildId(0);
+        stackEntry.setTextId(id);
+        stackEntry.setActive(false);
+        return;
+    }
+
     if (!tree.ensureSpaceBeforeAdd()) {
         uint64_t start = rdtsc() - traceLoggers.startupTime;
         if (!flush()) {
             fprintf(stderr, "TraceLogging: Couldn't write the data to disk.\n");
             enabled = false;
             failed = true;
             return;
         }
@@ -511,110 +632,109 @@ TraceLogger::startEvent(uint32_t id)
         return;
     }
 }
 
 TraceLogger::StackEntry &
 TraceLogger::getActiveAncestor()
 {
     uint32_t parentId = stack.currentId();
-    while (!stack[parentId].active)
+    while (!stack[parentId].active())
         parentId--;
     return stack[parentId];
 }
 
 bool
 TraceLogger::startEvent(uint32_t id, uint64_t timestamp)
 {
     // When a textId is disabled, a stack entry still needs to be pushed,
     // together with an annotation that nothing needs to get done when receiving
     // the stop event.
     if (!traceLoggers.isTextIdEnabled(id)) {
         StackEntry &stackEntry = stack.pushUninitialized();
-        stackEntry.active = false;
+        stackEntry.setActive(false);
         return true;
     }
 
     // Patch up the tree to be correct. There are two scenarios:
     // 1) Parent has no children yet. So update parent to include children.
     // 2) Parent has already children. Update last child to link to the new
     //    child.
     StackEntry &parent = getActiveAncestor();
 #ifdef DEBUG
     TreeEntry entry;
-    if (!getTreeEntry(parent.treeId, &entry))
+    if (!getTreeEntry(parent.treeId(), &entry))
         return false;
 #endif
 
-    if (parent.lastChildId == 0) {
-        JS_ASSERT(entry.u.s.hasChildren == 0);
-        JS_ASSERT(parent.treeId == tree.currentId() + treeOffset);
+    if (parent.lastChildId() == 0) {
+        MOZ_ASSERT(!entry.hasChildren());
+        MOZ_ASSERT(parent.treeId() == tree.currentId() + treeOffset);
 
-        if (!updateHasChildren(parent.treeId))
+        if (!updateHasChildren(parent.treeId()))
             return false;
     } else {
-        JS_ASSERT(entry.u.s.hasChildren == 1);
+        MOZ_ASSERT(entry.hasChildren());
 
-        if (!updateNextId(parent.lastChildId, tree.nextId() + treeOffset))
+        if (!updateNextId(parent.lastChildId(), tree.nextId() + treeOffset))
             return false;
     }
 
     // Add a new tree entry.
     TreeEntry &treeEntry = tree.pushUninitialized();
-    treeEntry.start = timestamp;
-    treeEntry.stop = 0;
-    treeEntry.u.s.textId = id;
-    treeEntry.u.s.hasChildren = false;
-    treeEntry.nextId = 0;
+    treeEntry.setStart(timestamp);
+    treeEntry.setStop(0);
+    treeEntry.setTextId(id);
+    treeEntry.setHasChildren(false);
+    treeEntry.setNextId(0);
 
     // Add a new stack entry.
     StackEntry &stackEntry = stack.pushUninitialized();
-    stackEntry.treeId = tree.currentId() + treeOffset;
-    stackEntry.lastChildId = 0;
-    stackEntry.active = true;
+    stackEntry.setTreeId(tree.currentId() + treeOffset);
+    stackEntry.setLastChildId(0);
+    stackEntry.setActive(true);
 
     // Set the last child of the parent to this newly added entry.
-    parent.lastChildId = tree.currentId() + treeOffset;
+    parent.setLastChildId(tree.currentId() + treeOffset);
 
     return true;
 }
 
 void
 TraceLogger::stopEvent(uint32_t id)
 {
 #ifdef DEBUG
     TreeEntry entry;
-    JS_ASSERT(getTreeEntry(stack.current().treeId, &entry));
-    JS_ASSERT(entry.u.s.textId == id);
+    MOZ_ASSERT_IF(stack.current().active(), getTreeEntry(stack.current().treeId(), &entry));
+    MOZ_ASSERT_IF(stack.current().active(), entry.textId() == id);
 #endif
     stopEvent();
 }
 
 void
 TraceLogger::stopEvent()
 {
-    if (!enabled)
-        return;
-
-    if (stack.current().active) {
+    if (enabled && stack.current().active()) {
         uint64_t stop = rdtsc() - traceLoggers.startupTime;
-        if (!updateStop(stack.current().treeId, stop)) {
+        if (!updateStop(stack.current().treeId(), stop)) {
             fprintf(stderr, "TraceLogging: Failed to stop an event.\n");
             enabled = false;
             failed = true;
             return;
         }
     }
     stack.pop();
 }
 
 TraceLogging::TraceLogging()
 {
     initialized = false;
     enabled = false;
+    mainThreadEnabled = true;
+    offThreadEnabled = true;
     loggerId = 0;
 
 #ifdef JS_THREADSAFE
     lock = PR_NewLock();
     if (!lock)
         MOZ_CRASH();
 #endif // JS_THREADSAFE
 }
@@ -677,17 +797,17 @@ TraceLogging::lazyInit()
 
 #ifdef JS_THREADSAFE
     if (!threadLoggers.init())
         return false;
 #endif // JS_THREADSAFE
 
     const char *env = getenv("TLLOG");
     if (!env)
-        return false;
+        env = "";
 
     if (strstr(env, "help")) {
         fflush(nullptr);
         printf(
             "\n"
             "usage: TLLOG=option,option,option,... where options can be:\n"
             "\n"
             "Collections:\n"
@@ -744,16 +864,38 @@ TraceLogging::lazyInit()
         enabledTextIds[TraceLogger::LICM] = true;
         enabledTextIds[TraceLogger::RangeAnalysis] = true;
         enabledTextIds[TraceLogger::EffectiveAddressAnalysis] = true;
         enabledTextIds[TraceLogger::EliminateDeadCode] = true;
         enabledTextIds[TraceLogger::EdgeCaseAnalysis] = true;
         enabledTextIds[TraceLogger::EliminateRedundantChecks] = true;
     }
 
+    const char *options = getenv("TLOPTIONS");
+    if (options) {
+        if (strstr(options, "help")) {
+            fflush(nullptr);
+            printf(
+                "\n"
+                "usage: TLOPTIONS=option,option,option,... where options can be:\n"
+                "\n"
+                "  DisableMainThread        Don't start logging the mainThread automatically.\n"
+                "  DisableOffThread         Don't start logging the off mainThread automatically.\n"
+            );
+            printf("\n");
+            exit(0);
+            /*NOTREACHED*/
+        }
+
+        if (strstr(options, "DisableMainThread"))
+           mainThreadEnabled = false;
+        if (strstr(options, "DisableOffThread"))
+           offThreadEnabled = false;
+    }
+
     startupTime = rdtsc();
     enabled = true;
     return true;
 }
 
 TraceLogger *
 js::TraceLoggerForMainThread(jit::CompileRuntime *runtime)
 {
@@ -787,16 +929,19 @@ TraceLogging::forMainThread(PerThreadDat
         if (!lazyInit())
             return nullptr;
 
         TraceLogger *logger = create();
         mainThread->traceLogger = logger;
 
         if (!mainThreadLoggers.append(logger))
             return nullptr;
+
+        if (!mainThreadEnabled)
+            logger->disable();
     }
 
     return mainThread->traceLogger;
 }
 
 TraceLogger *
 js::TraceLoggerForCurrentThread()
 {
@@ -825,16 +970,19 @@ TraceLogging::forThread(PRThread *thread
     if (!logger)
         return nullptr;
 
     if (!threadLoggers.add(p, thread, logger)) {
         delete logger;
         return nullptr;
     }
 
+    if (!offThreadEnabled)
+        logger->disable();
+
     return logger;
 }
 #endif // JS_THREADSAFE
 
 TraceLogger *
 TraceLogging::create()
 {
     if (loggerId > 999) {
@@ -862,8 +1010,14 @@ TraceLogging::create()
 
     if (!logger->init(loggerId)) {
         delete logger;
         return nullptr;
     }
 
     return logger;
 }
+
+bool
+js::TraceLogTextIdEnabled(uint32_t textId)
+{
+    return traceLoggers.isTextIdEnabled(textId);
+}
--- a/js/src/vm/TraceLogging.h
+++ b/js/src/vm/TraceLogging.h
@@ -147,29 +147,31 @@ class ContinuousSpace {
         return next_;
     }
 
     T &next() {
         return data()[next_];
     }
 
     uint32_t currentId() {
-        JS_ASSERT(next_ > 0);
+        MOZ_ASSERT(next_ > 0);
         return next_ - 1;
     }
 
     T &current() {
         return data()[currentId()];
     }
 
-    bool ensureSpaceBeforeAdd() {
-        if (next_ < capacity_)
+    bool ensureSpaceBeforeAdd(uint32_t count = 1) {
+        if (next_ + count <= capacity_)
             return true;
 
         uint32_t nCapacity = capacity_ * 2;
+        if (next_ + count > nCapacity)
+            nCapacity = next_ + count;
         T *entries = (T *) js_realloc(data_, nCapacity * sizeof(T));
 
         if (!entries)
             return false;
 
         data_ = entries;
         capacity_ = nCapacity;
 
@@ -182,21 +184,22 @@ class ContinuousSpace {
     }
 
     void push(T &data) {
         MOZ_ASSERT(next_ < capacity_);
         data()[next_++] = data;
     }
 
     T &pushUninitialized() {
+        MOZ_ASSERT(next_ < capacity_);
         return data()[next_++];
     }
 
     void pop() {
-        JS_ASSERT(next_ > 0);
+        MOZ_ASSERT(next_ > 0);
         next_--;
     }
 
     void clear() {
         next_ = 0;
     }
 };
 
@@ -222,16 +225,17 @@ class TraceLogger
       MinorGC,
       ParserCompileFunction,
       ParserCompileLazy,
       ParserCompileScript,
       TL,
       YarrCompile,
       YarrInterpret,
       YarrJIT,
+      VM,
 
       // Specific passes during ion compilation:
       SplitCriticalEdges,
       RenumberBlocks,
       DominatorTree,
       PhiAnalysis,
       ApplyTypes,
       ParallelSafetyAnalysis,
@@ -253,50 +257,112 @@ class TraceLogger
     typedef HashMap<const void *,
                     uint32_t,
                     PointerHasher<const void *, 3>,
                     SystemAllocPolicy> PointerHashMap;
 
     // The layout of the tree in memory and in the log file. Readable by JS
     // using TypedArrays.
     struct TreeEntry {
-        uint64_t start;
-        uint64_t stop;
+        uint64_t start_;
+        uint64_t stop_;
         union {
             struct {
-                uint32_t textId: 31;
-                uint32_t hasChildren: 1;
+                uint32_t textId_: 31;
+                uint32_t hasChildren_: 1;
             } s;
-            uint32_t value;
+            uint32_t value_;
         } u;
-        uint32_t nextId;
+        uint32_t nextId_;
 
         TreeEntry(uint64_t start, uint64_t stop, uint32_t textId, bool hasChildren,
                   uint32_t nextId)
         {
-            this->start = start;
-            this->stop = stop;
-            this->u.s.textId = textId;
-            this->u.s.hasChildren = hasChildren;
-            this->nextId = nextId;
+            start_ = start;
+            stop_ = stop;
+            u.s.textId_ = textId;
+            u.s.hasChildren_ = hasChildren;
+            nextId_ = nextId;
         }
         TreeEntry()
         { }
+        uint64_t start() {
+            return start_;
+        }
+        uint64_t stop() {
+            return stop_;
+        }
+        uint32_t textId() {
+            return u.s.textId_;
+        }
+        bool hasChildren() {
+            return u.s.hasChildren_;
+        }
+        uint32_t nextId() {
+            return nextId_;
+        }
+        void setStart(uint64_t start) {
+            start_ = start;
+        }
+        void setStop(uint64_t stop) {
+            stop_ = stop;
+        }
+        void setTextId(uint32_t textId) {
+            MOZ_ASSERT(textId < uint32_t(1<<31) );
+            u.s.textId_ = textId;
+        }
+        void setHasChildren(bool hasChildren) {
+            u.s.hasChildren_ = hasChildren;
+        }
+        void setNextId(uint32_t nextId) {
+            nextId_ = nextId;
+        }
     };
 
     // Helper structure for keeping track of the current entries in
     // the tree. Pushed by `start(id)`, popped by `stop(id)`. The active flag
     // is used to know if a subtree doesn't need to get logged.
     struct StackEntry {
-        uint32_t treeId;
-        uint32_t lastChildId;
-        bool active;
+        uint32_t treeId_;
+        uint32_t lastChildId_;
+        struct {
+            uint32_t textId_: 31;
+            uint32_t active_: 1;
+        } s;
         StackEntry(uint32_t treeId, uint32_t lastChildId, bool active = true)
-          : treeId(treeId), lastChildId(lastChildId), active(active)
-        { }
+          : treeId_(treeId), lastChildId_(lastChildId)
+        {
+            s.textId_ = 0;
+            s.active_ = active;
+        }
+        uint32_t treeId() {
+            return treeId_;
+        }
+        uint32_t lastChildId() {
+            return lastChildId_;
+        }
+        uint32_t textId() {
+            return s.textId_;
+        }
+        bool active() {
+            return s.active_;
+        }
+        void setTreeId(uint32_t treeId) {
+            treeId_ = treeId;
+        }
+        void setLastChildId(uint32_t lastChildId) {
+            lastChildId_ = lastChildId;
+        }
+        void setTextId(uint32_t textId) {
+            MOZ_ASSERT(textId < uint32_t(1<<31) );
+            s.textId_ = textId;
+        }
+        void setActive(bool active) {
+            s.active_ = active;
+        }
     };
 
     // The layout of the event log in memory and in the log file.
     // Readable by JS using TypedArrays.
     struct EventEntry {
         uint64_t time;
         uint32_t textId;
         EventEntry(uint64_t time, uint32_t textId)
@@ -304,16 +370,17 @@ class TraceLogger
         { }
     };
 
     FILE *dictFile;
     FILE *treeFile;
     FILE *eventFile;
 
     bool enabled;
+    uint32_t enabledTimes;
     bool failed;
     uint32_t nextTextId;
 
     PointerHashMap pointerMap;
 
     ContinuousSpace<TreeEntry> tree;
     ContinuousSpace<StackEntry> stack;
     ContinuousSpace<EventEntry> events;
@@ -350,16 +417,19 @@ class TraceLogger
     bool flush();
 
   public:
     TraceLogger();
     ~TraceLogger();
 
     bool init(uint32_t loggerId);
 
+    bool enable();
+    bool disable();
+
     // The createTextId functions map a unique input to a logger ID.
     // This ID can be used to log something. Calls to these functions should be
     // limited if possible, because of the overhead.
     uint32_t createTextId(const char *text);
     uint32_t createTextId(JSScript *script);
     uint32_t createTextId(const JS::ReadOnlyCompileOptions &script);
 
     // Log an event (no start/stop, only the timestamp is recorded).
@@ -391,16 +461,18 @@ class TraceLogging
                     PointerHasher<PRThread *, 3>,
                     SystemAllocPolicy> ThreadLoggerHashMap;
 #endif // JS_THREADSAFE
     typedef Vector<TraceLogger *, 1, js::SystemAllocPolicy > MainThreadLoggers;
 
     bool initialized;
     bool enabled;
     bool enabledTextIds[TraceLogger::LAST];
+    bool mainThreadEnabled;
+    bool offThreadEnabled;
 #ifdef JS_THREADSAFE
     ThreadLoggerHashMap threadLoggers;
 #endif // JS_THREADSAFE
     MainThreadLoggers mainThreadLoggers;
     uint32_t loggerId;
     FILE *out;
 
   public:
@@ -442,16 +514,31 @@ inline TraceLogger *TraceLoggerForMainTh
 inline TraceLogger *TraceLoggerForMainThread(jit::CompileRuntime *runtime) {
     return nullptr;
 };
 inline TraceLogger *TraceLoggerForCurrentThread() {
     return nullptr;
 };
 #endif
 
+inline bool TraceLoggerEnable(TraceLogger *logger) {
+#ifdef JS_TRACE_LOGGING
+    if (logger)
+        return logger->enable();
+#endif
+    return false;
+}
+inline bool TraceLoggerDisable(TraceLogger *logger) {
+#ifdef JS_TRACE_LOGGING
+    if (logger)
+        return logger->disable();
+#endif
+    return false;
+}
+
 inline uint32_t TraceLogCreateTextId(TraceLogger *logger, JSScript *script) {
 #ifdef JS_TRACE_LOGGING
     if (logger)
         return logger->createTextId(script);
 #endif
     return TraceLogger::TL_Error;
 }
 inline uint32_t TraceLogCreateTextId(TraceLogger *logger,
@@ -465,16 +552,23 @@ inline uint32_t TraceLogCreateTextId(Tra
 }
 inline uint32_t TraceLogCreateTextId(TraceLogger *logger, const char *text) {
 #ifdef JS_TRACE_LOGGING
     if (logger)
         return logger->createTextId(text);
 #endif
     return TraceLogger::TL_Error;
 }
+#ifdef JS_TRACE_LOGGING
+bool TraceLogTextIdEnabled(uint32_t textId);
+#else
+inline bool TraceLogTextIdEnabled(uint32_t textId) {
+    return false;
+}
+#endif
 inline void TraceLogTimestamp(TraceLogger *logger, uint32_t textId) {
 #ifdef JS_TRACE_LOGGING
     if (logger)
         logger->logTimestamp(textId);
 #endif
 }
 inline void TraceLogStartEvent(TraceLogger *logger, uint32_t textId) {
 #ifdef JS_TRACE_LOGGING
--- a/js/src/vm/make_opcode_doc.py
+++ b/js/src/vm/make_opcode_doc.py
@@ -280,17 +280,17 @@ def override(value, override_value):
 
 def format_flags(flags):
     if flags == '':
         return ''
 
     return ' ({flags})'.format(flags=flags)
 
 def print_opcode(opcode):
-    names_template = '{name} [-{nuses}, +{ndefs}] ({flags})'
+    names_template = '{name} [-{nuses}, +{ndefs}]{flags}'
     names = map(lambda code: names_template.format(name=escape(code.name),
                                                    nuses=override(code.nuses,
                                                                   opcode.nuses_override),
                                                    ndefs=override(code.ndefs,
                                                                   opcode.ndefs_override),
                                                    flags=format_flags(code.flags)),
                 sorted([opcode] + opcode.group,
                        key=lambda opcode: opcode.name))
--- a/js/xpconnect/src/XPCVariant.cpp
+++ b/js/xpconnect/src/XPCVariant.cpp
@@ -64,17 +64,17 @@ XPCTraceableVariant::~XPCTraceableVarian
         nsVariant::Cleanup(&mData);
 
     if (!JSVAL_IS_NULL(val))
         RemoveFromRootSet();
 }
 
 void XPCTraceableVariant::TraceJS(JSTracer* trc)
 {
-    MOZ_ASSERT(JSVAL_IS_TRACEABLE(mJSVal));
+    MOZ_ASSERT(mJSVal.isMarkable());
     JS_SET_TRACING_DETAILS(trc, GetTraceName, this, 0);
     JS_CallHeapValueTracer(trc, &mJSVal, "XPCTraceableVariant::mJSVal");
 }
 
 // static
 void
 XPCTraceableVariant::GetTraceName(JSTracer* trc, char *buf, size_t bufsize)
 {
@@ -110,17 +110,17 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(XP
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 // static
 already_AddRefed<XPCVariant>
 XPCVariant::newVariant(JSContext* cx, jsval aJSVal)
 {
     nsRefPtr<XPCVariant> variant;
 
-    if (!JSVAL_IS_TRACEABLE(aJSVal))
+    if (!aJSVal.isMarkable())
         variant = new XPCVariant(cx, aJSVal);
     else
         variant = new XPCTraceableVariant(cx, aJSVal);
 
     if (!variant->InitializeData(cx))
         return nullptr;
 
     return variant.forget();
--- a/layout/base/nsDisplayListInvalidation.cpp
+++ b/layout/base/nsDisplayListInvalidation.cpp
@@ -1,15 +1,16 @@
 /*-*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsDisplayListInvalidation.h"
 #include "nsDisplayList.h"
+#include "nsIFrame.h"
 
 nsDisplayItemGeometry::nsDisplayItemGeometry(nsDisplayItem* aItem, nsDisplayListBuilder* aBuilder)
 {
   MOZ_COUNT_CTOR(nsDisplayItemGeometry);
   bool snap;
   mBounds = aItem->GetBounds(aBuilder, &snap);
 }
 
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -5382,18 +5382,20 @@ nsLayoutUtils::SurfaceFromElement(nsIIma
   uint32_t noRasterize = aSurfaceFlags & SFE_NO_RASTERIZING_VECTORS;
 
   uint32_t whichFrame = (aSurfaceFlags & SFE_WANT_FIRST_FRAME)
                         ? (uint32_t) imgIContainer::FRAME_FIRST
                         : (uint32_t) imgIContainer::FRAME_CURRENT;
   uint32_t frameFlags = imgIContainer::FLAG_SYNC_DECODE;
   if (aSurfaceFlags & SFE_NO_COLORSPACE_CONVERSION)
     frameFlags |= imgIContainer::FLAG_DECODE_NO_COLORSPACE_CONVERSION;
-  if (aSurfaceFlags & SFE_NO_PREMULTIPLY_ALPHA)
+  if (aSurfaceFlags & SFE_PREFER_NO_PREMULTIPLY_ALPHA) {
     frameFlags |= imgIContainer::FLAG_DECODE_NO_PREMULTIPLY_ALPHA;
+    result.mIsPremultiplied = false;
+  }
 
   int32_t imgWidth, imgHeight;
   rv = imgContainer->GetWidth(&imgWidth);
   nsresult rv2 = imgContainer->GetHeight(&imgHeight);
   if (NS_FAILED(rv) || NS_FAILED(rv2))
     return result;
 
   if (!noRasterize || imgContainer->GetType() == imgIContainer::TYPE_RASTER) {
@@ -5445,62 +5447,38 @@ nsLayoutUtils::SurfaceFromElement(HTMLIm
 }
 
 nsLayoutUtils::SurfaceFromElementResult
 nsLayoutUtils::SurfaceFromElement(HTMLCanvasElement* aElement,
                                   uint32_t aSurfaceFlags,
                                   DrawTarget* aTarget)
 {
   SurfaceFromElementResult result;
-  nsresult rv;
-
-  bool premultAlpha = (aSurfaceFlags & SFE_NO_PREMULTIPLY_ALPHA) == 0;
+
+  bool* isPremultiplied = nullptr;
+  if (aSurfaceFlags & SFE_PREFER_NO_PREMULTIPLY_ALPHA) {
+    isPremultiplied = &result.mIsPremultiplied;
+  }
 
   gfxIntSize size = aElement->GetSize();
 
-  if (premultAlpha && aElement->CountContexts() == 1) {
-    nsICanvasRenderingContextInternal *srcCanvas = aElement->GetContextAtIndex(0);
-    result.mSourceSurface = srcCanvas->GetSurfaceSnapshot();
-  }
-
+  result.mSourceSurface = aElement->GetSurfaceSnapshot(isPremultiplied);
   if (!result.mSourceSurface) {
-    nsRefPtr<gfxContext> ctx;
-    RefPtr<DrawTarget> dt;
-    if (premultAlpha) {
-      if (aTarget) {
-        dt = aTarget->CreateSimilarDrawTarget(IntSize(size.width, size.height), SurfaceFormat::B8G8R8A8);
-      } else {
-        dt = gfxPlatform::GetPlatform()->CreateOffscreenContentDrawTarget(IntSize(size.width, size.height),
-                                                                          SurfaceFormat::B8G8R8A8);
-      }
-      if (!dt) {
-        return result;
-      }
-      ctx = new gfxContext(dt);
-    } else {
-      // TODO: RenderContextsExternal expects to get a gfxImageFormat
-      // so that it can un-premultiply.
-      RefPtr<DataSourceSurface> data = Factory::CreateDataSourceSurface(IntSize(size.width, size.height),
-                                                                        SurfaceFormat::B8G8R8A8);
-      memset(data->GetData(), 0, data->Stride() * size.height);
-      result.mSourceSurface = data;
-      nsRefPtr<gfxImageSurface> image = new gfxImageSurface(data->GetData(),
-                                                            gfxIntSize(size.width, size.height),
-                                                            data->Stride(),
-                                                            gfxImageFormat::ARGB32);
-      ctx = new gfxContext(image);
-    }
-    // XXX shouldn't use the external interface, but maybe we can layerify this
-    uint32_t flags = premultAlpha ? HTMLCanvasElement::RenderFlagPremultAlpha : 0;
-    rv = aElement->RenderContextsExternal(ctx, GraphicsFilter::FILTER_NEAREST, flags);
-    if (NS_FAILED(rv))
-      return result;
-
-    if (premultAlpha) {
-      result.mSourceSurface = dt->Snapshot();
+     // If the element doesn't have a context then we won't get a snapshot. The canvas spec wants us to not error and just
+     // draw nothing, so return an empty surface.
+     DrawTarget *ref = aTarget ? aTarget : gfxPlatform::GetPlatform()->ScreenReferenceDrawTarget();
+     RefPtr<DrawTarget> dt = ref->CreateSimilarDrawTarget(IntSize(size.width, size.height),
+                                                          SurfaceFormat::B8G8R8A8);
+     if (dt) {
+       result.mSourceSurface = dt->Snapshot();
+     }
+  } else if (aTarget) {
+    RefPtr<SourceSurface> opt = aTarget->OptimizeSourceSurface(result.mSourceSurface);
+    if (opt) {
+      result.mSourceSurface = opt;
     }
   }
 
   // Ensure that any future changes to the canvas trigger proper invalidation,
   // in case this is being used by -moz-element()
   aElement->MarkContextClean();
 
   result.mSize = size;
@@ -5512,17 +5490,17 @@ nsLayoutUtils::SurfaceFromElement(HTMLCa
 
 nsLayoutUtils::SurfaceFromElementResult
 nsLayoutUtils::SurfaceFromElement(HTMLVideoElement* aElement,
                                   uint32_t aSurfaceFlags,
                                   DrawTarget* aTarget)
 {
   SurfaceFromElementResult result;
 
-  NS_WARN_IF_FALSE((aSurfaceFlags & SFE_NO_PREMULTIPLY_ALPHA) == 0, "We can't support non-premultiplied alpha for video!");
+  NS_WARN_IF_FALSE((aSurfaceFlags & SFE_PREFER_NO_PREMULTIPLY_ALPHA) == 0, "We can't support non-premultiplied alpha for video!");
 
   uint16_t readyState;
   if (NS_SUCCEEDED(aElement->GetReadyState(&readyState)) &&
       (readyState == nsIDOMHTMLMediaElement::HAVE_NOTHING ||
        readyState == nsIDOMHTMLMediaElement::HAVE_METADATA)) {
     result.mIsStillLoading = true;
     return result;
   }
@@ -5536,16 +5514,23 @@ nsLayoutUtils::SurfaceFromElement(HTMLVi
   if (!container)
     return result;
 
   mozilla::gfx::IntSize size;
   result.mSourceSurface = container->GetCurrentAsSourceSurface(&size);
   if (!result.mSourceSurface)
     return result;
 
+  if (aTarget) {
+    RefPtr<SourceSurface> opt = aTarget->OptimizeSourceSurface(result.mSourceSurface);
+    if (opt) {
+      result.mSourceSurface = opt;
+    }
+  }
+
   result.mCORSUsed = aElement->GetCORSMode() != CORS_NONE;
   result.mSize = ThebesIntSize(size);
   result.mPrincipal = principal.forget();
   result.mIsWriteOnly = false;
 
   return result;
 }
 
@@ -6504,17 +6489,20 @@ nsLayoutUtils::WantSubAPZC()
      wantSubAPZC = false;
    }
 #endif
    return wantSubAPZC;
  }
 
 nsLayoutUtils::SurfaceFromElementResult::SurfaceFromElementResult()
   // Use safe default values here
-  : mIsWriteOnly(true), mIsStillLoading(false), mCORSUsed(false)
+  : mIsWriteOnly(true)
+  , mIsStillLoading(false)
+  , mCORSUsed(false)
+  , mIsPremultiplied(true)
 {
 }
 
 bool
 nsLayoutUtils::IsNonWrapperBlock(nsIFrame* aFrame)
 {
   return GetAsBlock(aFrame) && !aFrame->IsBlockWrapper();
 }
--- a/layout/base/nsLayoutUtils.h
+++ b/layout/base/nsLayoutUtils.h
@@ -1690,20 +1690,20 @@ public:
   enum {
     /* When creating a new surface, create an image surface */
     SFE_WANT_IMAGE_SURFACE = 1 << 0,
     /* Whether to extract the first frame (as opposed to the
        current frame) in the case that the element is an image. */
     SFE_WANT_FIRST_FRAME = 1 << 1,
     /* Whether we should skip colorspace/gamma conversion */
     SFE_NO_COLORSPACE_CONVERSION = 1 << 2,
-    /* Whether we should skip premultiplication -- the resulting
-       image will always be an image surface, and must not be given to
-       Thebes for compositing! */
-    SFE_NO_PREMULTIPLY_ALPHA = 1 << 3,
+    /* Specifies that the caller wants unpremultiplied pixel data.
+       If this is can be done efficiently, the result will be a
+       DataSourceSurface and mIsPremultiplied with be set to false. */
+    SFE_PREFER_NO_PREMULTIPLY_ALPHA = 1 << 3,
     /* Whether we should skip getting a surface for vector images and
        return a DirectDrawInfo containing an imgIContainer instead. */
     SFE_NO_RASTERIZING_VECTORS = 1 << 4
   };
 
   struct DirectDrawInfo {
     /* imgIContainer to directly draw to a context */
     nsCOMPtr<imgIContainer> mImgContainer;
@@ -1731,16 +1731,18 @@ public:
     nsCOMPtr<imgIRequest> mImageRequest;
     /* Whether the element was "write only", that is, the bits should not be exposed to content */
     bool mIsWriteOnly;
     /* Whether the element was still loading.  Some consumers need to handle
        this case specially. */
     bool mIsStillLoading;
     /* Whether the element used CORS when loading. */
     bool mCORSUsed;
+    /* Whether the returned image contains premultiplied pixel data */
+    bool mIsPremultiplied;
   };
 
   static SurfaceFromElementResult SurfaceFromElement(mozilla::dom::Element *aElement,
                                                      uint32_t aSurfaceFlags = 0,
                                                      DrawTarget *aTarget = nullptr);
   static SurfaceFromElementResult SurfaceFromElement(nsIImageLoadingContent *aElement,
                                                      uint32_t aSurfaceFlags = 0,
                                                      DrawTarget *aTarget = nullptr);
deleted file mode 100644
--- a/layout/generic/crashtests/455407.html
+++ /dev/null
@@ -1,13 +0,0 @@
-<html>
-<head>Crash [@ nsSubDocumentFrame::Reflow] with generated content and resizing iframe</title>
-</head>
-<body>
-<iframe id="content" src="data:text/html;charset=utf-8,%3Chtml%3E%3Chead%3E%3C/head%3E%3Cbody%3E%0A%3Cstyle%20id%3D%22e%22%3Ebody%3A%3Abefore%20%7B%20content%3A%22b%22%3B%20%7D%3C/style%3E%0A%3Cscript%3Ewindow.frameElement.style.width%3DMath.floor%28Math.random%28%29*100%29+%27%25%27%3B%0A%3C/script%3E%0A%3Ciframe%20src%3D%22http%3A//mozilla.org%22%3E%3C/iframe%3E%0A%3C/body%3E%3C/html%3E" onload="//doe()" style=" width:1000px;height: 200px;"></iframe>
-<script>
-function doe() {
-  document.getElementById('content').src = document.getElementById('content').src + '?1';
-}
-setInterval(doe, 1000);
-</script>
-</body>
-</html>
--- a/layout/generic/crashtests/crashtests.list
+++ b/layout/generic/crashtests/crashtests.list
@@ -295,17 +295,16 @@ load 451317-1.html
 load 451334-1.html
 load 452157-1.html
 load 452157-2.html
 load 452157-3.html
 load 453762-1.html
 load 455171-1.html
 load 455171-2.html
 load 455171-3.html
-load 455407.html
 load 455643-1.xhtml
 load 457375.html
 load 457380-1.html
 load 460910-1.xml
 load 461294-1.html
 load 463350-1.html
 load 463350-2.html
 load 463350-3.html
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -6685,18 +6685,18 @@ nsFrame::BreakWordBetweenPunctuation(con
   NS_ASSERTION(aPunctAfter != aState->mLastCharWasPunctuation,
                "Call this only at punctuation boundaries");
   if (aState->mLastCharWasWhitespace) {
     // We always stop between whitespace and punctuation
     return true;
   }
   if (!Preferences::GetBool("layout.word_select.stop_at_punctuation")) {
     // When this pref is false, we never stop at a punctuation boundary unless
-    // it's after whitespace
-    return false;
+    // it's followed by whitespace (in the relevant direction).
+    return aWhitespaceAfter;
   }
   if (!aIsKeyboardSelect) {
     // mouse caret movement (e.g. word selection) always stops at every punctuation boundary
     return true;
   }
   bool afterPunct = aForward ? aState->mLastCharWasPunctuation : aPunctAfter;
   if (!afterPunct) {
     // keyboard caret movement only stops after punctuation (in content order)
--- a/layout/generic/test/test_movement_by_words.html
+++ b/layout/generic/test/test_movement_by_words.html
@@ -9,41 +9,44 @@
 <body>
 <p id="display"></p>
 <div id="content" style="display: block">
 <div contentEditable id="editor"></div>
 </div>
 <p id="catch">Catch-all
 <pre id="test"><script class="testbody" type="text/javascript;version=1.7">
 
-/** Test for Bug 384147 **/
+/** Tests for bugs 384147 and 981281 **/
 
 SimpleTest.waitForExplicitFinish();
 
 SimpleTest.waitForFocus(function(){setTimeout(focusing, 0)});
 
 function focusing() {
   document.getElementById("editor").focus();
   // This seems to be necessary because the selection is not set up properly otherwise
   setTimeout(test, 0);
 }
 
 var eatSpace;
+var stopAtPunctuation;
 var wordModifiers =
     (navigator.platform.indexOf("Mac") >= 0) ? {altKey:true} : {ctrlKey:true};
 var sel = window.getSelection();
 var editor = document.getElementById("editor");
 
 function setPrefs(eat_space, stop_at_punctuation, callback) {
   eatSpace = eat_space;
+  stopAtPunctuation = stop_at_punctuation;
   SpecialPowers.pushPrefEnv({"set": [["layout.word_select.eat_space_to_next_word", eat_space], ["layout.word_select.stop_at_punctuation", stop_at_punctuation]]}, callback);
 }
 
 function errString(dir) {
-  return dir + " movement broken with eatSpace=" + eatSpace + " in \"" + editor.innerHTML +
+  return dir + " movement broken with eatSpace=" + eatSpace +
+    ", stopAtPunctuation=" + stopAtPunctuation + " in \"" + editor.innerHTML +
     "\"; sel.anchorNode.parentNode=" + sel.anchorNode.parentNode;
 }
 
 function testRight(node, offset) {
   synthesizeKey("VK_RIGHT", wordModifiers);
   is(sel.anchorNode, node, errString("Right"));
   is(sel.anchorOffset, offset, errString("Right"));
 }
@@ -277,15 +280,201 @@ function test2() {
   sel.collapse(editor.firstChild, 0);
   testRight(editor.firstChild, 3);
   testRight(editor.firstChild, 6);
   testRight(editor.firstChild, 8);
   testLeft(editor.firstChild, 6);
   testLeft(editor.firstChild, 3);
   testLeft(editor.firstChild, 0);
 
+  // Test basic word movement with stop_at_punctuation false (bug 981281).
+  setPrefs(false, false, test3);
+}
+
+function test3() {
+  editor.innerHTML = "Hello Kitty";
+  sel.collapse(editor.firstChild, 0);
+  testRight(editor.firstChild, 5);
+  testRight(editor.firstChild, 11);
+  testLeft(editor.firstChild, 6);
+  testLeft(editor.firstChild, 0);
+
+  editor.innerHTML = "<b>Hello</b> Kitty";
+  sel.collapse(editor.firstChild.firstChild, 0);
+  testRight(editor.firstChild.nextSibling, 0);
+  testRight(editor.firstChild.nextSibling, 6);
+  testLeft(editor.firstChild.nextSibling, 1);
+  testLeft(editor.firstChild.firstChild, 0);
+
+  editor.innerHTML = "<b>Hello </b>Kitty";
+  sel.collapse(editor.firstChild.firstChild, 0);
+  testRight(editor.firstChild.firstChild, 5);
+  testRight(editor.firstChild.nextSibling, 5);
+  testLeft(editor.firstChild.firstChild, 6);
+  testLeft(editor.firstChild.firstChild, 0);
+
+  editor.innerHTML = "<b>Log out</b>  roc";
+  sel.collapse(editor.firstChild.firstChild, 0);
+  testRight(editor.firstChild.firstChild, 3);
+  testRight(editor.firstChild.nextSibling, 0);
+  testRight(editor.firstChild.nextSibling, 5);
+  testLeft(editor.firstChild.nextSibling, 1);
+  testLeft(editor.firstChild.firstChild, 4);
+  testLeft(editor.firstChild.firstChild, 0);
+
+  editor.innerHTML = "http://www.mozilla.org";
+  sel.collapse(editor.firstChild, 0);
+  testRight(editor.firstChild, 22);
+  testLeft(editor.firstChild, 0);
+
+  editor.innerHTML = "Set .rc to <b>'</b>quiz'";
+  sel.collapse(editor.firstChild, 0);
+  testRight(editor.firstChild, 3);
+  testRight(editor.firstChild, 7);
+  testRight(editor.firstChild, 10);
+  testRight(editor.firstChild.nextSibling.nextSibling, 5);
+  testLeft(editor.firstChild, 11);
+  testLeft(editor.firstChild, 8);
+  testLeft(editor.firstChild, 4);
+  testLeft(editor.firstChild, 0);
+
+  editor.innerHTML = ChineseChars + HiraganaChars + ChineseChars;
+  sel.collapse(editor.firstChild, 0);
+  testRight(editor.firstChild, 2);
+  testRight(editor.firstChild, 6);
+  testRight(editor.firstChild, 8);
+  testLeft(editor.firstChild, 6);
+  testLeft(editor.firstChild, 2);
+  testLeft(editor.firstChild, 0);
+
+  editor.innerHTML = ChineseChars + KatakanaChars + ChineseChars;
+  sel.collapse(editor.firstChild, 0);
+  testRight(editor.firstChild, 2);
+  testRight(editor.firstChild, 6);
+  testRight(editor.firstChild, 8);
+  testLeft(editor.firstChild, 6);
+  testLeft(editor.firstChild, 2);
+  testLeft(editor.firstChild, 0);
+
+  editor.innerHTML = KatakanaChars + HiraganaChars + KatakanaChars;
+  sel.collapse(editor.firstChild, 0);
+  testRight(editor.firstChild, 4);
+  testRight(editor.firstChild, 8);
+  testRight(editor.firstChild, 12);
+  testLeft(editor.firstChild, 8);
+  testLeft(editor.firstChild, 4);
+  testLeft(editor.firstChild, 0);
+
+  editor.innerHTML = HiraganaChars + JapaneseComma + HiraganaChars + JapaneseFullStop + HiraganaChars;
+  sel.collapse(editor.firstChild, 0);
+  testRight(editor.firstChild, 14);
+  testLeft(editor.firstChild, 0);
+
+  editor.innerHTML = KatakanaChars + JapaneseComma + KatakanaChars + JapaneseFullStop + KatakanaChars;
+  sel.collapse(editor.firstChild, 0);
+  testRight(editor.firstChild, 14);
+  testLeft(editor.firstChild, 0);
+
+  editor.innerHTML = ChineseChars + JapaneseComma + ChineseChars + JapaneseFullStop + ChineseChars;
+  sel.collapse(editor.firstChild, 0);
+  testRight(editor.firstChild, 8);
+  testLeft(editor.firstChild, 0);
+
+  // And again with eat_space_next_to_word true.
+  setPrefs(true, false, test4);
+}
+
+function test4() {
+  editor.innerHTML = "Hello Kitty";
+  sel.collapse(editor.firstChild, 0);
+  testRight(editor.firstChild, 6);
+  testRight(editor.firstChild, 11);
+  testLeft(editor.firstChild, 6);
+  testLeft(editor.firstChild, 0);
+
+  editor.innerHTML = "<b>Hello</b> Kitty";
+  sel.collapse(editor.firstChild.firstChild, 0);
+  testRight(editor.firstChild.nextSibling, 1);
+  testRight(editor.firstChild.nextSibling, 6);
+  testLeft(editor.firstChild.nextSibling, 1);
+  testLeft(editor.firstChild.firstChild, 0);
+
+  editor.innerHTML = "<b>Hello </b>Kitty";
+  sel.collapse(editor.firstChild.firstChild, 0);
+  testRight(editor.firstChild.nextSibling, 0);
+  testRight(editor.firstChild.nextSibling, 5);
+  testLeft(editor.firstChild.firstChild, 6);
+  testLeft(editor.firstChild.firstChild, 0);
+
+  editor.innerHTML = "<b>Log out</b>  roc";
+  sel.collapse(editor.firstChild.firstChild, 0);
+  testRight(editor.firstChild.firstChild, 4);
+  testRight(editor.firstChild.nextSibling, 2);
+  testRight(editor.firstChild.nextSibling, 5);
+  testLeft(editor.firstChild.nextSibling, 1);
+  testLeft(editor.firstChild.firstChild, 4);
+  testLeft(editor.firstChild.firstChild, 0);
+
+  editor.innerHTML = "http://www.mozilla.org";
+  sel.collapse(editor.firstChild, 0);
+  testRight(editor.firstChild, 22);
+  testLeft(editor.firstChild, 0);
+
+  editor.innerHTML = "Set .rc to <b>'</b>quiz'";
+  sel.collapse(editor.firstChild, 0);
+  testRight(editor.firstChild, 4);
+  testRight(editor.firstChild, 8);
+  testRight(editor.firstChild.nextSibling.firstChild, 0);
+  testRight(editor.firstChild.nextSibling.nextSibling, 5);
+  testLeft(editor.firstChild, 11);
+  testLeft(editor.firstChild, 8);
+  testLeft(editor.firstChild, 4);
+  testLeft(editor.firstChild, 0);
+
+  editor.innerHTML = ChineseChars + HiraganaChars + ChineseChars;
+  sel.collapse(editor.firstChild, 0);
+  testRight(editor.firstChild, 2);
+  testRight(editor.firstChild, 6);
+  testRight(editor.firstChild, 8);
+  testLeft(editor.firstChild, 6);
+  testLeft(editor.firstChild, 2);
+  testLeft(editor.firstChild, 0);
+
+  editor.innerHTML = ChineseChars + KatakanaChars + ChineseChars;
+  sel.collapse(editor.firstChild, 0);
+  testRight(editor.firstChild, 2);
+  testRight(editor.firstChild, 6);
+  testRight(editor.firstChild, 8);
+  testLeft(editor.firstChild, 6);
+  testLeft(editor.firstChild, 2);
+  testLeft(editor.firstChild, 0);
+
+  editor.innerHTML = KatakanaChars + HiraganaChars + KatakanaChars;
+  sel.collapse(editor.firstChild, 0);
+  testRight(editor.firstChild, 4);
+  testRight(editor.firstChild, 8);
+  testRight(editor.firstChild, 12);
+  testLeft(editor.firstChild, 8);
+  testLeft(editor.firstChild, 4);
+  testLeft(editor.firstChild, 0);
+
+  editor.innerHTML = HiraganaChars + JapaneseComma + HiraganaChars + JapaneseFullStop + HiraganaChars;
+  sel.collapse(editor.firstChild, 0);
+  testRight(editor.firstChild, 14);
+  testLeft(editor.firstChild, 0);
+
+  editor.innerHTML = KatakanaChars + JapaneseComma + KatakanaChars + JapaneseFullStop + KatakanaChars;
+  sel.collapse(editor.firstChild, 0);
+  testRight(editor.firstChild, 14);
+  testLeft(editor.firstChild, 0);
+
+  editor.innerHTML = ChineseChars + JapaneseComma + ChineseChars + JapaneseFullStop + ChineseChars;
+  sel.collapse(editor.firstChild, 0);
+  testRight(editor.firstChild, 8);
+  testLeft(editor.firstChild, 0);
+
   SimpleTest.finish();
 }
 
 
 </script></pre>
 </body>
 </html>
--- a/layout/media/symbols.def.in
+++ b/layout/media/symbols.def.in
@@ -23,16 +23,17 @@ nestegg_track_codec_id
 nestegg_track_count
 nestegg_get_cue_point
 nestegg_track_seek
 nestegg_track_type
 nestegg_track_video_params
 nestegg_tstamp_scale
 nestegg_has_cues
 nestegg_sniff
+nestegg_set_halloc_func
 #endif
 #ifdef MOZ_WEBM_ENCODER
 writeSimpleBlock
 writeHeader
 writeSegmentInformation
 writeVideoTrack
 writeAudioTrack
 Ebml_Serialize
--- a/layout/style/nsFontFaceLoader.cpp
+++ b/layout/style/nsFontFaceLoader.cpp
@@ -485,19 +485,34 @@ nsUserFontSet::UpdateRules(const nsTArra
       }
     }
   }
 
   if (modified) {
     IncrementGeneration();
   }
 
+  // local rules have been rebuilt, so clear the flag
+  mLocalRulesUsed = false;
+
   return modified;
 }
 
+static bool
+HasLocalSrc(const nsCSSValue::Array *aSrcArr)
+{
+  size_t numSrc = aSrcArr->Count();
+  for (size_t i = 0; i < numSrc; i++) {
+    if (aSrcArr->Item(i).GetUnit() == eCSSUnit_Local_Font) {
+      return true;
+    }
+  }
+  return false;
+}
+
 void
 nsUserFontSet::InsertRule(nsCSSFontFaceRule* aRule, uint8_t aSheetType,
                           nsTArray<FontFaceRuleRecord>& aOldRules,
                           bool& aFontSetModified)
 {
   NS_ABORT_IF_FALSE(aRule->GetType() == mozilla::css::Rule::FONT_FACE_RULE,
                     "InsertRule passed a non-fontface CSS rule");
 
@@ -519,18 +534,30 @@ nsUserFontSet::InsertRule(nsCSSFontFaceR
     // usable font, so there is no point in processing it further.
     return;
   }
 
   // first, we check in oldRules; if the rule exists there, just move it
   // to the new rule list, and put the entry into the appropriate family
   for (uint32_t i = 0; i < aOldRules.Length(); ++i) {
     const FontFaceRuleRecord& ruleRec = aOldRules[i];
+
     if (ruleRec.mContainer.mRule == aRule &&
         ruleRec.mContainer.mSheetType == aSheetType) {
+
+      // if local rules were used, don't use the old font entry
+      // for rules containing src local usage
+      if (mLocalRulesUsed) {
+        aRule->GetDesc(eCSSFontDesc_Src, val);
+        unit = val.GetUnit();
+        if (unit == eCSSUnit_Array && HasLocalSrc(val.GetArrayValue())) {
+          break;
+        }
+      }
+
       AddFontFace(fontfamily, ruleRec.mFontEntry);
       mRules.AppendElement(ruleRec);
       aOldRules.RemoveElementAt(i);
       // note the set has been modified if an old rule was skipped to find
       // this one - something has been dropped, or ordering changed
       if (i > 0) {
         aFontSetModified = true;
       }
@@ -978,8 +1005,14 @@ nsUserFontSet::GetPrivateBrowsing()
   nsIPresShell* ps = mPresContext->PresShell();
   if (!ps) {
     return false;
   }
 
   nsCOMPtr<nsILoadContext> loadContext = ps->GetDocument()->GetLoadContext();
   return loadContext && loadContext->UsePrivateBrowsing();
 }
+
+void
+nsUserFontSet::DoRebuildUserFontSet()
+{
+  mPresContext->RebuildUserFontSet();
+}
--- a/layout/style/nsFontFaceLoader.h
+++ b/layout/style/nsFontFaceLoader.h
@@ -82,16 +82,18 @@ protected:
 
   virtual nsresult SyncLoadFontData(gfxProxyFontEntry* aFontToLoad,
                                     const gfxFontFaceSrc* aFontFaceSrc,
                                     uint8_t*& aBuffer,
                                     uint32_t& aBufferLength) MOZ_OVERRIDE;
 
   virtual bool GetPrivateBrowsing() MOZ_OVERRIDE;
 
+  virtual void DoRebuildUserFontSet() MOZ_OVERRIDE;
+
   nsPresContext* mPresContext;  // weak reference
 
   // Set of all loaders pointing to us. These are not strong pointers,
   // but that's OK because nsFontFaceLoader always calls RemoveLoader on
   // us before it dies (unless we die first).
   nsTHashtable< nsPtrHashKey<nsFontFaceLoader> > mLoaders;
 
   nsTArray<FontFaceRuleRecord>   mRules;
--- a/media/libnestegg/README_MOZILLA
+++ b/media/libnestegg/README_MOZILLA
@@ -1,8 +1,8 @@
 The source from this directory was copied from the nestegg
 git repository using the update.sh script.  The only changes
 made were those applied by update.sh and the addition of
 Makefile.in build files for the Mozilla build system.
 
 The nestegg git repository is: git://github.com/kinetiknz/nestegg.git
 
-The git commit ID used was 0851279ab11f5b2e9e8154ce7880b687b564c760.
+The git commit ID used was c739433afee18ee679ab0f3206d848b6d68f9de2.
--- a/media/libnestegg/include/nestegg.h
+++ b/media/libnestegg/include/nestegg.h
@@ -271,16 +271,26 @@ int nestegg_track_video_params(nestegg *
     @param context Stream context initialized by #nestegg_init.
     @param track   Zero based track number.
     @param params  Storage for the queried audio parameters.
     @retval  0 Success.
     @retval -1 Error. */
 int nestegg_track_audio_params(nestegg * context, unsigned int track,
                                nestegg_audio_params * params);
 
+/** Query the default frame duration for @a track.  For a video track, this
+    is typically the inverse of the video frame rate.
+    @param context  Stream context initialized by #nestegg_init.
+    @param track    Zero based track number.
+    @param duration Storage for the default duration in nanoseconds.
+    @retval  0 Success.
+    @retval -1 Error. */
+int nestegg_track_default_duration(nestegg * context, unsigned int track,
+                                   uint64_t * duration);
+
 /** Read a packet of media data.  A packet consists of one or more chunks of
     data associated with a single track.  nestegg_read_packet should be
     called in a loop while the return value is 1 to drive the stream parser
     forward.  @see nestegg_free_packet
     @param context Context returned by #nestegg_init.
     @param packet  Storage for the returned nestegg_packet.
     @retval  1 Additional packets may be read in subsequent calls.
     @retval  0 End of stream.
@@ -300,16 +310,23 @@ int nestegg_packet_track(nestegg_packet 
 
 /** Query the time stamp in nanoseconds of @a packet.
     @param packet Packet initialized by #nestegg_read_packet.
     @param tstamp Storage for the queried timestamp in nanoseconds.
     @retval  0 Success.
     @retval -1 Error. */
 int nestegg_packet_tstamp(nestegg_packet * packet, uint64_t * tstamp);
 
+/** Query the duration in nanoseconds of @a packet.
+    @param packet Packet initialized by #nestegg_read_packet.
+    @param duration Storage for the queried duration in nanoseconds.
+    @retval  0 Success.
+    @retval -1 Error. */
+int nestegg_packet_duration(nestegg_packet * packet, uint64_t * duration);
+
 /** Query the number of data chunks contained in @a packet.
     @param packet Packet initialized by #nestegg_read_packet.
     @param count  Storage for the queried timestamp in nanoseconds.
     @retval  0 Success.
     @retval -1 Error. */
 int nestegg_packet_count(nestegg_packet * packet, unsigned int * count);
 
 /** Get a pointer to chunk number @a item of packet data.
@@ -341,13 +358,20 @@ int nestegg_has_cues(nestegg * context);
  * Try to determine if the buffer looks like the beginning of a WebM file.
  *
  * @param buffer A buffer containing the beginning of a media file.
  * @param length The size of the buffer.
  * @retval 0 The file is not a WebM file.
  * @retval 1 The file is a WebM file. */
 int nestegg_sniff(unsigned char const * buffer, size_t length);
 
+/**
+ * Set the underlying allocation function for library allocations.
+ *
+ * @param realloc_func The desired function.
+ */
+void nestegg_set_halloc_func(void * (* realloc_func)(void *, size_t));
+
 #if defined(__cplusplus)
 }
 #endif
 
 #endif /* NESTEGG_671cac2a_365d_ed69_d7a3_4491d3538d79 */
--- a/media/libnestegg/src/nestegg.c
+++ b/media/libnestegg/src/nestegg.c
@@ -61,16 +61,17 @@
 #define ID_FLAG_DEFAULT         0x88
 #define ID_FLAG_LACING          0x9c
 #define ID_TRACK_TIMECODE_SCALE 0x23314f
 #define ID_LANGUAGE             0x22b59c
 #define ID_CODEC_ID             0x86
 #define ID_CODEC_PRIVATE        0x63a2
 #define ID_CODEC_DELAY          0x56aa
 #define ID_SEEK_PREROLL         0x56bb
+#define ID_DEFAULT_DURATION     0x23e383
 
 /* Video Elements */
 #define ID_VIDEO                0xe0
 #define ID_STEREO_MODE          0x53b8
 #define ID_PIXEL_WIDTH          0xb0
 #define ID_PIXEL_HEIGHT         0xba
 #define ID_PIXEL_CROP_BOTTOM    0x54aa
 #define ID_PIXEL_CROP_TOP       0x54bb
@@ -231,16 +232,17 @@ struct track_entry {
   struct ebml_type flag_default;
   struct ebml_type flag_lacing;
   struct ebml_type track_timecode_scale;
   struct ebml_type language;
   struct ebml_type codec_id;
   struct ebml_type codec_private;
   struct ebml_type codec_delay;
   struct ebml_type seek_preroll;
+  struct ebml_type default_duration;
   struct video video;
   struct audio audio;
 };
 
 struct tracks {
   struct ebml_list track_entry;
 };
 
@@ -305,16 +307,17 @@ struct nestegg {
   struct segment segment;
   int64_t segment_offset;
   unsigned int track_count;
 };
 
 struct nestegg_packet {
   uint64_t track;
   uint64_t timecode;
+  uint64_t duration;
   struct frame * frame;
   int64_t discard_padding;
 };
 
 /* Element Descriptor */
 struct ebml_element_desc {
   char const * name;
   uint64_t id;
@@ -414,16 +417,17 @@ static struct ebml_element_desc ne_track
   E_FIELD(ID_FLAG_DEFAULT, TYPE_UINT, struct track_entry, flag_default),
   E_FIELD(ID_FLAG_LACING, TYPE_UINT, struct track_entry, flag_lacing),
   E_FIELD(ID_TRACK_TIMECODE_SCALE, TYPE_FLOAT, struct track_entry, track_timecode_scale),
   E_FIELD(ID_LANGUAGE, TYPE_STRING, struct track_entry, language),
   E_FIELD(ID_CODEC_ID, TYPE_STRING, struct track_entry, codec_id),
   E_FIELD(ID_CODEC_PRIVATE, TYPE_BINARY, struct track_entry, codec_private),
   E_FIELD(ID_CODEC_DELAY, TYPE_UINT, struct track_entry, codec_delay),
   E_FIELD(ID_SEEK_PREROLL, TYPE_UINT, struct track_entry, seek_preroll),
+  E_FIELD(ID_DEFAULT_DURATION, TYPE_UINT, struct track_entry, default_duration),
   E_SINGLE_MASTER(ID_VIDEO, TYPE_MASTER, struct track_entry, video),
   E_SINGLE_MASTER(ID_AUDIO, TYPE_MASTER, struct track_entry, audio),
   E_LAST
 };
 
 static struct ebml_element_desc ne_tracks_elements[] = {
   E_MASTER(ID_TRACK_ENTRY, TYPE_MASTER, struct tracks, track_entry),
   E_LAST
@@ -467,52 +471,42 @@ static struct ebml_element_desc ne_top_l
 #undef E_SINGLE_MASTER_O
 #undef E_SINGLE_MASTER
 #undef E_SUSPEND
 #undef E_LAST
 
 static struct pool_ctx *
 ne_pool_init(void)
 {
-  struct pool_ctx * pool;
-
-  pool = h_malloc(sizeof(*pool));
-  if (!pool)
-    abort();
-  return pool;
+  return h_malloc(sizeof(struct pool_ctx));
 }
 
 static void
 ne_pool_destroy(struct pool_ctx * pool)
 {
   h_free(pool);
 }
 
 static void *
 ne_pool_alloc(size_t size, struct pool_ctx * pool)
 {
   void * p;
 
   p = h_malloc(size);
   if (!p)
-    abort();
+    return NULL;
   hattach(p, pool);
   memset(p, 0, size);
   return p;
 }
 
 static void *
 ne_alloc(size_t size)
 {
-  void * p;
-
-  p = calloc(1, size);
-  if (!p)
-    abort();
-  return p;
+  return calloc(1, size);
 }
 
 static int
 ne_io_read(nestegg_io * io, void * buffer, size_t length)
 {
   return io->read(buffer, length, io->userdata);
 }
 
@@ -693,30 +687,34 @@ static int
 ne_read_string(nestegg * ctx, char ** val, uint64_t length)
 {
   char * str;
   int r;
 
   if (length == 0 || length > LIMIT_STRING)
     return -1;
   str = ne_pool_alloc(length + 1, ctx->alloc_pool);
+  if (!str)
+    return -1;
   r = ne_io_read(ctx->io, (unsigned char *) str, length);
   if (r != 1)
     return r;
   str[length] = '\0';
   *val = str;
   return 1;
 }
 
 static int
 ne_read_binary(nestegg * ctx, struct ebml_binary * val, uint64_t length)
 {
   if (length == 0 || length > LIMIT_BINARY)
     return -1;
   val->data = ne_pool_alloc(length, ctx->alloc_pool);
+  if (!val->data)
+    return -1;
   val->length = length;
   return ne_io_read(ctx->io, val->data, length);
 }
 
 static int
 ne_get_uint(struct ebml_type type, uint64_t * value)
 {
   if (!type.read)
@@ -788,26 +786,29 @@ ne_find_element(uint64_t id, struct ebml
 
   for (element = elements; element->id; ++element)
     if (element->id == id)
       return element;
 
   return NULL;
 }
 
-static void
+static int
 ne_ctx_push(nestegg * ctx, struct ebml_element_desc * ancestor, void * data)
 {
   struct list_node * item;
 
   item = ne_alloc(sizeof(*item));
+  if (!item)
+    return -1;
   item->previous = ctx->ancestor;
   item->node = ancestor;
   item->data = data;
   ctx->ancestor = item;
+  return 0;
 }
 
 static void
 ne_ctx_pop(nestegg * ctx)
 {
   struct list_node * item;
 
   item = ctx->ancestor;
@@ -883,56 +884,63 @@ ne_read_element(nestegg * ctx, uint64_t 
   if (r != 1)
     return r;
 
   ctx->last_valid = 0;
 
   return 1;
 }
 
-static void
+static int
 ne_read_master(nestegg * ctx, struct ebml_element_desc * desc)
 {
   struct ebml_list * list;
   struct ebml_list_node * node, * oldtail;
 
   assert(desc->type == TYPE_MASTER && desc->flags & DESC_FLAG_MULTI);
 
   ctx->log(ctx, NESTEGG_LOG_DEBUG, "multi master element %llx (%s)",
            desc->id, desc->name);
 
   list = (struct ebml_list *) (ctx->ancestor->data + desc->offset);
 
   node = ne_pool_alloc(sizeof(*node), ctx->alloc_pool);
+  if (!node)
+    return -1;
   node->id = desc->id;
   node->data = ne_pool_alloc(desc->size, ctx->alloc_pool);
+  if (!node->data)
+    return -1;
 
   oldtail = list->tail;
   if (oldtail)
     oldtail->next = node;
   list->tail = node;
   if (!list->head)
     list->head = node;
 
   ctx->log(ctx, NESTEGG_LOG_DEBUG, " -> using data %p", node->data);
 
-  ne_ctx_push(ctx, desc->children, node->data);
+  if (ne_ctx_push(ctx, desc->children, node->data) < 0)
+    return -1;
+
+  return 0;
 }
 
-static void
+static int
 ne_read_single_master(nestegg * ctx, struct ebml_element_desc * desc)
 {
   assert(desc->type == TYPE_MASTER && !(desc->flags & DESC_FLAG_MULTI));
 
   ctx->log(ctx, NESTEGG_LOG_DEBUG, "single master element %llx (%s)",
            desc->id, desc->name);
   ctx->log(ctx, NESTEGG_LOG_DEBUG, " -> using data %p (%u)",
            ctx->ancestor->data + desc->offset, desc->offset);
 
-  ne_ctx_push(ctx, desc->children, ctx->ancestor->data + desc->offset);
+  return ne_ctx_push(ctx, desc->children, ctx->ancestor->data + desc->offset);
 }
 
 static int
 ne_read_simple(nestegg * ctx, struct ebml_element_desc * desc, size_t length)
 {
   struct ebml_type * storage;
   int r;
 
@@ -963,16 +971,17 @@ ne_read_simple(nestegg * ctx, struct ebm
     r = ne_read_string(ctx, &storage->v.s, length);
     break;
   case TYPE_BINARY:
     r = ne_read_binary(ctx, &storage->v.b, length);
     break;
   case TYPE_MASTER:
   case TYPE_UNKNOWN:
     assert(0);
+    r = 0;
     break;
   }
 
   if (r == 1)
     storage->read = 1;
 
   return r;
 }
@@ -1018,20 +1027,23 @@ ne_parse(nestegg * ctx, struct ebml_elem
         *data_offset = ne_io_tell(ctx->io);
         if (*data_offset < 0) {
           r = -1;
           break;
         }
       }
 
       if (element->type == TYPE_MASTER) {
-        if (element->flags & DESC_FLAG_MULTI)
-          ne_read_master(ctx, element);
-        else
-          ne_read_single_master(ctx, element);
+        if (element->flags & DESC_FLAG_MULTI) {
+          if (ne_read_master(ctx, element) < 0)
+            break;
+        } else {
+          if (ne_read_single_master(ctx, element) < 0)
+            break;
+        }
         continue;
       } else {
         r = ne_read_simple(ctx, element, size);
         if (r < 0)
           break;
       }
     } else if (ne_is_ancestor_element(id, ctx->ancestor->previous)) {
       ctx->log(ctx, NESTEGG_LOG_DEBUG, "parent element %llx", id);
@@ -1335,30 +1347,41 @@ ne_read_block(nestegg * ctx, uint64_t bl
   if (ne_get_uint(cluster->timecode, &cluster_tc) != 0)
     return -1;
 
   abs_timecode = timecode + cluster_tc;
   if (abs_timecode < 0)
     return -1;
 
   pkt = ne_alloc(sizeof(*pkt));
+  if (!pkt)
+    return -1;
   pkt->track = track;
   pkt->timecode = abs_timecode * tc_scale * track_scale;
 
   ctx->log(ctx, NESTEGG_LOG_DEBUG, "%sblock t %lld pts %f f %llx frames: %llu",
            block_id == ID_BLOCK ? "" : "simple", pkt->track, pkt->timecode / 1e9, flags, frames);
 
   last = NULL;
   for (i = 0; i < frames; ++i) {
     if (frame_sizes[i] > LIMIT_FRAME) {
       nestegg_free_packet(pkt);
       return -1;
     }
     f = ne_alloc(sizeof(*f));
+    if (!f) {
+      nestegg_free_packet(pkt);
+      return -1;
+    }
     f->data = ne_alloc(frame_sizes[i]);
+    if (!f->data) {
+      free(f);
+      nestegg_free_packet(pkt);
+      return -1;
+    }
     f->length = frame_sizes[i];
     r = ne_io_read(ctx->io, f->data, frame_sizes[i]);
     if (r != 1) {
       free(f->data);
       free(f);
       nestegg_free_packet(pkt);
       return -1;
     }
@@ -1371,16 +1394,44 @@ ne_read_block(nestegg * ctx, uint64_t bl
   }
 
   *data = pkt;
 
   return 1;
 }
 
 static int
+ne_read_block_duration(nestegg * ctx, nestegg_packet * pkt)
+{
+  int r;
+  uint64_t id, size;
+  struct ebml_element_desc * element;
+  struct ebml_type * storage;
+
+  r = ne_peek_element(ctx, &id, &size);
+  if (r != 1)
+    return r;
+
+  if (id != ID_BLOCK_DURATION)
+    return 1;
+
+  element = ne_find_element(id, ctx->ancestor->node);
+  if (!element)
+    return 1;
+
+  r = ne_read_simple(ctx, element, size);
+  if (r != 1)
+    return r;
+  storage = (struct ebml_type *) (ctx->ancestor->data + element->offset);
+  pkt->duration = storage->v.i * ne_get_timecode_scale(ctx);
+
+  return 1;
+}
+
+static int
 ne_read_discard_padding(nestegg * ctx, nestegg_packet * pkt)
 {
   int r;
   uint64_t id, size;
   struct ebml_element_desc * element;
   struct ebml_type * storage;
 
   r = ne_peek_element(ctx, &id, &size);
@@ -1545,19 +1596,22 @@ ne_init_cue_points(nestegg * ctx, int64_
     r = ne_read_element(ctx, &id, NULL);
     if (r != 1)
       return -1;
 
     if (id != ID_CUES)
       return -1;
 
     ctx->ancestor = NULL;
-    ne_ctx_push(ctx, ne_top_level_elements, ctx);
-    ne_ctx_push(ctx, ne_segment_elements, &ctx->segment);
-    ne_ctx_push(ctx, ne_cues_elements, &ctx->segment.cues);
+    if (ne_ctx_push(ctx, ne_top_level_elements, ctx) < 0)
+      return -1;
+    if (ne_ctx_push(ctx, ne_segment_elements, &ctx->segment) < 0)
+      return -1;
+    if (ne_ctx_push(ctx, ne_cues_elements, &ctx->segment.cues) < 0)
+      return -1;
     /* parser will run until end of cues element. */
     ctx->log(ctx, NESTEGG_LOG_DEBUG, "seek: parsing cue elements");
     r = ne_parse(ctx, ne_cues_elements, max_offset);
     while (ctx->ancestor)
       ne_ctx_pop(ctx);
 
     /* Reset parser state to original state and seek back to old position. */
     if (ne_ctx_restore(ctx, &state) != 0)
@@ -1638,20 +1692,30 @@ ne_match_webm(nestegg_io io, int64_t max
   uint64_t id;
   char * doctype;
   nestegg * ctx;
 
   if (!(io.read && io.seek && io.tell))
     return -1;
 
   ctx = ne_alloc(sizeof(*ctx));
+  if (!ctx)
+    return -1;
 
   ctx->io = ne_alloc(sizeof(*ctx->io));
+  if (!ctx->io) {
+    nestegg_destroy(ctx);
+    return -1;
+  }
   *ctx->io = io;
   ctx->alloc_pool = ne_pool_init();
+  if (!ctx->alloc_pool) {
+    nestegg_destroy(ctx);
+    return -1;
+  }
   ctx->log = ne_null_log_callback;
 
   r = ne_peek_element(ctx, &id, NULL);
   if (r != 1) {
     nestegg_destroy(ctx);
     return 0;
   }
 
@@ -1686,21 +1750,31 @@ nestegg_init(nestegg ** context, nestegg
   struct ebml_list_node * track;
   char * doctype;
   nestegg * ctx;
 
   if (!(io.read && io.seek && io.tell))
     return -1;
 
   ctx = ne_alloc(sizeof(*ctx));
+  if (!ctx)
+    return -1;
 
   ctx->io = ne_alloc(sizeof(*ctx->io));
+  if (!ctx->io) {
+    nestegg_destroy(ctx);
+    return -1;
+  }
   *ctx->io = io;
   ctx->log = callback;
   ctx->alloc_pool = ne_pool_init();
+  if (!ctx->alloc_pool) {
+    nestegg_destroy(ctx);
+    return -1;
+  }
 
   if (!ctx->log)
     ctx->log = ne_null_log_callback;
 
   r = ne_peek_element(ctx, &id, NULL);
   if (r != 1) {
     nestegg_destroy(ctx);
     return -1;
@@ -2162,16 +2236,34 @@ nestegg_track_audio_params(nestegg * ctx
   value = 0;
   ne_get_uint(entry->seek_preroll, &value);
   params->seek_preroll = value;
 
   return 0;
 }
 
 int
+nestegg_track_default_duration(nestegg * ctx, unsigned int track,
+                               uint64_t * duration)
+{
+  struct track_entry * entry;
+  uint64_t value;
+
+  entry = ne_find_track_entry(ctx, track);
+  if (!entry)
+    return -1;
+
+  if (ne_get_uint(entry->default_duration, &value) != 0)
+    return -1;
+  *duration = value;
+
+  return 0;
+}
+
+int
 nestegg_read_packet(nestegg * ctx, nestegg_packet ** pkt)
 {
   int r;
   uint64_t id, size;
 
   *pkt = NULL;
 
   for (;;) {
@@ -2186,16 +2278,20 @@ nestegg_read_packet(nestegg * ctx, neste
         return r;
 
       /* The only DESC_FLAG_SUSPEND fields are Blocks and SimpleBlocks, which we
          handle directly. */
       r = ne_read_block(ctx, id, size, pkt);
       if (r != 1)
         return r;
 
+      r = ne_read_block_duration(ctx, *pkt);
+      if (r != 1)
+        return r;
+
       r = ne_read_discard_padding(ctx, *pkt);
       if (r != 1)
         return r;
 
       return r;
     }
 
     r =  ne_parse(ctx, NULL, -1);
@@ -2231,16 +2327,23 @@ nestegg_packet_track(nestegg_packet * pk
 int
 nestegg_packet_tstamp(nestegg_packet * pkt, uint64_t * tstamp)
 {
   *tstamp = pkt->timecode;
   return 0;
 }
 
 int
+nestegg_packet_duration(nestegg_packet * pkt, uint64_t * duration)
+{
+  *duration = pkt->duration;
+  return 0;
+}
+
+int
 nestegg_packet_discard_padding(nestegg_packet * pkt, int64_t * discard_padding)
 {
   *discard_padding = pkt->discard_padding;
   return 0;
 }
 
 int
 nestegg_packet_count(nestegg_packet * pkt, unsigned int * count)
@@ -2299,8 +2402,13 @@ nestegg_sniff(unsigned char const * buff
 
   io.read = ne_buffer_read;
   io.seek = ne_buffer_seek;
   io.tell = ne_buffer_tell;
   io.userdata = &user_data;
   return ne_match_webm(io, length);
 }
 
+void
+nestegg_set_halloc_func(void * (* realloc_func)(void *, size_t))
+{
+  halloc_allocator = realloc_func;
+}
--- a/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp
+++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp
@@ -1595,17 +1595,21 @@ PeerConnectionImpl::CheckApiState(bool a
 }
 
 NS_IMETHODIMP
 PeerConnectionImpl::Close()
 {
   CSFLogDebug(logTag, "%s: for %s", __FUNCTION__, mHandle.c_str());
   PC_AUTO_ENTER_API_CALL_NO_CHECK();
 
-  return CloseInt();
+  nsresult res = CloseInt();
+
+  SetSignalingState_m(PCImplSignalingState::SignalingClosed);
+
+  return res;
 }
 
 
 nsresult
 PeerConnectionImpl::CloseInt()
 {
   PC_AUTO_ENTER_API_CALL_NO_CHECK();
 
--- a/memory/replace/dmd/DMD.h
+++ b/memory/replace/dmd/DMD.h
@@ -50,17 +50,20 @@ ClearReports();
 
 // Checks which heap blocks have been reported, and dumps a human-readable
 // summary (via |aWrite|).  If |aWrite| is nullptr it will dump to stderr.
 // Beware:  this output may have very long lines.
 MOZ_EXPORT void
 Dump(Writer aWriter);
 
 // A useful |WriterFun|.  If |fp| is a FILE* you want |Dump|'s output to be
-// written to, call |Dump(FpWrite, fp)|.
+// written to, call:
+//
+//   dmd::Writer writer(FpWrite, fp);
+//   dmd::Dump(writer);
 MOZ_EXPORT void
 FpWrite(void* aFp, const char* aFmt, va_list aAp);
 
 struct Sizes
 {
   size_t mStackTracesUsed;
   size_t mStackTracesUnused;
   size_t mStackTraceTable;
--- a/netwerk/base/public/nsIStreamLoader.idl
+++ b/netwerk/base/public/nsIStreamLoader.idl
@@ -22,19 +22,19 @@ interface nsIStreamLoaderObserver : nsIS
      *
      * This method will always be called asynchronously by the
      * nsIStreamLoader involved, on the thread that called the
      * loader's init() method.
      *
      * If the observer wants to take over responsibility for the
      * data buffer (result), it returns NS_SUCCESS_ADOPTED_DATA
      * in place of NS_OK as its success code. The loader will then
-     * "forget" about the data, and not NS_Free() it in its own
-     * destructor; observer must call NS_Free() when the data is
-     * no longer required.
+     * "forget" about the data and not NS_Free() it after
+     * onStreamComplete() returns; observer must call NS_Free()
+     * when the data is no longer required.
      */
     void onStreamComplete(in nsIStreamLoader loader,
                           in nsISupports ctxt,
                           in nsresult status,
                           in unsigned long resultLength,
                           [const,array,size_is(resultLength)] in octet result);
 };
 
--- a/netwerk/base/src/Seer.cpp
+++ b/netwerk/base/src/Seer.cpp
@@ -2731,38 +2731,50 @@ EnsureGlobalSeer(nsINetworkSeer **aSeer)
   NS_IF_ADDREF(*aSeer = seer);
   return NS_OK;
 }
 
 nsresult
 SeerPredict(nsIURI *targetURI, nsIURI *sourceURI, SeerPredictReason reason,
             nsILoadContext *loadContext, nsINetworkSeerVerifier *verifier)
 {
+  if (!IsNullOrHttp(targetURI) || !IsNullOrHttp(sourceURI)) {
+    return NS_OK;
+  }
+
   nsCOMPtr<nsINetworkSeer> seer;
   nsresult rv = EnsureGlobalSeer(getter_AddRefs(seer));
   NS_ENSURE_SUCCESS(rv, rv);
 
   return seer->Predict(targetURI, sourceURI, reason, loadContext, verifier);
 }
 
 nsresult
 SeerLearn(nsIURI *targetURI, nsIURI *sourceURI, SeerLearnReason reason,
           nsILoadContext *loadContext)
 {
+  if (!IsNullOrHttp(targetURI) || !IsNullOrHttp(sourceURI)) {
+    return NS_OK;
+  }
+
   nsCOMPtr<nsINetworkSeer> seer;
   nsresult rv = EnsureGlobalSeer(getter_AddRefs(seer));
   NS_ENSURE_SUCCESS(rv, rv);
 
   return seer->Learn(targetURI, sourceURI, reason, loadContext);
 }
 
 nsresult
 SeerLearn(nsIURI *targetURI, nsIURI *sourceURI, SeerLearnReason reason,
           nsILoadGroup *loadGroup)
 {
+  if (!IsNullOrHttp(targetURI) || !IsNullOrHttp(sourceURI)) {
+    return NS_OK;
+  }
+
   nsCOMPtr<nsINetworkSeer> seer;
   nsresult rv = EnsureGlobalSeer(getter_AddRefs(seer));
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsCOMPtr<nsILoadContext> loadContext;
 
   if (loadGroup) {
     nsCOMPtr<nsIInterfaceRequestor> callbacks;
@@ -2774,16 +2786,20 @@ SeerLearn(nsIURI *targetURI, nsIURI *sou
 
   return seer->Learn(targetURI, sourceURI, reason, loadContext);
 }
 
 nsresult
 SeerLearn(nsIURI *targetURI, nsIURI *sourceURI, SeerLearnReason reason,
           nsIDocument *document)
 {
+  if (!IsNullOrHttp(targetURI) || !IsNullOrHttp(sourceURI)) {
+    return NS_OK;
+  }
+
   nsCOMPtr<nsINetworkSeer> seer;
   nsresult rv = EnsureGlobalSeer(getter_AddRefs(seer));
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsCOMPtr<nsILoadContext> loadContext;
 
   if (document) {
     loadContext = document->GetLoadContext();
@@ -2791,30 +2807,34 @@ SeerLearn(nsIURI *targetURI, nsIURI *sou
 
   return seer->Learn(targetURI, sourceURI, reason, loadContext);
 }
 
 nsresult
 SeerLearnRedirect(nsIURI *targetURI, nsIChannel *channel,
                   nsILoadContext *loadContext)
 {
-  nsCOMPtr<nsINetworkSeer> seer;
-  nsresult rv = EnsureGlobalSeer(getter_AddRefs(seer));
-  NS_ENSURE_SUCCESS(rv, rv);
-
   nsCOMPtr<nsIURI> sourceURI;
-  rv = channel->GetOriginalURI(getter_AddRefs(sourceURI));
+  nsresult rv = channel->GetOriginalURI(getter_AddRefs(sourceURI));
   NS_ENSURE_SUCCESS(rv, rv);
 
   bool sameUri;
   rv = targetURI->Equals(sourceURI, &sameUri);
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (sameUri) {
     return NS_OK;
   }
 
+  if (!IsNullOrHttp(targetURI) || !IsNullOrHttp(sourceURI)) {
+    return NS_OK;
+  }
+
+  nsCOMPtr<nsINetworkSeer> seer;
+  rv = EnsureGlobalSeer(getter_AddRefs(seer));
+  NS_ENSURE_SUCCESS(rv, rv);
+
   return seer->Learn(targetURI, sourceURI,
                      nsINetworkSeer::LEARN_LOAD_REDIRECT, loadContext);
 }
 
 } // ::mozilla::net
 } // ::mozilla
--- a/netwerk/base/src/nsSocketTransport2.cpp
+++ b/netwerk/base/src/nsSocketTransport2.cpp
@@ -759,46 +759,42 @@ nsSocketTransport::nsSocketTransport()
     , mInputClosed(true)
     , mOutputClosed(true)
     , mResolving(false)
     , mNetAddrIsSet(false)
     , mLock("nsSocketTransport.mLock")
     , mFD(MOZ_THIS_IN_INITIALIZER_LIST())
     , mFDref(0)
     , mFDconnected(false)
+    , mSocketTransportService(gSocketTransportService)
     , mInput(MOZ_THIS_IN_INITIALIZER_LIST())
     , mOutput(MOZ_THIS_IN_INITIALIZER_LIST())
     , mQoSBits(0x00)
     , mKeepaliveEnabled(false)
     , mKeepaliveIdleTimeS(-1)
     , mKeepaliveRetryIntervalS(-1)
     , mKeepaliveProbeCount(-1)
 {
     SOCKET_LOG(("creating nsSocketTransport @%p\n", this));
 
-    NS_ADDREF(gSocketTransportService);
-
     mTimeouts[TIMEOUT_CONNECT]    = UINT16_MAX; // no timeout
     mTimeouts[TIMEOUT_READ_WRITE] = UINT16_MAX; // no timeout
 }
 
 nsSocketTransport::~nsSocketTransport()
 {
     SOCKET_LOG(("destroying nsSocketTransport @%p\n", this));
 
     // cleanup socket type info
     if (mTypes) {
         uint32_t i;
         for (i=0; i<mTypeCount; ++i)
             PL_strfree(mTypes[i]);
         free(mTypes);
     }
- 
-    nsSocketTransportService *serv = gSocketTransportService;
-    NS_RELEASE(serv); // nulls argument
 }
 
 nsresult
 nsSocketTransport::Init(const char **types, uint32_t typeCount,
                         const nsACString &host, uint16_t port,
                         nsIProxyInfo *givenProxyInfo)
 {
     MOZ_EVENT_TRACER_NAME_OBJECT(this, host.BeginReading());
@@ -956,17 +952,17 @@ nsSocketTransport::PostEvent(uint32_t ty
 {
     SOCKET_LOG(("nsSocketTransport::PostEvent [this=%p type=%u status=%x param=%p]\n",
         this, type, status, param));
 
     nsCOMPtr<nsIRunnable> event = new nsSocketEvent(this, type, status, param);
     if (!event)
         return NS_ERROR_OUT_OF_MEMORY;
 
-    return gSocketTransportService->Dispatch(event, NS_DISPATCH_NORMAL);
+    return mSocketTransportService->Dispatch(event, NS_DISPATCH_NORMAL);
 }
 
 void
 nsSocketTransport::SendStatus(nsresult status)
 {
     SOCKET_LOG(("nsSocketTransport::SendStatus [this=%p status=%x]\n", this, status));
 
     nsCOMPtr<nsITransportEventSink> sink;
@@ -1214,29 +1210,29 @@ nsSocketTransport::InitiateSocket()
     // in a race to call AttachSocket once notified.  for this reason, when
     // we get notified, we just re-enter this function.  as a result, we are
     // sure to ask again before calling AttachSocket.  in this way we deal
     // with the race condition.  though it isn't the most elegant solution,
     // it is far simpler than trying to build a system that would guarantee
     // FIFO ordering (which wouldn't even be that valuable IMO).  see bug
     // 194402 for more info.
     //
-    if (!gSocketTransportService->CanAttachSocket()) {
+    if (!mSocketTransportService->CanAttachSocket()) {
         nsCOMPtr<nsIRunnable> event =
                 new nsSocketEvent(this, MSG_RETRY_INIT_SOCKET);
         if (!event)
             return NS_ERROR_OUT_OF_MEMORY;
-        return gSocketTransportService->NotifyWhenCanAttachSocket(event);
+        return mSocketTransportService->NotifyWhenCanAttachSocket(event);
     }
 
     //
     // if we already have a connected socket, then just attach and return.
     //
     if (mFD.IsInitialized()) {
-        rv = gSocketTransportService->AttachSocket(mFD, this);
+        rv = mSocketTransportService->AttachSocket(mFD, this);
         if (NS_SUCCEEDED(rv))
             mAttached = true;
         return rv;
     }
 
     //
     // create new socket fd, push io layers, etc.
     //
@@ -1268,31 +1264,31 @@ nsSocketTransport::InitiateSocket()
     opt.option = PR_SockOpt_NoDelay;
     opt.value.no_delay = true;
     PR_SetSocketOption(fd, &opt);
 
     // if the network.tcp.sendbuffer preference is set, use it to size SO_SNDBUF
     // The Windows default of 8KB is too small and as of vista sp1, autotuning
     // only applies to receive window
     int32_t sndBufferSize;
-    gSocketTransportService->GetSendBufferSize(&sndBufferSize);
+    mSocketTransportService->GetSendBufferSize(&sndBufferSize);
     if (sndBufferSize > 0) {
         opt.option = PR_SockOpt_SendBufferSize;
         opt.value.send_buffer_size = sndBufferSize;
         PR_SetSocketOption(fd, &opt);
     }
 
     if (mQoSBits) {
         opt.option = PR_SockOpt_IpTypeOfService;
         opt.value.tos = mQoSBits;
         PR_SetSocketOption(fd, &opt);
     }
 
     // inform socket transport about this newly created socket...
-    rv = gSocketTransportService->AttachSocket(fd, this);
+    rv = mSocketTransportService->AttachSocket(fd, this);
     if (NS_FAILED(rv)) {
         PR_Close(fd);
         return rv;
     }
     mAttached = true;
 
     // assign mFD so that we can properly handle OnSocketDetached before we've
     // established a connection.
@@ -1459,17 +1455,17 @@ nsSocketTransport::RecoverFromError()
         }
     }
 
 #if defined(XP_WIN)
     // If not trying next address, try to make a connection using dialup. 
     // Retry if that connection is made.
     if (!tryAgain) {
         bool autodialEnabled;
-        gSocketTransportService->GetAutodialEnabled(&autodialEnabled);
+        mSocketTransportService->GetAutodialEnabled(&autodialEnabled);
         if (autodialEnabled) {
           tryAgain = nsNativeConnectionHelper::OnConnectionFailed(
                        NS_ConvertUTF8toUTF16(SocketHost()).get());
 	    }
     }
 #endif
 
     // prepare to try again.
@@ -1961,17 +1957,17 @@ nsSocketTransport::OpenInputStream(uint3
 
         // create a pipe
         nsCOMPtr<nsIAsyncOutputStream> pipeOut;
         rv = NS_NewPipe2(getter_AddRefs(pipeIn), getter_AddRefs(pipeOut),
                          !openBlocking, true, segsize, segcount);
         if (NS_FAILED(rv)) return rv;
 
         // async copy from socket to pipe
-        rv = NS_AsyncCopy(&mInput, pipeOut, gSocketTransportService,
+        rv = NS_AsyncCopy(&mInput, pipeOut, mSocketTransportService,
                           NS_ASYNCCOPY_VIA_WRITESEGMENTS, segsize);
         if (NS_FAILED(rv)) return rv;
 
         *result = pipeIn;
     }
     else
         *result = &mInput;
 
@@ -2007,17 +2003,17 @@ nsSocketTransport::OpenOutputStream(uint
 
         // create a pipe
         nsCOMPtr<nsIAsyncInputStream> pipeIn;
         rv = NS_NewPipe2(getter_AddRefs(pipeIn), getter_AddRefs(pipeOut),
                          true, !openBlocking, segsize, segcount);
         if (NS_FAILED(rv)) return rv;
 
         // async copy from socket to pipe
-        rv = NS_AsyncCopy(pipeIn, &mOutput, gSocketTransportService,
+        rv = NS_AsyncCopy(pipeIn, &mOutput, mSocketTransportService,
                           NS_ASYNCCOPY_VIA_READSEGMENTS, segsize);
         if (NS_FAILED(rv)) return rv;
 
         *result = pipeOut;
     }
     else
         *result = &mOutput;
 
@@ -2446,17 +2442,17 @@ nsSocketTransport::SetKeepaliveEnabledIn
 
     PRFileDescAutoLock fd(this);
     if (NS_WARN_IF(!fd.IsInitialized())) {
         return NS_ERROR_NOT_INITIALIZED;
     }
 
     // Only enable if keepalives are globally enabled, but ensure other
     // options are set correctly on the fd.
-    bool enable = aEnable && gSocketTransportService->IsKeepaliveEnabled();
+    bool enable = aEnable && mSocketTransportService->IsKeepaliveEnabled();
     nsresult rv = fd.SetKeepaliveVals(enable,
                                       mKeepaliveIdleTimeS,
                                       mKeepaliveRetryIntervalS,
                                       mKeepaliveProbeCount);
     if (NS_WARN_IF(NS_FAILED(rv))) {
         SOCKET_LOG(("  SetKeepaliveVals failed rv[0x%x]", rv));
         return rv;
     }
@@ -2478,31 +2474,31 @@ nsSocketTransport::GetKeepaliveEnabled(b
 }
 
 nsresult
 nsSocketTransport::EnsureKeepaliveValsAreInitialized()
 {
     nsresult rv = NS_OK;
     int32_t val = -1;
     if (mKeepaliveIdleTimeS == -1) {
-        rv = gSocketTransportService->GetKeepaliveIdleTime(&val);
+        rv = mSocketTransportService->GetKeepaliveIdleTime(&val);
         if (NS_WARN_IF(NS_FAILED(rv))) {
             return rv;
         }
         mKeepaliveIdleTimeS = val;
     }
     if (mKeepaliveRetryIntervalS == -1) {
-        rv = gSocketTransportService->GetKeepaliveRetryInterval(&val);
+        rv = mSocketTransportService->GetKeepaliveRetryInterval(&val);
         if (NS_WARN_IF(NS_FAILED(rv))) {
             return rv;
         }
         mKeepaliveRetryIntervalS = val;
     }
     if (mKeepaliveProbeCount == -1) {
-        rv = gSocketTransportService->GetKeepaliveProbeCount(&val);
+        rv = mSocketTransportService->GetKeepaliveProbeCount(&val);
         if (NS_WARN_IF(NS_FAILED(rv))) {
             return rv;
         }
         mKeepaliveProbeCount = val;
     }
     return NS_OK;
 }
 
@@ -2529,17 +2525,17 @@ nsSocketTransport::SetKeepaliveEnabled(b
         }
     }
     SOCKET_LOG(("nsSocketTransport::SetKeepaliveEnabled [%p] "
                 "%s, idle time[%ds] retry interval[%ds] packet count[%d]: "
                 "globally %s.",
                 this, aEnable ? "enabled" : "disabled",
                 mKeepaliveIdleTimeS, mKeepaliveRetryIntervalS,
                 mKeepaliveProbeCount,
-                gSocketTransportService->IsKeepaliveEnabled() ?
+                mSocketTransportService->IsKeepaliveEnabled() ?
                 "enabled" : "disabled"));
 
     // Set mKeepaliveEnabled here so that state is maintained; it is possible
     // that we're in between fds, e.g. the 1st IP address failed, so we're about
     // to retry on a 2nd from the DNS record.
     mKeepaliveEnabled = aEnable;
 
     rv = SetKeepaliveEnabledInternal(aEnable);
@@ -2578,17 +2574,17 @@ nsSocketTransport::SetKeepaliveVals(int3
         return NS_OK;
     }
     mKeepaliveIdleTimeS = aIdleTime;
     mKeepaliveRetryIntervalS = aRetryInterval;
 
     nsresult rv = NS_OK;
     if (mKeepaliveProbeCount == -1) {
         int32_t val = -1;
-        nsresult rv = gSocketTransportService->GetKeepaliveProbeCount(&val);
+        nsresult rv = mSocketTransportService->GetKeepaliveProbeCount(&val);
         if (NS_WARN_IF(NS_FAILED(rv))) {
             return rv;
         }
         mKeepaliveProbeCount = val;
     }
 
     SOCKET_LOG(("nsSocketTransport::SetKeepaliveVals [%p] "
                 "keepalive %s, idle time[%ds] retry interval[%ds] "
--- a/netwerk/base/src/nsSocketTransport2.h
+++ b/netwerk/base/src/nsSocketTransport2.h
@@ -18,16 +18,17 @@
 #include "nsIAsyncInputStream.h"
 #include "nsIAsyncOutputStream.h"
 #include "nsIDNSListener.h"
 #include "nsIClassInfo.h"
 #include "mozilla/net/DNS.h"
 #include "nsASocketHandler.h"
 
 #include "prerror.h"
+#include "nsAutoPtr.h"
 
 class nsSocketTransport;
 class nsICancelable;
 class nsIDNSRecord;
 class nsIInterfaceRequestor;
 
 nsresult
 ErrorAccordingToNSPR(PRErrorCode errorCode);
@@ -324,16 +325,21 @@ private:
     // socket input/output objects.  these may be accessed on any thread with
     // the exception of some specific methods (XXX).
 
     Mutex            mLock;  // protects members in this section.
     LockedPRFileDesc mFD;
     nsrefcnt         mFDref;       // mFD is closed when mFDref goes to zero.
     bool             mFDconnected; // mFD is available to consumer when TRUE.
 
+    // A delete protector reference to gSocketTransportService held for lifetime
+    // of 'this'. Sometimes used interchangably with gSocketTransportService due
+    // to scoping.
+    nsRefPtr<nsSocketTransportService> mSocketTransportService;
+
     nsCOMPtr<nsIInterfaceRequestor> mCallbacks;
     nsCOMPtr<nsITransportEventSink> mEventSink;
     nsCOMPtr<nsISupports>           mSecInfo;
 
     nsSocketInputStream  mInput;
     nsSocketOutputStream mOutput;
 
     friend class nsSocketInputStream;
--- a/netwerk/base/src/nsSocketTransportService2.cpp
+++ b/netwerk/base/src/nsSocketTransportService2.cpp
@@ -614,28 +614,23 @@ nsSocketTransportService::CreateTranspor
                                           const nsACString &host,
                                           int32_t port,
                                           nsIProxyInfo *proxyInfo,
                                           nsISocketTransport **result)
 {
     NS_ENSURE_TRUE(mInitialized, NS_ERROR_NOT_INITIALIZED);
     NS_ENSURE_TRUE(port >= 0 && port <= 0xFFFF, NS_ERROR_ILLEGAL_VALUE);
 
-    nsSocketTransport *trans = new nsSocketTransport();
-    if (!trans)
-        return NS_ERROR_OUT_OF_MEMORY;
-    NS_ADDREF(trans);
-
+    nsRefPtr<nsSocketTransport> trans = new nsSocketTransport();
     nsresult rv = trans->Init(types, typeCount, host, port, proxyInfo);
     if (NS_FAILED(rv)) {
-        NS_RELEASE(trans);
         return rv;
     }
 
-    *result = trans;
+    trans.forget(result);
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsSocketTransportService::CreateUnixDomainTransport(nsIFile *aPath,
                                                     nsISocketTransport **result)
 {
     nsresult rv;
@@ -643,18 +638,16 @@ nsSocketTransportService::CreateUnixDoma
     NS_ENSURE_TRUE(mInitialized, NS_ERROR_NOT_INITIALIZED);
 
     nsAutoCString path;
     rv = aPath->GetNativePath(path);
     if (NS_FAILED(rv))
         return rv;
 
     nsRefPtr<nsSocketTransport> trans = new nsSocketTransport();
-    if (!trans)
-        return NS_ERROR_OUT_OF_MEMORY;
 
     rv = trans->InitWithFilename(path.get());
     if (NS_FAILED(rv))
         return rv;
 
     trans.forget(result);
     return NS_OK;
 }
--- a/netwerk/base/src/nsStreamLoader.cpp
+++ b/netwerk/base/src/nsStreamLoader.cpp
@@ -13,19 +13,17 @@ nsStreamLoader::nsStreamLoader()
   : mData(nullptr),
     mAllocated(0),
     mLength(0)
 {
 }
 
 nsStreamLoader::~nsStreamLoader()
 {
-  if (mData) {
-    NS_Free(mData);
-  }
+  ReleaseData();
 }
 
 NS_IMETHODIMP
 nsStreamLoader::Init(nsIStreamLoaderObserver* observer)
 {
   NS_ENSURE_ARG_POINTER(observer);
   mObserver = observer;
   return NS_OK;
@@ -98,20 +96,19 @@ nsStreamLoader::OnStopRequest(nsIRequest
     // provide nsIStreamLoader::request during call to OnStreamComplete
     mRequest = request;
     nsresult rv = mObserver->OnStreamComplete(this, mContext, aStatus,
                                               mLength, mData);
     if (rv == NS_SUCCESS_ADOPTED_DATA) {
       // the observer now owns the data buffer, and the loader must
       // not deallocate it
       mData = nullptr;
-      mLength = 0;
-      mAllocated = 0;
     }
     // done.. cleanup
+    ReleaseData();
     mRequest = 0;
     mObserver = 0;
     mContext = 0;
   }
   return NS_OK;
 }
 
 NS_METHOD
@@ -127,18 +124,17 @@ nsStreamLoader::WriteSegmentFun(nsIInput
   if (count > UINT32_MAX - self->mLength) {
     return NS_ERROR_ILLEGAL_VALUE; // is there a better error to use here?
   }
 
   if (self->mLength + count > self->mAllocated) {
     self->mData = static_cast<uint8_t*>(NS_Realloc(self->mData,
                                                    self->mLength + count));
     if (!self->mData) {
-      self->mLength = 0;
-      self->mAllocated = 0;
+      self->ReleaseData();
       return NS_ERROR_OUT_OF_MEMORY;
     }
     self->mAllocated = self->mLength + count;
   }
 
   ::memcpy(self->mData + self->mLength, fromSegment, count);
   self->mLength += count;
 
@@ -150,8 +146,19 @@ nsStreamLoader::WriteSegmentFun(nsIInput
 NS_IMETHODIMP 
 nsStreamLoader::OnDataAvailable(nsIRequest* request, nsISupports *ctxt, 
                                 nsIInputStream *inStr, 
                                 uint64_t sourceOffset, uint32_t count)
 {
   uint32_t countRead;
   return inStr->ReadSegments(WriteSegmentFun, this, count, &countRead);
 }
+
+void
+nsStreamLoader::ReleaseData()
+{
+  if (mData) {
+    NS_Free(mData);
+    mData = nullptr;
+  }
+  mLength = 0;
+  mAllocated = 0;
+}
--- a/netwerk/base/src/nsStreamLoader.h
+++ b/netwerk/base/src/nsStreamLoader.h
@@ -25,16 +25,20 @@ public:
 
   static nsresult
   Create(nsISupports *aOuter, REFNSIID aIID, void **aResult);
 
 protected:
   static NS_METHOD WriteSegmentFun(nsIInputStream *, void *, const char *,
                                    uint32_t, uint32_t, uint32_t *);
 
+  // Utility method to free mData, if present, and update other state to
+  // reflect that no data has been allocated.
+  void ReleaseData();
+
   nsCOMPtr<nsIStreamLoaderObserver> mObserver;
   nsCOMPtr<nsISupports>             mContext;  // the observer's context
   nsCOMPtr<nsIRequest>              mRequest;
 
   uint8_t  *mData;      // buffer to accumulate incoming data
   uint32_t  mAllocated; // allocated size of data buffer (we preallocate if
                         //   contentSize is available)
   uint32_t  mLength;    // actual length of data in buffer
--- a/netwerk/protocol/http/nsHttpConnection.cpp
+++ b/netwerk/protocol/http/nsHttpConnection.cpp
@@ -43,17 +43,16 @@ namespace net {
 //-----------------------------------------------------------------------------
 // nsHttpConnection <public>
 //-----------------------------------------------------------------------------
 
 nsHttpConnection::nsHttpConnection()
     : mTransaction(nullptr)
     , mHttpHandler(gHttpHandler)
     , mCallbacksLock("nsHttpConnection::mCallbacksLock")
-    , mIdleTimeout(0)
     , mConsiderReusedAfterInterval(0)
     , mConsiderReusedAfterEpoch(0)
     , mCurrentBytesRead(0)
     , mMaxBytesRead(0)
     , mTotalBytesRead(0)
     , mTotalBytesWritten(0)
     , mKeepAlive(true) // assume to keep-alive by default
     , mKeepAliveMask(true)
@@ -75,16 +74,22 @@ nsHttpConnection::nsHttpConnection()
     , mReportedSpdy(false)
     , mEverUsedSpdy(false)
     , mLastHttpResponseVersion(NS_HTTP_VERSION_1_1)
     , mTransactionCaps(0)
     , mResponseTimeoutEnabled(false)
     , mTCPKeepaliveConfig(kTCPKeepaliveDisabled)
 {
     LOG(("Creating nsHttpConnection @%x\n", this));
+
+    // the default timeout is for when this connection has not yet processed a
+    // transaction
+    static const PRIntervalTime k5Sec = PR_SecondsToInterval(5);
+    mIdleTimeout =
+        (k5Sec < gHttpHandler->IdleTimeout()) ? k5Sec : gHttpHandler->IdleTimeout();
 }
 
 nsHttpConnection::~nsHttpConnection()
 {
     LOG(("Destroying nsHttpConnection @%x\n", this));
 
     if (!mEverUsedSpdy) {
         LOG(("nsHttpConnection %p performed %d HTTP/1.x transactions\n",
--- a/netwerk/protocol/http/nsHttpConnection.h
+++ b/netwerk/protocol/http/nsHttpConnection.h
@@ -109,17 +109,16 @@ public:
     void     GetConnectionInfo(nsHttpConnectionInfo **ci) { NS_IF_ADDREF(*ci = mConnInfo); }
     nsresult TakeTransport(nsISocketTransport **,
                            nsIAsyncInputStream **,
                            nsIAsyncOutputStream **);
     void     GetSecurityInfo(nsISupports **);
     bool     IsPersistent() { return IsKeepAlive(); }
     bool     IsReused();
     void     SetIsReusedAfter(uint32_t afterMilliseconds);
-    void     SetIdleTimeout(PRIntervalTime val) {mIdleTimeout = val;}
     nsresult PushBack(const char *data, uint32_t length);
     nsresult ResumeSend();
     nsresult ResumeRecv();
     int64_t  MaxBytesRead() {return mMaxBytesRead;}
     uint8_t GetLastHttpResponseVersion() { return mLastHttpResponseVersion; }
 
     friend class nsHttpConnectionForceRecv;
     nsresult ForceRecv();
--- a/netwerk/protocol/http/nsHttpConnectionMgr.cpp
+++ b/netwerk/protocol/http/nsHttpConnectionMgr.cpp
@@ -3062,24 +3062,16 @@ nsHalfOpenSocket::OnOutputStreamReady(ns
         mEnt->mPendingQ.RemoveElementAt(index);
         gHttpHandler->ConnMgr()->AddActiveConn(conn, mEnt);
         rv = gHttpHandler->ConnMgr()->DispatchTransaction(mEnt, temp, conn);
     }
     else {
         // this transaction was dispatched off the pending q before all the
         // sockets established themselves.
 
-        // We need to establish a small non-zero idle timeout so the connection
-        // mgr perceives this socket as suitable for persistent connection reuse
-        const PRIntervalTime k5Sec = PR_SecondsToInterval(5);
-        if (k5Sec < gHttpHandler->IdleTimeout())
-            conn->SetIdleTimeout(k5Sec);
-        else
-            conn->SetIdleTimeout(gHttpHandler->IdleTimeout());
-
         // After about 1 second allow for the possibility of restarting a
         // transaction due to server close. Keep at sub 1 second as that is the
         // minimum granularity we can expect a server to be timing out with.
         conn->SetIsReusedAfter(950);
 
         // if we are using ssl and no other transactions are waiting right now,
         // then form a null transaction to drive the SSL handshake to
         // completion. Afterwards the connection will be 100% ready for the next
--- a/python/mozbuild/mozbuild/config_status.py
+++ b/python/mozbuild/mozbuild/config_status.py
@@ -147,17 +147,17 @@ def config_status(topobjdir='.', topsrcd
     print('Reticulating splines...', file=sys.stderr)
     summary = the_backend.consume(definitions)
 
     for line in summary.summaries():
         print(line, file=sys.stderr)
 
     if options.diff:
         for path, diff in sorted(summary.file_diffs.items()):
-            print(diff)
+            print('\n'.join(diff))
 
     # Advertise Visual Studio if appropriate.
     if os.name == 'nt' and options.backend == 'RecursiveMake':
         print(VISUAL_STUDIO_ADVERTISEMENT)
 
     # Advertise Eclipse if it is appropriate.
     if MachCommandConditions.is_android(env):
         if options.backend == 'RecursiveMake':
--- a/python/mozbuild/mozbuild/test/test_util.py
+++ b/python/mozbuild/mozbuild/test/test_util.py
@@ -123,32 +123,32 @@ class TestFileAvoidWrite(unittest.TestCa
     def test_diff_update(self):
         """Diffs are produced on file update."""
 
         with MockedOpen({'file': 'old'}):
             faw = FileAvoidWrite('file', capture_diff=True)
             faw.write('new')
             faw.close()
 
-            self.assertIsInstance(faw.diff, unicode)
-            self.assertIn('-old', faw.diff)
-            self.assertIn('+new', faw.diff)
+            diff = '\n'.join(faw.diff)
+            self.assertIn('-old', diff)
+            self.assertIn('+new', diff)
 
     def test_diff_create(self):
         """Diffs are produced when files are created."""
 
         tmpdir = tempfile.mkdtemp()
         try:
             path = os.path.join(tmpdir, 'file')
             faw = FileAvoidWrite(path, capture_diff=True)
             faw.write('new')
             faw.close()
 
-            self.assertIsInstance(faw.diff, unicode)
-            self.assertIn('+new', faw.diff)
+            diff = '\n'.join(faw.diff)
+            self.assertIn('+new', diff)
         finally:
             shutil.rmtree(tmpdir)
 
 class TestResolveTargetToMake(unittest.TestCase):
     def setUp(self):
         self.topobjdir = data_path
 
     def assertResolve(self, path, expected):
--- a/python/mozbuild/mozbuild/util.py
+++ b/python/mozbuild/mozbuild/util.py
@@ -162,18 +162,18 @@ class FileAvoidWrite(StringIO):
         with open(self.name, 'w') as file:
             file.write(buf)
 
         if self._capture_diff:
             try:
                 old_lines = old_content.splitlines() if old_content else []
                 new_lines = buf.splitlines()
 
-                self.diff = '\n'.join(difflib.unified_diff(old_lines, new_lines,
-                    self.name, self.name, n=4, lineterm=''))
+                self.diff = difflib.unified_diff(old_lines, new_lines,
+                    self.name, self.name, n=4, lineterm='')
             # FileAvoidWrite isn't unicode/bytes safe. So, files with non-ascii
             # content or opened and written in different modes may involve
             # implicit conversion and this will make Python unhappy. Since
             # diffing isn't a critical feature, we just ignore the failure.
             # This can go away once FileAvoidWrite uses io.BytesIO and
             # io.StringIO. But that will require a lot of work.
             except (UnicodeDecodeError, UnicodeEncodeError):
                 self.diff = 'Binary or non-ascii file changed: %s' % self.name
--- a/security/manager/ssl/public/nsIX509Cert.idl
+++ b/security/manager/ssl/public/nsIX509Cert.idl
@@ -8,17 +8,17 @@
 
 interface nsIArray;
 interface nsIX509CertValidity;
 interface nsIASN1Object;
 
 /**
  * This represents a X.509 certificate.
  */
-[scriptable, uuid(45b24b0a-6189-4b05-af0b-8d4d66d57c59)]
+[scriptable, uuid(6286dd8c-c1a1-11e3-941d-180373d97f24)]
 interface nsIX509Cert : nsISupports {
 
   /**
    *  A nickname for the certificate.
    */
   readonly attribute AString nickname;
 
   /**
@@ -225,9 +225,15 @@ interface nsIX509Cert : nsISupports {
 
   /**
    *  Test whether two certificate instances represent the 
    *  same certificate.
    *
    *  @return Whether the certificates are equal
    */
   boolean equals(in nsIX509Cert other);
+
+  /**
+   * The base64 encoding of the DER encoded public key info using the specified
+   * digest.
+   */
+  readonly attribute ACString sha256SubjectPublicKeyInfoDigest;
 };
--- a/security/manager/ssl/src/nsNSSCallbacks.cpp
+++ b/security/manager/ssl/src/nsNSSCallbacks.cpp
@@ -605,16 +605,20 @@ nsHTTPListener::nsHTTPListener()
 {
 }
 
 nsHTTPListener::~nsHTTPListener()
 {
   if (mResponsibleForDoneSignal)
     send_done_signal();
 
+  if (mResultData) {
+    NS_Free(const_cast<uint8_t *>(mResultData));
+  }
+
   if (mLoader) {
     nsCOMPtr<nsIThread> mainThread(do_GetMainThread());
     NS_ProxyRelease(mainThread, mLoader);
   }
 }
 
 NS_IMPL_ISUPPORTS1(nsHTTPListener, nsIStreamLoaderObserver)
 
@@ -673,17 +677,18 @@ nsHTTPListener::OnStreamComplete(nsIStre
 
   if (NS_SUCCEEDED(rv))
   {
     rv = hchan->GetRequestSucceeded(&mHttpRequestSucceeded);
     if (NS_FAILED(rv))
       mHttpRequestSucceeded = false;
 
     mResultLen = stringLen;
-    mResultData = string; // reference. Make sure loader lives as long as this
+    mResultData = string; // take ownership of allocation
+    aStatus = NS_SUCCESS_ADOPTED_DATA;
 
     unsigned int rcode;
     rv = hchan->GetResponseStatus(&rcode);
     if (NS_FAILED(rv))
       mHttpResponseCode = 500;
     else
       mHttpResponseCode = rcode;
 
--- a/security/manager/ssl/src/nsNSSCallbacks.h
+++ b/security/manager/ssl/src/nsNSSCallbacks.h
@@ -44,17 +44,17 @@ public:
   nsCOMPtr<nsIStreamLoader> mLoader;
 
   nsresult mResultCode;
 
   bool mHttpRequestSucceeded;
   uint16_t mHttpResponseCode;
   nsCString mHttpResponseContentType;
 
-  const uint8_t* mResultData; // not owned, refers to mLoader
+  const uint8_t* mResultData; // allocated in loader, but owned by listener
   uint32_t mResultLen;
   
   mozilla::Mutex mLock;
   mozilla::CondVar mCondition;
   volatile bool mWaitFlag;
   
   bool mResponsibleForDoneSignal;
   void send_done_signal();
--- a/security/manager/ssl/src/nsNSSCertificate.cpp
+++ b/security/manager/ssl/src/nsNSSCertificate.cpp
@@ -35,16 +35,17 @@
 #include "nsThreadUtils.h"
 #include "nsCertVerificationThread.h"
 #include "nsIObjectOutputStream.h"
 #include "nsIObjectInputStream.h"
 #include "nsIProgrammingLanguage.h"
 #include "nsXULAppAPI.h"
 #include "ScopedNSSTypes.h"
 #include "nsProxyRelease.h"
+#include "mozilla/Base64.h"
 
 #include "nspr.h"
 #include "certdb.h"
 #include "secerr.h"
 #include "nssb64.h"
 #include "secasn1.h"
 #include "secder.h"
 #include "ssl.h"
@@ -1073,16 +1074,41 @@ nsNSSCertificate::GetTokenName(nsAString
       if (NS_SUCCEEDED(rv))
         aTokenName = tok;
     }
   }
   return NS_OK;
 }
 
 NS_IMETHODIMP
+nsNSSCertificate::GetSha256SubjectPublicKeyInfoDigest(nsACString& aSha256SPKIDigest)
+{
+  nsNSSShutDownPreventionLock locker;
+  if (isAlreadyShutDown()) {
+    return NS_ERROR_NOT_AVAILABLE;
+  }
+
+  aSha256SPKIDigest.Truncate();
+  Digest digest;
+  nsresult rv = digest.DigestBuf(SEC_OID_SHA256, mCert->derPublicKey.data,
+                                 mCert->derPublicKey.len);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+  rv = Base64Encode(nsDependentCSubstring(
+                      reinterpret_cast<const char*> (digest.get().data),
+                      digest.get().len),
+                    aSha256SPKIDigest);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 nsNSSCertificate::GetRawDER(uint32_t* aLength, uint8_t** aArray)
 {
   nsNSSShutDownPreventionLock locker;
   if (isAlreadyShutDown())
     return NS_ERROR_NOT_AVAILABLE;
 
   if (mCert) {
     *aArray = (uint8_t*)nsMemory::Alloc(mCert->derCert.len);
--- a/security/manager/ssl/src/nsNSSCertificateFakeTransport.cpp
+++ b/security/manager/ssl/src/nsNSSCertificateFakeTransport.cpp
@@ -226,16 +226,23 @@ nsNSSCertificateFakeTransport::GetASN1St
 NS_IMETHODIMP
 nsNSSCertificateFakeTransport::Equals(nsIX509Cert *other, bool *result)
 {
   NS_NOTREACHED("Unimplemented on content process");
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 NS_IMETHODIMP
+nsNSSCertificateFakeTransport::GetSha256SubjectPublicKeyInfoDigest(nsACString_internal&)
+{
+  NS_NOTREACHED("Unimplemented on content process");
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
 nsNSSCertificateFakeTransport::Write(nsIObjectOutputStream* aStream)
 {
   // On a non-chrome process we don't have mCert because we lack
   // nsNSSComponent.  nsNSSCertificateFakeTransport object is used only to carry the
   // certificate serialization.
 
   nsresult rv = aStream->Write32(mCertSerialization->len);
   if (NS_FAILED(rv)) {
--- a/security/pkix/lib/pkixder.h
+++ b/security/pkix/lib/pkixder.h
@@ -88,17 +88,17 @@ public:
     // XXX: this->input = input bug was not caught by tests! Why not?
     //      this->end = end bug was not caught by tests! Why not?
     this->input = data;
     this->end = data + len;
 
     return Success;
   }
 
-  Result Expect(const uint8_t* expected, size_t expectedLen)
+  Result Expect(const uint8_t* expected, uint16_t expectedLen)
   {
     if (EnsureLength(expectedLen) != Success) {
       return Fail(SEC_ERROR_BAD_DER);
     }
     if (memcmp(input, expected, expectedLen)) {
       return Fail(SEC_ERROR_BAD_DER);
     }
     input += expectedLen;
@@ -459,17 +459,17 @@ Integer(Input& input, /*out*/ SECItem& v
 }
 
 inline Result
 Null(Input& input)
 {
   return ExpectTagAndLength(input, NULLTag, 0);
 }
 
-template <size_t Len>
+template <uint16_t Len>
 Result
 OID(Input& input, const uint8_t (&expectedOid)[Len])
 {
   if (ExpectTagAndLength(input, OIDTag, Len) != Success) {
     return Failure;
   }
 
   return input.Expect(expectedOid, Len);
--- a/testing/marionette/client/MANIFEST.in
+++ b/testing/marionette/client/MANIFEST.in
@@ -1,4 +1,6 @@
 recursive-include marionette/touch *.js
+recursive-include marionette/www *
+recursive-include marionette/chrome *
 recursive-include marionette/runner/mixins/resources *
 exclude MANIFEST.in
 include requirements.txt
--- a/testing/marionette/client/marionette/runner/base.py
+++ b/testing/marionette/client/marionette/runner/base.py
@@ -470,16 +470,20 @@ class BaseMarionetteOptions(OptionParser
         self.add_option('--this-chunk',
                         dest='this_chunk',
                         type=int,
                         help='which chunk to run')
         self.add_option('--sources',
                         dest='sources',
                         action='store',
                         help='path to sources.xml (Firefox OS only)')
+        self.add_option('--server-root',
+                        dest='server_root',
+                        action='store',
+                        help='sets the web server\'s root directory to the given path')
 
     def parse_args(self, args=None, values=None):
         options, tests = OptionParser.parse_args(self, args, values)
         for handler in self.parse_args_handlers:
             handler(options, tests, args, values)
 
         return (options, tests)
 
@@ -540,17 +544,18 @@ class BaseMarionetteTestRunner(object):
 
     def __init__(self, address=None, emulator=None, emulatorBinary=None,
                  emulatorImg=None, emulator_res='480x800', homedir=None,
                  app=None, app_args=None, bin=None, profile=None, autolog=False,
                  revision=None, logger=None, testgroup="marionette", noWindow=False,
                  logcat_dir=None, xml_output=None, repeat=0, gecko_path=None,
                  testvars=None, tree=None, type=None, device_serial=None,
                  symbols_path=None, timeout=None, es_servers=None, shuffle=False,
-                 sdcard=None, this_chunk=1, total_chunks=1, sources=None, **kwargs):
+                 sdcard=None, this_chunk=1, total_chunks=1, sources=None, server_root=None,
+                 **kwargs):
         self.address = address
         self.emulator = emulator
         self.emulatorBinary = emulatorBinary
         self.emulatorImg = emulatorImg
         self.emulator_res = emulator_res
         self.homedir = homedir
         self.app = app
         self.app_args = app_args or []
@@ -576,16 +581,17 @@ class BaseMarionetteTestRunner(object):
         self.timeout = timeout
         self._device = None
         self._capabilities = None
         self._appName = None
         self.es_servers = es_servers
         self.shuffle = shuffle
         self.sdcard = sdcard
         self.sources = sources
+        self.server_root = server_root
         self.this_chunk = this_chunk
         self.total_chunks = total_chunks
         self.mixin_run_tests = []
         self.manifest_skipped_tests = []
         self.tests = []
 
         if testvars:
             if not os.path.exists(testvars):
@@ -649,19 +655,22 @@ class BaseMarionetteTestRunner(object):
         self.failed = 0
         self.todo = 0
         self.failures = []
 
     def start_httpd(self, need_external_ip):
         host = "127.0.0.1"
         if need_external_ip:
             host = moznetwork.get_ip()
+        docroot = self.server_root or os.path.join(os.path.dirname(os.path.dirname(__file__)), 'www')
+        if not os.path.isdir(docroot):
+            raise Exception("Server root %s is not a valid path" % docroot)
         self.httpd = MozHttpd(host=host,
                               port=0,
-                              docroot=os.path.join(os.path.dirname(os.path.dirname(__file__)), 'www'))
+                              docroot=docroot)
         self.httpd.start()
         self.marionette.baseurl = 'http://%s:%d/' % (host, self.httpd.httpd.server_port)
         self.logger.info('running webserver on %s' % self.marionette.baseurl)
 
 
     def _build_kwargs(self):
         kwargs = {
             'device_serial': self.device_serial,
--- a/testing/marionette/client/marionette/tests/unit/test_window_management.py
+++ b/testing/marionette/client/marionette/tests/unit/test_window_management.py
@@ -1,13 +1,13 @@
 # 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/.
 
-import os
+import time
 from marionette_test import MarionetteTestCase
 
 class TestSwitchWindow(MarionetteTestCase):
     def open_new_window(self):
         self.marionette.set_context("chrome")
         self.marionette.set_script_timeout(5000)
         self.marionette.execute_async_script("""
 var ww = Components.classes["@mozilla.org/embedcomp/window-watcher;1"]
@@ -55,19 +55,27 @@ if (win != null)
         self.assertEqual(self.marionette.current_window_handle, orig_win)
         self.assertEqual(len(self.marionette.window_handles), len(orig_available))
 
     def testShouldLoadAWindowAndThenCloseIt(self):
         test_html = self.marionette.absolute_url("test_windows.html")
         self.marionette.navigate(test_html)
         current = self.marionette.current_window_handle
 
-        self.marionette.find_element('link text',"Open new window").click()
-        window_handles = self.marionette.window_handles
-        window_handles.remove(current)
+        self.marionette.find_element('link text', "Open new window").click()
+        count = 0
+        while True:
+            window_handles = self.marionette.window_handles
+            window_handles.remove(current)
+            if len(window_handles) > 0:
+                break
+            elif count > 10:
+                self.fail("There were no windows that appeared when we clicked earlier")
+            else:
+                time.sleep(1)
 
         self.marionette.switch_to_window(window_handles[0])
         self.assertEqual(self.marionette.title, "We Arrive Here")
 
         handle = self.marionette.current_window_handle
 
         self.assertEqual(self.marionette.current_window_handle, handle)
         self.assertEqual(2, len(self.marionette.window_handles))
--- a/testing/marionette/client/marionette/tests/unit/unit-tests.ini
+++ b/testing/marionette/client/marionette/tests/unit/unit-tests.ini
@@ -87,17 +87,16 @@ browser = false
 [test_switch_remote_frame.py]
 
 [test_pagesource.py]
 
 [test_visibility.py]
 [test_window_switching.py]
 b2g = false
 [test_window_management.py]
-disabled = "Bug 990299"
 b2g = false
 
 [test_appcache.py]
 [test_screenshot.py]
 [test_cookies.py]
 b2g = false
 [test_window_title.py]
 [test_window_type.py]
--- a/testing/marionette/marionette-server.js
+++ b/testing/marionette/marionette-server.js
@@ -2370,18 +2370,19 @@ MarionetteServerConnection.prototype = {
       case "Marionette:register":
         // This code processes the content listener's registration information
         // and either accepts the listener, or ignores it
         let nullPrevious = (this.curBrowser.curFrameId == null);
         let listenerWindow =
                             Services.wm.getOuterWindowWithId(message.json.value);
 
         //go in here if we're already in a remote frame.
-        if ((!listenerWindow || listenerWindow.location.href != message.json.href) &&
-            (this.curBrowser.frameManager.currentRemoteFrame !== null)) {
+        if ((!listenerWindow || (listenerWindow.location &&
+                                listenerWindow.location.href != message.json.href)) &&
+                (this.curBrowser.frameManager.currentRemoteFrame !== null)) {
           // The outerWindowID from an OOP frame will not be meaningful to
           // the parent process here, since each process maintains its own
           // independent window list.  So, it will either be null (!listenerWindow)
           // if we're already in a remote frame,
           // or it will point to some random window, which will hopefully
           // cause an href mismatch.  Currently this only happens
           // in B2G for OOP frames registered in Marionette:switchToFrame, so
           // we'll acknowledge the switchToFrame message here.
--- a/testing/profiles/prefs_general.js
+++ b/testing/profiles/prefs_general.js
@@ -175,8 +175,17 @@ user_pref("pbackground.testing", true);
 user_pref("browser.webapps.testing", true);
 
 // Disable android snippets
 user_pref("browser.snippets.enabled", false);
 user_pref("browser.snippets.syncPromo.enabled", false);
 
 // Do not turn HTTP cache v2 for our infra tests (some tests are failing)
 user_pref("browser.cache.use_new_backend_temp", false);
+
+// Don't connect to Yahoo! for RSS feed tests.
+// en-US only uses .types.0.uri, but set all of them just to be sure.
+user_pref('browser.contentHandlers.types.0.uri', 'http://test1.example.org/rss?url=%%s')
+user_pref('browser.contentHandlers.types.1.uri', 'http://test1.example.org/rss?url=%%s')
+user_pref('browser.contentHandlers.types.2.uri', 'http://test1.example.org/rss?url=%%s')
+user_pref('browser.contentHandlers.types.3.uri', 'http://test1.example.org/rss?url=%%s')
+user_pref('browser.contentHandlers.types.4.uri', 'http://test1.example.org/rss?url=%%s')
+user_pref('browser.contentHandlers.types.5.uri', 'http://test1.example.org/rss?url=%%s')
--- a/toolkit/components/url-classifier/SafeBrowsing.jsm
+++ b/toolkit/components/url-classifier/SafeBrowsing.jsm
@@ -5,22 +5,29 @@
 this.EXPORTED_SYMBOLS = ["SafeBrowsing"];
 
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 const Cu = Components.utils;
 
 Cu.import("resource://gre/modules/Services.jsm");
 
-const phishingList = Services.prefs.getCharPref("urlclassifier.phish_table");
-const malwareList = Services.prefs.getCharPref("urlclassifier.malware_table");
-const downloadBlockList =
-  Services.prefs.getCharPref("urlclassifier.downloadBlockTable");
-const downloadAllowList =
-  Services.prefs.getCharPref("urlclassifier.downloadAllowTable");
+// Skip all the ones containining "test", because we never need to ask for
+// updates for them.
+function getLists(prefName) {
+  return Services.prefs.getCharPref(prefName).split(",")
+    .filter(function(value) { return value.indexOf("test-") == -1; })
+    .map(function(value) { return value.trim(); });
+}
+
+// These may be a comma-separated lists of tables.
+const phishingLists = getLists("urlclassifier.phish_table");
+const malwareLists = getLists("urlclassifier.malware_table");
+const downloadBlockLists = getLists("urlclassifier.downloadBlockTable");
+const downloadAllowLists = getLists("urlclassifier.downloadAllowTable");
 
 var debug = false;
 function log(...stuff) {
   if (!debug)
     return;
 
   let msg = "SafeBrowsing: " + stuff.join(" ");
   Services.console.logStringMessage(msg);
@@ -36,20 +43,28 @@ this.SafeBrowsing = {
     }
 
     Services.prefs.addObserver("browser.safebrowsing", this.readPrefs.bind(this), false);
     this.readPrefs();
 
     // Register our two types of tables, and add custom Mozilla entries
     let listManager = Cc["@mozilla.org/url-classifier/listmanager;1"].
                       getService(Ci.nsIUrlListManager);
-    listManager.registerTable(phishingList, false);
-    listManager.registerTable(malwareList, false);
-    listManager.registerTable(downloadBlockList, false);
-    listManager.registerTable(downloadAllowList, false);
+    for (let i = 0; i < phishingLists.length; ++i) {
+      listManager.registerTable(phishingLists[i], false);
+    }
+    for (let i = 0; i < malwareLists.length; ++i) {
+      listManager.registerTable(malwareLists[i], false);
+    }
+    for (let i = 0; i < downloadBlockLists.length; ++i) {
+      listManager.registerTable(downloadBlockLists[i], false);
+    }
+    for (let i = 0; i < downloadAllowLists.length; ++i) {
+      listManager.registerTable(downloadAllowLists[i], false);
+    }
     this.addMozEntries();
 
     this.controlUpdateChecking();
     this.initialized = true;
 
     log("init() finished");
   },
 
@@ -124,29 +139,43 @@ this.SafeBrowsing = {
 
 
   controlUpdateChecking: function() {
     log("phishingEnabled:", this.phishingEnabled, "malwareEnabled:", this.malwareEnabled);
 
     let listManager = Cc["@mozilla.org/url-classifier/listmanager;1"].
                       getService(Ci.nsIUrlListManager);
 
-    if (this.phishingEnabled)
-      listManager.enableUpdate(phishingList);
-    else
-      listManager.disableUpdate(phishingList);
-
-    if (this.malwareEnabled) {
-      listManager.enableUpdate(malwareList);
-      listManager.enableUpdate(downloadBlockList);
-      listManager.enableUpdate(downloadAllowList);
-    } else {
-      listManager.disableUpdate(malwareList);
-      listManager.disableUpdate(downloadBlockList);
-      listManager.disableUpdate(downloadAllowList);
+    for (let i = 0; i < phishingLists.length; ++i) {
+      if (this.phishingEnabled) {
+        listManager.enableUpdate(phishingLists[i]);
+      } else {
+        listManager.disableUpdate(phishingLists[i]);
+      }
+    }
+    for (let i = 0; i < malwareLists.length; ++i) {
+      if (this.malwareEnabled) {
+        listManager.enableUpdate(malwareLists[i]);
+      } else {
+        listManager.disableUpdate(malwareLists[i]);
+      }
+    }
+    for (let i = 0; i < downloadBlockLists.length; ++i) {
+      if (this.malwareEnabled) {
+        listManager.enableUpdate(downloadBlockLists[i]);
+      } else {
+        listManager.disableUpdate(downloadBlockLists[i]);
+      }
+    }
+    for (let i = 0; i < downloadAllowLists.length; ++i) {
+      if (this.malwareEnabled) {
+        listManager.enableUpdate(downloadAllowLists[i]);
+      } else {
+        listManager.disableUpdate(downloadAllowLists[i]);
+      }
     }
   },
 
 
   addMozEntries: function() {
     // Add test entries to the DB.
     // XXX bug 779008 - this could be done by DB itself?
     const phishURL   = "itisatrap.org/firefox/its-a-trap.html";
--- a/toolkit/devtools/server/tests/mochitest/test_inspector-release.html
+++ b/toolkit/devtools/server/tests/mochitest/test_inspector-release.html
@@ -26,17 +26,16 @@ var gClient = null;
 
 function assertOwnership() {
   return assertOwnershipTrees(gWalker);
 }
 
 addTest(function setup() {
   let url = document.getElementById("inspectorContent").href;
   attachURL(url, function(err, client, tab, doc) {
-    gInspectee = doc;
     let {InspectorFront} = devtools.require("devtools/server/actors/inspector");
     let inspector = InspectorFront(client, tab);
     promiseDone(inspector.getWalker().then(walker => {
       ok(walker, "getWalker() should return an actor.");
       gClient = client;
       gWalker = walker;
     }).then(runNextTest));
   });
--- a/toolkit/devtools/server/tests/mochitest/test_styles-applied.html
+++ b/toolkit/devtools/server/tests/mochitest/test_styles-applied.html
@@ -23,17 +23,16 @@ window.onload = function() {
 
 var gWalker = null;
 var gStyles = null;
 var gClient = null;
 
 addTest(function setup() {
   let url = document.getElementById("inspectorContent").href;
   attachURL(url, function(err, client, tab, doc) {
-    gInspectee = doc;
     let {InspectorFront} = devtools.require("devtools/server/actors/inspector");
     let inspector = InspectorFront(client, tab);
     promiseDone(inspector.getWalker().then(walker => {
       ok(walker, "getWalker() should return an actor.");
       gClient = client;
       gWalker = walker;
       return inspector.getPageStyle();
     }).then(styles => {
--- a/toolkit/devtools/server/tests/mochitest/test_styles-svg.html
+++ b/toolkit/devtools/server/tests/mochitest/test_styles-svg.html
@@ -24,17 +24,16 @@ window.onload = function() {
 
 var gWalker = null;
 var gStyles = null;
 var gClient = null;
 
 addTest(function setup() {
   let url = document.getElementById("inspectorContent").href;
   attachURL(url, function(err, client, tab, doc) {
-    gInspectee = doc;
     let {InspectorFront} = devtools.require("devtools/server/actors/inspector");
     let inspector = InspectorFront(client, tab);
     promiseDone(inspector.getWalker().then(walker => {
       ok(walker, "getWalker() should return an actor.");
       gClient = client;
       gWalker = walker;
       return inspector.getPageStyle();
     }).then(styles => {
--- a/widget/gonk/ParentProcessController.cpp
+++ b/widget/gonk/ParentProcessController.cpp
@@ -1,17 +1,17 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "ParentProcessController.h"
 #include "nsIContent.h"
 #include "nsLayoutUtils.h"
-#include "APZCCallbackHelper.h"
+#include "mozilla/layers/APZCCallbackHelper.h"
 #include "base/message_loop.h"
 
 namespace mozilla {
 namespace widget {
 
 class RequestContentRepaintEvent : public nsRunnable
 {
     typedef mozilla::layers::FrameMetrics FrameMetrics;
@@ -21,17 +21,17 @@ public:
         : mFrameMetrics(aFrameMetrics)
     {
     }
 
     NS_IMETHOD Run() {
         MOZ_ASSERT(NS_IsMainThread());
         nsCOMPtr<nsIContent> content = nsLayoutUtils::FindContentFor(mFrameMetrics.GetScrollId());
         if (content) {
-            APZCCallbackHelper::UpdateSubFrame(content, mFrameMetrics);
+            mozilla::layers::APZCCallbackHelper::UpdateSubFrame(content, mFrameMetrics);
         }
         return NS_OK;
     }
 
 protected:
     FrameMetrics mFrameMetrics;
 };
 
@@ -49,17 +49,17 @@ ParentProcessController::RequestContentR
         r->Run();
     }
 }
 
 void
 ParentProcessController::AcknowledgeScrollUpdate(const FrameMetrics::ViewID& aScrollId,
                                                  const uint32_t& aScrollGeneration)
 {
-    APZCCallbackHelper::AcknowledgeScrollUpdate(aScrollId, aScrollGeneration);
+    mozilla::layers::APZCCallbackHelper::AcknowledgeScrollUpdate(aScrollId, aScrollGeneration);
 }
 
 void
 ParentProcessController::PostDelayedTask(Task* aTask, int aDelayMs)
 {
     MessageLoop::current()->PostDelayedTask(FROM_HERE, aTask, aDelayMs);
 }
 
--- a/widget/windows/winrt/APZController.cpp
+++ b/widget/windows/winrt/APZController.cpp
@@ -4,17 +4,17 @@
 
 #include "APZController.h"
 #include "base/message_loop.h"
 #include "mozilla/layers/GeckoContentController.h"
 #include "nsThreadUtils.h"
 #include "MetroUtils.h"
 #include "nsPrintfCString.h"
 #include "nsIWidgetListener.h"
-#include "APZCCallbackHelper.h"
+#include "mozilla/layers/APZCCallbackHelper.h"
 #include "nsIDocument.h"
 #include "nsPresContext.h"
 #include "nsIDOMElement.h"
 #include "mozilla/dom/Element.h"
 #include "nsIDOMWindowUtils.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsLayoutUtils.h"
 #include "mozilla/TouchEvents.h"
@@ -109,31 +109,31 @@ public:
     }
 
     // If we're dealing with a sub frame or content editable element,
     // call UpdateSubFrame.
     if (targetContent) {
 #ifdef DEBUG_CONTROLLER
       WinUtils::Log("APZController: detected subframe or content editable");
 #endif
-      APZCCallbackHelper::UpdateSubFrame(targetContent, mFrameMetrics);
+      mozilla::layers::APZCCallbackHelper::UpdateSubFrame(targetContent, mFrameMetrics);
       return NS_OK;
     }
 
 #ifdef DEBUG_CONTROLLER
     WinUtils::Log("APZController: detected tab");
 #endif
 
     // We're dealing with a tab, call UpdateRootFrame.
     nsCOMPtr<nsIDOMWindowUtils> utils;
     nsCOMPtr<nsIDOMWindow> window = subDocument->GetDefaultView();
     if (window) {
       utils = do_GetInterface(window);
       if (utils) {
-        APZCCallbackHelper::UpdateRootFrame(utils, mFrameMetrics);
+        mozilla::layers::APZCCallbackHelper::UpdateRootFrame(utils, mFrameMetrics);
 
 #ifdef DEBUG_CONTROLLER
         WinUtils::Log("APZController: %I64d mDisplayPortMargins: %0.2f %0.2f %0.2f %0.2f",
           mFrameMetrics.GetScrollId(),
           mFrameMetrics.GetDisplayPortMargins().left,
           mFrameMetrics.GetDisplayPortMargins().top,
           mFrameMetrics.GetDisplayPortMargins().right,
           mFrameMetrics.GetDisplayPortMargins().bottom);
@@ -219,17 +219,17 @@ APZController::RequestContentRepaint(con
 void
 APZController::AcknowledgeScrollUpdate(const FrameMetrics::ViewID& aScrollId,
                                        const uint32_t& aScrollGeneration)
 {
 #ifdef DEBUG_CONTROLLER
   WinUtils::Log("APZController::AcknowledgeScrollUpdate scrollid=%I64d gen=%lu",
     aScrollId, aScrollGeneration);
 #endif
-  APZCCallbackHelper::AcknowledgeScrollUpdate(aScrollId, aScrollGeneration);
+  mozilla::layers::APZCCallbackHelper::AcknowledgeScrollUpdate(aScrollId, aScrollGeneration);
 }
 
 void
 APZController::HandleDoubleTap(const CSSPoint& aPoint,
                                int32_t aModifiers,
                                const ScrollableLayerGuid& aGuid)
 {
 }
--- a/widget/xpwidgets/moz.build
+++ b/widget/xpwidgets/moz.build
@@ -1,26 +1,22 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # 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/.
 
 EXPORTS += [
-    'ActiveElementManager.h',
-    'APZCCallbackHelper.h',
     'ContentHelper.h',
     'GfxDriverInfo.h',
     'GfxInfoBase.h',
     'GfxInfoCollector.h',
 ]
 
 UNIFIED_SOURCES += [
-    'ActiveElementManager.cpp',
-    'APZCCallbackHelper.cpp',
     'ContentHelper.cpp',
     'GfxDriverInfo.cpp',
     'GfxInfoBase.cpp',
     'GfxInfoCollector.cpp',
     'GfxInfoWebGL.cpp',
     'InputData.cpp',