merge b2g-inbound to mozilla-central
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Wed, 04 Dec 2013 09:47:17 +0100
changeset 173402 9688476c1544689573c7d3ef805fd61c2fc0f631
parent 173392 9fe5e212fa41e6f9d85abea50467003301509b42 (diff)
parent 173401 d997913037df89a04960346a36de1860425d6458 (current diff)
child 173403 5fb0eb7916d2ba00c9b3559b0d7f9d06a2cf3d7d
child 173404 e55e2e773ae677155175e56e8765eae2086f9e80
push id3224
push userlsblakk@mozilla.com
push dateTue, 04 Feb 2014 01:06:49 +0000
treeherdermozilla-beta@60c04d0987f1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone28.0a1
first release with
nightly linux32
9688476c1544 / 28.0a1 / 20131204030203 / files
nightly linux64
9688476c1544 / 28.0a1 / 20131204030203 / files
nightly mac
9688476c1544 / 28.0a1 / 20131204030203 / files
nightly win32
9688476c1544 / 28.0a1 / 20131204030203 / files
nightly win64
9688476c1544 / 28.0a1 / 20131204030203 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
merge b2g-inbound to mozilla-central
--- a/Makefile.in
+++ b/Makefile.in
@@ -241,17 +241,17 @@ maybe_clobber_profiledbuild:
 	find $(DIST)/$(MOZ_APP_NAME) -name '*.pgc' -exec mv {} $(DIST)/bin \;
 endif
 
 .PHONY: maybe_clobber_profiledbuild
 
 # Look for R_386_PC32 relocations in shared libs, these
 # break x86_64 builds and SELinux users.
 ifeq ($(OS_TARGET)_$(TARGET_XPCOM_ABI),Linux_x86-gcc3)
-scheck::
+check::
 	@relcount=`find $(DIST)/bin -name '*.so' | xargs objdump -R | grep R_386_PC32 | wc -l` && if test $$relcount -gt 0; then echo 'FAILED: R_386_PC32 relocations detected in a shared library.  Did you use a system header without adding it to config/system-headers?'; exit 1; else echo 'PASSED'; fi
 endif
 
 ifdef BUILD_JS
 js/src/Makefile: subsrcdir := js/src
 
 ifdef MOZ_PSEUDO_DERECURSE
 # Interdependencies for parallel export.
--- a/browser/components/customizableui/src/CustomizeMode.jsm
+++ b/browser/components/customizableui/src/CustomizeMode.jsm
@@ -553,20 +553,24 @@ CustomizeMode.prototype = {
                                 aNode.getAttribute("contextmenu") ? "contextmenu" : "";
     let currentContextMenu = aNode.getAttribute(contextMenuAttrName);
     let contextMenuForPlace = aPlace == "panel" ?
                                 kPanelItemContextMenu :
                                 kPaletteItemContextMenu;
     if (aPlace != "toolbar") {
       wrapper.setAttribute("context", contextMenuForPlace);
     }
-    if (currentContextMenu) {
+    // Only keep track of the menu if it is non-default.
+    if (currentContextMenu &&
+        currentContextMenu != contextMenuForPlace) {
       aNode.setAttribute("wrapped-context", currentContextMenu);
       aNode.setAttribute("wrapped-contextAttrName", contextMenuAttrName)
       aNode.removeAttribute(contextMenuAttrName);
+    } else if (currentContextMenu == contextMenuForPlace) {
+      aNode.removeAttribute(contextMenuAttrName);
     }
 
     wrapper.addEventListener("mousedown", this);
     wrapper.addEventListener("mouseup", this);
 
     return wrapper;
   },
 
--- a/browser/components/customizableui/test/browser_880164_customization_context_menus.js
+++ b/browser/components/customizableui/test/browser_880164_customization_context_menus.js
@@ -236,16 +236,61 @@ let gTests = [
       yield hiddenContextPromise;
     },
     teardown: function() {
       yield endCustomizing(this.otherWin);
       this.otherWin.close();
       this.otherWin = null;
     }
   },
+  {
+    desc: "Bug 945191 - Combined buttons show wrong context menu options when they are in the toolbar.",
+    setup: startCustomizing,
+    run: function () {
+      let contextMenu = document.getElementById("customizationPanelItemContextMenu");
+      let shownPromise = contextMenuShown(contextMenu);
+      let zoomControls = document.getElementById("wrapper-zoom-controls");
+      EventUtils.synthesizeMouse(zoomControls, 2, 2, {type: "contextmenu", button: 2});
+      yield shownPromise;
+      // Execute the command to move the item from the panel to the toolbar.
+      contextMenu.childNodes[0].doCommand();
+      let hiddenPromise = contextMenuHidden(contextMenu);
+      contextMenu.hidePopup();
+      yield hiddenPromise;
+      yield endCustomizing();
+
+      zoomControls = document.getElementById("zoom-controls");
+      is(zoomControls.parentNode.id, "nav-bar-customization-target", "Zoom-controls should be on the nav-bar");
+
+      contextMenu = document.getElementById("toolbar-context-menu");
+      shownPromise = contextMenuShown(contextMenu);
+      EventUtils.synthesizeMouse(zoomControls, 2, 2, {type: "contextmenu", button: 2});
+      yield shownPromise;
+
+      let expectedEntries = [
+        [".customize-context-addToPanel", true],
+        [".customize-context-removeFromToolbar", true],
+        ["---"]
+      ];
+      if (!isOSX) {
+        expectedEntries.push(["#toggle_toolbar-menubar", true]);
+      }
+      expectedEntries.push(
+        ["#toggle_PersonalToolbar", true],
+        ["---"],
+        [".viewCustomizeToolbar", true]
+      );
+      checkContextMenu(contextMenu, expectedEntries);
+
+      hiddenPromise = contextMenuHidden(contextMenu);
+      contextMenu.hidePopup();
+      yield hiddenPromise;
+    },
+    teardown: resetCustomization,
+  }
 ];
 
 function test() {
   waitForExplicitFinish();
   runTests(gTests);
 }
 
 function contextMenuShown(aContextMenu) {
--- a/configure.in
+++ b/configure.in
@@ -9122,19 +9122,16 @@ if test -z "$MOZ_NATIVE_NSPR"; then
       export CPPFLAGS="-include $_topsrcdir/mozglue/linker/dladdr.h $CPPFLAGS"
     fi
     export LDFLAGS="$LDFLAGS $NSPR_LDFLAGS"
     export CFLAGS="$CFLAGS $MOZ_FRAMEPTR_FLAGS"
 
     AC_OUTPUT_SUBDIRS(nsprpub)
 
     # .. and restore them
-    unset CFLAGS
-    unset CPPFLAGS
-    unset LDFLAGS
     CFLAGS="$_SAVE_CFLAGS"
     CPPFLAGS="$_SAVE_CPPFLAGS"
     LDFLAGS="$_SAVE_LDFLAGS"
 
     ac_configure_args="$_SUBDIR_CONFIG_ARGS"
 fi
 
 dnl ========================================================
--- a/content/media/directshow/DirectShowDecoder.cpp
+++ b/content/media/directshow/DirectShowDecoder.cpp
@@ -3,17 +3,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "DirectShowDecoder.h"
 #include "DirectShowReader.h"
 #include "MediaDecoderStateMachine.h"
 #include "mozilla/Preferences.h"
-#include "mozilla/WindowsVersion.h"
+#include "mozilla/WindowsVersion.h"
 
 namespace mozilla {
 
 MediaDecoderStateMachine* DirectShowDecoder::CreateStateMachine()
 {
   return new MediaDecoderStateMachine(this, new DirectShowReader(this));
 }
 
@@ -40,18 +40,17 @@ DirectShowDecoder::GetSupportedCodecs(co
 
   return false;
 }
 
 /* static */
 bool
 DirectShowDecoder::IsEnabled()
 {
-  return !IsVistaOrLater() &&
-         Preferences::GetBool("media.directshow.enabled");
+  return Preferences::GetBool("media.directshow.enabled");
 }
 
 DirectShowDecoder::DirectShowDecoder()
 {
   MOZ_COUNT_CTOR(DirectShowDecoder);
 }
 
 DirectShowDecoder::~DirectShowDecoder()
--- a/content/media/fmp4/BlankDecoderModule.cpp
+++ b/content/media/fmp4/BlankDecoderModule.cpp
@@ -193,28 +193,28 @@ class BlankDecoderModule : public Platfo
 public:
 
   // Called when the decoders have shutdown. Main thread only.
   virtual nsresult Shutdown() MOZ_OVERRIDE {
     return NS_OK;
   }
 
   // Decode thread.
-  virtual MediaDataDecoder* CreateVideoDecoder(layers::LayersBackend aLayersBackend,
-                                               layers::ImageContainer* aImageContainer) MOZ_OVERRIDE {
+  virtual MediaDataDecoder* CreateH264Decoder(layers::LayersBackend aLayersBackend,
+                                              layers::ImageContainer* aImageContainer) MOZ_OVERRIDE {
     BlankVideoDataCreator* decoder = new BlankVideoDataCreator(aImageContainer);
     return new BlankMediaDataDecoder<BlankVideoDataCreator>(decoder);
   }
 
   // Decode thread.
-  virtual MediaDataDecoder* CreateAudioDecoder(uint32_t aChannelCount,
-                                               uint32_t aSampleRate,
-                                               uint16_t aBitsPerSample,
-                                               const uint8_t* aUserData,
-                                               uint32_t aUserDataLength) MOZ_OVERRIDE {
+  virtual MediaDataDecoder* CreateAACDecoder(uint32_t aChannelCount,
+                                             uint32_t aSampleRate,
+                                             uint16_t aBitsPerSample,
+                                             const uint8_t* aUserData,
+                                             uint32_t aUserDataLength) MOZ_OVERRIDE {
     BlankAudioDataCreator* decoder = new BlankAudioDataCreator(aChannelCount,
                                                                aSampleRate,
                                                                aBitsPerSample);
     return new BlankMediaDataDecoder<BlankAudioDataCreator>(decoder);
   }
 };
 
 PlatformDecoderModule* CreateBlankDecoderModule()
--- a/content/media/fmp4/MP4Reader.cpp
+++ b/content/media/fmp4/MP4Reader.cpp
@@ -155,31 +155,31 @@ MP4Reader::ReadMetadata(MediaInfo* aInfo
   // If we have video, we *only* allow H.264 to be decoded.
   if (mHasVideo && video.codec() != kCodecH264) {
     return NS_ERROR_FAILURE;
   }
 
   if (mHasAudio) {
     mInfo.mAudio.mRate = audio.samples_per_second();
     mInfo.mAudio.mChannels = ChannelLayoutToChannelCount(audio.channel_layout());
-    mAudioDecoder = mPlatform->CreateAudioDecoder(mInfo.mAudio.mChannels,
-                                                  mInfo.mAudio.mRate,
-                                                  audio.bits_per_channel(),
-                                                  audio.extra_data(),
-                                                  audio.extra_data_size());
+    mAudioDecoder = mPlatform->CreateAACDecoder(mInfo.mAudio.mChannels,
+                                                mInfo.mAudio.mRate,
+                                                audio.bits_per_channel(),
+                                                audio.extra_data(),
+                                                audio.extra_data_size());
     NS_ENSURE_TRUE(mAudioDecoder != nullptr, NS_ERROR_FAILURE);
   }
 
   mInfo.mVideo.mHasVideo = mHasVideo = mDemuxer->HasVideo();
   if (mHasVideo) {
     const VideoDecoderConfig& config = mDemuxer->VideoConfig();
     IntSize sz = config.natural_size();
     mInfo.mVideo.mDisplay = nsIntSize(sz.width(), sz.height());
-    mVideoDecoder = mPlatform->CreateVideoDecoder(mLayersBackendType,
-                                                  mDecoder->GetImageContainer());
+    mVideoDecoder = mPlatform->CreateH264Decoder(mLayersBackendType,
+                                                 mDecoder->GetImageContainer());
     NS_ENSURE_TRUE(mVideoDecoder != nullptr, NS_ERROR_FAILURE);
   }
 
   // Get the duration, and report it to the decoder if we have it.
   Microseconds duration = mDemuxer->Duration();
   if (duration != -1) {
     ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
     mDecoder->SetMediaDuration(duration);
--- a/content/media/fmp4/PlatformDecoderModule.cpp
+++ b/content/media/fmp4/PlatformDecoderModule.cpp
@@ -25,19 +25,9 @@ PlatformDecoderModule::Create()
   nsAutoPtr<WMFDecoderModule> m(new WMFDecoderModule());
   if (NS_SUCCEEDED(m->Init())) {
     return m.forget();
   }
 #endif
   return nullptr;
 }
 
-void
-PlatformDecoderModule::OnDecodeThreadStart()
-{
-}
-
-void
-PlatformDecoderModule::OnDecodeThreadFinish()
-{
-}
-
 } // namespace mozilla
--- a/content/media/fmp4/PlatformDecoderModule.h
+++ b/content/media/fmp4/PlatformDecoderModule.h
@@ -11,74 +11,150 @@
 #include "mozilla/layers/LayersTypes.h"
 
 namespace mozilla {
 
 namespace layers {
 class ImageContainer;
 }
 
+class MediaDataDecoder;
 typedef int64_t Microseconds;
 
+// The PlatformDecoderModule interface is used by the MP4Reader to abstract
+// access to the H264 and AAC decoders provided by various platforms. It
+// may be extended to support other codecs in future. Each platform (Windows,
+// MacOSX, Linux etc) must implement a PlatformDecoderModule to provide access
+// to its decoders in order to get decompressed H.264/AAC from the MP4Reader.
+//
+// Platforms that don't have a corresponding PlatformDecoderModule won't be
+// able to play the H.264/AAC data output by the MP4Reader. In practice this
+// means that we won't have fragmented MP4 supported in Media Source
+// Extensions on platforms without PlatformDecoderModules.
+//
+// A cross-platform decoder module that discards input and produces "blank"
+// output samples exists for testing, and is created if the pref
+// "media.fragmented-mp4.use-blank-decoder" is true.
+class PlatformDecoderModule {
+public:
+
+  // Factory method that creates the appropriate PlatformDecoderModule for
+  // the platform we're running on. Caller is responsible for deleting this
+  // instance. It's expected that there will be multiple
+  // PlatformDecoderModules alive at the same time. There is one
+  // PlatformDecoderModule's created per MP4Reader.
+  // This is called on the main thread.
+  static PlatformDecoderModule* Create();
+
+  // Called to shutdown the decoder module and cleanup state. This should
+  // block until shutdown is complete. This is called after Shutdown() has
+  // been called on all MediaDataDecoders created from this
+  // PlatformDecoderModule.
+  // Called on the main thread only.
+  virtual nsresult Shutdown() = 0;
+
+  // Creates and initializes an H.264 decoder. The layers backend is
+  // passed in so that decoders can determine whether hardware accelerated
+  // decoding can be used. Returns nullptr if the decoder can't be
+  // initialized.
+  // Called on decode thread.
+  virtual MediaDataDecoder* CreateH264Decoder(layers::LayersBackend aLayersBackend,
+                                              layers::ImageContainer* aImageContainer) = 0;
+
+  // Creates and initializes an AAC decoder with the specified properties.
+  // The raw AAC AudioSpecificConfig as contained in the esds box. Some
+  // decoders need that to initialize. The caller owns the AAC config,
+  // so it must be copied if it is to be retained by the decoder.
+  // Returns nullptr if the decoder can't be initialized.
+  // Called on decode thread.
+  virtual MediaDataDecoder* CreateAACDecoder(uint32_t aChannelCount,
+                                             uint32_t aSampleRate,
+                                             uint16_t aBitsPerSample,
+                                             const uint8_t* aAACConfig,
+                                             uint32_t aAACConfigLength) = 0;
+
+  // Called when a decode thread is started. Called on decode thread.
+  virtual void OnDecodeThreadStart() {}
+
+  // Called just before a decode thread is finishing. Called on decode thread.
+  virtual void OnDecodeThreadFinish() {}
+
+  virtual ~PlatformDecoderModule() {}
+protected:
+  PlatformDecoderModule() {}
+};
+
+// Return value of the MediaDataDecoder functions.
 enum DecoderStatus {
-  DECODE_STATUS_NOT_ACCEPTING, // Can't accept input at this time.
-  DECODE_STATUS_NEED_MORE_INPUT, // Nothing in pipeline to produce output with at this time.
+  DECODE_STATUS_NOT_ACCEPTING, // Can't accept input at this time. Decoder can produce output.
+  DECODE_STATUS_NEED_MORE_INPUT, // Can't produce output. Decoder can accept input.
   DECODE_STATUS_OK,
   DECODE_STATUS_ERROR
 };
 
+// MediaDataDecoder is the interface exposed by decoders created by the
+// PlatformDecoderModule's Create*Decoder() functions. The type of
+// media data that the decoder accepts as valid input and produces as
+// output is determined when the MediaDataDecoder is created.
+// The decoder is assumed to be in one of three mutually exclusive and
+// implicit states: able to accept input, able to produce output, and
+// shutdown. The decoder is assumed to be able to accept input by the time
+// that it's returned by PlatformDecoderModule::Create*Decoder().
 class MediaDataDecoder {
 public:
   virtual ~MediaDataDecoder() {};
 
-  virtual nsresult Shutdown() = 0;
-
-  // Returns true if future decodes may produce output, or false
-  // on end of segment.
-  // Inserts data into the decoder's pipeline.
+  // Inserts aData into the decoding pipeline. Decoding may begin
+  // asynchronously. The caller owns aData, so it may need to be copied.
+  // The MP4Reader calls Input() with new input in a loop until Input()
+  // stops returning DECODE_STATUS_OK.
+  // Called on the media decode thread.
+  // Returns:
+  //  - DECODE_STATUS_OK if input was successfully inserted into
+  //    the decode pipeline.
+  //  - DECODE_STATUS_NOT_ACCEPTING if the decoder cannot accept any input
+  //    at this time. The MP4Reader will assume that the decoder can now
+  //    produce one or more output samples, and call the Output() function.
+  //    The MP4Reader will call Input() again with the same data later,
+  //    after the decoder's Output() function has stopped producing output.
+  //  - DECODE_STATUS_ERROR if the decoder has been shutdown, or some
+  //    unspecified error.
+  // This function should not return DECODE_STATUS_NEED_MORE_INPUT.
   virtual DecoderStatus Input(const uint8_t* aData,
                               uint32_t aLength,
                               Microseconds aDTS,
                               Microseconds aPTS,
                               int64_t aOffsetInStream) = 0;
 
-  // Blocks until decoded sample is produced by the deoder.
+  // Blocks until a decoded sample is produced by the deoder. The MP4Reader
+  // calls this until it stops returning DECODE_STATUS_OK.
+  // Called on the media decode thread.
+  // Returns:
+  //  - DECODE_STATUS_OK if an output sample was successfully placed in
+  //    aOutData. More samples for output may still be available, the
+  //    MP4Reader will call again to check.
+  //  - DECODE_STATUS_NEED_MORE_INPUT if the decoder needs more input to
+  //    produce a sample. The decoder should return this once it can no
+  //    longer produce output. This signals to the MP4Reader that it should
+  //    start feeding in data via the Input() function.
+  //  - DECODE_STATUS_ERROR if the decoder has been shutdown, or some
+  //    unspecified error.
+  // This function should not return DECODE_STATUS_NOT_ACCEPTING.
   virtual DecoderStatus Output(nsAutoPtr<MediaData>& aOutData) = 0;
 
+  // Causes all samples in the decoding pipeline to be discarded. When
+  // this function returns, the decoder must be ready to accept new input
+  // for decoding. This function is called when the demuxer seeks, before
+  // decoding resumes after the seek.
+  // Called on the media decode thread.
   virtual DecoderStatus Flush() = 0;
-};
-
-class PlatformDecoderModule {
-public:
 
-  // Creates the appropriate PlatformDecoderModule for this platform.
-  // Caller is responsible for deleting this instance. It's safe to have
-  // multiple PlatformDecoderModules alive at the same time.
-  // There is one PlatformDecoderModule's created per media decoder.
-  static PlatformDecoderModule* Create();
-
-  // Called when the decoders have shutdown. Main thread only.
+  // Cancels all decode operations, and shuts down the decoder. This should
+  // block until shutdown is complete. The decoder should return
+  // DECODE_STATUS_ERROR for all calls to its functions once this is called.
+  // Called on main thread.
   virtual nsresult Shutdown() = 0;
 
-  // TODO: Parameters for codec type.
-  // Decode thread.
-  virtual MediaDataDecoder* CreateVideoDecoder(layers::LayersBackend aLayersBackend,
-                                               layers::ImageContainer* aImageContainer) = 0;
-
-  // Decode thread.
-  virtual MediaDataDecoder* CreateAudioDecoder(uint32_t aChannelCount,
-                                               uint32_t aSampleRate,
-                                               uint16_t aBitsPerSample,
-                                               const uint8_t* aUserData,
-                                               uint32_t aUserDataLength) = 0;
-
-  // Platform decoders can override these. Base implementation does nothing.
-  virtual void OnDecodeThreadStart();
-  virtual void OnDecodeThreadFinish();
-
-  virtual ~PlatformDecoderModule() {}
-protected:
-  PlatformDecoderModule() {}
 };
 
 } // namespace mozilla
 
 #endif
--- a/content/media/fmp4/wmf/WMFDecoderModule.cpp
+++ b/content/media/fmp4/wmf/WMFDecoderModule.cpp
@@ -51,31 +51,31 @@ WMFDecoderModule::Shutdown()
 
   DebugOnly<HRESULT> hr = wmf::MFShutdown();
   NS_ASSERTION(SUCCEEDED(hr), "MFShutdown failed");
 
   return NS_OK;
 }
 
 MediaDataDecoder*
-WMFDecoderModule::CreateVideoDecoder(mozilla::layers::LayersBackend aLayersBackend,
-                                     mozilla::layers::ImageContainer* aImageContainer)
+WMFDecoderModule::CreateH264Decoder(mozilla::layers::LayersBackend aLayersBackend,
+                                    mozilla::layers::ImageContainer* aImageContainer)
 {
   nsAutoPtr<WMFVideoDecoder> decoder(new WMFVideoDecoder(mDXVAEnabled));
   nsresult rv = decoder->Init(aLayersBackend, aImageContainer);
   NS_ENSURE_SUCCESS(rv, nullptr);
   return decoder.forget();
 }
 
 MediaDataDecoder*
-WMFDecoderModule::CreateAudioDecoder(uint32_t aChannelCount,
-                                     uint32_t aSampleRate,
-                                     uint16_t aBitsPerSample,
-                                     const uint8_t* aUserData,
-                                     uint32_t aUserDataLength)
+WMFDecoderModule::CreateAACDecoder(uint32_t aChannelCount,
+                                   uint32_t aSampleRate,
+                                   uint16_t aBitsPerSample,
+                                   const uint8_t* aUserData,
+                                   uint32_t aUserDataLength)
 {
   nsAutoPtr<WMFAudioDecoder> decoder(new WMFAudioDecoder());
   nsresult rv = decoder->Init(aChannelCount,
                               aSampleRate,
                               aBitsPerSample,
                               aUserData,
                               aUserDataLength);
   NS_ENSURE_SUCCESS(rv, nullptr);
--- a/content/media/fmp4/wmf/WMFDecoderModule.h
+++ b/content/media/fmp4/wmf/WMFDecoderModule.h
@@ -21,25 +21,25 @@ public:
   nsresult Init();
 
   // Called when the decoders have shutdown. Main thread only.
   // Does this really need to be main thread only????
   virtual nsresult Shutdown() MOZ_OVERRIDE;
 
   // Decode thread.
   virtual MediaDataDecoder*
-  CreateVideoDecoder(mozilla::layers::LayersBackend aLayersBackend,
-                     mozilla::layers::ImageContainer* aImageContainer) MOZ_OVERRIDE;
+  CreateH264Decoder(mozilla::layers::LayersBackend aLayersBackend,
+                    mozilla::layers::ImageContainer* aImageContainer) MOZ_OVERRIDE;
 
   // Decode thread.
-  virtual MediaDataDecoder* CreateAudioDecoder(uint32_t aChannelCount,
-                                               uint32_t aSampleRate,
-                                               uint16_t aBitsPerSample,
-                                               const uint8_t* aUserData,
-                                               uint32_t aUserDataLength) MOZ_OVERRIDE;
+  virtual MediaDataDecoder* CreateAACDecoder(uint32_t aChannelCount,
+                                             uint32_t aSampleRate,
+                                             uint16_t aBitsPerSample,
+                                             const uint8_t* aUserData,
+                                             uint32_t aUserDataLength) MOZ_OVERRIDE;
 
   // Platform decoders can override these. Base implementation does nothing.
   virtual void OnDecodeThreadStart() MOZ_OVERRIDE;
   virtual void OnDecodeThreadFinish() MOZ_OVERRIDE;
 private:
   const bool mDXVAEnabled;
 };
 
--- a/content/media/webaudio/AudioBufferSourceNode.cpp
+++ b/content/media/webaudio/AudioBufferSourceNode.cpp
@@ -52,17 +52,17 @@ NS_IMPL_RELEASE_INHERITED(AudioBufferSou
  */
 class AudioBufferSourceNodeEngine : public AudioNodeEngine
 {
 public:
   explicit AudioBufferSourceNodeEngine(AudioNode* aNode,
                                        AudioDestinationNode* aDestination) :
     AudioNodeEngine(aNode),
     mStart(0), mStop(TRACK_TICKS_MAX),
-    mResampler(nullptr),
+    mResampler(nullptr), mRemainingResamplerTail(0),
     mOffset(0), mDuration(0),
     mLoopStart(0), mLoopEnd(0),
     mBufferSampleRate(0), mPosition(0), mChannels(0), mPlaybackRate(1.0f),
     mDopplerShift(1.0f),
     mDestination(static_cast<AudioNodeStream*>(aDestination->Stream())),
     mPlaybackRateTimeline(1.0f), mLoop(false)
   {}
 
@@ -80,25 +80,16 @@ public:
 
   virtual void SetTimelineParameter(uint32_t aIndex,
                                     const dom::AudioParamTimeline& aValue,
                                     TrackRate aSampleRate) MOZ_OVERRIDE
   {
     switch (aIndex) {
     case AudioBufferSourceNode::PLAYBACKRATE:
       mPlaybackRateTimeline = aValue;
-      // If we have a simple value that is 1.0 (i.e. intrinsic speed), and our
-      // input buffer is already at the ideal audio rate, and we have a
-      // resampler, we can release it.
-      if (mResampler && mPlaybackRateTimeline.HasSimpleValue() &&
-          mPlaybackRateTimeline.GetValue() == 1.0 &&
-          mBufferSampleRate == aSampleRate) {
-        speex_resampler_destroy(mResampler);
-        mResampler = nullptr;
-      }
       WebAudioUtils::ConvertAudioParamToTicks(mPlaybackRateTimeline, mSource, mDestination);
       break;
     default:
       NS_ERROR("Bad AudioBufferSourceNodeEngine TimelineParameter");
     }
   }
   virtual void SetStreamTimeParameter(uint32_t aIndex, TrackTicks aParam)
   {
@@ -145,16 +136,17 @@ public:
     }
 
     if (!mResampler) {
       mChannels = aChannels;
       mResampler = speex_resampler_init(mChannels, mBufferSampleRate,
                                         ComputeFinalOutSampleRate(aStream->SampleRate()),
                                         SPEEX_RESAMPLER_QUALITY_DEFAULT,
                                         nullptr);
+      speex_resampler_skip_zeros(mResampler);
     }
     return mResampler;
   }
 
   // Borrow a full buffer of size WEBAUDIO_BLOCK_SIZE from the source buffer
   // at offset aSourceOffset.  This avoids copying memory.
   void BorrowFromInputBuffer(AudioChunk* aOutput,
                              uint32_t aChannels,
@@ -191,49 +183,84 @@ public:
   // remaining in both the input and output buffer, and the playback rate (that
   // is, the ratio between the output samplerate and the input samplerate).
   void CopyFromInputBufferWithResampling(AudioNodeStream* aStream,
                                          AudioChunk* aOutput,
                                          uint32_t aChannels,
                                          uintptr_t aSourceOffset,
                                          uintptr_t aBufferOffset,
                                          uint32_t aAvailableInInputBuffer,
-                                         uint32_t& aFramesRead,
                                          uint32_t& aFramesWritten) {
-    double finalPlaybackRate =
-      static_cast<double>(mBufferSampleRate) / ComputeFinalOutSampleRate(aStream->SampleRate());
-    uint32_t availableInOuputBuffer = WEBAUDIO_BLOCK_SIZE - aBufferOffset;
-    uint32_t inputSamples, outputSamples;
-
-    // Check if we are short on input or output buffer.
-    if (aAvailableInInputBuffer < availableInOuputBuffer * finalPlaybackRate) {
-      outputSamples = ceil(aAvailableInInputBuffer / finalPlaybackRate);
-      inputSamples = aAvailableInInputBuffer;
-    } else {
-      inputSamples = ceil(availableInOuputBuffer * finalPlaybackRate);
-      outputSamples = availableInOuputBuffer;
-    }
-
+    // TODO: adjust for mStop (see bug 913854 comment 9).
+    uint32_t availableInOutputBuffer = WEBAUDIO_BLOCK_SIZE - aBufferOffset;
     SpeexResamplerState* resampler = Resampler(aStream, aChannels);
+    MOZ_ASSERT(aChannels > 0);
 
-    for (uint32_t i = 0; i < aChannels; ++i) {
-      uint32_t inSamples = inputSamples;
-      uint32_t outSamples = outputSamples;
+    if (aAvailableInInputBuffer) {
+      // Limit the number of input samples copied and possibly
+      // format-converted for resampling by estimating how many will be used.
+      // This may be a little small when filling the resampler with initial
+      // data, but we'll get called again and it will work out.
+      uint32_t num, den;
+      speex_resampler_get_ratio(resampler, &num, &den);
+      uint32_t inputLimit = std::min(aAvailableInInputBuffer,
+                                     availableInOutputBuffer * den / num + 10);
+      for (uint32_t i = 0; true; ) {
+        uint32_t inSamples = inputLimit;
+        const float* inputData = mBuffer->GetData(i) + aSourceOffset;
+
+        uint32_t outSamples = availableInOutputBuffer;
+        float* outputData =
+          static_cast<float*>(const_cast<void*>(aOutput->mChannelData[i])) +
+          aBufferOffset;
 
-      const float* inputData = mBuffer->GetData(i) + aSourceOffset;
-      float* outputData =
-        static_cast<float*>(const_cast<void*>(aOutput->mChannelData[i])) +
-        aBufferOffset;
+        WebAudioUtils::SpeexResamplerProcess(resampler, i,
+                                             inputData, &inSamples,
+                                             outputData, &outSamples);
+        if (++i == aChannels) {
+          mPosition += inSamples;
+          MOZ_ASSERT(mPosition <= mDuration);
+          aFramesWritten = outSamples;
+          if (inSamples == aAvailableInInputBuffer && !mLoop) {
+            // If the available output space were unbounded then the input
+            // latency would always be the correct amount of extra input to
+            // provide in order to advance the output position to align with
+            // the final point in the buffer.  However, when the output space
+            // becomes full, the resampler may read all available input
+            // without writing out the corresponding output.  Add one more
+            // input sample, so that we know that enough output has been
+            // written when the last input sample has been read.  This may
+            // often write more than necessary but the extra samples will be
+            // based on (mostly) zero input.
+            mRemainingResamplerTail =
+              speex_resampler_get_input_latency(resampler) + 1;
+          }
+          return;
+        }
+      }
+    } else {
+      for (uint32_t i = 0; true; ) {
+        uint32_t inSamples = mRemainingResamplerTail;
+        uint32_t outSamples = availableInOutputBuffer;
+        float* outputData =
+          static_cast<float*>(const_cast<void*>(aOutput->mChannelData[i])) +
+          aBufferOffset;
 
-      WebAudioUtils::SpeexResamplerProcess(resampler, i,
-                                           inputData, &inSamples,
-                                           outputData, &outSamples);
-
-      aFramesRead = inSamples;
-      aFramesWritten = outSamples;
+        // AudioDataValue* for aIn selects the function that does not try to
+        // copy and format-convert input data.
+        WebAudioUtils::SpeexResamplerProcess(resampler, i,
+                         static_cast<AudioDataValue*>(nullptr), &inSamples,
+                         outputData, &outSamples);
+        if (++i == aChannels) {
+          mRemainingResamplerTail -= inSamples;
+          MOZ_ASSERT(mRemainingResamplerTail >= 0);
+          aFramesWritten = outSamples;
+          break;
+        }
+      }
     }
   }
 
   /**
    * Fill aOutput with as many zero frames as we can, and advance
    * aOffsetWithinBlock and aCurrentPosition based on how many frames we write.
    * This will never advance aOffsetWithinBlock past WEBAUDIO_BLOCK_SIZE or
    * aCurrentPosition past aMaxPos.  This function knows when it needs to
@@ -295,24 +322,23 @@ public:
         AllocateAudioBlock(aChannels, aOutput);
       }
       if (!ShouldResample(aStream->SampleRate())) {
         CopyFromInputBuffer(aOutput, aChannels, aBufferOffset, *aOffsetWithinBlock, numFrames);
         *aOffsetWithinBlock += numFrames;
         *aCurrentPosition += numFrames;
         mPosition += numFrames;
       } else {
-        uint32_t framesRead, framesWritten, availableInInputBuffer;
+        uint32_t framesWritten, availableInInputBuffer;
 
         availableInInputBuffer = aBufferMax - aBufferOffset;
 
-        CopyFromInputBufferWithResampling(aStream, aOutput, aChannels, aBufferOffset, *aOffsetWithinBlock, availableInInputBuffer, framesRead, framesWritten);
+        CopyFromInputBufferWithResampling(aStream, aOutput, aChannels, aBufferOffset, *aOffsetWithinBlock, availableInInputBuffer, framesWritten);
         *aOffsetWithinBlock += framesWritten;
         *aCurrentPosition += framesWritten;
-        mPosition += framesRead;
       }
     }
   }
 
   uint32_t ComputeFinalOutSampleRate(TrackRate aStreamSampleRate)
   {
     if (mPlaybackRate <= 0 || mPlaybackRate != mPlaybackRate) {
       mPlaybackRate = 1.0f;
@@ -321,19 +347,22 @@ public:
       mDopplerShift = 1.0f;
     }
     return WebAudioUtils::TruncateFloatToInt<uint32_t>(aStreamSampleRate /
                                                        (mPlaybackRate * mDopplerShift));
   }
 
   bool ShouldResample(TrackRate aStreamSampleRate) const
   {
-    return !(mPlaybackRate == 1.0 &&
-             mDopplerShift == 1.0 &&
-             mBufferSampleRate == aStreamSampleRate);
+    // There is latency in the resampler.  If there is already a resampler,
+    // then it will have moved mPosition to after the samples it has read, but
+    // it hasn't output its buffered samples.  Keep using the resampler, even
+    // if the rates now match, so that this latency segment is output.
+    return mResampler ||
+      (mPlaybackRate * mDopplerShift * mBufferSampleRate != aStreamSampleRate);
   }
 
   void UpdateSampleRateIfNeeded(AudioNodeStream* aStream, uint32_t aChannels)
   {
     if (mPlaybackRateTimeline.HasSimpleValue()) {
       mPlaybackRate = mPlaybackRateTimeline.GetValue();
     } else {
       mPlaybackRate = mPlaybackRateTimeline.GetValueAtTime(aStream->GetCurrentPosition());
@@ -341,19 +370,19 @@ public:
 
     // Make sure the playback rate and the doppler shift are something
     // our resampler can work with.
     if (ComputeFinalOutSampleRate(aStream->SampleRate()) == 0) {
       mPlaybackRate = 1.0;
       mDopplerShift = 1.0;
     }
 
-    uint32_t currentOutSampleRate, currentInSampleRate;
-    if (ShouldResample(aStream->SampleRate())) {
+    if (mResampler) {
       SpeexResamplerState* resampler = Resampler(aStream, aChannels);
+      uint32_t currentOutSampleRate, currentInSampleRate;
       speex_resampler_get_rate(resampler, &currentInSampleRate, &currentOutSampleRate);
       uint32_t finalSampleRate = ComputeFinalOutSampleRate(aStream->SampleRate());
       if (currentOutSampleRate != finalSampleRate) {
         speex_resampler_set_rate(resampler, currentInSampleRate, finalSampleRate);
       }
     }
   }
 
@@ -393,35 +422,39 @@ public:
       if (mLoop) {
         if (mOffset + t < mLoopEnd) {
           CopyFromBuffer(aStream, aOutput, channels, &written, &streamPosition, mOffset + t, mLoopEnd);
         } else {
           uint32_t offsetInLoop = (mOffset + t - mLoopEnd) % (mLoopEnd - mLoopStart);
           CopyFromBuffer(aStream, aOutput, channels, &written, &streamPosition, mLoopStart + offsetInLoop, mLoopEnd);
         }
       } else {
-        if (t < mDuration) {
+        if (t < mDuration || mRemainingResamplerTail) {
           CopyFromBuffer(aStream, aOutput, channels, &written, &streamPosition, mOffset + t, mOffset + mDuration);
         } else {
           FillWithZeroes(aOutput, channels, &written, &streamPosition, TRACK_TICKS_MAX);
         }
       }
     }
 
     // We've finished if we've gone past mStop, or if we're past mDuration when
     // looping is disabled.
-    if (streamPosition >= mStop || (!mLoop && mPosition >= mDuration)) {
+    if (streamPosition >= mStop ||
+        (!mLoop && mPosition >= mDuration && !mRemainingResamplerTail)) {
       *aFinished = true;
     }
   }
 
   TrackTicks mStart;
   TrackTicks mStop;
   nsRefPtr<ThreadSharedFloatArrayBufferList> mBuffer;
   SpeexResamplerState* mResampler;
+  // mRemainingResamplerTail, like mPosition, mOffset, and mDuration, is
+  // measured in input buffer samples.
+  int mRemainingResamplerTail;
   int32_t mOffset;
   int32_t mDuration;
   int32_t mLoopStart;
   int32_t mLoopEnd;
   int32_t mBufferSampleRate;
   int32_t mPosition;
   uint32_t mChannels;
   float mPlaybackRate;
--- a/content/media/webaudio/test/test_mediaDecoding.html
+++ b/content/media/webaudio/test/test_mediaDecoding.html
@@ -1,12 +1,12 @@
 <!DOCTYPE HTML>
 <html>
 <head>
-  <title>Test the decodeAudioData API</title>
+  <title>Test the decodeAudioData API and Resampling</title>
   <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 </head>
 <body>
 <pre id="test">
 <script src="webaudio.js" type="text/javascript"></script>
 <script type="text/javascript">
 
@@ -224,42 +224,114 @@ function fuzzyMemcmp(buf1, buf2, fuzz) {
 
 function getFuzzTolerance(test) {
   var kIsMobile =
     navigator.userAgent.indexOf("Mobile") != -1 || // b2g
     navigator.userAgent.indexOf("Android") != -1;  // android
   return kIsMobile ? test.fuzzToleranceMobile : test.fuzzTolerance;
 }
 
+function bufferIsSilent(buffer) {
+  for (var i = 0; i < buffer.length; ++i) {
+    if (buffer.getChannelData(0)[i] != 0) {
+      return false;
+    }
+  }
+  return true;
+}
+
 function checkAudioBuffer(buffer, test) {
-  is(buffer.numberOfChannels, test.numberOfChannels, "Correct number of channels");
+  if (buffer.numberOfChannels != test.numberOfChannels) {
+    is(buffer.numberOfChannels, test.numberOfChannels, "Correct number of channels");
+    return;
+  }
   ok(Math.abs(buffer.duration - test.duration) < 1e-3, "Correct duration");
   if (Math.abs(buffer.duration - test.duration) >= 1e-3) {
     ok(false, "got: " + buffer.duration  + ", expected: " + test.duration);
   }
   is(buffer.sampleRate, test.sampleRate, "Correct sample rate");
-  // Take into account the resampling when checking the size
-  var expectedLength = test.frames * buffer.sampleRate / test.sampleRate;
-  ok(Math.abs(buffer.length - expectedLength) < 1.0, "Correct length", "got " + buffer.length + ", expected about " + expectedLength);
+  is(buffer.length, test.frames, "Correct length");
 
   var wave = createWaveFileData(buffer);
   ok(fuzzyMemcmp(wave, test.expectedWaveData, getFuzzTolerance(test)), "Received expected decoded data");
 }
 
+function checkResampledBuffer(buffer, test, callback) {
+  if (buffer.numberOfChannels != test.numberOfChannels) {
+    is(buffer.numberOfChannels, test.numberOfChannels, "Correct number of channels");
+    return;
+  }
+  ok(Math.abs(buffer.duration - test.duration) < 1e-3, "Correct duration");
+  if (Math.abs(buffer.duration - test.duration) >= 1e-3) {
+    ok(false, "got: " + buffer.duration  + ", expected: " + test.duration);
+  }
+  // Take into account the resampling when checking the size
+  var expectedLength = test.frames * buffer.sampleRate / test.sampleRate;
+  ok(Math.abs(buffer.length - expectedLength) < 1.0, "Correct length", "got " + buffer.length + ", expected about " + expectedLength);
+
+  // Playback the buffer in the original context, to resample back to the
+  // original rate and compare with the decoded buffer without resampling.
+  cx = test.nativeContext;
+  var expected = cx.createBufferSource();
+  expected.buffer = test.expectedBuffer;
+  expected.start();
+  var inverse = cx.createGain();
+  inverse.gain.value = -1;
+  expected.connect(inverse);
+  inverse.connect(cx.destination);
+  var resampled = cx.createBufferSource();
+  resampled.buffer = buffer;
+  resampled.start();
+  // This stop should do nothing, but it tests for bug 937475
+  resampled.stop(test.frames / cx.sampleRate);
+  resampled.connect(cx.destination);
+  cx.oncomplete = function(e) {
+    ok(!bufferIsSilent(e.renderedBuffer), "Expect buffer not silent");
+    // Resampling will lose the highest frequency components, so we should
+    // pass the difference through a low pass filter.  However, either the
+    // input files don't have significant high frequency components or the
+    // tolerance in compareBuffers() is too high to detect them.
+    compareBuffers(e.renderedBuffer,
+                   cx.createBuffer(test.numberOfChannels,
+                                   test.frames, test.sampleRate));
+    callback();
+  }
+  cx.startRendering();
+}
+
+function runResampling(test, response, callback) {
+  var sampleRate = test.sampleRate == 44100 ? 48000 : 44100;
+  var cx = new OfflineAudioContext(1, 1, sampleRate);
+  cx.decodeAudioData(response, function onSuccess(asyncResult) {
+    is(asyncResult.sampleRate, sampleRate, "Correct sample rate");
+    syncResult = cx.createBuffer(response, false);
+    compareBuffers(syncResult, asyncResult);
+
+    checkResampledBuffer(asyncResult, test, callback);
+  }, function onFailure() {
+    ok(false, "Expected successful decode with resample");
+    callback();
+  });
+}
+
 function runTest(test, response, callback) {
   var expectCallback = false;
-  var cx = new OfflineAudioContext(1, 1, test.sampleRate);
+  var cx = new OfflineAudioContext(test.numberOfChannels || 1,
+                                   test.frames || 1, test.sampleRate);
   cx.decodeAudioData(response, function onSuccess(asyncResult) {
     ok(expectCallback, "Success callback should fire asynchronously");
     ok(test.valid, "Did expect success for test " + test.url);
-    checkAudioBuffer(asyncResult, test);
 
     syncResult = cx.createBuffer(response, false);
     compareBuffers(syncResult, asyncResult);
-    callback();
+    checkAudioBuffer(asyncResult, test);
+
+    test.expectedBuffer = asyncResult;
+    test.nativeContext = cx;
+    runResampling(test, response, callback);
   }, function onFailure() {
     ok(expectCallback, "Failure callback should fire asynchronously");
     ok(!test.valid, "Did expect failure for test " + test.url);
     callback();
   });
   expectCallback = true;
 }
 
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -1306,24 +1306,33 @@ ContentChild::RecvActivateA11y()
         do_GetService("@mozilla.org/accessibilityService;1");
 #endif
     return true;
 }
 
 bool
 ContentChild::RecvGarbageCollect()
 {
+    // Rebroadcast the "child-gc-request" so that workers will GC.
+    nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
+    if (obs) {
+        obs->NotifyObservers(nullptr, "child-gc-request", nullptr);
+    }
     nsJSContext::GarbageCollectNow(JS::gcreason::DOM_IPC);
     return true;
 }
 
 bool
 ContentChild::RecvCycleCollect()
 {
-    nsJSContext::GarbageCollectNow(JS::gcreason::DOM_IPC);
+    // Rebroadcast the "child-cc-request" so that workers will CC.
+    nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
+    if (obs) {
+        obs->NotifyObservers(nullptr, "child-cc-request", nullptr);
+    }
     nsJSContext::CycleCollectNow();
     return true;
 }
 
 #ifdef MOZ_NUWA_PROCESS
 static void
 OnFinishNuwaPreparation ()
 {
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -622,16 +622,17 @@ ContentParent::Init()
     nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
     if (obs) {
         obs->AddObserver(this, "xpcom-shutdown", false);
         obs->AddObserver(this, NS_IPC_IOSERVICE_SET_OFFLINE_TOPIC, false);
         obs->AddObserver(this, "child-memory-reporter-request", false);
         obs->AddObserver(this, "memory-pressure", false);
         obs->AddObserver(this, "child-gc-request", false);
         obs->AddObserver(this, "child-cc-request", false);
+        obs->AddObserver(this, "child-mmu-request", false);
         obs->AddObserver(this, "last-pb-context-exited", false);
         obs->AddObserver(this, "file-watcher-update", false);
 #ifdef MOZ_WIDGET_GONK
         obs->AddObserver(this, NS_VOLUME_STATE_CHANGED, false);
         obs->AddObserver(this, "phone-state-changed", false);
 #endif
 #ifdef ACCESSIBILITY
         obs->AddObserver(this, "a11y-init-or-shutdown", false);
@@ -1003,16 +1004,17 @@ ContentParent::ActorDestroy(ActorDestroy
     nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
     if (obs) {
         obs->RemoveObserver(static_cast<nsIObserver*>(this), "xpcom-shutdown");
         obs->RemoveObserver(static_cast<nsIObserver*>(this), "memory-pressure");
         obs->RemoveObserver(static_cast<nsIObserver*>(this), "child-memory-reporter-request");
         obs->RemoveObserver(static_cast<nsIObserver*>(this), NS_IPC_IOSERVICE_SET_OFFLINE_TOPIC);
         obs->RemoveObserver(static_cast<nsIObserver*>(this), "child-gc-request");
         obs->RemoveObserver(static_cast<nsIObserver*>(this), "child-cc-request");
+        obs->RemoveObserver(static_cast<nsIObserver*>(this), "child-mmu-request");
         obs->RemoveObserver(static_cast<nsIObserver*>(this), "last-pb-context-exited");
         obs->RemoveObserver(static_cast<nsIObserver*>(this), "file-watcher-update");
 #ifdef MOZ_WIDGET_GONK
         obs->RemoveObserver(static_cast<nsIObserver*>(this), NS_VOLUME_STATE_CHANGED);
 #endif
 #ifdef ACCESSIBILITY
         obs->RemoveObserver(static_cast<nsIObserver*>(this), "a11y-init-or-shutdown");
 #endif
@@ -1832,16 +1834,19 @@ ContentParent::Observe(nsISupports* aSub
         unused << SendPMemoryReportRequestConstructor((uint32_t)(uintptr_t)aData);
     }
     else if (!strcmp(aTopic, "child-gc-request")){
         unused << SendGarbageCollect();
     }
     else if (!strcmp(aTopic, "child-cc-request")){
         unused << SendCycleCollect();
     }
+    else if (!strcmp(aTopic, "child-mmu-request")){
+        unused << SendMinimizeMemoryUsage();
+    }
     else if (!strcmp(aTopic, "last-pb-context-exited")) {
         unused << SendLastPrivateDocShellDestroyed();
     }
     else if (!strcmp(aTopic, "file-watcher-update")) {
         nsCString creason;
         CopyUTF16toUTF8(aData, creason);
         DeviceStorageFile* file = static_cast<DeviceStorageFile*>(aSubject);
 
--- a/dom/plugins/base/nsJSNPRuntime.cpp
+++ b/dom/plugins/base/nsJSNPRuntime.cpp
@@ -1009,21 +1009,21 @@ nsJSObjWrapper::GetNewOrUsed(NPP npp, JS
       return nullptr;
     }
   }
 
   nsJSObjWrapperKey key(obj, npp);
 
   JSObjWrapperTable::AddPtr p = sJSObjWrappers.lookupForAdd(key);
 
-  if (p/* && p->value*/) {
-    MOZ_ASSERT(p->value);
+  if (p/* && p->value()*/) {
+    MOZ_ASSERT(p->value());
     // Found a live nsJSObjWrapper, return it.
 
-    return _retainobject(p->value);
+    return _retainobject(p->value());
   }
 
   // No existing nsJSObjWrapper, create one.
 
   nsJSObjWrapper *wrapper =
     (nsJSObjWrapper *)_createobject(npp, &sJSObjWrapperNPClass);
 
   if (!wrapper) {
@@ -1868,17 +1868,17 @@ NPObjWrapperPluginDestroyedCallback(PLDH
 }
 
 // static
 void
 nsJSNPRuntime::OnPluginDestroy(NPP npp)
 {
   if (sJSObjWrappers.initialized()) {
     for (JSObjWrapperTable::Enum e(sJSObjWrappers); !e.empty(); e.popFront()) {
-      nsJSObjWrapper *npobj = e.front().value;
+      nsJSObjWrapper *npobj = e.front().value();
       MOZ_ASSERT(npobj->_class == &nsJSObjWrapper::sJSObjWrapperNPClass);
       if (npobj->mNpp == npp) {
         npobj->ClearJSObject();
         _releaseobject(npobj);
         e.removeFront();
       }
     }
   }
--- a/dom/plugins/base/nsNPAPIPluginInstance.cpp
+++ b/dom/plugins/base/nsNPAPIPluginInstance.cpp
@@ -49,16 +49,17 @@ using namespace mozilla;
 #include "mozilla/Mutex.h"
 #include "mozilla/CondVar.h"
 #include "AndroidBridge.h"
 #include "mozilla/dom/ScreenOrientation.h"
 #include "mozilla/Hal.h"
 #include "GLContextProvider.h"
 #include "GLContext.h"
 #include "TexturePoolOGL.h"
+#include "GLSharedHandleHelpers.h"
 
 using namespace mozilla::gl;
 
 typedef nsNPAPIPluginInstance::VideoInfo VideoInfo;
 
 class PluginEventRunnable : public nsRunnable
 {
 public:
@@ -133,19 +134,20 @@ public:
 
     if (!EnsureGLContext())
       return 0;
 
     if (mTextureInfo.mWidth == 0 || mTextureInfo.mHeight == 0)
       return 0;
 
     SharedTextureHandle handle =
-      sPluginContext->CreateSharedHandle(gl::SameProcess,
-                                         (void*)mTextureInfo.mTexture,
-                                         gl::TextureID);
+      gl::CreateSharedHandle(sPluginContext,
+                             gl::SameProcess,
+                             (void*)mTextureInfo.mTexture,
+                             gl::TextureID);
 
     // We want forget about this now, so delete the texture. Assigning it to zero
     // ensures that we create a new one in Lock()
     sPluginContext->fDeleteTextures(1, &mTextureInfo.mTexture);
     mTextureInfo.mTexture = 0;
     
     return handle;
   }
@@ -1013,19 +1015,20 @@ void* nsNPAPIPluginInstance::AcquireCont
 }
 
 SharedTextureHandle nsNPAPIPluginInstance::CreateSharedHandle()
 {
   if (mContentTexture) {
     return mContentTexture->CreateSharedHandle();
   } else if (mContentSurface) {
     EnsureGLContext();
-    return sPluginContext->CreateSharedHandle(gl::SameProcess,
-                                              mContentSurface,
-                                              gl::SurfaceTexture);
+    return gl::CreateSharedHandle(sPluginContext,
+                                  gl::SameProcess,
+                                  mContentSurface,
+                                  gl::SurfaceTexture);
   } else return 0;
 }
 
 void* nsNPAPIPluginInstance::AcquireVideoWindow()
 {
   nsSurfaceTexture* surface = CreateSurfaceTexture();
   if (!surface)
     return nullptr;
--- a/dom/plugins/base/nsPluginInstanceOwner.cpp
+++ b/dom/plugins/base/nsPluginInstanceOwner.cpp
@@ -54,16 +54,17 @@ using mozilla::DefaultXDisplay;
 #include "nsIFocusManager.h"
 #include "nsFocusManager.h"
 #include "nsIDOMDragEvent.h"
 #include "nsIScrollableFrame.h"
 #include "nsIDocShell.h"
 #include "ImageContainer.h"
 #include "nsIDOMHTMLCollection.h"
 #include "GLContext.h"
+#include "GLSharedHandleHelpers.h"
 #include "nsIContentInlines.h"
 #include "mozilla/MiscEvents.h"
 #include "mozilla/MouseEvents.h"
 #include "mozilla/TextEvents.h"
 
 #include "nsContentCID.h"
 #include "nsWidgetsCID.h"
 static NS_DEFINE_CID(kWidgetCID, NS_CHILD_CID);
@@ -1503,19 +1504,20 @@ already_AddRefed<ImageContainer> nsPlugi
   nsRefPtr<ImageContainer> container = LayerManager::CreateImageContainer();
 
   ImageFormat format = ImageFormat::SHARED_TEXTURE;
   nsRefPtr<Image> img = container->CreateImage(&format, 1);
 
   SharedTextureImage::Data data;
 
   data.mShareType = gl::SameProcess;
-  data.mHandle = mInstance->GLContext()->CreateSharedHandle(data.mShareType,
-                                                            aVideoInfo->mSurfaceTexture,
-                                                            gl::SurfaceTexture);
+  data.mHandle = gl::CreateSharedHandle(mInstance->GLContext(),
+                                        data.mShareType,
+                                        aVideoInfo->mSurfaceTexture,
+                                        gl::SurfaceTexture);
 
   // The logic below for Honeycomb is just a guess, but seems to work. We don't have a separate
   // inverted flag for video.
   data.mInverted = AndroidBridge::Bridge()->IsHoneycomb() ? true : mInstance->Inverted();
   data.mSize = gfxIntSize(aVideoInfo->mDimensions.width, aVideoInfo->mDimensions.height);
 
   SharedTextureImage* pluginImage = static_cast<SharedTextureImage*>(img.get());
   pluginImage->SetData(data);
--- a/dom/plugins/ipc/PluginModuleParent.cpp
+++ b/dom/plugins/ipc/PluginModuleParent.cpp
@@ -106,16 +106,20 @@ PluginModuleParent::LoadModule(const cha
     TimeoutChanged(CHILD_TIMEOUT_PREF, parent);
 
 #ifdef MOZ_CRASHREPORTER
     // If this fails, we're having IPC troubles, and we're doomed anyways.
     if (!CrashReporterParent::CreateCrashReporter(parent.get())) {
         parent->mShutdown = true;
         return nullptr;
     }
+#ifdef XP_WIN
+    mozilla::MutexAutoLock lock(parent->mCrashReporterMutex);
+    parent->mCrashReporter = parent->CrashReporter();
+#endif
 #endif
 
     return parent.forget();
 }
 
 
 PluginModuleParent::PluginModuleParent(const char* aFilePath)
     : mSubprocess(new PluginProcessParent(aFilePath))
@@ -125,16 +129,20 @@ PluginModuleParent::PluginModuleParent(c
     , mNPNIface(nullptr)
     , mPlugin(nullptr)
     , mTaskFactory(MOZ_THIS_IN_INITIALIZER_LIST())
 #ifdef XP_WIN
     , mPluginCpuUsageOnHang()
     , mHangUIParent(nullptr)
     , mHangUIEnabled(true)
     , mIsTimerReset(true)
+#ifdef MOZ_CRASHREPORTER
+    , mCrashReporterMutex("PluginModuleParent::mCrashReporterMutex")
+    , mCrashReporter(nullptr)
+#endif
 #endif
 #ifdef MOZ_CRASHREPORTER_INJECTOR
     , mFlashProcess1(0)
     , mFlashProcess2(0)
 #endif
 {
     NS_ASSERTION(mSubprocess, "Out of memory!");
 
@@ -189,16 +197,20 @@ PluginModuleParent::~PluginModuleParent(
     }
 #endif
 }
 
 #ifdef MOZ_CRASHREPORTER
 void
 PluginModuleParent::WriteExtraDataForMinidump(AnnotationTable& notes)
 {
+#ifdef XP_WIN
+    // mCrashReporterMutex is already held by the caller
+    mCrashReporterMutex.AssertCurrentThreadOwns();
+#endif
     typedef nsDependentCString CS;
 
     // Get the plugin filename, try to get just the file leafname
     const std::string& pluginFile = mSubprocess->GetPluginFilePath();
     size_t filePos = pluginFile.rfind(FILE_PATH_SEPARATOR);
     if (filePos == std::string::npos)
         filePos = 0;
     else
@@ -414,17 +426,27 @@ PluginModuleParent::ShouldContinueFromRe
     TerminateChildProcess(MessageLoop::current());
     return false;
 }
 
 void
 PluginModuleParent::TerminateChildProcess(MessageLoop* aMsgLoop)
 {
 #ifdef MOZ_CRASHREPORTER
+#ifdef XP_WIN
+    mozilla::MutexAutoLock lock(mCrashReporterMutex);
+    CrashReporterParent* crashReporter = mCrashReporter;
+    if (!crashReporter) {
+        // If mCrashReporter is null then the hang has ended, the plugin module
+        // is shutting down. There's nothing to do here.
+        return;
+    }
+#else
     CrashReporterParent* crashReporter = CrashReporter();
+#endif
     crashReporter->AnnotateCrashReport(NS_LITERAL_CSTRING("PluginHang"),
                                        NS_LITERAL_CSTRING("1"));
 #ifdef XP_WIN
     if (mHangUIParent) {
         unsigned int hangUIDuration = mHangUIParent->LastShowDurationMs();
         if (hangUIDuration) {
             nsPrintfCString strHangUIDuration("%u", hangUIDuration);
             crashReporter->AnnotateCrashReport(
@@ -631,16 +653,19 @@ RemoveMinidump(nsIFile* minidump)
         extraFile->Remove(true);
     }
 }
 #endif // MOZ_CRASHREPORTER_INJECTOR
 
 void
 PluginModuleParent::ProcessFirstMinidump()
 {
+#ifdef XP_WIN
+    mozilla::MutexAutoLock lock(mCrashReporterMutex);
+#endif
     CrashReporterParent* crashReporter = CrashReporter();
     if (!crashReporter)
         return;
 
     AnnotationTable notes(4);
     WriteExtraDataForMinidump(notes);
 
     if (!mPluginDumpID.IsEmpty()) {
@@ -1530,16 +1555,22 @@ PluginModuleParent::AllocPCrashReporterP
 #else
     return nullptr;
 #endif
 }
 
 bool
 PluginModuleParent::DeallocPCrashReporterParent(PCrashReporterParent* actor)
 {
+#ifdef XP_WIN
+    mozilla::MutexAutoLock lock(mCrashReporterMutex);
+    if (actor == static_cast<PCrashReporterParent*>(mCrashReporter)) {
+        mCrashReporter = nullptr;
+    }
+#endif
     delete actor;
     return true;
 }
 
 bool
 PluginModuleParent::RecvSetCursor(const NSCursorInfo& aCursorInfo)
 {
     PLUGIN_LOG_DEBUG(("%s", FULLFUNCTION));
--- a/dom/plugins/ipc/PluginModuleParent.h
+++ b/dom/plugins/ipc/PluginModuleParent.h
@@ -309,16 +309,27 @@ private:
     nsString mBrowserDumpID;
     nsString mHangID;
     nsRefPtr<nsIObserver> mProfilerObserver;
 #ifdef XP_WIN
     InfallibleTArray<float> mPluginCpuUsageOnHang;
     PluginHangUIParent *mHangUIParent;
     bool mHangUIEnabled;
     bool mIsTimerReset;
+#ifdef MOZ_CRASHREPORTER
+    /**
+     * This mutex protects the crash reporter when the Plugin Hang UI event
+     * handler is executing off main thread. It is intended to protect both
+     * the mCrashReporter variable in addition to the CrashReporterParent object
+     * that mCrashReporter refers to.
+     */
+    mozilla::Mutex mCrashReporterMutex;
+    CrashReporterParent* mCrashReporter;
+#endif // MOZ_CRASHREPORTER
+
 
     void
     EvaluateHangUIState(const bool aReset);
 
     bool
     GetPluginName(nsAString& aPluginName);
 
     /**
--- a/dom/workers/RuntimeService.cpp
+++ b/dom/workers/RuntimeService.cpp
@@ -96,16 +96,17 @@ static_assert(MAX_WORKERS_PER_DOMAIN >= 
 
 #define PREF_WORKERS_PREFIX "dom.workers."
 #define PREF_WORKERS_MAX_PER_DOMAIN PREF_WORKERS_PREFIX "maxPerDomain"
 
 #define PREF_MAX_SCRIPT_RUN_TIME_CONTENT "dom.max_script_run_time"
 #define PREF_MAX_SCRIPT_RUN_TIME_CHROME "dom.max_chrome_script_run_time"
 
 #define GC_REQUEST_OBSERVER_TOPIC "child-gc-request"
+#define CC_REQUEST_OBSERVER_TOPIC "child-cc-request"
 #define MEMORY_PRESSURE_OBSERVER_TOPIC "memory-pressure"
 
 #define BROADCAST_ALL_WORKERS(_func, ...)                                      \
   PR_BEGIN_MACRO                                                               \
     AssertIsOnMainThread();                                                    \
                                                                                \
     nsAutoTArray<WorkerPrivate*, 100> workers;                                 \
     {                                                                          \
@@ -1574,16 +1575,20 @@ RuntimeService::Init()
   NS_ENSURE_SUCCESS(rv, rv);
 
   mObserved = true;
 
   if (NS_FAILED(obs->AddObserver(this, GC_REQUEST_OBSERVER_TOPIC, false))) {
     NS_WARNING("Failed to register for GC request notifications!");
   }
 
+  if (NS_FAILED(obs->AddObserver(this, CC_REQUEST_OBSERVER_TOPIC, false))) {
+    NS_WARNING("Failed to register for CC request notifications!");
+  }
+
   if (NS_FAILED(obs->AddObserver(this, MEMORY_PRESSURE_OBSERVER_TOPIC,
                                  false))) {
     NS_WARNING("Failed to register for memory pressure notifications!");
   }
 
   NS_ASSERTION(!gRuntimeServiceDuringInit, "This should be null!");
   gRuntimeServiceDuringInit = this;
 
@@ -1822,16 +1827,20 @@ RuntimeService::Cleanup()
       NS_WARNING("Failed to unregister pref callbacks!");
     }
 
     if (obs) {
       if (NS_FAILED(obs->RemoveObserver(this, GC_REQUEST_OBSERVER_TOPIC))) {
         NS_WARNING("Failed to unregister for GC request notifications!");
       }
 
+      if (NS_FAILED(obs->RemoveObserver(this, CC_REQUEST_OBSERVER_TOPIC))) {
+        NS_WARNING("Failed to unregister for CC request notifications!");
+      }
+
       if (NS_FAILED(obs->RemoveObserver(this,
                                         MEMORY_PRESSURE_OBSERVER_TOPIC))) {
         NS_WARNING("Failed to unregister for memory pressure notifications!");
       }
 
       obs->RemoveObserver(this, NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID);
       obs->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID);
       mObserved = false;
@@ -2198,16 +2207,22 @@ RuntimeService::UpdateAllWorkerJITHarden
 }
 
 void
 RuntimeService::GarbageCollectAllWorkers(bool aShrinking)
 {
   BROADCAST_ALL_WORKERS(GarbageCollect, aShrinking);
 }
 
+void
+RuntimeService::CycleCollectAllWorkers()
+{
+  BROADCAST_ALL_WORKERS(CycleCollect, /* dummy = */ false);
+}
+
 // nsISupports
 NS_IMPL_ISUPPORTS1(RuntimeService, nsIObserver)
 
 // nsIObserver
 NS_IMETHODIMP
 RuntimeService::Observe(nsISupports* aSubject, const char* aTopic,
                         const PRUnichar* aData)
 {
@@ -2217,21 +2232,26 @@ RuntimeService::Observe(nsISupports* aSu
     Shutdown();
     return NS_OK;
   }
   if (!strcmp(aTopic, NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID)) {
     Cleanup();
     return NS_OK;
   }
   if (!strcmp(aTopic, GC_REQUEST_OBSERVER_TOPIC)) {
-    GarbageCollectAllWorkers(false);
+    GarbageCollectAllWorkers(/* shrinking = */ false);
+    return NS_OK;
+  }
+  if (!strcmp(aTopic, CC_REQUEST_OBSERVER_TOPIC)) {
+    CycleCollectAllWorkers();
     return NS_OK;
   }
   if (!strcmp(aTopic, MEMORY_PRESSURE_OBSERVER_TOPIC)) {
-    GarbageCollectAllWorkers(true);
+    GarbageCollectAllWorkers(/* shrinking = */ true);
+    CycleCollectAllWorkers();
     return NS_OK;
   }
 
   NS_NOTREACHED("Unknown observer topic!");
   return NS_OK;
 }
 
 /* static */ int
--- a/dom/workers/RuntimeService.h
+++ b/dom/workers/RuntimeService.h
@@ -247,16 +247,19 @@ public:
   }
 
   void
   UpdateAllWorkerJITHardening(bool aJITHardening);
 
   void
   GarbageCollectAllWorkers(bool aShrinking);
 
+  void
+  CycleCollectAllWorkers();
+
 private:
   RuntimeService();
   ~RuntimeService();
 
   nsresult
   Init();
 
   void
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -1568,30 +1568,65 @@ public:
   {
     // Silence bad assertions, this can be dispatched from either the main
     // thread or the timer thread..
     return true;
   }
 
   void
   PostDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
-                bool aDispatchResult)
+               bool aDispatchResult)
   {
     // Silence bad assertions, this can be dispatched from either the main
     // thread or the timer thread..
   }
 
   bool
   WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
   {
     aWorkerPrivate->GarbageCollectInternal(aCx, mShrinking, mCollectChildren);
     return true;
   }
 };
 
+class CycleCollectRunnable : public WorkerControlRunnable
+{
+protected:
+  bool mCollectChildren;
+
+public:
+  CycleCollectRunnable(WorkerPrivate* aWorkerPrivate, bool aCollectChildren)
+  : WorkerControlRunnable(aWorkerPrivate, WorkerThread, UnchangedBusyCount),
+    mCollectChildren(aCollectChildren)
+  { }
+
+  bool
+  PreDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
+  {
+    // Silence bad assertions, this can be dispatched from either the main
+    // thread or the timer thread..
+    return true;
+  }
+
+  void
+  PostDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
+               bool aDispatchResult)
+  {
+    // Silence bad assertions, this can be dispatched from either the main
+    // thread or the timer thread..
+  }
+
+  bool
+  WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
+  {
+    aWorkerPrivate->CycleCollectInternal(aCx, mCollectChildren);
+    return true;
+  }
+};
+
 class WorkerJSRuntimeStats : public JS::RuntimeStats
 {
   const nsACString& mRtPath;
 
 public:
   WorkerJSRuntimeStats(const nsACString& aRtPath)
   : JS::RuntimeStats(JsWorkerMallocSizeOf), mRtPath(aRtPath)
   { }
@@ -2887,19 +2922,35 @@ WorkerPrivateParent<Derived>::UpdateJITH
 
 template <class Derived>
 void
 WorkerPrivateParent<Derived>::GarbageCollect(JSContext* aCx, bool aShrinking)
 {
   AssertIsOnParentThread();
 
   nsRefPtr<GarbageCollectRunnable> runnable =
-    new GarbageCollectRunnable(ParentAsWorkerPrivate(), aShrinking, true);
+    new GarbageCollectRunnable(ParentAsWorkerPrivate(), aShrinking,
+                               /* collectChildren = */ true);
   if (!runnable->Dispatch(aCx)) {
-    NS_WARNING("Failed to update worker heap size!");
+    NS_WARNING("Failed to GC worker!");
+    JS_ClearPendingException(aCx);
+  }
+}
+
+template <class Derived>
+void
+WorkerPrivateParent<Derived>::CycleCollect(JSContext* aCx, bool aDummy)
+{
+  AssertIsOnParentThread();
+
+  nsRefPtr<CycleCollectRunnable> runnable =
+    new CycleCollectRunnable(ParentAsWorkerPrivate(),
+                             /* collectChildren = */ true);
+  if (!runnable->Dispatch(aCx)) {
+    NS_WARNING("Failed to CC worker!");
     JS_ClearPendingException(aCx);
   }
 }
 
 template <class Derived>
 bool
 WorkerPrivateParent<Derived>::RegisterSharedWorker(JSContext* aCx,
                                                    SharedWorker* aSharedWorker)
@@ -5213,16 +5264,30 @@ WorkerPrivate::GarbageCollectInternal(JS
 
   if (aCollectChildren) {
     for (uint32_t index = 0; index < mChildWorkers.Length(); index++) {
       mChildWorkers[index]->GarbageCollect(aCx, aShrinking);
     }
   }
 }
 
+void
+WorkerPrivate::CycleCollectInternal(JSContext* aCx, bool aCollectChildren)
+{
+  AssertIsOnWorkerThread();
+
+  nsCycleCollector_collect(nullptr);
+
+  if (aCollectChildren) {
+    for (uint32_t index = 0; index < mChildWorkers.Length(); index++) {
+      mChildWorkers[index]->CycleCollect(aCx, /* dummy = */ false);
+    }
+  }
+}
+
 
 template <class Derived>
 void
 WorkerPrivateParent<Derived>::RegisterHostObjectURI(const nsACString& aURI)
 {
   AssertIsOnMainThread();
   mHostObjectURIs.AppendElement(aURI);
 }
--- a/dom/workers/WorkerPrivate.h
+++ b/dom/workers/WorkerPrivate.h
@@ -489,16 +489,19 @@ public:
 #endif
 
   void
   UpdateJITHardening(JSContext* aCx, bool aJITHardening);
 
   void
   GarbageCollect(JSContext* aCx, bool aShrinking);
 
+  void
+  CycleCollect(JSContext* aCx, bool aDummy);
+
   bool
   RegisterSharedWorker(JSContext* aCx, SharedWorker* aSharedWorker);
 
   void
   UnregisterSharedWorker(JSContext* aCx, SharedWorker* aSharedWorker);
 
   void
   BroadcastErrorToSharedWorkers(JSContext* aCx,
@@ -1001,16 +1004,19 @@ public:
 
   void
   UpdateJITHardeningInternal(JSContext* aCx, bool aJITHardening);
 
   void
   GarbageCollectInternal(JSContext* aCx, bool aShrinking,
                          bool aCollectChildren);
 
+  void
+  CycleCollectInternal(JSContext* aCx, bool aCollectChildren);
+
   JSContext*
   GetJSContext() const
   {
     AssertIsOnWorkerThread();
     return mJSContext;
   }
 
   WorkerGlobalScope*
--- a/gfx/gl/GLBlitTextureImageHelper.cpp
+++ b/gfx/gl/GLBlitTextureImageHelper.cpp
@@ -1,15 +1,16 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /* vim: set ts=8 sts=4 et sw=4 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "GLBlitTextureImageHelper.h"
+#include "GLUploadHelpers.h"
 #include "DecomposeIntoNoRepeatTriangles.h"
 #include "GLContext.h"
 #include "nsRect.h"
 #include "gfx2DGlue.h"
 #include "gfxUtils.h"
 
 namespace mozilla {
 namespace gl {
@@ -111,17 +112,17 @@ GLBlitTextureImageHelper::BlitTextureIma
             float dy0 = 2.0f * float(srcSubInDstRect.y) / float(dstSize.height) - 1.0f;
             float dx1 = 2.0f * float(srcSubInDstRect.x + srcSubInDstRect.width) / float(dstSize.width) - 1.0f;
             float dy1 = 2.0f * float(srcSubInDstRect.y + srcSubInDstRect.height) / float(dstSize.height) - 1.0f;
             mGL->PushViewportRect(nsIntRect(0, 0, dstSize.width, dstSize.height));
 
             RectTriangles rects;
 
             nsIntSize realTexSize = srcSize;
-            if (!mGL->CanUploadNonPowerOfTwo()) {
+            if (!CanUploadNonPowerOfTwo(mGL)) {
                 realTexSize = nsIntSize(gfx::NextPowerOfTwo(srcSize.width),
                                         gfx::NextPowerOfTwo(srcSize.height));
             }
 
             if (aSrc->GetWrapMode() == LOCAL_GL_REPEAT) {
                 rects.addRect(/* dest rectangle */
                         dx0, dy0, dx1, dy1,
                         /* tex coords */
--- a/gfx/gl/GLContext.cpp
+++ b/gfx/gl/GLContext.cpp
@@ -1140,153 +1140,22 @@ GLContext::InitExtensions()
         MarkExtensionSupported(OES_rgb8_rgba8);
     }
 
 #ifdef DEBUG
     firstRun = false;
 #endif
 }
 
-
-// Take texture data in a given buffer and copy it into a larger buffer,
-// padding out the edge pixels for filtering if necessary
-static void
-CopyAndPadTextureData(const GLvoid* srcBuffer,
-                      GLvoid* dstBuffer,
-                      GLsizei srcWidth, GLsizei srcHeight,
-                      GLsizei dstWidth, GLsizei dstHeight,
-                      GLsizei stride, GLint pixelsize)
-{
-    unsigned char *rowDest = static_cast<unsigned char*>(dstBuffer);
-    const unsigned char *source = static_cast<const unsigned char*>(srcBuffer);
-
-    for (GLsizei h = 0; h < srcHeight; ++h) {
-        memcpy(rowDest, source, srcWidth * pixelsize);
-        rowDest += dstWidth * pixelsize;
-        source += stride;
-    }
-
-    GLsizei padHeight = srcHeight;
-
-    // Pad out an extra row of pixels so that edge filtering doesn't use garbage data
-    if (dstHeight > srcHeight) {
-        memcpy(rowDest, source - stride, srcWidth * pixelsize);
-        padHeight++;
-    }
-
-    // Pad out an extra column of pixels
-    if (dstWidth > srcWidth) {
-        rowDest = static_cast<unsigned char*>(dstBuffer) + srcWidth * pixelsize;
-        for (GLsizei h = 0; h < padHeight; ++h) {
-            memcpy(rowDest, rowDest - pixelsize, pixelsize);
-            rowDest += dstWidth * pixelsize;
-        }
-    }
-}
-
-// In both of these cases (for the Adreno at least) it is impossible
-// to determine good or bad driver versions for POT texture uploads,
-// so blacklist them all. Newer drivers use a different rendering
-// string in the form "Adreno (TM) 200" and the drivers we've seen so
-// far work fine with NPOT textures, so don't blacklist those until we
-// have evidence of any problems with them.
-bool
-GLContext::CanUploadSubTextures()
-{
-    if (!mWorkAroundDriverBugs)
-        return true;
-
-    // There are certain GPUs that we don't want to use glTexSubImage2D on
-    // because that function can be very slow and/or buggy
-    if (Renderer() == RendererAdreno200 || Renderer() == RendererAdreno205)
-        return false;
-
-    // On PowerVR glTexSubImage does a readback, so it will be slower
-    // than just doing a glTexImage2D() directly. i.e. 26ms vs 10ms
-    if (Renderer() == RendererSGX540 || Renderer() == RendererSGX530)
-        return false;
-
-    return true;
-}
-
-
-bool
-GLContext::CanReadSRGBFromFBOTexture()
-{
-    if (!mWorkAroundDriverBugs)
-        return true;
-
-#ifdef XP_MACOSX
-    // Bug 843668:
-    // MacOSX 10.6 reports to support EXT_framebuffer_sRGB and
-    // EXT_texture_sRGB but fails to convert from sRGB to linear
-    // when writing to an sRGB texture attached to an FBO.
-    SInt32 major, minor;
-    ::Gestalt(gestaltSystemVersionMajor, &major);
-    ::Gestalt(gestaltSystemVersionMinor, &minor);
-    if (major == 10 && minor <= 6) {
-        return false;
-    }
-#endif // XP_MACOSX
-    return true;
-}
-
-
-bool GLContext::sPowerOfTwoForced = false;
-bool GLContext::sPowerOfTwoPrefCached = false;
-
 void
 GLContext::PlatformStartup()
 {
-  CacheCanUploadNPOT();
   RegisterStrongMemoryReporter(new GfxTexturesReporter());
 }
 
-void
-GLContext::CacheCanUploadNPOT()
-{
-    MOZ_ASSERT(NS_IsMainThread(), "Can't cache prefs off the main thread.");
-    MOZ_ASSERT(!sPowerOfTwoPrefCached, "Must only call this function once!");
-
-    sPowerOfTwoPrefCached = true;
-    mozilla::Preferences::AddBoolVarCache(&sPowerOfTwoForced,
-                                          "gfx.textures.poweroftwo.force-enabled");
-}
-
-bool
-GLContext::CanUploadNonPowerOfTwo()
-{
-    MOZ_ASSERT(sPowerOfTwoPrefCached);
-
-    if (!mWorkAroundDriverBugs)
-        return true;
-
-    // Some GPUs driver crash when uploading non power of two 565 textures.
-    return sPowerOfTwoForced ? false : (Renderer() != RendererAdreno200 &&
-                                        Renderer() != RendererAdreno205);
-}
-
-bool
-GLContext::WantsSmallTiles()
-{
-    // We must use small tiles for good performance if we can't use
-    // glTexSubImage2D() for some reason.
-    if (!CanUploadSubTextures())
-        return true;
-
-    // We can't use small tiles on the SGX 540, because of races in texture upload.
-    if (mWorkAroundDriverBugs &&
-        Renderer() == RendererSGX540)
-        return false;
-
-    // Don't use small tiles otherwise. (If we implement incremental texture upload,
-    // then we will want to revisit this.)
-    return false;
-}
-
 // Common code for checking for both GL extensions and GLX extensions.
 bool
 GLContext::ListHasExtension(const GLubyte *extensions, const char *extension)
 {
     // fix bug 612572 - we were crashing as we were calling this function with extensions==null
     if (extensions == nullptr || extension == nullptr)
         return false;
 
@@ -1315,27 +1184,16 @@ GLContext::ListHasExtension(const GLubyt
                 return true;
             }
         }
         start = terminator;
     }
     return false;
 }
 
-already_AddRefed<TextureImage>
-GLContext::CreateTextureImage(const nsIntSize& aSize,
-                              TextureImage::ContentType aContentType,
-                              GLenum aWrapMode,
-                              TextureImage::Flags aFlags,
-                              TextureImage::ImageFormat aImageFormat)
-{
-    return CreateBasicTextureImage(this, aSize, aContentType, aWrapMode,
-                                   aFlags, aImageFormat);
-}
-
 void GLContext::ApplyFilterToBoundTexture(GraphicsFilter aFilter)
 {
     ApplyFilterToBoundTexture(LOCAL_GL_TEXTURE_2D, aFilter);
 }
 
 void GLContext::ApplyFilterToBoundTexture(GLuint aTarget,
                                           GraphicsFilter aFilter)
 {
@@ -2523,507 +2381,16 @@ GLContext::ReadPixelsIntoImageSurface(gf
                 }
             }
             dest->MarkDirty();
         }
     }
 #endif
 }
 
-static unsigned int
-DataOffset(const nsIntPoint &aPoint, int32_t aStride, gfxImageFormat aFormat)
-{
-  unsigned int data = aPoint.y * aStride;
-  data += aPoint.x * gfxASurface::BytePerPixelFromFormat(aFormat);
-  return data;
-}
-
-GLContext::SurfaceFormat
-GLContext::UploadImageDataToTexture(unsigned char* aData,
-                                    int32_t aStride,
-                                    gfxImageFormat aFormat,
-                                    const nsIntRegion& aDstRegion,
-                                    GLuint& aTexture,
-                                    bool aOverwrite,
-                                    bool aPixelBuffer,
-                                    GLenum aTextureUnit,
-                                    GLenum aTextureTarget)
-{
-    bool textureInited = aOverwrite ? false : true;
-    MakeCurrent();
-    fActiveTexture(aTextureUnit);
-
-    if (!aTexture) {
-        fGenTextures(1, &aTexture);
-        fBindTexture(aTextureTarget, aTexture);
-        fTexParameteri(aTextureTarget,
-                       LOCAL_GL_TEXTURE_MIN_FILTER,
-                       LOCAL_GL_LINEAR);
-        fTexParameteri(aTextureTarget,
-                       LOCAL_GL_TEXTURE_MAG_FILTER,
-                       LOCAL_GL_LINEAR);
-        fTexParameteri(aTextureTarget,
-                       LOCAL_GL_TEXTURE_WRAP_S,
-                       LOCAL_GL_CLAMP_TO_EDGE);
-        fTexParameteri(aTextureTarget,
-                       LOCAL_GL_TEXTURE_WRAP_T,
-                       LOCAL_GL_CLAMP_TO_EDGE);
-        textureInited = false;
-    } else {
-        fBindTexture(aTextureTarget, aTexture);
-    }
-
-    nsIntRegion paintRegion;
-    if (!textureInited) {
-        paintRegion = nsIntRegion(aDstRegion.GetBounds());
-    } else {
-        paintRegion = aDstRegion;
-    }
-
-    GLenum format;
-    GLenum internalFormat;
-    GLenum type;
-    int32_t pixelSize = gfxASurface::BytePerPixelFromFormat(aFormat);
-    SurfaceFormat surfaceFormat;
-
-    MOZ_ASSERT(GetPreferredARGB32Format() == LOCAL_GL_BGRA ||
-               GetPreferredARGB32Format() == LOCAL_GL_RGBA);
-    switch (aFormat) {
-        case gfxImageFormatARGB32:
-            if (GetPreferredARGB32Format() == LOCAL_GL_BGRA) {
-              format = LOCAL_GL_BGRA;
-              surfaceFormat = FORMAT_R8G8B8A8;
-              type = LOCAL_GL_UNSIGNED_INT_8_8_8_8_REV;
-            } else {
-              format = LOCAL_GL_RGBA;
-              surfaceFormat = FORMAT_B8G8R8A8;
-              type = LOCAL_GL_UNSIGNED_BYTE;
-            }
-            internalFormat = LOCAL_GL_RGBA;
-            break;
-        case gfxImageFormatRGB24:
-            // Treat RGB24 surfaces as RGBA32 except for the surface
-            // format used.
-            if (GetPreferredARGB32Format() == LOCAL_GL_BGRA) {
-              format = LOCAL_GL_BGRA;
-              surfaceFormat = FORMAT_R8G8B8X8;
-              type = LOCAL_GL_UNSIGNED_INT_8_8_8_8_REV;
-            } else {
-              format = LOCAL_GL_RGBA;
-              surfaceFormat = FORMAT_B8G8R8X8;
-              type = LOCAL_GL_UNSIGNED_BYTE;
-            }
-            internalFormat = LOCAL_GL_RGBA;
-            break;
-        case gfxImageFormatRGB16_565:
-            internalFormat = format = LOCAL_GL_RGB;
-            type = LOCAL_GL_UNSIGNED_SHORT_5_6_5;
-            surfaceFormat = FORMAT_R5G6B5;
-            break;
-        case gfxImageFormatA8:
-            internalFormat = format = LOCAL_GL_LUMINANCE;
-            type = LOCAL_GL_UNSIGNED_BYTE;
-            // We don't have a specific luminance shader
-            surfaceFormat = FORMAT_A8;
-            break;
-        default:
-            NS_ASSERTION(false, "Unhandled image surface format!");
-            format = 0;
-            type = 0;
-            surfaceFormat = FORMAT_UNKNOWN;
-    }
-
-    nsIntRegionRectIterator iter(paintRegion);
-    const nsIntRect *iterRect;
-
-    // Top left point of the region's bounding rectangle.
-    nsIntPoint topLeft = paintRegion.GetBounds().TopLeft();
-
-    while ((iterRect = iter.Next())) {
-        // The inital data pointer is at the top left point of the region's
-        // bounding rectangle. We need to find the offset of this rect
-        // within the region and adjust the data pointer accordingly.
-        unsigned char *rectData =
-            aData + DataOffset(iterRect->TopLeft() - topLeft, aStride, aFormat);
-
-        NS_ASSERTION(textureInited || (iterRect->x == 0 && iterRect->y == 0),
-                     "Must be uploading to the origin when we don't have an existing texture");
-
-        if (textureInited && CanUploadSubTextures()) {
-            TexSubImage2D(aTextureTarget,
-                          0,
-                          iterRect->x,
-                          iterRect->y,
-                          iterRect->width,
-                          iterRect->height,
-                          aStride,
-                          pixelSize,
-                          format,
-                          type,
-                          rectData);
-        } else {
-            TexImage2D(aTextureTarget,
-                       0,
-                       internalFormat,
-                       iterRect->width,
-                       iterRect->height,
-                       aStride,
-                       pixelSize,
-                       0,
-                       format,
-                       type,
-                       rectData);
-        }
-
-    }
-
-    return surfaceFormat;
-}
-
-GLContext::SurfaceFormat
-GLContext::UploadSurfaceToTexture(gfxASurface *aSurface,
-                                  const nsIntRegion& aDstRegion,
-                                  GLuint& aTexture,
-                                  bool aOverwrite,
-                                  const nsIntPoint& aSrcPoint,
-                                  bool aPixelBuffer,
-                                  GLenum aTextureUnit,
-                                  GLenum aTextureTarget)
-{
-
-    nsRefPtr<gfxImageSurface> imageSurface = aSurface->GetAsImageSurface();
-    unsigned char* data = nullptr;
-
-    if (!imageSurface ||
-        (imageSurface->Format() != gfxImageFormatARGB32 &&
-         imageSurface->Format() != gfxImageFormatRGB24 &&
-         imageSurface->Format() != gfxImageFormatRGB16_565 &&
-         imageSurface->Format() != gfxImageFormatA8)) {
-        // We can't get suitable pixel data for the surface, make a copy
-        nsIntRect bounds = aDstRegion.GetBounds();
-        imageSurface =
-          new gfxImageSurface(gfxIntSize(bounds.width, bounds.height),
-                              gfxImageFormatARGB32);
-
-        nsRefPtr<gfxContext> context = new gfxContext(imageSurface);
-
-        context->Translate(-gfxPoint(aSrcPoint.x, aSrcPoint.y));
-        context->SetSource(aSurface);
-        context->Paint();
-        data = imageSurface->Data();
-        NS_ASSERTION(!aPixelBuffer,
-                     "Must be using an image compatible surface with pixel buffers!");
-    } else {
-        // If a pixel buffer is bound the data pointer parameter is relative
-        // to the start of the data block.
-        if (!aPixelBuffer) {
-              data = imageSurface->Data();
-        }
-        data += DataOffset(aSrcPoint, imageSurface->Stride(),
-                           imageSurface->Format());
-    }
-
-    MOZ_ASSERT(imageSurface);
-    imageSurface->Flush();
-
-    return UploadImageDataToTexture(data,
-                                    imageSurface->Stride(),
-                                    imageSurface->Format(),
-                                    aDstRegion, aTexture, aOverwrite,
-                                    aPixelBuffer, aTextureUnit, aTextureTarget);
-}
-
-static gfxImageFormat
-ImageFormatForSurfaceFormat(gfx::SurfaceFormat aFormat)
-{
-    switch (aFormat) {
-        case gfx::FORMAT_B8G8R8A8:
-            return gfxImageFormatARGB32;
-        case gfx::FORMAT_B8G8R8X8:
-            return gfxImageFormatRGB24;
-        case gfx::FORMAT_R5G6B5:
-            return gfxImageFormatRGB16_565;
-        case gfx::FORMAT_A8:
-            return gfxImageFormatA8;
-        default:
-            return gfxImageFormatUnknown;
-    }
-}
-
-GLContext::SurfaceFormat
-GLContext::UploadSurfaceToTexture(gfx::DataSourceSurface *aSurface,
-                                  const nsIntRegion& aDstRegion,
-                                  GLuint& aTexture,
-                                  bool aOverwrite,
-                                  const nsIntPoint& aSrcPoint,
-                                  bool aPixelBuffer,
-                                  GLenum aTextureUnit,
-                                  GLenum aTextureTarget)
-{
-    unsigned char* data = aPixelBuffer ? nullptr : aSurface->GetData();
-    int32_t stride = aSurface->Stride();
-    gfxImageFormat format =
-        ImageFormatForSurfaceFormat(aSurface->GetFormat());
-    data += DataOffset(aSrcPoint, stride, format);
-    return UploadImageDataToTexture(data, stride, format,
-                                    aDstRegion, aTexture, aOverwrite,
-                                    aPixelBuffer, aTextureUnit,
-                                    aTextureTarget);
-}
-
-static GLint GetAddressAlignment(ptrdiff_t aAddress)
-{
-    if (!(aAddress & 0x7)) {
-       return 8;
-    } else if (!(aAddress & 0x3)) {
-        return 4;
-    } else if (!(aAddress & 0x1)) {
-        return 2;
-    } else {
-        return 1;
-    }
-}
-
-void
-GLContext::TexImage2D(GLenum target, GLint level, GLint internalformat,
-                      GLsizei width, GLsizei height, GLsizei stride,
-                      GLint pixelsize, GLint border, GLenum format,
-                      GLenum type, const GLvoid *pixels)
-{
-    if (IsGLES2()) {
-
-        NS_ASSERTION(format == (GLenum)internalformat,
-                    "format and internalformat not the same for glTexImage2D on GLES2");
-
-        if (!CanUploadNonPowerOfTwo()
-            && (stride != width * pixelsize
-            || !IsPowerOfTwo(width)
-            || !IsPowerOfTwo(height))) {
-
-            // Pad out texture width and height to the next power of two
-            // as we don't support/want non power of two texture uploads
-            GLsizei paddedWidth = NextPowerOfTwo(width);
-            GLsizei paddedHeight = NextPowerOfTwo(height);
-
-            GLvoid* paddedPixels = new unsigned char[paddedWidth * paddedHeight * pixelsize];
-
-            // Pad out texture data to be in a POT sized buffer for uploading to
-            // a POT sized texture
-            CopyAndPadTextureData(pixels, paddedPixels, width, height,
-                                  paddedWidth, paddedHeight, stride, pixelsize);
-
-            fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT,
-                    std::min(GetAddressAlignment((ptrdiff_t)paddedPixels),
-                            GetAddressAlignment((ptrdiff_t)paddedWidth * pixelsize)));
-            fTexImage2D(target,
-                        border,
-                        internalformat,
-                        paddedWidth,
-                        paddedHeight,
-                        border,
-                        format,
-                        type,
-                        paddedPixels);
-            fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, 4);
-
-            delete[] static_cast<unsigned char*>(paddedPixels);
-            return;
-        }
-
-        if (stride == width * pixelsize) {
-            fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT,
-                    std::min(GetAddressAlignment((ptrdiff_t)pixels),
-                            GetAddressAlignment((ptrdiff_t)stride)));
-            fTexImage2D(target,
-                        border,
-                        internalformat,
-                        width,
-                        height,
-                        border,
-                        format,
-                        type,
-                        pixels);
-            fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, 4);
-        } else {
-            // Use GLES-specific workarounds for GL_UNPACK_ROW_LENGTH; these are
-            // implemented in TexSubImage2D.
-            fTexImage2D(target,
-                        border,
-                        internalformat,
-                        width,
-                        height,
-                        border,
-                        format,
-                        type,
-                        nullptr);
-            TexSubImage2D(target,
-                          level,
-                          0,
-                          0,
-                          width,
-                          height,
-                          stride,
-                          pixelsize,
-                          format,
-                          type,
-                          pixels);
-        }
-    } else {
-        // desktop GL (non-ES) path
-
-        fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT,
-                    std::min(GetAddressAlignment((ptrdiff_t)pixels),
-                            GetAddressAlignment((ptrdiff_t)stride)));
-        int rowLength = stride/pixelsize;
-        fPixelStorei(LOCAL_GL_UNPACK_ROW_LENGTH, rowLength);
-        fTexImage2D(target,
-                    level,
-                    internalformat,
-                    width,
-                    height,
-                    border,
-                    format,
-                    type,
-                    pixels);
-        fPixelStorei(LOCAL_GL_UNPACK_ROW_LENGTH, 0);
-        fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, 4);
-    }
-}
-
-void
-GLContext::TexSubImage2D(GLenum target, GLint level,
-                         GLint xoffset, GLint yoffset,
-                         GLsizei width, GLsizei height, GLsizei stride,
-                         GLint pixelsize, GLenum format,
-                         GLenum type, const GLvoid* pixels)
-{
-    if (IsGLES2()) {
-        if (stride == width * pixelsize) {
-            fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT,
-                    std::min(GetAddressAlignment((ptrdiff_t)pixels),
-                            GetAddressAlignment((ptrdiff_t)stride)));
-            fTexSubImage2D(target,
-                          level,
-                          xoffset,
-                          yoffset,
-                          width,
-                          height,
-                          format,
-                          type,
-                          pixels);
-            fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, 4);
-        } else if (IsExtensionSupported(EXT_unpack_subimage)) {
-            TexSubImage2DWithUnpackSubimageGLES(target, level, xoffset, yoffset,
-                                                width, height, stride,
-                                                pixelsize, format, type, pixels);
-
-        } else {
-            TexSubImage2DWithoutUnpackSubimage(target, level, xoffset, yoffset,
-                                              width, height, stride,
-                                              pixelsize, format, type, pixels);
-        }
-    } else {
-        // desktop GL (non-ES) path
-        fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT,
-                    std::min(GetAddressAlignment((ptrdiff_t)pixels),
-                            GetAddressAlignment((ptrdiff_t)stride)));
-        int rowLength = stride/pixelsize;
-        fPixelStorei(LOCAL_GL_UNPACK_ROW_LENGTH, rowLength);
-        fTexSubImage2D(target,
-                      level,
-                      xoffset,
-                      yoffset,
-                      width,
-                      height,
-                      format,
-                      type,
-                      pixels);
-        fPixelStorei(LOCAL_GL_UNPACK_ROW_LENGTH, 0);
-        fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, 4);
-    }
-}
-
-void
-GLContext::TexSubImage2DWithUnpackSubimageGLES(GLenum target, GLint level,
-                                               GLint xoffset, GLint yoffset,
-                                               GLsizei width, GLsizei height,
-                                               GLsizei stride, GLint pixelsize,
-                                               GLenum format, GLenum type,
-                                               const GLvoid* pixels)
-{
-    fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT,
-                 std::min(GetAddressAlignment((ptrdiff_t)pixels),
-                        GetAddressAlignment((ptrdiff_t)stride)));
-    // When using GL_UNPACK_ROW_LENGTH, we need to work around a Tegra
-    // driver crash where the driver apparently tries to read
-    // (stride - width * pixelsize) bytes past the end of the last input
-    // row. We only upload the first height-1 rows using GL_UNPACK_ROW_LENGTH,
-    // and then we upload the final row separately. See bug 697990.
-    int rowLength = stride/pixelsize;
-    fPixelStorei(LOCAL_GL_UNPACK_ROW_LENGTH, rowLength);
-    fTexSubImage2D(target,
-                    level,
-                    xoffset,
-                    yoffset,
-                    width,
-                    height-1,
-                    format,
-                    type,
-                    pixels);
-    fPixelStorei(LOCAL_GL_UNPACK_ROW_LENGTH, 0);
-    fTexSubImage2D(target,
-                    level,
-                    xoffset,
-                    yoffset+height-1,
-                    width,
-                    1,
-                    format,
-                    type,
-                    (const unsigned char *)pixels+(height-1)*stride);
-    fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, 4);
-}
-
-void
-GLContext::TexSubImage2DWithoutUnpackSubimage(GLenum target, GLint level,
-                                              GLint xoffset, GLint yoffset,
-                                              GLsizei width, GLsizei height,
-                                              GLsizei stride, GLint pixelsize,
-                                              GLenum format, GLenum type,
-                                              const GLvoid* pixels)
-{
-    // Not using the whole row of texture data and GL_UNPACK_ROW_LENGTH
-    // isn't supported. We make a copy of the texture data we're using,
-    // such that we're using the whole row of data in the copy. This turns
-    // out to be more efficient than uploading row-by-row; see bug 698197.
-    unsigned char *newPixels = new unsigned char[width*height*pixelsize];
-    unsigned char *rowDest = newPixels;
-    const unsigned char *rowSource = (const unsigned char *)pixels;
-    for (int h = 0; h < height; h++) {
-            memcpy(rowDest, rowSource, width*pixelsize);
-            rowDest += width*pixelsize;
-            rowSource += stride;
-    }
-
-    stride = width*pixelsize;
-    fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT,
-                    std::min(GetAddressAlignment((ptrdiff_t)newPixels),
-                            GetAddressAlignment((ptrdiff_t)stride)));
-    fTexSubImage2D(target,
-                    level,
-                    xoffset,
-                    yoffset,
-                    width,
-                    height,
-                    format,
-                    type,
-                    newPixels);
-    delete [] newPixels;
-    fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, 4);
-}
-
 #ifdef MOZ_ENABLE_GL_TRACKING
 void
 GLContext::CreatedProgram(GLContext *aOrigin, GLuint aName)
 {
     mTrackedPrograms.AppendElement(NamedResource(aOrigin, aName));
 }
 
 void
--- a/gfx/gl/GLContext.h
+++ b/gfx/gl/GLContext.h
@@ -2468,31 +2468,19 @@ public:
      *
      * If surf is null, this removes any previously set override, and makes the
      * context current again against its primary surface.
      */
     virtual void SetEGLSurfaceOverride(EGLSurface surf) {
         MOZ_CRASH("Must be called against a GLContextEGL.");
     }
 
-    bool CanUploadSubTextures();
-    bool CanReadSRGBFromFBOTexture();
-
     static void PlatformStartup();
 
-protected:
-    static bool sPowerOfTwoForced;
-    static bool sPowerOfTwoPrefCached;
-    static void CacheCanUploadNPOT();
-
 public:
-    bool CanUploadNonPowerOfTwo();
-
-    bool WantsSmallTiles();
-
     /**
      * If this context wraps a double-buffered target, swap the back
      * and front buffers.  It should be assumed that after a swap, the
      * contents of the new back buffer are undefined.
      */
     virtual bool SwapBuffers() { return false; }
 
     /**
@@ -2518,20 +2506,16 @@ public:
     virtual bool BindExternalBuffer(GLuint texture, void* buffer) { return false; }
     virtual bool UnbindExternalBuffer(GLuint texture) { return false; }
 
 #ifdef MOZ_WIDGET_GONK
     virtual EGLImage CreateEGLImageForNativeBuffer(void* buffer) = 0;
     virtual void DestroyEGLImage(EGLImage image) = 0;
 #endif
 
-    virtual already_AddRefed<TextureImage>
-    CreateDirectTextureImage(::android::GraphicBuffer* aBuffer, GLenum aWrapMode)
-    { return nullptr; }
-
     // Before reads from offscreen texture
     void GuaranteeResolve();
 
     /*
      * Resize the current offscreen buffer.  Returns true on success.
      * If it returns false, the context should be treated as unusable
      * and should be recreated.  After the resize, the viewport is not
      * changed; glViewport should be called as appropriate.
@@ -2544,81 +2528,16 @@ public:
 
     /*
      * Return size of this offscreen context.
      *
      * Only valid if IsOffscreen() returns true.
      */
     const gfxIntSize& OffscreenSize() const;
 
-    /*
-     * Create a new shared GLContext content handle, using the passed buffer as a source.
-     * Must be released by ReleaseSharedHandle. UpdateSharedHandle will have no effect
-     * on handles created with this method, as the caller owns the source (the passed buffer)
-     * and is responsible for updating it accordingly.
-     */
-    virtual SharedTextureHandle CreateSharedHandle(SharedTextureShareType shareType,
-                                                   void* buffer,
-                                                   SharedTextureBufferType bufferType)
-    { return 0; }
-    /**
-     * Publish GLContext content to intermediate buffer attached to shared handle.
-     * Shared handle content is ready to be used after call returns, and no need extra Flush/Finish are required.
-     * GLContext must be current before this call
-     */
-    virtual void UpdateSharedHandle(SharedTextureShareType shareType,
-                                    SharedTextureHandle sharedHandle)
-    { }
-    /**
-     * - It is better to call ReleaseSharedHandle before original GLContext destroyed,
-     *     otherwise warning will be thrown on attempt to destroy Texture associated with SharedHandle, depends on backend implementation.
-     * - It does not require to be called on context where it was created,
-     *     because SharedHandle suppose to keep Context reference internally,
-     *     or don't require specific context at all, for example IPC SharedHandle.
-     * - Not recommended to call this between AttachSharedHandle and Draw Target call.
-     *      if it is really required for some special backend, then DetachSharedHandle API must be added with related implementation.
-     * - It is recommended to stop any possible access to SharedHandle (Attachments, pending GL calls) before calling Release,
-     *      otherwise some artifacts might appear or even crash if API backend implementation does not expect that.
-     * SharedHandle (currently EGLImage) does not require GLContext because it is EGL call, and can be destroyed
-     *   at any time, unless EGLImage have siblings (which are not expected with current API).
-     */
-    virtual void ReleaseSharedHandle(SharedTextureShareType shareType,
-                                     SharedTextureHandle sharedHandle)
-    { }
-
-
-    typedef struct {
-        GLenum mTarget;
-        SurfaceFormat mTextureFormat;
-        gfx3DMatrix mTextureTransform;
-    } SharedHandleDetails;
-
-    /**
-     * Returns information necessary for rendering a shared handle.
-     * These values change depending on what sharing mechanism is in use
-     */
-    virtual bool GetSharedHandleDetails(SharedTextureShareType shareType,
-                                        SharedTextureHandle sharedHandle,
-                                        SharedHandleDetails& details)
-    { return false; }
-    /**
-     * Attach Shared GL Handle to GL_TEXTURE_2D target
-     * GLContext must be current before this call
-     */
-    virtual bool AttachSharedHandle(SharedTextureShareType shareType,
-                                    SharedTextureHandle sharedHandle)
-    { return false; }
-
-    /**
-     * Detach Shared GL Handle from GL_TEXTURE_2D target
-     */
-    virtual void DetachSharedHandle(SharedTextureShareType shareType,
-                                    SharedTextureHandle sharedHandle)
-    { }
-
     void BindFB(GLuint fb) {
         fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, fb);
         MOZ_ASSERT(!fb || fIsFramebuffer(fb));
     }
 
     void BindDrawFB(GLuint fb) {
         fBindFramebuffer(LOCAL_GL_DRAW_FRAMEBUFFER_EXT, fb);
     }
@@ -2685,63 +2604,20 @@ private:
         }
     }
 
 public:
 
     void ForceDirtyScreen();
     void CleanDirtyScreen();
 
-    virtual bool TextureImageSupportsGetBackingSurface() {
-        return false;
-    }
-
     virtual GLenum GetPreferredARGB32Format() { return LOCAL_GL_RGBA; }
 
     virtual bool RenewSurface() { return false; }
 
-    /**
-     * Return a valid, allocated TextureImage of |aSize| with
-     * |aContentType|.  If |aContentType| is COLOR, |aImageFormat| can be used
-     * to hint at the preferred RGB format, however it is not necessarily
-     * respected.  The TextureImage's texture is configured to use
-     * |aWrapMode| (usually GL_CLAMP_TO_EDGE or GL_REPEAT) and by
-     * default, GL_LINEAR filtering.  Specify
-     * |aFlags=UseNearestFilter| for GL_NEAREST filtering. Specify
-     * |aFlags=NeedsYFlip| if the image is flipped. Return
-     * nullptr if creating the TextureImage fails.
-     *
-     * The returned TextureImage may only be used with this GLContext.
-     * Attempting to use the returned TextureImage after this
-     * GLContext is destroyed will result in undefined (and likely
-     * crashy) behavior.
-     */
-    virtual already_AddRefed<TextureImage>
-    CreateTextureImage(const nsIntSize& aSize,
-                       TextureImage::ContentType aContentType,
-                       GLenum aWrapMode,
-                       TextureImage::Flags aFlags = TextureImage::NoFlags,
-                       TextureImage::ImageFormat aImageFormat = gfxImageFormatUnknown);
-
-    /**
-     * In EGL we want to use Tiled Texture Images, which we return
-     * from CreateTextureImage above.
-     * Inside TiledTextureImage we need to create actual images and to
-     * prevent infinite recursion we need to differentiate the two
-     * functions.
-     **/
-    virtual already_AddRefed<TextureImage>
-    TileGenFunc(const nsIntSize& aSize,
-                TextureImage::ContentType aContentType,
-                TextureImage::Flags aFlags = TextureImage::NoFlags,
-                TextureImage::ImageFormat aImageFormat = gfxImageFormatUnknown)
-    {
-        return nullptr;
-    }
-
 private:
     /**
      * Helpers for ReadTextureImage
      */
     GLuint TextureImageProgramFor(GLenum aTextureTarget, int aShader);
     bool ReadBackPixelsIntoSurface(gfxImageSurface* aSurface, const gfxIntSize& aSize);
 
 public:
@@ -2780,111 +2656,16 @@ public:
     void ReadPixelsIntoImageSurface(gfxImageSurface* dest);
 
     // Similar to ReadPixelsIntoImageSurface, but pulls from the screen
     // instead of the currently bound framebuffer.
     void ReadScreenIntoImageSurface(gfxImageSurface* dest);
 
     TemporaryRef<gfx::SourceSurface> ReadPixelsToSourceSurface(const gfx::IntSize &aSize);
 
-    /**
-     * Creates a RGB/RGBA texture (or uses one provided) and uploads the surface
-     * contents to it within aSrcRect.
-     *
-     * aSrcRect.x/y will be uploaded to 0/0 in the texture, and the size
-     * of the texture with be aSrcRect.width/height.
-     *
-     * If an existing texture is passed through aTexture, it is assumed it
-     * has already been initialised with glTexImage2D (or this function),
-     * and that its size is equal to or greater than aSrcRect + aDstPoint.
-     * You can alternatively set the overwrite flag to true and have a new
-     * texture memory block allocated.
-     *
-     * The aDstPoint parameter is ignored if no texture was provided
-     * or aOverwrite is true.
-     *
-     * \param aData Image data to upload.
-     * \param aDstRegion Region of texture to upload to.
-     * \param aTexture Texture to use, or 0 to have one created for you.
-     * \param aOverwrite Over an existing texture with a new one.
-     * \param aSrcPoint Offset into aSrc where the region's bound's
-     *  TopLeft() sits.
-     * \param aPixelBuffer Pass true to upload texture data with an
-     *  offset from the base data (generally for pixel buffer objects),
-     *  otherwise textures are upload with an absolute pointer to the data.
-     * \param aTextureUnit, the texture unit used temporarily to upload the
-     *  surface. This testure may be overridden, clients should not rely on
-     *  the contents of this texture after this call or even on this
-     *  texture unit being active.
-     * \return Surface format of this texture.
-     */
-    SurfaceFormat UploadImageDataToTexture(unsigned char* aData,
-                                           int32_t aStride,
-                                           gfxImageFormat aFormat,
-                                           const nsIntRegion& aDstRegion,
-                                           GLuint& aTexture,
-                                           bool aOverwrite = false,
-                                           bool aPixelBuffer = false,
-                                           GLenum aTextureUnit = LOCAL_GL_TEXTURE0,
-                                           GLenum aTextureTarget = LOCAL_GL_TEXTURE_2D);
-
-    /**
-     * Convenience wrapper around UploadImageDataToTexture for gfxASurfaces.
-     */
-    SurfaceFormat UploadSurfaceToTexture(gfxASurface *aSurface,
-                                         const nsIntRegion& aDstRegion,
-                                         GLuint& aTexture,
-                                         bool aOverwrite = false,
-                                         const nsIntPoint& aSrcPoint = nsIntPoint(0, 0),
-                                         bool aPixelBuffer = false,
-                                         GLenum aTextureUnit = LOCAL_GL_TEXTURE0,
-                                         GLenum aTextureTarget = LOCAL_GL_TEXTURE_2D);
-
-    /**
-     * Same as above, for DataSourceSurfaces.
-     */
-    SurfaceFormat UploadSurfaceToTexture(gfx::DataSourceSurface *aSurface,
-                                         const nsIntRegion& aDstRegion,
-                                         GLuint& aTexture,
-                                         bool aOverwrite = false,
-                                         const nsIntPoint& aSrcPoint = nsIntPoint(0, 0),
-                                         bool aPixelBuffer = false,
-                                         GLenum aTextureUnit = LOCAL_GL_TEXTURE0,
-                                         GLenum aTextureTarget = LOCAL_GL_TEXTURE_2D);
-
-    void TexImage2D(GLenum target, GLint level, GLint internalformat,
-                    GLsizei width, GLsizei height, GLsizei stride,
-                    GLint pixelsize, GLint border, GLenum format,
-                    GLenum type, const GLvoid *pixels);
-
-    void TexSubImage2D(GLenum target, GLint level,
-                       GLint xoffset, GLint yoffset,
-                       GLsizei width, GLsizei height, GLsizei stride,
-                       GLint pixelsize, GLenum format,
-                       GLenum type, const GLvoid* pixels);
-
-    /**
-     * Uses the Khronos GL_EXT_unpack_subimage extension, working around
-     * quirks in the Tegra implementation of this extension.
-     */
-    void TexSubImage2DWithUnpackSubimageGLES(GLenum target, GLint level,
-                                             GLint xoffset, GLint yoffset,
-                                             GLsizei width, GLsizei height,
-                                             GLsizei stride, GLint pixelsize,
-                                             GLenum format, GLenum type,
-                                             const GLvoid* pixels);
-
-    void TexSubImage2DWithoutUnpackSubimage(GLenum target, GLint level,
-                                            GLint xoffset, GLint yoffset,
-                                            GLsizei width, GLsizei height,
-                                            GLsizei stride, GLint pixelsize,
-                                            GLenum format, GLenum type,
-                                            const GLvoid* pixels);
-
-
     // Shared code for GL extensions and GLX extensions.
     static bool ListHasExtension(const GLubyte *extensions,
                                  const char *extension);
 
     GLint GetMaxTextureImageSize() { return mMaxTextureImageSize; }
     void SetFlipped(bool aFlipped) { mFlipped = aFlipped; }
 
 
@@ -3121,27 +2902,27 @@ protected:
 public:
     TextureGarbageBin* TexGarbageBin() {
         MOZ_ASSERT(mTexGarbageBin);
         return mTexGarbageBin;
     }
 
     void EmptyTexGarbageBin();
 
+    bool IsOffscreenSizeAllowed(const gfxIntSize& aSize) const;
+
 protected:
     nsDataHashtable<nsPtrHashKey<void>, void*> mUserData;
 
     GLuint mReadTextureImagePrograms[4];
 
     bool InitWithPrefix(const char *prefix, bool trygl);
 
     void InitExtensions();
 
-    bool IsOffscreenSizeAllowed(const gfxIntSize& aSize) const;
-
     nsTArray<nsIntRect> mViewportStack;
     nsTArray<nsIntRect> mScissorStack;
 
     GLint mMaxTextureSize;
     GLint mMaxCubeMapTextureSize;
     GLint mMaxTextureImageSize;
     GLint mMaxRenderbufferSize;
     GLsizei mMaxSamples;
--- a/gfx/gl/GLContextFeatures.cpp
+++ b/gfx/gl/GLContextFeatures.cpp
@@ -2,16 +2,20 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 
 #include "GLContext.h"
 #include "nsPrintfCString.h"
 
+#ifdef XP_MACOSX
+#include "nsCocoaFeatures.h"
+#endif
+
 namespace mozilla {
 namespace gl {
 
 const size_t kMAX_EXTENSION_GROUP_SIZE = 5;
 
 // ARB_ES2_compatibility is natively supported in OpenGL 4.1.
 static const unsigned int kGLCoreVersionForES2Compat = 410;
 
@@ -361,16 +365,34 @@ IsFeatureIsPartOfProfileVersion(GLFeatur
 }
 
 const char*
 GLContext::GetFeatureName(GLFeature::Enum feature)
 {
     return GetFeatureInfo(feature).mName;
 }
 
+static bool
+CanReadSRGBFromFBOTexture(GLContext* gl)
+{
+    if (!gl->WorkAroundDriverBugs())
+        return true;
+
+#ifdef XP_MACOSX
+    // Bug 843668:
+    // MacOSX 10.6 reports to support EXT_framebuffer_sRGB and
+    // EXT_texture_sRGB but fails to convert from sRGB to linear
+    // when writing to an sRGB texture attached to an FBO.
+    if (!nsCocoaFeatures::OnLionOrLater()) {
+        return false;
+    }
+#endif // XP_MACOSX
+    return true;
+}
+
 void
 GLContext::InitFeatures()
 {
     for (size_t i = 0; i < GLFeature::EnumMax; i++)
     {
         GLFeature::Enum feature = GLFeature::Enum(i);
 
         if (IsFeatureIsPartOfProfileVersion(feature, mProfile, mVersion)) {
@@ -402,17 +424,17 @@ GLContext::InitFeatures()
     // EXT_texture_sRGB and EXT_framebuffer_sRGB is required.
     const bool aresRGBExtensionsAvailable =
         IsExtensionSupported(EXT_texture_sRGB) &&
         (IsExtensionSupported(ARB_framebuffer_sRGB) ||
          IsExtensionSupported(EXT_framebuffer_sRGB));
 
     mAvailableFeatures[GLFeature::sRGB] =
         aresRGBExtensionsAvailable &&
-        CanReadSRGBFromFBOTexture();
+        CanReadSRGBFromFBOTexture(this);
 }
 
 void
 GLContext::MarkUnsupported(GLFeature::Enum feature)
 {
     mAvailableFeatures[feature] = false;
 
     const FeatureInfo& featureInfo = GetFeatureInfo(feature);
--- a/gfx/gl/GLContextProviderCGL.mm
+++ b/gfx/gl/GLContextProviderCGL.mm
@@ -1,15 +1,16 @@
 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "GLContextProvider.h"
 #include "GLContext.h"
+#include "TextureImageCGL.h"
 #include "nsDebug.h"
 #include "nsIWidget.h"
 #include "OpenGL/OpenGL.h"
 #include <OpenGL/gl.h>
 #include <AppKit/NSOpenGL.h>
 #include "gfxASurface.h"
 #include "gfxImageSurface.h"
 #include "gfxQuartzSurface.h"
@@ -184,213 +185,26 @@ public:
     {
       PROFILER_LABEL("GLContext", "SwapBuffers");
       [mContext flushBuffer];
       return true;
     }
 
     bool ResizeOffscreen(const gfxIntSize& aNewSize);
 
-    virtual already_AddRefed<TextureImage>
-    CreateTextureImage(const nsIntSize& aSize,
-                       TextureImage::ContentType aContentType,
-                       GLenum aWrapMode,
-                       TextureImage::Flags aFlags = TextureImage::NoFlags,
-                       TextureImage::ImageFormat aImageFormat = gfxImageFormatUnknown) MOZ_OVERRIDE;
-
-    virtual already_AddRefed<TextureImage>
-    TileGenFunc(const nsIntSize& aSize,
-                TextureImage::ContentType aContentType,
-                TextureImage::Flags aFlags = TextureImage::NoFlags,
-                TextureImage::ImageFormat aImageFormat = gfxImageFormatUnknown) MOZ_OVERRIDE;
-
     NSOpenGLContext *mContext;
     GLuint mTempTextureName;
-
-    already_AddRefed<TextureImage>
-    CreateTextureImageInternal(const nsIntSize& aSize,
-                               TextureImage::ContentType aContentType,
-                               GLenum aWrapMode,
-                               TextureImage::Flags aFlags,
-                               TextureImage::ImageFormat aImageFormat);
-
 };
 
 bool
 GLContextCGL::ResizeOffscreen(const gfxIntSize& aNewSize)
 {
     return ResizeScreenBuffer(aNewSize);
 }
 
-class TextureImageCGL : public BasicTextureImage
-{
-    friend already_AddRefed<TextureImage>
-    GLContextCGL::CreateTextureImageInternal(const nsIntSize& aSize,
-                                             TextureImage::ContentType aContentType,
-                                             GLenum aWrapMode,
-                                             TextureImage::Flags aFlags,
-                                             TextureImage::ImageFormat aImageFormat);
-public:
-    ~TextureImageCGL()
-    {
-        if (mPixelBuffer) {
-            mGLContext->MakeCurrent();
-            mGLContext->fDeleteBuffers(1, &mPixelBuffer);
-        }
-    }
-
-protected:
-    already_AddRefed<gfxASurface>
-    GetSurfaceForUpdate(const gfxIntSize& aSize, ImageFormat aFmt)
-    {
-        gfxIntSize size(aSize.width + 1, aSize.height + 1);
-        mGLContext->MakeCurrent();
-        if (!mGLContext->
-            IsExtensionSupported(GLContext::ARB_pixel_buffer_object)) 
-        {
-            return gfxPlatform::GetPlatform()->
-                CreateOffscreenSurface(size,
-                                       gfxASurface::ContentFromFormat(aFmt));
-        }
-
-        if (!mPixelBuffer) {
-            mGLContext->fGenBuffers(1, &mPixelBuffer);
-        }
-        mGLContext->fBindBuffer(LOCAL_GL_PIXEL_UNPACK_BUFFER, mPixelBuffer);
-        int32_t length = size.width * 4 * size.height;
-
-        if (length > mPixelBufferSize) {
-            mGLContext->fBufferData(LOCAL_GL_PIXEL_UNPACK_BUFFER, length,
-                                    NULL, LOCAL_GL_STREAM_DRAW);
-            mPixelBufferSize = length;
-        }
-        unsigned char* data = 
-            (unsigned char*)mGLContext->
-                fMapBuffer(LOCAL_GL_PIXEL_UNPACK_BUFFER, 
-                           LOCAL_GL_WRITE_ONLY);
-
-        mGLContext->fBindBuffer(LOCAL_GL_PIXEL_UNPACK_BUFFER, 0);
-
-        if (!data) {
-            nsAutoCString failure;
-            failure += "Pixel buffer binding failed: ";
-            failure.AppendPrintf("%dx%d\n", size.width, size.height);
-            gfx::LogFailure(failure);
-
-            mGLContext->fBindBuffer(LOCAL_GL_PIXEL_UNPACK_BUFFER, 0);
-            return gfxPlatform::GetPlatform()->
-                CreateOffscreenSurface(size,
-                                       gfxASurface::ContentFromFormat(aFmt));
-        }
-
-        nsRefPtr<gfxQuartzSurface> surf = 
-            new gfxQuartzSurface(data, size, size.width * 4, aFmt);
-
-        mBoundPixelBuffer = true;
-        return surf.forget();
-    }
-  
-    bool FinishedSurfaceUpdate()
-    {
-        if (mBoundPixelBuffer) {
-            mGLContext->MakeCurrent();
-            mGLContext->fBindBuffer(LOCAL_GL_PIXEL_UNPACK_BUFFER, mPixelBuffer);
-            mGLContext->fUnmapBuffer(LOCAL_GL_PIXEL_UNPACK_BUFFER);
-            return true;
-        }
-        return false;
-    }
-
-    void FinishedSurfaceUpload()
-    {
-        if (mBoundPixelBuffer) {
-            mGLContext->MakeCurrent();
-            mGLContext->fBindBuffer(LOCAL_GL_PIXEL_UNPACK_BUFFER, 0);
-            mBoundPixelBuffer = false;
-        }
-    }
-
-private:
-    TextureImageCGL(GLuint aTexture,
-                    const nsIntSize& aSize,
-                    GLenum aWrapMode,
-                    ContentType aContentType,
-                    GLContext* aContext,
-                    TextureImage::Flags aFlags = TextureImage::NoFlags,
-                    TextureImage::ImageFormat aImageFormat = gfxImageFormatUnknown)
-        : BasicTextureImage(aTexture, aSize, aWrapMode, aContentType,
-                            aContext, aFlags, aImageFormat)
-        , mPixelBuffer(0)
-        , mPixelBufferSize(0)
-        , mBoundPixelBuffer(false)
-    {}
-    
-    GLuint mPixelBuffer;
-    int32_t mPixelBufferSize;
-    bool mBoundPixelBuffer;
-};
-
-already_AddRefed<TextureImage>
-GLContextCGL::CreateTextureImageInternal(const nsIntSize& aSize,
-                                         TextureImage::ContentType aContentType,
-                                         GLenum aWrapMode,
-                                         TextureImage::Flags aFlags,
-                                         TextureImage::ImageFormat aImageFormat)
-{
-    bool useNearestFilter = aFlags & TextureImage::UseNearestFilter;
-    MakeCurrent();
-
-    GLuint texture;
-    fGenTextures(1, &texture);
-
-    fActiveTexture(LOCAL_GL_TEXTURE0);
-    fBindTexture(LOCAL_GL_TEXTURE_2D, texture);
-
-    GLint texfilter = useNearestFilter ? LOCAL_GL_NEAREST : LOCAL_GL_LINEAR;
-    fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MIN_FILTER, texfilter);
-    fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MAG_FILTER, texfilter);
-    fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_S, aWrapMode);
-    fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_T, aWrapMode);
-
-    nsRefPtr<TextureImageCGL> teximage
-        (new TextureImageCGL(texture, aSize, aWrapMode, aContentType,
-                             this, aFlags, aImageFormat));
-    return teximage.forget();
-}
-
-already_AddRefed<TextureImage>
-GLContextCGL::CreateTextureImage(const nsIntSize& aSize,
-                                 TextureImage::ContentType aContentType,
-                                 GLenum aWrapMode,
-                                 TextureImage::Flags aFlags,
-                                 TextureImage::ImageFormat aImageFormat)
-{
-    if (!IsOffscreenSizeAllowed(gfxIntSize(aSize.width, aSize.height)) &&
-        gfxPlatform::OffMainThreadCompositingEnabled()) {
-      NS_ASSERTION(aWrapMode == LOCAL_GL_CLAMP_TO_EDGE, "Can't support wrapping with tiles!");
-      nsRefPtr<TextureImage> t = new gl::TiledTextureImage(this, aSize, aContentType,
-                                                           aFlags, aImageFormat);
-      return t.forget();
-    }
-
-    return CreateBasicTextureImage(this, aSize, aContentType, aWrapMode,
-                                   aFlags, aImageFormat);
-}
-
-already_AddRefed<TextureImage>
-GLContextCGL::TileGenFunc(const nsIntSize& aSize,
-                          TextureImage::ContentType aContentType,
-                          TextureImage::Flags aFlags,
-                          TextureImage::ImageFormat aImageFormat)
-{
-    return CreateTextureImageInternal(aSize, aContentType,
-                                      LOCAL_GL_CLAMP_TO_EDGE, aFlags,
-                                      aImageFormat);
-}
-
 static GLContextCGL *
 GetGlobalContextCGL()
 {
     return static_cast<GLContextCGL*>(GLContextProviderCGL::GetGlobalContext());
 }
 
 already_AddRefed<GLContext>
 GLContextProviderCGL::CreateForWindow(nsIWidget *aWidget)
--- a/gfx/gl/GLContextProviderEGL.cpp
+++ b/gfx/gl/GLContextProviderEGL.cpp
@@ -266,17 +266,16 @@ public:
         , mSurfaceOverride(EGL_NO_SURFACE)
         , mContext(context)
         , mThebesSurface(nullptr)
         , mBound(false)
         , mIsPBuffer(false)
         , mIsDoubleBuffered(false)
         , mCanBindToTexture(false)
         , mShareWithEGLImage(false)
-        , mTemporaryEGLImageTexture(0)
     {
         // any EGL contexts will always be GLESv2
         SetProfileVersion(ContextProfile::OpenGLES, 200);
 
 #ifdef DEBUG
         printf_stderr("Initializing context %p surface %p on display %p\n", mContext, mSurface, EGL_DISPLAY());
 #endif
 #if defined(MOZ_WIDGET_GONK)
@@ -289,23 +288,16 @@ public:
                 mHwc = nullptr;
             }
         }
 #endif
     }
 
     ~GLContextEGL()
     {
-        if (MakeCurrent()) {
-            if (mTemporaryEGLImageTexture != 0) {
-                fDeleteTextures(1, &mTemporaryEGLImageTexture);
-                mTemporaryEGLImageTexture = 0;
-            }
-        }
-
         MarkDestroyed();
 
 #ifdef DEBUG
         printf_stderr("Destroying context %p surface %p on display %p\n", mContext, mSurface, EGL_DISPLAY());
 #endif
 
         sEGLLibrary.fDestroyContext(EGL_DISPLAY(), mContext);
         mozilla::gl::DestroySurface(mSurface);
@@ -537,30 +529,17 @@ public:
                 }
             } else
 #endif
                 return sEGLLibrary.fSwapBuffers(EGL_DISPLAY(), mSurface);
         } else {
             return false;
         }
     }
-    // GLContext interface - returns Tiled Texture Image in our case
-    virtual already_AddRefed<TextureImage>
-    CreateTextureImage(const nsIntSize& aSize,
-                       TextureImage::ContentType aContentType,
-                       GLenum aWrapMode,
-                       TextureImage::Flags aFlags = TextureImage::NoFlags,
-                       TextureImage::ImageFormat aImageFormat = gfxImageFormatUnknown);
 
-    // a function to generate Tiles for Tiled Texture Image
-    virtual already_AddRefed<TextureImage>
-    TileGenFunc(const nsIntSize& aSize,
-                TextureImage::ContentType aContentType,
-                TextureImage::Flags aFlags = TextureImage::NoFlags,
-                TextureImage::ImageFormat aImageFormat = gfxImageFormatUnknown) MOZ_OVERRIDE;
     // hold a reference to the given surface
     // for the lifetime of this context.
     void HoldSurface(gfxASurface *aSurf) {
         mThebesSurface = aSurf;
     }
 
     EGLContext Context() {
         return mContext;
@@ -572,29 +551,16 @@ public:
     void BindOffscreenFramebuffer();
 
     static already_AddRefed<GLContextEGL>
     CreateEGLPixmapOffscreenContext(const gfxIntSize& size);
 
     static already_AddRefed<GLContextEGL>
     CreateEGLPBufferOffscreenContext(const gfxIntSize& size);
 
-    virtual SharedTextureHandle CreateSharedHandle(SharedTextureShareType shareType,
-                                                   void* buffer,
-                                                   SharedTextureBufferType bufferType);
-    virtual void UpdateSharedHandle(SharedTextureShareType shareType,
-                                    SharedTextureHandle sharedHandle);
-    virtual void ReleaseSharedHandle(SharedTextureShareType shareType,
-                                     SharedTextureHandle sharedHandle);
-    virtual bool GetSharedHandleDetails(SharedTextureShareType shareType,
-                                        SharedTextureHandle sharedHandle,
-                                        SharedHandleDetails& details);
-    virtual bool AttachSharedHandle(SharedTextureShareType shareType,
-                                    SharedTextureHandle sharedHandle);
-
 protected:
     friend class GLContextProviderEGL;
 
     EGLConfig  mConfig;
     EGLSurface mSurface;
     EGLSurface mSurfaceOverride;
     EGLContext mContext;
     nsRefPtr<gfxASurface> mThebesSurface;
@@ -603,20 +569,16 @@ protected:
     bool mIsPBuffer;
     bool mIsDoubleBuffered;
     bool mCanBindToTexture;
     bool mShareWithEGLImage;
 #ifdef MOZ_WIDGET_GONK
     nsRefPtr<HwcComposer2D> mHwc;
 #endif
 
-    // A dummy texture ID that can be used when we need a texture object whose
-    // images we're going to define with EGLImageTargetTexture2D.
-    GLuint mTemporaryEGLImageTexture;
-
     static EGLSurface CreatePBufferSurfaceTryingPowerOfTwo(EGLConfig config,
                                                            EGLenum bindToTextureFormat,
                                                            gfxIntSize& pbsize)
     {
         nsTArray<EGLint> pbattrs(16);
         EGLSurface surface = nullptr;
 
     TRY_AGAIN_POWER_OF_TWO:
@@ -651,372 +613,22 @@ protected:
             NS_WARNING("Failed to create pbuffer surface");
             return nullptr;
         }
 
         return surface;
     }
 };
 
-
-enum SharedHandleType {
-    SharedHandleType_Image
-#ifdef MOZ_WIDGET_ANDROID
-    , SharedHandleType_SurfaceTexture
-#endif
-};
-
-class SharedTextureHandleWrapper
-{
-public:
-    SharedTextureHandleWrapper(SharedHandleType aHandleType) : mHandleType(aHandleType)
-    {
-    }
-
-    virtual ~SharedTextureHandleWrapper()
-    {
-    }
-
-    SharedHandleType Type() { return mHandleType; }
-
-    SharedHandleType mHandleType;
-};
-
-#ifdef MOZ_WIDGET_ANDROID
-
-class SurfaceTextureWrapper: public SharedTextureHandleWrapper
-{
-public:
-    SurfaceTextureWrapper(nsSurfaceTexture* aSurfaceTexture) :
-        SharedTextureHandleWrapper(SharedHandleType_SurfaceTexture)
-        , mSurfaceTexture(aSurfaceTexture)
-    {
-    }
-
-    virtual ~SurfaceTextureWrapper() {
-        mSurfaceTexture = nullptr;
-    }
-
-    nsSurfaceTexture* SurfaceTexture() { return mSurfaceTexture; }
-
-    nsRefPtr<nsSurfaceTexture> mSurfaceTexture;
-};
-
-#endif // MOZ_WIDGET_ANDROID
-
-class EGLTextureWrapper : public SharedTextureHandleWrapper
-{
-public:
-    EGLTextureWrapper() :
-        SharedTextureHandleWrapper(SharedHandleType_Image)
-        , mEGLImage(nullptr)
-        , mSyncObject(nullptr)
-    {
-    }
-
-    // Args are the active GL context, and a texture in that GL
-    // context for which to create an EGLImage.  After the EGLImage
-    // is created, the texture is unused by EGLTextureWrapper.
-    bool CreateEGLImage(GLContextEGL *ctx, GLuint texture) {
-        MOZ_ASSERT(!mEGLImage && texture && sEGLLibrary.HasKHRImageBase());
-        static const EGLint eglAttributes[] = {
-            LOCAL_EGL_NONE
-        };
-        EGLContext eglContext = (EGLContext)ctx->GetEGLContext();
-        mEGLImage = sEGLLibrary.fCreateImage(EGL_DISPLAY(), eglContext, LOCAL_EGL_GL_TEXTURE_2D,
-                                             (EGLClientBuffer)texture, eglAttributes);
-        if (!mEGLImage) {
-#ifdef DEBUG
-            printf_stderr("Could not create EGL images: ERROR (0x%04x)\n", sEGLLibrary.fGetError());
-#endif
-            return false;
-        }
-        return true;
-    }
-
-    virtual ~EGLTextureWrapper() {
-        if (mEGLImage) {
-            sEGLLibrary.fDestroyImage(EGL_DISPLAY(), mEGLImage);
-            mEGLImage = nullptr;
-        }
-    }
-
-    const EGLImage GetEGLImage() {
-        return mEGLImage;
-    }
-
-    // Insert a sync point on the given context, which should be the current active
-    // context.
-    bool MakeSync(GLContext *ctx) {
-        MOZ_ASSERT(mSyncObject == nullptr);
-
-        if (sEGLLibrary.IsExtensionSupported(GLLibraryEGL::KHR_fence_sync)) {
-            mSyncObject = sEGLLibrary.fCreateSync(EGL_DISPLAY(), LOCAL_EGL_SYNC_FENCE, nullptr);
-            // We need to flush to make sure the sync object enters the command stream;
-            // we can't use EGL_SYNC_FLUSH_COMMANDS_BIT at wait time, because the wait
-            // happens on a different thread/context.
-            ctx->fFlush();
-        }
-
-        if (mSyncObject == EGL_NO_SYNC) {
-            // we failed to create one, so just do a finish
-            ctx->fFinish();
-        }
-
-        return true;
-    }
-
-    bool WaitSync() {
-        if (!mSyncObject) {
-            // if we have no sync object, then we did a Finish() earlier
-            return true;
-        }
-
-        // wait at most 1 second; this should really be never/rarely hit
-        const uint64_t ns_per_ms = 1000 * 1000;
-        EGLTime timeout = 1000 * ns_per_ms;
-
-        EGLint result = sEGLLibrary.fClientWaitSync(EGL_DISPLAY(), mSyncObject, 0, timeout);
-        sEGLLibrary.fDestroySync(EGL_DISPLAY(), mSyncObject);
-        mSyncObject = nullptr;
-
-        return result == LOCAL_EGL_CONDITION_SATISFIED;
-    }
-
-private:
-    EGLImage mEGLImage;
-    EGLSync mSyncObject;
-};
-
-void
-GLContextEGL::UpdateSharedHandle(SharedTextureShareType shareType,
-                                 SharedTextureHandle sharedHandle)
-{
-    if (shareType != SameProcess) {
-        NS_ERROR("Implementation not available for this sharing type");
-        return;
-    }
-
-    SharedTextureHandleWrapper* wrapper = reinterpret_cast<SharedTextureHandleWrapper*>(sharedHandle);
-
-    NS_ASSERTION(wrapper->Type() == SharedHandleType_Image, "Expected EGLImage shared handle");
-    NS_ASSERTION(mShareWithEGLImage, "EGLImage not supported or disabled in runtime");
-
-    EGLTextureWrapper* wrap = reinterpret_cast<EGLTextureWrapper*>(wrapper);
-    // We need to copy the current GLContext drawing buffer to the texture
-    // exported by the EGLImage.  Need to save both the read FBO and the texture
-    // binding, because we're going to munge them to do this.
-    ScopedBindTexture autoTex(this, mTemporaryEGLImageTexture);
-    fEGLImageTargetTexture2D(LOCAL_GL_TEXTURE_2D, wrap->GetEGLImage());
-
-    // CopyTexSubImage2D, is ~2x slower than simple FBO render to texture with
-    // draw quads, but if we want that, we need to assure that our default
-    // framebuffer is texture-backed.
-    gfxIntSize size = OffscreenSize();
-    BlitHelper()->BlitFramebufferToTexture(0, mTemporaryEGLImageTexture, size, size);
-
-    // Make sure our copy is finished, so that we can be ready to draw
-    // in different thread GLContext.  If we have KHR_fence_sync, then
-    // we insert a sync object, otherwise we have to do a GuaranteeResolve.
-    wrap->MakeSync(this);
-}
-
-SharedTextureHandle
-GLContextEGL::CreateSharedHandle(SharedTextureShareType shareType,
-                                 void* buffer,
-                                 SharedTextureBufferType bufferType)
-{
-    // Both EGLImage and SurfaceTexture only support same-process currently, but
-    // it's possible to make SurfaceTexture work across processes. We should do that.
-    if (shareType != SameProcess)
-        return 0;
-
-    switch (bufferType) {
-#ifdef MOZ_WIDGET_ANDROID
-    case SharedTextureBufferType::SurfaceTexture:
-        if (!IsExtensionSupported(GLContext::OES_EGL_image_external)) {
-            NS_WARNING("Missing GL_OES_EGL_image_external");
-            return 0;
-        }
-
-        return (SharedTextureHandle) new SurfaceTextureWrapper(reinterpret_cast<nsSurfaceTexture*>(buffer));
-#endif
-    case SharedTextureBufferType::TextureID: {
-        if (!mShareWithEGLImage)
-            return 0;
-
-        GLuint texture = (uintptr_t)buffer;
-        EGLTextureWrapper* tex = new EGLTextureWrapper();
-        if (!tex->CreateEGLImage(this, texture)) {
-            NS_ERROR("EGLImage creation for EGLTextureWrapper failed");
-            delete tex;
-            return 0;
-        }
-
-        return (SharedTextureHandle)tex;
-    }
-    default:
-        NS_ERROR("Unknown shared texture buffer type");
-        return 0;
-    }
-}
-
-void GLContextEGL::ReleaseSharedHandle(SharedTextureShareType shareType,
-                                       SharedTextureHandle sharedHandle)
-{
-    if (shareType != SameProcess) {
-        NS_ERROR("Implementation not available for this sharing type");
-        return;
-    }
-
-    SharedTextureHandleWrapper* wrapper = reinterpret_cast<SharedTextureHandleWrapper*>(sharedHandle);
-
-    switch (wrapper->Type()) {
-#ifdef MOZ_WIDGET_ANDROID
-    case SharedHandleType_SurfaceTexture:
-        delete wrapper;
-        break;
-#endif
-    
-    case SharedHandleType_Image: {
-        NS_ASSERTION(mShareWithEGLImage, "EGLImage not supported or disabled in runtime");
-
-        EGLTextureWrapper* wrap = (EGLTextureWrapper*)sharedHandle;
-        delete wrap;
-        break;
-    }
-
-    default:
-        NS_ERROR("Unknown shared handle type");
-        return;
-    }
-}
-
-bool GLContextEGL::GetSharedHandleDetails(SharedTextureShareType shareType,
-                                          SharedTextureHandle sharedHandle,
-                                          SharedHandleDetails& details)
-{
-    if (shareType != SameProcess)
-        return false;
-
-    SharedTextureHandleWrapper* wrapper = reinterpret_cast<SharedTextureHandleWrapper*>(sharedHandle);
-
-    switch (wrapper->Type()) {
-#ifdef MOZ_WIDGET_ANDROID
-    case SharedHandleType_SurfaceTexture: {
-        SurfaceTextureWrapper* surfaceWrapper = reinterpret_cast<SurfaceTextureWrapper*>(wrapper);
-
-        details.mTarget = LOCAL_GL_TEXTURE_EXTERNAL;
-        details.mTextureFormat = FORMAT_R8G8B8A8;
-        surfaceWrapper->SurfaceTexture()->GetTransformMatrix(details.mTextureTransform);
-        break;
-    }
-#endif
-
-    case SharedHandleType_Image:
-        details.mTarget = LOCAL_GL_TEXTURE_2D;
-        details.mTextureFormat = FORMAT_R8G8B8A8;
-        break;
-
-    default:
-        NS_ERROR("Unknown shared handle type");
-        return false;
-    }
-
-    return true;
-}
-
-bool GLContextEGL::AttachSharedHandle(SharedTextureShareType shareType,
-                                      SharedTextureHandle sharedHandle)
-{
-    if (shareType != SameProcess)
-        return false;
-
-    SharedTextureHandleWrapper* wrapper = reinterpret_cast<SharedTextureHandleWrapper*>(sharedHandle);
-
-    switch (wrapper->Type()) {
-#ifdef MOZ_WIDGET_ANDROID
-    case SharedHandleType_SurfaceTexture: {
-#ifndef DEBUG
-        /**
-         * NOTE: SurfaceTexture spams us if there are any existing GL errors, so we'll clear
-         * them here in order to avoid that.
-         */
-        GetAndClearError();
-#endif
-        SurfaceTextureWrapper* surfaceTextureWrapper = reinterpret_cast<SurfaceTextureWrapper*>(wrapper);
-
-        // FIXME: SurfaceTexture provides a transform matrix which is supposed to
-        // be applied to the texture coordinates. We should return that here
-        // so we can render correctly. Bug 775083
-        surfaceTextureWrapper->SurfaceTexture()->UpdateTexImage();
-        break;
-    }
-#endif // MOZ_WIDGET_ANDROID
-
-    case SharedHandleType_Image: {
-        NS_ASSERTION(mShareWithEGLImage, "EGLImage not supported or disabled in runtime");
-
-        EGLTextureWrapper* wrap = (EGLTextureWrapper*)sharedHandle;
-        wrap->WaitSync();
-        fEGLImageTargetTexture2D(LOCAL_GL_TEXTURE_2D, wrap->GetEGLImage());
-        break;
-    }
-
-    default:
-        NS_ERROR("Unknown shared handle type");
-        return false;
-    }
-
-    return true;
-}
-
 bool
 GLContextEGL::ResizeOffscreen(const gfxIntSize& aNewSize)
 {
 	return ResizeScreenBuffer(aNewSize);
 }
 
-already_AddRefed<TextureImage>
-GLContextEGL::CreateTextureImage(const nsIntSize& aSize,
-                                 TextureImage::ContentType aContentType,
-                                 GLenum aWrapMode,
-                                 TextureImage::Flags aFlags,
-                                 TextureImage::ImageFormat aImageFormat)
-{
-    nsRefPtr<TextureImage> t = new gl::TiledTextureImage(this, aSize, aContentType, aFlags, aImageFormat);
-    return t.forget();
-}
-
-already_AddRefed<TextureImage>
-GLContextEGL::TileGenFunc(const nsIntSize& aSize,
-                          TextureImage::ContentType aContentType,
-                          TextureImage::Flags aFlags,
-                          TextureImage::ImageFormat aImageFormat)
-{
-  MakeCurrent();
-
-  GLuint texture;
-  fGenTextures(1, &texture);
-
-  nsRefPtr<TextureImageEGL> teximage =
-      new TextureImageEGL(texture, aSize, LOCAL_GL_CLAMP_TO_EDGE, aContentType,
-                          this, aFlags, TextureImage::Created, aImageFormat);
-  
-  teximage->BindTexture(LOCAL_GL_TEXTURE0);
-
-  GLint texfilter = aFlags & TextureImage::UseNearestFilter ? LOCAL_GL_NEAREST : LOCAL_GL_LINEAR;
-  fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MIN_FILTER, texfilter);
-  fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MAG_FILTER, texfilter);
-  fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_S, LOCAL_GL_CLAMP_TO_EDGE);
-  fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_T, LOCAL_GL_CLAMP_TO_EDGE);
-
-  return teximage.forget();
-}
-
 static const EGLint kEGLConfigAttribsOffscreenPBuffer[] = {
     LOCAL_EGL_SURFACE_TYPE,    LOCAL_EGL_PBUFFER_BIT,
     LOCAL_EGL_RENDERABLE_TYPE, LOCAL_EGL_OPENGL_ES2_BIT,
     LOCAL_EGL_NONE
 };
 
 static const EGLint kEGLConfigAttribsRGB16[] = {
     LOCAL_EGL_SURFACE_TYPE,    LOCAL_EGL_WINDOW_BIT,
--- a/gfx/gl/GLContextProviderGLX.cpp
+++ b/gfx/gl/GLContextProviderGLX.cpp
@@ -928,28 +928,16 @@ TRY_AGAIN_NO_SHARING:
     {
         if (!mDoubleBuffered)
             return false;
         mGLX->xSwapBuffers(mDisplay, mDrawable);
         mGLX->xWaitGL();
         return true;
     }
 
-    bool TextureImageSupportsGetBackingSurface()
-    {
-        return false;
-    }
-
-    virtual already_AddRefed<TextureImage>
-    CreateTextureImage(const nsIntSize& aSize,
-                       TextureImage::ContentType aContentType,
-                       GLenum aWrapMode,
-                       TextureImage::Flags aFlags = TextureImage::NoFlags,
-                       TextureImage::ImageFormat aImageFormat = gfxImageFormatUnknown);
-
 private:
     friend class GLContextProviderGLX;
 
     GLContextGLX(const SurfaceCaps& caps,
                  GLContext* shareContext,
                  bool isOffscreen,
                  Display *aDisplay,
                  GLXDrawable aDrawable,
@@ -980,188 +968,16 @@ private:
     bool mDoubleBuffered;
 
     LibType mLibType;
     GLXLibrary* mGLX;
 
     nsRefPtr<gfxXlibSurface> mPixmap;
 };
 
-class TextureImageGLX : public TextureImage
-{
-    friend already_AddRefed<TextureImage>
-    GLContextGLX::CreateTextureImage(const nsIntSize&,
-                                     ContentType,
-                                     GLenum,
-                                     TextureImage::Flags,
-                                     TextureImage::ImageFormat);
-
-public:
-    virtual ~TextureImageGLX()
-    {
-        mGLContext->MakeCurrent();
-        mGLContext->fDeleteTextures(1, &mTexture);
-        sGLXLib.DestroyPixmap(mPixmap);
-    }
-
-    virtual gfxASurface* BeginUpdate(nsIntRegion& aRegion)
-    {
-        mInUpdate = true;
-        return mUpdateSurface;
-    }
-
-    virtual void EndUpdate()
-    {
-        mInUpdate = false;
-    }
-
-
-    virtual bool DirectUpdate(gfxASurface* aSurface, const nsIntRegion& aRegion, const nsIntPoint& aFrom)
-    {
-        nsRefPtr<gfxContext> ctx = new gfxContext(mUpdateSurface);
-        gfxUtils::ClipToRegion(ctx, aRegion);
-        ctx->SetSource(aSurface, aFrom);
-        ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
-        ctx->Paint();
-        return true;
-    }
-
-    virtual void BindTexture(GLenum aTextureUnit)
-    {
-        mGLContext->fActiveTexture(aTextureUnit);
-        mGLContext->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexture);
-        sGLXLib.BindTexImage(mPixmap);
-        mGLContext->fActiveTexture(LOCAL_GL_TEXTURE0);
-    }
-
-    virtual void ReleaseTexture()
-    {
-        sGLXLib.ReleaseTexImage(mPixmap);
-    }
-
-    virtual already_AddRefed<gfxASurface> GetBackingSurface()
-    {
-        nsRefPtr<gfxASurface> copy = mUpdateSurface;
-        return copy.forget();
-    }
-
-    virtual bool InUpdate() const { return mInUpdate; }
-
-    virtual GLuint GetTextureID() {
-        return mTexture;
-    }
-
-private:
-   TextureImageGLX(GLuint aTexture,
-                   const nsIntSize& aSize,
-                   GLenum aWrapMode,
-                   ContentType aContentType,
-                   GLContext* aContext,
-                   gfxASurface* aSurface,
-                   GLXPixmap aPixmap,
-                   TextureImage::Flags aFlags,
-                   LibType aLibType)
-        : TextureImage(aSize, aWrapMode, aContentType, aFlags)
-        , mGLContext(aContext)
-        , mUpdateSurface(aSurface)
-        , mPixmap(aPixmap)
-        , mInUpdate(false)
-        , mTexture(aTexture)
-        , sGLXLib(sGLXLibrary[aLibType])
-    {
-        if (aSurface->GetContentType() == GFX_CONTENT_COLOR_ALPHA) {
-            mTextureFormat = FORMAT_R8G8B8A8;
-        } else {
-            mTextureFormat = FORMAT_R8G8B8X8;
-        }
-    }
-
-    nsRefPtr<GLContext> mGLContext;
-    nsRefPtr<gfxASurface> mUpdateSurface;
-    GLXPixmap mPixmap;
-    bool mInUpdate;
-    GLuint mTexture;
-    GLXLibrary& sGLXLib;
-
-    virtual void ApplyFilter()
-    {
-        mGLContext->ApplyFilterToBoundTexture(mFilter);
-    }
-};
-
-already_AddRefed<TextureImage>
-GLContextGLX::CreateTextureImage(const nsIntSize& aSize,
-                                 TextureImage::ContentType aContentType,
-                                 GLenum aWrapMode,
-                                 TextureImage::Flags aFlags,
-                                 TextureImage::ImageFormat aImageFormat)
-{
-    if (!TextureImageSupportsGetBackingSurface()) {
-        return GLContext::CreateTextureImage(aSize, 
-                                             aContentType, 
-                                             aWrapMode, 
-                                             aFlags,
-                                             aImageFormat);
-    }
-
-    Display *display = DefaultXDisplay();
-    int xscreen = DefaultScreen(display);
-    gfxImageFormat imageFormat =
-        gfxPlatform::GetPlatform()->OptimalFormatForContent(aContentType);
-
-    XRenderPictFormat* xrenderFormat =
-        gfxXlibSurface::FindRenderFormat(display, imageFormat);
-    NS_ASSERTION(xrenderFormat, "Could not find a render format for our display!");
-
-
-    nsRefPtr<gfxXlibSurface> surface =
-        gfxXlibSurface::Create(ScreenOfDisplay(display, xscreen),
-                               xrenderFormat,
-                               gfxIntSize(aSize.width, aSize.height));
-
-    NS_ASSERTION(surface, "Failed to create xlib surface!");
-
-    if (aContentType == GFX_CONTENT_COLOR_ALPHA) {
-        nsRefPtr<gfxContext> ctx = new gfxContext(surface);
-        ctx->SetOperator(gfxContext::OPERATOR_CLEAR);
-        ctx->Paint();
-    }
-
-    MakeCurrent();
-    GLXPixmap pixmap = mGLX->CreatePixmap(surface);
-    // GLX might not be able to give us an A8 pixmap. If so, just use CPU
-    // memory.
-    if (!pixmap && imageFormat == gfxImageFormatA8) {
-        return GLContext::CreateTextureImage(aSize,
-                                             aContentType,
-                                             aWrapMode,
-                                             aFlags,
-                                             aImageFormat);
-    }
-    NS_ASSERTION(pixmap, "Failed to create pixmap!");
-
-    GLuint texture;
-    fGenTextures(1, &texture);
-
-    fActiveTexture(LOCAL_GL_TEXTURE0);
-    fBindTexture(LOCAL_GL_TEXTURE_2D, texture);
-
-    nsRefPtr<TextureImageGLX> teximage =
-        new TextureImageGLX(texture, aSize, aWrapMode, aContentType, 
-                            this, surface, pixmap, aFlags, mLibType);
-
-    GLint texfilter = aFlags & TextureImage::UseNearestFilter ? LOCAL_GL_NEAREST : LOCAL_GL_LINEAR;
-    fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MIN_FILTER, texfilter);
-    fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MAG_FILTER, texfilter);
-    fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_S, aWrapMode);
-    fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_T, aWrapMode);
-
-    return teximage.forget();
-}
-
 static GLContextGLX *
 GetGlobalContextGLX(const ContextFlags aFlags = ContextFlagsNone)
 {
     return static_cast<GLContextGLX*>(GLContextProviderGLX::GetGlobalContext(aFlags));
 }
 
 static bool
 AreCompatibleVisuals(Visual *one, Visual *two)
new file mode 100644
--- /dev/null
+++ b/gfx/gl/GLSharedHandleHelpers.cpp
@@ -0,0 +1,328 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "GLContext.h"
+#include "GLLibraryEGL.h"
+#include "GLSharedHandleHelpers.h"
+
+namespace mozilla {
+namespace gl {
+
+enum SharedHandleType {
+    SharedHandleType_Image
+#ifdef MOZ_WIDGET_ANDROID
+    , SharedHandleType_SurfaceTexture
+#endif
+};
+
+class SharedTextureHandleWrapper
+{
+public:
+    SharedTextureHandleWrapper(SharedHandleType aHandleType) : mHandleType(aHandleType)
+    {
+    }
+
+    virtual ~SharedTextureHandleWrapper()
+    {
+    }
+
+    SharedHandleType Type() { return mHandleType; }
+
+    SharedHandleType mHandleType;
+};
+
+#ifdef MOZ_WIDGET_ANDROID
+
+class SurfaceTextureWrapper: public SharedTextureHandleWrapper
+{
+public:
+    SurfaceTextureWrapper(nsSurfaceTexture* aSurfaceTexture) :
+        SharedTextureHandleWrapper(SharedHandleType_SurfaceTexture)
+        , mSurfaceTexture(aSurfaceTexture)
+    {
+    }
+
+    virtual ~SurfaceTextureWrapper() {
+        mSurfaceTexture = nullptr;
+    }
+
+    nsSurfaceTexture* SurfaceTexture() { return mSurfaceTexture; }
+
+    nsRefPtr<nsSurfaceTexture> mSurfaceTexture;
+};
+
+#endif // MOZ_WIDGET_ANDROID
+
+class EGLTextureWrapper : public SharedTextureHandleWrapper
+{
+public:
+    EGLTextureWrapper() :
+        SharedTextureHandleWrapper(SharedHandleType_Image)
+        , mEGLImage(nullptr)
+        , mSyncObject(nullptr)
+    {
+    }
+
+    // Args are the active GL context, and a texture in that GL
+    // context for which to create an EGLImage.  After the EGLImage
+    // is created, the texture is unused by EGLTextureWrapper.
+    bool CreateEGLImage(GLContext *ctx, uintptr_t texture) {
+        MOZ_ASSERT(!mEGLImage && texture && sEGLLibrary.HasKHRImageBase());
+        static const EGLint eglAttributes[] = {
+            LOCAL_EGL_NONE
+        };
+        EGLContext eglContext = (EGLContext)ctx->GetNativeData(GLContext::NativeGLContext);
+        mEGLImage = sEGLLibrary.fCreateImage(EGL_DISPLAY(), eglContext, LOCAL_EGL_GL_TEXTURE_2D,
+                                             (EGLClientBuffer)texture, eglAttributes);
+        if (!mEGLImage) {
+#ifdef DEBUG
+            printf_stderr("Could not create EGL images: ERROR (0x%04x)\n", sEGLLibrary.fGetError());
+#endif
+            return false;
+        }
+        return true;
+    }
+
+    virtual ~EGLTextureWrapper() {
+        if (mEGLImage) {
+            sEGLLibrary.fDestroyImage(EGL_DISPLAY(), mEGLImage);
+            mEGLImage = nullptr;
+        }
+    }
+
+    const EGLImage GetEGLImage() {
+        return mEGLImage;
+    }
+
+    // Insert a sync point on the given context, which should be the current active
+    // context.
+    bool MakeSync(GLContext *ctx) {
+        MOZ_ASSERT(mSyncObject == nullptr);
+
+        if (sEGLLibrary.IsExtensionSupported(GLLibraryEGL::KHR_fence_sync)) {
+            mSyncObject = sEGLLibrary.fCreateSync(EGL_DISPLAY(), LOCAL_EGL_SYNC_FENCE, nullptr);
+            // We need to flush to make sure the sync object enters the command stream;
+            // we can't use EGL_SYNC_FLUSH_COMMANDS_BIT at wait time, because the wait
+            // happens on a different thread/context.
+            ctx->fFlush();
+        }
+
+        if (mSyncObject == EGL_NO_SYNC) {
+            // we failed to create one, so just do a finish
+            ctx->fFinish();
+        }
+
+        return true;
+    }
+
+    bool WaitSync() {
+        if (!mSyncObject) {
+            // if we have no sync object, then we did a Finish() earlier
+            return true;
+        }
+
+        // wait at most 1 second; this should really be never/rarely hit
+        const uint64_t ns_per_ms = 1000 * 1000;
+        EGLTime timeout = 1000 * ns_per_ms;
+
+        EGLint result = sEGLLibrary.fClientWaitSync(EGL_DISPLAY(), mSyncObject, 0, timeout);
+        sEGLLibrary.fDestroySync(EGL_DISPLAY(), mSyncObject);
+        mSyncObject = nullptr;
+
+        return result == LOCAL_EGL_CONDITION_SATISFIED;
+    }
+
+private:
+    EGLImage mEGLImage;
+    EGLSync mSyncObject;
+};
+
+static bool DoesEGLContextSupportSharingWithEGLImage(GLContext *gl)
+{
+    return sEGLLibrary.HasKHRImageBase() &&
+           sEGLLibrary.HasKHRImageTexture2D() &&
+           gl->IsExtensionSupported(GLContext::OES_EGL_image);
+}
+
+SharedTextureHandle CreateSharedHandle(GLContext* gl,
+                                       SharedTextureShareType shareType,
+                                       void* buffer,
+                                       SharedTextureBufferType bufferType)
+{
+    // unimplemented outside of EGL
+    if (gl->GetContextType() != ContextTypeEGL)
+        return 0;
+
+    // Both EGLImage and SurfaceTexture only support same-process currently, but
+    // it's possible to make SurfaceTexture work across processes. We should do that.
+    if (shareType != SameProcess)
+        return 0;
+
+    switch (bufferType) {
+#ifdef MOZ_WIDGET_ANDROID
+    case SharedTextureBufferType::SurfaceTexture:
+        if (!gl->IsExtensionSupported(GLContext::OES_EGL_image_external)) {
+            NS_WARNING("Missing GL_OES_EGL_image_external");
+            return 0;
+        }
+
+        return (SharedTextureHandle) new SurfaceTextureWrapper(reinterpret_cast<nsSurfaceTexture*>(buffer));
+#endif
+    case SharedTextureBufferType::TextureID: {
+        if (!DoesEGLContextSupportSharingWithEGLImage(gl))
+            return 0;
+
+        GLuint texture = (uintptr_t)buffer;
+        EGLTextureWrapper* tex = new EGLTextureWrapper();
+        if (!tex->CreateEGLImage(gl, texture)) {
+            NS_ERROR("EGLImage creation for EGLTextureWrapper failed");
+            delete tex;
+            return 0;
+        }
+
+        return (SharedTextureHandle)tex;
+    }
+    default:
+        NS_ERROR("Unknown shared texture buffer type");
+        return 0;
+    }
+}
+
+void ReleaseSharedHandle(GLContext* gl,
+                         SharedTextureShareType shareType,
+                         SharedTextureHandle sharedHandle)
+{
+    // unimplemented outside of EGL
+    if (gl->GetContextType() != ContextTypeEGL)
+        return;
+
+    if (shareType != SameProcess) {
+        NS_ERROR("Implementation not available for this sharing type");
+        return;
+    }
+
+    SharedTextureHandleWrapper* wrapper = reinterpret_cast<SharedTextureHandleWrapper*>(sharedHandle);
+
+    switch (wrapper->Type()) {
+#ifdef MOZ_WIDGET_ANDROID
+    case SharedHandleType_SurfaceTexture:
+        delete wrapper;
+        break;
+#endif
+
+    case SharedHandleType_Image: {
+        NS_ASSERTION(DoesEGLContextSupportSharingWithEGLImage(gl), "EGLImage not supported or disabled in runtime");
+
+        EGLTextureWrapper* wrap = (EGLTextureWrapper*)sharedHandle;
+        delete wrap;
+        break;
+    }
+
+    default:
+        NS_ERROR("Unknown shared handle type");
+        return;
+    }
+}
+
+bool GetSharedHandleDetails(GLContext* gl,
+                            SharedTextureShareType shareType,
+                            SharedTextureHandle sharedHandle,
+                            SharedHandleDetails& details)
+{
+    // unimplemented outside of EGL
+    if (gl->GetContextType() != ContextTypeEGL)
+        return false;
+
+    if (shareType != SameProcess)
+        return false;
+
+    SharedTextureHandleWrapper* wrapper = reinterpret_cast<SharedTextureHandleWrapper*>(sharedHandle);
+
+    switch (wrapper->Type()) {
+#ifdef MOZ_WIDGET_ANDROID
+    case SharedHandleType_SurfaceTexture: {
+        SurfaceTextureWrapper* surfaceWrapper = reinterpret_cast<SurfaceTextureWrapper*>(wrapper);
+
+        details.mTarget = LOCAL_GL_TEXTURE_EXTERNAL;
+        details.mTextureFormat = gfx::FORMAT_R8G8B8A8;
+        surfaceWrapper->SurfaceTexture()->GetTransformMatrix(details.mTextureTransform);
+        break;
+    }
+#endif
+
+    case SharedHandleType_Image:
+        details.mTarget = LOCAL_GL_TEXTURE_2D;
+        details.mTextureFormat = gfx::FORMAT_R8G8B8A8;
+        break;
+
+    default:
+        NS_ERROR("Unknown shared handle type");
+        return false;
+    }
+
+    return true;
+}
+
+bool AttachSharedHandle(GLContext* gl,
+                        SharedTextureShareType shareType,
+                        SharedTextureHandle sharedHandle)
+{
+    // unimplemented outside of EGL
+    if (gl->GetContextType() != ContextTypeEGL)
+        return false;
+
+    if (shareType != SameProcess)
+        return false;
+
+    SharedTextureHandleWrapper* wrapper = reinterpret_cast<SharedTextureHandleWrapper*>(sharedHandle);
+
+    switch (wrapper->Type()) {
+#ifdef MOZ_WIDGET_ANDROID
+    case SharedHandleType_SurfaceTexture: {
+#ifndef DEBUG
+        /*
+         * NOTE: SurfaceTexture spams us if there are any existing GL errors, so we'll clear
+         * them here in order to avoid that.
+         */
+        gl->GetAndClearError();
+#endif
+        SurfaceTextureWrapper* surfaceTextureWrapper = reinterpret_cast<SurfaceTextureWrapper*>(wrapper);
+
+        // FIXME: SurfaceTexture provides a transform matrix which is supposed to
+        // be applied to the texture coordinates. We should return that here
+        // so we can render correctly. Bug 775083
+        surfaceTextureWrapper->SurfaceTexture()->UpdateTexImage();
+        break;
+    }
+#endif // MOZ_WIDGET_ANDROID
+
+    case SharedHandleType_Image: {
+        NS_ASSERTION(DoesEGLContextSupportSharingWithEGLImage(gl), "EGLImage not supported or disabled in runtime");
+
+        EGLTextureWrapper* wrap = (EGLTextureWrapper*)sharedHandle;
+        wrap->WaitSync();
+        gl->fEGLImageTargetTexture2D(LOCAL_GL_TEXTURE_2D, wrap->GetEGLImage());
+        break;
+    }
+
+    default:
+        NS_ERROR("Unknown shared handle type");
+        return false;
+    }
+
+    return true;
+}
+
+/**
+  * Detach Shared GL Handle from GL_TEXTURE_2D target
+  */
+void DetachSharedHandle(GLContext*,
+                        SharedTextureShareType,
+                        SharedTextureHandle)
+{
+  // currently a no-operation
+}
+
+}
+}
new file mode 100644
--- /dev/null
+++ b/gfx/gl/GLSharedHandleHelpers.h
@@ -0,0 +1,73 @@
+/* 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 GLSHAREDHANDLEHELPERS_H_
+#define GLSHAREDHANDLEHELPERS_H_
+
+#include "GLContextTypes.h"
+#include "mozilla/gfx/Types.h"
+
+namespace mozilla {
+namespace gl {
+
+/**
+  * Create a new shared GLContext content handle, using the passed buffer as a source.
+  * Must be released by ReleaseSharedHandle.
+  */
+SharedTextureHandle CreateSharedHandle(GLContext* gl,
+                                       SharedTextureShareType shareType,
+                                       void* buffer,
+                                       SharedTextureBufferType bufferType);
+
+/**
+  * - It is better to call ReleaseSharedHandle before original GLContext destroyed,
+  *     otherwise warning will be thrown on attempt to destroy Texture associated with SharedHandle, depends on backend implementation.
+  * - It does not require to be called on context where it was created,
+  *     because SharedHandle suppose to keep Context reference internally,
+  *     or don't require specific context at all, for example IPC SharedHandle.
+  * - Not recommended to call this between AttachSharedHandle and Draw Target call.
+  *      if it is really required for some special backend, then DetachSharedHandle API must be added with related implementation.
+  * - It is recommended to stop any possible access to SharedHandle (Attachments, pending GL calls) before calling Release,
+  *      otherwise some artifacts might appear or even crash if API backend implementation does not expect that.
+  * SharedHandle (currently EGLImage) does not require GLContext because it is EGL call, and can be destroyed
+  *   at any time, unless EGLImage have siblings (which are not expected with current API).
+  */
+void ReleaseSharedHandle(GLContext* gl,
+                         SharedTextureShareType shareType,
+                         SharedTextureHandle sharedHandle);
+
+
+typedef struct {
+    GLenum mTarget;
+    gfx::SurfaceFormat mTextureFormat;
+    gfx3DMatrix mTextureTransform;
+} SharedHandleDetails;
+
+/**
+  * Returns information necessary for rendering a shared handle.
+  * These values change depending on what sharing mechanism is in use
+  */
+bool GetSharedHandleDetails(GLContext* gl,
+                            SharedTextureShareType shareType,
+                            SharedTextureHandle sharedHandle,
+                            SharedHandleDetails& details);
+/**
+  * Attach Shared GL Handle to GL_TEXTURE_2D target
+  * GLContext must be current before this call
+  */
+bool AttachSharedHandle(GLContext* gl,
+                        SharedTextureShareType shareType,
+                        SharedTextureHandle sharedHandle);
+
+/**
+  * Detach Shared GL Handle from GL_TEXTURE_2D target
+  */
+void DetachSharedHandle(GLContext* gl,
+                        SharedTextureShareType shareType,
+                        SharedTextureHandle sharedHandle);
+
+}
+}
+
+#endif
--- a/gfx/gl/GLTextureImage.cpp
+++ b/gfx/gl/GLTextureImage.cpp
@@ -5,28 +5,74 @@
 
 #include "GLTextureImage.h"
 #include "GLContext.h"
 #include "gfxContext.h"
 #include "gfxPlatform.h"
 #include "gfxUtils.h"
 #include "gfx2DGlue.h"
 #include "ScopedGLHelpers.h"
+#include "GLUploadHelpers.h"
+
+#include "TextureImageEGL.h"
+#ifdef XP_MACOSX
+#include "TextureImageCGL.h"
+#endif
 
 namespace mozilla {
 namespace gl {
 
 already_AddRefed<TextureImage>
+CreateTextureImage(GLContext* gl,
+                   const nsIntSize& aSize,
+                   TextureImage::ContentType aContentType,
+                   GLenum aWrapMode,
+                   TextureImage::Flags aFlags,
+                   TextureImage::ImageFormat aImageFormat)
+{
+    switch (gl->GetContextType()) {
+#ifdef XP_MACOSX
+        case ContextTypeCGL:
+            return CreateTextureImageCGL(gl, aSize, aContentType, aWrapMode, aFlags, aImageFormat);
+#endif
+        case ContextTypeEGL:
+            return CreateTextureImageEGL(gl, aSize, aContentType, aWrapMode, aFlags, aImageFormat);
+        default:
+            return CreateBasicTextureImage(gl, aSize, aContentType, aWrapMode, aFlags, aImageFormat);
+    }
+}
+
+
+static already_AddRefed<TextureImage>
+TileGenFunc(GLContext* gl,
+            const nsIntSize& aSize,
+            TextureImage::ContentType aContentType,
+            TextureImage::Flags aFlags,
+            TextureImage::ImageFormat aImageFormat)
+{
+    switch (gl->GetContextType()) {
+#ifdef XP_MACOSX
+        case ContextTypeCGL:
+            return TileGenFuncCGL(gl, aSize, aContentType, aFlags, aImageFormat);
+#endif
+        case ContextTypeEGL:
+            return TileGenFuncEGL(gl, aSize, aContentType, aFlags, aImageFormat);
+        default:
+            return nullptr;
+    }
+}
+already_AddRefed<TextureImage>
+
 TextureImage::Create(GLContext* gl,
                      const nsIntSize& size,
                      TextureImage::ContentType contentType,
                      GLenum wrapMode,
                      TextureImage::Flags flags)
 {
-    return gl->CreateTextureImage(size, contentType, wrapMode, flags);
+    return CreateTextureImage(gl, size, contentType, wrapMode, flags);
 }
 
 // Moz2D equivalent...
 already_AddRefed<TextureImage>
 TextureImage::Create(GLContext* gl,
                      const gfx::IntSize& size,
                      TextureImage::ContentType contentType,
                      GLenum wrapMode,
@@ -79,17 +125,17 @@ BasicTextureImage::~BasicTextureImage()
 }
 
 gfxASurface*
 BasicTextureImage::BeginUpdate(nsIntRegion& aRegion)
 {
     NS_ASSERTION(!mUpdateSurface, "BeginUpdate() without EndUpdate()?");
 
     // determine the region the client will need to repaint
-    if (mGLContext->CanUploadSubTextures()) {
+    if (CanUploadSubTextures(mGLContext)) {
         GetUpdateRegion(aRegion);
     } else {
         aRegion = nsIntRect(nsIntPoint(0, 0), mSize);
     }
 
     mUpdateRegion = aRegion;
 
     nsIntRect rgnSize = mUpdateRegion.GetBounds();
@@ -133,22 +179,23 @@ BasicTextureImage::EndUpdate()
 
     // Undo the device offset that BeginUpdate set; doesn't much matter for us here,
     // but important if we ever do anything directly with the surface.
     mUpdateSurface->SetDeviceOffset(gfxPoint(0, 0));
 
     bool relative = FinishedSurfaceUpdate();
 
     mTextureFormat =
-        mGLContext->UploadSurfaceToTexture(mUpdateSurface,
-                                           mUpdateRegion,
-                                           mTexture,
-                                           mTextureState == Created,
-                                           mUpdateOffset,
-                                           relative);
+        UploadSurfaceToTexture(mGLContext,
+                               mUpdateSurface,
+                               mUpdateRegion,
+                               mTexture,
+                               mTextureState == Created,
+                               mUpdateOffset,
+                               relative);
     FinishedSurfaceUpload();
 
     mUpdateSurface = nullptr;
     mTextureState = Valid;
 }
 
 void
 BasicTextureImage::BindTexture(GLenum aTextureUnit)
@@ -191,22 +238,23 @@ BasicTextureImage::DirectUpdate(gfxASurf
     if (mTextureState != Valid) {
         bounds = nsIntRect(0, 0, mSize.width, mSize.height);
         region = nsIntRegion(bounds);
     } else {
         region = aRegion;
     }
 
     mTextureFormat =
-        mGLContext->UploadSurfaceToTexture(aSurf,
-                                           region,
-                                           mTexture,
-                                           mTextureState == Created,
-                                           bounds.TopLeft() + aFrom,
-                                           false);
+        UploadSurfaceToTexture(mGLContext,
+                               aSurf,
+                               region,
+                               mTexture,
+                               mTextureState == Created,
+                               bounds.TopLeft() + aFrom,
+                               false);
     mTextureState = Valid;
     return true;
 }
 
 void
 BasicTextureImage::Resize(const nsIntSize& aSize)
 {
     NS_ASSERTION(!mUpdateSurface, "Resize() while in update?");
@@ -280,32 +328,50 @@ CreateBasicTextureImage(GLContext* aGL,
                         const gfx::IntSize& aSize,
                         TextureImage::ContentType aContentType,
                         GLenum aWrapMode,
                         TextureImage::Flags aFlags)
 {
   return CreateBasicTextureImage(aGL, ThebesIntSize(aSize), aContentType, aWrapMode, aFlags);
 }
 
+static bool
+WantsSmallTiles(GLContext* gl)
+{
+    // We must use small tiles for good performance if we can't use
+    // glTexSubImage2D() for some reason.
+    if (!CanUploadSubTextures(gl))
+        return true;
+
+    // We can't use small tiles on the SGX 540, because of races in texture upload.
+    if (gl->WorkAroundDriverBugs() &&
+        gl->Renderer() == GLContext::RendererSGX540)
+        return false;
+
+    // Don't use small tiles otherwise. (If we implement incremental texture upload,
+    // then we will want to revisit this.)
+    return false;
+}
+
 TiledTextureImage::TiledTextureImage(GLContext* aGL,
                                      nsIntSize aSize,
                                      TextureImage::ContentType aContentType,
                                      TextureImage::Flags aFlags,
                                      TextureImage::ImageFormat aImageFormat)
     : TextureImage(aSize, LOCAL_GL_CLAMP_TO_EDGE, aContentType, aFlags)
     , mCurrentImage(0)
     , mIterationCallback(nullptr)
     , mInUpdate(false)
     , mRows(0)
     , mColumns(0)
     , mGL(aGL)
     , mTextureState(Created)
     , mImageFormat(aImageFormat)
 {
-    if (!(aFlags & TextureImage::DisallowBigImage) && mGL->WantsSmallTiles()) {
+    if (!(aFlags & TextureImage::DisallowBigImage) && WantsSmallTiles(mGL)) {
       mTileSize = 256;
     } else {
       mGL->fGetIntegerv(LOCAL_GL_MAX_TEXTURE_SIZE, (GLint*) &mTileSize);
     }
     if (aSize.width != 0 && aSize.height != 0) {
         Resize(aSize);
     }
 }
@@ -339,17 +405,17 @@ TiledTextureImage::DirectUpdate(gfxASurf
         int yPos = tileRect.y;
 
         nsIntRegion tileRegion;
         tileRegion.And(region, tileRect); // intersect with tile
 
         if (tileRegion.IsEmpty())
             continue;
 
-        if (mGL->CanUploadSubTextures()) {
+        if (CanUploadSubTextures(mGL)) {
           tileRegion.MoveBy(-xPos, -yPos); // translate into tile local space
         } else {
           // If sub-textures are unsupported, expand to tile boundaries
           tileRect.x = tileRect.y = 0;
           tileRegion = nsIntRegion(tileRect);
         }
 
         result &= mImages[mCurrentImage]->
@@ -640,17 +706,17 @@ void TiledTextureImage::Resize(const nsI
                     // Width hasn't changed, reuse existing tile.
                     i++;
                     continue;
                 }
             }
 
             // Create a new tile.
             nsRefPtr<TextureImage> teximg =
-                    mGL->TileGenFunc(size, mContentType, mFlags, mImageFormat);
+                TileGenFunc(mGL, size, mContentType, mFlags, mImageFormat);
             if (replace)
                 mImages.ReplaceElementAt(i, teximg.forget());
             else
                 mImages.InsertElementAt(i, teximg.forget());
             i++;
         }
 
         // Prune any unused tiles on the end of the column.
--- a/gfx/gl/GLTextureImage.h
+++ b/gfx/gl/GLTextureImage.h
@@ -427,12 +427,36 @@ CreateBasicTextureImage(GLContext* aGL,
 
 already_AddRefed<TextureImage>
 CreateBasicTextureImage(GLContext* aGL,
                         const gfx::IntSize& aSize,
                         TextureImage::ContentType aContentType,
                         GLenum aWrapMode,
                         TextureImage::Flags aFlags);
 
+/**
+  * Return a valid, allocated TextureImage of |aSize| with
+  * |aContentType|.  If |aContentType| is COLOR, |aImageFormat| can be used
+  * to hint at the preferred RGB format, however it is not necessarily
+  * respected.  The TextureImage's texture is configured to use
+  * |aWrapMode| (usually GL_CLAMP_TO_EDGE or GL_REPEAT) and by
+  * default, GL_LINEAR filtering.  Specify
+  * |aFlags=UseNearestFilter| for GL_NEAREST filtering. Specify
+  * |aFlags=NeedsYFlip| if the image is flipped. Return
+  * nullptr if creating the TextureImage fails.
+  *
+  * The returned TextureImage may only be used with this GLContext.
+  * Attempting to use the returned TextureImage after this
+  * GLContext is destroyed will result in undefined (and likely
+  * crashy) behavior.
+  */
+already_AddRefed<TextureImage>
+CreateTextureImage(GLContext* gl,
+                   const nsIntSize& aSize,
+                   TextureImage::ContentType aContentType,
+                   GLenum aWrapMode,
+                   TextureImage::Flags aFlags = TextureImage::NoFlags,
+                   TextureImage::ImageFormat aImageFormat = gfxImageFormatUnknown);
+
 } // namespace gl
 } // namespace mozilla
 
 #endif /* GLTEXTUREIMAGE_H_ */
new file mode 100644
--- /dev/null
+++ b/gfx/gl/GLUploadHelpers.cpp
@@ -0,0 +1,602 @@
+/* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40; -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "GLUploadHelpers.h"
+
+#include "GLContext.h"
+#include "mozilla/gfx/2D.h"
+#include "gfxASurface.h"
+#include "gfxUtils.h"
+#include "gfxContext.h"
+#include "nsRegion.h"
+
+namespace mozilla {
+
+using gfx::SurfaceFormat;
+
+namespace gl {
+
+static unsigned int
+DataOffset(const nsIntPoint &aPoint, int32_t aStride, gfxImageFormat aFormat)
+{
+  unsigned int data = aPoint.y * aStride;
+  data += aPoint.x * gfxASurface::BytePerPixelFromFormat(aFormat);
+  return data;
+}
+
+static gfxImageFormat
+ImageFormatForSurfaceFormat(gfx::SurfaceFormat aFormat)
+{
+    switch (aFormat) {
+        case gfx::FORMAT_B8G8R8A8:
+            return gfxImageFormatARGB32;
+        case gfx::FORMAT_B8G8R8X8:
+            return gfxImageFormatRGB24;
+        case gfx::FORMAT_R5G6B5:
+            return gfxImageFormatRGB16_565;
+        case gfx::FORMAT_A8:
+            return gfxImageFormatA8;
+        default:
+            return gfxImageFormatUnknown;
+    }
+}
+
+static GLint GetAddressAlignment(ptrdiff_t aAddress)
+{
+    if (!(aAddress & 0x7)) {
+       return 8;
+    } else if (!(aAddress & 0x3)) {
+        return 4;
+    } else if (!(aAddress & 0x1)) {
+        return 2;
+    } else {
+        return 1;
+    }
+}
+
+// Take texture data in a given buffer and copy it into a larger buffer,
+// padding out the edge pixels for filtering if necessary
+static void
+CopyAndPadTextureData(const GLvoid* srcBuffer,
+                      GLvoid* dstBuffer,
+                      GLsizei srcWidth, GLsizei srcHeight,
+                      GLsizei dstWidth, GLsizei dstHeight,
+                      GLsizei stride, GLint pixelsize)
+{
+    unsigned char *rowDest = static_cast<unsigned char*>(dstBuffer);
+    const unsigned char *source = static_cast<const unsigned char*>(srcBuffer);
+
+    for (GLsizei h = 0; h < srcHeight; ++h) {
+        memcpy(rowDest, source, srcWidth * pixelsize);
+        rowDest += dstWidth * pixelsize;
+        source += stride;
+    }
+
+    GLsizei padHeight = srcHeight;
+
+    // Pad out an extra row of pixels so that edge filtering doesn't use garbage data
+    if (dstHeight > srcHeight) {
+        memcpy(rowDest, source - stride, srcWidth * pixelsize);
+        padHeight++;
+    }
+
+    // Pad out an extra column of pixels
+    if (dstWidth > srcWidth) {
+        rowDest = static_cast<unsigned char*>(dstBuffer) + srcWidth * pixelsize;
+        for (GLsizei h = 0; h < padHeight; ++h) {
+            memcpy(rowDest, rowDest - pixelsize, pixelsize);
+            rowDest += dstWidth * pixelsize;
+        }
+    }
+}
+
+// In both of these cases (for the Adreno at least) it is impossible
+// to determine good or bad driver versions for POT texture uploads,
+// so blacklist them all. Newer drivers use a different rendering
+// string in the form "Adreno (TM) 200" and the drivers we've seen so
+// far work fine with NPOT textures, so don't blacklist those until we
+// have evidence of any problems with them.
+bool
+CanUploadSubTextures(GLContext* gl)
+{
+    if (!gl->WorkAroundDriverBugs())
+        return true;
+
+    // There are certain GPUs that we don't want to use glTexSubImage2D on
+    // because that function can be very slow and/or buggy
+    if (gl->Renderer() == GLContext::RendererAdreno200 ||
+        gl->Renderer() == GLContext::RendererAdreno205)
+    {
+        return false;
+    }
+
+    // On PowerVR glTexSubImage does a readback, so it will be slower
+    // than just doing a glTexImage2D() directly. i.e. 26ms vs 10ms
+    if (gl->Renderer() == GLContext::RendererSGX540 ||
+        gl->Renderer() == GLContext::RendererSGX530)
+    {
+        return false;
+    }
+
+    return true;
+}
+
+static void
+TexSubImage2DWithUnpackSubimageGLES(GLContext* gl,
+                                    GLenum target, GLint level,
+                                    GLint xoffset, GLint yoffset,
+                                    GLsizei width, GLsizei height,
+                                    GLsizei stride, GLint pixelsize,
+                                    GLenum format, GLenum type,
+                                    const GLvoid* pixels)
+{
+    gl->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT,
+                     std::min(GetAddressAlignment((ptrdiff_t)pixels),
+                              GetAddressAlignment((ptrdiff_t)stride)));
+    // When using GL_UNPACK_ROW_LENGTH, we need to work around a Tegra
+    // driver crash where the driver apparently tries to read
+    // (stride - width * pixelsize) bytes past the end of the last input
+    // row. We only upload the first height-1 rows using GL_UNPACK_ROW_LENGTH,
+    // and then we upload the final row separately. See bug 697990.
+    int rowLength = stride/pixelsize;
+    gl->fPixelStorei(LOCAL_GL_UNPACK_ROW_LENGTH, rowLength);
+    gl->fTexSubImage2D(target,
+                       level,
+                       xoffset,
+                       yoffset,
+                       width,
+                       height-1,
+                       format,
+                       type,
+                       pixels);
+    gl->fPixelStorei(LOCAL_GL_UNPACK_ROW_LENGTH, 0);
+    gl->fTexSubImage2D(target,
+                       level,
+                       xoffset,
+                       yoffset+height-1,
+                       width,
+                       1,
+                       format,
+                       type,
+                       (const unsigned char *)pixels+(height-1)*stride);
+    gl->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, 4);
+}
+
+static void
+TexSubImage2DWithoutUnpackSubimage(GLContext* gl,
+                                   GLenum target, GLint level,
+                                   GLint xoffset, GLint yoffset,
+                                   GLsizei width, GLsizei height,
+                                   GLsizei stride, GLint pixelsize,
+                                   GLenum format, GLenum type,
+                                   const GLvoid* pixels)
+{
+    // Not using the whole row of texture data and GL_UNPACK_ROW_LENGTH
+    // isn't supported. We make a copy of the texture data we're using,
+    // such that we're using the whole row of data in the copy. This turns
+    // out to be more efficient than uploading row-by-row; see bug 698197.
+    unsigned char *newPixels = new unsigned char[width*height*pixelsize];
+    unsigned char *rowDest = newPixels;
+    const unsigned char *rowSource = (const unsigned char *)pixels;
+    for (int h = 0; h < height; h++) {
+            memcpy(rowDest, rowSource, width*pixelsize);
+            rowDest += width*pixelsize;
+            rowSource += stride;
+    }
+
+    stride = width*pixelsize;
+    gl->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT,
+                     std::min(GetAddressAlignment((ptrdiff_t)newPixels),
+                              GetAddressAlignment((ptrdiff_t)stride)));
+    gl->fTexSubImage2D(target,
+                       level,
+                       xoffset,
+                       yoffset,
+                       width,
+                       height,
+                       format,
+                       type,
+                       newPixels);
+    delete [] newPixels;
+    gl->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, 4);
+}
+
+static void
+TexSubImage2DHelper(GLContext *gl,
+                    GLenum target, GLint level,
+                    GLint xoffset, GLint yoffset,
+                    GLsizei width, GLsizei height, GLsizei stride,
+                    GLint pixelsize, GLenum format,
+                    GLenum type, const GLvoid* pixels)
+{
+    if (gl->IsGLES2()) {
+        if (stride == width * pixelsize) {
+            gl->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT,
+                             std::min(GetAddressAlignment((ptrdiff_t)pixels),
+                                      GetAddressAlignment((ptrdiff_t)stride)));
+            gl->fTexSubImage2D(target,
+                               level,
+                               xoffset,
+                               yoffset,
+                               width,
+                               height,
+                               format,
+                               type,
+                               pixels);
+            gl->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, 4);
+        } else if (gl->IsExtensionSupported(GLContext::EXT_unpack_subimage)) {
+            TexSubImage2DWithUnpackSubimageGLES(gl, target, level, xoffset, yoffset,
+                                                width, height, stride,
+                                                pixelsize, format, type, pixels);
+
+        } else {
+            TexSubImage2DWithoutUnpackSubimage(gl, target, level, xoffset, yoffset,
+                                              width, height, stride,
+                                              pixelsize, format, type, pixels);
+        }
+    } else {
+        // desktop GL (non-ES) path
+        gl->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT,
+                         std::min(GetAddressAlignment((ptrdiff_t)pixels),
+                                  GetAddressAlignment((ptrdiff_t)stride)));
+        int rowLength = stride/pixelsize;
+        gl->fPixelStorei(LOCAL_GL_UNPACK_ROW_LENGTH, rowLength);
+        gl->fTexSubImage2D(target,
+                           level,
+                           xoffset,
+                           yoffset,
+                           width,
+                           height,
+                           format,
+                           type,
+                           pixels);
+        gl->fPixelStorei(LOCAL_GL_UNPACK_ROW_LENGTH, 0);
+        gl->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, 4);
+    }
+}
+
+static void
+TexImage2DHelper(GLContext *gl,
+                 GLenum target, GLint level, GLint internalformat,
+                 GLsizei width, GLsizei height, GLsizei stride,
+                 GLint pixelsize, GLint border, GLenum format,
+                 GLenum type, const GLvoid *pixels)
+{
+    if (gl->IsGLES2()) {
+
+        NS_ASSERTION(format == (GLenum)internalformat,
+                    "format and internalformat not the same for glTexImage2D on GLES2");
+
+        if (!CanUploadNonPowerOfTwo(gl)
+            && (stride != width * pixelsize
+            || !gfx::IsPowerOfTwo(width)
+            || !gfx::IsPowerOfTwo(height))) {
+
+            // Pad out texture width and height to the next power of two
+            // as we don't support/want non power of two texture uploads
+            GLsizei paddedWidth = gfx::NextPowerOfTwo(width);
+            GLsizei paddedHeight = gfx::NextPowerOfTwo(height);
+
+            GLvoid* paddedPixels = new unsigned char[paddedWidth * paddedHeight * pixelsize];
+
+            // Pad out texture data to be in a POT sized buffer for uploading to
+            // a POT sized texture
+            CopyAndPadTextureData(pixels, paddedPixels, width, height,
+                                  paddedWidth, paddedHeight, stride, pixelsize);
+
+            gl->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT,
+                             std::min(GetAddressAlignment((ptrdiff_t)paddedPixels),
+                                      GetAddressAlignment((ptrdiff_t)paddedWidth * pixelsize)));
+            gl->fTexImage2D(target,
+                            border,
+                            internalformat,
+                            paddedWidth,
+                            paddedHeight,
+                            border,
+                            format,
+                            type,
+                            paddedPixels);
+            gl->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, 4);
+
+            delete[] static_cast<unsigned char*>(paddedPixels);
+            return;
+        }
+
+        if (stride == width * pixelsize) {
+            gl->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT,
+                             std::min(GetAddressAlignment((ptrdiff_t)pixels),
+                                      GetAddressAlignment((ptrdiff_t)stride)));
+            gl->fTexImage2D(target,
+                            border,
+                            internalformat,
+                            width,
+                            height,
+                            border,
+                            format,
+                            type,
+                            pixels);
+            gl->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, 4);
+        } else {
+            // Use GLES-specific workarounds for GL_UNPACK_ROW_LENGTH; these are
+            // implemented in TexSubImage2D.
+            gl->fTexImage2D(target,
+                            border,
+                            internalformat,
+                            width,
+                            height,
+                            border,
+                            format,
+                            type,
+                            nullptr);
+            TexSubImage2DHelper(gl,
+                                target,
+                                level,
+                                0,
+                                0,
+                                width,
+                                height,
+                                stride,
+                                pixelsize,
+                                format,
+                                type,
+                                pixels);
+        }
+    } else {
+        // desktop GL (non-ES) path
+
+        gl->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT,
+                         std::min(GetAddressAlignment((ptrdiff_t)pixels),
+                                  GetAddressAlignment((ptrdiff_t)stride)));
+        int rowLength = stride/pixelsize;
+        gl->fPixelStorei(LOCAL_GL_UNPACK_ROW_LENGTH, rowLength);
+        gl->fTexImage2D(target,
+                        level,
+                        internalformat,
+                        width,
+                        height,
+                        border,
+                        format,
+                        type,
+                        pixels);
+        gl->fPixelStorei(LOCAL_GL_UNPACK_ROW_LENGTH, 0);
+        gl->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, 4);
+    }
+}
+
+SurfaceFormat
+UploadImageDataToTexture(GLContext* gl,
+                         unsigned char* aData,
+                         int32_t aStride,
+                         gfxImageFormat aFormat,
+                         const nsIntRegion& aDstRegion,
+                         GLuint& aTexture,
+                         bool aOverwrite,
+                         bool aPixelBuffer,
+                         GLenum aTextureUnit,
+                         GLenum aTextureTarget)
+{
+    bool textureInited = aOverwrite ? false : true;
+    gl->MakeCurrent();
+    gl->fActiveTexture(aTextureUnit);
+
+    if (!aTexture) {
+        gl->fGenTextures(1, &aTexture);
+        gl->fBindTexture(aTextureTarget, aTexture);
+        gl->fTexParameteri(aTextureTarget,
+                           LOCAL_GL_TEXTURE_MIN_FILTER,
+                           LOCAL_GL_LINEAR);
+        gl->fTexParameteri(aTextureTarget,
+                           LOCAL_GL_TEXTURE_MAG_FILTER,
+                           LOCAL_GL_LINEAR);
+        gl->fTexParameteri(aTextureTarget,
+                           LOCAL_GL_TEXTURE_WRAP_S,
+                           LOCAL_GL_CLAMP_TO_EDGE);
+        gl->fTexParameteri(aTextureTarget,
+                           LOCAL_GL_TEXTURE_WRAP_T,
+                           LOCAL_GL_CLAMP_TO_EDGE);
+        textureInited = false;
+    } else {
+        gl->fBindTexture(aTextureTarget, aTexture);
+    }
+
+    nsIntRegion paintRegion;
+    if (!textureInited) {
+        paintRegion = nsIntRegion(aDstRegion.GetBounds());
+    } else {
+        paintRegion = aDstRegion;
+    }
+
+    GLenum format;
+    GLenum internalFormat;
+    GLenum type;
+    int32_t pixelSize = gfxASurface::BytePerPixelFromFormat(aFormat);
+    SurfaceFormat surfaceFormat;
+
+    MOZ_ASSERT(gl->GetPreferredARGB32Format() == LOCAL_GL_BGRA ||
+               gl->GetPreferredARGB32Format() == LOCAL_GL_RGBA);
+    switch (aFormat) {
+        case gfxImageFormatARGB32:
+            if (gl->GetPreferredARGB32Format() == LOCAL_GL_BGRA) {
+              format = LOCAL_GL_BGRA;
+              surfaceFormat = gfx::FORMAT_R8G8B8A8;
+              type = LOCAL_GL_UNSIGNED_INT_8_8_8_8_REV;
+            } else {
+              format = LOCAL_GL_RGBA;
+              surfaceFormat = gfx::FORMAT_B8G8R8A8;
+              type = LOCAL_GL_UNSIGNED_BYTE;
+            }
+            internalFormat = LOCAL_GL_RGBA;
+            break;
+        case gfxImageFormatRGB24:
+            // Treat RGB24 surfaces as RGBA32 except for the surface
+            // format used.
+            if (gl->GetPreferredARGB32Format() == LOCAL_GL_BGRA) {
+              format = LOCAL_GL_BGRA;
+              surfaceFormat = gfx::FORMAT_R8G8B8X8;
+              type = LOCAL_GL_UNSIGNED_INT_8_8_8_8_REV;
+            } else {
+              format = LOCAL_GL_RGBA;
+              surfaceFormat = gfx::FORMAT_B8G8R8X8;
+              type = LOCAL_GL_UNSIGNED_BYTE;
+            }
+            internalFormat = LOCAL_GL_RGBA;
+            break;
+        case gfxImageFormatRGB16_565:
+            internalFormat = format = LOCAL_GL_RGB;
+            type = LOCAL_GL_UNSIGNED_SHORT_5_6_5;
+            surfaceFormat = gfx::FORMAT_R5G6B5;
+            break;
+        case gfxImageFormatA8:
+            internalFormat = format = LOCAL_GL_LUMINANCE;
+            type = LOCAL_GL_UNSIGNED_BYTE;
+            // We don't have a specific luminance shader
+            surfaceFormat = gfx::FORMAT_A8;
+            break;
+        default:
+            NS_ASSERTION(false, "Unhandled image surface format!");
+            format = 0;
+            type = 0;
+            surfaceFormat = gfx::FORMAT_UNKNOWN;
+    }
+
+    nsIntRegionRectIterator iter(paintRegion);
+    const nsIntRect *iterRect;
+
+    // Top left point of the region's bounding rectangle.
+    nsIntPoint topLeft = paintRegion.GetBounds().TopLeft();
+
+    while ((iterRect = iter.Next())) {
+        // The inital data pointer is at the top left point of the region's
+        // bounding rectangle. We need to find the offset of this rect
+        // within the region and adjust the data pointer accordingly.
+        unsigned char *rectData =
+            aData + DataOffset(iterRect->TopLeft() - topLeft, aStride, aFormat);
+
+        NS_ASSERTION(textureInited || (iterRect->x == 0 && iterRect->y == 0),
+                     "Must be uploading to the origin when we don't have an existing texture");
+
+        if (textureInited && CanUploadSubTextures(gl)) {
+            TexSubImage2DHelper(gl,
+                                aTextureTarget,
+                                0,
+                                iterRect->x,
+                                iterRect->y,
+                                iterRect->width,
+                                iterRect->height,
+                                aStride,
+                                pixelSize,
+                                format,
+                                type,
+                                rectData);
+        } else {
+            TexImage2DHelper(gl,
+                             aTextureTarget,
+                             0,
+                             internalFormat,
+                             iterRect->width,
+                             iterRect->height,
+                             aStride,
+                             pixelSize,
+                             0,
+                             format,
+                             type,
+                             rectData);
+        }
+
+    }
+
+    return surfaceFormat;
+}
+
+SurfaceFormat
+UploadSurfaceToTexture(GLContext* gl,
+                       gfxASurface *aSurface,
+                       const nsIntRegion& aDstRegion,
+                       GLuint& aTexture,
+                       bool aOverwrite,
+                       const nsIntPoint& aSrcPoint,
+                       bool aPixelBuffer,
+                       GLenum aTextureUnit,
+                       GLenum aTextureTarget)
+{
+
+    nsRefPtr<gfxImageSurface> imageSurface = aSurface->GetAsImageSurface();
+    unsigned char* data = nullptr;
+
+    if (!imageSurface ||
+        (imageSurface->Format() != gfxImageFormatARGB32 &&
+         imageSurface->Format() != gfxImageFormatRGB24 &&
+         imageSurface->Format() != gfxImageFormatRGB16_565 &&
+         imageSurface->Format() != gfxImageFormatA8)) {
+        // We can't get suitable pixel data for the surface, make a copy
+        nsIntRect bounds = aDstRegion.GetBounds();
+        imageSurface =
+          new gfxImageSurface(gfxIntSize(bounds.width, bounds.height),
+                              gfxImageFormatARGB32);
+
+        nsRefPtr<gfxContext> context = new gfxContext(imageSurface);
+
+        context->Translate(-gfxPoint(aSrcPoint.x, aSrcPoint.y));
+        context->SetSource(aSurface);
+        context->Paint();
+        data = imageSurface->Data();
+        NS_ASSERTION(!aPixelBuffer,
+                     "Must be using an image compatible surface with pixel buffers!");
+    } else {
+        // If a pixel buffer is bound the data pointer parameter is relative
+        // to the start of the data block.
+        if (!aPixelBuffer) {
+              data = imageSurface->Data();
+        }
+        data += DataOffset(aSrcPoint, imageSurface->Stride(),
+                           imageSurface->Format());
+    }
+
+    MOZ_ASSERT(imageSurface);
+    imageSurface->Flush();
+
+    return UploadImageDataToTexture(gl,
+                                    data,
+                                    imageSurface->Stride(),
+                                    imageSurface->Format(),
+                                    aDstRegion, aTexture, aOverwrite,
+                                    aPixelBuffer, aTextureUnit, aTextureTarget);
+}
+
+SurfaceFormat
+UploadSurfaceToTexture(GLContext* gl,
+                       gfx::DataSourceSurface *aSurface,
+                       const nsIntRegion& aDstRegion,
+                       GLuint& aTexture,
+                       bool aOverwrite,
+                       const nsIntPoint& aSrcPoint,
+                       bool aPixelBuffer,
+                       GLenum aTextureUnit,
+                       GLenum aTextureTarget)
+{
+    unsigned char* data = aPixelBuffer ? nullptr : aSurface->GetData();
+    int32_t stride = aSurface->Stride();
+    gfxImageFormat format =
+        ImageFormatForSurfaceFormat(aSurface->GetFormat());
+    data += DataOffset(aSrcPoint, stride, format);
+    return UploadImageDataToTexture(gl, data, stride, format,
+                                    aDstRegion, aTexture, aOverwrite,
+                                    aPixelBuffer, aTextureUnit,
+                                    aTextureTarget);
+}
+
+bool
+CanUploadNonPowerOfTwo(GLContext* gl)
+{
+    if (!gl->WorkAroundDriverBugs())
+        return true;
+
+    // Some GPUs driver crash when uploading non power of two 565 textures.
+    return gl->Renderer() != GLContext::RendererAdreno200 &&
+           gl->Renderer() != GLContext::RendererAdreno205;
+}
+
+}
+}
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/gfx/gl/GLUploadHelpers.h
@@ -0,0 +1,104 @@
+/* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40; -*- */
+/* 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 GLUploadHelpers_h_
+#define GLUploadHelpers_h_
+
+#include "GLDefs.h"
+#include "gfxTypes.h"
+#include "mozilla/gfx/Types.h"
+#include "nsPoint.h"
+
+class gfxASurface;
+class nsIntRegion;
+
+namespace mozilla {
+
+namespace gfx {
+class DataSourceSurface;
+}
+
+namespace gl {
+
+class GLContext;
+
+/**
+  * Creates a RGB/RGBA texture (or uses one provided) and uploads the surface
+  * contents to it within aSrcRect.
+  *
+  * aSrcRect.x/y will be uploaded to 0/0 in the texture, and the size
+  * of the texture with be aSrcRect.width/height.
+  *
+  * If an existing texture is passed through aTexture, it is assumed it
+  * has already been initialised with glTexImage2D (or this function),
+  * and that its size is equal to or greater than aSrcRect + aDstPoint.
+  * You can alternatively set the overwrite flag to true and have a new
+  * texture memory block allocated.
+  *
+  * The aDstPoint parameter is ignored if no texture was provided
+  * or aOverwrite is true.
+  *
+  * \param aData Image data to upload.
+  * \param aDstRegion Region of texture to upload to.
+  * \param aTexture Texture to use, or 0 to have one created for you.
+  * \param aOverwrite Over an existing texture with a new one.
+  * \param aSrcPoint Offset into aSrc where the region's bound's
+  *  TopLeft() sits.
+  * \param aPixelBuffer Pass true to upload texture data with an
+  *  offset from the base data (generally for pixel buffer objects),
+  *  otherwise textures are upload with an absolute pointer to the data.
+  * \param aTextureUnit, the texture unit used temporarily to upload the
+  *  surface. This testure may be overridden, clients should not rely on
+  *  the contents of this texture after this call or even on this
+  *  texture unit being active.
+  * \return Surface format of this texture.
+  */
+gfx::SurfaceFormat
+UploadImageDataToTexture(GLContext* gl,
+                         unsigned char* aData,
+                         int32_t aStride,
+                         gfxImageFormat aFormat,
+                         const nsIntRegion& aDstRegion,
+                         GLuint& aTexture,
+                         bool aOverwrite = false,
+                         bool aPixelBuffer = false,
+                         GLenum aTextureUnit = LOCAL_GL_TEXTURE0,
+                         GLenum aTextureTarget = LOCAL_GL_TEXTURE_2D);
+
+/**
+  * Convenience wrapper around UploadImageDataToTexture for gfxASurfaces.
+  */
+gfx::SurfaceFormat
+UploadSurfaceToTexture(GLContext* gl,
+                       gfxASurface *aSurface,
+                       const nsIntRegion& aDstRegion,
+                       GLuint& aTexture,
+                       bool aOverwrite = false,
+                       const nsIntPoint& aSrcPoint = nsIntPoint(0, 0),
+                       bool aPixelBuffer = false,
+                       GLenum aTextureUnit = LOCAL_GL_TEXTURE0,
+                       GLenum aTextureTarget = LOCAL_GL_TEXTURE_2D);
+
+/**
+  * Convenience wrapper around UploadImageDataToTexture for gfx::DataSourceSurface's.
+  */
+gfx::SurfaceFormat
+UploadSurfaceToTexture(GLContext* gl,
+                       gfx::DataSourceSurface *aSurface,
+                       const nsIntRegion& aDstRegion,
+                       GLuint& aTexture,
+                       bool aOverwrite,
+                       const nsIntPoint& aSrcPoint,
+                       bool aPixelBuffer,
+                       GLenum aTextureUnit,
+                       GLenum aTextureTarget);
+
+bool CanUploadSubTextures(GLContext* gl);
+bool CanUploadNonPowerOfTwo(GLContext* gl);
+
+}
+}
+
+#endif
--- a/gfx/gl/GLXLibrary.h
+++ b/gfx/gl/GLXLibrary.h
@@ -18,16 +18,17 @@ typedef XID GLXDrawable;
 typedef struct __GLXFBConfigRec *GLXFBConfig;
 typedef XID GLXFBConfigID;
 typedef XID GLXContextID;
 typedef XID GLXWindow;
 typedef XID GLXPbuffer;
 // end of stuff from glx.h
 
 struct PRLibrary;
+class gfxASurface;
 
 namespace mozilla {
 namespace gl {
 
 class GLXLibrary
 {
 public:
     GLXLibrary() : mInitialized(false), mTriedInitializing(false),
new file mode 100644
--- /dev/null
+++ b/gfx/gl/SurfaceTypes.cpp
@@ -0,0 +1,59 @@
+/* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40; -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "SurfaceTypes.h"
+#include "mozilla/layers/ISurfaceAllocator.h"
+
+namespace mozilla {
+namespace gfx {
+
+SurfaceCaps::SurfaceCaps()
+{
+  Clear();
+}
+
+SurfaceCaps::SurfaceCaps(const SurfaceCaps& other)
+{
+  *this = other;
+}
+
+SurfaceCaps&
+SurfaceCaps::operator=(const SurfaceCaps& other)
+{
+  any = other.any;
+  color = other.color;
+  alpha = other.alpha;
+  bpp16 = other.bpp16;
+  depth = other.depth;
+  stencil = other.stencil;
+  antialias = other.antialias;
+  preserve = other.preserve;
+  surfaceAllocator = other.surfaceAllocator;
+
+  return *this;
+}
+
+void
+SurfaceCaps::Clear()
+{
+  any = false;
+  color = false;
+  alpha = false;
+  bpp16 = false;
+  depth = false;
+  stencil = false;
+  antialias = false;
+  preserve = false;
+  surfaceAllocator = nullptr;
+}
+
+
+
+SurfaceCaps::~SurfaceCaps()
+{
+}
+
+}
+}
--- a/gfx/gl/SurfaceTypes.h
+++ b/gfx/gl/SurfaceTypes.h
@@ -2,49 +2,49 @@
 /* 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 SURFACE_TYPES_H_
 #define SURFACE_TYPES_H_
 
 #include "mozilla/TypedEnum.h"
+#include "mozilla/RefPtr.h"
+#include "mozilla/Attributes.h"
 #include <stdint.h>
 
-#include <cstring>
-
 namespace mozilla {
 namespace layers {
 class ISurfaceAllocator;
 }
 
 namespace gfx {
 
 typedef uintptr_t SurfaceStreamHandle;
 
-struct SurfaceCaps
+struct SurfaceCaps MOZ_FINAL
 {
     bool any;
     bool color, alpha;
     bool bpp16;
     bool depth, stencil;
     bool antialias;
     bool preserve;
 
     // The surface allocator that we want to create this
     // for.  May be null.
-    layers::ISurfaceAllocator* surfaceAllocator;
+    RefPtr<layers::ISurfaceAllocator> surfaceAllocator;
 
-    SurfaceCaps() {
-        Clear();
-    }
+    SurfaceCaps();
+    SurfaceCaps(const SurfaceCaps& other);
+    ~SurfaceCaps();
 
-    void Clear() {
-        std::memset(this, 0, sizeof(SurfaceCaps));
-    }
+    void Clear();
+
+    SurfaceCaps& operator=(const SurfaceCaps& other);
 
     // We can't use just 'RGB' here, since it's an ancient Windows macro.
     static SurfaceCaps ForRGB() {
         SurfaceCaps caps;
 
         caps.color = true;
 
         return caps;
new file mode 100644
--- /dev/null
+++ b/gfx/gl/TextureImageCGL.h
@@ -0,0 +1,66 @@
+/* -*- 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 TextureImageCGL_h_
+#define TextureImageCGL_h_
+
+#include "GLTextureImage.h"
+#include "GLContextTypes.h"
+#include "nsAutoPtr.h"
+#include "nsSize.h"
+
+class gfxASurface;
+
+namespace mozilla {
+namespace gl {
+
+class TextureImageCGL : public BasicTextureImage
+{
+public:
+
+    TextureImageCGL(GLuint aTexture,
+                    const nsIntSize& aSize,
+                    GLenum aWrapMode,
+                    ContentType aContentType,
+                    GLContext* aContext,
+                    TextureImage::Flags aFlags = TextureImage::NoFlags,
+                    TextureImage::ImageFormat aImageFormat = gfxImageFormatUnknown);
+
+    ~TextureImageCGL();
+
+protected:
+    already_AddRefed<gfxASurface>
+    GetSurfaceForUpdate(const gfxIntSize& aSize, ImageFormat aFmt);
+
+    bool FinishedSurfaceUpdate();
+
+    void FinishedSurfaceUpload();
+
+private:
+
+    GLuint mPixelBuffer;
+    int32_t mPixelBufferSize;
+    bool mBoundPixelBuffer;
+};
+
+already_AddRefed<TextureImage>
+CreateTextureImageCGL(GLContext *gl,
+                      const nsIntSize& aSize,
+                      TextureImage::ContentType aContentType,
+                      GLenum aWrapMode,
+                      TextureImage::Flags aFlags,
+                      TextureImage::ImageFormat aImageFormat);
+
+already_AddRefed<TextureImage>
+TileGenFuncCGL(GLContext *gl,
+               const nsIntSize& aSize,
+               TextureImage::ContentType aContentType,
+               TextureImage::Flags aFlags,
+               TextureImage::ImageFormat aImageFormat);
+
+}
+}
+
+#endif
new file mode 100644
--- /dev/null
+++ b/gfx/gl/TextureImageCGL.mm
@@ -0,0 +1,158 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "TextureImageCGL.h"
+#include "GLContext.h"
+#include "gfxQuartzSurface.h"
+#include "gfxPlatform.h"
+#include "gfxFailure.h"
+
+namespace mozilla {
+namespace gl {
+
+TextureImageCGL::TextureImageCGL(GLuint aTexture,
+                const nsIntSize& aSize,
+                GLenum aWrapMode,
+                ContentType aContentType,
+                GLContext* aContext,
+                TextureImage::Flags aFlags,
+                TextureImage::ImageFormat aImageFormat)
+    : BasicTextureImage(aTexture, aSize, aWrapMode, aContentType,
+                        aContext, aFlags, aImageFormat)
+    , mPixelBuffer(0)
+    , mPixelBufferSize(0)
+    , mBoundPixelBuffer(false)
+{}
+
+TextureImageCGL::~TextureImageCGL()
+{
+    if (mPixelBuffer) {
+        mGLContext->MakeCurrent();
+        mGLContext->fDeleteBuffers(1, &mPixelBuffer);
+    }
+}
+
+already_AddRefed<gfxASurface>
+TextureImageCGL::GetSurfaceForUpdate(const gfxIntSize& aSize, ImageFormat aFmt)
+{
+    gfxIntSize size(aSize.width + 1, aSize.height + 1);
+    mGLContext->MakeCurrent();
+    if (!mGLContext->
+        IsExtensionSupported(GLContext::ARB_pixel_buffer_object))
+    {
+        return gfxPlatform::GetPlatform()->
+            CreateOffscreenSurface(size,
+                                    gfxASurface::ContentFromFormat(aFmt));
+    }
+
+    if (!mPixelBuffer) {
+        mGLContext->fGenBuffers(1, &mPixelBuffer);
+    }
+    mGLContext->fBindBuffer(LOCAL_GL_PIXEL_UNPACK_BUFFER, mPixelBuffer);
+    int32_t length = size.width * 4 * size.height;
+
+    if (length > mPixelBufferSize) {
+        mGLContext->fBufferData(LOCAL_GL_PIXEL_UNPACK_BUFFER, length,
+                                NULL, LOCAL_GL_STREAM_DRAW);
+        mPixelBufferSize = length;
+    }
+    unsigned char* data =
+        (unsigned char*)mGLContext->
+            fMapBuffer(LOCAL_GL_PIXEL_UNPACK_BUFFER,
+                        LOCAL_GL_WRITE_ONLY);
+
+    mGLContext->fBindBuffer(LOCAL_GL_PIXEL_UNPACK_BUFFER, 0);
+
+    if (!data) {
+        nsAutoCString failure;
+        failure += "Pixel buffer binding failed: ";
+        failure.AppendPrintf("%dx%d\n", size.width, size.height);
+        gfx::LogFailure(failure);
+
+        mGLContext->fBindBuffer(LOCAL_GL_PIXEL_UNPACK_BUFFER, 0);
+        return gfxPlatform::GetPlatform()->
+            CreateOffscreenSurface(size,
+                                    gfxASurface::ContentFromFormat(aFmt));
+    }
+
+    nsRefPtr<gfxQuartzSurface> surf =
+        new gfxQuartzSurface(data, size, size.width * 4, aFmt);
+
+    mBoundPixelBuffer = true;
+    return surf.forget();
+}
+
+bool
+TextureImageCGL::FinishedSurfaceUpdate()
+{
+    if (mBoundPixelBuffer) {
+        mGLContext->MakeCurrent();
+        mGLContext->fBindBuffer(LOCAL_GL_PIXEL_UNPACK_BUFFER, mPixelBuffer);
+        mGLContext->fUnmapBuffer(LOCAL_GL_PIXEL_UNPACK_BUFFER);
+        return true;
+    }
+    return false;
+}
+
+void
+TextureImageCGL::FinishedSurfaceUpload()
+{
+    if (mBoundPixelBuffer) {
+        mGLContext->MakeCurrent();
+        mGLContext->fBindBuffer(LOCAL_GL_PIXEL_UNPACK_BUFFER, 0);
+        mBoundPixelBuffer = false;
+    }
+}
+
+already_AddRefed<TextureImage>
+CreateTextureImageCGL(GLContext* gl,
+                      const nsIntSize& aSize,
+                      TextureImage::ContentType aContentType,
+                      GLenum aWrapMode,
+                      TextureImage::Flags aFlags,
+                      TextureImage::ImageFormat aImageFormat)
+{
+    if (!gl->IsOffscreenSizeAllowed(gfxIntSize(aSize.width, aSize.height)) &&
+        gfxPlatform::OffMainThreadCompositingEnabled()) {
+      NS_ASSERTION(aWrapMode == LOCAL_GL_CLAMP_TO_EDGE, "Can't support wrapping with tiles!");
+      nsRefPtr<TextureImage> t = new gl::TiledTextureImage(gl, aSize, aContentType,
+                                                           aFlags, aImageFormat);
+      return t.forget();
+    }
+
+    return CreateBasicTextureImage(gl, aSize, aContentType, aWrapMode,
+                                   aFlags, aImageFormat);
+}
+
+already_AddRefed<TextureImage>
+TileGenFuncCGL(GLContext *gl,
+               const nsIntSize& aSize,
+               TextureImage::ContentType aContentType,
+               TextureImage::Flags aFlags,
+               TextureImage::ImageFormat aImageFormat)
+{
+    bool useNearestFilter = aFlags & TextureImage::UseNearestFilter;
+    gl->MakeCurrent();
+
+    GLuint texture;
+    gl->fGenTextures(1, &texture);
+
+    gl->fActiveTexture(LOCAL_GL_TEXTURE0);
+    gl->fBindTexture(LOCAL_GL_TEXTURE_2D, texture);
+
+    GLint texfilter = useNearestFilter ? LOCAL_GL_NEAREST : LOCAL_GL_LINEAR;
+    gl->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MIN_FILTER, texfilter);
+    gl->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MAG_FILTER, texfilter);
+    gl->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_S, LOCAL_GL_CLAMP_TO_EDGE);
+    gl->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_T, LOCAL_GL_CLAMP_TO_EDGE);
+
+    nsRefPtr<TextureImageCGL> teximage
+        (new TextureImageCGL(texture, aSize, LOCAL_GL_CLAMP_TO_EDGE, aContentType,
+                             gl, aFlags, aImageFormat));
+    return teximage.forget();
+}
+
+}
+}
--- a/gfx/gl/TextureImageEGL.cpp
+++ b/gfx/gl/TextureImageEGL.cpp
@@ -1,16 +1,17 @@
 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "TextureImageEGL.h"
 #include "GLLibraryEGL.h"
 #include "GLContext.h"
+#include "GLUploadHelpers.h"
 #include "gfxPlatform.h"
 #include "mozilla/gfx/Types.h"
 
 namespace mozilla {
 namespace gl {
 
 static GLenum
 GLFormatForImage(gfxImageFormat aFormat)
@@ -210,22 +211,23 @@ TextureImageEGL::DirectUpdate(gfxASurfac
     if (mTextureState != Valid) {
         bounds = nsIntRect(0, 0, mSize.width, mSize.height);
         region = nsIntRegion(bounds);
     } else {
         region = aRegion;
     }
 
     mTextureFormat =
-      mGLContext->UploadSurfaceToTexture(aSurf,
-                                          region,
-                                          mTexture,
-                                          mTextureState == Created,
-                                          bounds.TopLeft() + aFrom,
-                                          false);
+      UploadSurfaceToTexture(mGLContext,
+                             aSurf,
+                             region,
+                             mTexture,
+                             mTextureState == Created,
+                             bounds.TopLeft() + aFrom,
+                             false);
 
     mTextureState = Valid;
     return true;
 }
 
 void
 TextureImageEGL::BindTexture(GLenum aTextureUnit)
 {
@@ -310,10 +312,49 @@ TextureImageEGL::DestroyEGLSurface(void)
 }
 
 void
 TextureImageEGL::ApplyFilter()
 {
     mGLContext->ApplyFilterToBoundTexture(mFilter);
 }
 
+already_AddRefed<TextureImage>
+CreateTextureImageEGL(GLContext *gl,
+                      const nsIntSize& aSize,
+                      TextureImage::ContentType aContentType,
+                      GLenum aWrapMode,
+                      TextureImage::Flags aFlags,
+                      TextureImage::ImageFormat aImageFormat)
+{
+    nsRefPtr<TextureImage> t = new gl::TiledTextureImage(gl, aSize, aContentType, aFlags, aImageFormat);
+    return t.forget();
+}
+
+already_AddRefed<TextureImage>
+TileGenFuncEGL(GLContext *gl,
+               const nsIntSize& aSize,
+               TextureImage::ContentType aContentType,
+               TextureImage::Flags aFlags,
+               TextureImage::ImageFormat aImageFormat)
+{
+  gl->MakeCurrent();
+
+  GLuint texture;
+  gl->fGenTextures(1, &texture);
+
+  nsRefPtr<TextureImageEGL> teximage =
+      new TextureImageEGL(texture, aSize, LOCAL_GL_CLAMP_TO_EDGE, aContentType,
+                          gl, aFlags, TextureImage::Created, aImageFormat);
+
+  teximage->BindTexture(LOCAL_GL_TEXTURE0);
+
+  GLint texfilter = aFlags & TextureImage::UseNearestFilter ? LOCAL_GL_NEAREST : LOCAL_GL_LINEAR;
+  gl->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MIN_FILTER, texfilter);
+  gl->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MAG_FILTER, texfilter);
+  gl->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_S, LOCAL_GL_CLAMP_TO_EDGE);
+  gl->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_T, LOCAL_GL_CLAMP_TO_EDGE);
+
+  return teximage.forget();
+}
+
 }
 }
\ No newline at end of file
--- a/gfx/gl/TextureImageEGL.h
+++ b/gfx/gl/TextureImageEGL.h
@@ -74,13 +74,27 @@ protected:
     EGLConfig mConfig;
     TextureState mTextureState;
 
     bool mBound;
 
     virtual void ApplyFilter();
 };
 
+already_AddRefed<TextureImage>
+CreateTextureImageEGL(GLContext *gl,
+                      const nsIntSize& aSize,
+                      TextureImage::ContentType aContentType,
+                      GLenum aWrapMode,
+                      TextureImage::Flags aFlags,
+                      TextureImage::ImageFormat aImageFormat);
+
+already_AddRefed<TextureImage>
+TileGenFuncEGL(GLContext *gl,
+               const nsIntSize& aSize,
+               TextureImage::ContentType aContentType,
+               TextureImage::Flags aFlags,
+               TextureImage::ImageFormat aImageFormat);
 
 }
 }
 
 #endif // TEXTUREIMAGEEGL_H_
\ No newline at end of file
--- a/gfx/gl/moz.build
+++ b/gfx/gl/moz.build
@@ -36,18 +36,20 @@ EXPORTS += [
     'GLContextProviderImpl.h',
     'GLContextSymbols.h',
     'GLContextTypes.h',
     'GLContextUtils.h',
     'GLDefs.h',
     'GLLibraryEGL.h',
     'GLLibraryLoader.h',
     'GLScreenBuffer.h',
+    'GLSharedHandleHelpers.h',
     'GLTextureImage.h',
     'GLTypes.h',
+    'GLUploadHelpers.h',
     'ScopedGLHelpers.h',
     'SharedSurface.h',
     'SharedSurfaceEGL.h',
     'SharedSurfaceGL.h',
     'SurfaceFactory.h',
     'SurfaceStream.h',
     'SurfaceTypes.h',
     'TextureGarbageBin.h',
@@ -74,20 +76,20 @@ if CONFIG['MOZ_ENABLE_SKIA_GPU']:
     ]
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
     UNIFIED_SOURCES += ['SharedSurfaceGralloc.cpp']
     EXPORTS += ['SharedSurfaceGralloc.h']
     LOCAL_INCLUDES += ['/widget/gonk']
 
 if gl_provider == 'CGL':
-    # This file includes Mac headers that are unfriendly to unified builds,
-    # and we have only one .mm file here anyway.
+    # These files include Mac headers that are unfriendly to unified builds
     SOURCES += [
-        "GLContextProvider%s.mm" % (gl_provider),
+        "GLContextProviderCGL.mm",
+        "TextureImageCGL.mm"
     ]
     EXPORTS += [
         'SharedSurfaceIO.h',
     ]
     # SharedSurfaceIO.cpp includes MacIOSurface.h which include Mac headers
     # which define Size and Point types in root namespace with often conflict with
     # our own types. While I haven't actually hit this issue in the present case,
     # it's been an issue in gfx/layers so let's not risk it.
@@ -112,23 +114,26 @@ UNIFIED_SOURCES += [
     'GLBlitTextureImageHelper.cpp',
     'GLContext.cpp',
     'GLContextFeatures.cpp',
     'GLContextTypes.cpp',
     'GLContextUtils.cpp',
     'GLLibraryEGL.cpp',
     'GLLibraryLoader.cpp',
     'GLScreenBuffer.cpp',
+    'GLSharedHandleHelpers.cpp',
     'GLTextureImage.cpp',
+    'GLUploadHelpers.cpp',
     'ScopedGLHelpers.cpp',
     'SharedSurface.cpp',
     'SharedSurfaceEGL.cpp',
     'SharedSurfaceGL.cpp',
     'SurfaceFactory.cpp',
     'SurfaceStream.cpp',
+    'SurfaceTypes.cpp',
     'TextureGarbageBin.cpp',
     'TextureImageEGL.cpp',
     'VBOArena.cpp',
 ]
 
 FAIL_ON_WARNINGS = True
 
 MSVC_ENABLE_PGO = True
--- a/gfx/layers/basic/BasicCompositor.cpp
+++ b/gfx/layers/basic/BasicCompositor.cpp
@@ -1,14 +1,15 @@
 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "BasicCompositor.h"
+#include "TextureHostBasic.h"
 #include "ipc/AutoOpenSurface.h"
 #include "mozilla/layers/Effects.h"
 #include "mozilla/layers/YCbCrImageDataSerializer.h"
 #include "nsIWidget.h"
 #include "gfx2DGlue.h"
 #include "mozilla/gfx/2D.h"
 #include "mozilla/gfx/Helpers.h"
 #include "gfxUtils.h"
@@ -17,26 +18,16 @@
 #define PIXMAN_DONT_DEFINE_STDINT
 #include "pixman.h"                     // for pixman_f_transform, etc
 
 namespace mozilla {
 using namespace mozilla::gfx;
 
 namespace layers {
 
-/**
- * A texture source interface that can be used by the software Compositor.
- */
-class TextureSourceBasic
-{
-public:
-  virtual ~TextureSourceBasic() {}
-  virtual gfx::SourceSurface* GetSurface() = 0;
-};
-
 class DataTextureSourceBasic : public DataTextureSource
                              , public TextureSourceBasic
 {
 public:
 
   virtual TextureSourceBasic* AsSourceBasic() MOZ_OVERRIDE { return this; }
 
   virtual gfx::SourceSurface* GetSurface() MOZ_OVERRIDE { return mSurface; }
@@ -84,17 +75,17 @@ public:
   {}
 
   SurfaceFormat GetFormat() const MOZ_OVERRIDE { return mFormat; }
 
   virtual IntSize GetSize() const MOZ_OVERRIDE { return mSize; }
 
   virtual TextureSourceBasic* AsSourceBasic() MOZ_OVERRIDE { return this; }
 
-  SourceSurface *GetSurface() { return mSurface; }
+  SourceSurface *GetSurface() MOZ_OVERRIDE { return mSurface; }
 
   virtual void SetCompositor(Compositor* aCompositor)
   {
     mCompositor = static_cast<BasicCompositor*>(aCompositor);
   }
 
   virtual const char *Name() { return "DeprecatedTextureHostBasic"; }
 
@@ -118,17 +109,20 @@ protected:
     return true;
   }
 
   virtual bool Lock() MOZ_OVERRIDE {
     return EnsureSurface();
   }
 
   virtual TemporaryRef<gfx::DataSourceSurface> GetAsSurface() MOZ_OVERRIDE {
-    return nullptr;
+    if (!mSurface) {
+        return nullptr;
+    }
+    return mSurface->GetDataSurface();
   }
 
   BasicCompositor *mCompositor;
   RefPtr<SourceSurface> mSurface;
   IntSize mSize;
   SurfaceFormat mFormat;
 };
 
new file mode 100644
--- /dev/null
+++ b/gfx/layers/basic/MacIOSurfaceTextureHostBasic.cpp
@@ -0,0 +1,94 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "MacIOSurfaceTextureHostBasic.h"
+#include "mozilla/layers/BasicCompositor.h"
+#include "mozilla/gfx/MacIOSurface.h"
+
+namespace mozilla {
+namespace layers {
+
+MacIOSurfaceTextureSourceBasic::MacIOSurfaceTextureSourceBasic(
+                                BasicCompositor* aCompositor,
+                                MacIOSurface* aSurface)
+  : mCompositor(aCompositor)
+  , mSurface(aSurface)
+{}
+
+MacIOSurfaceTextureSourceBasic::~MacIOSurfaceTextureSourceBasic()
+{
+}
+
+gfx::IntSize
+MacIOSurfaceTextureSourceBasic::GetSize() const
+{
+  return gfx::IntSize(mSurface->GetDevicePixelWidth(),
+                      mSurface->GetDevicePixelHeight());
+}
+
+gfx::SurfaceFormat
+MacIOSurfaceTextureSourceBasic::GetFormat() const
+{
+  return mSurface->HasAlpha() ? gfx::FORMAT_R8G8B8A8 : gfx::FORMAT_B8G8R8X8;
+}
+
+MacIOSurfaceTextureHostBasic::MacIOSurfaceTextureHostBasic(
+    uint64_t aID,
+    TextureFlags aFlags,
+    const SurfaceDescriptorMacIOSurface& aDescriptor
+)
+  : TextureHost(aID, aFlags)
+{
+  mSurface = MacIOSurface::LookupSurface(aDescriptor.surface(),
+                                         aDescriptor.scaleFactor(),
+                                         aDescriptor.hasAlpha());
+}
+
+gfx::SourceSurface*
+MacIOSurfaceTextureSourceBasic::GetSurface()
+{
+  if (!mSourceSurface) {
+    mSourceSurface = mSurface->GetAsSurface();
+  }
+  return mSourceSurface;
+}
+
+
+bool
+MacIOSurfaceTextureHostBasic::Lock()
+{
+  if (!mCompositor) {
+    return false;
+  }
+
+  if (!mTextureSource) {
+    mTextureSource = new MacIOSurfaceTextureSourceBasic(mCompositor, mSurface);
+  }
+  return true;
+}
+
+void
+MacIOSurfaceTextureHostBasic::SetCompositor(Compositor* aCompositor)
+{
+  BasicCompositor* compositor = static_cast<BasicCompositor*>(aCompositor);
+  mCompositor = compositor;
+  if (mTextureSource) {
+    mTextureSource->SetCompositor(compositor);
+  }
+}
+
+gfx::SurfaceFormat
+MacIOSurfaceTextureHostBasic::GetFormat() const {
+  return mSurface->HasAlpha() ? gfx::FORMAT_R8G8B8A8 : gfx::FORMAT_B8G8R8X8;
+}
+
+gfx::IntSize
+MacIOSurfaceTextureHostBasic::GetSize() const {
+  return gfx::IntSize(mSurface->GetDevicePixelWidth(),
+                      mSurface->GetDevicePixelHeight());
+}
+
+}
+}
new file mode 100644
--- /dev/null
+++ b/gfx/layers/basic/MacIOSurfaceTextureHostBasic.h
@@ -0,0 +1,94 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef MOZILLA_GFX_MACIOSURFACETEXTUREHOST_BASIC_H
+#define MOZILLA_GFX_MACIOSURFACETEXTUREHOST_BASIC_H
+
+#include "mozilla/layers/TextureHostBasic.h"
+
+class MacIOSurface;
+
+namespace mozilla {
+namespace layers {
+
+class BasicCompositor;
+
+/**
+ * A texture source meant for use with BasicCompositor.
+ *
+ * It does not own any GL texture, and attaches its shared handle to one of
+ * the compositor's temporary textures when binding.
+ */
+class MacIOSurfaceTextureSourceBasic
+  : public TextureSourceBasic,
+    public NewTextureSource
+{
+public:
+  MacIOSurfaceTextureSourceBasic(BasicCompositor* aCompositor,
+                                 MacIOSurface* aSurface);
+  virtual ~MacIOSurfaceTextureSourceBasic();
+
+  virtual TextureSourceBasic* AsSourceBasic() MOZ_OVERRIDE { return this; }
+
+  virtual gfx::IntSize GetSize() const MOZ_OVERRIDE;
+  virtual gfx::SurfaceFormat GetFormat() const MOZ_OVERRIDE;
+  virtual gfx::SourceSurface* GetSurface() MOZ_OVERRIDE;
+
+  virtual void DeallocateDeviceData() MOZ_OVERRIDE { }
+
+  void SetCompositor(BasicCompositor* aCompositor) {
+    mCompositor = aCompositor;
+  }
+
+protected:
+  BasicCompositor* mCompositor;
+  RefPtr<MacIOSurface> mSurface;
+  RefPtr<gfx::SourceSurface> mSourceSurface;
+};
+
+/**
+ * A TextureHost for shared MacIOSurface
+ *
+ * Most of the logic actually happens in MacIOSurfaceTextureSourceBasic.
+ */
+class MacIOSurfaceTextureHostBasic : public TextureHost
+{
+public:
+  MacIOSurfaceTextureHostBasic(uint64_t aID,
+                             TextureFlags aFlags,
+                             const SurfaceDescriptorMacIOSurface& aDescriptor);
+
+  virtual void SetCompositor(Compositor* aCompositor) MOZ_OVERRIDE;
+
+  virtual bool Lock() MOZ_OVERRIDE;
+
+  virtual gfx::SurfaceFormat GetFormat() const MOZ_OVERRIDE;
+
+  virtual NewTextureSource* GetTextureSources() MOZ_OVERRIDE
+  {
+    return mTextureSource;
+  }
+
+  virtual TemporaryRef<gfx::DataSourceSurface> GetAsSurface() MOZ_OVERRIDE
+  {
+    return nullptr; // XXX - implement this (for MOZ_DUMP_PAINTING)
+  }
+
+  virtual gfx::IntSize GetSize() const MOZ_OVERRIDE;
+
+#ifdef MOZ_LAYERS_HAVE_LOG
+  virtual const char* Name() { return "MacIOSurfaceTextureHostBasic"; }
+#endif
+
+protected:
+  BasicCompositor* mCompositor;
+  RefPtr<MacIOSurfaceTextureSourceBasic> mTextureSource;
+  RefPtr<MacIOSurface> mSurface;
+};
+
+}
+}
+
+#endif // MOZILLA_GFX_MACIOSURFACETEXTUREHOSTOGL_BASIC_H
new file mode 100644
--- /dev/null
+++ b/gfx/layers/basic/TextureHostBasic.cpp
@@ -0,0 +1,41 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+* This Source Code Form is subject to the terms of the Mozilla Public
+* License, v. 2.0. If a copy of the MPL was not distributed with this
+* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "TextureHostBasic.h"
+#include "MacIOSurfaceTextureHostBasic.h"
+
+using namespace mozilla::gl;
+using namespace mozilla::gfx;
+
+namespace mozilla {
+namespace layers {
+
+TemporaryRef<TextureHost>
+CreateTextureHostBasic(uint64_t aID,
+                       const SurfaceDescriptor& aDesc,
+                       ISurfaceAllocator* aDeallocator,
+                       TextureFlags aFlags)
+{
+  RefPtr<TextureHost> result;
+  switch (aDesc.type()) {
+#ifdef XP_MACOSX
+    case SurfaceDescriptor::TSurfaceDescriptorMacIOSurface: {
+      const SurfaceDescriptorMacIOSurface& desc =
+        aDesc.get_SurfaceDescriptorMacIOSurface();
+      result = new MacIOSurfaceTextureHostBasic(aID, aFlags, desc);
+      break;
+    }
+#endif
+    default: {
+      result = CreateBackendIndependentTextureHost(aID, aDesc, aDeallocator, aFlags);
+      break;
+    }
+  }
+
+  return result;
+}
+
+} // namespace layers
+} // namespace gfx
new file mode 100644
--- /dev/null
+++ b/gfx/layers/basic/TextureHostBasic.h
@@ -0,0 +1,31 @@
+
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+* This Source Code Form is subject to the terms of the Mozilla Public
+* License, v. 2.0. If a copy of the MPL was not distributed with this
+* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef MOZILLA_GFX_TEXTUREHOSTBASIC_H_
+#define MOZILLA_GFX_TEXTUREHOSTBASIC_H_
+
+#include "CompositableHost.h"
+#include "mozilla/layers/LayersSurfaces.h"
+#include "mozilla/layers/TextureHost.h"
+#include "mozilla/gfx/2D.h"
+
+namespace mozilla {
+namespace layers {
+
+/**
+ * A texture source interface that can be used by the software Compositor.
+ */
+class TextureSourceBasic
+{
+public:
+  virtual ~TextureSourceBasic() {}
+  virtual gfx::SourceSurface* GetSurface() = 0;
+};
+
+} // namespace layers
+} // namespace mozilla
+
+#endif // MOZILLA_GFX_TEXTUREHOSTBASIC_H_
--- a/gfx/layers/client/ContentClient.cpp
+++ b/gfx/layers/client/ContentClient.cpp
@@ -981,17 +981,18 @@ DeprecatedContentClientSingleBuffered::S
                           mBufferRect,
                           mBufferRotation);
 
   backBuffer = GetDTBufferOnWhite();
   if (!backBuffer && mDeprecatedTextureClientOnWhite) {
     backBuffer = mDeprecatedTextureClientOnWhite->LockDrawTarget();
   }
   if (!backBuffer) {
-    NS_WARNING("Could not lock texture client (on white)");
+    NS_WARN_IF_FALSE(!mDeprecatedTextureClientOnWhite,
+                     "Could not lock texture client (on white)");
     return;
   }
 
   oldBuffer = SetDTBufferOnWhite(backBuffer);
 }
 
 static void
 WrapRotationAxis(int32_t* aRotationPoint, int32_t aSize)
--- a/gfx/layers/client/TextureClient.h
+++ b/gfx/layers/client/TextureClient.h
@@ -363,17 +363,17 @@ public:
 
   virtual void OnActorDestroy() MOZ_OVERRIDE
   {
     mShmem = ipc::Shmem();
   }
 
 protected:
   ipc::Shmem mShmem;
-  ISurfaceAllocator* mAllocator;
+  RefPtr<ISurfaceAllocator> mAllocator;
   bool mAllocated;
 };
 
 /**
  * TextureClient that wraps raw memory.
  * The corresponding texture on the host side is MemoryTextureHost.
  * Can obviously not be used in a cross process setup.
  */
--- a/gfx/layers/composite/ContainerLayerComposite.cpp
+++ b/gfx/layers/composite/ContainerLayerComposite.cpp
@@ -27,16 +27,17 @@
 #include "nsAutoPtr.h"                  // for nsRefPtr
 #include "nsDebug.h"                    // for NS_ASSERTION
 #include "nsISupportsUtils.h"           // for NS_ADDREF, NS_RELEASE
 #include "nsPoint.h"                    // for nsIntPoint
 #include "nsRect.h"                     // for nsIntRect
 #include "nsRegion.h"                   // for nsIntRegion
 #include "nsTArray.h"                   // for nsAutoTArray
 #include "nsTraceRefcnt.h"              // for MOZ_COUNT_CTOR, etc
+#include <vector>
 
 namespace mozilla {
 namespace layers {
 
 // HasOpaqueAncestorLayer and ContainerRender are shared between RefLayer and ContainerLayer
 static bool
 HasOpaqueAncestorLayer(Layer* aLayer)
 {
@@ -74,16 +75,136 @@ GetOpaqueRect(Layer* aLayer)
   }
   const nsIntRect* clipRect = aLayer->GetEffectiveClipRect();
   if (clipRect) {
     result.IntersectRect(result, *clipRect);
   }
   return result;
 }
 
+struct LayerVelocityUserData : public LayerUserData {
+public:
+  LayerVelocityUserData() {
+    MOZ_COUNT_CTOR(LayerVelocityUserData);
+  }
+  ~LayerVelocityUserData() {
+    MOZ_COUNT_DTOR(LayerVelocityUserData);
+  }
+
+  struct VelocityData {
+    VelocityData(TimeStamp frameTime, int scrollX, int scrollY)
+      : mFrameTime(frameTime)
+      , mPoint(scrollX, scrollY)
+    {}
+
+    TimeStamp mFrameTime;
+    gfx::Point mPoint;
+  };
+  std::vector<VelocityData> mData;
+};
+
+static void DrawVelGraph(const nsIntRect& aClipRect,
+                         LayerManagerComposite* aManager,
+                         Layer* aLayer) {
+  static char sLayerVelocityUserDataKey;
+  Compositor* compositor = aManager->GetCompositor();
+  gfx::Rect clipRect(aClipRect.x, aClipRect.y,
+                     aClipRect.width, aClipRect.height);
+
+  TimeStamp now = TimeStamp::Now();
+
+  void* key = reinterpret_cast<void*>(&sLayerVelocityUserDataKey);
+  if (!aLayer->HasUserData(key)) {
+    aLayer->SetUserData(key, new LayerVelocityUserData());
+  }
+
+  LayerVelocityUserData* velocityData =
+    static_cast<LayerVelocityUserData*>(aLayer->GetUserData(key));
+
+  if (velocityData->mData.size() >= 1 &&
+    now > velocityData->mData[velocityData->mData.size() - 1].mFrameTime +
+      TimeDuration::FromMilliseconds(200)) {
+    // clear stale data
+    velocityData->mData.clear();
+  }
+
+  nsIntPoint scrollOffset =
+    aLayer->GetEffectiveVisibleRegion().GetBounds().TopLeft();
+  velocityData->mData.push_back(
+    LayerVelocityUserData::VelocityData(now, scrollOffset.x, scrollOffset.y));
+
+
+  // XXX: Uncomment these lines to enable ScrollGraph logging. This is
+  //      useful for HVGA phones or to output the data to accurate
+  //      graphing software.
+  //printf_stderr("ScrollGraph (%p): %i, %i\n",
+  //  aLayer, scrollOffset.x, scrollOffset.y);
+
+  // Keep a circular buffer of 100.
+  size_t circularBufferSize = 100;
+  if (velocityData->mData.size() > circularBufferSize) {
+    velocityData->mData.erase(velocityData->mData.begin());
+  }
+
+  if (velocityData->mData.size() == 1) {
+    return;
+  }
+
+  // Clear and disable the graph when it's flat
+  for (size_t i = 1; i < velocityData->mData.size(); i++) {
+    if (velocityData->mData[i - 1].mPoint != velocityData->mData[i].mPoint) {
+      break;
+    }
+    if (i == velocityData->mData.size() - 1) {
+      velocityData->mData.clear();
+      return;
+    }
+  }
+
+  if (aLayer->GetEffectiveVisibleRegion().GetBounds().width < 300 ||
+      aLayer->GetEffectiveVisibleRegion().GetBounds().height < 300) {
+    // Don't want a graph for smaller layers
+    return;
+  }
+
+  aManager->SetDebugOverlayWantsNextFrame(true);
+
+  gfx::Matrix4x4 transform;
+  ToMatrix4x4(aLayer->GetEffectiveTransform(), transform);
+  nsIntRect bounds = aLayer->GetEffectiveVisibleRegion().GetBounds();
+  gfx::Rect graphBounds = gfx::Rect(bounds.x, bounds.y,
+                                    bounds.width, bounds.height);
+  gfx::Rect graphRect = gfx::Rect(bounds.x, bounds.y, 200, 100);
+
+  float opacity = 1.0;
+  EffectChain effects;
+  effects.mPrimaryEffect = new EffectSolidColor(gfx::Color(0.2,0,0,1));
+  compositor->DrawQuad(graphRect,
+                       clipRect,
+                       effects,
+                       opacity,
+                       transform);
+
+  std::vector<gfx::Point> graph;
+  int yScaleFactor = 3;
+  for (int32_t i = (int32_t)velocityData->mData.size() - 2; i >= 0; i--) {
+    const gfx::Point& p1 = velocityData->mData[i+1].mPoint;
+    const gfx::Point& p2 = velocityData->mData[i].mPoint;
+    int vel = sqrt((p1.x - p2.x) * (p1.x - p2.x) +
+                   (p1.y - p2.y) * (p1.y - p2.y));
+    graph.push_back(
+      gfx::Point(bounds.x + graphRect.width / circularBufferSize * i,
+                 graphBounds.y + graphRect.height - vel/yScaleFactor));
+  }
+
+  compositor->DrawLines(graph, clipRect, gfx::Color(0,1,0,1),
+                        opacity, transform);
+
+}
+
 template<class ContainerT> void
 ContainerRender(ContainerT* aContainer,
                 LayerManagerComposite* aManager,
                 const nsIntRect& aClipRect)
 {
   /**
    * Setup our temporary surface for rendering the contents of this container.
    */
@@ -195,16 +316,20 @@ ContainerRender(ContainerT* aContainer,
 
     if (layerToRender->HasLayerBeenComposited()) {
       // Composer2D will compose this layer so skip GPU composition
       // this time & reset composition flag for next composition phase
       layerToRender->SetLayerComposited(false);
     } else {
       layerToRender->RenderLayer(clipRect);
     }
+
+    if (gfxPlatform::GetPrefLayersScrollGraph()) {
+      DrawVelGraph(clipRect, aManager, layerToRender->GetLayer());
+    }
     // invariant: our GL context should be current here, I don't think we can
     // assert it though
   }
 
   if (needsSurface) {
     // Unbind the current surface and rebind the previous one.
 #ifdef MOZ_DUMP_PAINTING
     if (gfxUtils::sDumpPainting) {
--- a/gfx/layers/composite/ContentHost.h
+++ b/gfx/layers/composite/ContentHost.h
@@ -457,25 +457,25 @@ private:
       LEFT, RIGHT
     };
     enum YSide {
       TOP, BOTTOM
     };
 
     nsIntRect GetQuadrantRectangle(XSide aXSide, YSide aYSide) const;
 
-    ISurfaceAllocator* mDeAllocator;
+    RefPtr<ISurfaceAllocator> mDeAllocator;
     TextureIdentifier mTextureId;
     SurfaceDescriptor mDescriptor;
     nsIntRegion mUpdated;
     nsIntRect mBufferRect;
     nsIntPoint mBufferRotation;
   };
 
   nsTArray<nsAutoPtr<Request> > mUpdateList;
 
-  ISurfaceAllocator* mDeAllocator;
+  RefPtr<ISurfaceAllocator> mDeAllocator;
 };
 
 }
 }
 
 #endif
--- a/gfx/layers/composite/LayerManagerComposite.cpp
+++ b/gfx/layers/composite/LayerManagerComposite.cpp
@@ -98,16 +98,17 @@ LayerManagerComposite::ClearCachedResour
 
 /**
  * LayerManagerComposite
  */
 LayerManagerComposite::LayerManagerComposite(Compositor* aCompositor)
 : mCompositor(aCompositor)
 , mInTransaction(false)
 , mIsCompositorReady(false)
+, mDebugOverlayWantsNextFrame(false)
 {
   MOZ_ASSERT(aCompositor);
 }
 
 LayerManagerComposite::~LayerManagerComposite()
 {
   Destroy();
 }
@@ -820,24 +821,16 @@ LayerManagerComposite::GetTextureFactory
 int32_t
 LayerManagerComposite::GetMaxTextureSize() const
 {
   return mCompositor->GetMaxTextureSize();
 }
 
 #ifndef MOZ_HAVE_PLATFORM_SPECIFIC_LAYER_BUFFERS
 
-/*static*/ already_AddRefed<TextureImage>
-LayerManagerComposite::OpenDescriptorForDirectTexturing(GLContext*,
-                                                        const SurfaceDescriptor&,
-                                                        GLenum)
-{
-  return nullptr;
-}
-
 /*static*/ bool
 LayerManagerComposite::SupportsDirectTexturing()
 {
   return false;
 }
 
 /*static*/ void
 LayerManagerComposite::PlatformSyncBeforeReplyUpdate()
--- a/gfx/layers/composite/LayerManagerComposite.h
+++ b/gfx/layers/composite/LayerManagerComposite.h
@@ -205,26 +205,16 @@ public:
    * screen on the last render. This is only useful when progressive tile
    * drawing is enabled, otherwise this will always return 1.0.
    * This function's expense scales with the size of the layer tree and the
    * complexity of individual layers' valid regions.
    */
   float ComputeRenderIntegrity();
 
   /**
-   * Try to open |aDescriptor| for direct texturing.  If the
-   * underlying surface supports direct texturing, a non-null
-   * TextureImage is returned.  Otherwise null is returned.
-   */
-  static already_AddRefed<gl::TextureImage>
-  OpenDescriptorForDirectTexturing(gl::GLContext* aContext,
-                                   const SurfaceDescriptor& aDescriptor,
-                                   GLenum aWrapMode);
-
-  /**
    * returns true if PlatformAllocBuffer will return a buffer that supports
    * direct texturing
    */
   static bool SupportsDirectTexturing();
 
   static void PlatformSyncBeforeReplyUpdate();
 
   void SetCompositorID(uint32_t aID);
@@ -236,16 +226,24 @@ public:
 
   Compositor* GetCompositor() const
   {
     return mCompositor;
   }
 
   bool PlatformDestroySharedSurface(SurfaceDescriptor* aSurface);
 
+  /**
+   * LayerManagerComposite provides sophisticated debug overlays
+   * that can request a next frame.
+   */
+  bool DebugOverlayWantsNextFrame() { return mDebugOverlayWantsNextFrame; }
+  void SetDebugOverlayWantsNextFrame(bool aVal)
+  { mDebugOverlayWantsNextFrame = aVal; }
+
 private:
   /** Region we're clipping our current drawing to. */
   nsIntRegion mClippingRegion;
   nsIntRect mRenderBounds;
 
   /** Current root layer. */
   LayerComposite *RootLayer() const;
 
@@ -282,16 +280,17 @@ private:
   DrawThebesLayerCallback mThebesLayerCallback;
   void *mThebesLayerCallbackData;
   gfxMatrix mWorldMatrix;
 
   bool mInTransaction;
   bool mIsCompositorReady;
   nsIntRegion mInvalidRegion;
   nsAutoPtr<LayerProperties> mClonedLayerTreeProperties;
+  bool mDebugOverlayWantsNextFrame;
 };
 
 /**
  * Composite layers are for use with OMTC on the compositor thread only. There
  * must be corresponding Basic layers on the content thread. For composite
  * layers, the layer manager only maintains the layer tree, all rendering is
  * done by a Compositor (see Compositor.h). As such, composite layers are
  * platform-independent and can be used on any platform for which there is a
--- a/gfx/layers/composite/TextureHost.cpp
+++ b/gfx/layers/composite/TextureHost.cpp
@@ -75,37 +75,40 @@ DeprecatedTextureHost::CreateDeprecatedT
       return CreateBasicDeprecatedTextureHost(aDescriptorType,
                                           aDeprecatedTextureHostFlags,
                                           aTextureFlags);
     default:
       MOZ_CRASH("Couldn't create texture host");
   }
 }
 
-// implemented in TextureOGL.cpp
+// implemented in TextureHostOGL.cpp
 TemporaryRef<TextureHost> CreateTextureHostOGL(uint64_t aID,
                                                const SurfaceDescriptor& aDesc,
                                                ISurfaceAllocator* aDeallocator,
                                                TextureFlags aFlags);
 
+// implemented in TextureHostBasic.cpp
+TemporaryRef<TextureHost> CreateTextureHostBasic(uint64_t aID,
+                                               const SurfaceDescriptor& aDesc,
+                                               ISurfaceAllocator* aDeallocator,
+                                               TextureFlags aFlags);
+
 // static
 TemporaryRef<TextureHost>
 TextureHost::Create(uint64_t aID,
                     const SurfaceDescriptor& aDesc,
                     ISurfaceAllocator* aDeallocator,
                     TextureFlags aFlags)
 {
   switch (Compositor::GetBackend()) {
     case LAYERS_OPENGL:
       return CreateTextureHostOGL(aID, aDesc, aDeallocator, aFlags);
     case LAYERS_BASIC:
-      return CreateBackendIndependentTextureHost(aID,
-                                                 aDesc,
-                                                 aDeallocator,
-                                                 aFlags);
+      return CreateTextureHostBasic(aID, aDesc, aDeallocator, aFlags);
 #ifdef XP_WIN
     case LAYERS_D3D11:
     case LAYERS_D3D9:
       // XXX - not implemented yet
 #endif
     default:
       MOZ_CRASH("Couldn't create texture host");
       return nullptr;
@@ -256,21 +259,23 @@ DeprecatedTextureHost::PrintInfo(nsACStr
 {
   aTo += aPrefix;
   aTo += nsPrintfCString("%s (0x%p)", Name(), this);
   AppendToString(aTo, GetSize(), " [size=", "]");
   AppendToString(aTo, GetFormat(), " [format=", "]");
   AppendToString(aTo, mFlags, " [flags=", "]");
 }
 
-
-
-
-
-
+void
+DeprecatedTextureHost::SetBuffer(SurfaceDescriptor* aBuffer, ISurfaceAllocator* aAllocator)
+{
+  MOZ_ASSERT(!mBuffer || mBuffer == aBuffer, "Will leak the old mBuffer");
+  mBuffer = aBuffer;
+  mDeAllocator = aAllocator;
+}
 
 BufferTextureHost::BufferTextureHost(uint64_t aID,
                                      gfx::SurfaceFormat aFormat,
                                      TextureFlags aFlags)
 : TextureHost(aID, aFlags)
 , mCompositor(nullptr)
 , mFormat(aFormat)
 , mUpdateSerial(1)
--- a/gfx/layers/composite/TextureHost.h
+++ b/gfx/layers/composite/TextureHost.h
@@ -483,17 +483,17 @@ public:
   virtual uint8_t* GetBuffer() MOZ_OVERRIDE;
 
   virtual const char *Name() MOZ_OVERRIDE { return "ShmemTextureHost"; }
 
   virtual void OnActorDestroy() MOZ_OVERRIDE;
 
 protected:
   mozilla::ipc::Shmem* mShmem;
-  ISurfaceAllocator* mDeallocator;
+  RefPtr<ISurfaceAllocator> mDeallocator;
 };
 
 /**
  * TextureHost that wraps raw memory.
  * The corresponding texture on the client side is MemoryTextureClient.
  * Can obviously not be used in a cross process setup.
  * This TextureHost is backend-independent.
  */
@@ -700,22 +700,17 @@ public:
   /**
    * Set a SurfaceDescriptor for this texture host. By setting a buffer and
    * allocator/de-allocator for the DeprecatedTextureHost, you cause the DeprecatedTextureHost to
    * retain a SurfaceDescriptor.
    * Ownership of the SurfaceDescriptor passes to this.
    */
   // only made virtual to allow overriding in GrallocDeprecatedTextureHostOGL, for hacky fix in gecko 23 for bug 862324.
   // see bug 865908 about fixing this.
-  virtual void SetBuffer(SurfaceDescriptor* aBuffer, ISurfaceAllocator* aAllocator)
-  {
-    MOZ_ASSERT(!mBuffer || mBuffer == aBuffer, "Will leak the old mBuffer");
-    mBuffer = aBuffer;
-    mDeAllocator = aAllocator;
-  }
+  virtual void SetBuffer(SurfaceDescriptor* aBuffer, ISurfaceAllocator* aAllocator);
 
   // used only for hacky fix in gecko 23 for bug 862324
   // see bug 865908 about fixing this.
   virtual void ForgetBuffer() {}
 
   void OnActorDestroy();
 
 protected:
@@ -757,17 +752,17 @@ protected:
 
   // Texture info
   TextureFlags mFlags;
   SurfaceDescriptor* mBuffer; // FIXME [bjacob] it's terrible to have a SurfaceDescriptor here,
                               // because SurfaceDescriptor's may have raw pointers to IPDL actors,
                               // which can go away under our feet at any time. This is the cause
                               // of bug 862324 among others. Our current understanding is that
                               // this will be gone in Gecko 24. See bug 858914.
-  ISurfaceAllocator* mDeAllocator;
+  RefPtr<ISurfaceAllocator> mDeAllocator;
   gfx::SurfaceFormat mFormat;
 };
 
 class AutoLockDeprecatedTextureHost
 {
 public:
   AutoLockDeprecatedTextureHost(DeprecatedTextureHost* aHost)
     : mDeprecatedTextureHost(aHost)
--- a/gfx/layers/ipc/CompositorParent.cpp
+++ b/gfx/layers/ipc/CompositorParent.cpp
@@ -588,18 +588,23 @@ CompositorParent::CompositeInTransaction
 
 #ifdef MOZ_DUMP_PAINTING
   static bool gDumpCompositorTree = false;
   if (gDumpCompositorTree) {
     printf_stderr("Painting --- compositing layer tree:\n");
     mLayerManager->Dump();
   }
 #endif
+  mLayerManager->SetDebugOverlayWantsNextFrame(false);
   mLayerManager->EndEmptyTransaction();
 
+  if (mLayerManager->DebugOverlayWantsNextFrame()) {
+    ScheduleComposition();
+  }
+
 #ifdef COMPOSITOR_PERFORMANCE_WARNING
   if (mExpectedComposeTime + TimeDuration::FromMilliseconds(15) < TimeStamp::Now()) {
     printf_stderr("Compositor: Composite took %i ms.\n",
                   15 + (int)(TimeStamp::Now() - mExpectedComposeTime).ToMilliseconds());
   }
 #endif
   profiler_tracing("Paint", "Composite", TRACING_INTERVAL_END);
 }
--- a/gfx/layers/ipc/ISurfaceAllocator.h
+++ b/gfx/layers/ipc/ISurfaceAllocator.h
@@ -138,17 +138,16 @@ protected:
                                               gfxContentType aContent,
                                               uint32_t aCaps,
                                               SurfaceDescriptor* aBuffer);
 
 
   virtual ~ISurfaceAllocator() {}
 
   friend class detail::RefCounted<ISurfaceAllocator, detail::AtomicRefCount>;
-  //friend class detail::RefCounted<ISurfaceAllocator, detail::AtomicRefCount>;
 };
 
 class GfxMemoryImageReporter MOZ_FINAL : public mozilla::MemoryUniReporter
 {
 public:
   GfxMemoryImageReporter()
     : MemoryUniReporter("explicit/gfx/heap-textures", KIND_HEAP, UNITS_BYTES,
                         "Heap memory shared between threads by texture clients and hosts.")
--- a/gfx/layers/ipc/ImageBridgeChild.cpp
+++ b/gfx/layers/ipc/ImageBridgeChild.cpp
@@ -824,17 +824,17 @@ ImageBridgeChild::AllocShmem(size_t aSiz
   } else {
     return DispatchAllocShmemInternal(aSize, aType, aShmem, false); // false: unsafe
   }
 }
 
 // NewRunnableFunction accepts a limited number of parameters so we need a
 // struct here
 struct AllocShmemParams {
-  ISurfaceAllocator* mAllocator;
+  RefPtr<ISurfaceAllocator> mAllocator;
   size_t mSize;
   ipc::SharedMemory::SharedMemoryType mType;
   ipc::Shmem* mShmem;
   bool mUnsafe;
   bool mSuccess;
 };
 
 static void ProxyAllocShmemNow(AllocShmemParams* aParams,
--- a/gfx/layers/ipc/ShadowLayerUtilsD3D10.cpp
+++ b/gfx/layers/ipc/ShadowLayerUtilsD3D10.cpp
@@ -83,24 +83,16 @@ ShadowLayerForwarder::PlatformSyncBefore
 }
 
 bool
 ISurfaceAllocator::PlatformDestroySharedSurface(SurfaceDescriptor*)
 {
   return false;
 }
 
-/*static*/ already_AddRefed<TextureImage>
-LayerManagerComposite::OpenDescriptorForDirectTexturing(GLContext*,
-                                                        const SurfaceDescriptor&,
-                                                        GLenum)
-{
-  return nullptr;
-}
-
 /*static*/ bool
 LayerManagerComposite::SupportsDirectTexturing()
 {
   return true;
 }
 
 /*static*/ void
 LayerManagerComposite::PlatformSyncBeforeReplyUpdate()
--- a/gfx/layers/ipc/ShadowLayerUtilsGralloc.cpp
+++ b/gfx/layers/ipc/ShadowLayerUtilsGralloc.cpp
@@ -286,29 +286,16 @@ void GrallocBufferActor::AddDeprecatedTe
 void GrallocBufferActor::RemoveDeprecatedTextureHost(DeprecatedTextureHost* aDeprecatedTextureHost)
 {
   mDeprecatedTextureHosts.RemoveElement(aDeprecatedTextureHost);
   // that should be the only occurence, otherwise we'd leak this TextureHost...
   // assert that that's not happening.
   MOZ_ASSERT(!mDeprecatedTextureHosts.Contains(aDeprecatedTextureHost));
 }
 
-/*static*/ already_AddRefed<TextureImage>
-LayerManagerComposite::OpenDescriptorForDirectTexturing(GLContext* aGL,
-                                                        const SurfaceDescriptor& aDescriptor,
-                                                        GLenum aWrapMode)
-{
-  PROFILER_LABEL("LayerManagerComposite", "OpenDescriptorForDirectTexturing");
-  if (SurfaceDescriptor::TSurfaceDescriptorGralloc != aDescriptor.type()) {
-    return nullptr;
-  }
-  sp<GraphicBuffer> buffer = GrallocBufferActor::GetFrom(aDescriptor);
-  return aGL->CreateDirectTextureImage(buffer.get(), aWrapMode);
-}
-
 /*static*/ bool
 LayerManagerComposite::SupportsDirectTexturing()
 {
   return true;
 }
 
 /*static*/ void
 LayerManagerComposite::PlatformSyncBeforeReplyUpdate()
--- a/gfx/layers/ipc/ShadowLayerUtilsMac.cpp
+++ b/gfx/layers/ipc/ShadowLayerUtilsMac.cpp
@@ -101,24 +101,16 @@ LayerManagerComposite::PlatformSyncBefor
 }
 
 bool
 ISurfaceAllocator::PlatformDestroySharedSurface(SurfaceDescriptor*)
 {
   return false;
 }
 
-/*static*/ already_AddRefed<TextureImage>
-LayerManagerComposite::OpenDescriptorForDirectTexturing(GLContext*,
-                                                        const SurfaceDescriptor&,
-                                                        GLenum)
-{
-  return nullptr;
-}
-
 /*static*/ bool
 LayerManagerComposite::SupportsDirectTexturing()
 {
   return false;
 }
 
 
 } // namespace layers
--- a/gfx/layers/ipc/ShadowLayerUtilsX11.cpp
+++ b/gfx/layers/ipc/ShadowLayerUtilsX11.cpp
@@ -222,25 +222,16 @@ LayerManagerComposite::PlatformSyncBefor
     // operations on the *front buffers* before handing them back to
     // the child, even though they will be read operations.
     // Otherwise, the child might start scribbling on new back buffers
     // that are still participating in requests as old front buffers.
     FinishX(DefaultXDisplay());
   }
 }
 
-/*static*/ already_AddRefed<TextureImage>
-LayerManagerComposite::OpenDescriptorForDirectTexturing(GLContext*,
-                                                        const SurfaceDescriptor&,
-                                                        GLenum)
-{
-  // FIXME/bug XXXXXX: implement this using texture-from-pixmap
-  return nullptr;
-}
-
 /*static*/ bool
 LayerManagerComposite::SupportsDirectTexturing()
 {
   return false;
 }
 
 bool
 ISurfaceAllocator::PlatformDestroySharedSurface(SurfaceDescriptor* aSurface)
--- a/gfx/layers/ipc/SharedPlanarYCbCrImage.cpp
+++ b/gfx/layers/ipc/SharedPlanarYCbCrImage.cpp
@@ -40,16 +40,22 @@ SharedPlanarYCbCrImage::~SharedPlanarYCb
 
   if (mCompositable->GetAsyncID() != 0 &&
       !InImageBridgeChildThread()) {
     ImageBridgeChild::DispatchReleaseTextureClient(mTextureClient.forget().drop());
     ImageBridgeChild::DispatchReleaseImageClient(mCompositable.forget().drop());
   }
 }
 
+DeprecatedSharedPlanarYCbCrImage::DeprecatedSharedPlanarYCbCrImage(ISurfaceAllocator* aAllocator)
+: PlanarYCbCrImage(nullptr)
+, mSurfaceAllocator(aAllocator), mAllocated(false)
+{
+  MOZ_COUNT_CTOR(DeprecatedSharedPlanarYCbCrImage);
+}
 
 DeprecatedSharedPlanarYCbCrImage::~DeprecatedSharedPlanarYCbCrImage() {
   MOZ_COUNT_DTOR(DeprecatedSharedPlanarYCbCrImage);
 
   if (mAllocated) {
     SurfaceDescriptor desc;
     DropToSurfaceDescriptor(desc);
     mSurfaceAllocator->DestroySharedSurface(&desc);
--- a/gfx/layers/ipc/SharedPlanarYCbCrImage.h
+++ b/gfx/layers/ipc/SharedPlanarYCbCrImage.h
@@ -25,22 +25,17 @@ class ImageClient;
 class ISurfaceAllocator;
 class SurfaceDescriptor;
 class TextureClient;
 
 // XXX - This class will be removed along with DeprecatedImageClient
 class DeprecatedSharedPlanarYCbCrImage : public PlanarYCbCrImage
 {
 public:
-  DeprecatedSharedPlanarYCbCrImage(ISurfaceAllocator* aAllocator)
-  : PlanarYCbCrImage(nullptr)
-  , mSurfaceAllocator(aAllocator), mAllocated(false)
-  {
-    MOZ_COUNT_CTOR(DeprecatedSharedPlanarYCbCrImage);
-  }
+  DeprecatedSharedPlanarYCbCrImage(ISurfaceAllocator* aAllocator);
 
   ~DeprecatedSharedPlanarYCbCrImage();
 
   virtual DeprecatedSharedPlanarYCbCrImage* AsDeprecatedSharedPlanarYCbCrImage() MOZ_OVERRIDE
   {
     return this;
   }
 
@@ -84,17 +79,17 @@ public:
   /**
    * Returns a DeprecatedSharedPlanarYCbCrImage* iff the descriptor was initialized with
    * ToSurfaceDescriptor.
    */
   static DeprecatedSharedPlanarYCbCrImage* FromSurfaceDescriptor(const SurfaceDescriptor& aDesc);
 
 private:
   ipc::Shmem mShmem;
-  ISurfaceAllocator* mSurfaceAllocator;
+  RefPtr<ISurfaceAllocator> mSurfaceAllocator;
   bool mAllocated;
 };
 
 
 class SharedPlanarYCbCrImage : public PlanarYCbCrImage
                              , public ISharedImage
 {
 public:
--- a/gfx/layers/ipc/SharedRGBImage.h
+++ b/gfx/layers/ipc/SharedRGBImage.h
@@ -86,17 +86,17 @@ public:
 
   bool AllocateBuffer(nsIntSize aSize, gfxImageFormat aImageFormat);
 
   TextureClient* GetTextureClient() MOZ_OVERRIDE { return nullptr; }
 
 protected:
   gfxIntSize mSize;
   gfxImageFormat mImageFormat;
-  ISurfaceAllocator* mSurfaceAllocator;
+  RefPtr<ISurfaceAllocator> mSurfaceAllocator;
 
   bool mAllocated;
   ipc::Shmem *mShmem;
 };
 
 /**
  * Stores RGB data in shared memory
  * It is assumed that the image width and stride are equal
--- a/gfx/layers/moz.build
+++ b/gfx/layers/moz.build
@@ -94,16 +94,18 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'wind
         ]
 
 EXPORTS.gfxipc += [
     'ipc/ShadowLayerUtils.h',
 ]
 
 EXPORTS.mozilla.layers += [
     'basic/BasicCompositor.h',
+    'basic/MacIOSurfaceTextureHostBasic.h',
+    'basic/TextureHostBasic.h',
     'client/CanvasClient.h',
     'client/CompositableClient.h',
     'client/ContentClient.h',
     'client/ImageClient.h',
     'client/TextureClient.h',
     'client/TiledContentClient.h',
     'composite/APZCTreeManager.h',
     'composite/AsyncCompositionManager.h',
@@ -196,16 +198,17 @@ UNIFIED_SOURCES += [
     'basic/BasicCanvasLayer.cpp',
     'basic/BasicColorLayer.cpp',
     'basic/BasicCompositor.cpp',
     'basic/BasicContainerLayer.cpp',
     'basic/BasicImages.cpp',
     'basic/BasicLayerManager.cpp',
     'basic/BasicLayersImpl.cpp',
     'basic/BasicThebesLayer.cpp',
+    'basic/TextureHostBasic.cpp',
     'BufferUnrotate.cpp',
     'client/CanvasClient.cpp',
     'client/ClientCanvasLayer.cpp',
     'client/ClientColorLayer.cpp',
     'client/ClientContainerLayer.cpp',
     'client/ClientImageLayer.cpp',
     'client/ClientLayerManager.cpp',
     'client/ClientThebesLayer.cpp',
@@ -270,16 +273,17 @@ UNIFIED_SOURCES += [
 
 SOURCES += [
     'basic/BasicImageLayer.cpp',
     'ImageContainer.cpp',
 ]
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':
     SOURCES += [
+        'basic/MacIOSurfaceTextureHostBasic.cpp',
         'opengl/MacIOSurfaceTextureClientOGL.cpp',
         'opengl/MacIOSurfaceTextureHostOGL.cpp',
     ]
 
 IPDL_SOURCES = [
     'ipc/LayersMessages.ipdlh',
     'ipc/LayersSurfaces.ipdlh',
     'ipc/PCompositable.ipdl',
--- a/gfx/layers/opengl/CompositorOGL.cpp
+++ b/gfx/layers/opengl/CompositorOGL.cpp
@@ -5,16 +5,17 @@
 
 #include "CompositorOGL.h"
 #include <stddef.h>                     // for size_t
 #include <stdint.h>                     // for uint32_t, uint8_t
 #include <stdlib.h>                     // for free, malloc
 #include "FPSCounter.h"                 // for FPSState, FPSCounter
 #include "GLContextProvider.h"          // for GLContextProvider
 #include "GLContext.h"                  // for GLContext
+#include "GLUploadHelpers.h"
 #include "Layers.h"                     // for WriteSnapshotToDumpFile
 #include "LayerScope.h"                 // for LayerScope
 #include "gfx2DGlue.h"                  // for ThebesFilter
 #include "gfx3DMatrix.h"                // for gfx3DMatrix
 #include "gfxASurface.h"                // for gfxASurface, etc
 #include "gfxCrashReporterUtils.h"      // for ScopedGfxFeatureReporter
 #include "gfxImageSurface.h"            // for gfxImageSurface
 #include "gfxMatrix.h"                  // for gfxMatrix
@@ -576,17 +577,17 @@ CompositorOGL::BindAndDrawQuadWithTextur
   // because we can't rely on full non-power-of-two texture support
   // (which is required for the REPEAT wrap mode).
 
   RectTriangles rects;
 
   GLenum wrapMode = aTexture->AsSourceOGL()->GetWrapMode();
 
   IntSize realTexSize = aTexture->GetSize();
-  if (!mGLContext->CanUploadNonPowerOfTwo()) {
+  if (!CanUploadNonPowerOfTwo(mGLContext)) {
     realTexSize = IntSize(NextPowerOfTwo(realTexSize.width),
                           NextPowerOfTwo(realTexSize.height));
   }
 
   // We need to convert back to actual texels here to get proper behaviour with
   // our GL helper functions. Should fix this sometime.
   // I want to vomit.
   IntRect texCoordRect = IntRect(NS_roundf(aTexCoordRect.x * aTexture->GetSize().width),
@@ -751,17 +752,17 @@ bool CompositorOGL::sDrawFPS = false;
  * Returns a size that is larger than and closest to aSize where both
  * width and height are powers of two.
  * If the OpenGL setup is capable of using non-POT textures, then it
  * will just return aSize.
  */
 static IntSize
 CalculatePOTSize(const IntSize& aSize, GLContext* gl)
 {
-  if (gl->CanUploadNonPowerOfTwo())
+  if (CanUploadNonPowerOfTwo(gl))
     return aSize;
 
   return IntSize(NextPowerOfTwo(aSize.width), NextPowerOfTwo(aSize.height));
 }
 
 void
 CompositorOGL::BeginFrame(const nsIntRegion& aInvalidRegion,
                           const Rect *aClipRectIn,
@@ -1496,17 +1497,17 @@ CompositorOGL::CreateDataTextureSource(T
     new TextureImageTextureSourceOGL(mGLContext,
                                      !(aFlags & TEXTURE_DISALLOW_BIGIMAGE));
   return result;
 }
 
 bool
 CompositorOGL::SupportsPartialTextureUpdate()
 {
-  return mGLContext->CanUploadSubTextures();
+  return CanUploadSubTextures(mGLContext);
 }
 
 int32_t
 CompositorOGL::GetMaxTextureSize() const
 {
   MOZ_ASSERT(mGLContext);
   GLint texSize = 0;
   mGLContext->fGetIntegerv(LOCAL_GL_MAX_TEXTURE_SIZE,
--- a/gfx/layers/opengl/TextureHostOGL.cpp
+++ b/gfx/layers/opengl/TextureHostOGL.cpp
@@ -1,15 +1,17 @@
 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "TextureHostOGL.h"
 #include "GLContext.h"                  // for GLContext, etc
+#include "GLSharedHandleHelpers.h"
+#include "GLUploadHelpers.h"
 #include "GLContextUtils.h"             // for GLContextUtils
 #include "SharedSurface.h"              // for SharedSurface
 #include "SharedSurfaceEGL.h"           // for SharedSurface_EGLImage
 #include "SharedSurfaceGL.h"            // for SharedSurface_GLTexture, etc
 #include "SurfaceStream.h"              // for SurfaceStream
 #include "SurfaceTypes.h"               // for SharedSurfaceType, etc
 #include "TiledLayerBuffer.h"           // for TILEDLAYERBUFFER_TILE_SIZE
 #include "gfx2DGlue.h"                  // for ContentForFormat, etc
@@ -239,20 +241,21 @@ TextureImageTextureSourceOGL::Update(gfx
   if (!mTexImage ||
       mTexImage->GetSize() != size ||
       mTexImage->GetContentType() != gfx::ContentForFormat(aSurface->GetFormat())) {
     if (mAllowBigImage) {
       // XXX - clarify which size we want to use. IncrementalContentHost will
       // require the size of the destination surface to be different from
       // the size of aSurface.
       // See bug 893300 (tracks the implementation of ContentHost for new textures).
-      mTexImage = mGL->CreateTextureImage(size,
-                                          gfx::ContentForFormat(aSurface->GetFormat()),
-                                          WrapMode(mGL, aFlags & TEXTURE_ALLOW_REPEAT),
-                                          FlagsToGLFlags(aFlags));
+      mTexImage = CreateTextureImage(mGL,
+                                     size,
+                                     gfx::ContentForFormat(aSurface->GetFormat()),
+                                     WrapMode(mGL, aFlags & TEXTURE_ALLOW_REPEAT),
+                                     FlagsToGLFlags(aFlags));
     } else {
       mTexImage = CreateBasicTextureImage(mGL,
                                           size,
                                           gfx::ContentForFormat(aSurface->GetFormat()),
                                           WrapMode(mGL, aFlags & TEXTURE_ALLOW_REPEAT),
                                           FlagsToGLFlags(aFlags));
     }
   }
@@ -320,30 +323,30 @@ SharedTextureSourceOGL::BindTexture(GLen
   if (!gl()) {
     NS_WARNING("Trying to bind a texture without a GLContext");
     return;
   }
   GLuint tex = mCompositor->GetTemporaryTexture(aTextureUnit);
 
   gl()->fActiveTexture(aTextureUnit);
   gl()->fBindTexture(mTextureTarget, tex);
-  if (!gl()->AttachSharedHandle(mShareType, mSharedHandle)) {
+  if (!AttachSharedHandle(gl(), mShareType, mSharedHandle)) {
     NS_ERROR("Failed to bind shared texture handle");
     return;
   }
   gl()->fActiveTexture(LOCAL_GL_TEXTURE0);
 }
 
 void
 SharedTextureSourceOGL::DetachSharedHandle()
 {
   if (!gl()) {
     return;
   }
-  gl()->DetachSharedHandle(mShareType, mSharedHandle);
+  gl::DetachSharedHandle(gl(), mShareType, mSharedHandle);
 }
 
 void
 SharedTextureSourceOGL::SetCompositor(CompositorOGL* aCompositor)
 {
   mCompositor = aCompositor;
 }
 
@@ -357,18 +360,18 @@ gl::GLContext*
 SharedTextureSourceOGL::gl() const
 {
   return mCompositor ? mCompositor->gl() : nullptr;
 }
 
 gfx3DMatrix
 SharedTextureSourceOGL::GetTextureTransform()
 {
-  GLContext::SharedHandleDetails handleDetails;
-  if (!gl()->GetSharedHandleDetails(mShareType, mSharedHandle, handleDetails)) {
+  SharedHandleDetails handleDetails;
+  if (!GetSharedHandleDetails(gl(), mShareType, mSharedHandle, handleDetails)) {
     NS_WARNING("Could not get shared handle details");
     return gfx3DMatrix();
   }
 
   return handleDetails.mTextureTransform;
 }
 
 SharedTextureHostOGL::SharedTextureHostOGL(uint64_t aID,
@@ -402,18 +405,18 @@ SharedTextureHostOGL::Lock()
 {
   if (!mCompositor) {
     return false;
   }
 
   if (!mTextureSource) {
     // XXX on android GetSharedHandleDetails can call into Java which we'd
     // rather not do from the compositor
-    GLContext::SharedHandleDetails handleDetails;
-    if (!gl()->GetSharedHandleDetails(mShareType, mSharedHandle, handleDetails)) {
+    SharedHandleDetails handleDetails;
+    if (!GetSharedHandleDetails(gl(), mShareType, mSharedHandle, handleDetails)) {
       NS_WARNING("Could not get shared handle details");
       return false;
     }
 
     GLenum wrapMode = LOCAL_GL_CLAMP_TO_EDGE;
     mTextureSource = new SharedTextureSourceOGL(mCompositor,
                                                 mSharedHandle,
                                                 handleDetails.mTextureFormat,
@@ -495,20 +498,21 @@ TextureImageDeprecatedTextureHostOGL::Se
 
 void
 TextureImageDeprecatedTextureHostOGL::EnsureBuffer(const nsIntSize& aSize,
                                          gfxContentType aContentType)
 {
   if (!mTexture ||
       mTexture->GetSize() != aSize ||
       mTexture->GetContentType() != aContentType) {
-    mTexture = mGL->CreateTextureImage(aSize,
-                                       aContentType,
-                                       WrapMode(mGL, mFlags & TEXTURE_ALLOW_REPEAT),
-                                       FlagsToGLFlags(mFlags));
+    mTexture = CreateTextureImage(mGL,
+                                  aSize,
+                                  aContentType,
+                                  WrapMode(mGL, mFlags & TEXTURE_ALLOW_REPEAT),
+                                  FlagsToGLFlags(mFlags));
   }
   mTexture->Resize(aSize);
 }
 
 void
 TextureImageDeprecatedTextureHostOGL::CopyTo(const nsIntRect& aSourceRect,
                                    DeprecatedTextureHost *aDest,
                                    const nsIntRect& aDestRect)
@@ -551,21 +555,22 @@ TextureImageDeprecatedTextureHostOGL::Up
   TextureImage::ImageFormat format = surf.ImageFormat();
 
   if (!mTexture ||
       (mTexture->GetSize() != size && !aOffset) ||
       mTexture->GetContentType() != surf.ContentType() ||
       (mTexture->GetImageFormat() != format &&
        mTexture->GetImageFormat() != gfxImageFormatUnknown)) {
 
-    mTexture = mGL->CreateTextureImage(size,
-                                       surf.ContentType(),
-                                       WrapMode(mGL, mFlags & TEXTURE_ALLOW_REPEAT),
-                                       FlagsToGLFlags(mFlags),
-                                       format);
+    mTexture = CreateTextureImage(mGL,
+                                  size,
+                                  surf.ContentType(),
+                                  WrapMode(mGL, mFlags & TEXTURE_ALLOW_REPEAT),
+                                  FlagsToGLFlags(mFlags),
+                                  format);
   }
 
   // XXX this is always just ridiculously slow
   nsIntRegion updateRegion;
 
   if (!aRegion) {
     updateRegion = nsIntRegion(nsIntRect(0, 0, size.width, size.height));
   } else {
@@ -611,17 +616,17 @@ SharedDeprecatedTextureHostOGL::DeleteTe
 {
   MOZ_ASSERT(mGL);
   if (!mGL->MakeCurrent()) {
     mSharedHandle = 0;
     mTextureHandle = 0;
     return;
   }
   if (mSharedHandle) {
-    mGL->ReleaseSharedHandle(mShareType, mSharedHandle);
+    ReleaseSharedHandle(mGL, mShareType, mSharedHandle);
     mSharedHandle = 0;
   }
   if (mTextureHandle) {
     mGL->fDeleteTextures(1, &mTextureHandle);
     mTextureHandle = 0;
   }
 }
 
@@ -645,60 +650,60 @@ SharedDeprecatedTextureHostOGL::SwapText
   SharedTextureHandle newHandle = texture.handle();
   nsIntSize size = texture.size();
   mSize = gfx::IntSize(size.width, size.height);
   if (texture.inverted()) {
     mFlags |= TEXTURE_NEEDS_Y_FLIP;
   }
 
   if (mSharedHandle && mSharedHandle != newHandle) {
-    mGL->ReleaseSharedHandle(mShareType, mSharedHandle);
+    ReleaseSharedHandle(mGL, mShareType, mSharedHandle);
   }
 
   mShareType = texture.shareType();
   mSharedHandle = newHandle;
 
-  GLContext::SharedHandleDetails handleDetails;
-  if (mSharedHandle && mGL->GetSharedHandleDetails(mShareType, mSharedHandle, handleDetails)) {
+  SharedHandleDetails handleDetails;
+  if (mSharedHandle && GetSharedHandleDetails(mGL, mShareType, mSharedHandle, handleDetails)) {
     mTextureTarget = handleDetails.mTarget;
     mFormat = handleDetails.mTextureFormat;
   }
 }
 
 bool
 SharedDeprecatedTextureHostOGL::Lock()
 {
   MakeTextureIfNeeded(mGL, mTextureTarget, mTextureHandle);
 
   mGL->fActiveTexture(LOCAL_GL_TEXTURE0);
   mGL->fBindTexture(mTextureTarget, mTextureHandle);
-  if (!mGL->AttachSharedHandle(mShareType, mSharedHandle)) {
+  if (!AttachSharedHandle(mGL, mShareType, mSharedHandle)) {
     NS_ERROR("Failed to bind shared texture handle");
     return false;
   }
 
   return true;
 }
 
 void
 SharedDeprecatedTextureHostOGL::Unlock()
 {
-  mGL->DetachSharedHandle(mShareType, mSharedHandle);
+  DetachSharedHandle(mGL, mShareType, mSharedHandle);
   mGL->fBindTexture(LOCAL_GL_TEXTURE_2D, 0);
 }
 
 
 gfx3DMatrix
 SharedDeprecatedTextureHostOGL::GetTextureTransform()
 {
-  GLContext::SharedHandleDetails handleDetails;
+  SharedHandleDetails handleDetails;
   // GetSharedHandleDetails can call into Java which we'd
   // rather not do from the compositor
   if (mSharedHandle) {
-    mGL->GetSharedHandleDetails(mShareType, mSharedHandle, handleDetails);
+    GetSharedHandleDetails(mGL, mShareType, mSharedHandle, handleDetails);
   }
   return handleDetails.mTextureTransform;
 }
 
 
 void
 SurfaceStreamHostOGL::SetCompositor(Compositor* aCompositor)
 {
@@ -814,20 +819,21 @@ SurfaceStreamHostOGL::Lock()
       MOZ_CRASH("Invalid SharedSurface type.");
   }
 
   if (toUpload) {
     // mBounds seems to end up as (0,0,0,0) a lot, so don't use it?
     nsIntSize size(toUpload->GetSize());
     nsIntRect rect(nsIntPoint(0,0), size);
     nsIntRegion bounds(rect);
-    mFormat = mGL->UploadSurfaceToTexture(toUpload,
-                                          bounds,
-                                          mUploadTexture,
-                                          true);
+    mFormat = UploadSurfaceToTexture(mGL,
+                                     toUpload,
+                                     bounds,
+                                     mUploadTexture,
+                                     true);
     mTextureHandle = mUploadTexture;
     mTextureTarget = LOCAL_GL_TEXTURE_2D;
   }
 
   MOZ_ASSERT(mTextureHandle);
   mGL->fBindTexture(mTextureTarget, mTextureHandle);
   mGL->fTexParameteri(mTextureTarget,
                       LOCAL_GL_TEXTURE_WRAP_S,
--- a/gfx/src/nsITheme.h
+++ b/gfx/src/nsITheme.h
@@ -152,16 +152,22 @@ public:
    * Does the nsITheme implementation draw its own focus ring for this widget?
    */
   virtual bool ThemeDrawsFocusForWidget(uint8_t aWidgetType)=0;
   
   /**
     * Should we insert a dropmarker inside of combobox button?
    */
   virtual bool ThemeNeedsComboboxDropmarker()=0;
+
+  /**
+   * Should we hide scrollbars?
+   */
+  virtual bool ShouldHideScrollbars()
+  { return false; }
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsITheme, NS_ITHEME_IID)
 
 // Creator function
 extern nsresult NS_NewNativeTheme(nsISupports *aOuter, REFNSIID aIID, void **aResult);
 
 #endif
--- a/gfx/thebes/gfxPlatform.cpp
+++ b/gfx/thebes/gfxPlatform.cpp
@@ -2032,16 +2032,17 @@ gfxPlatform::GetOrientationSyncMillis() 
 static bool sPrefLayersOffMainThreadCompositionEnabled = false;
 static bool sPrefLayersOffMainThreadCompositionTestingEnabled = false;
 static bool sPrefLayersOffMainThreadCompositionForceEnabled = false;
 static bool sPrefLayersAccelerationForceEnabled = false;
 static bool sPrefLayersAccelerationDisabled = false;
 static bool sPrefLayersPreferOpenGL = false;
 static bool sPrefLayersPreferD3D9 = false;
 static bool sPrefLayersDump = false;
+static bool sPrefLayersScrollGraph = false;
 static bool sLayersSupportsD3D9 = false;
 static int  sPrefLayoutFrameRate = -1;
 static bool sBufferRotationEnabled = false;
 static bool sComponentAlphaEnabled = true;
 static bool sPrefBrowserTabsRemote = false;
 
 static bool sLayersAccelerationPrefsInitialized = false;
 
@@ -2059,16 +2060,17 @@ InitLayersAccelerationPrefs()
     sPrefLayersOffMainThreadCompositionEnabled = Preferences::GetBool("layers.offmainthreadcomposition.enabled", false);
     sPrefLayersOffMainThreadCompositionTestingEnabled = Preferences::GetBool("layers.offmainthreadcomposition.testing.enabled", false);
     sPrefLayersOffMainThreadCompositionForceEnabled = Preferences::GetBool("layers.offmainthreadcomposition.force-enabled", false);
     sPrefLayersAccelerationForceEnabled = Preferences::GetBool("layers.acceleration.force-enabled", false);
     sPrefLayersAccelerationDisabled = Preferences::GetBool("layers.acceleration.disabled", false);
     sPrefLayersPreferOpenGL = Preferences::GetBool("layers.prefer-opengl", false);
     sPrefLayersPreferD3D9 = Preferences::GetBool("layers.prefer-d3d9", false);
     sPrefLayersDump = Preferences::GetBool("layers.dump", false);
+    sPrefLayersScrollGraph = Preferences::GetBool("layers.scroll-graph", false);
     sPrefLayoutFrameRate = Preferences::GetInt("layout.frame_rate", -1);
     sBufferRotationEnabled = Preferences::GetBool("layers.bufferrotation.enabled", true);
     sComponentAlphaEnabled = Preferences::GetBool("layers.componentalpha.enabled", true);
     sPrefBrowserTabsRemote = Preferences::GetBool("browser.tabs.remote", false);
 
 #ifdef XP_WIN
     if (sPrefLayersAccelerationForceEnabled) {
       sLayersSupportsD3D9 = true;
@@ -2164,16 +2166,25 @@ gfxPlatform::GetPrefLayoutFrameRate()
 bool
 gfxPlatform::GetPrefLayersDump()
 {
   InitLayersAccelerationPrefs();
   return sPrefLayersDump;
 }
 
 bool
+gfxPlatform::GetPrefLayersScrollGraph()
+{
+  // this function is called from the compositor thread, so it is not
+  // safe to init the prefs etc. from here.
+  MOZ_ASSERT(sLayersAccelerationPrefsInitialized);
+  return sPrefLayersScrollGraph;
+}
+
+bool
 gfxPlatform::BufferRotationEnabled()
 {
   MutexAutoLock autoLock(*gGfxPlatformPrefsLock);
 
   InitLayersAccelerationPrefs();
   return sBufferRotationEnabled;
 }
 
--- a/gfx/thebes/gfxPlatform.h
+++ b/gfx/thebes/gfxPlatform.h
@@ -501,16 +501,17 @@ public:
     static bool GetPrefLayersOffMainThreadCompositionForceEnabled();
     static bool GetPrefLayersAccelerationForceEnabled();
     static bool GetPrefLayersAccelerationDisabled();
     static bool GetPrefLayersPreferOpenGL();
     static bool GetPrefLayersPreferD3D9();
     static bool CanUseDirect3D9();
     static int  GetPrefLayoutFrameRate();
     static bool GetPrefLayersDump();
+    static bool GetPrefLayersScrollGraph();
 
     static bool OffMainThreadCompositionRequired();
 
     /**
      * Is it possible to use buffer rotation
      */
     static bool BufferRotationEnabled();
     static void DisableBufferRotation();
--- a/gfx/thebes/gfxReusableSharedImageSurfaceWrapper.cpp
+++ b/gfx/thebes/gfxReusableSharedImageSurfaceWrapper.cpp
@@ -51,17 +51,17 @@ gfxReusableSharedImageSurfaceWrapper::Ge
   NS_ABORT_IF_FALSE(readCount > 0, "A ReadLock must be held when calling GetWritable");
   if (readCount == 1) {
     *aSurface = mSurface;
     return this;
   }
 
   // Something else is reading the surface, copy it
   nsRefPtr<gfxSharedImageSurface> copySurface =
-    gfxSharedImageSurface::CreateUnsafe(mAllocator, mSurface->GetSize(), mSurface->Format());
+    gfxSharedImageSurface::CreateUnsafe(mAllocator.get(), mSurface->GetSize(), mSurface->Format());
   copySurface->CopyFrom(mSurface);
   *aSurface = copySurface;
 
   // We need to create a new wrapper since this wrapper has an external ReadLock
   gfxReusableSurfaceWrapper* wrapper = new gfxReusableSharedImageSurfaceWrapper(mAllocator, copySurface);
 
   // No need to release the ReadLock on the surface, this will happen when
   // the wrapper is destroyed.
--- a/gfx/thebes/gfxReusableSharedImageSurfaceWrapper.h
+++ b/gfx/thebes/gfxReusableSharedImageSurfaceWrapper.h
@@ -1,16 +1,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef GFXSHMCOWSURFACEWRAPPER
 #define GFXSHMCOWSURFACEWRAPPER
 
 #include "gfxReusableSurfaceWrapper.h"
+#include "mozilla/RefPtr.h"
 
 class gfxSharedImageSurface;
 
 namespace mozilla {
 namespace ipc {
 class Shmem;
 }
 namespace layers {
@@ -48,13 +49,13 @@ public:
    * Create a gfxReusableSurfaceWrapper from the shared memory segment of a
    * gfxSharedImageSurface. A ReadLock must be held, which will be adopted by
    * the returned gfxReusableSurfaceWrapper.
    */
   static already_AddRefed<gfxReusableSharedImageSurfaceWrapper>
   Open(mozilla::layers::ISurfaceAllocator* aAllocator, const mozilla::ipc::Shmem& aShmem);
 
 private:
-  mozilla::layers::ISurfaceAllocator*     mAllocator;
+  mozilla::RefPtr<mozilla::layers::ISurfaceAllocator> mAllocator;
   nsRefPtr<gfxSharedImageSurface>         mSurface;
 };
 
 #endif // GFXSHMCOWSURFACEWRAPPER
--- a/image/src/SurfaceCache.cpp
+++ b/image/src/SurfaceCache.cpp
@@ -28,42 +28,16 @@
 #include "nsTArray.h"
 #include "prsystem.h"
 #include "SVGImageContext.h"
 
 using std::max;
 using std::min;
 using mozilla::gfx::DrawTarget;
 
-/**
- * Hashtable key class to use with objects for which Hash() and operator==()
- * are defined.
- * XXX(seth): This will get moved to xpcom/glue/nsHashKeys.h in a followup bug.
- */
-template <typename T>
-class nsGenericHashKey : public PLDHashEntryHdr
-{
-public:
-  typedef const T& KeyType;
-  typedef const T* KeyTypePointer;
-
-  nsGenericHashKey(KeyTypePointer aKey) : mKey(*aKey) { }
-  nsGenericHashKey(const nsGenericHashKey<T>& aOther) : mKey(aOther.mKey) { }
-
-  KeyType GetKey() const { return mKey; }
-  bool KeyEquals(KeyTypePointer aKey) const { return *aKey == mKey; }
-
-  static KeyTypePointer KeyToPointer(KeyType aKey) { return &aKey; }
-  static PLDHashNumber HashKey(KeyTypePointer aKey) { return aKey->Hash(); }
-  enum { ALLOW_MEMMOVE = true };
-
-private:
-  T mKey;
-};
-
 namespace mozilla {
 namespace image {
 
 class CachedSurface;
 class SurfaceCacheImpl;
 
 ///////////////////////////////////////////////////////////////////////////////
 // Static Data
--- a/js/ipc/JavaScriptShared.cpp
+++ b/js/ipc/JavaScriptShared.cpp
@@ -25,29 +25,29 @@ ObjectStore::init()
 {
     return table_.init(32);
 }
 
 void
 ObjectStore::trace(JSTracer *trc)
 {
     for (ObjectTable::Range r(table_.all()); !r.empty(); r.popFront()) {
-        DebugOnly<JSObject *> prior = r.front().value.get();
-        JS_CallHeapObjectTracer(trc, &r.front().value, "ipc-object");
-        MOZ_ASSERT(r.front().value == prior);
+        DebugOnly<JSObject *> prior = r.front().value().get();
+        JS_CallHeapObjectTracer(trc, &r.front().value(), "ipc-object");
+        MOZ_ASSERT(r.front().value() == prior);
     }
 }
 
 JSObject *
 ObjectStore::find(ObjectId id)
 {
     ObjectTable::Ptr p = table_.lookup(id);
     if (!p)
         return nullptr;
-    return p->value;
+    return p->value();
 }
 
 bool
 ObjectStore::add(ObjectId id, JSObject *obj)
 {
     return table_.put(id, obj);
 }
 
@@ -77,29 +77,29 @@ ObjectIdCache::init()
     table_ = new ObjectIdTable(SystemAllocPolicy());
     return table_ && table_->init(32);
 }
 
 void
 ObjectIdCache::trace(JSTracer *trc)
 {
     for (ObjectIdTable::Range r(table_->all()); !r.empty(); r.popFront()) {
-        JSObject *obj = r.front().key;
+        JSObject *obj = r.front().key();
         JS_CallObjectTracer(trc, &obj, "ipc-id");
-        MOZ_ASSERT(obj == r.front().key);
+        MOZ_ASSERT(obj == r.front().key());
     }
 }
 
 ObjectId
 ObjectIdCache::find(JSObject *obj)
 {
     ObjectIdTable::Ptr p = table_->lookup(obj);
     if (!p)
         return 0;
-    return p->value;
+    return p->value();
 }
 
 bool
 ObjectIdCache::add(JSContext *cx, JSObject *obj, ObjectId id)
 {
     if (!table_->put(obj, id))
         return false;
     JS_StoreObjectPostBarrierCallback(cx, keyMarkCallback, obj, table_);
--- a/js/public/HashTable.h
+++ b/js/public/HashTable.h
@@ -55,18 +55,18 @@ template <class Key,
           class AllocPolicy = TempAllocPolicy>
 class HashMap
 {
     typedef HashMapEntry<Key, Value> TableEntry;
 
     struct MapHashPolicy : HashPolicy
     {
         typedef Key KeyType;
-        static const Key &getKey(TableEntry &e) { return e.key; }
-        static void setKey(TableEntry &e, Key &k) { HashPolicy::rekey(const_cast<Key &>(e.key), k); }
+        static const Key &getKey(TableEntry &e) { return e.key(); }
+        static void setKey(TableEntry &e, Key &k) { HashPolicy::rekey(e.mutableKey(), k); }
     };
 
     typedef detail::HashTable<TableEntry, MapHashPolicy, AllocPolicy> Impl;
     Impl impl;
 
   public:
     typedef typename HashPolicy::Lookup Lookup;
     typedef TableEntry Entry;
@@ -146,17 +146,17 @@ class HashMap
     bool add(AddPtr &p, KeyInput &&k) {
         Entry e(mozilla::Forward<KeyInput>(k), Value());
         return impl.add(p, mozilla::Move(e));
     }
 
     template<typename KeyInput, typename ValueInput>
     bool relookupOrAdd(AddPtr &p, KeyInput &&k, ValueInput &&v) {
         Entry e(mozilla::Forward<KeyInput>(k), mozilla::Forward<ValueInput>(v));
-        return impl.relookupOrAdd(p, e.key, mozilla::Move(e));
+        return impl.relookupOrAdd(p, e.key(), mozilla::Move(e));
     }
 
     // |all()| returns a Range containing |count()| elements. E.g.:
     //
     //   typedef HashMap<int,char> HM;
     //   HM h;
     //   for (HM::Range r = h.all(); !r.empty(); r.popFront())
     //     char c = r.front().value;
@@ -218,27 +218,27 @@ class HashMap
         return impl.lookup(l) != nullptr;
     }
 
     // Overwrite existing value with v. Return false on oom.
     template<typename KeyInput, typename ValueInput>
     bool put(KeyInput &&k, ValueInput &&v) {
         AddPtr p = lookupForAdd(k);
         if (p) {
-            p->value = mozilla::Forward<ValueInput>(v);
+            p->value() = mozilla::Forward<ValueInput>(v);
             return true;
         }
         return add(p, mozilla::Forward<KeyInput>(k), mozilla::Forward<ValueInput>(v));
     }
 
     // Like put, but assert that the given key is not already present.
     template<typename KeyInput, typename ValueInput>
     bool putNew(KeyInput &&k, ValueInput &&v) {
         Entry e(mozilla::Forward<KeyInput>(k), mozilla::Forward<ValueInput>(v));
-        return impl.putNew(e.key, mozilla::Move(e));
+        return impl.putNew(e.key(), mozilla::Move(e));
     }
 
     // Add (k,defaultValue) if |k| is not found. Return a false-y Ptr on oom.
     Ptr lookupWithDefault(const Key &k, const Value &defaultValue) {
         AddPtr p = lookupForAdd(k);
         if (p)
             return p;
         (void)add(p, k, defaultValue);  // p is left false-y on oom.
@@ -611,35 +611,47 @@ struct DefaultHasher<float>
 // Both HashMap and HashSet are implemented by a single HashTable that is even
 // more heavily parameterized than the other two. This leaves HashTable gnarly
 // and extremely coupled to HashMap and HashSet; thus code should not use
 // HashTable directly.
 
 template <class Key, class Value>
 class HashMapEntry
 {
+    Key key_;
+    Value value_;
+
     template <class, class, class> friend class detail::HashTable;
     template <class> friend class detail::HashTableEntry;
+    template <class, class, class, class> friend class HashMap;
 
-    HashMapEntry(const HashMapEntry &) MOZ_DELETE;
-    void operator=(const HashMapEntry &) MOZ_DELETE;
+    Key & mutableKey() { return key_; }
 
   public:
     template<typename KeyInput, typename ValueInput>
     HashMapEntry(KeyInput &&k, ValueInput &&v)
-      : key(mozilla::Forward<KeyInput>(k)), value(mozilla::Forward<ValueInput>(v)) { }
+      : key_(mozilla::Forward<KeyInput>(k)),
+        value_(mozilla::Forward<ValueInput>(v))
+    {}
 
     HashMapEntry(HashMapEntry &&rhs)
-      : key(mozilla::Move(const_cast<Key &>(rhs.key))), value(mozilla::Move(rhs.value)) { }
+      : key_(mozilla::Move(rhs.key_)),
+        value_(mozilla::Move(rhs.value_))
+    {}
 
     typedef Key KeyType;
     typedef Value ValueType;
 
-    const Key key;
-    Value value;
+    const Key & key() const { return key_; }
+    const Value & value() const { return value_; }
+    Value & value() { return value_; }
+
+  private:
+    HashMapEntry(const HashMapEntry &) MOZ_DELETE;
+    void operator=(const HashMapEntry &) MOZ_DELETE;
 };
 
 } // namespace js
 
 namespace mozilla {
 
 template <typename T>
 struct IsPod<js::detail::HashTableEntry<T> > : IsPod<T> {};
--- a/js/public/MemoryMetrics.h
+++ b/js/public/MemoryMetrics.h
@@ -338,23 +338,23 @@ struct ZoneStats : js::ZoneStatsPod
     // same string.)
     void add(const ZoneStats &other) {
         ZoneStatsPod::add(other);
 
         MOZ_ASSERT(notableStrings.empty());
         MOZ_ASSERT(other.notableStrings.empty());
 
         for (StringsHashMap::Range r = other.strings.all(); !r.empty(); r.popFront()) {
-            StringsHashMap::AddPtr p = strings.lookupForAdd(r.front().key);
+            StringsHashMap::AddPtr p = strings.lookupForAdd(r.front().key());
             if (p) {
                 // We've seen this string before; add its size to our tally.
-                p->value.add(r.front().value);
+                p->value().add(r.front().value());
             } else {
                 // We haven't seen this string before; add it to the hashtable.
-                strings.add(p, r.front().key, r.front().value);
+                strings.add(p, r.front().key(), r.front().value());
             }
         }
     }
 
     size_t sizeOfLiveGCThings() const {
         size_t n = ZoneStatsPod::sizeOfLiveGCThings();
         for (size_t i = 0; i < notableStrings.length(); i++) {
             const JS::NotableStringInfo& info = notableStrings[i];
new file mode 100644
--- /dev/null
+++ b/js/public/SliceBudget.h
@@ -0,0 +1,57 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef js_SliceBudget_h
+#define js_SliceBudget_h
+
+#include <stdint.h>
+
+namespace js {
+
+/*
+ * This class records how much work has been done in a given collection slice, so that
+ * we can return before pausing for too long. Some slices are allowed to run for
+ * unlimited time, and others are bounded. To reduce the number of gettimeofday
+ * calls, we only check the time every 1000 operations.
+ */
+struct JS_PUBLIC_API(SliceBudget)
+{
+    int64_t deadline; /* in microseconds */
+    intptr_t counter;
+
+    static const intptr_t CounterReset = 1000;
+
+    static const int64_t Unlimited = 0;
+    static int64_t TimeBudget(int64_t millis);
+    static int64_t WorkBudget(int64_t work);
+
+    /* Equivalent to SliceBudget(UnlimitedBudget). */
+    SliceBudget();
+
+    /* Instantiate as SliceBudget(Time/WorkBudget(n)). */
+    SliceBudget(int64_t budget);
+
+    void reset() {
+        deadline = INT64_MAX;
+        counter = INTPTR_MAX;
+    }
+
+    void step(intptr_t amt = 1) {
+        counter -= amt;
+    }
+
+    bool checkOverBudget();
+
+    bool isOverBudget() {
+        if (counter >= 0)
+            return false;
+        return checkOverBudget();
+    }
+};
+
+} // namespace js
+
+#endif /* js_SliceBudget_h */
--- a/js/src/ctypes/CTypes.cpp
+++ b/js/src/ctypes/CTypes.cpp
@@ -2918,24 +2918,24 @@ BuildTypeSource(JSContext* cx,
 
     const FieldInfoHash* fields = StructType::GetFieldInfo(typeObj);
     size_t length = fields->count();
     Array<const FieldInfoHash::Entry*, 64> fieldsArray;
     if (!fieldsArray.resize(length))
       break;
 
     for (FieldInfoHash::Range r = fields->all(); !r.empty(); r.popFront())
-      fieldsArray[r.front().value.mIndex] = &r.front();
+      fieldsArray[r.front().value().mIndex] = &r.front();
 
     for (size_t i = 0; i < length; ++i) {
       const FieldInfoHash::Entry* entry = fieldsArray[i];
       AppendString(result, "{ \"");
-      AppendString(result, entry->key);
+      AppendString(result, entry->key());
       AppendString(result, "\": ");
-      BuildTypeSource(cx, entry->value.mType, true, result);
+      BuildTypeSource(cx, entry->value().mType, true, result);
       AppendString(result, " }");
       if (i != length - 1)
         AppendString(result, ", ");
     }
 
     AppendString(result, "])");
     break;
   }
@@ -3068,29 +3068,29 @@ BuildDataSource(JSContext* cx,
     // be able to ImplicitConvert successfully.
     const FieldInfoHash* fields = StructType::GetFieldInfo(typeObj);
     size_t length = fields->count();
     Array<const FieldInfoHash::Entry*, 64> fieldsArray;
     if (!fieldsArray.resize(length))
       return false;
 
     for (FieldInfoHash::Range r = fields->all(); !r.empty(); r.popFront())
-      fieldsArray[r.front().value.mIndex] = &r.front();
+      fieldsArray[r.front().value().mIndex] = &r.front();
 
     for (size_t i = 0; i < length; ++i) {
       const FieldInfoHash::Entry* entry = fieldsArray[i];
 
       if (isImplicit) {
         AppendString(result, "\"");
-        AppendString(result, entry->key);
+        AppendString(result, entry->key());
         AppendString(result, "\": ");
       }
 
-      char* fieldData = static_cast<char*>(data) + entry->value.mOffset;
-      RootedObject entryType(cx, entry->value.mType);
+      char* fieldData = static_cast<char*>(data) + entry->value().mOffset;
+      RootedObject entryType(cx, entry->value().mType);
       if (!BuildDataSource(cx, entryType, fieldData, true, result))
         return false;
 
       if (i + 1 != length)
         AppendString(result, ", ");
     }
 
     if (isImplicit)
@@ -3347,21 +3347,21 @@ CType::Trace(JSTracer* trc, JSObject* ob
   case TYPE_struct: {
     slot = obj->getReservedSlot(SLOT_FIELDINFO);
     if (JSVAL_IS_VOID(slot))
       return;
 
     FieldInfoHash* fields =
       static_cast<FieldInfoHash*>(JSVAL_TO_PRIVATE(slot));
     for (FieldInfoHash::Enum e(*fields); !e.empty(); e.popFront()) {
-      JSString *key = e.front().key;
+      JSString *key = e.front().key();
       JS_CallStringTracer(trc, &key, "fieldName");
-      if (key != e.front().key)
+      if (key != e.front().key())
           e.rekeyFront(JS_ASSERT_STRING_IS_FLAT(key));
-      JS_CallHeapObjectTracer(trc, &e.front().value.mType, "fieldType");
+      JS_CallHeapObjectTracer(trc, &e.front().value().mType, "fieldType");
     }
 
     break;
   }
   case TYPE_function: {
     // Check if we have a FunctionInfo.
     slot = obj->getReservedSlot(SLOT_FNINFO);
     if (JSVAL_IS_VOID(slot))
@@ -4926,20 +4926,20 @@ StructType::BuildFFIType(JSContext* cx, 
     if (!elements) {
       JS_ReportOutOfMemory(cx);
       return nullptr;
     }
     elements[len] = nullptr;
 
     for (FieldInfoHash::Range r = fields->all(); !r.empty(); r.popFront()) {
       const FieldInfoHash::Entry& entry = r.front();
-      ffi_type* fieldType = CType::GetFFIType(cx, entry.value.mType);
+      ffi_type* fieldType = CType::GetFFIType(cx, entry.value().mType);
       if (!fieldType)
         return nullptr;
-      elements[entry.value.mIndex] = fieldType;
+      elements[entry.value().mIndex] = fieldType;
     }
 
   } else {
     // Represent an empty struct as having a size of 1 byte, just like C++.
     JS_ASSERT(structSize == 1);
     JS_ASSERT(structAlign == 1);
     elements = cx->pod_malloc<ffi_type*>(2);
     if (!elements) {
@@ -5067,17 +5067,17 @@ StructType::ConstructData(JSContext* cx,
 
     // Fall through to try option 2).
   }
 
   // We have a type constructor of the form 'ctypes.StructType(a, b, c, ...)'.
   // ImplicitConvert each field.
   if (args.length() == fields->count()) {
     for (FieldInfoHash::Range r = fields->all(); !r.empty(); r.popFront()) {
-      const FieldInfo& field = r.front().value;
+      const FieldInfo& field = r.front().value();
       STATIC_ASSUME(field.mIndex < fields->count());  /* Quantified invariant */
       if (!ImplicitConvert(cx, args[field.mIndex], field.mType,
              buffer + field.mOffset,
              false, nullptr))
         return false;
     }
 
     return true;
@@ -5103,17 +5103,17 @@ StructType::GetFieldInfo(JSObject* obj)
 const FieldInfo*
 StructType::LookupField(JSContext* cx, JSObject* obj, JSFlatString *name)
 {
   JS_ASSERT(CType::IsCType(obj));
   JS_ASSERT(CType::GetTypeCode(obj) == TYPE_struct);
 
   FieldInfoHash::Ptr ptr = GetFieldInfo(obj)->lookup(name);
   if (ptr)
-    return &ptr->value;
+    return &ptr->value();
 
   JSAutoByteString bytes(cx, name);
   if (!bytes)
     return nullptr;
 
   JS_ReportError(cx, "%s does not name a field", bytes.ptr());
   return nullptr;
 }
@@ -5131,18 +5131,18 @@ StructType::BuildFieldsArray(JSContext* 
   // Prepare a new array for the 'fields' property of the StructType.
   JS::AutoValueVector fieldsVec(cx);
   if (!fieldsVec.resize(len))
     return nullptr;
 
   for (FieldInfoHash::Range r = fields->all(); !r.empty(); r.popFront()) {
     const FieldInfoHash::Entry& entry = r.front();
     // Add the field descriptor to the array.
-    if (!AddFieldToArray(cx, &fieldsVec[entry.value.mIndex],
-                         entry.key, entry.value.mType))
+    if (!AddFieldToArray(cx, &fieldsVec[entry.value().mIndex],
+                         entry.key(), entry.value().mType))
       return nullptr;
   }
 
   RootedObject fieldsProp(cx, JS_NewArrayObject(cx, len, fieldsVec.begin()));
   if (!fieldsProp)
     return nullptr;
 
   // Seal the fields array.
--- a/js/src/ds/InlineMap.h
+++ b/js/src/ds/InlineMap.h
@@ -129,22 +129,22 @@ class InlineMap
         }
 
         operator ConvertibleToBool() const {
             return ConvertibleToBool(found());
         }
 
         K &key() {
             JS_ASSERT(found());
-            return isInlinePtr ? inlPtr->key : mapPtr->key;
+            return isInlinePtr ? inlPtr->key : mapPtr->key();
         }
 
         V &value() {
             JS_ASSERT(found());
-            return isInlinePtr ? inlPtr->value : mapPtr->value;
+            return isInlinePtr ? inlPtr->value : mapPtr->value();
         }
     }; /* class Ptr */
 
     class AddPtr
     {
         friend class InlineMap;
 
         WordMapAddPtr   mapAddPtr;
@@ -173,17 +173,17 @@ class InlineMap
         operator ConvertibleToBool() const {
             return found() ? ConvertibleToBool(1) : ConvertibleToBool(0);
         }
 
         V &value() {
             JS_ASSERT(found());
             if (isInlinePtr)
                 return inlAddPtr->value;
-            return mapAddPtr->value;
+            return mapAddPtr->value();
         }
     }; /* class AddPtr */
 
     size_t count() {
         return usingMap() ? map.count() : inlCount;
     }
 
     bool empty() const {
@@ -351,17 +351,17 @@ class InlineMap
         bool empty() const {
             return isInlineRange() ? cur == end : mapRange.empty();
         }
 
         Entry front() {
             JS_ASSERT(!empty());
             if (isInlineRange())
                 return Entry(cur->key, cur->value);
-            return Entry(mapRange.front().key, mapRange.front().value);
+            return Entry(mapRange.front().key(), mapRange.front().value());
         }
 
         void popFront() {
             JS_ASSERT(!empty());
             if (isInlineRange())
                 bumpCurPtr();
             else
                 mapRange.popFront();
--- a/js/src/frontend/ParseMaps.cpp
+++ b/js/src/frontend/ParseMaps.cpp
@@ -110,18 +110,18 @@ AtomDecls<ParseHandler>::addShadow(JSAto
 
 void
 frontend::InitAtomMap(frontend::AtomIndexMap *indices, HeapPtrAtom *atoms)
 {
     if (indices->isMap()) {
         typedef AtomIndexMap::WordMap WordMap;
         const WordMap &wm = indices->asMap();
         for (WordMap::Range r = wm.all(); !r.empty(); r.popFront()) {
-            JSAtom *atom = r.front().key;
-            jsatomid index = r.front().value;
+            JSAtom *atom = r.front().key();
+            jsatomid index = r.front().value();
             JS_ASSERT(index < indices->count());
             atoms[index].init(atom);
         }
     } else {
         for (const AtomIndexMap::InlineElem *it = indices->asInline(), *end = indices->inlineEnd();
              it != end; ++it) {
             JSAtom *atom = it->key;
             if (!atom)
--- a/js/src/gc/Marking.cpp
+++ b/js/src/gc/Marking.cpp
@@ -4,16 +4,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "gc/Marking.h"
 
 #include "mozilla/DebugOnly.h"
 
 #include "jit/IonCode.h"
+#include "js/SliceBudget.h"
 #include "vm/ArgumentsObject.h"
 #include "vm/ScopeObject.h"
 #include "vm/Shape.h"
 #include "vm/TypedArrayObject.h"
 
 #include "jscompartmentinlines.h"
 #include "jsinferinlines.h"
 #include "jsobjinlines.h"
--- a/js/src/gc/RootMarking.cpp
+++ b/js/src/gc/RootMarking.cpp
@@ -469,33 +469,33 @@ AutoGCRooter::trace(JSTracer *trc)
         AutoScriptVector::VectorImpl &vector = static_cast<AutoScriptVector *>(this)->vector;
         MarkScriptRootRange(trc, vector.length(), vector.begin(), "js::AutoScriptVector.vector");
         return;
       }
 
       case OBJOBJHASHMAP: {
         AutoObjectObjectHashMap::HashMapImpl &map = static_cast<AutoObjectObjectHashMap *>(this)->map;
         for (AutoObjectObjectHashMap::Enum e(map); !e.empty(); e.popFront()) {
-            MarkObjectRoot(trc, &e.front().value, "AutoObjectObjectHashMap value");
-            JS_SET_TRACING_LOCATION(trc, (void *)&e.front().key);
-            JSObject *key = e.front().key;
+            MarkObjectRoot(trc, &e.front().value(), "AutoObjectObjectHashMap value");
+            JS_SET_TRACING_LOCATION(trc, (void *)&e.front().key());
+            JSObject *key = e.front().key();
             MarkObjectRoot(trc, &key, "AutoObjectObjectHashMap key");
-            if (key != e.front().key)
+            if (key != e.front().key())
                 e.rekeyFront(key);
         }
         return;
       }
 
       case OBJU32HASHMAP: {
         AutoObjectUnsigned32HashMap *self = static_cast<AutoObjectUnsigned32HashMap *>(this);
         AutoObjectUnsigned32HashMap::HashMapImpl &map = self->map;
         for (AutoObjectUnsigned32HashMap::Enum e(map); !e.empty(); e.popFront()) {
-            JSObject *key = e.front().key;
+            JSObject *key = e.front().key();
             MarkObjectRoot(trc, &key, "AutoObjectUnsignedHashMap key");
-            if (key != e.front().key)
+            if (key != e.front().key())
                 e.rekeyFront(key);
         }
         return;
       }
 
       case OBJHASHSET: {
         AutoObjectHashSet *self = static_cast<AutoObjectHashSet *>(this);
         AutoObjectHashSet::HashSetImpl &set = self->set;
@@ -679,26 +679,28 @@ js::gc::MarkRuntime(JSTracer *trc, bool 
 #else
         MarkConservativeStackRoots(trc, useSavedRoots);
 #endif
         rt->markSelfHostingGlobal(trc);
     }
 
     for (RootRange r = rt->gcRootsHash.all(); !r.empty(); r.popFront()) {
         const RootEntry &entry = r.front();
-        const char *name = entry.value.name ? entry.value.name : "root";
-        if (entry.value.type == JS_GC_ROOT_VALUE_PTR) {
-            MarkValueRoot(trc, reinterpret_cast<Value *>(entry.key), name);
-        } else if (*reinterpret_cast<void **>(entry.key)){
-            if (entry.value.type == JS_GC_ROOT_STRING_PTR)
-                MarkStringRoot(trc, reinterpret_cast<JSString **>(entry.key), name);
-            else if (entry.value.type == JS_GC_ROOT_OBJECT_PTR)
-                MarkObjectRoot(trc, reinterpret_cast<JSObject **>(entry.key), name);
-            else if (entry.value.type == JS_GC_ROOT_SCRIPT_PTR)
-                MarkScriptRoot(trc, reinterpret_cast<JSScript **>(entry.key), name);
+        const char *name = entry.value().name ? entry.value().name : "root";
+        JSGCRootType type = entry.value().type;
+        void *key = entry.key();
+        if (type == JS_GC_ROOT_VALUE_PTR) {
+            MarkValueRoot(trc, reinterpret_cast<Value *>(key), name);
+        } else if (*reinterpret_cast<void **>(key)){
+            if (type == JS_GC_ROOT_STRING_PTR)
+                MarkStringRoot(trc, reinterpret_cast<JSString **>(key), name);
+            else if (type == JS_GC_ROOT_OBJECT_PTR)
+                MarkObjectRoot(trc, reinterpret_cast<JSObject **>(key), name);
+            else if (type == JS_GC_ROOT_SCRIPT_PTR)
+                MarkScriptRoot(trc, reinterpret_cast<JSScript **>(key), name);
             else
                 MOZ_ASSUME_UNREACHABLE("unexpected js::RootInfo::type value");
         }
     }
 
     MarkPersistentRootedChains(trc);
 
     if (rt->scriptAndCountsVector) {
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/ion/bug945294.js
@@ -0,0 +1,22 @@
+// |jit-test| error:is not a function
+var arr = [];
+
+var C = function () {};
+C.prototype.dump = function () {};
+arr[0] = new C;
+
+C = function () {};
+C.prototype.dump = this;
+arr[1] = new C;
+
+function f() {
+    for (var i = 0; i < arr.length; i++)
+        arr[i].dump();
+}
+
+try {
+    f();
+} catch (exc) {
+    assertEq(exc.message.contains("is not a function"), true);
+}
+f();
--- a/js/src/jit/AsmJS.cpp
+++ b/js/src/jit/AsmJS.cpp
@@ -1391,23 +1391,24 @@ class MOZ_STACK_CLASS ModuleCompiler
     bool hasError() const { return errorString_ != nullptr; }
     const AsmJSModule &module() const { return *module_.get(); }
 
     ParseNode *moduleFunctionNode() const { return moduleFunctionNode_; }
     PropertyName *moduleFunctionName() const { return moduleFunctionName_; }
 
     const Global *lookupGlobal(PropertyName *name) const {
         if (GlobalMap::Ptr p = globals_.lookup(name))
-            return p->value;
+            return p->value();
         return nullptr;
     }
     Func *lookupFunction(PropertyName *name) {
         if (GlobalMap::Ptr p = globals_.lookup(name)) {
-            if (p->value->which() == Global::Function)
-                return functions_[p->value->funcIndex()];
+            Global *value = p->value();
+            if (value->which() == Global::Function)
+                return functions_[value->funcIndex()];
         }
         return nullptr;
     }
     unsigned numFunctions() const {
         return functions_.length();
     }
     Func &function(unsigned i) {
         return *functions_[i];
@@ -1415,17 +1416,17 @@ class MOZ_STACK_CLASS ModuleCompiler
     unsigned numFuncPtrTables() const {
         return funcPtrTables_.length();
     }
     FuncPtrTable &funcPtrTable(unsigned i) {
         return funcPtrTables_[i];
     }
     bool lookupStandardLibraryMathName(PropertyName *name, AsmJSMathBuiltin *mathBuiltin) const {
         if (MathNameMap::Ptr p = standardLibraryMathNames_.lookup(name)) {
-            *mathBuiltin = p->value;
+            *mathBuiltin = p->value();
             return true;
         }
         return false;
     }
     ExitMap::Range allExits() const {
         return exits_.all();
     }
 
@@ -1546,17 +1547,17 @@ class MOZ_STACK_CLASS ModuleCompiler
         AsmJSModule::ReturnType retType = func->sig().retType().toModuleReturnType();
         return module_->addExportedFunction(func->name(), maybeFieldName,
                                             Move(argCoercions), retType);
     }
     bool addExit(unsigned ffiIndex, PropertyName *name, Signature &&sig, unsigned *exitIndex) {
         ExitDescriptor exitDescriptor(name, Move(sig));
         ExitMap::AddPtr p = exits_.lookupForAdd(exitDescriptor);
         if (p) {
-            *exitIndex = p->value;
+            *exitIndex = p->value();
             return true;
         }
         if (!module_->addExit(ffiIndex, exitIndex))
             return false;
         return exits_.add(p, Move(exitDescriptor), *exitIndex);
     }
     bool addGlobalAccess(AsmJSGlobalAccess access) {
         return globalAccesses_.append(access);
@@ -1974,17 +1975,17 @@ class FunctionCompiler
 
     MIRGenerator & mirGen() const     { JS_ASSERT(mirGen_); return *mirGen_; }
     MIRGraph &     mirGraph() const   { JS_ASSERT(graph_); return *graph_; }
     CompileInfo &  info() const       { JS_ASSERT(info_); return *info_; }
 
     const Local *lookupLocal(PropertyName *name) const
     {
         if (LocalMap::Ptr p = locals_.lookup(name))
-            return &p->value;
+            return &p->value();
         return nullptr;
     }
 
     MDefinition *getLocalDef(const Local &local)
     {
         if (!curBlock_)
             return nullptr;
         return curBlock_->getSlot(info().localSlot(local.slot));
@@ -2531,17 +2532,17 @@ class FunctionCompiler
         }
         return bindUnlabeledBreaks(pn);
     }
 
     bool bindContinues(ParseNode *pn, const LabelVector *maybeLabels)
     {
         bool createdJoinBlock = false;
         if (UnlabeledBlockMap::Ptr p = unlabeledContinues_.lookup(pn)) {
-            if (!bindBreaksOrContinues(&p->value, &createdJoinBlock, pn))
+            if (!bindBreaksOrContinues(&p->value(), &createdJoinBlock, pn))
                 return false;
             unlabeledContinues_.remove(p);
         }
         return bindLabeledBreaksOrContinues(maybeLabels, &labeledContinues_, &createdJoinBlock, pn);
     }
 
     bool bindLabeledBreaks(const LabelVector *maybeLabels, ParseNode *pn)
     {
@@ -2693,17 +2694,17 @@ class FunctionCompiler
     bool bindLabeledBreaksOrContinues(const LabelVector *maybeLabels, LabeledBlockMap *map,
                                       bool *createdJoinBlock, ParseNode *pn)
     {
         if (!maybeLabels)
             return true;
         const LabelVector &labels = *maybeLabels;
         for (unsigned i = 0; i < labels.length(); i++) {
             if (LabeledBlockMap::Ptr p = map->lookup(labels[i])) {
-                if (!bindBreaksOrContinues(&p->value, createdJoinBlock, pn))
+                if (!bindBreaksOrContinues(&p->value(), createdJoinBlock, pn))
                     return false;
                 map->remove(p);
             }
         }
         return true;
     }
 
     template <class Key, class Map>
@@ -2712,27 +2713,27 @@ class FunctionCompiler
         if (!curBlock_)
             return true;
         typename Map::AddPtr p = map->lookupForAdd(key);
         if (!p) {
             BlockVector empty(m().cx());
             if (!map->add(p, key, Move(empty)))
                 return false;
         }
-        if (!p->value.append(curBlock_))
+        if (!p->value().append(curBlock_))
             return false;
         curBlock_ = nullptr;
         return true;
     }
 
     bool bindUnlabeledBreaks(ParseNode *pn)
     {
         bool createdJoinBlock = false;
         if (UnlabeledBlockMap::Ptr p = unlabeledBreaks_.lookup(pn)) {
-            if (!bindBreaksOrContinues(&p->value, &createdJoinBlock, pn))
+            if (!bindBreaksOrContinues(&p->value(), &createdJoinBlock, pn))
                 return false;
             unlabeledBreaks_.remove(p);
         }
         return true;
     }
 };
 
 } /* anonymous namespace */
@@ -6368,17 +6369,17 @@ GenerateStubs(ModuleCompiler &m)
             return false;
     }
 
     Label throwLabel;
 
     // The order of the iterations here is non-deterministic, since
     // m.allExits() is a hash keyed by pointer values!
     for (ModuleCompiler::ExitMap::Range r = m.allExits(); !r.empty(); r.popFront()) {
-        GenerateFFIExit(m, r.front().key, r.front().value, &throwLabel);
+        GenerateFFIExit(m, r.front().key(), r.front().value(), &throwLabel);
         if (m.masm().oom())
             return false;
     }
 
     if (m.stackOverflowLabel().used()) {
         if (!GenerateStackOverflowExit(m, &throwLabel))
             return false;
     }
--- a/js/src/jit/BaselineJIT.cpp
+++ b/js/src/jit/BaselineJIT.cpp
@@ -886,17 +886,17 @@ jit::FinishDiscardBaselineScript(FreeOp 
     script->setBaselineScript(nullptr);
     BaselineScript::Destroy(fop, baseline);
 }
 
 void
 jit::JitCompartment::toggleBaselineStubBarriers(bool enabled)
 {
     for (ICStubCodeMap::Enum e(*stubCodes_); !e.empty(); e.popFront()) {
-        IonCode *code = *e.front().value.unsafeGet();
+        IonCode *code = *e.front().value().unsafeGet();
         code->togglePreBarriers(enabled);
     }
 }
 
 void
 jit::AddSizeOfBaselineData(JSScript *script, mozilla::MallocSizeOf mallocSizeOf, size_t *data,
                            size_t *fallbackStubs)
 {
--- a/js/src/jit/Ion.cpp
+++ b/js/src/jit/Ion.cpp
@@ -598,17 +598,17 @@ JitRuntime::getBailoutTable(const FrameS
 IonCode *
 JitRuntime::getVMWrapper(const VMFunction &f) const
 {
     JS_ASSERT(functionWrappers_);
     JS_ASSERT(functionWrappers_->initialized());
     JitRuntime::VMWrapperMap::Ptr p = functionWrappers_->readonlyThreadsafeLookup(&f);
     JS_ASSERT(p);
 
-    return p->value;
+    return p->value();
 }
 
 template <AllowGC allowGC>
 IonCode *
 IonCode::New(JSContext *cx, uint8_t *code, uint32_t bufferSize, JSC::ExecutablePool *pool)
 {
     IonCode *codeObj = gc::NewGCThing<IonCode, allowGC>(cx, gc::FINALIZE_IONCODE, sizeof(IonCode), gc::DefaultHeap);
     if (!codeObj) {
--- a/js/src/jit/IonAnalysis.cpp
+++ b/js/src/jit/IonAnalysis.cpp
@@ -1372,29 +1372,29 @@ BoundsCheckHashIgnoreOffset(MBoundsCheck
 }
 
 static MBoundsCheck *
 FindDominatingBoundsCheck(BoundsCheckMap &checks, MBoundsCheck *check, size_t index)
 {
     // See the comment in ValueNumberer::findDominatingDef.
     HashNumber hash = BoundsCheckHashIgnoreOffset(check);
     BoundsCheckMap::Ptr p = checks.lookup(hash);
-    if (!p || index > p->value.validUntil) {
+    if (!p || index > p->value().validUntil) {
         // We didn't find a dominating bounds check.
         BoundsCheckInfo info;
         info.check = check;
         info.validUntil = index + check->block()->numDominated();
 
         if(!checks.put(hash, info))
             return nullptr;
 
         return check;
     }
 
-    return p->value.check;
+    return p->value().check;
 }
 
 // Extract a linear sum from ins, if possible (otherwise giving the sum 'ins + 0').
 SimpleLinearSum
 jit::ExtractLinearSum(MDefinition *ins)
 {
     if (ins->isBeta())
         ins = ins->getOperand(0);
--- a/js/src/jit/IonBuilder.cpp
+++ b/js/src/jit/IonBuilder.cpp
@@ -710,16 +710,19 @@ IonBuilder::build()
     if (info().hasArguments() && !info().argsObjAliasesFormals()) {
         lazyArguments_ = MConstant::New(alloc(), MagicValue(JS_OPTIMIZED_ARGUMENTS));
         current->add(lazyArguments_);
     }
 
     if (!traverseBytecode())
         return false;
 
+    if (!maybeAddOsrTypeBarriers())
+        return false;
+
     if (!processIterators())
         return false;
 
     JS_ASSERT(loopDepth_ == 0);
     abortReason_ = AbortReason_NoAbort;
     return true;
 }
 
@@ -1199,17 +1202,17 @@ IonBuilder::traverseBytecode()
             // thus |while| instead of |if| so we don't skip any opcodes.
             if (!cfgStack_.empty() && cfgStack_.back().stopAt == pc) {
                 ControlStatus status = processCfgStack();
                 if (status == ControlStatus_Error)
                     return false;
                 if (status == ControlStatus_Abort)
                     return abort("Aborted while processing control flow");
                 if (!current)
-                    return maybeAddOsrTypeBarriers();
+                    return true;
                 continue;
             }
 
             // Some opcodes need to be handled early because they affect control
             // flow, terminating the current basic block and/or instructing the
             // traversal algorithm to continue from a new pc.
             //
             //   (1) If the opcode does not affect control flow, then the opcode
@@ -1227,17 +1230,17 @@ IonBuilder::traverseBytecode()
             ControlStatus status;
             if ((status = snoopControlFlow(JSOp(*pc))) == ControlStatus_None)
                 break;
             if (status == ControlStatus_Error)
                 return false;
             if (status == ControlStatus_Abort)
                 return abort("Aborted while processing control flow");
             if (!current)
-                return maybeAddOsrTypeBarriers();
+                return true;
         }
 
 #ifdef DEBUG
         // In debug builds, after compiling this op, check that all values
         // popped by this opcode either:
         //
         //   (1) Have the Folded flag set on them.
         //   (2) Have more uses than before compiling this op (the value is
@@ -1306,17 +1309,17 @@ IonBuilder::traverseBytecode()
             }
         }
 #endif
 
         pc += js_CodeSpec[op].length;
         current->updateTrackedPc(pc);
     }
 
-    return maybeAddOsrTypeBarriers();
+    return true;
 }
 
 IonBuilder::ControlStatus
 IonBuilder::snoopControlFlow(JSOp op)
 {
     switch (op) {
       case JSOP_NOP:
         return maybeLoop(op, info().getNote(gsn, pc));
@@ -7998,17 +8001,17 @@ IonBuilder::annotateGetPropertyCache(MDe
         if (typeObj->unknownProperties() || !typeObj->proto().isObject())
             continue;
 
         types::HeapTypeSetKey ownTypes = typeObj->property(NameToId(name));
         if (ownTypes.isOwnProperty(constraints()))
             continue;
 
         JSObject *singleton = testSingletonProperty(typeObj->proto().toObject(), name);
-        if (!singleton)
+        if (!singleton || !singleton->is<JSFunction>())
             continue;
 
         // Don't add cases corresponding to non-observed pushes
         if (!pushedTypes->hasType(types::Type::ObjectType(singleton)))
             continue;
 
         if (!inlinePropTable->addEntry(alloc(), baseTypeObj, &singleton->as<JSFunction>()))
             return false;
--- a/js/src/jit/JitCompartment.h
+++ b/js/src/jit/JitCompartment.h
@@ -363,17 +363,17 @@ class JitCompartment
   public:
     OffThreadCompilationVector &finishedOffThreadCompilations() {
         return finishedOffThreadCompilations_;
     }
 
     IonCode *getStubCode(uint32_t key) {
         ICStubCodeMap::AddPtr p = stubCodes_->lookupForAdd(key);
         if (p)
-            return p->value;
+            return p->value();
         return nullptr;
     }
     bool putStubCode(uint32_t key, Handle<IonCode *> stubCode) {
         // Make sure to do a lookupForAdd(key) and then insert into that slot, because
         // that way if stubCode gets moved due to a GC caused by lookupForAdd, then
         // we still write the correct pointer.
         JS_ASSERT(!stubCodes_->has(key));
         ICStubCodeMap::AddPtr p = stubCodes_->lookupForAdd(key);
--- a/js/src/jit/ValueNumbering.cpp
+++ b/js/src/jit/ValueNumbering.cpp
@@ -30,24 +30,24 @@ ValueNumberer::alloc() const
 uint32_t
 ValueNumberer::lookupValue(MDefinition *ins)
 {
 
     ValueMap::AddPtr p = values.lookupForAdd(ins);
 
     if (p) {
         // make sure this is in the correct group
-        setClass(ins, p->key);
+        setClass(ins, p->key());
     } else {
         if (!values.add(p, ins, ins->id()))
             return 0;
         breakClass(ins);
     }
 
-    return p->value;
+    return p->value();
 }
 
 MDefinition *
 ValueNumberer::simplify(MDefinition *def, bool useValueNumbers)
 {
     if (def->isEffectful())
         return def;
 
@@ -304,34 +304,34 @@ ValueNumberer::computeValueNumbers()
 }
 
 MDefinition *
 ValueNumberer::findDominatingDef(InstructionMap &defs, MDefinition *ins, size_t index)
 {
     JS_ASSERT(ins->valueNumber() != 0);
     InstructionMap::Ptr p = defs.lookup(ins->valueNumber());
     MDefinition *dom;
-    if (!p || index > p->value.validUntil) {
+    if (!p || index > p->value().validUntil) {
         DominatingValue value;
         value.def = ins;
         // Since we are traversing the dominator tree in pre-order, when we
         // are looking at the |index|-th block, the next numDominated() blocks
         // we traverse are precisely the set of blocks that are dominated.
         //
         // So, this value is visible in all blocks if:
         // index <= index + ins->block->numDominated()
         // and becomes invalid after that.
         value.validUntil = index + ins->block()->numDominated();
 
         if(!defs.put(ins->valueNumber(), value))
             return nullptr;
 
         dom = ins;
     } else {
-        dom = p->value.def;
+        dom = p->value().def;
     }
 
     return dom;
 }
 
 bool
 ValueNumberer::eliminateRedundancies()
 {
--- a/js/src/jit/arm/Architecture-arm.cpp
+++ b/js/src/jit/arm/Architecture-arm.cpp
@@ -8,17 +8,17 @@
 
 #include <elf.h>
 #include <fcntl.h>
 #include <unistd.h>
 
 #include "jit/arm/Assembler-arm.h"
 
 #if !(defined(ANDROID) || defined(MOZ_B2G))
-#define HWCAP_ARMv7 (1 << 31)
+#define HWCAP_ARMv7 (1 << 29)
 #include <asm/hwcap.h>
 #else
 #define HWCAP_VFP      (1<<0)
 #define HWCAP_VFPv3    (1<<1)
 #define HWCAP_VFPv3D16 (1<<2)
 #define HWCAP_VFPv4    (1<<3)
 #define HWCAP_IDIVA    (1<<4)
 #define HWCAP_IDIVT    (1<<5)
--- a/js/src/jit/arm/Trampoline-arm.cpp
+++ b/js/src/jit/arm/Trampoline-arm.cpp
@@ -655,17 +655,17 @@ IonCode *
 JitRuntime::generateVMWrapper(JSContext *cx, const VMFunction &f)
 {
     typedef MoveResolver::MoveOperand MoveOperand;
 
     JS_ASSERT(functionWrappers_);
     JS_ASSERT(functionWrappers_->initialized());
     VMWrapperMap::AddPtr p = functionWrappers_->lookupForAdd(&f);
     if (p)
-        return p->value;
+        return p->value();
 
     // Generate a separated code for the wrapper.
     MacroAssembler masm(cx);
     GeneralRegisterSet regs = GeneralRegisterSet(Register::Codes::WrapperMask);
 
     // Wrapper register set is a superset of Volatile register set.
     JS_STATIC_ASSERT((Register::Codes::VolatileMask & ~Register::Codes::WrapperMask) == 0);
 
--- a/js/src/jit/x64/MacroAssembler-x64.cpp
+++ b/js/src/jit/x64/MacroAssembler-x64.cpp
@@ -23,17 +23,17 @@ MacroAssemblerX64::loadConstantDouble(do
 
     if (!doubleMap_.initialized()) {
         enoughMemory_ &= doubleMap_.init();
         if (!enoughMemory_)
             return;
     }
     size_t doubleIndex;
     if (DoubleMap::AddPtr p = doubleMap_.lookupForAdd(d)) {
-        doubleIndex = p->value;
+        doubleIndex = p->value();
     } else {
         doubleIndex = doubles_.length();
         enoughMemory_ &= doubles_.append(Double(d));
         enoughMemory_ &= doubleMap_.add(p, d, doubleIndex);
         if (!enoughMemory_)
             return;
     }
     Double &dbl = doubles_[doubleIndex];
@@ -57,17 +57,17 @@ MacroAssemblerX64::loadConstantFloat32(f
 
     if (!floatMap_.initialized()) {
         enoughMemory_ &= floatMap_.init();
         if (!enoughMemory_)
             return;
     }
     size_t floatIndex;
     if (FloatMap::AddPtr p = floatMap_.lookupForAdd(f)) {
-        floatIndex = p->value;
+        floatIndex = p->value();
     } else {
         floatIndex = floats_.length();
         enoughMemory_ &= floats_.append(Float(f));
         enoughMemory_ &= floatMap_.add(p, f, floatIndex);
         if (!enoughMemory_)
             return;
     }
     Float &flt = floats_[floatIndex];
--- a/js/src/jit/x64/Trampoline-x64.cpp
+++ b/js/src/jit/x64/Trampoline-x64.cpp
@@ -505,17 +505,17 @@ JitRuntime::generateVMWrapper(JSContext 
 {
     typedef MoveResolver::MoveOperand MoveOperand;
 
     JS_ASSERT(!StackKeptAligned);
     JS_ASSERT(functionWrappers_);
     JS_ASSERT(functionWrappers_->initialized());
     VMWrapperMap::AddPtr p = functionWrappers_->lookupForAdd(&f);
     if (p)
-        return p->value;
+        return p->value();
 
     // Generate a separated code for the wrapper.
     MacroAssembler masm;
 
     // Avoid conflicts with argument registers while discarding the result after
     // the function call.
     GeneralRegisterSet regs = GeneralRegisterSet(Register::Codes::WrapperMask);
 
--- a/js/src/jit/x86/MacroAssembler-x86.cpp
+++ b/js/src/jit/x86/MacroAssembler-x86.cpp
@@ -24,17 +24,17 @@ MacroAssemblerX86::getDouble(double d)
     if (!doubleMap_.initialized()) {
         enoughMemory_ &= doubleMap_.init();
         if (!enoughMemory_)
             return nullptr;
     }
     size_t doubleIndex;
     DoubleMap::AddPtr p = doubleMap_.lookupForAdd(d);
     if (p) {
-        doubleIndex = p->value;
+        doubleIndex = p->value();
     } else {
         doubleIndex = doubles_.length();
         enoughMemory_ &= doubles_.append(Double(d));
         enoughMemory_ &= doubleMap_.add(p, d, doubleIndex);
         if (!enoughMemory_)
             return nullptr;
     }
     Double &dbl = doubles_[doubleIndex];
@@ -70,17 +70,17 @@ MacroAssemblerX86::getFloat(float f)
     if (!floatMap_.initialized()) {
         enoughMemory_ &= floatMap_.init();
         if (!enoughMemory_)
             return nullptr;
     }
     size_t floatIndex;
     FloatMap::AddPtr p = floatMap_.lookupForAdd(f);
     if (p) {
-        floatIndex = p->value;
+        floatIndex = p->value();
     } else {
         floatIndex = floats_.length();
         enoughMemory_ &= floats_.append(Float(f));
         enoughMemory_ &= floatMap_.add(p, f, floatIndex);
         if (!enoughMemory_)
             return nullptr;
     }
     Float &flt = floats_[floatIndex];
--- a/js/src/jit/x86/Trampoline-x86.cpp
+++ b/js/src/jit/x86/Trampoline-x86.cpp
@@ -540,17 +540,17 @@ JitRuntime::generateVMWrapper(JSContext 
 {
     typedef MoveResolver::MoveOperand MoveOperand;
 
     JS_ASSERT(!StackKeptAligned);
     JS_ASSERT(functionWrappers_);
     JS_ASSERT(functionWrappers_->initialized());
     VMWrapperMap::AddPtr p = functionWrappers_->lookupForAdd(&f);
     if (p)
-        return p->value;
+        return p->value();
 
     // Generate a separated code for the wrapper.
     MacroAssembler masm;
 
     // Avoid conflicts with argument registers while discarding the result after
     // the function call.
     GeneralRegisterSet regs = GeneralRegisterSet(Register::Codes::WrapperMask);
 
--- a/js/src/jsapi-tests/testHashTable.cpp
+++ b/js/src/jsapi-tests/testHashTable.cpp
@@ -56,25 +56,25 @@ static bool
 MapsAreEqual(IntMap &am, IntMap &bm)
 {
     bool equal = true;
     if (am.count() != bm.count()) {
         equal = false;
         fprintf(stderr, "A.count() == %u and B.count() == %u\n", am.count(), bm.count());
     }
     for (IntMap::Range r = am.all(); !r.empty(); r.popFront()) {
-        if (!bm.has(r.front().key)) {
+        if (!bm.has(r.front().key())) {
             equal = false;
-            fprintf(stderr, "B does not have %x which is in A\n", r.front().key);
+            fprintf(stderr, "B does not have %x which is in A\n", r.front().key());
         }
     }
     for (IntMap::Range r = bm.all(); !r.empty(); r.popFront()) {
-        if (!am.has(r.front().key)) {
+        if (!am.has(r.front().key())) {
             equal = false;
-            fprintf(stderr, "A does not have %x which is in B\n", r.front().key);
+            fprintf(stderr, "A does not have %x which is in B\n", r.front().key());
         }
     }
     return equal;
 }
 
 static bool
 SetsAreEqual(IntSet &am, IntSet &bm)
 {
@@ -136,27 +136,27 @@ AddLowKeys(IntSet *as, IntSet *bs, int s
 
 template <class NewKeyFunction>
 static bool
 SlowRekey(IntMap *m) {
     IntMap tmp;
     tmp.init();
 
     for (IntMap::Range r = m->all(); !r.empty(); r.popFront()) {
-        if (NewKeyFunction::shouldBeRemoved(r.front().key))
+        if (NewKeyFunction::shouldBeRemoved(r.front().key()))
             continue;
-        uint32_t hi = NewKeyFunction::rekey(r.front().key);
+        uint32_t hi = NewKeyFunction::rekey(r.front().key());
         if (tmp.has(hi))
             return false;
-        tmp.putNew(hi, r.front().value);
+        tmp.putNew(hi, r.front().value());
     }
 
     m->clear();
     for (IntMap::Range r = tmp.all(); !r.empty(); r.popFront()) {
-        m->putNew(r.front().key, r.front().value);
+        m->putNew(r.front().key(), r.front().value());
     }
 
     return true;
 }
 
 template <class NewKeyFunction>
 static bool
 SlowRekey(IntSet *s) {
@@ -188,18 +188,18 @@ BEGIN_TEST(testHashRekeyManual)
     for (size_t i = 0; i < TestIterations; ++i) {
 #ifdef FUZZ
         fprintf(stderr, "map1: %lu\n", i);
 #endif
         CHECK(AddLowKeys(&am, &bm, i));
         CHECK(MapsAreEqual(am, bm));
 
         for (IntMap::Enum e(am); !e.empty(); e.popFront()) {
-            uint32_t tmp = LowToHigh::rekey(e.front().key);
-            if (tmp != e.front().key)
+            uint32_t tmp = LowToHigh::rekey(e.front().key());
+            if (tmp != e.front().key())
                 e.rekeyFront(tmp);
         }
         CHECK(SlowRekey<LowToHigh>(&bm));
 
         CHECK(MapsAreEqual(am, bm));
         am.clear();
         bm.clear();
     }
@@ -238,21 +238,21 @@ BEGIN_TEST(testHashRekeyManualRemoval)
     for (size_t i = 0; i < TestIterations; ++i) {
 #ifdef FUZZ
         fprintf(stderr, "map2: %lu\n", i);
 #endif
         CHECK(AddLowKeys(&am, &bm, i));
         CHECK(MapsAreEqual(am, bm));
 
         for (IntMap::Enum e(am); !e.empty(); e.popFront()) {
-            if (LowToHighWithRemoval::shouldBeRemoved(e.front().key)) {
+            if (LowToHighWithRemoval::shouldBeRemoved(e.front().key())) {
                 e.removeFront();
             } else {
-                uint32_t tmp = LowToHighWithRemoval::rekey(e.front().key);
-                if (tmp != e.front().key)
+                uint32_t tmp = LowToHighWithRemoval::rekey(e.front().key());
+                if (tmp != e.front().key())
                     e.rekeyFront(tmp);
             }
         }
         CHECK(SlowRekey<LowToHighWithRemoval>(&bm));
 
         CHECK(MapsAreEqual(am, bm));
         am.clear();
         bm.clear();
--- a/js/src/jsapi-tests/testIntTypesABI.cpp
+++ b/js/src/jsapi-tests/testIntTypesABI.cpp
@@ -25,16 +25,17 @@
 #include "js/Id.h"
 /* LegacyIntTypes.h is deliberately exempted from this requirement */
 #include "js/MemoryMetrics.h"
 #include "js/OldDebugAPI.h"
 #include "js/ProfilingStack.h"
 #include "js/PropertyKey.h"
 #include "js/RequiredDefines.h"
 #include "js/RootingAPI.h"
+#include "js/SliceBudget.h"
 #include "js/StructuredClone.h"
 #include "js/Tracer.h"
 #include "js/TypeDecls.h"
 #include "js/Utility.h"
 #include "js/Value.h"
 #include "js/Vector.h"
 #include "jsapi-tests/tests.h"
 
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -56,16 +56,17 @@
 #include "builtin/RegExp.h"
 #include "builtin/TypedObject.h"
 #include "frontend/BytecodeCompiler.h"
 #include "frontend/FullParseHandler.h"  // for JS_BufferIsCompileableUnit
 #include "frontend/Parser.h" // for JS_BufferIsCompileableUnit
 #include "gc/Marking.h"
 #include "jit/AsmJSLink.h"
 #include "js/CharacterEncoding.h"
+#include "js/SliceBudget.h"
 #include "js/StructuredClone.h"
 #if ENABLE_INTL_API
 #include "unicode/uclean.h"
 #include "unicode/utypes.h"
 #endif // ENABLE_INTL_API
 #include "vm/DateObject.h"
 #include "vm/Debugger.h"
 #include "vm/ErrorObject.h"
@@ -1089,17 +1090,17 @@ JS_TransplantObject(JSContext *cx, Handl
         // object will continue to work.
         if (!JSObject::swap(cx, origobj, target))
             MOZ_CRASH();
         newIdentity = origobj;
     } else if (WrapperMap::Ptr p = destination->lookupWrapper(origv)) {
         // There might already be a wrapper for the original object in
         // the new compartment. If there is, we use its identity and swap
         // in the contents of |target|.
-        newIdentity = &p->value.toObject();
+        newIdentity = &p->value().toObject();
 
         // When we remove origv from the wrapper map, its wrapper, newIdentity,
         // must immediately cease to be a cross-compartment wrapper. Neuter it.
         destination->removeWrapper(p);
         NukeCrossCompartmentWrapper(cx, newIdentity);
 
         if (!JSObject::swap(cx, newIdentity, target))
             MOZ_CRASH();
--- a/js/src/jscntxt.cpp
+++ b/js/src/jscntxt.cpp
@@ -96,18 +96,18 @@ js::TraceCycleDetectionSet(JSTracer *trc
     }
 }
 
 void
 JSCompartment::sweepCallsiteClones()
 {
     if (callsiteClones.initialized()) {
         for (CallsiteCloneTable::Enum e(callsiteClones); !e.empty(); e.popFront()) {
-            CallsiteCloneKey key = e.front().key;
-            JSFunction *fun = e.front().value;
+            CallsiteCloneKey key = e.front().key();
+            JSFunction *fun = e.front().value();
             if (!IsScriptMarked(&key.script) || !IsObjectMarked(&fun))
                 e.removeFront();
         }
     }
 }
 
 JSFunction *
 js::ExistingCloneFunctionAtCallsite(const CallsiteCloneTable &table, JSFunction *fun,
@@ -123,17 +123,17 @@ js::ExistingCloneFunctionAtCallsite(cons
      */
     JS_ASSERT(fun->isTenured());
 
     if (!table.initialized())
         return nullptr;
 
     CallsiteCloneTable::Ptr p = table.lookup(CallsiteCloneKey(fun, script, script->pcToOffset(pc)));
     if (p)
-        return p->value;
+        return p->value();
 
     return nullptr;
 }
 
 JSFunction *
 js::CloneFunctionAtCallsite(JSContext *cx, HandleFunction fun, HandleScript script, jsbytecode *pc)
 {
     if (JSFunction *clone = ExistingCloneFunctionAtCallsite(cx->compartment()->callsiteClones, fun, script, pc))
--- a/js/src/jscompartment.cpp
+++ b/js/src/jscompartment.cpp
@@ -224,17 +224,17 @@ JSCompartment::wrap(JSContext *cx, JSStr
     if (str->isAtom()) {
         JS_ASSERT(cx->runtime()->isAtomsZone(str->zone()));
         return true;
     }
 
     /* Check the cache. */
     RootedValue key(cx, StringValue(str));
     if (WrapperMap::Ptr p = crossCompartmentWrappers.lookup(key)) {
-        *strp = p->value.get().toString();
+        *strp = p->value().get().toString();
         return true;
     }
 
     /* No dice. Make a copy, and cache it. */
     Rooted<JSLinearString *> linear(cx, str->ensureLinear(cx));
     if (!linear)
         return false;
     JSString *copy = js_NewStringCopyN<CanGC>(cx, linear->chars(),
@@ -328,17 +328,17 @@ JSCompartment::wrap(JSContext *cx, Mutab
         JSObject *outer = GetOuterObject(cx, obj);
         JS_ASSERT(outer && outer == obj);
     }
 #endif
 
     /* If we already have a wrapper for this value, use it. */
     RootedValue key(cx, ObjectValue(*obj));
     if (WrapperMap::Ptr p = crossCompartmentWrappers.lookup(key)) {
-        obj.set(&p->value.get().toObject());
+        obj.set(&p->value().get().toObject());
         JS_ASSERT(obj->is<CrossCompartmentWrapperObject>());
         JS_ASSERT(obj->getParent() == global);
         return true;
     }
 
     RootedObject proto(cx, Proxy::LazyProto);
     RootedObject existing(cx, existingArg);
     if (existing) {
@@ -444,18 +444,18 @@ JSCompartment::wrap(JSContext *cx, AutoI
  * across compartments.
  */
 void
 JSCompartment::markCrossCompartmentWrappers(JSTracer *trc)
 {
     JS_ASSERT(!zone()->isCollecting());
 
     for (WrapperMap::Enum e(crossCompartmentWrappers); !e.empty(); e.popFront()) {
-        Value v = e.front().value;
-        if (e.front().key.kind == CrossCompartmentKey::ObjectWrapper) {
+        Value v = e.front().value();
+        if (e.front().key().kind == CrossCompartmentKey::ObjectWrapper) {
             ProxyObject *wrapper = &v.toObject().as<ProxyObject>();
 
             /*
              * We have a cross-compartment wrapper. Its private pointer may
              * point into the compartment being collected, so we should mark it.
              */
             Value referent = wrapper->private_();
             MarkValueRoot(trc, &referent, "cross-compartment wrapper");
@@ -469,22 +469,22 @@ JSCompartment::markCrossCompartmentWrapp
  * wrapper map. It should be called only for minor GCs, since minor GCs cannot,
  * by their nature, apply the weak constraint to safely remove items from the
  * wrapper map.
  */
 void
 JSCompartment::markAllCrossCompartmentWrappers(JSTracer *trc)
 {
     for (WrapperMap::Enum e(crossCompartmentWrappers); !e.empty(); e.popFront()) {
-        CrossCompartmentKey key = e.front().key;
+        CrossCompartmentKey key = e.front().key();
         MarkGCThingRoot(trc, (void **)&key.wrapped, "CrossCompartmentKey::wrapped");
         if (key.debugger)
             MarkObjectRoot(trc, &key.debugger, "CrossCompartmentKey::debugger");
-        MarkValueRoot(trc, e.front().value.unsafeGet(), "CrossCompartmentWrapper");
-        if (key.wrapped != e.front().key.wrapped || key.debugger != e.front().key.debugger)
+        MarkValueRoot(trc, e.front().value().unsafeGet(), "CrossCompartmentWrapper");
+        if (key.wrapped != e.front().key().wrapped || key.debugger != e.front().key().debugger)
             e.rekeyFront(key);
     }
 }
 
 void
 JSCompartment::mark(JSTracer *trc)
 {
     JS_ASSERT(!trc->runtime->isHeapMinorCollecting());
@@ -572,24 +572,26 @@ JSCompartment::sweepCrossCompartmentWrap
 {
     JSRuntime *rt = runtimeFromMainThread();
 
     gcstats::AutoPhase ap1(rt->gcStats, gcstats::PHASE_SWEEP_TABLES);
     gcstats::AutoPhase ap2(rt->gcStats, gcstats::PHASE_SWEEP_TABLES_WRAPPER);
 
     /* Remove dead wrappers from the table. */
     for (WrapperMap::Enum e(crossCompartmentWrappers); !e.empty(); e.popFront()) {
-        CrossCompartmentKey key = e.front().key;
+        CrossCompartmentKey key = e.front().key();
         bool keyDying = IsCellAboutToBeFinalized(&key.wrapped);
-        bool valDying = IsValueAboutToBeFinalized(e.front().value.unsafeGet());
+        bool valDying = IsValueAboutToBeFinalized(e.front().value().unsafeGet());
         bool dbgDying = key.debugger && IsObjectAboutToBeFinalized(&key.debugger);
         if (keyDying || valDying || dbgDying) {
             JS_ASSERT(key.kind != CrossCompartmentKey::StringWrapper);
             e.removeFront();
-        } else if (key.wrapped != e.front().key.wrapped || key.debugger != e.front().key.debugger) {
+        } else if (key.wrapped != e.front().key().wrapped ||
+                   key.debugger != e.front().key().debugger)
+        {
             e.rekeyFront(key);
         }
     }
 }
 
 void
 JSCompartment::purge()
 {
--- a/js/src/jscompartment.h
+++ b/js/src/jscompartment.h
@@ -605,21 +605,21 @@ struct WrapperValue
 {
     /*
      * We use unsafeGet() in the constructors to avoid invoking a read barrier
      * on the wrapper, which may be dead (see the comment about bug 803376 in
      * jsgc.cpp regarding this). If there is an incremental GC while the wrapper
      * is in use, the AutoWrapper rooter will ensure the wrapper gets marked.
      */
     explicit WrapperValue(const WrapperMap::Ptr &ptr)
-      : value(*ptr->value.unsafeGet())
+      : value(*ptr->value().unsafeGet())
     {}
 
     explicit WrapperValue(const WrapperMap::Enum &e)
-      : value(*e.front().value.unsafeGet())
+      : value(*e.front().value().unsafeGet())
     {}
 
     Value &get() { return value; }
     Value get() const { return value; }
     operator const Value &() const { return value; }
     JSObject &toObject() const { return value.toObject(); }
 
   private:
--- a/js/src/jscompartmentinlines.h
+++ b/js/src/jscompartmentinlines.h
@@ -86,19 +86,19 @@ JSCompartment::wrap(JSContext *cx, JS::M
      * that we get the same answer.
      */
 #ifdef DEBUG
     JS::RootedObject cacheResult(cx);
 #endif
     JS::RootedValue v(cx, vp);
     if (js::WrapperMap::Ptr p = crossCompartmentWrappers.lookup(v)) {
 #ifdef DEBUG
-        cacheResult = &p->value.get().toObject();
+        cacheResult = &p->value().get().toObject();
 #else
-        vp.set(p->value);
+        vp.set(p->value());
         return true;
 #endif
     }
 
     JS::RootedObject obj(cx, &vp.toObject());
     if (!wrap(cx, &obj, existing))
         return false;
     vp.setObject(*obj);
--- a/js/src/jsfriendapi.cpp
+++ b/js/src/jsfriendapi.cpp
@@ -655,17 +655,17 @@ js::GCThingTraceKind(void *thing)
 }
 
 JS_FRIEND_API(void)
 js::VisitGrayWrapperTargets(Zone *zone, GCThingCallback callback, void *closure)
 {
     JSRuntime *rt = zone->runtimeFromMainThread();
     for (CompartmentsInZoneIter comp(zone); !comp.done(); comp.next()) {
         for (JSCompartment::WrapperEnum e(comp); !e.empty(); e.popFront()) {
-            gc::Cell *thing = e.front().key.wrapped;
+            gc::Cell *thing = e.front().key().wrapped;
             if (!IsInsideNursery(rt, thing) && thing->isMarked(gc::GRAY))
                 callback(closure, thing);
         }
     }
 }
 
 JS_FRIEND_API(JSObject *)
 js::GetWeakmapKeyDelegate(JSObject *key)
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -204,16 +204,17 @@
 #include "gc/FindSCCs.h"
 #include "gc/GCInternals.h"
 #include "gc/Marking.h"
 #include "gc/Memory.h"
 #ifdef JS_ION
 # include "jit/BaselineJIT.h"
 #endif
 #include "jit/IonCode.h"
+#include "js/SliceBudget.h"
 #include "vm/Debugger.h"
 #include "vm/ForkJoin.h"
 #include "vm/ProxyObject.h"
 #include "vm/Shape.h"
 #include "vm/String.h"
 #include "vm/WrapperObject.h"
 
 #include "jsobjinlines.h"
@@ -2875,27 +2876,27 @@ struct CompartmentCheckTracer : public J
 static bool
 InCrossCompartmentMap(JSObject *src, Cell *dst, JSGCTraceKind dstKind)
 {
     JSCompartment *srccomp = src->compartment();
 
     if (dstKind == JSTRACE_OBJECT) {
         Value key = ObjectValue(*static_cast<JSObject *>(dst));
         if (WrapperMap::Ptr p = srccomp->lookupWrapper(key)) {
-            if (*p->value.unsafeGet() == ObjectValue(*src))
+            if (*p->value().unsafeGet() == ObjectValue(*src))
                 return true;
         }
     }
 
     /*
      * If the cross-compartment edge is caused by the debugger, then we don't
      * know the right hashtable key, so we have to iterate.
      */
     for (JSCompartment::WrapperEnum e(srccomp); !e.empty(); e.popFront()) {
-        if (e.front().key.wrapped == dst && ToMarkable(e.front().value) == src)
+        if (e.front().key().wrapped == dst && ToMarkable(e.front().value()) == src)
             return true;
     }
 
     return false;
 }
 
 static void
 CheckCompartment(CompartmentCheckTracer *trc, JSCompartment *thingCompartment,
@@ -3118,17 +3119,17 @@ BeginMarkPhase(JSRuntime *rt)
      * the JS_TransplantObject function has finished. This ensures that the dead
      * zones will be cleaned up. See AutoMarkInDeadZone and
      * AutoMaybeTouchDeadZones for details.
      */
 
     /* Set the maybeAlive flag based on cross-compartment edges. */
     for (CompartmentsIter c(rt, SkipAtoms); !c.done(); c.next()) {
         for (JSCompartment::WrapperEnum e(c); !e.empty(); e.popFront()) {
-            Cell *dst = e.front().key.wrapped;
+            Cell *dst = e.front().key().wrapped;
             dst->tenuredZone()->maybeAlive = true;
         }
     }
 
     /*
      * For black roots, code in gc/Marking.cpp will already have set maybeAlive
      * during MarkRuntime.
      */
@@ -3246,17 +3247,17 @@ js::gc::MarkingValidator::MarkingValidat
 {}
 
 js::gc::MarkingValidator::~MarkingValidator()
 {
     if (!map.initialized())
         return;
 
     for (BitmapMap::Range r(map.all()); !r.empty(); r.popFront())
-        js_delete(r.front().value);
+        js_delete(r.front().value());
 }
 
 void
 js::gc::MarkingValidator::nonIncrementalMark()
 {
     /*
      * Perform a non-incremental mark for all collecting zones and record
      * the results for later comparison.
@@ -3352,17 +3353,17 @@ js::gc::MarkingValidator::nonIncremental
             zone->setGCState(Zone::Mark);
         }
     }
 
     /* Take a copy of the non-incremental mark state and restore the original. */
     for (GCChunkSet::Range r(runtime->gcChunkSet.all()); !r.empty(); r.popFront()) {
         Chunk *chunk = r.front();
         ChunkBitmap *bitmap = &chunk->bitmap;
-        ChunkBitmap *entry = map.lookup(chunk)->value;
+        ChunkBitmap *entry = map.lookup(chunk)->value();
         Swap(*entry, *bitmap);
     }
 
     /* Restore the weak map and array buffer lists. */
     for (GCCompartmentsIter c(runtime); !c.done(); c.next()) {
         WeakMapBase::resetCompartmentWeakMapList(c);
         ArrayBufferObject::resetArrayBufferList(c);
     }
@@ -3384,17 +3385,17 @@ js::gc::MarkingValidator::validate()
         return;
 
     for (GCChunkSet::Range r(runtime->gcChunkSet.all()); !r.empty(); r.popFront()) {
         Chunk *chunk = r.front();
         BitmapMap::Ptr ptr = map.lookup(chunk);
         if (!ptr)
             continue;  /* Allocated after we did the non-incremental mark. */
 
-        ChunkBitmap *bitmap = ptr->value;
+        ChunkBitmap *bitmap = ptr->value();
         ChunkBitmap *incBitmap = &chunk->bitmap;
 
         for (size_t i = 0; i < ArenasPerChunk; i++) {
             if (chunk->decommittedArenas.get(i))
                 continue;
             Arena *arena = &chunk->arenas[i];
             if (!arena->aheader.allocated())
                 continue;
@@ -3476,17 +3477,17 @@ DropStringWrappers(JSRuntime *rt)
 {
     /*
      * String "wrappers" are dropped on GC because their presence would require
      * us to sweep the wrappers in all compartments every time we sweep a
      * compartment group.
      */
     for (CompartmentsIter c(rt, SkipAtoms); !c.done(); c.next()) {
         for (JSCompartment::WrapperEnum e(c); !e.empty(); e.popFront()) {
-            if (e.front().key.kind == CrossCompartmentKey::StringWrapper)
+            if (e.front().key().kind == CrossCompartmentKey::StringWrapper)
                 e.removeFront();
         }
     }
 }
 
 /*
  * Group zones that must be swept at the same time.
  *
@@ -3501,19 +3502,19 @@ DropStringWrappers(JSRuntime *rt)
  *
  * Tarjan's algorithm is used to calculate the components.
  */
 
 void
 JSCompartment::findOutgoingEdges(ComponentFinder<JS::Zone> &finder)
 {
     for (js::WrapperMap::Enum e(crossCompartmentWrappers); !e.empty(); e.popFront()) {
-        CrossCompartmentKey::Kind kind = e.front().key.kind;
+        CrossCompartmentKey::Kind kind = e.front().key().kind;
         JS_ASSERT(kind != CrossCompartmentKey::StringWrapper);
-        Cell *other = e.front().key.wrapped;
+        Cell *other = e.front().key().wrapped;
         if (kind == CrossCompartmentKey::ObjectWrapper) {
             /*
              * Add edge to wrapped object compartment if wrapped object is not
              * marked black to indicate that wrapper compartment not be swept
              * after wrapped compartment.
              */
             if (!other->isMarked(BLACK) || other->isMarked(GRAY)) {
                 JS::Zone *w = other->tenuredZone();
@@ -4027,18 +4028,18 @@ BeginSweepPhase(JSRuntime *rt, bool last
 #ifdef JS_THREADSAFE
     rt->gcSweepOnBackgroundThread = !lastGC && rt->useHelperThreads();
 #endif
 
 #ifdef DEBUG
     for (CompartmentsIter c(rt, SkipAtoms); !c.done(); c.next()) {
         JS_ASSERT(!c->gcIncomingGrayPointers);
         for (JSCompartment::WrapperEnum e(c); !e.empty(); e.popFront()) {
-            if (e.front().key.kind != CrossCompartmentKey::StringWrapper)
-                AssertNotOnGrayList(&e.front().value.get().toObject());
+            if (e.front().key().kind != CrossCompartmentKey::StringWrapper)
+                AssertNotOnGrayList(&e.front().value().get().toObject());
         }
     }
 #endif
 
     DropStringWrappers(rt);
     FindZoneGroups(rt);
     EndMarkingZoneGroup(rt);
     BeginSweepingZoneGroup(rt);
@@ -4250,18 +4251,18 @@ EndSweepPhase(JSRuntime *rt, JSGCInvocat
     }
 
 #ifdef DEBUG
     for (CompartmentsIter c(rt, SkipAtoms); !c.done(); c.next()) {
         JS_ASSERT(!c->gcIncomingGrayPointers);
         JS_ASSERT(!c->gcLiveArrayBuffers);
 
         for (JSCompartment::WrapperEnum e(c); !e.empty(); e.popFront()) {
-            if (e.front().key.kind != CrossCompartmentKey::StringWrapper)
-                AssertNotOnGrayList(&e.front().value.get().toObject());
+            if (e.front().key().kind != CrossCompartmentKey::StringWrapper)
+                AssertNotOnGrayList(&e.front().value().get().toObject());
         }
     }
 #endif
 
     FinishMarkingValidation(rt);
 
     rt->gcLastGCTime = PRMJ_Now();
 }
--- a/js/src/jsgc.h
+++ b/js/src/jsgc.h
@@ -11,16 +11,17 @@
 
 #include "mozilla/DebugOnly.h"
 #include "mozilla/MemoryReporting.h"
 
 #include "jslock.h"
 #include "jsobj.h"
 
 #include "js/GCAPI.h"
+#include "js/SliceBudget.h"
 #include "js/Tracer.h"
 #include "js/Vector.h"
 
 class JSAtom;
 struct JSCompartment;
 class JSFlatString;
 class JSLinearString;
 
@@ -34,17 +35,16 @@ class DebugScopeObject;
 class GCHelperThread;
 class GlobalObject;
 class LazyScript;
 class Nursery;
 class PropertyName;
 class ScopeObject;
 class Shape;
 class UnownedBaseShape;
-struct SliceBudget;
 
 unsigned GetCPUCount();
 
 enum HeapState {
     Idle,             // doing nothing with the GC heap
     Tracing,          // tracing the GC heap without collecting, e.g. IterateCompartments()
     MajorCollecting,  // doing a GC of the major heap
     MinorCollecting   // doing a GC of the minor heap (nursery)
@@ -1059,56 +1059,16 @@ struct MarkStack {
         setBaseCapacity(gcMode);
     }
 
     size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
         return mallocSizeOf(stack_);
     }
 };
 
-/*
- * This class records how much work has been done in a given GC slice, so that
- * we can return before pausing for too long. Some slices are allowed to run for
- * unlimited time, and others are bounded. To reduce the number of gettimeofday
- * calls, we only check the time every 1000 operations.
- */
-struct SliceBudget {
-    int64_t deadline; /* in microseconds */
-    intptr_t counter;
-
-    static const intptr_t CounterReset = 1000;
-
-    static const int64_t Unlimited = 0;
-    static int64_t TimeBudget(int64_t millis);
-    static int64_t WorkBudget(int64_t work);
-
-    /* Equivalent to SliceBudget(UnlimitedBudget). */
-    SliceBudget();
-
-    /* Instantiate as SliceBudget(Time/WorkBudget(n)). */
-    SliceBudget(int64_t budget);
-
-    void reset() {
-        deadline = INT64_MAX;
-        counter = INTPTR_MAX;
-    }
-
-    void step(intptr_t amt = 1) {
-        counter -= amt;
-    }
-
-    bool checkOverBudget();
-
-    bool isOverBudget() {
-        if (counter >= 0)
-            return false;
-        return checkOverBudget();
-    }
-};
-
 struct GrayRoot {
     void *thing;
     JSGCTraceKind kind;
 #ifdef DEBUG
     JSTraceNamePrinter debugPrinter;
     const void *debugPrintArg;
     size_t debugPrintIndex;
 #endif
--- a/js/src/jsinfer.cpp
+++ b/js/src/jsinfer.cpp
@@ -1817,17 +1817,17 @@ TypeCompartment::addAllocationSiteTypeOb
     if (prev) {
         AllocationSiteKey nkey;
         nkey.script = key.script;
         nkey.offset = key.script->pcToOffset(prev);
         nkey.kind = JSProto_Array;
 
         AllocationSiteTable::Ptr p = cx->compartment()->types.allocationSiteTable->lookup(nkey);
         if (p)
-            res = p->value;
+            res = p->value();
     }
 
     if (!res) {
         RootedObject proto(cx);
         if (!js_GetClassPrototype(cx, key.kind, &proto, nullptr))
             return nullptr;
 
         Rooted<TaggedProto> tagged(cx, TaggedProto(proto));
@@ -2298,17 +2298,17 @@ TypeCompartment::setTypeToHomogenousArra
             cx->compartment()->types.setPendingNukeTypes(cx);
             return;
         }
     }
 
     ArrayTableKey key(elementType, obj->getProto());
     DependentAddPtr<ArrayTypeTable> p(cx, *arrayTypeTable, key);
     if (p) {
-        obj->setType(p->value);
+        obj->setType(p->value());
     } else {
         /* Make a new type to use for future arrays with the same elements. */
         RootedObject objProto(cx, obj->getProto());
         TypeObject *objType = newTypeObject(cx, &ArrayObject::class_, objProto);
         if (!objType) {
             cx->compartment()->types.setPendingNukeTypes(cx);
             return;
         }
@@ -2487,21 +2487,21 @@ TypeCompartment::fixObjectType(Exclusive
         entry.value = obj->getSlot(shape->slot());
         shape = shape->previous();
     }
 
     ObjectTableKey::Lookup lookup(properties.begin(), properties.length(), obj->numFixedSlots());
     ObjectTypeTable::AddPtr p = objectTypeTable->lookupForAdd(lookup);
 
     if (p) {
-        JS_ASSERT(obj->getProto() == p->value.object->proto);
-        JS_ASSERT(obj->lastProperty() == p->value.shape);
-
-        UpdateObjectTableEntryTypes(cx, p->value, properties.begin(), properties.length());
-        obj->setType(p->value.object);
+        JS_ASSERT(obj->getProto() == p->value().object->proto);
+        JS_ASSERT(obj->lastProperty() == p->value().shape);
+
+        UpdateObjectTableEntryTypes(cx, p->value(), properties.begin(), properties.length());
+        obj->setType(p->value().object);
         return;
     }
 
     /* Make a new type to use for the object and similar future ones. */
     Rooted<TaggedProto> objProto(cx, obj->getTaggedProto());
     TypeObject *objType = newTypeObject(cx, &JSObject::class_, objProto);
     if (!objType || !objType->addDefiniteProperties(cx, obj)) {
         cx->compartment()->types.setPendingNukeTypes(cx);
@@ -2590,30 +2590,30 @@ TypeCompartment::newTypedObject(JSContex
     if (!p)
         return nullptr;
 
     RootedObject obj(cx, NewBuiltinClassInstance(cx, &JSObject::class_, allocKind));
     if (!obj) {
         cx->clearPendingException();
         return nullptr;
     }
-    JS_ASSERT(obj->getProto() == p->value.object->proto);
-
-    RootedShape shape(cx, p->value.shape);
+    JS_ASSERT(obj->getProto() == p->value().object->proto);
+
+    RootedShape shape(cx, p->value().shape);
     if (!JSObject::setLastProperty(cx, obj, shape)) {
         cx->clearPendingException();
         return nullptr;
     }
 
-    UpdateObjectTableEntryTypes(cx, p->value, properties, nproperties);
+    UpdateObjectTableEntryTypes(cx, p->value(), properties, nproperties);
 
     for (size_t i = 0; i < nproperties; i++)
         obj->setSlot(i, properties[i].value);
 
-    obj->setType(p->value.object);
+    obj->setType(p->value().object);
     return obj;
 }
 
 /////////////////////////////////////////////////////////////////////
 // TypeObject
 /////////////////////////////////////////////////////////////////////
 
 static inline void
@@ -4021,44 +4021,44 @@ TypeCompartment::sweep(FreeOp *fop)
 {
     /*
      * Iterate through the array/object type tables and remove all entries
      * referencing collected data. These tables only hold weak references.
      */
 
     if (arrayTypeTable) {
         for (ArrayTypeTable::Enum e(*arrayTypeTable); !e.empty(); e.popFront()) {
-            const ArrayTableKey &key = e.front().key;
+            const ArrayTableKey &key = e.front().key();
             JS_ASSERT(key.type.isUnknown() || !key.type.isSingleObject());
 
             bool remove = false;
             TypeObject *typeObject = nullptr;
             if (!key.type.isUnknown() && key.type.isTypeObject()) {
                 typeObject = key.type.typeObject();
                 if (IsTypeObjectAboutToBeFinalized(&typeObject))
                     remove = true;
             }
-            if (IsTypeObjectAboutToBeFinalized(e.front().value.unsafeGet()))
+            if (IsTypeObjectAboutToBeFinalized(e.front().value().unsafeGet()))
                 remove = true;
 
             if (remove) {
                 e.removeFront();
             } else if (typeObject && typeObject != key.type.typeObject()) {
                 ArrayTableKey newKey;
                 newKey.type = Type::ObjectType(typeObject);
                 newKey.proto = key.proto;
                 e.rekeyFront(newKey);
             }
         }
     }
 
     if (objectTypeTable) {
         for (ObjectTypeTable::Enum e(*objectTypeTable); !e.empty(); e.popFront()) {
-            const ObjectTableKey &key = e.front().key;
-            ObjectTableEntry &entry = e.front().value;
+            const ObjectTableKey &key = e.front().key();
+            ObjectTableEntry &entry = e.front().value();
 
             bool remove = false;
             if (IsTypeObjectAboutToBeFinalized(entry.object.unsafeGet()))
                 remove = true;
             if (IsShapeAboutToBeFinalized(entry.shape.unsafeGet()))
                 remove = true;
             for (unsigned i = 0; !remove && i < key.nproperties; i++) {
                 if (JSID_IS_STRING(key.properties[i])) {
@@ -4083,22 +4083,22 @@ TypeCompartment::sweep(FreeOp *fop)
                 js_free(entry.types);
                 e.removeFront();
             }
         }
     }
 
     if (allocationSiteTable) {
         for (AllocationSiteTable::Enum e(*allocationSiteTable); !e.empty(); e.popFront()) {
-            AllocationSiteKey key = e.front().key;
+            AllocationSiteKey key = e.front().key();
             bool keyDying = IsScriptAboutToBeFinalized(&key.script);
-            bool valDying = IsTypeObjectAboutToBeFinalized(e.front().value.unsafeGet());
+            bool valDying = IsTypeObjectAboutToBeFinalized(e.front().value().unsafeGet());
             if (keyDying || valDying)
                 e.removeFront();
-            else if (key.script != e.front().key.script)
+            else if (key.script != e.front().key().script)
                 e.rekeyFront(key);
         }
     }
 
     /*
      * The pending array is reset on GC, it can grow large (75+ KB) and is easy
      * to reallocate if the compartment becomes active again.
      */
@@ -4113,18 +4113,18 @@ void
 TypeCompartment::sweepShapes(FreeOp *fop)
 {
     /*
      * Sweep any weak shape references that may be finalized even if a GC is
      * preserving type information.
      */
     if (objectTypeTable) {
         for (ObjectTypeTable::Enum e(*objectTypeTable); !e.empty(); e.popFront()) {
-            const ObjectTableKey &key = e.front().key;
-            ObjectTableEntry &entry = e.front().value;
+            const ObjectTableKey &key = e.front().key();
+            ObjectTableEntry &entry = e.front().value();
 
             if (IsShapeAboutToBeFinalized(entry.shape.unsafeGet())) {
                 fop->free_(key.properties);
                 fop->free_(entry.types);
                 e.removeFront();
             }
         }
     }
@@ -4228,18 +4228,18 @@ TypeCompartment::addSizeOfExcludingThis(
 
     if (objectTypeTable) {
         *objectTypeTables += objectTypeTable->sizeOfIncludingThis(mallocSizeOf);
 
         for (ObjectTypeTable::Enum e(*objectTypeTable);
              !e.empty();
              e.popFront())
         {
-            const ObjectTableKey &key = e.front().key;
-            const ObjectTableEntry &value = e.front().value;
+            const ObjectTableKey &key = e.front().key();
+            const ObjectTableEntry &value = e.front().value();
 
             /* key.ids and values.types have the same length. */
             *objectTypeTables += mallocSizeOf(key.properties) + mallocSizeOf(value.types);
         }
     }
 }
 
 size_t
--- a/js/src/jsinferinlines.h
+++ b/js/src/jsinferinlines.h
@@ -716,17 +716,17 @@ TypeScript::InitObject(JSContext *cx, JS
     key.kind = kind;
 
     if (!cx->compartment()->types.allocationSiteTable)
         return cx->compartment()->types.addAllocationSiteTypeObject(cx, key);
 
     AllocationSiteTable::Ptr p = cx->compartment()->types.allocationSiteTable->lookup(key);
 
     if (p)
-        return p->value;
+        return p->value();
     return cx->compartment()->types.addAllocationSiteTypeObject(cx, key);
 }
 
 /* Set the type to use for obj according to the site it was allocated at. */
 static inline bool
 SetInitializerObjectType(JSContext *cx, HandleScript script, jsbytecode *pc, HandleObject obj, NewObjectKind kind)
 {
     if (!cx->typeInferenceEnabled())
--- a/js/src/jsproxy.cpp
+++ b/js/src/jsproxy.cpp
@@ -3003,17 +3003,17 @@ ProxyObject::trace(JSTracer *trc, JSObje
         JSObject *referent = &proxy->private_().toObject();
         if (referent->compartment() != proxy->compartment()) {
             /*
              * Assert that this proxy is tracked in the wrapper map. We maintain
              * the invariant that the wrapped object is the key in the wrapper map.
              */
             Value key = ObjectValue(*referent);
             WrapperMap::Ptr p = proxy->compartment()->lookupWrapper(key);
-            JS_ASSERT(*p->value.unsafeGet() == ObjectValue(*proxy));
+            JS_ASSERT(*p->value().unsafeGet() == ObjectValue(*proxy));
         }
     }
 #endif
 
     // Note: If you add new slots here, make sure to change
     // nuke() to cope.
     MarkCrossCompartmentSlot(trc, obj, proxy->slotOfPrivate(), "private");
     MarkSlot(trc, proxy->slotOfExtra(0), "extra0");
--- a/js/src/jsscript.cpp
+++ b/js/src/jsscript.cpp
@@ -907,40 +907,40 @@ static inline ScriptCountsMap::Ptr GetSc
     JS_ASSERT(p);
     return p;
 }
 
 js::PCCounts
 JSScript::getPCCounts(jsbytecode *pc) {
     JS_ASSERT(containsPC(pc));
     ScriptCountsMap::Ptr p = GetScriptCountsMapEntry(this);
-    return p->value.pcCountsVector[pcToOffset(pc)];
+    return p->value().pcCountsVector[pcToOffset(pc)];
 }
 
 void
 JSScript::addIonCounts(jit::IonScriptCounts *ionCounts)
 {
     ScriptCountsMap::Ptr p = GetScriptCountsMapEntry(this);
-    if (p->value.ionCounts)
-        ionCounts->setPrevious(p->value.ionCounts);
-    p->value.ionCounts = ionCounts;
+    if (p->value().ionCounts)
+        ionCounts->setPrevious(p->value().ionCounts);
+    p->value().ionCounts = ionCounts;
 }
 
 jit::IonScriptCounts *
 JSScript::getIonCounts()
 {
     ScriptCountsMap::Ptr p = GetScriptCountsMapEntry(this);
-    return p->value.ionCounts;
+    return p->value().ionCounts;
 }
 
 ScriptCounts
 JSScript::releaseScriptCounts()
 {
     ScriptCountsMap::Ptr p = GetScriptCountsMapEntry(this);
-    ScriptCounts counts = p->value;
+    ScriptCounts counts = p->value();
     compartment()->scriptCountsMap->remove(p);
     hasScriptCounts = false;
     return counts;
 }
 
 void
 JSScript::destroyScriptCounts(FreeOp *fop)
 {
@@ -1077,17 +1077,17 @@ SourceDataCache::AutoSuppressPurge::~Aut
 
 const jschar *
 SourceDataCache::lookup(ScriptSource *ss, const AutoSuppressPurge &asp)
 {
     JS_ASSERT(this == &asp.cache());
     if (!map_)
         return nullptr;
     if (Map::Ptr p = map_->lookup(ss))
-        return p->value;
+        return p->value();
     return nullptr;
 }
 
 bool
 SourceDataCache::put(ScriptSource *ss, const jschar *str, const AutoSuppressPurge &asp)
 {
     JS_ASSERT(this == &asp.cache());
 
@@ -1108,17 +1108,17 @@ SourceDataCache::put(ScriptSource *ss, c
 
 void
 SourceDataCache::purge()
 {
     if (!map_ || numSuppressPurges_ > 0)
         return;
 
     for (Map::Range r = map_->all(); !r.empty(); r.popFront())
-        js_delete(const_cast<jschar*>(r.front().value));
+        js_delete(const_cast<jschar*>(r.front().value()));
 
     js_delete(map_);
     map_ = nullptr;
 }
 
 const jschar *
 ScriptSource::chars(JSContext *cx, const SourceDataCache::AutoSuppressPurge &asp)
 {
@@ -2159,17 +2159,17 @@ js::GetSrcNote(GSNCache &cache, JSScript
 {
     size_t target = pc - script->code();
     if (target >= script->length())
         return nullptr;
 
     if (cache.code == script->code()) {
         JS_ASSERT(cache.map.initialized());
         GSNCache::Map::Ptr p = cache.map.lookup(pc);
-        return p ? p->value : nullptr;
+        return p ? p->value() : nullptr;
     }
 
     size_t offset = 0;
     jssrcnote *result;
     for (jssrcnote *sn = script->notes(); ; sn = SN_NEXT(sn)) {
         if (SN_IS_TERMINATOR(sn)) {
             result = nullptr;
             break;
@@ -2586,28 +2586,28 @@ js::CloneFunctionScript(JSContext *cx, H
 DebugScript *
 JSScript::debugScript()
 {
     JS_ASSERT(hasDebugScript);
     DebugScriptMap *map = compartment()->debugScriptMap;
     JS_ASSERT(map);
     DebugScriptMap::Ptr p = map->lookup(this);
     JS_ASSERT(p);
-    return p->value;
+    return p->value();
 }
 
 DebugScript *
 JSScript::releaseDebugScript()
 {
     JS_ASSERT(hasDebugScript);
     DebugScriptMap *map = compartment()->debugScriptMap;
     JS_ASSERT(map);
     DebugScriptMap::Ptr p = map->lookup(this);
     JS_ASSERT(p);
-    DebugScript *debug = p->value;
+    DebugScript *debug = p->value();
     map->remove(p);
     hasDebugScript = false;
     return debug;
 }
 
 void
 JSScript::destroyDebugScript(FreeOp *fop)
 {
--- a/js/src/jswatchpoint.cpp
+++ b/js/src/jswatchpoint.cpp
@@ -30,26 +30,27 @@ class AutoEntryHolder {
     Map &map;
     Map::Ptr p;
     uint32_t gen;
     RootedObject obj;
     RootedId id;
 
   public:
     AutoEntryHolder(JSContext *cx, Map &map, Map::Ptr p)
-        : map(map), p(p), gen(map.generation()), obj(cx, p->key.object), id(cx, p->key.id) {
-        JS_ASSERT(!p->value.held);
-        p->value.held = true;
+      : map(map), p(p), gen(map.generation()), obj(cx, p->key().object), id(cx, p->key().id)
+    {
+        JS_ASSERT(!p->value().held);
+        p->value().held = true;
     }
 
     ~AutoEntryHolder() {
         if (gen != map.generation())
             p = map.lookup(WatchKey(obj, id));
         if (p)
-            p->value.held = false;
+            p->value().held = false;
     }
 };
 
 } /* anonymous namespace */
 
 bool
 WatchpointMap::init()
 {
@@ -79,55 +80,55 @@ WatchpointMap::watch(JSContext *cx, Hand
 }
 
 void
 WatchpointMap::unwatch(JSObject *obj, jsid id,
                        JSWatchPointHandler *handlerp, JSObject **closurep)
 {
     if (Map::Ptr p = map.lookup(WatchKey(obj, id))) {
         if (handlerp)
-            *handlerp = p->value.handler;
+            *handlerp = p->value().handler;
         if (closurep) {
             // Read barrier to prevent an incorrectly gray closure from escaping the
             // watchpoint. See the comment before UnmarkGrayChildren in gc/Marking.cpp
-            JS::ExposeGCThingToActiveJS(p->value.closure, JSTRACE_OBJECT);
-            *closurep = p->value.closure;
+            JS::ExposeGCThingToActiveJS(p->value().closure, JSTRACE_OBJECT);
+            *closurep = p->value().closure;
         }
         map.remove(p);
     }
 }
 
 void
 WatchpointMap::unwatchObject(JSObject *obj)
 {
     for (Map::Enum e(map); !e.empty(); e.popFront()) {
         Map::Entry &entry = e.front();
-        if (entry.key.object == obj)
+        if (entry.key().object == obj)
             e.removeFront();
     }
 }
 
 void
 WatchpointMap::clear()
 {
     map.clear();
 }
 
 bool
 WatchpointMap::triggerWatchpoint(JSContext *cx, HandleObject obj, HandleId id, MutableHandleValue vp)
 {
     Map::Ptr p = map.lookup(WatchKey(obj, id));
-    if (!p || p->value.held)
+    if (!p || p->value().held)
         return true;
 
     AutoEntryHolder holder(cx, map, p);
 
     /* Copy the entry, since GC would invalidate p. */
-    JSWatchPointHandler handler = p->value.handler;
-    RootedObject closure(cx, p->value.closure);
+    JSWatchPointHandler handler = p->value().handler;
+    RootedObject closure(cx, p->value().closure);
 
     /* Determine the property's old value. */
     Value old;
     old.setUndefined();
     if (obj->isNative()) {
         if (Shape *shape = obj->nativeLookup(cx, id)) {
             if (shape->hasSlot())
                 old = obj->nativeGetSlot(shape->slot());
@@ -151,55 +152,56 @@ WatchpointMap::markCompartmentIterativel
 }
 
 bool
 WatchpointMap::markIteratively(JSTracer *trc)
 {
     bool marked = false;
     for (Map::Enum e(map); !e.empty(); e.popFront()) {
         Map::Entry &entry = e.front();
-        JSObject *priorKeyObj = entry.key.object;
-        jsid priorKeyId(entry.key.id.get());
-        bool objectIsLive = IsObjectMarked(const_cast<EncapsulatedPtrObject *>(&entry.key.object));
-        if (objectIsLive || entry.value.held) {
+        JSObject *priorKeyObj = entry.key().object;
+        jsid priorKeyId(entry.key().id.get());
+        bool objectIsLive =
+            IsObjectMarked(const_cast<EncapsulatedPtrObject *>(&entry.key().object));
+        if (objectIsLive || entry.value().held) {
             if (!objectIsLive) {
-                MarkObject(trc, const_cast<EncapsulatedPtrObject *>(&entry.key.object),
+                MarkObject(trc, const_cast<EncapsulatedPtrObject *>(&entry.key().object),
                            "held Watchpoint object");
                 marked = true;
             }
 
             JS_ASSERT(JSID_IS_STRING(priorKeyId) || JSID_IS_INT(priorKeyId));
-            MarkId(trc, const_cast<EncapsulatedId *>(&entry.key.id), "WatchKey::id");
+            MarkId(trc, const_cast<EncapsulatedId *>(&entry.key().id), "WatchKey::id");
 
-            if (entry.value.closure && !IsObjectMarked(&entry.value.closure)) {
-                MarkObject(trc, &entry.value.closure, "Watchpoint::closure");
+            if (entry.value().closure && !IsObjectMarked(&entry.value().closure)) {
+                MarkObject(trc, &entry.value().closure, "Watchpoint::closure");
                 marked = true;
             }
 
             /* We will sweep this entry in sweepAll if !objectIsLive. */
-            if (priorKeyObj != entry.key.object || priorKeyId != entry.key.id)
-                e.rekeyFront(WatchKey(entry.key.object, entry.key.id));
+            if (priorKeyObj != entry.key().object || priorKeyId != entry.key().id)
+                e.rekeyFront(WatchKey(entry.key().object, entry.key().id));
         }
     }
     return marked;
 }
 
 void
 WatchpointMap::markAll(JSTracer *trc)
 {
     for (Map::Enum e(map); !e.empty(); e.popFront()) {
         Map::Entry &entry = e.front();
-        WatchKey key = entry.key;
+        WatchKey key = entry.key();
         WatchKey prior = key;
         JS_ASSERT(JSID_IS_STRING(prior.id) || JSID_IS_INT(prior.id));
 
         MarkObject(trc, const_cast<EncapsulatedPtrObject *>(&key.object),
                    "held Watchpoint object");
         MarkId(trc, const_cast<EncapsulatedId *>(&key.id), "WatchKey::id");
-        MarkObject(trc, &entry.value.closure, "Watchpoint::closure");
+        MarkObject(trc, &entry.value().closure, "Watchpoint::closure");
 
         if (prior.object != key.object || prior.id != key.id)
             e.rekeyFront(key);
     }
 }
 
 void
 WatchpointMap::sweepAll(JSRuntime *rt)
@@ -210,22 +212,22 @@ WatchpointMap::sweepAll(JSRuntime *rt)
     }
 }
 
 void
 WatchpointMap::sweep()
 {
     for (Map::Enum e(map); !e.empty(); e.popFront()) {
         Map::Entry &entry = e.front();
-        JSObject *obj(entry.key.object);
+        JSObject *obj(entry.key().object);
         if (IsObjectAboutToBeFinalized(&obj)) {
-            JS_ASSERT(!entry.value.held);
+            JS_ASSERT(!entry.value().held);
             e.removeFront();
-        } else if (obj != entry.key.object) {
-            e.rekeyFront(WatchKey(obj, entry.key.id));
+        } else if (obj != entry.key().object) {
+            e.rekeyFront(WatchKey(obj, entry.key().id));
         }
     }
 }
 
 void
 WatchpointMap::traceAll(WeakMapTracer *trc)
 {
     JSRuntime *rt = trc->runtime;
@@ -236,12 +238,12 @@ WatchpointMap::traceAll(WeakMapTracer *t
 }
 
 void
 WatchpointMap::trace(WeakMapTracer *trc)
 {
     for (Map::Range r = map.all(); !r.empty(); r.popFront()) {
         Map::Entry &entry = r.front();
         trc->callback(trc, nullptr,
-                      entry.key.object.get(), JSTRACE_OBJECT,
-                      entry.value.closure.get(), JSTRACE_OBJECT);
+                      entry.key().object.get(), JSTRACE_OBJECT,
+                      entry.value().closure.get(), JSTRACE_OBJECT);
     }
 }
--- a/js/src/jsweakcache.h
+++ b/js/src/jsweakcache.h
@@ -84,24 +84,24 @@ class WeakValueCache : public HashMap<Ke
     explicit WeakValueCache(JSRuntime *rt) : Base(rt) { }
     explicit WeakValueCache(JSContext *cx) : Base(cx->runtime()) { }
 
   public:
     // Sweep all entries which have unmarked key or value.
     void sweep(FreeOp *fop) {
         // Remove all entries whose values remain unmarked.
         for (Enum e(*this); !e.empty(); e.popFront()) {
-            if (gc::IsAboutToBeFinalized(e.front().value))
+            if (gc::IsAboutToBeFinalized(e.front().value()))
                 e.removeFront();
         }
 
 #if DEBUG
         // Once we've swept, all remaining edges should stay within the
         // known-live part of the graph.
         for (Range r = Base::all(); !r.empty(); r.popFront())
-            JS_ASSERT(!gc::IsAboutToBeFinalized(r.front().value));
+            JS_ASSERT(!gc::IsAboutToBeFinalized(r.front().value()));
 #endif
     }
 };
 
 } // namespace js
 
 #endif /* jsweakcache_h */
--- a/js/src/jsweakmap.cpp
+++ b/js/src/jsweakmap.cpp
@@ -195,19 +195,19 @@ WeakMap_get_impl(JSContext *cx, CallArgs
     JSObject *key = GetKeyArg(cx, args);
     if (!key)
         return false;
 
     if (ObjectValueMap *map = args.thisv().toObject().as<WeakMapObject>().getMap()) {
         if (ObjectValueMap::Ptr ptr = map->lookup(key)) {
             // Read barrier to prevent an incorrectly gray value from escaping the
             // weak map. See the comment before UnmarkGrayChildren in gc/Marking.cpp
-            ExposeValueToActiveJS(ptr->value.get());
+            ExposeValueToActiveJS(ptr->value().get());
 
-            args.rval().set(ptr->value);
+            args.rval().set(ptr->value());
             return true;
         }
     }
 
     args.rval().set((args.length() > 1) ? args[1] : UndefinedValue());
     return true;
 }
 
@@ -352,17 +352,17 @@ JS_NondeterministicGetWeakMapKeys(JSCont
     RootedObject arr(cx, NewDenseEmptyArray(cx));
     if (!arr)
         return false;
     ObjectValueMap *map = obj->as<WeakMapObject>().getMap();
     if (map) {
         // Prevent GC from mutating the weakmap while iterating.
         gc::AutoSuppressGC suppress(cx);
         for (ObjectValueMap::Base::Range r = map->all(); !r.empty(); r.popFront()) {
-            RootedObject key(cx, r.front().key);
+            RootedObject key(cx, r.front().key());
             if (!cx->compartment()->wrap(cx, &key))
                 return false;
             if (!js_NewbornArrayPush(cx, arr, ObjectValue(*key)))
                 return false;
         }
     }
     *ret = arr;
     return true;
--- a/js/src/jsweakmap.h
+++ b/js/src/jsweakmap.h
@@ -143,26 +143,26 @@ class WeakMap : public HashMap<Key, Valu
             return false;
         gc::Mark(trc, x, "WeakMap entry value");
         JS_ASSERT(gc::IsMarked(x));
         return true;
     }
 
     void nonMarkingTraceKeys(JSTracer *trc) {
         for (Enum e(*this); !e.empty(); e.popFront()) {
-            Key key(e.front().key);
+            Key key(e.front().key());
             gc::Mark(trc, &key, "WeakMap entry key");
-            if (key != e.front().key)
+            if (key != e.front().key())
                 entryMoved(e, key);
         }
     }
 
     void nonMarkingTraceValues(JSTracer *trc) {
         for (Range r = Base::all(); !r.empty(); r.popFront())
-            gc::Mark(trc, &r.front().value, "WeakMap entry value");
+            gc::Mark(trc, &r.front().value(), "WeakMap entry value");
     }
 
     bool keyNeedsMark(JSObject *key) {
         if (JSWeakmapKeyDelegateOp op = key->getClass()->ext.weakmapKeyDelegateOp) {
             JSObject *delegate = op(key);
             /*
              * Check if the delegate is marked with any color to properly handle
              * gray marking when the key's delegate is black and the map is
@@ -176,59 +176,59 @@ class WeakMap : public HashMap<Key, Valu
     bool keyNeedsMark(gc::Cell *cell) {
         return false;
     }
 
     bool markIteratively(JSTracer *trc) {
         bool markedAny = false;
         for (Enum e(*this); !e.empty(); e.popFront()) {
             /* If the entry is live, ensure its key and value are marked. */
-            Key key(e.front().key);
+            Key key(e.front().key());
             if (gc::IsMarked(const_cast<Key *>(&key))) {
-                if (markValue(trc, &e.front().value))
+                if (markValue(trc, &e.front().value()))
                     markedAny = true;
-                if (e.front().key != key)
+                if (e.front().key() != key)
                     entryMoved(e, key);
             } else if (keyNeedsMark(key)) {
-                gc::Mark(trc, const_cast<Key *>(&key), "proxy-preserved WeakMap entry key");
-                if (e.front().key != key)
+                gc::Mark(trc, &key, "proxy-preserved WeakMap entry key");
+                if (e.front().key() != key)
                     entryMoved(e, key);
-                gc::Mark(trc, &e.front().value, "WeakMap entry value");
+                gc::Mark(trc, &e.front().value(), "WeakMap entry value");
                 markedAny = true;
             }
             key.unsafeSet(nullptr);
         }
         return markedAny;
     }
 
     void sweep() {
         /* Remove all entries whose keys remain unmarked. */
         for (Enum e(*this); !e.empty(); e.popFront()) {
-            Key k(e.front().key);
+            Key k(e.front().key());
             if (gc::IsAboutToBeFinalized(&k))
                 e.removeFront();
-            else if (k != e.front().key)
+            else if (k != e.front().key())
                 entryMoved(e, k);
         }
         /*
          * Once we've swept, all remaining edges should stay within the
          * known-live part of the graph.
          */
         assertEntriesNotAboutToBeFinalized();
     }
 
     /* memberOf can be nullptr, which means that the map is not part of a JSObject. */
     void traceMappings(WeakMapTracer *tracer) {
         for (Range r = Base::all(); !r.empty(); r.popFront()) {
-            gc::Cell *key = gc::ToMarkable(r.front().key);
-            gc::Cell *value = gc::ToMarkable(r.front().value);
+            gc::Cell *key = gc::ToMarkable(r.front().key());
+            gc::Cell *value = gc::ToMarkable(r.front().value());
             if (key && value) {
                 tracer->callback(tracer, memberOf,
-                                 key, gc::TraceKind(r.front().key),
-                                 value, gc::TraceKind(r.front().value));
+                                 key, gc::TraceKind(r.front().key()),
+                                 value, gc::TraceKind(r.front().value()));
             }
         }
     }
 
     /* Rekey an entry when moved, ensuring we do not trigger barriers. */
     void entryMoved(Enum &eArg, const Key &k) {
         typedef typename HashMap<typename Unbarriered<Key>::type,
                                  typename Unbarriered<Value>::type,
@@ -237,20 +237,20 @@ class WeakMap : public HashMap<Key, Valu
         UnbarrieredEnum &e = reinterpret_cast<UnbarrieredEnum &>(eArg);
         e.rekeyFront(reinterpret_cast<const typename Unbarriered<Key>::type &>(k));
     }
 
 protected:
     void assertEntriesNotAboutToBeFinalized() {
 #if DEBUG
         for (Range r = Base::all(); !r.empty(); r.popFront()) {
-            Key k(r.front().key);
+            Key k(r.front().key());
             JS_ASSERT(!gc::IsAboutToBeFinalized(&k));
-            JS_ASSERT(!gc::IsAboutToBeFinalized(&r.front().value));
-            JS_ASSERT(k == r.front().key);
+            JS_ASSERT(!gc::IsAboutToBeFinalized(&r.front().value()));
+            JS_ASSERT(k == r.front().key());
         }
 #endif
     }
 };
 
 } /* namespace js */
 
 extern JSObject *
--- a/js/src/jswrapper.cpp
+++ b/js/src/jswrapper.cpp
@@ -888,17 +888,17 @@ js::NukeCrossCompartmentWrappers(JSConte
     for (CompartmentsIter c(rt, SkipAtoms); !c.done(); c.next()) {
         if (!sourceFilter.match(c))
             continue;
 
         // Iterate the wrappers looking for anything interesting.
         for (JSCompartment::WrapperEnum e(c); !e.empty(); e.popFront()) {
             // Some cross-compartment wrappers are for strings.  We're not
             // interested in those.
-            const CrossCompartmentKey &k = e.front().key;
+            const CrossCompartmentKey &k = e.front().key();
             if (k.kind != CrossCompartmentKey::ObjectWrapper)
                 continue;
 
             AutoWrapperRooter wobj(cx, WrapperValue(e));
             JSObject *wrapped = UncheckedUnwrap(wobj);
 
             if (nukeReferencesToWindow == DontNukeWindowReferences &&
                 wrapped->getClass()->ext.innerObject)
@@ -936,17 +936,17 @@ js::RemapWrapper(JSContext *cx, JSObject
     // for the same target), we must not have an existing wrapper for the new
     // target, otherwise this will break.
     JS_ASSERT_IF(origTarget != newTarget,
                  !wcompartment->lookupWrapper(ObjectValue(*newTarget)));
 
     // The old value should still be in the cross-compartment wrapper map, and
     // the lookup should return wobj.
     WrapperMap::Ptr p = wcompartment->lookupWrapper(origv);
-    JS_ASSERT(&p->value.unsafeGet()->toObject() == wobj);
+    JS_ASSERT(&p->value().unsafeGet()->toObject() == wobj);
     wcompartment->removeWrapper(p);
 
     // When we remove origv from the wrapper map, its wrapper, wobj, must
     // immediately cease to be a cross-compartment wrapper. Neuter it.
     NukeCrossCompartmentWrapper(cx, wobj);
 
     // First, we wrap it in the new compartment. We try to use the existing
     // wrapper, |wobj|, since it's been nuked anyway. The wrap() function has
@@ -1020,17 +1020,17 @@ js::RecomputeWrappers(JSContext *cx, con
     for (CompartmentsIter c(cx->runtime(), SkipAtoms); !c.done(); c.next()) {
         // Filter by source compartment.
         if (!sourceFilter.match(c))
             continue;
 
         // Iterate over the wrappers, filtering appropriately.
         for (JSCompartment::WrapperEnum e(c); !e.empty(); e.popFront()) {
             // Filter out non-objects.
-            const CrossCompartmentKey &k = e.front().key;
+            const CrossCompartmentKey &k = e.front().key();
             if (k.kind != CrossCompartmentKey::ObjectWrapper)
                 continue;
 
             // Filter by target compartment.
             if (!targetFilter.match(static_cast<JSObject *>(k.wrapped)->compartment()))
                 continue;
 
             // Add it to the list.
--- a/js/src/moz.build
+++ b/js/src/moz.build
@@ -76,16 +76,17 @@ EXPORTS.js += [
     '../public/Id.h',
     '../public/LegacyIntTypes.h',
     '../public/MemoryMetrics.h',
     '../public/OldDebugAPI.h',
     '../public/ProfilingStack.h',
     '../public/PropertyKey.h',
     '../public/RequiredDefines.h',
     '../public/RootingAPI.h',
+    '../public/SliceBudget.h',
     '../public/StructuredClone.h',
     '../public/Tracer.h',
     '../public/TypeDecls.h',
     '../public/Utility.h',
     '../public/Value.h',
     '../public/Vector.h',
 ]
 
--- a/js/src/shell/jsheaptools.cpp
+++ b/js/src/shell/jsheaptools.cpp
@@ -241,18 +241,18 @@ class HeapReverser : public JSTracer, pu
         return OBJECT_TO_JSVAL(object);
     }
 
     /* Keep all tracked objects live across GC. */
     virtual void trace(JSTracer *trc) MOZ_OVERRIDE {
         if (!map.initialized())
             return;
         for (Map::Enum e(map); !e.empty(); e.popFront()) {
-            gc::MarkGCThingRoot(trc, const_cast<void **>(&e.front().key), "HeapReverser::map::key");
-            e.front().value.trace(trc);
+            gc::MarkGCThingRoot(trc, const_cast<void **>(&e.front().key()), "HeapReverser::map::key");
+            e.front().value().trace(trc);
         }
         for (Child *c = work.begin(); c != work.end(); ++c)
             gc::MarkGCThingRoot(trc, &c->cell, "HeapReverser::Child");
     }
 };
 
 bool
 HeapReverser::traverseEdge(void *cell, JSGCTraceKind kind)
@@ -276,17 +276,17 @@ HeapReverser::traverseEdge(void *cell, J
             !work.append(Child(cell, kind)))
             return false;
         /* If the map has been resized, re-check the pointer. */
         if (map.generation() != generation)
             a = map.lookupForAdd(cell);
     }
 
     /* Add this edge to the reversed map. */
-    return a->value.incoming.append(Move(e));
+    return a->value().incoming.append(Move(e));
 }
 
 bool
 HeapReverser::reverseHeap()
 {
     traversalStatus = true;
 
     /* Prime the work stack with the roots of collection. */
@@ -422,17 +422,17 @@ ReferenceFinder::visit(void *cell, Path 
     JS_CHECK_RECURSION(context, return false);
 
     /* Have we reached a root? Always report that. */
     if (!cell)
         return addReferrer(JSVAL_NULL, path);
 
     HeapReverser::Map::Ptr p = reverser.map.lookup(cell);
     JS_ASSERT(p);
-    HeapReverser::Node *node = &p->value;
+    HeapReverser::Node *node = &p->value();
 
     /* Is |cell| a representable cell, reached via a non-empty path? */
     if (path != nullptr) {
         jsval representation = representable(cell, node->kind);
         if (!JSVAL_IS_VOID(representation))
             return addReferrer(representation, path);
     }
 
--- a/js/src/vm/Debugger.cpp
+++ b/js/src/vm/Debugger.cpp
@@ -206,17 +206,17 @@ class Debugger::FrameRange
     }
 
     bool empty() const {
         return nextDebugger >= debuggerCount;
     }
 
     JSObject *frontFrame() const {
         JS_ASSERT(!empty());
-        return entry->value;
+        return entry->value();
     }
 
     Debugger *frontDebugger() const {
         JS_ASSERT(!empty());
         return (*debuggers)[nextDebugger];
     }
 
     /*
@@ -463,17 +463,17 @@ Debugger::getScriptFrame(JSContext *cx, 
         frameobj->setPrivate(frame.raw());
         frameobj->setReservedSlot(JSSLOT_DEBUGFRAME_OWNER, ObjectValue(*object));
 
         if (!frames.add(p, frame, frameobj)) {
             js_ReportOutOfMemory(cx);
             return false;
         }
     }
-    vp.setObject(*p->value);
+    vp.setObject(*p->value());
     return true;
 }
 
 JSObject *
 Debugger::getHook(Hook hook) const
 {
     JS_ASSERT(hook >= 0 && hook < HookCount);
     const Value &v = object->getReservedSlot(JSSLOT_DEBUG_HOOK_START + hook);
@@ -496,17 +496,17 @@ Debugger::hasAnyLiveHooks() const
 
     /* If any breakpoints are in live scripts, return true. */
     for (Breakpoint *bp = firstBreakpoint(); bp; bp = bp->nextInDebugger()) {
         if (IsScriptMarked(&bp->site->script))
             return true;
     }
 
     for (FrameMap::Range r = frames.all(); !r.empty(); r.popFront()) {
-        JSObject *frameObj = r.front().value;
+        JSObject *frameObj = r.front().value();
         if (!frameObj->getReservedSlot(JSSLOT_DEBUGFRAME_ONSTEP_HANDLER).isUndefined() ||
             !frameObj->getReservedSlot(JSSLOT_DEBUGFRAME_ONPOP_HANDLER).isUndefined())
             return true;
     }
 
     return false;
 }
 
@@ -669,17 +669,17 @@ Debugger::wrapEnvironment(JSContext *cx,
      * DebuggerEnv should only wrap a debug scope chain obtained (transitively)
      * from GetDebugScopeFor(Frame|Function).
      */
     JS_ASSERT(!env->is<ScopeObject>());
 
     JSObject *envobj;
     DependentAddPtr<ObjectWeakMap> p(cx, environments, env);
     if (p) {
-        envobj = p->value;
+        envobj = p->value();
     } else {
         /* Create a new Debugger.Environment for env. */
         JSObject *proto = &object->getReservedSlot(JSSLOT_DEBUG_ENV_PROTO).toObject();
         envobj = NewObjectWithGivenProto(cx, &DebuggerEnv_class, proto, nullptr, TenuredObject);
         if (!envobj)
             return false;
         envobj->setPrivateGCThing(env);
         envobj->setReservedSlot(JSSLOT_DEBUGENV_OWNER, ObjectValue(*object));
@@ -710,17 +710,17 @@ Debugger::wrapDebuggeeValue(JSContext *c
         if (obj->is<JSFunction>()) {
             RootedFunction fun(cx, &obj->as<JSFunction>());
             if (!EnsureFunctionHasScript(cx, fun))
                 return false;
         }
 
         DependentAddPtr<ObjectWeakMap> p(cx, objects, obj);
         if (p) {
-            vp.setObject(*p->value);
+            vp.setObject(*p->value());
         } else {
             /* Create a new Debugger.Object for obj. */
             JSObject *proto = &object->getReservedSlot(JSSLOT_DEBUG_OBJECT_PROTO).toObject();
             JSObject *dobj =
                 NewObjectWithGivenProto(cx, &DebuggerObject_class, proto, nullptr, TenuredObject);
             if (!dobj)
                 return false;
             dobj->setPrivateGCThing(obj);
@@ -1262,18 +1262,18 @@ Debugger::onSingleStep(JSContext *cx, Mu
     {
         uint32_t stepperCount = 0;
         JSScript *trappingScript = iter.script();
         GlobalObject *global = cx->global();
         if (GlobalObject::DebuggerVector *debuggers = global->getDebuggers()) {
             for (Debugger **p = debuggers->begin(); p != debuggers->end(); p++) {
                 Debugger *dbg = *p;
                 for (FrameMap::Range r = dbg->frames.all(); !r.empty(); r.popFront()) {
-                    AbstractFramePtr frame = r.front().key;
-                    JSObject *frameobj = r.front().value;
+                    AbstractFramePtr frame = r.front().key();
+                    JSObject *frameobj = r.front().value();
                     if (frame.script() == trappingScript &&
                         !frameobj->getReservedSlot(JSSLOT_DEBUGFRAME_ONSTEP_HANDLER).isUndefined())
                     {
                         stepperCount++;
                     }
                 }
             }
         }
@@ -1589,17 +1589,17 @@ Debugger::trace(JSTracer *trc)
      * Mark Debugger.Frame objects. These are all reachable from JS, because the
      * corresponding StackFrames are still on the stack.
      *
      * (Once we support generator frames properly, we will need
      * weakly-referenced Debugger.Frame objects as well, for suspended generator
      * frames.)
      */
     for (FrameMap::Range r = frames.all(); !r.empty(); r.popFront()) {
-        RelocatablePtrObject &frameobj = r.front().value;
+        RelocatablePtrObject &frameobj = r.front().value();
         JS_ASSERT(frameobj->getPrivate());
         MarkObject(trc, &frameobj, "live Debugger.Frame");
     }
 
     /* Trace the weak map from JSScript instances to Debugger.Script objects. */
     scripts.trace(trc);
 
     /* Trace the referent ->Debugger.Source weak map */
@@ -2267,19 +2267,19 @@ Debugger::removeDebuggeeGlobal(FreeOp *f
      * objects referring to a particular js::StackFrame. This is hard if
      * Debugger objects that are no longer debugging the relevant global might
      * have live Frame objects. So we take the easy way out and kill them here.
      * This is a bug, since it's observable and contrary to the spec. One
      * possible fix would be to put such objects into a compartment-wide bag
      * which slowPathOnLeaveFrame would have to examine.
      */
     for (FrameMap::Enum e(frames); !e.empty(); e.popFront()) {
-        AbstractFramePtr frame = e.front().key;
+        AbstractFramePtr frame = e.front().key();
         if (&frame.script()->global() == global) {
-            DebuggerFrame_freeScriptFrameIterData(fop, e.front().value);
+            DebuggerFrame_freeScriptFrameIterData(fop, e.front().value());
             e.removeFront();
         }
     }