Merge mozilla-central to fx-team
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Wed, 16 Oct 2013 13:14:17 +0200
changeset 165745 762cd8723f8dc716f042f0f0af74bbac89340d51
parent 165744 759187c7a9a9bda0b0b0b15e1b3139bf1d0e5c5b (current diff)
parent 165696 c14ca6b27b3007a972bddc75fa42731b071a0466 (diff)
child 165746 cea994e07f34d6acd53396faffd4c56f31e8bffd
push id428
push userbbajaj@mozilla.com
push dateTue, 28 Jan 2014 00:16:25 +0000
treeherdermozilla-release@cd72a7ff3a75 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone27.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge mozilla-central to fx-team
--- a/b2g/config/gaia.json
+++ b/b2g/config/gaia.json
@@ -1,4 +1,4 @@
 {
-    "revision": "e811ee9b89a2a4cbb789fb88e532113dc5105e2a", 
+    "revision": "36aa3e5d226a844b07b3e4b2219f54b549456ec1", 
     "repo_path": "/integration/gaia-central"
 }
--- a/b2g/config/mozconfigs/win32_gecko/nightly
+++ b/b2g/config/mozconfigs/win32_gecko/nightly
@@ -8,20 +8,16 @@ ac_add_options --enable-signmar
 # Nightlies only since this has a cost in performance
 ac_add_options --enable-js-diagnostics
 
 # Needed to enable breakpad in application.ini
 export MOZILLA_OFFICIAL=1
 
 export MOZ_TELEMETRY_REPORTING=1
 
-if test -z "${_PYMAKE}"; then
-  mk_add_options MOZ_MAKE_FLAGS=-j1
-fi
-
 if test "$PROCESSOR_ARCHITECTURE" = "AMD64" -o "$PROCESSOR_ARCHITEW6432" = "AMD64"; then
   . $topsrcdir/build/win32/mozconfig.vs2010-win64
 else
   . $topsrcdir/build/win32/mozconfig.vs2010
 fi
 
 # B2G Options
 ac_add_options --enable-application=b2g
--- a/browser/config/mozconfigs/win32/common-opt
+++ b/browser/config/mozconfigs/win32/common-opt
@@ -13,20 +13,16 @@ fi
 ac_add_options --with-google-api-keyfile=${_gapi_keyfile}
 
 
 # Needed to enable breakpad in application.ini
 export MOZILLA_OFFICIAL=1
 
 export MOZ_TELEMETRY_REPORTING=1
 
-if test -z "${_PYMAKE}"; then
-  mk_add_options MOZ_MAKE_FLAGS=-j1
-fi
-
 if test "$PROCESSOR_ARCHITECTURE" = "AMD64" -o "$PROCESSOR_ARCHITEW6432" = "AMD64"; then
   . $topsrcdir/build/win32/mozconfig.vs2010-win64
 else
   . $topsrcdir/build/win32/mozconfig.vs2010
 fi
 
 # Treat warnings as errors in directories with FAIL_ON_WARNINGS.
 ac_add_options --enable-warnings-as-errors
--- a/browser/config/mozconfigs/win32/debug
+++ b/browser/config/mozconfigs/win32/debug
@@ -3,20 +3,16 @@
 ac_add_options --enable-debug
 ac_add_options --enable-trace-malloc
 ac_add_options --enable-signmar
 ac_add_options --enable-metro
 
 # Needed to enable breakpad in application.ini
 export MOZILLA_OFFICIAL=1
 
-if test -z "${_PYMAKE}"; then
-  mk_add_options MOZ_MAKE_FLAGS=-j1
-fi
-
 if test "$PROCESSOR_ARCHITECTURE" = "AMD64" -o "$PROCESSOR_ARCHITEW6432" = "AMD64"; then
   . $topsrcdir/build/win32/mozconfig.vs2010-win64
 else
   . $topsrcdir/build/win32/mozconfig.vs2010
 fi
 
 # Treat warnings as errors in directories with FAIL_ON_WARNINGS.
 ac_add_options --enable-warnings-as-errors
--- a/browser/config/mozconfigs/win64/common-opt
+++ b/browser/config/mozconfigs/win64/common-opt
@@ -12,14 +12,10 @@ else
 fi
 ac_add_options --with-google-api-keyfile=${_gapi_keyfile}
 
 # Needed to enable breakpad in application.ini
 export MOZILLA_OFFICIAL=1
 
 export MOZ_TELEMETRY_REPORTING=1
 
-if test -z "${_PYMAKE}"; then
-  mk_add_options MOZ_MAKE_FLAGS=-j1
-fi
-
 # Package js shell.
 export MOZ_PACKAGE_JSSHELL=1
--- a/browser/config/mozconfigs/win64/debug
+++ b/browser/config/mozconfigs/win64/debug
@@ -6,18 +6,14 @@ ac_add_options --host=x86_64-pc-mingw32
 ac_add_options --enable-debug
 ac_add_options --enable-trace-malloc
 ac_add_options --enable-signmar
 ac_add_options --enable-metro
 
 # Needed to enable breakpad in application.ini
 export MOZILLA_OFFICIAL=1
 
-if test -z "${_PYMAKE}"; then
-  mk_add_options MOZ_MAKE_FLAGS=-j1
-fi
-
 # Package js shell.
 export MOZ_PACKAGE_JSSHELL=1
 
 . $topsrcdir/build/win64/mozconfig.vs2010
 
 . "$topsrcdir/build/mozconfig.common.override"
--- a/build/mozconfig.vs2010-common
+++ b/build/mozconfig.vs2010-common
@@ -1,8 +1,4 @@
 # Pymake needs Windows-style paths. Use cmd.exe to hack around this.
 mk_export_correct_style() {
-  if test -n "${_PYMAKE}"; then
-    mk_add_options "export $1=$(cmd.exe //c echo %$1%)"
-  else
-    mk_add_options "export $1=$(eval echo \$$1)"
-  fi
+  mk_add_options "export $1=$(cmd.exe //c echo %$1%)"
 }
--- a/client.mk
+++ b/client.mk
@@ -80,23 +80,16 @@ endif
 
 
 ####################################
 # Sanity checks
 
 # Windows checks.
 ifneq (,$(findstring mingw,$(CONFIG_GUESS)))
 
-# Require pymake (as opposed to GNU make).
-ifndef .PYMAKE
-$(error Pymake is required to build on Windows. Run |./mach build| to \
-automatically use pymake. Or, invoke pymake directly via \
-|python build/pymake/make.py|.)
-endif
-
 # check for CRLF line endings
 ifneq (0,$(shell $(PERL) -e 'binmode(STDIN); while (<STDIN>) { if (/\r/) { print "1"; exit } } print "0"' < $(TOPSRCDIR)/client.mk))
 $(error This source tree appears to have Windows-style line endings. To \
 convert it to Unix-style line endings, run \
 "python mozilla/build/win32/mozilla-dos2unix.py")
 endif
 endif
 
@@ -112,17 +105,17 @@ define CR
 
 endef
 
 # As $(shell) doesn't preserve newlines, use sed to replace them with an
 # unlikely sequence (||), which is then replaced back to newlines by make
 # before evaluation. $(shell) replacing newlines with spaces, || is always
 # followed by a space (since sed doesn't remove newlines), except on the
 # last line, so replace both '|| ' and '||'.
-MOZCONFIG_CONTENT := $(subst ||,$(CR),$(subst || ,$(CR),$(shell _PYMAKE=$(.PYMAKE) $(TOPSRCDIR)/$(MOZCONFIG_LOADER) $(TOPSRCDIR) | sed 's/$$/||/')))
+MOZCONFIG_CONTENT := $(subst ||,$(CR),$(subst || ,$(CR),$(shell $(TOPSRCDIR)/$(MOZCONFIG_LOADER) $(TOPSRCDIR) | sed 's/$$/||/')))
 $(eval $(MOZCONFIG_CONTENT))
 
 export FOUND_MOZCONFIG
 
 # As '||' was used as a newline separator, it means it's not occurring in
 # lines themselves. It can thus safely be used to replaces normal spaces,
 # to then replace newlines with normal spaces. This allows to get a list
 # of mozconfig output lines.
--- a/config/baseconfig.mk
+++ b/config/baseconfig.mk
@@ -4,26 +4,25 @@ installdir = $(libdir)/$(MOZ_APP_NAME)-$
 sdkdir = $(libdir)/$(MOZ_APP_NAME)-devel-$(MOZ_APP_VERSION)
 DIST = $(DEPTH)/dist
 
 # We do magic with OBJ_SUFFIX in config.mk, the following ensures we don't
 # manually use it before config.mk inclusion
 _OBJ_SUFFIX := $(OBJ_SUFFIX)
 OBJ_SUFFIX = $(error config/config.mk needs to be included before using OBJ_SUFFIX)
 
-# We only want to do the pymake sanity on Windows, other os's can cope
 ifeq ($(HOST_OS_ARCH),WINNT)
-# Ensure invariants between GNU Make and pymake
-# Checked here since we want the sane error in a file that
-# actually can be found regardless of path-style.
-ifeq (_:,$(.PYMAKE)_$(findstring :,$(srcdir)))
-$(error Windows-style srcdir being used with GNU make. Did you mean to run $(topsrcdir)/build/pymake/make.py instead? [see-also:     https://developer.mozilla.org/en/Gmake_vs._Pymake])
+# We only support building with pymake or a specially built gnu make.
+ifndef .PYMAKE
+ifeq (,$(filter mozmake%,$(notdir $(MAKE))))
+$(error Only building with pymake or mozmake is supported.)
 endif
-ifeq (1_a,$(.PYMAKE)_$(firstword a$(subst /, ,$(srcdir))))
-$(error MSYS-style srcdir being used with Pymake. Did you mean to run GNU Make instead? [see-also: https://developer.mozilla.org/    en/Gmake_vs._Pymake])
+endif
+ifeq (a,$(firstword a$(subst /, ,$(srcdir))))
+$(error MSYS-style srcdir are not supported for Windows builds.)
 endif
 endif # WINNT
 
 ifdef .PYMAKE
 include_deps = $(eval -includedeps $(1))
 else
 include_deps = $(eval -include $(1))
 endif
--- a/config/rules.mk
+++ b/config/rules.mk
@@ -215,23 +215,23 @@ cppunittests-remote:
 	fi
 
 endif # CPP_UNIT_TESTS
 
 .PHONY: check
 
 ifdef PYTHON_UNIT_TESTS
 
-RUN_PYTHON_UNIT_TESTS := $(addprefix run-,$(PYTHON_UNIT_TESTS))
+RUN_PYTHON_UNIT_TESTS := $(addsuffix -run,$(PYTHON_UNIT_TESTS))
 
 .PHONY: $(RUN_PYTHON_UNIT_TESTS)
 
 check:: $(RUN_PYTHON_UNIT_TESTS)
 
-$(RUN_PYTHON_UNIT_TESTS): run-%: %
+$(RUN_PYTHON_UNIT_TESTS): %-run: %
 	@PYTHONDONTWRITEBYTECODE=1 $(PYTHON) $<
 
 endif # PYTHON_UNIT_TESTS
 
 endif # ENABLE_TESTS
 
 
 #
--- a/gfx/2d/DrawTargetCG.cpp
+++ b/gfx/2d/DrawTargetCG.cpp
@@ -1186,16 +1186,21 @@ DrawTargetCG::CopySurface(SourceSurface 
     CGContextResetClip(mCg);
     CGContextSetBlendMode(mCg, kCGBlendModeCopy);
 
     CGContextScaleCTM(mCg, 1, -1);
 
     CGRect flippedRect = CGRectMake(aDestination.x, -(aDestination.y + aSourceRect.height),
                                     aSourceRect.width, aSourceRect.height);
 
+    // Quartz seems to copy A8 surfaces incorrectly if we don't initialize them
+    // to transparent first.
+    if (mFormat == FORMAT_A8) {
+      CGContextClearRect(mCg, flippedRect);
+    }
     CGContextDrawImage(mCg, flippedRect, image);
 
     CGContextRestoreGState(mCg);
 
     CGImageRelease(subimage);
   }
 }
 
--- a/gfx/layers/ImageDataSerializer.cpp
+++ b/gfx/layers/ImageDataSerializer.cpp
@@ -11,16 +11,18 @@
 #include "mozilla/Assertions.h"         // for MOZ_ASSERT, etc
 #include "mozilla/gfx/2D.h"             // for DataSourceSurface, Factory
 #include "mozilla/gfx/Tools.h"          // for GetAlignedStride, etc
 #include "mozilla/mozalloc.h"           // for operator delete, etc
 
 namespace mozilla {
 namespace layers {
 
+using namespace gfx;
+
 // The Data is layed out as follows:
 //
 //  +-------------------+   -++ --+   <-- ImageDataSerializerBase::mData pointer
 //  | SurfaceBufferInfo |     |   |
 //  +-------------------+   --+   | offset
 //  |        ...        |         |
 //  +-------------------+   ------+
 //  |                   |
@@ -31,105 +33,119 @@ namespace layers {
 // Structure written at the beginning of the data blob containing the image
 // (as shown in the figure above). It contains the necessary informations to
 // read the image in the blob.
 namespace {
 struct SurfaceBufferInfo
 {
   uint32_t width;
   uint32_t height;
-  gfx::SurfaceFormat format;
+  SurfaceFormat format;
 
   static uint32_t GetOffset()
   {
-    return gfx::GetAlignedStride<16>(sizeof(SurfaceBufferInfo));
+    return GetAlignedStride<16>(sizeof(SurfaceBufferInfo));
   }
 };
 } // anonymous namespace
 
 static SurfaceBufferInfo*
 GetBufferInfo(uint8_t* aBuffer)
 {
   return reinterpret_cast<SurfaceBufferInfo*>(aBuffer);
 }
 
 
 void
-ImageDataSerializer::InitializeBufferInfo(gfx::IntSize aSize,
-                                          gfx::SurfaceFormat aFormat)
+ImageDataSerializer::InitializeBufferInfo(IntSize aSize,
+                                          SurfaceFormat aFormat)
 {
   SurfaceBufferInfo* info = GetBufferInfo(mData);
   info->width = aSize.width;
   info->height = aSize.height;
   info->format = aFormat;
 }
 
 static inline uint32_t
-ComputeStride(gfx::SurfaceFormat aFormat, uint32_t aWidth)
+ComputeStride(SurfaceFormat aFormat, uint32_t aWidth)
 {
-  return gfx::GetAlignedStride<4>(gfx::BytesPerPixel(aFormat) * aWidth);
+  return GetAlignedStride<4>(BytesPerPixel(aFormat) * aWidth);
 }
 
 uint32_t
-ImageDataSerializer::ComputeMinBufferSize(gfx::IntSize aSize,
-                                          gfx::SurfaceFormat aFormat)
+ImageDataSerializer::ComputeMinBufferSize(IntSize aSize,
+                                          SurfaceFormat aFormat)
 {
   uint32_t bufsize = aSize.height * ComputeStride(aFormat, aSize.width);
   return SurfaceBufferInfo::GetOffset()
-       + gfx::GetAlignedStride<16>(bufsize);
+       + GetAlignedStride<16>(bufsize);
 }
 
 bool
 ImageDataSerializerBase::IsValid() const
 {
   // XXX - We could use some sanity checks here.
   return !!mData;
 }
 
 uint8_t*
 ImageDataSerializerBase::GetData()
 {
   MOZ_ASSERT(IsValid());
   return mData + SurfaceBufferInfo::GetOffset();
 }
 
-gfx::IntSize
+uint32_t
+ImageDataSerializerBase::GetStride() const
+{
+  MOZ_ASSERT(IsValid());
+  SurfaceBufferInfo* info = GetBufferInfo(mData);
+  return ComputeStride(GetFormat(), info->width);
+}
+
+IntSize
 ImageDataSerializerBase::GetSize() const
 {
   MOZ_ASSERT(IsValid());
   SurfaceBufferInfo* info = GetBufferInfo(mData);
-  return gfx::IntSize(info->width, info->height);
+  return IntSize(info->width, info->height);
 }
 
-gfx::SurfaceFormat
+SurfaceFormat
 ImageDataSerializerBase::GetFormat() const
 {
   MOZ_ASSERT(IsValid());
   return GetBufferInfo(mData)->format;
 }
 
 TemporaryRef<gfxImageSurface>
 ImageDataSerializerBase::GetAsThebesSurface()
 {
   MOZ_ASSERT(IsValid());
-  SurfaceBufferInfo* info = GetBufferInfo(mData);
-  uint32_t stride = ComputeStride(GetFormat(), info->width);
-  gfxIntSize size(info->width, info->height);
-  RefPtr<gfxImageSurface> surf =
-    new gfxImageSurface(GetData(), size, stride,
-                        gfx::SurfaceFormatToImageFormat(GetFormat()));
-  return surf.forget();
+  IntSize size = GetSize();
+  return new gfxImageSurface(GetData(),
+                             gfxIntSize(size.width, size.height),
+                             GetStride(),
+                             SurfaceFormatToImageFormat(GetFormat()));
 }
 
-TemporaryRef<gfx::DataSourceSurface>
+TemporaryRef<DrawTarget>
+ImageDataSerializerBase::GetAsDrawTarget()
+{
+  MOZ_ASSERT(IsValid());
+  return gfxPlatform::GetPlatform()->CreateDrawTargetForData(GetData(),
+                                                             GetSize(),
+                                                             GetStride(),
+                                                             GetFormat());
+}
+
+TemporaryRef<DataSourceSurface>
 ImageDataSerializerBase::GetAsSurface()
 {
   MOZ_ASSERT(IsValid());
-  SurfaceBufferInfo* info = GetBufferInfo(mData);
-  gfx::IntSize size(info->width, info->height);
-  uint32_t stride = ComputeStride(GetFormat(), info->width);
-  RefPtr<gfx::DataSourceSurface> surf =
-    gfx::Factory::CreateWrappingDataSourceSurface(GetData(), stride, size, GetFormat());
-  return surf.forget();
+  return Factory::CreateWrappingDataSourceSurface(GetData(),
+                                                  GetStride(),
+                                                  GetSize(),
+                                                  GetFormat());
 }
 
 } // namespace layers
 } // namespace mozilla
--- a/gfx/layers/ImageDataSerializer.h
+++ b/gfx/layers/ImageDataSerializer.h
@@ -14,34 +14,38 @@
 #include "mozilla/gfx/Point.h"          // for IntSize
 #include "mozilla/gfx/Types.h"          // for SurfaceFormat
 
 class gfxImageSurface;
 
 namespace mozilla {
 namespace gfx {
 class DataSourceSurface;
+class DrawTarget;
 } // namespace gfx
 } // namespace mozilla
 
 namespace mozilla {
 namespace layers {
 
 class ImageDataSerializerBase
 {
 public:
   bool IsValid() const;
 
   uint8_t* GetData();
   gfx::IntSize GetSize() const;
   gfx::SurfaceFormat GetFormat() const;
   TemporaryRef<gfx::DataSourceSurface> GetAsSurface();
   TemporaryRef<gfxImageSurface> GetAsThebesSurface();
+  TemporaryRef<gfx::DrawTarget> GetAsDrawTarget();
 
 protected:
+  uint32_t GetStride() const;
+
   ImageDataSerializerBase(uint8_t* aData)
   : mData(aData) {}
   uint8_t* mData;
 };
 
 /**
  * A facility to serialize an image into a buffer of memory.
  * This is intended for use with the IPC code, in order to copy image data
--- a/gfx/layers/client/TextureClient.cpp
+++ b/gfx/layers/client/TextureClient.cpp
@@ -17,26 +17,28 @@
 #include "mozilla/layers/ISurfaceAllocator.h"
 #include "mozilla/layers/ImageDataSerializer.h"
 #include "mozilla/layers/ShadowLayers.h"  // for ShadowLayerForwarder
 #include "mozilla/layers/SharedPlanarYCbCrImage.h"
 #include "mozilla/layers/YCbCrImageDataSerializer.h"
 #include "nsDebug.h"                    // for NS_ASSERTION, NS_WARNING, etc
 #include "nsTraceRefcnt.h"              // for MOZ_COUNT_CTOR, etc
 #include "ImageContainer.h"             // for PlanarYCbCrImage, etc
+#include "mozilla/gfx/2D.h"
 
 #ifdef MOZ_ANDROID_OMTC
 #  include "gfxReusableImageSurfaceWrapper.h"
 #  include "gfxImageSurface.h"
 #else
 #  include "gfxReusableSharedImageSurfaceWrapper.h"
 #  include "gfxSharedImageSurface.h"
 #endif
 
 using namespace mozilla::gl;
+using namespace mozilla::gfx;
 
 namespace mozilla {
 namespace layers {
 
 class ShmemTextureClientData : public TextureClientData
 {
 public:
   ShmemTextureClientData(ipc::Shmem& aShmem)
@@ -254,25 +256,33 @@ BufferTextureClient::UpdateSurface(gfxAS
   MOZ_ASSERT(!IsImmutable());
   MOZ_ASSERT(IsValid());
 
   ImageDataSerializer serializer(GetBuffer());
   if (!serializer.IsValid()) {
     return false;
   }
 
-  RefPtr<gfxImageSurface> surf = serializer.GetAsThebesSurface();
-  if (!surf) {
-    return false;
+  if (gfxPlatform::GetPlatform()->SupportsAzureContent()) {
+    RefPtr<DrawTarget> dt = serializer.GetAsDrawTarget();
+    RefPtr<SourceSurface> source = gfxPlatform::GetPlatform()->GetSourceSurfaceForSurface(dt, aSurface);
+
+    dt->CopySurface(source, IntRect(IntPoint(), serializer.GetSize()), IntPoint());
+  } else {
+    RefPtr<gfxImageSurface> surf = serializer.GetAsThebesSurface();
+    if (!surf) {
+      return false;
+    }
+
+    nsRefPtr<gfxContext> tmpCtx = new gfxContext(surf.get());
+    tmpCtx->SetOperator(gfxContext::OPERATOR_SOURCE);
+    tmpCtx->DrawSurface(aSurface, gfxSize(serializer.GetSize().width,
+                                          serializer.GetSize().height));
   }
 
-  nsRefPtr<gfxContext> tmpCtx = new gfxContext(surf.get());
-  tmpCtx->SetOperator(gfxContext::OPERATOR_SOURCE);
-  tmpCtx->DrawSurface(aSurface, gfxSize(serializer.GetSize().width,
-                                        serializer.GetSize().height));
 
   if (TextureRequiresLocking(mFlags) && !ImplementsLocking()) {
     // We don't have support for proper locking yet, so we'll
     // have to be immutable instead.
     MarkImmutable();
   }
   return true;
 }
--- a/gfx/tests/gtest/TestTextures.cpp
+++ b/gfx/tests/gtest/TestTextures.cpp
@@ -6,18 +6,19 @@
 #include "gtest/gtest.h"
 #include "gmock/gmock.h"
 
 #include "mozilla/layers/TextureClient.h"
 #include "mozilla/layers/TextureHost.h"
 #include "gfx2DGlue.h"
 #include "gfxImageSurface.h"
 #include "gfxTypes.h"
+#include "ImageContainer.h"
+#include "mozilla/layers/YCbCrImageDataSerializer.h"
 
-using namespace gfx;
 using namespace mozilla;
 using namespace mozilla::layers;
 
 /*
  * This test performs the following actions:
  * - creates a surface
  * - initialize a texture client with it
  * - serilaizes the texture client
@@ -68,16 +69,41 @@ void AssertSurfacesEqual(gfxImageSurface
       for (int b = 0; b < bpp; ++b) {
         ASSERT_EQ(data1[y*stride1 + x*bpp + b],
                   data2[y*stride2 + x*bpp + b]);
       }
     }
   }
 }
 
+// Same as above, for YCbCr surfaces
+void AssertYCbCrSurfacesEqual(PlanarYCbCrData* surface1,
+                              PlanarYCbCrData* surface2)
+{
+  ASSERT_EQ(surface1->mYSize, surface2->mYSize);
+  ASSERT_EQ(surface1->mCbCrSize, surface2->mCbCrSize);
+  ASSERT_EQ(surface1->mStereoMode, surface2->mStereoMode);
+  ASSERT_EQ(surface1->mPicSize, surface2->mPicSize);
+
+  for (int y = 0; y < surface1->mYSize.height; ++y) {
+    for (int x = 0; x < surface1->mYSize.width; ++x) {
+      ASSERT_EQ(surface1->mYChannel[y*surface1->mYStride + x*(1+surface1->mYSkip)],
+                surface2->mYChannel[y*surface2->mYStride + x*(1+surface2->mYSkip)]);
+    }
+  }
+  for (int y = 0; y < surface1->mCbCrSize.height; ++y) {
+    for (int x = 0; x < surface1->mCbCrSize.width; ++x) {
+      ASSERT_EQ(surface1->mCbChannel[y*surface1->mCbCrStride + x*(1+surface1->mCbSkip)],
+                surface2->mCbChannel[y*surface2->mCbCrStride + x*(1+surface2->mCbSkip)]);
+      ASSERT_EQ(surface1->mCrChannel[y*surface1->mCbCrStride + x*(1+surface1->mCrSkip)],
+                surface2->mCrChannel[y*surface2->mCbCrStride + x*(1+surface2->mCrSkip)]);
+    }
+  }
+}
+
 // Run the test for a texture client and a surface
 void TestTextureClientSurface(TextureClient* texture, gfxImageSurface* surface) {
 
   // client allocation
   ASSERT_TRUE(texture->AsTextureClientSurface() != nullptr);
   TextureClientSurface* client = texture->AsTextureClientSurface();
   client->AllocateForSurface(ToIntSize(surface->GetSize()));
   ASSERT_TRUE(texture->IsAllocated());
@@ -114,16 +140,84 @@ void TestTextureClientSurface(TextureCli
   host->Unlock();
 
   AssertSurfacesEqual(surface, hostSurface.get());
 
   // host deallocation
   host->DeallocateSharedData();
 }
 
+// Same as above, for YCbCr surfaces
+void TestTextureClientYCbCr(TextureClient* client, PlanarYCbCrData& ycbcrData) {
+
+  // client allocation
+  ASSERT_TRUE(client->AsTextureClientYCbCr() != nullptr);
+  TextureClientYCbCr* texture = client->AsTextureClientYCbCr();
+  texture->AllocateForYCbCr(ToIntSize(ycbcrData.mYSize),
+                            ToIntSize(ycbcrData.mCbCrSize),
+                            ycbcrData.mStereoMode);
+  ASSERT_TRUE(client->IsAllocated());
+
+  // client painting
+  texture->UpdateYCbCr(ycbcrData);
+
+  ASSERT_TRUE(client->Lock(OPEN_READ_ONLY));
+  client->Unlock();
+
+  // client serialization
+  client->SetID(1);
+  SurfaceDescriptor descriptor;
+  ASSERT_TRUE(client->ToSurfaceDescriptor(descriptor));
+
+  ASSERT_NE(descriptor.type(), SurfaceDescriptor::Tnull_t);
+
+  // host deserialization
+  RefPtr<TextureHost> textureHost = CreateBackendIndependentTextureHost(client->GetID(),
+                                                                        descriptor, nullptr,
+                                                                        client->GetFlags());
+
+  RefPtr<BufferTextureHost> host = static_cast<BufferTextureHost*>(textureHost.get());
+
+  ASSERT_TRUE(host.get() != nullptr);
+  ASSERT_EQ(host->GetFlags(), client->GetFlags());
+  ASSERT_EQ(host->GetID(), client->GetID());
+
+  // This will work iff the compositor is not BasicCompositor
+  ASSERT_EQ(host->GetFormat(), mozilla::gfx::FORMAT_YUV);
+
+  // host read
+  ASSERT_TRUE(host->Lock());
+
+  ASSERT_TRUE(host->GetFormat() == mozilla::gfx::FORMAT_YUV);
+
+  YCbCrImageDataDeserializer yuvDeserializer(host->GetBuffer());
+  ASSERT_TRUE(yuvDeserializer.IsValid());
+  PlanarYCbCrData data;
+  data.mYChannel = yuvDeserializer.GetYData();
+  data.mCbChannel = yuvDeserializer.GetCbData();
+  data.mCrChannel = yuvDeserializer.GetCrData();
+  data.mYStride = yuvDeserializer.GetYStride();
+  data.mCbCrStride = yuvDeserializer.GetCbCrStride();
+  data.mStereoMode = yuvDeserializer.GetStereoMode();
+  data.mYSize = yuvDeserializer.GetYSize();
+  data.mCbCrSize = yuvDeserializer.GetCbCrSize();
+  data.mYSkip = 0;
+  data.mCbSkip = 0;
+  data.mCrSkip = 0;
+  data.mPicSize = data.mYSize;
+  data.mPicX = 0;
+  data.mPicY = 0;
+
+  AssertYCbCrSurfacesEqual(&ycbcrData, &data);
+  host->Unlock();
+
+  // host deallocation
+  host->DeallocateSharedData();
+}
+
 TEST(Layers, TextureSerialization) {
   // the test is run on all the following image formats
   gfxImageFormat formats[3] = {
     gfxImageFormatARGB32,
     gfxImageFormatRGB24,
     gfxImageFormatA8,
   };
 
@@ -137,8 +231,43 @@ TEST(Layers, TextureSerialization) {
                                 mozilla::gfx::ImageFormatToSurfaceFormat(surface->Format()),
                                 TEXTURE_FLAGS_DEFAULT);
 
     TestTextureClientSurface(client, surface);
 
     // XXX - Test more texture client types.
   }
 }
+
+TEST(Layers, TextureYCbCrSerialization) {
+  RefPtr<gfxImageSurface> ySurface = new gfxImageSurface(gfxIntSize(400,300), gfxImageFormatA8);
+  RefPtr<gfxImageSurface> cbSurface = new gfxImageSurface(gfxIntSize(200,150), gfxImageFormatA8);
+  RefPtr<gfxImageSurface> crSurface = new gfxImageSurface(gfxIntSize(200,150), gfxImageFormatA8);
+  SetupSurface(ySurface.get());
+  SetupSurface(cbSurface.get());
+  SetupSurface(crSurface.get());
+
+  PlanarYCbCrData clientData;
+  clientData.mYChannel = ySurface->Data();
+  clientData.mCbChannel = cbSurface->Data();
+  clientData.mCrChannel = crSurface->Data();
+  clientData.mYSize = ySurface->GetSize();
+  clientData.mPicSize = ySurface->GetSize();
+  clientData.mCbCrSize = cbSurface->GetSize();
+  clientData.mYStride = ySurface->Stride();
+  clientData.mCbCrStride = cbSurface->Stride();
+  clientData.mStereoMode = STEREO_MODE_MONO;
+  clientData.mYSkip = 0;
+  clientData.mCbSkip = 0;
+  clientData.mCrSkip = 0;
+  clientData.mCrSkip = 0;
+  clientData.mPicX = 0;
+  clientData.mPicX = 0;
+
+  RefPtr<TextureClient> client
+    = new MemoryTextureClient(nullptr,
+                              mozilla::gfx::FORMAT_YUV,
+                              TEXTURE_FLAGS_DEFAULT);
+
+  TestTextureClientYCbCr(client, clientData);
+
+  // XXX - Test more texture client types.
+}
--- a/gfx/thebes/gfxASurface.cpp
+++ b/gfx/thebes/gfxASurface.cpp
@@ -5,16 +5,17 @@
 
 #include "nsIMemoryReporter.h"
 #include "nsMemory.h"
 #include "mozilla/Base64.h"
 #include "mozilla/CheckedInt.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/MemoryReporting.h"
 #include "nsTraceRefcnt.h"
+#include "mozilla/gfx/2D.h"
 
 #include "gfxASurface.h"
 #include "gfxContext.h"
 #include "gfxImageSurface.h"
 #include "gfxPlatform.h"
 #include "gfxRect.h"
 
 #include "cairo.h"
@@ -47,16 +48,17 @@
 #include "nsComponentManagerUtils.h"
 #include "nsISupportsUtils.h"
 #include "nsCOMPtr.h"
 #include "nsServiceManagerUtils.h"
 #include "nsString.h"
 #include "nsIClipboardHelper.h"
 
 using namespace mozilla;
+using namespace mozilla::gfx;
 
 static cairo_user_data_key_t gfxasurface_pointer_key;
 
 gfxASurface::gfxASurface()
  : mSurface(nullptr), mFloatingRefs(0), mBytesRecorded(0),
    mSurfaceValid(false), mAllowUseAsSource(true)
 {
     MOZ_COUNT_CTOR(gfxASurface);
@@ -354,20 +356,27 @@ gfxASurface::CopyToARGB32ImageSurface()
     if (!mSurface || !mSurfaceValid) {
       return nullptr;
     }
 
     const nsIntSize size = GetSize();
     nsRefPtr<gfxImageSurface> imgSurface =
         new gfxImageSurface(size, gfxImageFormatARGB32);
 
-    gfxContext ctx(imgSurface);
-    ctx.SetOperator(gfxContext::OPERATOR_SOURCE);
-    ctx.SetSource(this);
-    ctx.Paint();
+    if (gfxPlatform::GetPlatform()->SupportsAzureContent()) {
+        RefPtr<DrawTarget> dt = gfxPlatform::GetPlatform()->CreateDrawTargetForSurface(imgSurface, IntSize(size.width, size.height));
+        RefPtr<SourceSurface> source = gfxPlatform::GetPlatform()->GetSourceSurfaceForSurface(dt, this);
+
+        dt->CopySurface(source, IntRect(0, 0, size.width, size.height), IntPoint());
+    } else {
+        gfxContext ctx(imgSurface);
+        ctx.SetOperator(gfxContext::OPERATOR_SOURCE);
+        ctx.SetSource(this);
+        ctx.Paint();
+    }
 
     return imgSurface.forget();
 }
 
 int
 gfxASurface::CairoStatus()
 {
     if (!mSurfaceValid)
--- a/gfx/thebes/gfxDrawable.cpp
+++ b/gfx/thebes/gfxDrawable.cpp
@@ -183,16 +183,20 @@ gfxCallbackDrawable::Draw(gfxContext* aC
 
 gfxPatternDrawable::gfxPatternDrawable(gfxPattern* aPattern,
                                        const gfxIntSize aSize)
  : gfxDrawable(aSize)
  , mPattern(aPattern)
 {
 }
 
+gfxPatternDrawable::~gfxPatternDrawable()
+{
+}
+
 class DrawingCallbackFromDrawable : public gfxDrawingCallback {
 public:
     DrawingCallbackFromDrawable(gfxDrawable* aDrawable)
      : mDrawable(aDrawable) {
         NS_ASSERTION(aDrawable, "aDrawable is null!");
     }
 
     virtual ~DrawingCallbackFromDrawable() {}
--- a/gfx/thebes/gfxDrawable.h
+++ b/gfx/thebes/gfxDrawable.h
@@ -118,17 +118,17 @@ protected:
 /**
  * gfxPatternDrawable
  * A convenience implementation of gfxDrawable for patterns.
  */
 class gfxPatternDrawable : public gfxDrawable {
 public:
     gfxPatternDrawable(gfxPattern* aPattern,
                        const gfxIntSize aSize);
-    virtual ~gfxPatternDrawable() {}
+    virtual ~gfxPatternDrawable();
 
     virtual bool Draw(gfxContext* aContext,
                         const gfxRect& aFillRect,
                         bool aRepeat,
                         const GraphicsFilter& aFilter,
                         const gfxMatrix& aTransform = gfxMatrix());
 
 protected:
--- a/gfx/thebes/gfxMacPlatformFontList.h
+++ b/gfx/thebes/gfxMacPlatformFontList.h
@@ -1,26 +1,26 @@
 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef gfxMacPlatformFontList_H_
 #define gfxMacPlatformFontList_H_
 
+#include <CoreFoundation/CoreFoundation.h>
+
 #include "mozilla/MemoryReporting.h"
 #include "nsDataHashtable.h"
 #include "nsRefPtrHashtable.h"
 
 #include "gfxPlatformFontList.h"
 #include "gfxPlatform.h"
 #include "gfxPlatformMac.h"
 
-#include <Carbon/Carbon.h>
-
 #include "nsUnicharUtils.h"
 #include "nsTArray.h"
 
 class gfxMacPlatformFontList;
 
 // a single member of a font family (i.e. a single face, such as Times Italic)
 class MacOSFontEntry : public gfxFontEntry
 {
@@ -96,30 +96,31 @@ private:
     virtual ~gfxMacPlatformFontList();
 
     // initialize font lists
     virtual nsresult InitFontList();
 
     // special case font faces treated as font families (set via prefs)
     void InitSingleFaceList();
 
-    static void ATSNotification(ATSFontNotificationInfoRef aInfo, void* aUserArg);
+    static void RegisteredFontsChangedNotificationCallback(CFNotificationCenterRef center,
+                                                           void *observer,
+                                                           CFStringRef name,
+                                                           const void *object,
+                                                           CFDictionaryRef userInfo);
 
     // search fonts system-wide for a given character, null otherwise
     virtual gfxFontEntry* GlobalFontFallback(const uint32_t aCh,
                                              int32_t aRunScript,
                                              const gfxFontStyle* aMatchStyle,
                                              uint32_t& aCmapCount,
                                              gfxFontFamily** aMatchedFamily);
 
     virtual bool UsesSystemFallback() { return true; }
 
-    // keep track of ATS generation to prevent unneeded updates when loading downloaded fonts
-    uint32_t mATSGeneration;
-
     enum {
         kATSGenerationInitial = -1
     };
 
     // default font for use with system-wide font fallback
     CTFontRef mDefaultFont;
 };
 
--- a/gfx/thebes/gfxMacPlatformFontList.mm
+++ b/gfx/thebes/gfxMacPlatformFontList.mm
@@ -38,17 +38,16 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifdef MOZ_LOGGING
 #define FORCE_PR_LOG /* Allow logging in the release build */
 #endif
 #include "prlog.h"
 
-#include <Carbon/Carbon.h>
 #include <algorithm>
 
 #import <AppKit/AppKit.h>
 
 #include "gfxPlatformMac.h"
 #include "gfxMacPlatformFontList.h"
 #include "gfxMacFont.h"
 #include "gfxUserFontSet.h"
@@ -641,22 +640,25 @@ gfxSingleFaceMacFontFamily::ReadOtherFam
     mOtherFamilyNamesInitialized = true;
 }
 
 
 /* gfxMacPlatformFontList */
 #pragma mark-
 
 gfxMacPlatformFontList::gfxMacPlatformFontList() :
-    gfxPlatformFontList(false), mATSGeneration(uint32_t(kATSGenerationInitial)),
+    gfxPlatformFontList(false),
     mDefaultFont(nullptr)
 {
-    ::ATSFontNotificationSubscribe(ATSNotification,
-                                   kATSFontNotifyOptionDefault,
-                                   (void*)this, nullptr);
+    ::CFNotificationCenterAddObserver(::CFNotificationCenterGetLocalCenter(),
+                                      this,
+                                      RegisteredFontsChangedNotificationCallback,
+                                      kCTFontManagerRegisteredFontsChangedNotification,
+                                      0,
+                                      CFNotificationSuspensionBehaviorDeliverImmediately);
 
     // cache this in a static variable so that MacOSFontFamily objects
     // don't have to repeatedly look it up
     sFontManager = [NSFontManager sharedFontManager];
 }
 
 gfxMacPlatformFontList::~gfxMacPlatformFontList()
 {
@@ -665,29 +667,18 @@ gfxMacPlatformFontList::~gfxMacPlatformF
     }
 }
 
 nsresult
 gfxMacPlatformFontList::InitFontList()
 {
     nsAutoreleasePool localPool;
 
-    ATSGeneration currentGeneration = ::ATSGetGeneration();
-
-    // need to ignore notifications after adding each font
-    if (mATSGeneration == currentGeneration)
-        return NS_OK;
-
     Telemetry::AutoTimer<Telemetry::MAC_INITFONTLIST_TOTAL> timer;
 
-    mATSGeneration = currentGeneration;
-#ifdef PR_LOGGING
-    LOG_FONTLIST(("(fontlist) updating to generation: %d", mATSGeneration));
-#endif
-
     // reset font lists
     gfxPlatformFontList::InitFontList();
     
     // iterate over available families
     NSEnumerator *families = [[sFontManager availableFontFamilies]
                               objectEnumerator];  // returns "canonical", non-localized family name
 
     nsAutoString availableFamilyName;
@@ -772,21 +763,28 @@ gfxMacPlatformFontList::GetStandardFamil
         family->LocalizedName(aFamilyName);
         return true;
     }
 
     return false;
 }
 
 void
-gfxMacPlatformFontList::ATSNotification(ATSFontNotificationInfoRef aInfo,
-                                        void* aUserArg)
+gfxMacPlatformFontList::RegisteredFontsChangedNotificationCallback(CFNotificationCenterRef center,
+                                                                   void *observer,
+                                                                   CFStringRef name,
+                                                                   const void *object,
+                                                                   CFDictionaryRef userInfo)
 {
+    if (!::CFEqual(name, kCTFontManagerRegisteredFontsChangedNotification)) {
+        return;
+    }
+
     // xxx - should be carefully pruning the list of fonts, not rebuilding it from scratch
-    static_cast<gfxMacPlatformFontList*>(aUserArg)->UpdateFontList();
+    static_cast<gfxMacPlatformFontList*>(observer)->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);
 }
 
 gfxFontEntry*
--- a/image/src/ClippedImage.cpp
+++ b/image/src/ClippedImage.cpp
@@ -230,30 +230,39 @@ ClippedImage::GetFrameInternal(const nsI
 
   float frameToDraw = InnerImage()->GetFrameIndex(aWhichFrame);
   if (!mCachedSurface || !mCachedSurface->Matches(aViewportSize,
                                                   aSVGContext,
                                                   frameToDraw,
                                                   aFlags)) {
     // Create a surface to draw into.
     mozilla::RefPtr<mozilla::gfx::DrawTarget> target;
-    target = gfxPlatform::GetPlatform()->
-      CreateOffscreenCanvasDrawTarget(gfx::IntSize(mClip.width, mClip.height),
-                                      gfx::FORMAT_B8G8R8A8);
-    nsRefPtr<gfxASurface> surface = gfxPlatform::GetPlatform()->
-      GetThebesSurfaceForDrawTarget(target);
+    nsRefPtr<gfxContext> ctx;
+
+    if (gfxPlatform::GetPlatform()->SupportsAzureContent()) {
+      target = gfxPlatform::GetPlatform()->
+        CreateOffscreenContentDrawTarget(gfx::IntSize(mClip.width, mClip.height),
+                                        gfx::FORMAT_B8G8R8A8);
+      ctx = new gfxContext(target);
+    } else {
+      target = gfxPlatform::GetPlatform()->
+        CreateOffscreenCanvasDrawTarget(gfx::IntSize(mClip.width, mClip.height),
+                                        gfx::FORMAT_B8G8R8A8);
+      nsRefPtr<gfxASurface> surface = gfxPlatform::GetPlatform()->
+        GetThebesSurfaceForDrawTarget(target);
+      ctx = new gfxContext(surface);
+    }
 
     // Create our callback.
     nsRefPtr<gfxDrawingCallback> drawTileCallback =
       new DrawSingleTileCallback(this, mClip, aViewportSize, aSVGContext, aWhichFrame, aFlags);
     nsRefPtr<gfxDrawable> drawable =
       new gfxCallbackDrawable(drawTileCallback, mClip.Size());
 
     // Actually draw. The callback will end up invoking DrawSingleTile.
-    nsRefPtr<gfxContext> ctx = new gfxContext(surface);
     gfxRect imageRect(0, 0, mClip.width, mClip.height);
     gfxUtils::DrawPixelSnapped(ctx, drawable, gfxMatrix(),
                                imageRect, imageRect, imageRect, imageRect,
                                gfxImageFormatARGB32,
                                GraphicsFilter::FILTER_FAST);
 
     // Cache the resulting surface.
     mCachedSurface = new ClippedImageCachedSurface(target,
--- a/image/src/imgRequest.cpp
+++ b/image/src/imgRequest.cpp
@@ -240,37 +240,67 @@ void imgRequest::CancelAndAbort(nsresult
   // notification callbacks. In that case, make sure to break the cycle between
   // the channel and us, because it won't.
   if (mChannel) {
     mChannel->SetNotificationCallbacks(mPrevChannelSink);
     mPrevChannelSink = nullptr;
   }
 }
 
+class imgRequestMainThreadCancel : public nsRunnable
+{
+public:
+  imgRequestMainThreadCancel(imgRequest *aImgRequest, nsresult aStatus)
+    : mImgRequest(aImgRequest)
+    , mStatus(aStatus)
+  {
+    MOZ_ASSERT(!NS_IsMainThread(), "Create me off main thread only!");
+    MOZ_ASSERT(aImgRequest);
+  }
+
+  NS_IMETHOD Run()
+  {
+    MOZ_ASSERT(NS_IsMainThread(), "I should be running on the main thread!");
+    mImgRequest->ContinueCancel(mStatus);
+    return NS_OK;
+  } 
+private:
+  nsRefPtr<imgRequest> mImgRequest;
+  nsresult mStatus;
+};
+
 void imgRequest::Cancel(nsresult aStatus)
 {
   /* The Cancel() method here should only be called by this class. */
 
   LOG_SCOPE(GetImgLog(), "imgRequest::Cancel");
 
   nsRefPtr<imgStatusTracker> statusTracker = GetStatusTracker();
 
   statusTracker->MaybeUnblockOnload();
 
   statusTracker->RecordCancel();
 
   if (NS_IsMainThread()) {
-    RemoveFromCache();
+    ContinueCancel(aStatus);
   } else {
-    NS_DispatchToMainThread(
-      NS_NewRunnableMethod(this, &imgRequest::RemoveFromCache));
+    NS_DispatchToMainThread(new imgRequestMainThreadCancel(this, aStatus));
   }
+}
 
-  if (mRequest && statusTracker->IsLoading())
-    mRequest->Cancel(aStatus);
+void imgRequest::ContinueCancel(nsresult aStatus)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  RemoveFromCache();
+
+  nsRefPtr<imgStatusTracker> statusTracker = GetStatusTracker();
+  if (mRequest && statusTracker->IsLoading()) {
+     mRequest->Cancel(aStatus);
+  }
 }
 
 nsresult imgRequest::GetURI(ImageURL **aURI)
 {
   MOZ_ASSERT(aURI);
 
   LOG_FUNC(GetImgLog(), "imgRequest::GetURI");
 
--- a/image/src/imgRequest.h
+++ b/image/src/imgRequest.h
@@ -67,16 +67,19 @@ public:
 
   nsresult RemoveProxy(imgRequestProxy *proxy, nsresult aStatus);
 
   // Cancel, but also ensure that all work done in Init() is undone. Call this
   // only when the channel has failed to open, and so calling Cancel() on it
   // won't be sufficient.
   void CancelAndAbort(nsresult aStatus);
 
+  // Called or dispatched by cancel for main thread only execution.
+  void ContinueCancel(nsresult aStatus);
+
   // Methods that get forwarded to the Image, or deferred until it's
   // instantiated.
   nsresult LockImage();
   nsresult UnlockImage();
   nsresult StartDecoding();
   nsresult RequestDecode();
 
   inline void SetInnerWindowID(uint64_t aInnerWindowId) {
--- a/image/src/imgTools.cpp
+++ b/image/src/imgTools.cpp
@@ -18,18 +18,21 @@
 #include "nsComponentManagerUtils.h"
 #include "nsStreamUtils.h"
 #include "nsNetUtil.h"
 #include "nsContentUtils.h"
 #include "ImageFactory.h"
 #include "Image.h"
 #include "ScriptedNotificationObserver.h"
 #include "imgIScriptedNotificationObserver.h"
+#include "gfxPlatform.h"
 
+using namespace mozilla;
 using namespace mozilla::image;
+using namespace mozilla::gfx;
 
 /* ========== imgITools implementation ========== */
 
 
 
 NS_IMPL_ISUPPORTS1(imgTools, imgITools)
 
 imgTools::imgTools()
@@ -139,27 +142,43 @@ NS_IMETHODIMP imgTools::EncodeScaledImag
     aScaledWidth = frameWidth;
   } else if (aScaledHeight == 0) {
     aScaledHeight = frameHeight;
   }
 
   // Create a temporary image surface
   nsRefPtr<gfxImageSurface> dest = new gfxImageSurface(gfxIntSize(aScaledWidth, aScaledHeight),
                                                        gfxImageFormatARGB32);
-  gfxContext ctx(dest);
+  if (gfxPlatform::GetPlatform()->SupportsAzureContent()) {
+    RefPtr<DrawTarget> dt =
+      gfxPlatform::GetPlatform()->CreateDrawTargetForSurface(dest, IntSize(aScaledWidth, aScaledHeight));
+    RefPtr<SourceSurface> source = gfxPlatform::GetPlatform()->GetSourceSurfaceForSurface(dt, frame);
+
+    dt->DrawSurface(source,
+                    Rect(0, 0, aScaledWidth, aScaledHeight),
+                    Rect(0, 0, frameWidth, frameHeight),
+                    DrawSurfaceOptions(),
+                    DrawOptions(1.0f, OP_SOURCE));
+  } else {
+    gfxContext ctx(dest);
 
-  // Set scaling
-  gfxFloat sw = (double) aScaledWidth / frameWidth;
-  gfxFloat sh = (double) aScaledHeight / frameHeight;
-  ctx.Scale(sw, sh);
+    // Set scaling
+    gfxFloat sw = (double) aScaledWidth / frameWidth;
+    gfxFloat sh = (double) aScaledHeight / frameHeight;
+    ctx.Scale(sw, sh);
 
-  // Paint a scaled image
-  ctx.SetOperator(gfxContext::OPERATOR_SOURCE);
-  ctx.SetSource(frame);
-  ctx.Paint();
+    // Paint a scaled image
+    ctx.SetOperator(gfxContext::OPERATOR_SOURCE);
+
+    nsRefPtr<gfxPattern> pat = new gfxPattern(frame);
+    pat->SetExtend(gfxPattern::EXTEND_PAD);
+    ctx.SetPattern(pat);
+    ctx.Paint();
+  }
+
 
   return EncodeImageData(dest, aMimeType, aOutputOptions, aStream);
 }
 
 NS_IMETHODIMP imgTools::EncodeCroppedImage(imgIContainer *aContainer,
                                            const nsACString& aMimeType,
                                            int32_t aOffsetX,
                                            int32_t aOffsetY,
index 421b9ce30d13399ab7520119b5edb9f737eb2319..58497e3fa006eb6fc457aec0c05eedd7035fa20f
GIT binary patch
literal 2285
zc$@+42om>+P)<h;3K|Lk000e1NJLTq001BW001Be1^@s6b9#F8000QINkl<ZScT1(
zZA@HM8pr?4oerEbGNmI3<*qPgm_mUL(-A5*^>*nS6s82|P#OU{xHF>&4x}%L6_K{I
zL)(>teWS}#ERY(sR0*bj&|F@&apRIqccXDvv(e}#nl+n=o0>K8!+$@_g{@6Z*OzSe
zNltQ-d+vRH_y0WSInM$9pDh>+nu5Wgy}7wrDJ(2htVu~qZcL2gFd7wy)v9dSvPEfa
zZB@>mJ*!MkPAYSAbN2c9dDG7cU_W~FXm3+fle&KWdNm_CS+&Q+s7|9%b!KF!+qP{}
zTUuJw)2C0XlarI`%*;&h+}xb~M>`~Gx_R@aeRg(M@pwFnd&iDI)1Ez{$15u6&dFh!
z*~~J7f#pK5T9(<6pU-_ecd|PW;F<1jp6>1rJylf|a625zP=EgqSLEi+oA$51`l@$!
zc2@OxJZj;ZHK9#bYq&log(u?TIAAa^sME1Wk~k;?&&9{{pe*z8j11Q1<gnak3qNc!
zh1_|0>fotU|GgsP<Kw20krDf=uU-vIO-+T)_w})E`*s$|GE0P@58wd6aex;9j!NJ=
z0(@J5$0X1La67>DIvt$`1Gi;ov%RH-FTVJq+TY)=+!bJCWW+u^JlfmU)g7v=tO{>g
zyOx#7$!rjU`z48;06PJ80XzcmB>{dQgYU`UIRUmJ0#Rl#&}lYvwZ*~*91cGC;Dc&m
zVd32Y+S@ynr=NaSedLjPS}ZFmOA=jCQEUfz5#SiWlK_uM;0pr0YzA+ng7Y#sAiz#Y
z?1bQxu?Z|nw{g{~RZL1sV#=~*p)w%?=K=cw@cp@vnVG9(XXmIE%SzsJPuwCvH^A!v
z{|rzCI3>VqGI%W&oHB!B0z4^!Cm}cnndg?TVMBq!4I4Ia)v8s@PfQH&6(TeM^qvRq
zoC|urUP(wu2v{tZkSxnI8jVbqB<_le;u(M+0sI=^rvPsVa9RehXwv^$0{a9wBm}1<
znO99Y?6ntie?b8o($m>wHnZPg;4lz64g@+J4rToI-J#d(Rg1+Es;H<4yId~HvP_#K
zu`w!&FKdp!)gV5Uz;OW{7vM7zctn7gWpGNCI4%TVUlPaPo6P*<^5uLtHkQ{72F~bo
zyaI%~fY7sfdFuG>yQ8S6h^3{atgo+U#f}}!kY(mC(ee4E;9COxLIS@5_$9#i0KTs6
zgg$^51$bQs-;u#l0bT}p1K<|`!`eF^Yhk<y@T}F!SDKnQ9t?)|@7WVbOG{HQJw43}
z7cQ{8yqsBSY0Qj`rE4iTAcG+p42#Hzt^<5qgZL}J4*`BGfnN&n0|CAyMW8MNd<$Sm
zbN=NmAb&6#`I^<rp4{AUiOm+WSS;#y0Gz3*+`M!t0|I<Q20xX-uLbxSz$@DL3?OeC
zA8LvO0PfZ4csM$m!^@U&)@0(}mn>Oa_k{-6BLvH3nNFLH-w8pp%f<HOWDZK;`y%4}
zTM7IG;HWk}xdXrrfcpS$)ajUSFmPjHB0X!@@{HZik4&b;bzx1J(b!l9($nc)vnB%I
za=F;h(7@J;3O<vP!U2HunsndX@`pVDX90c=@LzWTcu1$C#b981Vj>@2yOu5M*6~f7
zjUOc^^Dpu7{F4y8E=hb@2tF&z^x160^z<}`hK5*MTT3M;hsAMmi>3Fv2C?9vR)e^v
zLEIjKM>L4s=x7!!TgFP8ja|jXJX2Q2UZ<1&vdoJ@@QfsJzYz2pjS+xLmoCxo_w$$Q
z*3ohAz1*bJ@#$M){yxA%02=|m0PyN9N%pZezp6cJ1h^AmDZq-vMEZ-0*iu!+rjimi
z6*$?lBAx-0flnlw=}S(IgrKIThKCOyX4}4fEXc{B!(d>ePPZ8Ih2)vi)L3wMQ5y?D
zH?%e903HO`6dldR#6&jP?QE&4;-l4NEG$T7f!)mNqC)!0$|3;O)z$3i=wKiaU~X<M
zR|`SEBrO6gRKicS`QHFe06Z2I#TLDuoq9bdqoVk`B}@2*$;3<d-N&Ak6dp`W=Kkn-
z29i_xMA=qW?{RV6&U`*l`9Qd;zAEJPdL!F#aBz^-)z!?(%3?x70&|66t0XOkV4)Iz
zt<C=d@Lhms^?Ftsjoe@~vPQ4x6DAV_c02cN-O9GgN<LRq#$$<2J`-<cwKJ6!JM;PE
zzQ=f=t3A}()*A47y^%sRFfhQ<(o$w+Wzp$$a{KDlY>tcLIe_onA?yE%$N@F1*R$AY
zq|I#RLn~HrYgSgceDmf|U0t2p+}x~o)_B!Zzu2sH8Z*?g45R9DWvWMx98`ygM|(#`
zM!s8$Yin!S($d0X$Bwb<si#<PwbBFd_#Lu-0bnF5idA|&A6l`3yEbp;uXgVa)$iIB
zsH>|}nwy)Ij@@3RU*4j07_ExSYE)dVOy%g&c4cH_#6CVg{-49hYPG6fuUGBs>kEyI
zjfHy;9b!dxHg_P>fLyyph0g(gpmjvQiPf=E7`Wm7`@?(O?$Ch)2YTDu+J0D5s@Llk
ztJSJ_y<R043<i37dO~}BJ{GTB$$BlTZ*_hRk&b9o2D{S@+$x)yla?0RwsB*it*y=8
z*4Fmp+w$Ybk1N4oP~F?u$l~m5J}Ly?l%&OqxRCuX2=IsuKA9QIqMUTv?RGUcH}~$X
z*WGMlVnUgim{5C9oM1(9F)L-6{X#5O#D(nttpxf7Semk&C4~hnE-qF}N=kk@z}(!N
zeP(8+cW`h}b-UfF+u;bE%*zYEZng4;(a86;v)~Lsmrlq0q$IjFZDLJLjk<gH?w<}Y
zKR<7po13!_4Gk%7w_AD6?+?7v(-V5FsflA&D+d9dMdZlMHyD_in#vuerSy0_s>kE`
z=>WIef+DY-I;Eb<%Tu2R)aL>9F-cN0V`5Z`#iEv%m#aRXuh;MQ|M)A}_t}CXll}cl
zzr&#%0+d65;sKP*m>4B3ElqK`T#DcCxBGm)pYKxozqEe?4Z#qjs*EUi00000NkvXX
Hu0mjf-V|(k
--- a/image/test/unit/test_imgtools.js
+++ b/image/test/unit/test_imgtools.js
@@ -284,17 +284,17 @@ testdesc = "test encoding a scaled PNG";
 // we'll reuse the container from the previous test
 istream = imgTools.encodeScaledImage(container, "image/png", 32, 32);
 encodedBytes = streamToArray(istream);
 
 // Get bytes for exected result
 refName = "image3ico32x32.png";
 refFile = do_get_file(refName);
 istream = getFileInputStream(refFile);
-do_check_eq(istream.available(), 2281);
+do_check_eq(istream.available(), 2285);
 referenceBytes = streamToArray(istream);
 
 // compare the encoder's output to the reference file.
 compareArrays(encodedBytes, referenceBytes);
 
 
 /* ========== 9 ========== */
 testnum++;
--- a/js/src/config/baseconfig.mk
+++ b/js/src/config/baseconfig.mk
@@ -11,26 +11,25 @@ DIST = $(DEPTH)/$(TOP_DIST)
 endif
 endif
 
 # We do magic with OBJ_SUFFIX in config.mk, the following ensures we don't
 # manually use it before config.mk inclusion
 _OBJ_SUFFIX := $(OBJ_SUFFIX)
 OBJ_SUFFIX = $(error config/config.mk needs to be included before using OBJ_SUFFIX)
 
-# We only want to do the pymake sanity on Windows, other os's can cope
 ifeq ($(HOST_OS_ARCH),WINNT)
-# Ensure invariants between GNU Make and pymake
-# Checked here since we want the sane error in a file that
-# actually can be found regardless of path-style.
-ifeq (_:,$(.PYMAKE)_$(findstring :,$(srcdir)))
-$(error Windows-style srcdir being used with GNU make. Did you mean to run $(topsrcdir)/build/pymake/make.py instead? [see-also:     https://developer.mozilla.org/en/Gmake_vs._Pymake])
+# We only support building with pymake or a specially built gnu make.
+ifndef .PYMAKE
+ifeq (,$(filter mozmake%,$(notdir $(MAKE))))
+$(error Only building with pymake or mozmake is supported.)
 endif
-ifeq (1_a,$(.PYMAKE)_$(firstword a$(subst /, ,$(srcdir))))
-$(error MSYS-style srcdir being used with Pymake. Did you mean to run GNU Make instead? [see-also: https://developer.mozilla.org/    en/Gmake_vs._Pymake])
+endif
+ifeq (a,$(firstword a$(subst /, ,$(srcdir))))
+$(error MSYS-style srcdir are not supported for Windows builds.)
 endif
 endif # WINNT
 
 ifdef .PYMAKE
 include_deps = $(eval -includedeps $(1))
 else
 include_deps = $(eval -include $(1))
 endif
--- a/js/src/config/rules.mk
+++ b/js/src/config/rules.mk
@@ -215,23 +215,23 @@ cppunittests-remote:
 	fi
 
 endif # CPP_UNIT_TESTS
 
 .PHONY: check
 
 ifdef PYTHON_UNIT_TESTS
 
-RUN_PYTHON_UNIT_TESTS := $(addprefix run-,$(PYTHON_UNIT_TESTS))
+RUN_PYTHON_UNIT_TESTS := $(addsuffix -run,$(PYTHON_UNIT_TESTS))
 
 .PHONY: $(RUN_PYTHON_UNIT_TESTS)
 
 check:: $(RUN_PYTHON_UNIT_TESTS)
 
-$(RUN_PYTHON_UNIT_TESTS): run-%: %
+$(RUN_PYTHON_UNIT_TESTS): %-run: %
 	@PYTHONDONTWRITEBYTECODE=1 $(PYTHON) $<
 
 endif # PYTHON_UNIT_TESTS
 
 endif # ENABLE_TESTS
 
 
 #
--- a/js/src/configure.in
+++ b/js/src/configure.in
@@ -4192,26 +4192,28 @@ if test -n "$ENABLE_INTL_API" -a -z "$MO
     # don't include obsolete header files
     ICU_CPPFLAGS="$ICU_CPPFLAGS -DU_NO_DEFAULT_INCLUDE_UTF_HEADERS=1"
     # remove chunks of the library that we don't need (yet)
     ICU_CPPFLAGS="$ICU_CPPFLAGS -DUCONFIG_NO_LEGACY_CONVERSION"
     ICU_CPPFLAGS="$ICU_CPPFLAGS -DUCONFIG_NO_TRANSLITERATION"
     ICU_CPPFLAGS="$ICU_CPPFLAGS -DUCONFIG_NO_REGULAR_EXPRESSIONS"
     ICU_CPPFLAGS="$ICU_CPPFLAGS -DUCONFIG_NO_BREAK_ITERATION"
 
+    ICU_SRCDIR=""
     # Set OS dependent options for ICU
     case "$OS_TARGET" in
         Darwin)
             ICU_TARGET=MacOSX
             ;;
         Linux)
             ICU_TARGET=Linux
             ;;
         WINNT)
             ICU_TARGET=MSYS/MSVC
+            ICU_SRCDIR="--srcdir=$(cd $srcdir/../../intl/icu/source; pwd -W)"
             ;;
         DragonFly|FreeBSD|NetBSD|OpenBSD)
             ICU_TARGET=BSD
             ;;
     esac
 
     # To reduce library size, use static linking
     ICU_LINK_OPTS="--enable-static --disable-shared"
@@ -4235,16 +4237,18 @@ if test -n "$ENABLE_INTL_API" -a -z "$MO
     (cd $_objdir/intl/icu
      MOZ_SUBCONFIGURE_WRAP([.],[
      CC="$CC" CXX="$CXX" \
      CFLAGS="$ICU_CFLAGS" CPPFLAGS="$ICU_CPPFLAGS" CXXFLAGS="$ICU_CXXFLAGS" \
             $SHELL $abs_srcdir/../../intl/icu/source/runConfigureICU \
             $ICU_BUILD_OPTS \
             $ICU_TARGET \
             $ICU_LINK_OPTS \
+dnl Shell quoting is fun.
+            ${ICU_SRCDIR+"$ICU_SRCDIR"} \
             --enable-extras=no --enable-icuio=no  --enable-layout=no \
             --enable-tests=no --enable-samples=no || exit 1
      ])
     ) || exit 1
 fi
 
 
 dnl ========================================================
--- a/js/src/jit/IonMacroAssembler.cpp
+++ b/js/src/jit/IonMacroAssembler.cpp
@@ -473,16 +473,20 @@ MacroAssembler::loadFromTypedArray(int a
         load32(src, dest.gpr());
         break;
       case ScalarTypeRepresentation::TYPE_UINT32:
         if (dest.isFloat()) {
             load32(src, temp);
             convertUInt32ToDouble(temp, dest.fpu());
         } else {
             load32(src, dest.gpr());
+
+            // Bail out if the value doesn't fit into a signed int32 value. This
+            // is what allows MLoadTypedArrayElement to have a type() of
+            // MIRType_Int32 for UInt32 array loads.
             test32(dest.gpr(), dest.gpr());
             j(Assembler::Signed, fail);
         }
         break;
       case ScalarTypeRepresentation::TYPE_FLOAT32:
         if (LIRGenerator::allowFloat32Optimizations()) {
             loadFloat(src, dest.fpu());
             canonicalizeFloat(dest.fpu());
--- a/js/src/jit/LIR-Common.h
+++ b/js/src/jit/LIR-Common.h
@@ -2022,18 +2022,18 @@ class LBitOpI : public LInstructionHelpe
   public:
     LIR_HEADER(BitOpI)
 
     LBitOpI(JSOp op)
       : op_(op)
     { }
 
     const char *extraName() const {
-        if (bitop() == JSOP_URSH && mir_->toUrsh()->canOverflow())
-            return "UrshCanOverflow";
+        if (bitop() == JSOP_URSH && mir_->toUrsh()->bailoutsDisabled())
+            return "ursh:BailoutsDisabled";
         return js_CodeName[op_];
     }
 
     JSOp bitop() const {
         return op_;
     }
 };
 
--- a/js/src/jit/Lowering.cpp
+++ b/js/src/jit/Lowering.cpp
@@ -2701,16 +2701,17 @@ LIRGenerator::visitGuardString(MGuardStr
 
 bool
 LIRGenerator::visitAssertRange(MAssertRange *ins)
 {
     MDefinition *input = ins->input();
     LInstruction *lir = nullptr;
 
     switch (input->type()) {
+      case MIRType_Boolean:
       case MIRType_Int32:
         lir = new LAssertRangeI(useRegisterAtStart(input));
         break;
 
       case MIRType_Double:
         lir = new LAssertRangeD(useRegister(input), tempFloat());
         break;
 
--- a/js/src/jit/MIR.cpp
+++ b/js/src/jit/MIR.cpp
@@ -1461,19 +1461,19 @@ bool
 MMul::canOverflow()
 {
     if (isTruncated())
         return false;
     return !range() || !range()->hasInt32Bounds();
 }
 
 bool
-MUrsh::canOverflow()
+MUrsh::fallible()
 {
-    if (!canOverflow_)
+    if (bailoutsDisabled())
         return false;
     return !range() || !range()->hasInt32Bounds();
 }
 
 static inline bool
 KnownNonStringPrimitive(MDefinition *op)
 {
     return !op->mightBeType(MIRType_Object)
@@ -2008,17 +2008,24 @@ MUrsh::New(MDefinition *left, MDefinitio
     return new MUrsh(left, right);
 }
 
 MUrsh *
 MUrsh::NewAsmJS(MDefinition *left, MDefinition *right)
 {
     MUrsh *ins = new MUrsh(left, right);
     ins->specializeForAsmJS();
-    ins->canOverflow_ = false;
+
+    // Since Ion has no UInt32 type, we use Int32 and we have a special
+    // exception to the type rules: we can return values in
+    // (INT32_MIN,UINT32_MAX] and still claim that we have an Int32 type
+    // without bailing out. This is necessary because Ion has no UInt32
+    // type and we can't have bailouts in asm.js code.
+    ins->bailoutsDisabled_ = true;
+
     return ins;
 }
 
 MResumePoint *
 MResumePoint::New(MBasicBlock *block, jsbytecode *pc, MResumePoint *parent, Mode mode)
 {
     MResumePoint *resume = new MResumePoint(block, pc, parent, mode);
     if (!resume->init())
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -354,16 +354,20 @@ class MDefinition : public MNode
     void setTrackedPc(jsbytecode *pc) {
         trackedPc_ = pc;
     }
 
     jsbytecode *trackedPc() {
         return trackedPc_;
     }
 
+    // Return the range of this value, *before* any bailout checks. Contrast
+    // this with the type() method, and the Range constructor which takes an
+    // MDefinition*, which describe the value *after* any bailout checks.
+    //
     // Warning: Range analysis is removing the bit-operations such as '| 0' at
     // the end of the transformations. Using this function to analyse any
     // operands after the truncate phase of the range analysis will lead to
     // errors. Instead, one should define the collectRangeInfo() to set the
     // right set of flags which are dependent on the range of the inputs.
     Range *range() const {
         JS_ASSERT(type() != MIRType_None);
         return range_;
@@ -433,16 +437,22 @@ class MDefinition : public MNode
     }\
     void set##flag##Unchecked() {\
         setFlags(1 << flag);\
     }
 
     MIR_FLAG_LIST(FLAG_ACCESSOR)
 #undef FLAG_ACCESSOR
 
+    // Return the type of this value. This may be speculative, and enforced
+    // dynamically with the use of bailout checks. If all the bailout checks
+    // pass, the value will have this type.
+    //
+    // Unless this is an MUrsh, which, as a special case, may return a value
+    // in (INT32_MAX,UINT32_MAX] even when its type() is MIRType_Int32.
     MIRType type() const {
         return resultType_;
     }
 
     types::TemporaryTypeSet *resultTypeSet() const {
         return resultTypeSet_;
     }
     bool emptyResultTypeSet() const;
@@ -543,17 +553,18 @@ class MDefinition : public MNode
     }
 
   public:
     // Opcode testing and casts.
 #   define OPCODE_CASTS(opcode)                                             \
     bool is##opcode() const {                                               \
         return op() == Op_##opcode;                                         \
     }                                                                       \
-    inline M##opcode *to##opcode();
+    inline M##opcode *to##opcode();                                         \
+    inline const M##opcode *to##opcode() const;
     MIR_OPCODE_LIST(OPCODE_CASTS)
 #   undef OPCODE_CASTS
 
     inline MInstruction *toInstruction();
     bool isInstruction() const {
         return !isPhi();
     }
 
@@ -3227,21 +3238,21 @@ class MRsh : public MShiftInstruction
         // x >> 0 => x
         return getOperand(0);
     }
     void computeRange();
 };
 
 class MUrsh : public MShiftInstruction
 {
-    bool canOverflow_;
+    bool bailoutsDisabled_;
 
     MUrsh(MDefinition *left, MDefinition *right)
       : MShiftInstruction(left, right),
-        canOverflow_(true)
+        bailoutsDisabled_(false)
     { }
 
   public:
     INSTRUCTION_HEADER(Ursh)
     static MUrsh *New(MDefinition *left, MDefinition *right);
     static MUrsh *NewAsmJS(MDefinition *left, MDefinition *right);
 
     MDefinition *foldIfZero(size_t operand) {
@@ -3249,21 +3260,21 @@ class MUrsh : public MShiftInstruction
         if (operand == 0)
             return getOperand(0);
 
         return this;
     }
 
     void infer(BaselineInspector *inspector, jsbytecode *pc);
 
-    bool canOverflow();
-
-    bool fallible() {
-        return canOverflow();
-    }
+    bool bailoutsDisabled() const {
+        return bailoutsDisabled_;
+    }
+
+    bool fallible();
 
     void computeRange();
 };
 
 class MBinaryArithInstruction
   : public MBinaryInstruction,
     public ArithPolicy
 {
@@ -8931,16 +8942,21 @@ class MAsmJSCheckOverRecursed : public M
 #undef INSTRUCTION_HEADER
 
 // Implement opcode casts now that the compiler can see the inheritance.
 #define OPCODE_CASTS(opcode)                                                \
     M##opcode *MDefinition::to##opcode()                                    \
     {                                                                       \
         JS_ASSERT(is##opcode());                                            \
         return static_cast<M##opcode *>(this);                              \
+    }                                                                       \
+    const M##opcode *MDefinition::to##opcode() const                        \
+    {                                                                       \
+        JS_ASSERT(is##opcode());                                            \
+        return static_cast<const M##opcode *>(this);                        \
     }
 MIR_OPCODE_LIST(OPCODE_CASTS)
 #undef OPCODE_CASTS
 
 MDefinition *MNode::toDefinition()
 {
     JS_ASSERT(isDefinition());
     return (MDefinition *)this;
--- a/js/src/jit/RangeAnalysis.cpp
+++ b/js/src/jit/RangeAnalysis.cpp
@@ -24,17 +24,20 @@ using namespace js::jit;
 using mozilla::Abs;
 using mozilla::CountLeadingZeroes32;
 using mozilla::DoubleIsInt32;
 using mozilla::ExponentComponent;
 using mozilla::IsInfinite;
 using mozilla::IsFinite;
 using mozilla::IsNaN;
 using mozilla::IsNegative;
+using mozilla::NegativeInfinity;
+using mozilla::PositiveInfinity;
 using mozilla::Swap;
+using JS::GenericNaN;
 
 // This algorithm is based on the paper "Eliminating Range Checks Using
 // Static Single Assignment Form" by Gough and Klaren.
 //
 // We associate a range object with each SSA name, and the ranges are consulted
 // in order to determine whether overflow is possible for arithmetic
 // computations.
 //
@@ -137,32 +140,29 @@ RangeAnalysis::addBetaNodes()
 
         BranchDirection branch_dir;
         MTest *test = block->immediateDominatorBranch(&branch_dir);
 
         if (!test || !test->getOperand(0)->isCompare())
             continue;
 
         MCompare *compare = test->getOperand(0)->toCompare();
-
-        // TODO: support unsigned comparisons
-        if (compare->compareType() == MCompare::Compare_UInt32)
-            continue;
-
         MDefinition *left = compare->getOperand(0);
         MDefinition *right = compare->getOperand(1);
         double bound;
-        int16_t exponent = Range::IncludesInfinity;
+        double conservativeLower = NegativeInfinity();
+        double conservativeUpper = PositiveInfinity();
         MDefinition *val = nullptr;
 
         JSOp jsop = compare->jsop();
 
         if (branch_dir == FALSE_BRANCH) {
             jsop = analyze::NegateCompareOp(jsop);
-            exponent = Range::IncludesInfinityAndNaN;
+            conservativeLower = GenericNaN();
+            conservativeUpper = GenericNaN();
         }
 
         if (left->isConstant() && left->toConstant()->value().isNumber()) {
             bound = left->toConstant()->value().toNumber();
             val = right;
             jsop = analyze::ReverseCompareOp(jsop);
         } else if (right->isConstant() && right->toConstant()->value().isNumber()) {
             bound = right->toConstant()->value().toNumber();
@@ -192,49 +192,45 @@ RangeAnalysis::addBetaNodes()
         } else {
             continue;
         }
 
         // At this point, one of the operands if the compare is a constant, and
         // val is the other operand.
         JS_ASSERT(val);
 
-        // If we can't convert this bound to an int32_t, it won't be as easy to
-        // create interesting Ranges with.
-        if (!IsFinite(bound) || bound < INT32_MIN || bound > INT32_MAX)
-            continue;
-
         Range comp;
         switch (jsop) {
           case JSOP_LE:
-            comp.set(Range::NoInt32LowerBound, ceil(bound), true, exponent);
+            comp.setDouble(conservativeLower, bound);
             break;
           case JSOP_LT:
             // For integers, if x < c, the upper bound of x is c-1.
             if (val->type() == MIRType_Int32) {
                 int32_t intbound;
                 if (DoubleIsInt32(bound, &intbound) && SafeSub(intbound, 1, &intbound))
                     bound = intbound;
             }
-            comp.set(Range::NoInt32LowerBound, ceil(bound), true, exponent);
+            comp.setDouble(conservativeLower, bound);
             break;
           case JSOP_GE:
-            comp.set(floor(bound), Range::NoInt32UpperBound, true, exponent);
+            comp.setDouble(bound, conservativeUpper);
             break;
           case JSOP_GT:
             // For integers, if x > c, the lower bound of x is c+1.
             if (val->type() == MIRType_Int32) {
                 int32_t intbound;
                 if (DoubleIsInt32(bound, &intbound) && SafeAdd(intbound, 1, &intbound))
                     bound = intbound;
             }
-            comp.set(floor(bound), Range::NoInt32UpperBound, true, exponent);
+            comp.setDouble(bound, conservativeUpper);
             break;
           case JSOP_EQ:
-            comp.set(floor(bound), ceil(bound), true, exponent);
+            comp.setDouble(bound, bound);
+            break;
           default:
             continue; // well, for neq we could have
                       // [-\inf, bound-1] U [bound+1, \inf] but we only use contiguous ranges.
         }
 
         if (IonSpewEnabled(IonSpew_Range)) {
             IonSpewHeader(IonSpew_Range);
             fprintf(IonSpewFile, "Adding beta node for %d with range ", val->id());
@@ -371,16 +367,44 @@ Range::intersect(const Range *lhs, const
         return nullptr;
     }
 
     bool newHasInt32LowerBound = lhs->hasInt32LowerBound_ || rhs->hasInt32LowerBound_;
     bool newHasInt32UpperBound = lhs->hasInt32UpperBound_ || rhs->hasInt32UpperBound_;
     bool newFractional = lhs->canHaveFractionalPart_ && rhs->canHaveFractionalPart_;
     uint16_t newExponent = Min(lhs->max_exponent_, rhs->max_exponent_);
 
+    // NaN is a special value which is neither greater than infinity or less than
+    // negative infinity. When we intersect two ranges like [?, 0] and [0, ?], we
+    // can end up thinking we have both a lower and upper bound, even though NaN
+    // is still possible. In this case, just be conservative, since any case where
+    // we can have NaN is not especially interesting.
+    if (newHasInt32LowerBound && newHasInt32UpperBound && newExponent == IncludesInfinityAndNaN)
+        return nullptr;
+
+    // If one of the ranges has a fractional part and the other doesn't, it's
+    // possible that we will have computed a newExponent that's more precise
+    // than our newLower and newUpper. This is unusual, so we handle it here
+    // instead of in optimize().
+    //
+    // For example, when the floating-point range has an actual maximum value
+    // of 1.5, it may have a range like [0,2] and the max_exponent may be zero.
+    // When intersecting such a range with an integer range, the fractional part
+    // of the range is dropped, but the max exponent of 0 remains valid.
+    if (lhs->canHaveFractionalPart_ != rhs->canHaveFractionalPart_ &&
+        newExponent < MaxInt32Exponent)
+    {
+        // pow(2, newExponent+1)-1 to compute the maximum value for newExponent.
+        int32_t limit = (uint32_t(1) << (newExponent + 1)) - 1;
+        if (limit != INT32_MIN) {
+            newUpper = Min(newUpper, limit);
+            newLower = Max(newLower, -limit);
+        }
+    }
+
     return new Range(newLower, newHasInt32LowerBound, newUpper, newHasInt32UpperBound,
                      newFractional, newExponent);
 }
 
 void
 Range::unionWith(const Range *other)
 {
     int32_t newLower = Min(lower_, other->lower_);
@@ -394,32 +418,112 @@ Range::unionWith(const Range *other)
     rawInitialize(newLower, newHasInt32LowerBound, newUpper, newHasInt32UpperBound,
                   newFractional, newExponent);
 }
 
 Range::Range(const MDefinition *def)
   : symbolicLower_(nullptr),
     symbolicUpper_(nullptr)
 {
-    const Range *other = def->range();
-    if (!other) {
-        if (def->type() == MIRType_Int32)
+    if (const Range *other = def->range()) {
+        // The instruction has range information; use it.
+        *this = *other;
+
+        // Simulate the effect of converting the value to its type.
+        switch (def->type()) {
+          case MIRType_Int32:
+            wrapAroundToInt32();
+            break;
+          case MIRType_Boolean:
+            wrapAroundToBoolean();
+            break;
+          case MIRType_None:
+            MOZ_ASSUME_UNREACHABLE("Asking for the range of an instruction with no value");
+          default:
+            break;
+        }
+    } else {
+        // Otherwise just use type information. We can trust the type here
+        // because we don't care what value the instruction actually produces,
+        // but what value we might get after we get past the bailouts.
+        switch (def->type()) {
+          case MIRType_Int32:
             setInt32(JSVAL_INT_MIN, JSVAL_INT_MAX);
-        else if (def->type() == MIRType_Boolean)
+            break;
+          case MIRType_Boolean:
             setInt32(0, 1);
-        else
+            break;
+          case MIRType_None:
+            MOZ_ASSUME_UNREACHABLE("Asking for the range of an instruction with no value");
+          default:
             setUnknown();
-        symbolicLower_ = symbolicUpper_ = nullptr;
-        return;
+            break;
+        }
     }
 
-    JS_ASSERT_IF(def->type() == MIRType_Boolean, other->isBoolean());
+    // As a special case, MUrsh is permitted to claim a result type of
+    // MIRType_Int32 while actually returning values in [0,UINT32_MAX] without
+    // bailouts. If range analysis hasn't ruled out values in
+    // (INT32_MAX,UINT32_MAX], set the range to be conservatively correct for
+    // use as either a uint32 or an int32.
+    if (!hasInt32UpperBound() && def->isUrsh() && def->toUrsh()->bailoutsDisabled())
+        lower_ = INT32_MIN;
+
+    assertInvariants();
+}
+
+static uint16_t
+ExponentImpliedByDouble(double d)
+{
+    // Handle the special values.
+    if (IsNaN(d))
+        return Range::IncludesInfinityAndNaN;
+    if (IsInfinite(d))
+        return Range::IncludesInfinity;
+
+    // Otherwise take the exponent part and clamp it at zero, since the Range
+    // class doesn't track fractional ranges.
+    return uint16_t(Max(int_fast16_t(0), ExponentComponent(d)));
+}
 
-    *this = *other;
-    symbolicLower_ = symbolicUpper_ = nullptr;
+void
+Range::setDouble(double l, double h)
+{
+    // Infer lower_, upper_, hasInt32LowerBound_, and hasInt32UpperBound_.
+    if (l >= INT32_MIN && l <= INT32_MAX) {
+        lower_ = int32_t(floor(l));
+        hasInt32LowerBound_ = true;
+    } else {
+        lower_ = INT32_MIN;
+        hasInt32LowerBound_ = false;
+    }
+    if (h >= INT32_MIN && h <= INT32_MAX) {
+        upper_ = int32_t(ceil(h));
+        hasInt32UpperBound_ = true;
+    } else {
+        upper_ = INT32_MAX;
+        hasInt32UpperBound_ = false;
+    }
+
+    // Infer max_exponent_.
+    uint16_t lExp = ExponentImpliedByDouble(l);
+    uint16_t hExp = ExponentImpliedByDouble(h);
+    max_exponent_ = Max(lExp, hExp);
+
+    // Infer the canHaveFractionalPart_ field. We can have a fractional part
+    // if the range crosses through the neighborhood of zero. We won't have a
+    // fractional value if the value is always beyond the point at which
+    // double precision can't represent fractional values.
+    uint16_t minExp = Min(lExp, hExp);
+    bool includesNegative = IsNaN(l) || l < 0;
+    bool includesPositive = IsNaN(h) || h > 0;
+    bool crossesZero = includesNegative && includesPositive;
+    canHaveFractionalPart_ = crossesZero || minExp < MaxTruncatableExponent;
+
+    optimize();
 }
 
 static inline bool
 MissingAnyInt32Bounds(const Range *lhs, const Range *rhs)
 {
     return !lhs->hasInt32LowerBound() || !lhs->hasInt32UpperBound() ||
            !rhs->hasInt32LowerBound() || !rhs->hasInt32UpperBound();
 }
@@ -754,32 +858,32 @@ Range::abs(const Range *op)
                      op->max_exponent_);
 }
 
 Range *
 Range::min(const Range *lhs, const Range *rhs)
 {
     // If either operand is NaN, the result is NaN.
     if (lhs->canBeNaN() || rhs->canBeNaN())
-        return new Range();
+        return nullptr;
 
     return new Range(Min(lhs->lower_, rhs->lower_),
                      lhs->hasInt32LowerBound_ && rhs->hasInt32LowerBound_,
                      Min(lhs->upper_, rhs->upper_),
                      lhs->hasInt32UpperBound_ || rhs->hasInt32UpperBound_,
                      lhs->canHaveFractionalPart_ || rhs->canHaveFractionalPart_,
                      Max(lhs->max_exponent_, rhs->max_exponent_));
 }
 
 Range *
 Range::max(const Range *lhs, const Range *rhs)
 {
     // If either operand is NaN, the result is NaN.
     if (lhs->canBeNaN() || rhs->canBeNaN())
-        return new Range();
+        return nullptr;
 
     return new Range(Max(lhs->lower_, rhs->lower_),
                      lhs->hasInt32LowerBound_ || rhs->hasInt32LowerBound_,
                      Max(lhs->upper_, rhs->upper_),
                      lhs->hasInt32UpperBound_ && rhs->hasInt32UpperBound_,
                      lhs->canHaveFractionalPart_ || rhs->canHaveFractionalPart_,
                      Max(lhs->max_exponent_, rhs->max_exponent_));
 }
@@ -832,111 +936,53 @@ MPhi::computeRange()
         if (getOperand(i)->block()->earlyAbort()) {
             IonSpew(IonSpew_Range, "Ignoring unreachable input %d", getOperand(i)->id());
             continue;
         }
 
         if (isOSRLikeValue(getOperand(i)))
             continue;
 
-        Range *input = getOperand(i)->range();
+        // Peek at the pre-bailout range so we can take a short-cut; if any of
+        // the operands has an unknown range, this phi has an unknown range.
+        if (!getOperand(i)->range())
+            return;
 
-        if (!input) {
-            range = nullptr;
-            break;
-        }
+        Range input(getOperand(i));
 
         if (range)
-            range->unionWith(input);
+            range->unionWith(&input);
         else
-            range = new Range(*input);
+            range = new Range(input);
     }
 
     setRange(range);
 }
 
 void
 MBeta::computeRange()
 {
     bool emptyRange = false;
 
-    Range *range = Range::intersect(getOperand(0)->range(), comparison_, &emptyRange);
+    Range opRange(getOperand(0));
+    Range *range = Range::intersect(&opRange, comparison_, &emptyRange);
     if (emptyRange) {
         IonSpew(IonSpew_Range, "Marking block for inst %d unexitable", id());
         block()->setEarlyAbort();
     } else {
         setRange(range);
     }
 }
 
 void
 MConstant::computeRange()
 {
-    if (type() == MIRType_Int32) {
-        setRange(Range::NewSingleValueRange(value().toInt32()));
-        return;
-    }
-
-    if (type() != MIRType_Double)
-        return;
-
-    double d = value().toDouble();
-
-    // NaN is not handled by range analysis.
-    if (IsNaN(d))
-        return;
-
-    // Beyond-int32 values are used to set both lower and upper to the range boundaries.
-    if (IsInfinite(d)) {
-        if (IsNegative(d))
-            setRange(Range::NewDoubleRange(Range::NoInt32LowerBound,
-                                           Range::NoInt32LowerBound,
-                                           Range::IncludesInfinity));
-        else
-            setRange(Range::NewDoubleRange(Range::NoInt32UpperBound,
-                                           Range::NoInt32UpperBound,
-                                           Range::IncludesInfinity));
-        return;
-    }
-
-    // Extract the exponent, to approximate it with the range analysis.
-    int exp = ExponentComponent(d);
-    if (exp < 0) {
-        // This double only has a fractional part.
-        if (IsNegative(d))
-            setRange(Range::NewDoubleRange(-1, 0));
-        else
-            setRange(Range::NewDoubleRange(0, 1));
-    } else if (exp < Range::MaxTruncatableExponent) {
-        // Extract the integral part.
-        int64_t integral = ToInt64(d);
-        // Extract the fractional part.
-        double rest = d - (double) integral;
-        // Estimate the smallest integral boundaries.
-        //   Safe double comparisons, because there is no precision loss.
-        int64_t l = integral - ((rest < 0) ? 1 : 0);
-        int64_t h = integral + ((rest > 0) ? 1 : 0);
-        // If we adjusted into a new exponent range, adjust exp accordingly.
-        if ((rest < 0 && (l == INT64_MIN || IsPowerOfTwo(Abs(l)))) ||
-            (rest > 0 && (h == INT64_MIN || IsPowerOfTwo(Abs(h)))))
-        {
-            ++exp;
-        }
-        setRange(new Range(l, h, (rest != 0), exp));
-    } else {
-        // This double has a precision loss. This also mean that it cannot
-        // encode any values with fractional parts.
-        if (IsNegative(d))
-            setRange(Range::NewDoubleRange(Range::NoInt32LowerBound,
-                                           Range::NoInt32LowerBound,
-                                           exp));
-        else
-            setRange(Range::NewDoubleRange(Range::NoInt32UpperBound,
-                                           Range::NoInt32UpperBound,
-                                           exp));
+    if (value().isNumber()) {
+        double d = value().toNumber();
+        setRange(Range::NewDoubleRange(d, d));
     }
 }
 
 void
 MCharCodeAt::computeRange()
 {
     // ECMA 262 says that the integer will be non-negative and at most 65535.
     setRange(Range::NewInt32Range(0, 65535));
@@ -1044,31 +1090,29 @@ MUrsh::computeRange()
         right.wrapAroundToShiftCount();
         setRange(Range::ursh(&left, &right));
     } else {
         int32_t c = rhs->toConstant()->value().toInt32();
         setRange(Range::ursh(&left, c));
     }
 
     JS_ASSERT(range()->lower() >= 0);
-    if (type() == MIRType_Int32 && !range()->hasInt32UpperBound())
-        range()->extendUInt32ToInt32Min();
 }
 
 void
 MAbs::computeRange()
 {
     if (specialization_ != MIRType_Int32 && specialization_ != MIRType_Double)
         return;
 
     Range other(getOperand(0));
-    setRange(Range::abs(&other));
-
+    Range *next = Range::abs(&other);
     if (implicitTruncate_)
-        range()->wrapAroundToInt32();
+        next->wrapAroundToInt32();
+    setRange(next);
 }
 
 void
 MMinMax::computeRange()
 {
     if (specialization_ != MIRType_Int32 && specialization_ != MIRType_Double)
         return;
 
@@ -1080,50 +1124,48 @@ MMinMax::computeRange()
 void
 MAdd::computeRange()
 {
     if (specialization() != MIRType_Int32 && specialization() != MIRType_Double)
         return;
     Range left(getOperand(0));
     Range right(getOperand(1));
     Range *next = Range::add(&left, &right);
+    if (isTruncated())
+        next->wrapAroundToInt32();
     setRange(next);
-
-    if (isTruncated())
-        range()->wrapAroundToInt32();
 }
 
 void
 MSub::computeRange()
 {
     if (specialization() != MIRType_Int32 && specialization() != MIRType_Double)
         return;
     Range left(getOperand(0));
     Range right(getOperand(1));
     Range *next = Range::sub(&left, &right);
+    if (isTruncated())
+        next->wrapAroundToInt32();
     setRange(next);
-
-    if (isTruncated())
-        range()->wrapAroundToInt32();
 }
 
 void
 MMul::computeRange()
 {
     if (specialization() != MIRType_Int32 && specialization() != MIRType_Double)
         return;
     Range left(getOperand(0));
     Range right(getOperand(1));
     if (canBeNegativeZero())
         canBeNegativeZero_ = Range::negativeZeroMul(&left, &right);
-    setRange(Range::mul(&left, &right));
-
+    Range *next = Range::mul(&left, &right);
     // Truncated multiplications could overflow in both directions
     if (isTruncated())
-        range()->wrapAroundToInt32();
+        next->wrapAroundToInt32();
+    setRange(next);
 }
 
 void
 MMod::computeRange()
 {
     if (specialization() != MIRType_Int32 && specialization() != MIRType_Double)
         return;
     Range lhs(getOperand(0));
@@ -1260,44 +1302,44 @@ static Range *GetTypedArrayRange(int typ
     }
 
   return nullptr;
 }
 
 void
 MLoadTypedArrayElement::computeRange()
 {
-    if (Range *range = GetTypedArrayRange(arrayType())) {
-        if (type() == MIRType_Int32 && !range->hasInt32UpperBound())
-            range->extendUInt32ToInt32Min();
-        setRange(range);
-    }
+    // We have an Int32 type and if this is a UInt32 load it may produce a value
+    // outside of our range, but we have a bailout to handle those cases.
+    setRange(GetTypedArrayRange(arrayType()));
 }
 
 void
 MLoadTypedArrayElementStatic::computeRange()
 {
-    if (Range *range = GetTypedArrayRange(typedArray_->type()))
-        setRange(range);
+    // We don't currently use MLoadTypedArrayElementStatic for uint32, so we
+    // don't have to worry about it returning a value outside our type.
+    JS_ASSERT(typedArray_->type() != ScalarTypeRepresentation::TYPE_UINT32);
+
+    setRange(GetTypedArrayRange(typedArray_->type()));
 }
 
 void
 MArrayLength::computeRange()
 {
-    Range *r = Range::NewUInt32Range(0, UINT32_MAX);
-    r->extendUInt32ToInt32Min();
-    setRange(r);
+    // Array lengths can go up to UINT32_MAX, but we only create MArrayLength
+    // nodes when the value is known to be int32 (see the
+    // OBJECT_FLAG_LENGTH_OVERFLOW flag).
+    setRange(Range::NewUInt32Range(0, INT32_MAX));
 }
 
 void
 MInitializedLength::computeRange()
 {
-    Range *r = Range::NewUInt32Range(0, UINT32_MAX);
-    r->extendUInt32ToInt32Min();
-    setRange(r);
+    setRange(Range::NewUInt32Range(0, JSObject::NELEMENTS_LIMIT));
 }
 
 void
 MTypedArrayLength::computeRange()
 {
     setRange(Range::NewUInt32Range(0, INT32_MAX));
 }
 
@@ -1840,24 +1882,35 @@ RangeAnalysis::addRangeAssertions()
     // instructions for each MInstruction with a computed range, and it uses
     // registers, so it also affects register allocation.
     for (ReversePostorderIterator iter(graph_.rpoBegin()); iter != graph_.rpoEnd(); iter++) {
         MBasicBlock *block = *iter;
 
         for (MInstructionIterator iter(block->begin()); iter != block->end(); iter++) {
             MInstruction *ins = *iter;
 
-            if (ins->type() == MIRType_None)
+            // Perform range checking for all numeric and numeric-like types.
+            if (!IsNumberType(ins->type()) &&
+                ins->type() != MIRType_Boolean &&
+                ins->type() != MIRType_Value)
+            {
+                continue;
+            }
+
+            Range r(ins);
+
+            // Don't insert assertions if there's nothing interesting to assert.
+            if (r.isUnknown() || (ins->type() == MIRType_Int32 && r.isUnknownInt32()))
                 continue;
 
-            Range *r = ins->range();
-            if (!r)
+            // Range-checking PassArgs breaks stuff.
+            if (ins->isPassArg())
                 continue;
 
-            MAssertRange *guard = MAssertRange::New(ins, new Range(*r));
+            MAssertRange *guard = MAssertRange::New(ins, new Range(r));
 
             // The code that removes beta nodes assumes that it can find them
             // in a contiguous run at the top of each block. Don't insert
             // range assertions in between beta nodes.
             MInstructionIterator insertIter = iter;
             while (insertIter->isBeta())
                 insertIter++;
 
@@ -1985,32 +2038,23 @@ MMul::truncate()
 }
 
 bool
 MDiv::truncate()
 {
     // Remember analysis, needed to remove negative zero checks.
     setTruncated(true);
 
-    if (type() == MIRType_Double || type() == MIRType_Int32) {
-        specialization_ = MIRType_Int32;
-        setResultType(MIRType_Int32);
-        if (range())
-            range()->wrapAroundToInt32();
-
-        // Divisions where the lhs and rhs are unsigned and the result is
-        // truncated can be lowered more efficiently.
-        if (tryUseUnsignedOperands())
-            unsigned_ = true;
-
+    // Divisions where the lhs and rhs are unsigned and the result is
+    // truncated can be lowered more efficiently.
+    if (specialization() == MIRType_Int32 && tryUseUnsignedOperands()) {
+        unsigned_ = true;
         return true;
     }
 
-    JS_ASSERT(specialization() != MIRType_Int32); // fixme
-
     // No modifications.
     return false;
 }
 
 bool
 MMod::truncate()
 {
     // Remember analysis, needed to remove negative zero checks.
@@ -2151,17 +2195,17 @@ AllUsesTruncate(MInstruction *candidate)
 
     return true;
 }
 
 static void
 RemoveTruncatesOnOutput(MInstruction *truncated)
 {
     JS_ASSERT(truncated->type() == MIRType_Int32);
-    JS_ASSERT_IF(truncated->range(), truncated->range()->isInt32());
+    JS_ASSERT(Range(truncated).isInt32());
 
     for (MUseDefIterator use(truncated); use; use++) {
         MDefinition *def = use.def();
         if (!def->isTruncateToInt32() || !def->isToInt32())
             continue;
 
         def->replaceAllUsesWith(truncated);
     }
@@ -2221,17 +2265,19 @@ RangeAnalysis::truncate()
               case MDefinition::Op_Rsh:
               case MDefinition::Op_Ursh:
                 if (!bitops.append(static_cast<MBinaryBitwiseInstruction*>(*iter)))
                     return false;
               default:;
             }
 
             // Set truncated flag if range analysis ensure that it has no
-            // rounding errors and no fractional part.
+            // rounding errors and no fractional part. Note that we can't use
+            // the MDefinition Range constructor, because we need to know if
+            // the value will have rounding errors before any bailout checks.
             const Range *r = iter->range();
             bool canHaveRoundingErrors = !r || r->canHaveRoundingErrors();
 
             // Special case integer division: the result of a/b can be infinite
             // but cannot actually have rounding errors induced by truncation.
             if (iter->isDiv() && iter->toDiv()->specialization() == MIRType_Int32)
                 canHaveRoundingErrors = false;
 
@@ -2294,30 +2340,32 @@ RangeAnalysis::truncate()
 
 ///////////////////////////////////////////////////////////////////////////////
 // Collect Range information of operands
 ///////////////////////////////////////////////////////////////////////////////
 
 void
 MInArray::collectRangeInfo()
 {
-    needsNegativeIntCheck_ = !index()->range() || !index()->range()->isFiniteNonNegative();
+    Range indexRange(index());
+    needsNegativeIntCheck_ = !indexRange.isFiniteNonNegative();
 }
 
 void
 MLoadElementHole::collectRangeInfo()
 {
-    needsNegativeIntCheck_ = !index()->range() || !index()->range()->isFiniteNonNegative();
+    Range indexRange(index());
+    needsNegativeIntCheck_ = !indexRange.isFiniteNonNegative();
 }
 
 void
 MMod::collectRangeInfo()
 {
-    canBeNegativeDividend_ = !lhs()->range() || !lhs()->range()->isFiniteNonNegative();
+    Range lhsRange(lhs());
+    canBeNegativeDividend_ = !lhsRange.isFiniteNonNegative();
 }
 
 void
 MBoundsCheckLower::collectRangeInfo()
 {
-    fallible_ = !index()->range() ||
-                !index()->range()->hasInt32LowerBound() ||
-                index()->range()->lower() < minimum_;
+    Range indexRange(index());
+    fallible_ = !indexRange.hasInt32LowerBound() || indexRange.lower() < minimum_;
 }
--- a/js/src/jit/RangeAnalysis.h
+++ b/js/src/jit/RangeAnalysis.h
@@ -171,25 +171,44 @@ class Range : public TempObject {
 
     // Any symbolic lower or upper bound computed for this term.
     const SymbolicBound *symbolicLower_;
     const SymbolicBound *symbolicUpper_;
 
     // This function simply makes several JS_ASSERTs to verify the internal
     // consistency of this range.
     void assertInvariants() const {
+        // Basic sanity :).
         JS_ASSERT(lower_ <= upper_);
+
+        // When hasInt32LowerBound_ or hasInt32UpperBound_ are false, we set
+        // lower_ and upper_ to these specific values as it simplifies the
+        // implementation in some places.
         JS_ASSERT_IF(!hasInt32LowerBound_, lower_ == JSVAL_INT_MIN);
         JS_ASSERT_IF(!hasInt32UpperBound_, upper_ == JSVAL_INT_MAX);
-        JS_ASSERT_IF(!hasInt32LowerBound_ || !hasInt32UpperBound_, max_exponent_ >= MaxInt32Exponent);
+
+        // max_exponent_ must be one of three possible things.
         JS_ASSERT(max_exponent_ <= MaxFiniteExponent ||
                   max_exponent_ == IncludesInfinity ||
                   max_exponent_ == IncludesInfinityAndNaN);
-        JS_ASSERT(max_exponent_ >= mozilla::FloorLog2(mozilla::Abs(upper_)));
-        JS_ASSERT(max_exponent_ >= mozilla::FloorLog2(mozilla::Abs(lower_)));
+
+        // Forbid the max_exponent_ field from implying better bounds for
+        // lower_/upper_ fields. We have to add 1 to the max_exponent_ when
+        // canHaveFractionalPart_ is true in order to accomodate fractional
+        // offsets. For example, 2147483647.9 is greater than INT32_MAX, so a
+        // range containing that value will have hasInt32UpperBound_ set to
+        // false, however that value also has exponent 30, which is strictly
+        // less than MaxInt32Exponent. For another example, 1.9 has an exponent
+        // of 0 but requires upper_ to be at least 2, which has exponent 1.
+        JS_ASSERT_IF(!hasInt32LowerBound_ || !hasInt32UpperBound_,
+                     max_exponent_ + canHaveFractionalPart_ >= MaxInt32Exponent);
+        JS_ASSERT(max_exponent_ + canHaveFractionalPart_ >=
+                  mozilla::FloorLog2(mozilla::Abs(upper_)));
+        JS_ASSERT(max_exponent_ + canHaveFractionalPart_ >=
+                  mozilla::FloorLog2(mozilla::Abs(lower_)));
 
         // The following are essentially static assertions, but FloorLog2 isn't
         // trivially suitable for constexpr :(.
         JS_ASSERT(mozilla::FloorLog2(JSVAL_INT_MIN) == MaxInt32Exponent);
         JS_ASSERT(mozilla::FloorLog2(JSVAL_INT_MAX) == 30);
         JS_ASSERT(mozilla::FloorLog2(UINT32_MAX) == MaxUInt32Exponent);
         JS_ASSERT(mozilla::FloorLog2(0) == 0);
     }
@@ -302,34 +321,38 @@ class Range : public TempObject {
         canHaveFractionalPart_(other.canHaveFractionalPart_),
         max_exponent_(other.max_exponent_),
         symbolicLower_(nullptr),
         symbolicUpper_(nullptr)
     {
         assertInvariants();
     }
 
+    // Construct a range from the given MDefinition. This differs from the
+    // MDefinition's range() method in that it describes the range of values
+    // *after* any bailout checks.
     Range(const MDefinition *def);
 
     static Range *NewInt32Range(int32_t l, int32_t h) {
         return new Range(l, h, false, MaxInt32Exponent);
     }
 
     static Range *NewUInt32Range(uint32_t l, uint32_t h) {
         // For now, just pass them to the constructor as int64_t values.
         // They'll become unbounded if they're not in the int32_t range.
         return new Range(l, h, false, MaxUInt32Exponent);
     }
 
-    static Range *NewDoubleRange(int64_t l, int64_t h, uint16_t e = IncludesInfinityAndNaN) {
-        return new Range(l, h, true, e);
-    }
+    static Range *NewDoubleRange(double l, double h) {
+        if (mozilla::IsNaN(l) && mozilla::IsNaN(h))
+            return nullptr;
 
-    static Range *NewSingleValueRange(int64_t v) {
-        return new Range(v, v, false, IncludesInfinityAndNaN);
+        Range *r = new Range();
+        r->setDouble(l, h);
+        return r;
     }
 
     void print(Sprinter &sp) const;
     void dump(FILE *fp) const;
     bool update(const Range *other);
 
     // Unlike the other operations, unionWith is an in-place
     // modification. This is to avoid a bunch of useless extra
@@ -351,16 +374,27 @@ class Range : public TempObject {
     static Range * rsh(const Range *lhs, const Range *rhs);
     static Range * ursh(const Range *lhs, const Range *rhs);
     static Range * abs(const Range *op);
     static Range * min(const Range *lhs, const Range *rhs);
     static Range * max(const Range *lhs, const Range *rhs);
 
     static bool negativeZeroMul(const Range *lhs, const Range *rhs);
 
+    bool isUnknownInt32() const {
+        return isInt32() && lower() == INT32_MIN && upper() == INT32_MAX;
+    }
+
+    bool isUnknown() const {
+        return !hasInt32LowerBound_ &&
+               !hasInt32UpperBound_ &&
+               canHaveFractionalPart_ &&
+               max_exponent_ == IncludesInfinityAndNaN;
+    }
+
     bool hasInt32LowerBound() const {
         return hasInt32LowerBound_;
     }
     bool hasInt32UpperBound() const {
         return hasInt32UpperBound_;
     }
 
     // Test whether the value is known to be within [INT32_MIN,INT32_MAX].
@@ -466,22 +500,21 @@ class Range : public TempObject {
         hasInt32UpperBound_ = true;
         lower_ = l;
         upper_ = h;
         canHaveFractionalPart_ = false;
         max_exponent_ = exponentImpliedByInt32Bounds();
         assertInvariants();
     }
 
+    void setDouble(double l, double h);
+
     void setUnknown() {
-        setDouble(NoInt32LowerBound, NoInt32UpperBound);
-    }
-
-    void setDouble(int64_t l, int64_t h, uint16_t e = IncludesInfinityAndNaN) {
-        set(l, h, true, e);
+        set(NoInt32LowerBound, NoInt32UpperBound, true, IncludesInfinityAndNaN);
+        JS_ASSERT(isUnknown());
     }
 
     void set(int64_t l, int64_t h, bool f, uint16_t e) {
         max_exponent_ = e;
         canHaveFractionalPart_ = f;
         setLowerInit(l);
         setUpperInit(h);
         optimize();
@@ -498,24 +531,16 @@ class Range : public TempObject {
     // If this range exceeds [0, 32) range, at either or both ends, change
     // it to the [0, 32) range.  Otherwise do nothing.
     void wrapAroundToShiftCount();
 
     // If this range exceeds [0, 1] range, at either or both ends, change
     // it to the [0, 1] range.  Otherwise do nothing.
     void wrapAroundToBoolean();
 
-    // As we lack support of MIRType_UInt32, we need to work around the int32
-    // representation by doing an overflow while keeping the upper infinity to
-    // repesent the fact that the value might reach bigger numbers.
-    void extendUInt32ToInt32Min() {
-        JS_ASSERT(!hasInt32UpperBound());
-        lower_ = JSVAL_INT_MIN;
-    }
-
     const SymbolicBound *symbolicLower() const {
         return symbolicLower_;
     }
     const SymbolicBound *symbolicUpper() const {
         return symbolicUpper_;
     }
 
     void setSymbolicLower(SymbolicBound *bound) {
--- a/js/src/jit/arm/CodeGenerator-arm.cpp
+++ b/js/src/jit/arm/CodeGenerator-arm.cpp
@@ -902,17 +902,17 @@ CodeGeneratorARM::visitShiftI(LShiftI *i
                 masm.ma_mov(lhs, dest);
             break;
           case JSOP_URSH:
             if (shift) {
                 masm.ma_lsr(Imm32(shift), lhs, dest);
             } else {
                 // x >>> 0 can overflow.
                 masm.ma_mov(lhs, dest);
-                if (ins->mir()->toUrsh()->canOverflow()) {
+                if (ins->mir()->toUrsh()->fallible()) {
                     masm.ma_cmp(dest, Imm32(0));
                     if (!bailoutIf(Assembler::LessThan, ins->snapshot()))
                         return false;
                 }
             }
             break;
           default:
             MOZ_ASSUME_UNREACHABLE("Unexpected shift op");
@@ -927,17 +927,17 @@ CodeGeneratorARM::visitShiftI(LShiftI *i
           case JSOP_LSH:
             masm.ma_lsl(dest, lhs, dest);
             break;
           case JSOP_RSH:
             masm.ma_asr(dest, lhs, dest);
             break;
           case JSOP_URSH:
             masm.ma_lsr(dest, lhs, dest);
-            if (ins->mir()->toUrsh()->canOverflow()) {
+            if (ins->mir()->toUrsh()->fallible()) {
                 // x >>> 0 can overflow.
                 masm.ma_cmp(dest, Imm32(0));
                 if (!bailoutIf(Assembler::LessThan, ins->snapshot()))
                     return false;
             }
             break;
           default:
             MOZ_ASSUME_UNREACHABLE("Unexpected shift op");
--- a/js/src/jit/shared/CodeGenerator-x86-shared.cpp
+++ b/js/src/jit/shared/CodeGenerator-x86-shared.cpp
@@ -1099,17 +1099,17 @@ CodeGeneratorX86Shared::visitShiftI(LShi
             break;
           case JSOP_RSH:
             if (shift)
                 masm.sarl(Imm32(shift), lhs);
             break;
           case JSOP_URSH:
             if (shift) {
                 masm.shrl(Imm32(shift), lhs);
-            } else if (ins->mir()->toUrsh()->canOverflow()) {
+            } else if (ins->mir()->toUrsh()->fallible()) {
                 // x >>> 0 can overflow.
                 masm.testl(lhs, lhs);
                 if (!bailoutIf(Assembler::Signed, ins->snapshot()))
                     return false;
             }
             break;
           default:
             MOZ_ASSUME_UNREACHABLE("Unexpected shift op");
@@ -1120,17 +1120,17 @@ CodeGeneratorX86Shared::visitShiftI(LShi
           case JSOP_LSH:
             masm.shll_cl(lhs);
             break;
           case JSOP_RSH:
             masm.sarl_cl(lhs);
             break;
           case JSOP_URSH:
             masm.shrl_cl(lhs);
-            if (ins->mir()->toUrsh()->canOverflow()) {
+            if (ins->mir()->toUrsh()->fallible()) {
                 // x >>> 0 can overflow.
                 masm.testl(lhs, lhs);
                 if (!bailoutIf(Assembler::Signed, ins->snapshot()))
                     return false;
             }
             break;
           default:
             MOZ_ASSUME_UNREACHABLE("Unexpected shift op");
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -1117,18 +1117,18 @@ js_RemoveRoot(JSRuntime *rt, void *rp)
 typedef RootedValueMap::Range RootRange;
 typedef RootedValueMap::Entry RootEntry;
 typedef RootedValueMap::Enum RootEnum;
 
 static size_t
 ComputeTriggerBytes(Zone *zone, size_t lastBytes, size_t maxBytes, JSGCInvocationKind gckind)
 {
     size_t base = gckind == GC_SHRINK ? lastBytes : Max(lastBytes, zone->runtimeFromMainThread()->gcAllocationThreshold);
-    float trigger = float(base) * zone->gcHeapGrowthFactor;
-    return size_t(Min(float(maxBytes), trigger));
+    double trigger = double(base) * zone->gcHeapGrowthFactor;
+    return size_t(Min(double(maxBytes), trigger));
 }
 
 void
 Zone::setGCLastBytes(size_t lastBytes, JSGCInvocationKind gckind)
 {
     /*
      * The heap growth factor depends on the heap size after a GC and the GC frequency.
      * For low frequency GCs (more than 1sec between GCs) we let the heap grow to 150%.
--- a/js/src/vm/ForkJoin.cpp
+++ b/js/src/vm/ForkJoin.cpp
@@ -404,16 +404,17 @@ class ForkJoinShared : public TaskExecut
     // Requests that computation abort.
     void setAbortFlag(bool fatal);
 
     // Set the fatal flag for the next abort.
     void setPendingAbortFatal() { fatal_ = true; }
 
     JSRuntime *runtime() { return cx_->runtime(); }
     JS::Zone *zone() { return cx_->zone(); }
+    JSCompartment *compartment() { return cx_->compartment(); }
 
     JSContext *acquireContext() { PR_Lock(cxLock_); return cx_; }
     void releaseContext() { PR_Unlock(cxLock_); }
 };
 
 class AutoEnterWarmup
 {
     JSRuntime *runtime_;
@@ -1684,16 +1685,23 @@ ForkJoinSlice::ForkJoinSlice(PerThreadDa
     shared(shared),
     acquiredContext_(false)
 {
     /*
      * Unsafely set the zone. This is used to track malloc counters and to
      * trigger GCs and is otherwise not thread-safe to access.
      */
     zone_ = shared->zone();
+
+    /*
+     * Unsafely set the compartment. This is used to get read-only access to
+     * shared tables.
+     */
+    compartment_ = shared->compartment();
+
     allocator_ = allocator;
 }
 
 bool
 ForkJoinSlice::isMainThread() const
 {
     return perThreadData == &shared->runtime()->mainThread;
 }
--- a/python/mozbuild/mozbuild/base.py
+++ b/python/mozbuild/mozbuild/base.py
@@ -453,16 +453,23 @@ class MozbuildObject(ProcessExecutionMix
         }
 
         if log:
             params['log_name'] = 'make'
 
         return fn(**params)
 
     def _make_path(self, force_pymake=False):
+        if self._is_windows() and not force_pymake:
+            # Use mozmake if it's available.
+            try:
+                return [which.which('mozmake')]
+            except which.WhichError:
+                pass
+
         if self._is_windows() or force_pymake:
             make_py = os.path.join(self.topsrcdir, 'build', 'pymake',
                 'make.py').replace(os.sep, '/')
 
             # We might want to consider invoking with the virtualenv's Python
             # some day. But, there is a chicken-and-egg problem w.r.t. when the
             # virtualenv is created.
             return [sys.executable, make_py]
--- a/security/build/Makefile.in
+++ b/security/build/Makefile.in
@@ -124,42 +124,40 @@ DEFAULT_GMAKE_FLAGS += CC="$(CC)"
 DEFAULT_GMAKE_FLAGS += SOURCE_MD_DIR=$(ABS_DIST)
 DEFAULT_GMAKE_FLAGS += SOURCE_MDHEADERS_DIR=$(NSPR_INCLUDE_DIR)
 DEFAULT_GMAKE_FLAGS += DIST=$(ABS_DIST)
 DEFAULT_GMAKE_FLAGS += NSPR_INCLUDE_DIR=$(NSPR_INCLUDE_DIR)
 DEFAULT_GMAKE_FLAGS += NSPR_LIB_DIR=$(NSPR_LIB_DIR)
 DEFAULT_GMAKE_FLAGS += MOZILLA_CLIENT=1
 DEFAULT_GMAKE_FLAGS += NO_MDUPDATE=1
 DEFAULT_GMAKE_FLAGS += NSS_ENABLE_ECC=1
-DEFAULT_GMAKE_FLAGS += NSINSTALL="$(NSINSTALL)"
-ifeq ($(OS_ARCH),WINNT)
-DEFAULT_GMAKE_FLAGS += INSTALL="$(NSINSTALL) -t"
-endif
 ifeq ($(OS_ARCH)_$(GNU_CC),WINNT_1)
 DEFAULT_GMAKE_FLAGS += OS_DLLFLAGS="-static-libgcc"
 endif
 ifndef MOZ_NATIVE_SQLITE
 ifdef MOZ_FOLD_LIBS
 DEFAULT_GMAKE_FLAGS += SQLITE_LIB_NAME=nss3
 else
 DEFAULT_GMAKE_FLAGS += SQLITE_LIB_NAME=mozsqlite3
 endif # MOZ_FOLD_LIBS
 DEFAULT_GMAKE_FLAGS += SQLITE_INCLUDE_DIR=$(ABS_DIST)/include
 endif
 ifdef NSS_DISABLE_DBM 
 DEFAULT_GMAKE_FLAGS += NSS_DISABLE_DBM=1
 endif
+ifeq ($(HOST_OS_ARCH),WINNT)
+ABS_topsrcdir   := $(shell cd $(topsrcdir); pwd -W)
+else
 ABS_topsrcdir   := $(shell cd $(topsrcdir); pwd)
-ifeq ($(HOST_OS_ARCH),WINNT)
-ifdef .PYMAKE
-ABS_topsrcdir   := $(shell cd $(topsrcdir); pwd -W)
-endif
 endif
 # Hack to force NSS build system to use "normal" object directories
-DEFAULT_GMAKE_FLAGS += BUILD='$(MOZ_BUILD_ROOT)/security/$$(subst $(ABS_topsrcdir)/security/,,$$(CURDIR))'
+DEFAULT_GMAKE_FLAGS += ABS_topsrcdir='$(ABS_topsrcdir)'
+# ABS_topsrcdir can't be expanded here because msys path mangling likes to break
+# paths in that case.
+DEFAULT_GMAKE_FLAGS += BUILD='$(MOZ_BUILD_ROOT)/security/$$(subst $$(ABS_topsrcdir)/security/,,$$(CURDIR))'
 DEFAULT_GMAKE_FLAGS += BUILD_TREE='$$(BUILD)' OBJDIR='$$(BUILD)' DEPENDENCIES='$$(BUILD)/.deps' SINGLE_SHLIB_DIR='$$(BUILD)'
 DEFAULT_GMAKE_FLAGS += SOURCE_XP_DIR=$(ABS_DIST)
 ifndef MOZ_DEBUG
 DEFAULT_GMAKE_FLAGS += BUILD_OPT=1 OPT_CODE_SIZE=1
 endif
 ifdef GNU_CC
 DEFAULT_GMAKE_FLAGS += NS_USE_GCC=1
 else
@@ -445,16 +443,26 @@ endif
 libs-nss/lib/softoken: $(DIST)/lib/$(IMPORT_PREFIX)nssutil3$(IMPORT_SUFFIX)
 libs-nss/lib/freebl: $(DIST)/lib/$(IMPORT_PREFIX)nssutil3$(IMPORT_SUFFIX) $(NSPR_IMPORT_LIBS)
 
 # For each directory where we build static libraries, force the NSS build system
 # to only build static libraries.
 $(addprefix libs-,$(NSS_STATIC_DIRS)): DEFAULT_GMAKE_FLAGS += SHARED_LIBRARY= IMPORT_LIBRARY=
 endif # MOZ_FOLD_LIBS
 
+ifeq ($(NSINSTALL_PY),$(NSINSTALL))
+DEFAULT_GMAKE_FLAGS += PYTHON='$(PYTHON)'
+DEFAULT_GMAKE_FLAGS += NSINSTALL_PY='$(call core_abspath,$(topsrcdir)/config/nsinstall.py)'
+DEFAULT_GMAKE_FLAGS += NSINSTALL='$$(PYTHON) $$(NSINSTALL_PY)'
+else
+DEFAULT_GMAKE_FLAGS += NSINSTALL='$(NSINSTALL)'
+endif
+ifeq ($(OS_ARCH),WINNT)
+DEFAULT_GMAKE_FLAGS += INSTALL='$$(NSINSTALL) -t'
+endif
 DEFAULT_GMAKE_FLAGS += $(EXTRA_GMAKE_FLAGS)
 
 $(addprefix libs-,$(NSS_DIRS)): libs-%:
 # Work around NSS's export rule being racy when recursing for private_export
 # See bug #836220.
 $(addprefix export-,$(NSS_DIRS)): EXTRA_GMAKE_FLAGS = PRIVATE_EXPORTS=
 $(addprefix export-,$(NSS_DIRS)): export-%: private_export-%
 $(addprefix private_export-,$(NSS_DIRS)): EXTRA_GMAKE_FLAGS =
--- a/testing/marionette/mach_commands.py
+++ b/testing/marionette/mach_commands.py
@@ -1,81 +1,119 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 from __future__ import unicode_literals
 import os
 
-from mozbuild.base import MachCommandBase
+from mozbuild.base import (
+    MachCommandBase,
+    MachCommandConditions as conditions,
+)
 
 from mach.decorators import (
     CommandArgument,
     CommandProvider,
     Command,
 )
 
+MARIONETTE_DISABLED = '''
+The %s command requires a Marionette-enabled build.
+
+Add 'ENABLE_MARIONETTE=1' to your mozconfig file and re-build the application.
+Your currently active mozconfig is %s.
+'''.lstrip()
+
+MARIONETTE_DISABLED_B2G = '''
+The %s command requires a Marionette-enabled build.
+
+Please create an engineering build, which has Marionette enabled.  You can do
+this by ommitting the VARIANT variable when building, or using:
+
+VARIANT=eng ./build.sh
+'''
+
+def run_marionette(tests, b2g_path=None, emulator=None, testtype=None,
+    address=None, bin=None, topsrcdir=None):
+    from marionette.runtests import (
+        MarionetteTestRunner,
+        MarionetteTestOptions,
+        startTestRunner
+    )
+
+    parser = MarionetteTestOptions()
+    options, args = parser.parse_args()
+
+    if not tests:
+        tests = [os.path.join(topsrcdir,
+                    'testing/marionette/client/marionette/tests/unit-tests.ini')]
+
+    options.type = testtype
+    if b2g_path:
+        options.homedir = b2g_path
+        if emulator:
+            options.emulator = emulator
+    else:
+        options.bin = bin
+        path, exe = os.path.split(options.bin)
+        if 'b2g' in exe:
+            options.app = 'b2gdesktop'
+
+    options.address = address
+
+    parser.verify_usage(options, tests)
+
+    runner = startTestRunner(MarionetteTestRunner, options, tests)
+    if runner.failed > 0:
+        return 1
+
+    return 0
+
+@CommandProvider
+class B2GCommands(MachCommandBase):
+    def __init__(self, context):
+        MachCommandBase.__init__(self, context)
+
+        for attr in ('b2g_home', 'device_name'):
+            setattr(self, attr, getattr(context, attr, None))
+    @Command('marionette-webapi', category='testing',
+        description='Run a Marionette webapi test',
+        conditions=[conditions.is_b2g])
+    @CommandArgument('--emulator', choices=['x86', 'arm'],
+        help='Run an emulator of the specified architecture.')
+    @CommandArgument('--type', dest='testtype',
+        help='Test type, usually one of: browser, b2g, b2g-qemu.',
+        default='b2g')
+    @CommandArgument('tests', nargs='*', metavar='TESTS',
+        help='Path to test(s) to run.')
+    def run_marionette_webapi(self, tests, emulator=None, testtype=None):
+        if not emulator and self.device_name in ('emulator', 'emulator-jb'):
+            emulator='arm'
+
+        if self.substs.get('ENABLE_MARIONETTE') != '1':
+            print(MARIONETTE_DISABLED_B2G % 'marionette-webapi')
+            return 1
+
+        return run_marionette(tests, b2g_path=self.b2g_home, emulator=emulator,
+            testtype=testtype, topsrcdir=self.topsrcdir, address=None)
+
 
 @CommandProvider
 class MachCommands(MachCommandBase):
     @Command('marionette-test', category='testing',
-        description='Run a Marionette test.')
-    @CommandArgument('--homedir', dest='b2g_path',
-        help='For B2G testing, the path to the B2G repo.')
-    @CommandArgument('--emulator', choices=['x86', 'arm'],
-        help='Run an emulator of the specified architecture.')
+        description='Run a Marionette test.',
+        conditions=[conditions.is_firefox])
     @CommandArgument('--address',
         help='host:port of running Gecko instance to connect to.')
     @CommandArgument('--type', dest='testtype',
-        help='Test type, usually one of: browser, b2g, b2g-qemu.')
+        help='Test type, usually one of: browser, b2g, b2g-qemu.',
+        default='browser')
     @CommandArgument('tests', nargs='*', metavar='TESTS',
         help='Path to test(s) to run.')
-    def run_marionette(self, tests, emulator=None, address=None, b2g_path=None,
-            testtype=None):
-        from marionette.runtests import (
-            MarionetteTestRunner,
-            MarionetteTestOptions,
-            startTestRunner
-        )
-
-        parser = MarionetteTestOptions()
-        options, args = parser.parse_args()
-
-        if not tests:
-            tests = ['testing/marionette/client/marionette/tests/unit-tests.ini']
-
-        options.type = testtype
-        if emulator:
-            if b2g_path:
-                options.homedir = b2g_path
-            if not testtype:
-                options.type = "b2g"
-        else:
-            if not testtype:
-                options.type = "browser"
-            try:
-                bin = self.get_binary_path('app')
-                options.bin = bin
-            except Exception as e:
-                print("It looks like your program isn't built.",
-                      "You can run |mach build| to build it.")
-                print(e)
-                return 1
-            path, exe = os.path.split(options.bin)
-            if 'b2g' in exe:
-                options.app = 'b2gdesktop'
-
-        if not emulator:
-            if self.substs.get('ENABLE_MARIONETTE') != '1':
-                print("Marionette doesn't appear to be enabled; please "
-                      "add ENABLE_MARIONETTE=1 to your mozconfig and "
-                      "perform a clobber build.")
-                return 1
-
-        options.address = address
-
-        parser.verify_usage(options, tests)
-
-        runner = startTestRunner(MarionetteTestRunner, options, tests)
-        if runner.failed > 0:
+    def run_marionette_test(self, tests, address=None, testtype=None):
+        if self.substs.get('ENABLE_MARIONETTE') != '1':
+            print(MARIONETTE_DISABLED % ('marionette-test',
+                                         self.mozconfig['path']))
             return 1
 
-        return 0
+        return run_marionette(tests, bin=bin, testtype=testtype,
+            topsrcdir=self.topsrcdir, address=address)
index 1175ba32034339ca14228d18eab23747e411a58f..01ef1cb21af23c0b9a98c7f7d7528c146003ceae
GIT binary patch
literal 221
zc$@*<03!d1P)<h;3K|Lk000e1NJLTq000mG000mO1^@s6AM^iV0001_Nkl<ZIE~$t
zv5iDA2t>c+kdTmoz-3Sd1rWF#il7)5LMgMc?}t8Vr5)*|FMyfnc^+KyPl7Q9hzQIK
z5rL{6hzOV&M1(QMTR=pZbHdEv?udv3cZZo_&IuxV3z!*ZhP4(l6IFGPnOJMV%)rcV
zfr!A}k(t<gqq`6G-pEY2J4ECyP*p?(stVnWzv*sN6(Rzv`jdj|BVNDpx=7bm{@NNp
Xq#?avna<MG00000NkvXXu0mjfgGO3k
index 1b121e9951835972d5540b4f85eff512c0d83e8e..1368150071ef06d0e6ec3e84b9cef72a221e3c39
GIT binary patch
literal 122
zc%17D@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`j-D=#Ar`$yFB=LnIB+l@EN)g&
zQRMVIaiV+2qwZW|XNCrk{miSh*zU?U&+I(-?%0EONk15DoAd(L2g+aiAHRW-Ke6+V
V!9|6Q#X!RtJYD@<);T3K0RR({C~5!z
index 56021cbd591c8ced583cf2fa158023bd73832bf0..0bfe1378e6707666d4164f9ccec2b79a6c406bd5
GIT binary patch
literal 116
zc%17D@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`)}AhoAr`%F&lvI^U=U#nyraPB
z>ER?~^y11Asaf`SD)<?`xfM-HtM<HBmODLVn|h|o_u7I3jO>3{D;N?x{}@~>&#(p>
O!{F)a=d#Wzp$P!{jU+Gt
--- a/xulrunner/config/mozconfigs/win32/xulrunner
+++ b/xulrunner/config/mozconfigs/win32/xulrunner
@@ -2,19 +2,15 @@
 
 export MOZILLA_OFFICIAL=1
 export JAVA_HOME=/d/jdk1.6.0_14
 
 ac_add_options --enable-application=xulrunner
 ac_add_options --enable-jemalloc
 ac_add_options --disable-tests
 
-if test -z "${_PYMAKE}"; then
-  mk_add_options MOZ_MAKE_FLAGS=-j1
-fi
-
 if test "$PROCESSOR_ARCHITECTURE" = "AMD64" -o "$PROCESSOR_ARCHITEW6432" = "AMD64"; then
   . $topsrcdir/build/win32/mozconfig.vs2010-win64
 else
   . $topsrcdir/build/win32/mozconfig.vs2010
 fi
 
 . "$topsrcdir/xulrunner/config/mozconfigs/common.override"
--- a/xulrunner/config/mozconfigs/win64/xulrunner
+++ b/xulrunner/config/mozconfigs/win64/xulrunner
@@ -5,13 +5,9 @@ ac_add_options --host=x86_64-pc-mingw32
 
 export MOZILLA_OFFICIAL=1
 export JAVA_HOME=/d/jdk1.6.0_14
 
 ac_add_options --enable-application=xulrunner
 ac_add_options --enable-jemalloc
 ac_add_options --disable-tests
 
-if test -z "${_PYMAKE}"; then
-  mk_add_options MOZ_MAKE_FLAGS=-j1
-fi
-
 . "$topsrcdir/xulrunner/config/mozconfigs/common.override"