Merge inbound to central, a=merge
authorWes Kocher <wkocher@mozilla.com>
Mon, 06 Jul 2015 17:07:18 -0700
changeset 275883 e8e7191442b368c9a37242ff1fc0188e2e1bfde3
parent 275800 d4708e272a05b73aad895060094b03321fbb6ba9 (current diff)
parent 275882 cf4897732a5f9db1fb68596449be7416fa05a98c (diff)
child 275884 358ebab1fafe6bbcdcc10286212b23e6d2c635f2
push id3246
push usergijskruitbosch@gmail.com
push dateTue, 07 Jul 2015 09:06:38 +0000
reviewersmerge
milestone42.0a1
Merge inbound to central, a=merge
gfx/thebes/gfxD2DSurface.cpp
gfx/thebes/gfxD2DSurface.h
--- a/accessible/base/DocManager.cpp
+++ b/accessible/base/DocManager.cpp
@@ -452,20 +452,22 @@ DocManager::CreateDocOrRootAccessible(ns
     // Note: don't use AccReorderEvent to avoid coalsecense and special reorder
     // events processing.
     docAcc->FireDelayedEvent(nsIAccessibleEvent::EVENT_REORDER,
                              ApplicationAcc());
 
     if (IPCAccessibilityActive()) {
       DocAccessibleChild* ipcDoc = new DocAccessibleChild(docAcc);
       docAcc->SetIPCDoc(ipcDoc);
-      nsCOMPtr<nsITabChild> tabChild =
-        do_GetInterface(aDocument->GetDocShell());
-    static_cast<TabChild*>(tabChild.get())->
-      SendPDocAccessibleConstructor(ipcDoc, nullptr, 0);
+      nsIDocShell* docShell = aDocument->GetDocShell();
+      if (docShell) {
+        nsCOMPtr<nsITabChild> tabChild = do_GetInterface(docShell);
+        static_cast<TabChild*>(tabChild.get())->
+          SendPDocAccessibleConstructor(ipcDoc, nullptr, 0);
+      }
     }
   } else {
     parentDocAcc->BindChildDocument(docAcc);
   }
 
 #ifdef A11Y_LOG
   if (logging::IsEnabled(logging::eDocCreate)) {
     logging::DocCreate("document creation finished", aDocument);
--- a/b2g/app/b2g.js
+++ b/b2g/app/b2g.js
@@ -923,16 +923,18 @@ pref("general.useragent.updates.enabled"
 pref("general.useragent.updates.url", "https://dynamicua.cdn.mozilla.net/0/%APP_ID%");
 pref("general.useragent.updates.interval", 604800); // 1 week
 pref("general.useragent.updates.retry", 86400); // 1 day
 // Device ID can be composed of letter, numbers, hyphen ("-") and dot (".")
 pref("general.useragent.device_id", "");
 
 // Make <audio> and <video> talk to the AudioChannelService.
 pref("media.useAudioChannelService", true);
+// Add Mozilla AudioChannel APIs.
+pref("media.useAudioChannelAPI", true);
 
 pref("b2g.version", @MOZ_B2G_VERSION@);
 pref("b2g.osName", @MOZ_B2G_OS_NAME@);
 
 // Disable console buffering to save memory.
 pref("consoleservice.buffered", false);
 
 #ifdef MOZ_WIDGET_GONK
--- a/b2g/chrome/content/settings.js
+++ b/b2g/chrome/content/settings.js
@@ -550,29 +550,31 @@ let settingsToObserve = {
     defaultValue: false
   },
   'devtools.eventlooplag.threshold': 100,
   'devtools.remote.wifi.visible': {
     resetToPref: true
   },
   'dom.mozApps.use_reviewer_certs': false,
   'dom.mozApps.signed_apps_installable_from': 'https://marketplace.firefox.com',
+  'dom.serviceWorkers.interception.enabled': true,
+  'dom.serviceWorkers.testing.enabled': false,
   'gfx.layerscope.enabled': false,
   'layers.draw-borders': false,
   'layers.draw-tile-borders': false,
   'layers.dump': false,
   'layers.enable-tiles': true,
   'layers.effect.invert': false,
   'layers.effect.grayscale': false,
-  'layers.effect.contrast': "0.0",
+  'layers.effect.contrast': '0.0',
+  'mms.debugging.enabled': false,
   'network.debugging.enabled': false,
   'privacy.donottrackheader.enabled': false,
   'ril.debugging.enabled': false,
   'ril.radio.disabled': false,
-  'mms.debugging.enabled': false,
   'ril.mms.requestReadReport.enabled': {
     prefName: 'dom.mms.requestReadReport',
     defaultValue: true
   },
   'ril.mms.requestStatusReport.enabled': {
     prefName: 'dom.mms.requestStatusReport',
     defaultValue: false
   },
--- a/dom/audiochannel/tests/test_telephonyPolicy.html
+++ b/dom/audiochannel/tests/test_telephonyPolicy.html
@@ -47,16 +47,17 @@ var tests = [
        { "type": "embed-apps", "allow": 1, "context": document },
        { "type": "webapps-manage", "allow": 1, "context": document },
        { "type": "audio-channel-telephony", "allow": 1, "context": document }], runTest);
   },
 
   // Preferences
   function() {
     SpecialPowers.pushPrefEnv({"set": [["dom.ipc.browser_frames.oop_by_default", true],
+                                       ["media.useAudioChannelAPI", true],
                                        ["media.useAudioChannelService", true],
                                        ["media.defaultAudioChannel", "telephony"],
                                        ["dom.mozBrowserFramesEnabled", true],
                                        ["network.disable.ipc.security", true]]}, runTest);
   },
 
   // Run 2 apps
   mainApp,
--- a/dom/base/FragmentOrElement.cpp
+++ b/dom/base/FragmentOrElement.cpp
@@ -8,17 +8,16 @@
  * Base class for all element classes; this provides an implementation
  * of DOM Core's nsIDOMElement, implements nsIContent, provides
  * utility methods for subclasses, and so forth.
  */
 
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/Likely.h"
 #include "mozilla/MemoryReporting.h"
-#include "mozilla/SegmentedVector.h"
 #include "mozilla/StaticPtr.h"
 
 #include "mozilla/dom/FragmentOrElement.h"
 
 #include "mozilla/AsyncEventDispatcher.h"
 #include "mozilla/EventDispatcher.h"
 #include "mozilla/EventListenerManager.h"
 #include "mozilla/EventStates.h"
@@ -1222,22 +1221,34 @@ FragmentOrElement::FireNodeInserted(nsID
       mozAutoSubtreeModified subtree(aDoc, aParent);
       (new AsyncEventDispatcher(childContent, mutation))->RunDOMEventWhenSafe();
     }
   }
 }
 
 //----------------------------------------------------------------------
 
-class ContentUnbinder
+// nsISupports implementation
+
+#define SUBTREE_UNBINDINGS_PER_RUNNABLE 500
+
+class ContentUnbinder : public nsRunnable
 {
-  static const size_t kSegmentSize = sizeof(void*) * 512;
-  typedef SegmentedVector<nsCOMPtr<nsIContent>, kSegmentSize, InfallibleAllocPolicy> ContentArray;
-
-  static void UnbindSubtree(nsIContent* aNode)
+public:
+  ContentUnbinder()
+  {
+    mLast = this;
+  }
+
+  ~ContentUnbinder()
+  {
+    Run();
+  }
+
+  void UnbindSubtree(nsIContent* aNode)
   {
     if (aNode->NodeType() != nsIDOMNode::ELEMENT_NODE &&
         aNode->NodeType() != nsIDOMNode::DOCUMENT_FRAGMENT_NODE) {
       return;
     }
     FragmentOrElement* container = static_cast<FragmentOrElement*>(aNode);
     uint32_t childCount = container->mAttrsAndChildren.ChildCount();
     if (childCount) {
@@ -1253,66 +1264,83 @@ class ContentUnbinder
           container->mFirstChild = nullptr;
         }
         UnbindSubtree(child);
         child->UnbindFromTree();
       }
     }
   }
 
-  // These two methods are based on DeferredFinalizerImpl.
-
-  static void*
-  AppendContentUnbinderPointer(void* aData, void* aObject)
+  NS_IMETHOD Run()
   {
-    ContentArray* contentArray = static_cast<ContentArray*>(aData);
-    if (!contentArray) {
-      contentArray = new ContentArray();
+    nsAutoScriptBlocker scriptBlocker;
+    uint32_t len = mSubtreeRoots.Length();
+    if (len) {
+      for (uint32_t i = 0; i < len; ++i) {
+        UnbindSubtree(mSubtreeRoots[i]);
+      }
+      mSubtreeRoots.Clear();
     }
-
-    contentArray->InfallibleAppend(dont_AddRef(static_cast<nsIContent*>(aObject)));
-    return contentArray;
+    nsCycleCollector_dispatchDeferredDeletion();
+    if (this == sContentUnbinder) {
+      sContentUnbinder = nullptr;
+      if (mNext) {
+        nsRefPtr<ContentUnbinder> next;
+        next.swap(mNext);
+        sContentUnbinder = next;
+        next->mLast = mLast;
+        mLast = nullptr;
+        NS_DispatchToMainThread(next);
+      }
+    }
+    return NS_OK;
   }
 
-  static bool
-  DeferredFinalize(uint32_t aSliceBudget, void* aData)
+  static void UnbindAll()
   {
-    MOZ_ASSERT(aSliceBudget > 0, "nonsensical/useless call with aSliceBudget == 0");
-    nsAutoScriptBlocker scriptBlocker;
-    ContentArray* contentArray = static_cast<ContentArray*>(aData);
-
-    size_t numToRemove = contentArray->Length();
-    if (aSliceBudget < numToRemove) {
-      numToRemove = aSliceBudget;
+    nsRefPtr<ContentUnbinder> ub = sContentUnbinder;
+    sContentUnbinder = nullptr;
+    while (ub) {
+      ub->Run();
+      ub = ub->mNext;
     }
-
-    for (size_t i = 0; i < numToRemove; ++i) {
-      nsCOMPtr<nsIContent> element = contentArray->GetLast().forget();
-      contentArray->PopLast();
-      UnbindSubtree(element);
+  }
+
+  static void Append(nsIContent* aSubtreeRoot)
+  {
+    if (!sContentUnbinder) {
+      sContentUnbinder = new ContentUnbinder();
+      nsCOMPtr<nsIRunnable> e = sContentUnbinder;
+      NS_DispatchToMainThread(e);
+    }
+
+    if (sContentUnbinder->mLast->mSubtreeRoots.Length() >=
+        SUBTREE_UNBINDINGS_PER_RUNNABLE) {
+      sContentUnbinder->mLast->mNext = new ContentUnbinder();
+      sContentUnbinder->mLast = sContentUnbinder->mLast->mNext;
     }
-
-    nsCycleCollector_dispatchDeferredDeletion();
-
-    if (contentArray->Length() == 0) {
-      delete contentArray;
-      return true;
-    }
-    return false;
+    sContentUnbinder->mLast->mSubtreeRoots.AppendElement(aSubtreeRoot);
   }
 
-public:
-  static void
-  Append(nsIContent* aSubtreeRoot)
-  {
-    nsCOMPtr<nsIContent> root = aSubtreeRoot;
-    mozilla::DeferredFinalize(AppendContentUnbinderPointer, DeferredFinalize, root.forget().take());
-  }
+private:
+  nsAutoTArray<nsCOMPtr<nsIContent>,
+               SUBTREE_UNBINDINGS_PER_RUNNABLE> mSubtreeRoots;
+  nsRefPtr<ContentUnbinder>                     mNext;
+  ContentUnbinder*                              mLast;
+  static ContentUnbinder*                       sContentUnbinder;
 };
 
+ContentUnbinder* ContentUnbinder::sContentUnbinder = nullptr;
+
+void
+FragmentOrElement::ClearContentUnbinder()
+{
+  ContentUnbinder::UnbindAll();
+}
+
 NS_IMPL_CYCLE_COLLECTION_CLASS(FragmentOrElement)
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(FragmentOrElement)
   nsINode::Unlink(tmp);
 
   // The XBL binding is removed by RemoveFromBindingManagerRunnable
   // which is dispatched in UnbindFromTree.
 
--- a/dom/base/FragmentOrElement.h
+++ b/dom/base/FragmentOrElement.h
@@ -60,17 +60,17 @@ public:
   void NoticeNodeDestruction()
   {
     mNode = nullptr;
   }
 
 private:
   ~nsNodeWeakReference();
 
-  nsINode* mNode;
+  nsINode* MOZ_NON_OWNING_REF mNode;
 };
 
 /**
  * Tearoff to use for nodes to implement nsISupportsWeakReference
  */
 class nsNodeSupportsWeakRefTearoff final : public nsISupportsWeakReference
 {
 public:
@@ -210,16 +210,17 @@ public:
     return mRefCnt.IsPurple();
   }
 
   virtual void RemovePurple() override
   {
     mRefCnt.RemovePurple();
   }
 
+  static void ClearContentUnbinder();
   static bool CanSkip(nsINode* aNode, bool aRemovingAllowed);
   static bool CanSkipInCC(nsINode* aNode);
   static bool CanSkipThis(nsINode* aNode);
   static void RemoveBlackMarkedNode(nsINode* aNode);
   static void MarkNodeChildren(nsINode* aNode);
   static void InitCCCallbacks();
   static void MarkUserData(void* aObject, nsIAtom* aKey, void* aChild,
                            void *aData);
--- a/dom/base/nsCCUncollectableMarker.cpp
+++ b/dom/base/nsCCUncollectableMarker.cpp
@@ -313,16 +313,18 @@ MarkWindowList(nsISimpleEnumerator* aWin
   }
 }
 
 nsresult
 nsCCUncollectableMarker::Observe(nsISupports* aSubject, const char* aTopic,
                                  const char16_t* aData)
 {
   if (!strcmp(aTopic, "xpcom-shutdown")) {
+    Element::ClearContentUnbinder();
+
     nsCOMPtr<nsIObserverService> obs =
       mozilla::services::GetObserverService();
     if (!obs)
       return NS_ERROR_FAILURE;
 
     // No need for kungFuDeathGrip here, yay observerservice!
     obs->RemoveObserver(this, "xpcom-shutdown");
     obs->RemoveObserver(this, "cycle-collector-begin");
@@ -337,16 +339,19 @@ nsCCUncollectableMarker::Observe(nsISupp
                !strcmp(aTopic, "cycle-collector-forget-skippable"), "wrong topic");
 
   // JS cleanup can be slow. Do it only if there has been a GC.
   bool cleanupJS =
     nsJSContext::CleanupsSinceLastGC() == 0 &&
     !strcmp(aTopic, "cycle-collector-forget-skippable");
 
   bool prepareForCC = !strcmp(aTopic, "cycle-collector-begin");
+  if (prepareForCC) {
+    Element::ClearContentUnbinder();
+  }
 
   // Increase generation to effectively unmark all current objects
   if (!++sGeneration) {
     ++sGeneration;
   }
 
   nsFocusManager::MarkUncollectableForCCGeneration(sGeneration);
 
--- a/dom/base/nsIMutationObserver.h
+++ b/dom/base/nsIMutationObserver.h
@@ -57,26 +57,26 @@ struct CharacterDataChangeInfo
   /**
    * The net result is that mChangeStart characters at the beginning of the
    * text remained as they were.  The next mChangeEnd - mChangeStart characters
    * were removed, and mReplaceLength characters were inserted in their place.
    * The text that used to begin at mChangeEnd now begins at
    * mChangeStart + mReplaceLength.
    */
 
-  struct Details {
+  struct MOZ_STACK_CLASS Details {
     enum {
       eMerge,  // two text nodes are merged as a result of normalize()
       eSplit   // a text node is split as a result of splitText()
     } mType;
     /**
      * For eMerge it's the text node that will be removed, for eSplit it's the
      * new text node.
      */
-    nsIContent* mNextSibling;
+    nsIContent* MOZ_NON_OWNING_REF mNextSibling;
   };
 
   /**
    * Used for splitText() and normalize(), otherwise null.
    */
   Details* mDetails;
 };
 
--- a/dom/base/nsPIDOMWindow.h
+++ b/dom/base/nsPIDOMWindow.h
@@ -773,17 +773,20 @@ protected:
   // Cache the URI when mDoc is cleared.
   nsCOMPtr<nsIURI> mDocumentURI; // strong
   nsCOMPtr<nsIURI> mDocBaseURI; // strong
 
   nsCOMPtr<mozilla::dom::EventTarget> mParentTarget; // strong
 
   // These members are only used on outer windows.
   nsCOMPtr<mozilla::dom::Element> mFrameElement;
-  nsIDocShell           *mDocShell;  // Weak Reference
+  // This reference is used by the subclass nsGlobalWindow, and cleared in it's
+  // DetachFromDocShell() method. This method is called by nsDocShell::Destroy(),
+  // which is called before the nsDocShell is destroyed.
+  nsIDocShell* MOZ_NON_OWNING_REF mDocShell;  // Weak Reference
 
   // mPerformance is only used on inner windows.
   nsRefPtr<nsPerformance>       mPerformance;
 
   uint32_t               mModalStateDepth;
 
   // These variables are only used on inner windows.
   nsTimeout             *mRunningTimeout;
--- a/dom/bindings/BindingUtils.h
+++ b/dom/bindings/BindingUtils.h
@@ -41,25 +41,16 @@
 
 class nsIJSID;
 class nsPIDOMWindow;
 
 namespace mozilla {
 namespace dom {
 template<typename DataType> class MozMap;
 
-struct SelfRef
-{
-  SelfRef() : ptr(nullptr) {}
-  explicit SelfRef(nsISupports *p) : ptr(p) {}
-  ~SelfRef() { NS_IF_RELEASE(ptr); }
-
-  nsISupports* ptr;
-};
-
 nsresult
 UnwrapArgImpl(JS::Handle<JSObject*> src, const nsIID& iid, void** ppArg);
 
 /** Convert a jsval to an XPCOM pointer. */
 template <class Interface>
 inline nsresult
 UnwrapArg(JS::Handle<JSObject*> src, Interface** ppArg)
 {
--- a/dom/events/EventStateManager.cpp
+++ b/dom/events/EventStateManager.cpp
@@ -450,16 +450,19 @@ EventStateManager::ReleaseCurrentIMECont
   }
   mIMEContentObserver = nullptr;
 }
 
 void
 EventStateManager::OnStartToObserveContent(
                      IMEContentObserver* aIMEContentObserver)
 {
+  if (mIMEContentObserver == aIMEContentObserver) {
+    return;
+  }
   ReleaseCurrentIMEContentObserver();
   mIMEContentObserver = aIMEContentObserver;
 }
 
 void
 EventStateManager::OnStopObservingContent(
                      IMEContentObserver* aIMEContentObserver)
 {
--- a/dom/html/HTMLMediaElement.cpp
+++ b/dom/html/HTMLMediaElement.cpp
@@ -1071,16 +1071,21 @@ static bool IsAutoplayEnabled()
   return Preferences::GetBool("media.autoplay.enabled");
 }
 
 static bool UseAudioChannelService()
 {
   return Preferences::GetBool("media.useAudioChannelService");
 }
 
+static bool UseAudioChannelAPI()
+{
+  return Preferences::GetBool("media.useAudioChannelAPI");
+}
+
 void HTMLMediaElement::UpdatePreloadAction()
 {
   PreloadAction nextAction = PRELOAD_UNDEFINED;
   // If autoplay is set, or we're playing, we should always preload data,
   // as we'll need it to play.
   if ((IsAutoplayEnabled() && HasAttr(kNameSpaceID_None, nsGkAtoms::autoplay)) ||
       !mPaused)
   {
@@ -4440,21 +4445,25 @@ nsresult HTMLMediaElement::UpdateChannel
       (aCanPlay != AUDIO_CHANNEL_STATE_FADED && mAudioChannelFaded)) {
     mAudioChannelFaded = !mAudioChannelFaded;
     SetVolumeInternal();
   }
 
   // We have to mute this channel.
   if (aCanPlay == AUDIO_CHANNEL_STATE_MUTED && !(mMuted & MUTED_BY_AUDIO_CHANNEL)) {
     SetMutedInternal(mMuted | MUTED_BY_AUDIO_CHANNEL);
-    DispatchAsyncEvent(NS_LITERAL_STRING("mozinterruptbegin"));
+    if (UseAudioChannelAPI()) {
+      DispatchAsyncEvent(NS_LITERAL_STRING("mozinterruptbegin"));
+    }
   } else if (aCanPlay != AUDIO_CHANNEL_STATE_MUTED &&
              (mMuted & MUTED_BY_AUDIO_CHANNEL)) {
     SetMutedInternal(mMuted & ~MUTED_BY_AUDIO_CHANNEL);
-    DispatchAsyncEvent(NS_LITERAL_STRING("mozinterruptend"));
+    if (UseAudioChannelAPI()) {
+      DispatchAsyncEvent(NS_LITERAL_STRING("mozinterruptend"));
+    }
   }
 
   SuspendOrResumeElement(mMuted & MUTED_BY_AUDIO_CHANNEL, false);
   return NS_OK;
 }
 
 void HTMLMediaElement::UpdateAudioChannelPlayingState()
 {
--- a/dom/inputmethod/Keyboard.jsm
+++ b/dom/inputmethod/Keyboard.jsm
@@ -258,17 +258,17 @@ this.Keyboard = {
       case 'Keyboard:SetComposition':
         this.setComposition(msg);
         break;
       case 'Keyboard:EndComposition':
         this.endComposition(msg);
         break;
       case 'Keyboard:Register':
         this._keyboardMM = mm;
-        if (kbID !== null) {
+        if (kbID) {
           // keyboard identifies itself, use its kbID
           // this msg would be async, so no need to return
           this._keyboardID = kbID;
         }else{
           // generate the id for the keyboard
           this._keyboardID = this._nextKeyboardID;
           this._nextKeyboardID++;
           // this msg is sync,
--- a/dom/inputmethod/MozKeyboard.js
+++ b/dom/inputmethod/MozKeyboard.js
@@ -14,84 +14,115 @@ Cu.import("resource://gre/modules/DOMReq
 
 XPCOMUtils.defineLazyServiceGetter(this, "cpmm",
   "@mozilla.org/childprocessmessagemanager;1", "nsISyncMessageSender");
 
 XPCOMUtils.defineLazyServiceGetter(this, "tm",
   "@mozilla.org/thread-manager;1", "nsIThreadManager");
 
 /*
- * A WeakMap to map input method iframe window to its active status and kbID.
+ * A WeakMap to map input method iframe window to
+ * it's active status, kbID, and ipcHelper.
  */
 let WindowMap = {
   // WeakMap of <window, object> pairs.
   _map: null,
 
   /*
+   * Set the object associated to the window and return it.
+   */
+  _getObjForWin: function(win) {
+    if (!this._map) {
+      this._map = new WeakMap();
+    }
+    if (this._map.has(win)) {
+      return this._map.get(win);
+    } else {
+      let obj = {
+        active: false,
+        kbID: undefined,
+        ipcHelper: null
+      };
+      this._map.set(win, obj);
+
+      return obj;
+    }
+  },
+
+  /*
    * Check if the given window is active.
    */
   isActive: function(win) {
     if (!this._map || !win) {
       return false;
     }
 
-    let obj = this._map.get(win);
-    if (obj && 'active' in obj) {
-      return obj.active;
-    }else{
-      return false;
-    }
+    return this._getObjForWin(win).active;
   },
 
   /*
    * Set the active status of the given window.
    */
   setActive: function(win, isActive) {
     if (!win) {
       return;
     }
-    if (!this._map) {
-      this._map = new WeakMap();
-    }
-    if (!this._map.has(win)) {
-      this._map.set(win, {});
-    }
-    this._map.get(win).active = isActive;
+    let obj = this._getObjForWin(win);
+    obj.active = isActive;
   },
 
   /*
-   * Get the keyboard ID (assigned by Keyboard.ksm) of the given window.
+   * Get the keyboard ID (assigned by Keyboard.jsm) of the given window.
    */
   getKbID: function(win) {
     if (!this._map || !win) {
-      return null;
+      return undefined;
     }
 
-    let obj = this._map.get(win);
-    if (obj && 'kbID' in obj) {
-      return obj.kbID;
-    }else{
-      return null;
-    }
+    let obj = this._getObjForWin(win);
+    return obj.kbID;
   },
 
   /*
-   * Set the keyboard ID (assigned by Keyboard.ksm) of the given window.
+   * Set the keyboard ID (assigned by Keyboard.jsm) of the given window.
    */
   setKbID: function(win, kbID) {
     if (!win) {
       return;
     }
-    if (!this._map) {
-      this._map = new WeakMap();
+    let obj = this._getObjForWin(win);
+    obj.kbID = kbID;
+  },
+
+  /*
+   * Get InputContextDOMRequestIpcHelper instance attached to this window.
+   */
+  getInputContextIpcHelper: function(win) {
+    if (!win) {
+      return;
+    }
+    let obj = this._getObjForWin(win);
+    if (!obj.ipcHelper) {
+      obj.ipcHelper = new InputContextDOMRequestIpcHelper(win);
     }
-    if (!this._map.has(win)) {
-      this._map.set(win, {});
+    return obj.ipcHelper;
+  },
+
+  /*
+   * Unset InputContextDOMRequestIpcHelper instance.
+   */
+  unsetInputContextIpcHelper: function(win) {
+    if (!win) {
+      return;
     }
-    this._map.get(win).kbID = kbID;
+    let obj = this._getObjForWin(win);
+    if (!obj.ipcHelper) {
+      return;
+    }
+    obj.ipcHelper = null;
   }
 };
 
 let cpmmSendAsyncMessageWithKbID = function (self, msg, data) {
   data.kbID = WindowMap.getKbID(self._window);
   cpmm.sendAsyncMessage(msg, data);
 };
 
@@ -327,19 +358,19 @@ MozInputMethod.prototype = {
       // a GetContext:Result:OK event, and we can initialize ourselves.
       // Otherwise silently ignored.
 
       // get keyboard ID from Keyboard.jsm,
       // or if we already have it, get it from our map
       // Note: if we need to get it from Keyboard.jsm,
       // we have to use a synchronous message
       var kbID = WindowMap.getKbID(this._window);
-      if (kbID !== null) {
+      if (kbID) {
         cpmmSendAsyncMessageWithKbID(this, 'Keyboard:Register', {});
-      }else{
+      } else {
         let res = cpmm.sendSyncMessage('Keyboard:Register', {});
         WindowMap.setKbID(this._window, res[0]);
       }
 
       cpmmSendAsyncMessageWithKbID(this, 'Keyboard:GetContext', {});
     } else {
       // Deactive current input method.
       cpmmSendAsyncMessageWithKbID(this, 'Keyboard:Unregister', {});
@@ -412,16 +443,71 @@ MozInputMethod.prototype = {
       let resolverId = self.getPromiseResolverId({ resolve: resolve, reject: reject });
       callback(resolverId);
     });
   }
 };
 
  /**
  * ==============================================
+ * InputContextDOMRequestIpcHelper
+ * ==============================================
+ */
+function InputContextDOMRequestIpcHelper(win) {
+  this.initDOMRequestHelper(win,
+    ["Keyboard:GetText:Result:OK",
+     "Keyboard:GetText:Result:Error",
+     "Keyboard:SetSelectionRange:Result:OK",
+     "Keyboard:ReplaceSurroundingText:Result:OK",
+     "Keyboard:SendKey:Result:OK",
+     "Keyboard:SendKey:Result:Error",
+     "Keyboard:SetComposition:Result:OK",
+     "Keyboard:EndComposition:Result:OK",
+     "Keyboard:SequenceError"]);
+}
+
+InputContextDOMRequestIpcHelper.prototype = {
+  __proto__: DOMRequestIpcHelper.prototype,
+  _inputContext: null,
+
+  attachInputContext: function(inputCtx) {
+    if (this._inputContext) {
+      throw new Error("InputContextDOMRequestIpcHelper: detach the context first.");
+    }
+
+    this._inputContext = inputCtx;
+  },
+
+  // Unset ourselves when the window is destroyed.
+  uninit: function() {
+    WindowMap.unsetInputContextIpcHelper(this._window);
+  },
+
+  detachInputContext: function() {
+    // All requests that are still pending need to be invalidated
+    // because the context is no longer valid.
+    this.forEachPromiseResolver(k => {
+      this.takePromiseResolver(k).reject("InputContext got destroyed");
+    });
+
+    this._inputContext = null;
+  },
+
+  receiveMessage: function(msg) {
+    if (!this._inputContext) {
+      dump('InputContextDOMRequestIpcHelper received message without context attached.\n');
+      return;
+    }
+
+    this._inputContext.receiveMessage(msg);
+  }
+};
+
+ /**
+ * ==============================================
  * InputContext
  * ==============================================
  */
 function MozInputContext(ctx) {
   this._context = {
     inputtype: ctx.type,
     inputmode: ctx.inputmode,
     lang: ctx.lang,
@@ -433,78 +519,63 @@ function MozInputContext(ctx) {
     textBeforeCursor: ctx.textBeforeCursor,
     textAfterCursor: ctx.textAfterCursor
   };
 
   this._contextId = ctx.contextId;
 }
 
 MozInputContext.prototype = {
-  __proto__: DOMRequestIpcHelper.prototype,
-
   _window: null,
   _context: null,
   _contextId: -1,
+  _ipcHelper: null,
 
   classID: Components.ID("{1e38633d-d08b-4867-9944-afa5c648adb6}"),
 
   QueryInterface: XPCOMUtils.generateQI([
     Ci.nsIObserver,
     Ci.nsISupportsWeakReference
   ]),
 
   init: function ic_init(win) {
     this._window = win;
-    this._utils = win.QueryInterface(Ci.nsIInterfaceRequestor)
-                     .getInterface(Ci.nsIDOMWindowUtils);
-    this.initDOMRequestHelper(win,
-      ["Keyboard:GetText:Result:OK",
-       "Keyboard:GetText:Result:Error",
-       "Keyboard:SetSelectionRange:Result:OK",
-       "Keyboard:ReplaceSurroundingText:Result:OK",
-       "Keyboard:SendKey:Result:OK",
-       "Keyboard:SendKey:Result:Error",
-       "Keyboard:SetComposition:Result:OK",
-       "Keyboard:EndComposition:Result:OK",
-       "Keyboard:SequenceError"]);
+
+    this._ipcHelper = WindowMap.getInputContextIpcHelper(win);
+    this._ipcHelper.attachInputContext(this);
   },
 
   destroy: function ic_destroy() {
-    let self = this;
-
-    // All requests that are still pending need to be invalidated
-    // because the context is no longer valid.
-    this.forEachPromiseResolver(function(k) {
-      self.takePromiseResolver(k).reject("InputContext got destroyed");
-    });
-    this.destroyDOMRequestHelper();
-
     // A consuming application might still hold a cached version of
     // this object. After destroying all methods will throw because we
     // cannot create new promises anymore, but we still hold
     // (outdated) information in the context. So let's clear that out.
     for (var k in this._context) {
       if (this._context.hasOwnProperty(k)) {
         this._context[k] = null;
       }
     }
 
+    this._ipcHelper.detachInputContext();
+    this._ipcHelper = null;
+
     this._window = null;
   },
 
   receiveMessage: function ic_receiveMessage(msg) {
     if (!msg || !msg.json) {
       dump('InputContext received message without data\n');
       return;
     }
 
     let json = msg.json;
-    let resolver = this.takePromiseResolver(json.requestId);
+    let resolver = this._ipcHelper.takePromiseResolver(json.requestId);
 
     if (!resolver) {
+      dump('InputContext received invalid requestId.\n');
       return;
     }
 
     // Update context first before resolving promise to avoid race condition
     if (json.selectioninfo) {
       this.updateSelectionContext(json.selectioninfo, true);
     }
 
@@ -710,20 +781,20 @@ MozInputContext.prototype = {
         requestId: resolverId,
         text: text || ''
       });
     });
   },
 
   _sendPromise: function(callback) {
     let self = this;
-    return this.createPromise(function(resolve, reject) {
-      let resolverId = self.getPromiseResolverId({ resolve: resolve, reject: reject });
+    return this._ipcHelper.createPromise(function(resolve, reject) {
+      let resolverId = self._ipcHelper.getPromiseResolverId({ resolve: resolve, reject: reject });
       if (!WindowMap.isActive(self._window)) {
-        self.removePromiseResolver(resolverId);
+        self._ipcHelper.removePromiseResolver(resolverId);
         reject('Input method is not active.');
         return;
       }
       callback(resolverId);
     });
   }
 };
 
--- a/dom/inputmethod/forms.js
+++ b/dom/inputmethod/forms.js
@@ -666,17 +666,18 @@ let FormAssistant = {
   handleFocus: function fa_handleFocus(target) {
     if (this.focusedElement === target)
       return;
 
     if (target instanceof HTMLOptionElement)
       target = target.parentNode;
 
     this.setFocusedElement(target);
-    this.isHandlingFocus = this.sendInputState(target);
+    this.sendInputState(target);
+    this.isHandlingFocus = true;
   },
 
   unhandleFocus: function fa_unhandleFocus() {
     this.setFocusedElement(null);
     this.isHandlingFocus = false;
     sendAsyncMessage("Forms:Input", { "type": "blur" });
   },
 
@@ -685,40 +686,33 @@ let FormAssistant = {
         element instanceof HTMLTextAreaElement)
       return true;
 
     if (element instanceof HTMLOptionElement &&
         element.parentNode instanceof HTMLSelectElement)
       return true;
 
     return (element instanceof HTMLInputElement &&
-            !this.ignoredInputTypes.has(element.type));
+            !this.ignoredInputTypes.has(element.type) &&
+            !element.readOnly);
   },
 
   getTopLevelEditable: function fa_getTopLevelEditable(element) {
     function retrieveTopLevelEditable(element) {
       while (element && !isContentEditable(element))
         element = element.parentNode;
 
       return element;
     }
 
     return retrieveTopLevelEditable(element) || element;
   },
 
   sendInputState: function(element) {
-    // FIXME/bug 729623: work around apparent bug in the IME manager
-    // in gecko.
-    let readonly = element.getAttribute("readonly");
-    if (readonly) {
-      return false;
-    }
-
     sendAsyncMessage("Forms:Input", getJSON(element, this._focusCounter));
-    return true;
   },
 
   getSelectionInfo: function fa_getSelectionInfo() {
     let element = this.focusedElement;
     let range =  getSelectionRange(element);
 
     let text = isContentEditable(element) ? getContentEditableText(element)
                                           : element.value;
--- a/dom/inputmethod/mochitest/mochitest.ini
+++ b/dom/inputmethod/mochitest/mochitest.ini
@@ -15,13 +15,14 @@ support-files =
 [test_bug949059.html]
 [test_bug953044.html]
 [test_bug960946.html]
 [test_bug978918.html]
 [test_bug1026997.html]
 [test_bug1043828.html]
 [test_bug1059163.html]
 [test_bug1066515.html]
+[test_bug1175399.html]
 [test_sendkey_cancel.html]
 [test_sync_edit.html]
 [test_two_inputs.html]
 [test_two_selects.html]
 [test_unload.html]
--- a/dom/inputmethod/mochitest/test_bug1043828.html
+++ b/dom/inputmethod/mochitest/test_bug1043828.html
@@ -27,17 +27,17 @@ function kbFrameScript() {
     var ctx = content.navigator.mozInputMethod.inputcontext;
     if (ctx) {
       var p = ctx.getText();
       p.then(function(){
         sendAsyncMessage('test:InputMethod:getText:Resolve');
       }, function(e){
         sendAsyncMessage('test:InputMethod:getText:Reject');
       });
-    }else{
+    } else {
       dump("Could not get inputcontext") ;
     }
   }
 
   addMessageListener('test:InputMethod:getText:Do', function(){
     tryGetText();
   });
 }
@@ -98,17 +98,17 @@ function runTest() {
         handleEvent: function(){
           keyboardB.removeEventListener('mozbrowserloadend', this);
 
           mmKeyboardB = SpecialPowers.getBrowserFrameMessageManager(keyboardB);
 
           mmKeyboardB.loadFrameScript('data:,(' + kbFrameScript.toString() + ')();', false);
 
           mmKeyboardB.addMessageListener('test:InputMethod:getText:Resolve', function() {
-            ok(true, 'getText() was resolved');
+            info('getText() was resolved');
             inputmethod_cleanup();
           });
 
           mmKeyboardB.addMessageListener('test:InputMethod:getText:Reject', function() {
             ok(false, 'getText() was rejected');
             inputmethod_cleanup();
           });
 
@@ -119,64 +119,68 @@ function runTest() {
       };
 
       keyboardB.addEventListener('mozbrowserloadend', handler);
     });
   }
 
   // STEP 2: Set keyboard A active
   function step2() {
+    info('step2');
     let req = keyboardA.setInputMethodActive(true);
 
     req.onsuccess = function(){
       setTimeout(function(){
         step3();
       }, WAIT_TIME);
     };
 
     req.onerror = function(){
       ok(false, 'setInputMethodActive failed: ' + this.error.name);
       inputmethod_cleanup();
     };
   }
 
   // STEP 3: Set keyboard B active
   function step3() {
+    info('step3');
     let req = keyboardB.setInputMethodActive(true);
 
     req.onsuccess = function(){
       setTimeout(function(){
         step4();
       }, WAIT_TIME);
     };
 
     req.onerror = function(){
       ok(false, 'setInputMethodActive failed: ' + this.error.name);
       inputmethod_cleanup();
     };
   }
 
   // STEP 4: Set keyboard A inactive
   function step4() {
+    info('step4');
     let req = keyboardA.setInputMethodActive(false);
 
     req.onsuccess = function(){
       setTimeout(function(){
         step5();
       }, WAIT_TIME);
     };
 
     req.onerror = function(){
       ok(false, 'setInputMethodActive failed: ' + this.error.name);
       inputmethod_cleanup();
     };
   }
 
   // STEP 5: getText
   function step5() {
+    info('step5');
     mmKeyboardB.sendAsyncMessage('test:InputMethod:getText:Do');
   }
 
   step1();
 }
 
 </script>
 </pre>
new file mode 100644
--- /dev/null
+++ b/dom/inputmethod/mochitest/test_bug1175399.html
@@ -0,0 +1,62 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1175399
+-->
+<head>
+  <title>Test focus when page unloads</title>
+  <script type="application/javascript;version=1.7" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="application/javascript;version=1.7" src="inputmethod_common.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1175399">Mozilla Bug 1175399</a>
+<p id="display"></p>
+<pre id="test">
+<script class="testbody" type="application/javascript;version=1.7">
+
+inputmethod_setup(function() {
+  runTest();
+});
+
+let appFrameScript = function appFrameScript() {
+  let input = content.document.body.firstElementChild;
+  input.focus();
+
+  content.setTimeout(function() {
+    sendAsyncMessage('test:step');
+  });
+};
+
+function runTest() {
+  let im = navigator.mozInputMethod;
+
+  // Set current page as an input method.
+  SpecialPowers.wrap(im).setActive(true);
+
+  let iframe = document.createElement('iframe');
+  iframe.src = 'data:text/html,<html><body><input value="First" readonly></body></html>';
+  iframe.setAttribute('mozbrowser', true);
+  document.body.appendChild(iframe);
+
+  let mm = SpecialPowers.getBrowserFrameMessageManager(iframe);
+  im.oninputcontextchange = function() {
+    is(false, 'should not receive inputcontextchange event');
+  };
+
+  iframe.addEventListener('mozbrowserloadend', function() {
+    mm.addMessageListener('test:step', function() {
+      let inputcontext = navigator.mozInputMethod.inputcontext;
+      is(inputcontext, null, 'inputcontext is null');
+
+      inputmethod_cleanup();
+    });
+    mm.loadFrameScript('data:,(' + encodeURIComponent(appFrameScript.toString()) + ')();', false);
+  });
+}
+
+</script>
+</pre>
+</body>
+</html>
+
--- a/dom/media/eme/MediaKeySystemAccess.cpp
+++ b/dom/media/eme/MediaKeySystemAccess.cpp
@@ -156,27 +156,16 @@ EnsureMinCDMVersion(mozIGeckoMediaPlugin
     return MediaKeySystemStatus::Error;
   }
 
   if (!hasPlugin) {
     aOutMessage = NS_LITERAL_CSTRING("CDM is not installed");
     return MediaKeySystemStatus::Cdm_not_installed;
   }
 
-  if (aMinCdmVersion == NO_CDM_VERSION) {
-    return MediaKeySystemStatus::Available;
-  }
-
-  nsresult rv;
-  int32_t version = versionStr.ToInteger(&rv);
-  if (NS_FAILED(rv) || version < 0 || aMinCdmVersion > version) {
-    aOutMessage = NS_LITERAL_CSTRING("Installed CDM version insufficient");
-    return MediaKeySystemStatus::Cdm_insufficient_version;
-  }
-
 #ifdef XP_WIN
   if (aKeySystem.EqualsLiteral("com.adobe.access") ||
       aKeySystem.EqualsLiteral("com.adobe.primetime")) {
     // Verify that anti-virus hasn't "helpfully" deleted the Adobe GMP DLL,
     // as we suspect may happen (Bug 1160382).
     bool somethingMissing = false;
     if (!AdobePluginDLLExists(versionStr)) {
       aOutMessage = NS_LITERAL_CSTRING("Adobe DLL was expected to be on disk but was not");
@@ -192,16 +181,24 @@ EnsureMinCDMVersion(mozIGeckoMediaPlugin
       // Firefox will try to download the plugin next time the updater runs.
       Preferences::ClearUser("media.gmp-eme-adobe.lastUpdate");
       Preferences::ClearUser("media.gmp-eme-adobe.version");
       return MediaKeySystemStatus::Cdm_not_installed;
     }
   }
 #endif
 
+  nsresult rv;
+  int32_t version = versionStr.ToInteger(&rv);
+  if (aMinCdmVersion != NO_CDM_VERSION &&
+      (NS_FAILED(rv) || version < 0 || aMinCdmVersion > version)) {
+    aOutMessage = NS_LITERAL_CSTRING("Installed CDM version insufficient");
+    return MediaKeySystemStatus::Cdm_insufficient_version;
+  }
+
   return MediaKeySystemStatus::Available;
 }
 
 /* static */
 MediaKeySystemStatus
 MediaKeySystemAccess::GetKeySystemStatus(const nsAString& aKeySystem,
                                          int32_t aMinCdmVersion,
                                          nsACString& aOutMessage)
--- a/dom/media/gmp/GMPParent.cpp
+++ b/dom/media/gmp/GMPParent.cpp
@@ -178,17 +178,17 @@ GMPParent::LoadProcess()
       return NS_ERROR_FAILURE;
     }
     LOGD("%s: Sent StartPlugin to child process", __FUNCTION__);
   }
 
   mState = GMPStateLoaded;
 
   // Hold a self ref while the child process is alive. This ensures that
-  // during shutdown the GMPParent stays we stay alive long enough to
+  // during shutdown the GMPParent stays alive long enough to
   // terminate the child process.
   MOZ_ASSERT(!mHoldingSelfRef);
   mHoldingSelfRef = true;
   AddRef();
 
   return NS_OK;
 }
 
@@ -207,16 +207,17 @@ AbortWaitingForGMPAsyncShutdown(nsITimer
   if (service) {
     service->AsyncShutdownComplete(parent);
   }
 }
 
 nsresult
 GMPParent::EnsureAsyncShutdownTimeoutSet()
 {
+  MOZ_ASSERT(mAsyncShutdownRequired);
   if (mAsyncShutdownTimeout) {
     return NS_OK;
   }
 
   nsresult rv;
   mAsyncShutdownTimeout = do_CreateInstance(NS_TIMER_CONTRACTID, &rv);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
@@ -230,19 +231,21 @@ GMPParent::EnsureAsyncShutdownTimeoutSet
   }
 
   int32_t timeout = GMP_DEFAULT_ASYNC_SHUTDONW_TIMEOUT;
   nsRefPtr<GeckoMediaPluginServiceParent> service =
     GeckoMediaPluginServiceParent::GetSingleton();
   if (service) {
     timeout = service->AsyncShutdownTimeoutMs();
   }
-  return mAsyncShutdownTimeout->InitWithFuncCallback(
+  rv = mAsyncShutdownTimeout->InitWithFuncCallback(
     &AbortWaitingForGMPAsyncShutdown, this, timeout,
     nsITimer::TYPE_ONE_SHOT);
+  unused << NS_WARN_IF(NS_FAILED(rv));
+  return rv;
 }
 
 bool
 GMPParent::RecvPGMPContentChildDestroyed()
 {
   --mGMPContentChildCount;
   if (!IsUsed()) {
 #if defined(MOZ_CRASHREPORTER)
@@ -281,27 +284,35 @@ GMPParent::CloseIfUnused()
       if (!mAsyncShutdownInProgress) {
         LOGD("%s: sending async shutdown notification", __FUNCTION__);
 #if defined(MOZ_CRASHREPORTER)
       CrashReporter::AnnotateCrashReport(
         nsPrintfCString("AsyncPluginShutdown-%s@%p", GetDisplayName().get(), this),
         NS_LITERAL_CSTRING("Sent BeginAsyncShutdown"));
 #endif
         mAsyncShutdownInProgress = true;
-        if (!SendBeginAsyncShutdown() ||
-            NS_FAILED(EnsureAsyncShutdownTimeoutSet())) {
+        if (!SendBeginAsyncShutdown()) {
 #if defined(MOZ_CRASHREPORTER)
           CrashReporter::AnnotateCrashReport(
             nsPrintfCString("AsyncPluginShutdown-%s@%p", GetDisplayName().get(), this),
-            NS_LITERAL_CSTRING("Could not send BeginAsyncShutdown - Aborting"));
+            NS_LITERAL_CSTRING("Could not send BeginAsyncShutdown - Aborting async shutdown"));
+#endif
+          AbortAsyncShutdown();
+        } else if (NS_FAILED(EnsureAsyncShutdownTimeoutSet())) {
+#if defined(MOZ_CRASHREPORTER)
+          CrashReporter::AnnotateCrashReport(
+            nsPrintfCString("AsyncPluginShutdown-%s@%p", GetDisplayName().get(), this),
+            NS_LITERAL_CSTRING("Could not start timer after sending BeginAsyncShutdown - Aborting async shutdown"));
 #endif
           AbortAsyncShutdown();
         }
       }
     } else {
+      // No async-shutdown, kill async-shutdown timer started in CloseActive().
+      AbortAsyncShutdown();
       // Any async shutdown must be complete. Shutdown GMPStorage.
       for (size_t i = mStorage.Length(); i > 0; i--) {
         mStorage[i - 1]->Shutdown();
       }
       Shutdown();
     }
   }
 }
@@ -341,17 +352,48 @@ GMPParent::CloseActive(bool aDieWhenUnlo
     mState = GMPStateUnloading;
   }
   if (mState != GMPStateNotLoaded && IsUsed()) {
 #if defined(MOZ_CRASHREPORTER)
     CrashReporter::AnnotateCrashReport(
       nsPrintfCString("AsyncPluginShutdown-%s@%p", GetDisplayName().get(), this),
       nsPrintfCString("Sent CloseActive, content children to close: %u", mGMPContentChildCount));
 #endif
-    unused << SendCloseActive();
+    if (!SendCloseActive()) {
+#if defined(MOZ_CRASHREPORTER)
+      CrashReporter::AnnotateCrashReport(
+        nsPrintfCString("AsyncPluginShutdown-%s@%p", GetDisplayName().get(), this),
+        NS_LITERAL_CSTRING("Could not send CloseActive - Aborting async shutdown"));
+#endif
+      AbortAsyncShutdown();
+    } else if (IsUsed()) {
+      // We're expecting RecvPGMPContentChildDestroyed's -> Start async-shutdown timer now if needed.
+      if (mAsyncShutdownRequired && NS_FAILED(EnsureAsyncShutdownTimeoutSet())) {
+#if defined(MOZ_CRASHREPORTER)
+        CrashReporter::AnnotateCrashReport(
+          nsPrintfCString("AsyncPluginShutdown-%s@%p", GetDisplayName().get(), this),
+          NS_LITERAL_CSTRING("Could not start timer after sending CloseActive - Aborting async shutdown"));
+#endif
+        AbortAsyncShutdown();
+      }
+    } else {
+      // We're not expecting any RecvPGMPContentChildDestroyed
+      // -> Call CloseIfUnused() now, to run async shutdown if necessary.
+      // Note that CloseIfUnused() may have already been called from a prior
+      // RecvPGMPContentChildDestroyed(), however depending on the state at
+      // that time, it might not have proceeded with shutdown; And calling it
+      // again after shutdown is fine because after the first one we'll be in
+      // GMPStateNotLoaded.
+#if defined(MOZ_CRASHREPORTER)
+      CrashReporter::AnnotateCrashReport(
+        nsPrintfCString("AsyncPluginShutdown-%s@%p", GetDisplayName().get(), this),
+        NS_LITERAL_CSTRING("Content children already destroyed"));
+#endif
+      CloseIfUnused();
+    }
   }
 }
 
 void
 GMPParent::MarkForDeletion()
 {
   mDeleteProcessOnlyOnUnload = true;
   mIsBlockingDeletion = true;
--- a/dom/media/webaudio/AudioContext.cpp
+++ b/dom/media/webaudio/AudioContext.cpp
@@ -30,16 +30,17 @@
 #include "StereoPannerNode.h"
 #include "ChannelMergerNode.h"
 #include "ChannelSplitterNode.h"
 #include "MediaStreamAudioDestinationNode.h"
 #include "WaveShaperNode.h"
 #include "PeriodicWave.h"
 #include "ConvolverNode.h"
 #include "OscillatorNode.h"
+#include "blink/PeriodicWave.h"
 #include "nsNetUtil.h"
 #include "AudioStream.h"
 #include "mozilla/dom/Promise.h"
 
 namespace mozilla {
 namespace dom {
 
 // 0 is a special value that MediaStreams use to denote they are not part of a
@@ -1045,10 +1046,53 @@ AudioContext::CollectReports(nsIHandleRe
 }
 
 double
 AudioContext::ExtraCurrentTime() const
 {
   return mDestination->ExtraCurrentTime();
 }
 
+BasicWaveFormCache*
+AudioContext::GetBasicWaveFormCache()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  if (!mBasicWaveFormCache) {
+    mBasicWaveFormCache = new BasicWaveFormCache(SampleRate());
+  }
+  return mBasicWaveFormCache;
+}
+
+BasicWaveFormCache::BasicWaveFormCache(uint32_t aSampleRate)
+  : mSampleRate(aSampleRate)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+}
+BasicWaveFormCache::~BasicWaveFormCache()
+{ }
+
+WebCore::PeriodicWave*
+BasicWaveFormCache::GetBasicWaveForm(OscillatorType aType)
+{
+  MOZ_ASSERT(!NS_IsMainThread());
+  if (aType == OscillatorType::Sawtooth) {
+    if (!mSawtooth) {
+      mSawtooth = WebCore::PeriodicWave::createSawtooth(mSampleRate);
+    }
+    return mSawtooth;
+  } else if (aType == OscillatorType::Square) {
+    if (!mSquare) {
+      mSquare = WebCore::PeriodicWave::createSquare(mSampleRate);
+    }
+    return mSquare;
+  } else if (aType == OscillatorType::Triangle) {
+    if (!mTriangle) {
+      mTriangle = WebCore::PeriodicWave::createTriangle(mSampleRate);
+    }
+    return mTriangle;
+  } else {
+    MOZ_ASSERT(false, "Not reached");
+    return nullptr;
+  }
+}
+
 }
 }
--- a/dom/media/webaudio/AudioContext.h
+++ b/dom/media/webaudio/AudioContext.h
@@ -22,16 +22,20 @@
 #include "nsIMemoryReporter.h"
 
 // X11 has a #define for CurrentTime. Unbelievable :-(.
 // See dom/media/DOMMediaStream.h for more fun!
 #ifdef CurrentTime
 #undef CurrentTime
 #endif
 
+namespace WebCore {
+  class PeriodicWave;
+};
+
 class nsPIDOMWindow;
 
 namespace mozilla {
 
 class DOMMediaStream;
 class ErrorResult;
 class MediaStream;
 class MediaStreamGraph;
@@ -60,16 +64,35 @@ class MediaStreamAudioDestinationNode;
 class MediaStreamAudioSourceNode;
 class OscillatorNode;
 class PannerNode;
 class ScriptProcessorNode;
 class StereoPannerNode;
 class WaveShaperNode;
 class PeriodicWave;
 class Promise;
+enum class OscillatorType : uint32_t;
+
+// This is addrefed by the OscillatorNodeEngine on the main thread
+// and then used from the MSG thread.
+// It can be released either from the graph thread or the main thread.
+class BasicWaveFormCache
+{
+public:
+  explicit BasicWaveFormCache(uint32_t aSampleRate);
+  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(BasicWaveFormCache)
+  WebCore::PeriodicWave* GetBasicWaveForm(OscillatorType aType);
+private:
+  ~BasicWaveFormCache();
+  nsRefPtr<WebCore::PeriodicWave> mSawtooth;
+  nsRefPtr<WebCore::PeriodicWave> mSquare;
+  nsRefPtr<WebCore::PeriodicWave> mTriangle;
+  uint32_t mSampleRate;
+};
+
 
 /* This runnable allows the MSG to notify the main thread when audio is actually
  * flowing */
 class StateChangeTask final : public nsRunnable
 {
 public:
   /* This constructor should be used when this event is sent from the main
    * thread. */
@@ -289,16 +312,18 @@ public:
 
   double StreamTimeToDOMTime(double aTime) const
   {
     return aTime + ExtraCurrentTime();
   }
 
   void OnStateChanged(void* aPromise, AudioContextState aNewState);
 
+  BasicWaveFormCache* GetBasicWaveFormCache();
+
   IMPL_EVENT_HANDLER(mozinterruptbegin)
   IMPL_EVENT_HANDLER(mozinterruptend)
 
 private:
   /**
    * Returns the amount of extra time added to the current time of the
    * AudioDestinationNode's MediaStream to get this AudioContext's currentTime.
    * Must be subtracted from all DOM API parameter times that are on the same
@@ -334,16 +359,18 @@ private:
   // they are resolved, so we can safely pass them accross threads.
   nsTArray<nsRefPtr<Promise>> mPromiseGripArray;
   // See RegisterActiveNode.  These will keep the AudioContext alive while it
   // is rendering and the window remains alive.
   nsTHashtable<nsRefPtrHashKey<AudioNode> > mActiveNodes;
   // Hashsets containing all the PannerNodes, to compute the doppler shift.
   // These are weak pointers.
   nsTHashtable<nsPtrHashKey<PannerNode> > mPannerNodes;
+  // Cache to avoid recomputing basic waveforms all the time.
+  nsRefPtr<BasicWaveFormCache> mBasicWaveFormCache;
   // Number of channels passed in the OfflineAudioContext ctor.
   uint32_t mNumberOfChannels;
   // Number of nodes that currently exist for this AudioContext
   int32_t mNodeCount;
   bool mIsOffline;
   bool mIsStarted;
   bool mIsShutDown;
   // Close has been called, reject suspend and resume call.
--- a/dom/media/webaudio/AudioDestinationNode.cpp
+++ b/dom/media/webaudio/AudioDestinationNode.cpp
@@ -288,16 +288,21 @@ private:
   bool mLastInputMuted;
 };
 
 static bool UseAudioChannelService()
 {
   return Preferences::GetBool("media.useAudioChannelService");
 }
 
+static bool UseAudioChannelAPI()
+{
+  return Preferences::GetBool("media.useAudioChannelAPI");
+}
+
 class EventProxyHandler final : public nsIDOMEventListener
 {
 public:
   NS_DECL_ISUPPORTS
 
   explicit EventProxyHandler(nsIDOMEventListener* aNode)
   {
     MOZ_ASSERT(aNode);
@@ -538,19 +543,21 @@ AudioDestinationNode::CanPlayChanged(int
   bool playing = aCanPlay == AudioChannelState::AUDIO_CHANNEL_STATE_NORMAL;
   if (playing == mAudioChannelAgentPlaying) {
     return NS_OK;
   }
 
   mAudioChannelAgentPlaying = playing;
   SetCanPlay(playing);
 
-  Context()->DispatchTrustedEvent(
-    playing ? NS_LITERAL_STRING("mozinterruptend")
-            : NS_LITERAL_STRING("mozinterruptbegin"));
+  if (UseAudioChannelAPI()) {
+    Context()->DispatchTrustedEvent(
+      playing ? NS_LITERAL_STRING("mozinterruptend")
+              : NS_LITERAL_STRING("mozinterruptbegin"));
+  }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 AudioDestinationNode::WindowVolumeChanged()
 {
   MOZ_ASSERT(mAudioChannelAgent);
--- a/dom/media/webaudio/OscillatorNode.cpp
+++ b/dom/media/webaudio/OscillatorNode.cpp
@@ -35,16 +35,18 @@ public:
     // Keep the default values in sync with OscillatorNode::OscillatorNode.
     , mFrequency(440.f)
     , mDetune(0.f)
     , mType(OscillatorType::Sine)
     , mPhase(0.)
     , mRecomputeParameters(true)
     , mCustomLength(0)
   {
+    MOZ_ASSERT(NS_IsMainThread());
+    mBasicWaveFormCache = aDestination->Context()->GetBasicWaveFormCache();
   }
 
   void SetSourceStream(AudioNodeStream* aSource)
   {
     mSource = aSource;
   }
 
   enum Parameters {
@@ -99,23 +101,19 @@ public:
           mPeriodicWave = nullptr;
           mRecomputeParameters = true;
         }
         switch (mType) {
           case OscillatorType::Sine:
             mPhase = 0.0;
             break;
           case OscillatorType::Square:
-            mPeriodicWave = WebCore::PeriodicWave::createSquare(mSource->SampleRate());
-            break;
           case OscillatorType::Triangle:
-            mPeriodicWave = WebCore::PeriodicWave::createTriangle(mSource->SampleRate());
-            break;
           case OscillatorType::Sawtooth:
-            mPeriodicWave = WebCore::PeriodicWave::createSawtooth(mSource->SampleRate());
+            mPeriodicWave = mBasicWaveFormCache->GetBasicWaveForm(mType);
             break;
           case OscillatorType::Custom:
             break;
           default:
             NS_ERROR("Bad OscillatorNodeEngine type parameter.");
         }
         // End type switch.
         break;
@@ -366,18 +364,19 @@ public:
   AudioParamTimeline mFrequency;
   AudioParamTimeline mDetune;
   OscillatorType mType;
   float mPhase;
   float mFinalFrequency;
   float mPhaseIncrement;
   bool mRecomputeParameters;
   nsRefPtr<ThreadSharedFloatArrayBufferList> mCustom;
+  nsRefPtr<BasicWaveFormCache> mBasicWaveFormCache;
   uint32_t mCustomLength;
-  nsAutoPtr<WebCore::PeriodicWave> mPeriodicWave;
+  nsRefPtr<WebCore::PeriodicWave> mPeriodicWave;
 };
 
 OscillatorNode::OscillatorNode(AudioContext* aContext)
   : AudioNode(aContext,
               2,
               ChannelCountMode::Max,
               ChannelInterpretation::Speakers)
   , mType(OscillatorType::Sine)
--- a/dom/media/webaudio/PeriodicWave.h
+++ b/dom/media/webaudio/PeriodicWave.h
@@ -7,17 +7,16 @@
 #ifndef PeriodicWave_h_
 #define PeriodicWave_h_
 
 #include "nsWrapperCache.h"
 #include "nsCycleCollectionParticipant.h"
 #include "mozilla/Attributes.h"
 #include "AudioContext.h"
 #include "AudioNodeEngine.h"
-#include "nsAutoPtr.h"
 
 namespace mozilla {
 
 namespace dom {
 
 class PeriodicWave final : public nsWrapperCache
 {
 public:
--- a/dom/media/webaudio/blink/PeriodicWave.cpp
+++ b/dom/media/webaudio/blink/PeriodicWave.cpp
@@ -35,58 +35,68 @@ const unsigned PeriodicWaveSize = 4096; 
 const unsigned NumberOfRanges = 36; // There should be 3 * log2(PeriodicWaveSize) 1/3 octave ranges.
 const float CentsPerRange = 1200 / 3; // 1/3 Octave.
 
 using namespace mozilla;
 using mozilla::dom::OscillatorType;
 
 namespace WebCore {
 
-PeriodicWave* PeriodicWave::create(float sampleRate,
-                                   const float* real,
-                                   const float* imag,
-                                   size_t numberOfComponents)
+already_AddRefed<PeriodicWave>
+PeriodicWave::create(float sampleRate,
+                     const float* real,
+                     const float* imag,
+                     size_t numberOfComponents)
 {
     bool isGood = real && imag && numberOfComponents > 0 &&
          numberOfComponents <= PeriodicWaveSize;
     MOZ_ASSERT(isGood);
     if (isGood) {
-        PeriodicWave* periodicWave = new PeriodicWave(sampleRate);
+        nsRefPtr<PeriodicWave> periodicWave =
+            new PeriodicWave(sampleRate);
         periodicWave->createBandLimitedTables(real, imag, numberOfComponents);
-        return periodicWave;
+        return periodicWave.forget();
     }
-    return 0;
+    return nullptr;
 }
 
-PeriodicWave* PeriodicWave::createSine(float sampleRate)
+already_AddRefed<PeriodicWave>
+PeriodicWave::createSine(float sampleRate)
 {
-      PeriodicWave* periodicWave = new PeriodicWave(sampleRate);
-          periodicWave->generateBasicWaveform(OscillatorType::Sine);
-              return periodicWave;
+    nsRefPtr<PeriodicWave> periodicWave =
+        new PeriodicWave(sampleRate);
+    periodicWave->generateBasicWaveform(OscillatorType::Sine);
+    return periodicWave.forget();
 }
 
-PeriodicWave* PeriodicWave::createSquare(float sampleRate)
+already_AddRefed<PeriodicWave>
+PeriodicWave::createSquare(float sampleRate)
 {
-      PeriodicWave* periodicWave = new PeriodicWave(sampleRate);
-          periodicWave->generateBasicWaveform(OscillatorType::Square);
-              return periodicWave;
+    nsRefPtr<PeriodicWave> periodicWave =
+        new PeriodicWave(sampleRate);
+    periodicWave->generateBasicWaveform(OscillatorType::Square);
+    return periodicWave.forget();
 }
 
-PeriodicWave* PeriodicWave::createSawtooth(float sampleRate)
+already_AddRefed<PeriodicWave>
+PeriodicWave::createSawtooth(float sampleRate)
 {
-      PeriodicWave* periodicWave = new PeriodicWave(sampleRate);
-          periodicWave->generateBasicWaveform(OscillatorType::Sawtooth);
-              return periodicWave;
+    nsRefPtr<PeriodicWave> periodicWave =
+        new PeriodicWave(sampleRate);
+    periodicWave->generateBasicWaveform(OscillatorType::Sawtooth);
+    return periodicWave.forget();
 }
 
-PeriodicWave* PeriodicWave::createTriangle(float sampleRate)
+already_AddRefed<PeriodicWave>
+PeriodicWave::createTriangle(float sampleRate)
 {
-      PeriodicWave* periodicWave = new PeriodicWave(sampleRate);
-          periodicWave->generateBasicWaveform(OscillatorType::Triangle);
-              return periodicWave;
+    nsRefPtr<PeriodicWave> periodicWave =
+        new PeriodicWave(sampleRate);
+    periodicWave->generateBasicWaveform(OscillatorType::Triangle);
+    return periodicWave.forget();
 }
 
 PeriodicWave::PeriodicWave(float sampleRate)
     : m_sampleRate(sampleRate)
     , m_periodicWaveSize(PeriodicWaveSize)
     , m_numberOfRanges(NumberOfRanges)
     , m_centsPerRange(CentsPerRange)
 {
--- a/dom/media/webaudio/blink/PeriodicWave.h
+++ b/dom/media/webaudio/blink/PeriodicWave.h
@@ -37,27 +37,29 @@
 
 namespace WebCore {
 
 typedef AlignedTArray<float> AlignedAudioFloatArray;
 typedef nsTArray<float> AudioFloatArray;
 
 class PeriodicWave {
 public:
-    static PeriodicWave* createSine(float sampleRate);
-    static PeriodicWave* createSquare(float sampleRate);
-    static PeriodicWave* createSawtooth(float sampleRate);
-    static PeriodicWave* createTriangle(float sampleRate);
+    NS_INLINE_DECL_THREADSAFE_REFCOUNTING(WebCore::PeriodicWave);
+
+    static already_AddRefed<PeriodicWave> createSine(float sampleRate);
+    static already_AddRefed<PeriodicWave> createSquare(float sampleRate);
+    static already_AddRefed<PeriodicWave> createSawtooth(float sampleRate);
+    static already_AddRefed<PeriodicWave> createTriangle(float sampleRate);
 
     // Creates an arbitrary periodic wave given the frequency components
     // (Fourier coefficients).
-    static PeriodicWave* create(float sampleRate,
-                                const float* real,
-                                const float* imag,
-                                size_t numberOfComponents);
+    static already_AddRefed<PeriodicWave> create(float sampleRate,
+                                                 const float* real,
+                                                 const float* imag,
+                                                 size_t numberOfComponents);
 
     // Returns pointers to the lower and higher wave data for the pitch range
     // containing the given fundamental frequency. These two tables are in
     // adjacent "pitch" ranges where the higher table will have the maximum
     // number of partials which won't alias when played back at this
     // fundamental frequency. The lower wave is the next range containing fewer
     // partials than the higher wave. Interpolation between these two tables
     // can be made according to tableInterpolationFactor. Where values
@@ -70,16 +72,17 @@ public:
 
     unsigned periodicWaveSize() const { return m_periodicWaveSize; }
     float sampleRate() const { return m_sampleRate; }
 
     size_t sizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
 
 private:
     explicit PeriodicWave(float sampleRate);
+    ~PeriodicWave() {}
 
     void generateBasicWaveform(mozilla::dom::OscillatorType);
 
     float m_sampleRate;
     unsigned m_periodicWaveSize;
     unsigned m_numberOfRanges;
     float m_centsPerRange;
 
--- a/dom/media/webaudio/test/browser_mozAudioChannel.js
+++ b/dom/media/webaudio/test/browser_mozAudioChannel.js
@@ -30,16 +30,17 @@ function eventListener(evt) {
 function test() {
 
   waitForExplicitFinish();
 
   let testURL = "http://mochi.test:8888/browser/" +
     "dom/media/webaudio/test/browser_mozAudioChannel.html";
 
   SpecialPowers.pushPrefEnv({"set": [["media.defaultAudioChannel", "content" ],
+                                     ["media.useAudioChannelAPI", true ],
                                      ["media.useAudioChannelService", true ]]},
     function() {
       let tab1 = gBrowser.addTab(testURL);
       gBrowser.selectedTab = tab1;
 
       whenBrowserLoaded(tab1.linkedBrowser, function() {
         let doc = tab1.linkedBrowser.contentDocument;
         tab1.linkedBrowser.contentWindow.addEventListener('testmozchannel', eventListener, false);
--- a/dom/media/webaudio/test/browser_mozAudioChannel_muted.js
+++ b/dom/media/webaudio/test/browser_mozAudioChannel_muted.js
@@ -30,16 +30,17 @@ function whenBrowserUnloaded(aBrowser, a
 function test() {
 
   waitForExplicitFinish();
 
   let testURL = "http://mochi.test:8888/browser/" +
     "dom/media/webaudio/test/browser_mozAudioChannel_muted.html";
 
   SpecialPowers.pushPrefEnv({"set": [["media.defaultAudioChannel", "content" ],
+                                     ["media.useAudioChannelAPI", true ],
                                      ["media.useAudioChannelService", true ]]},
     function() {
       let tab1 = gBrowser.addTab(testURL);
       gBrowser.selectedTab = tab1;
 
       whenBrowserLoaded(tab1.linkedBrowser, function() {
         let doc = tab1.linkedBrowser.contentDocument;
         is(doc.getElementById("mozAudioChannelTest").textContent, "READY",
--- a/dom/media/webaudio/test/test_mozaudiochannel.html
+++ b/dom/media/webaudio/test/test_mozaudiochannel.html
@@ -136,16 +136,17 @@ function runTest() {
     SimpleTest.finish();
     return;
   }
 
   var test = tests.shift();
   test();
 }
 
-SpecialPowers.pushPrefEnv({"set": [["media.useAudioChannelService", true ]]}, runTest);
+SpecialPowers.pushPrefEnv({"set": [["media.useAudioChannelAPI", true ],
+                                   ["media.useAudioChannelService", true ]]}, runTest);
 SimpleTest.waitForExplicitFinish();
 SimpleTest.requestLongerTimeout(5);
 
 </script>
 </pre>
 </body>
 </html>
--- a/dom/plugins/ipc/PluginInstanceChild.cpp
+++ b/dom/plugins/ipc/PluginInstanceChild.cpp
@@ -2848,18 +2848,17 @@ PluginInstanceChild::CreateOptSurface(vo
             gfxXlibSurface::Create(screen, xfmt,
                                    gfxIntSize(mWindow.width,
                                               mWindow.height));
         return mCurrentSurface != nullptr;
     }
 #endif
 
 #ifdef XP_WIN
-    if (mSurfaceType == gfxSurfaceType::Win32 ||
-        mSurfaceType == gfxSurfaceType::D2D) {
+    if (mSurfaceType == gfxSurfaceType::Win32) {
         bool willHaveTransparentPixels = mIsTransparent && !mBackground;
 
         SharedDIBSurface* s = new SharedDIBSurface();
         if (!s->Create(reinterpret_cast<HDC>(mWindow.window),
                        mWindow.width, mWindow.height,
                        willHaveTransparentPixels))
             return false;
 
--- a/dom/promise/Promise.h
+++ b/dom/promise/Promise.h
@@ -45,18 +45,19 @@ class PromiseInit;
 class PromiseNativeHandler;
 class PromiseDebugging;
 
 class Promise;
 
 #if defined(DOM_PROMISE_DEPRECATED_REPORTING)
 class PromiseReportRejectFeature : public workers::WorkerFeature
 {
-  // The Promise that owns this feature.
-  Promise* mPromise;
+  // PromiseReportRejectFeature is held by an nsAutoPtr on the Promise which
+  // means that this object will be destroyed before the Promise is destroyed.
+  Promise* MOZ_NON_OWNING_REF mPromise;
 
 public:
   explicit PromiseReportRejectFeature(Promise* aPromise)
     : mPromise(aPromise)
   {
     MOZ_ASSERT(mPromise);
   }
 
--- a/dom/webidl/AudioContext.webidl
+++ b/dom/webidl/AudioContext.webidl
@@ -90,23 +90,23 @@ interface AudioContext : EventTarget {
     [NewObject, Throws]
     PeriodicWave createPeriodicWave(Float32Array real, Float32Array imag);
 
 };
 
 // Mozilla extensions
 partial interface AudioContext {
   // Read AudioChannel.webidl for more information about this attribute.
-  [Pref="media.useAudioChannelService"]
+  [Pref="media.useAudioChannelAPI"]
   readonly attribute AudioChannel mozAudioChannelType;
 
   // These 2 events are dispatched when the AudioContext object is muted by
   // the AudioChannelService. It's call 'interrupt' because when this event is
   // dispatched on a HTMLMediaElement, the audio stream is paused.
-  [Pref="media.useAudioChannelService"]
+  [Pref="media.useAudioChannelAPI"]
   attribute EventHandler onmozinterruptbegin;
 
-  [Pref="media.useAudioChannelService"]
+  [Pref="media.useAudioChannelAPI"]
   attribute EventHandler onmozinterruptend;
 
   // This method is for test only.
   [ChromeOnly] AudioChannel testAudioChannelInAudioNodeStream();
 };
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -3539,22 +3539,48 @@ bool
 WorkerPrivateParent<Derived>::DispatchMessageEventToMessagePort(
                                 JSContext* aCx, uint64_t aMessagePortSerial,
                                 JSAutoStructuredCloneBuffer&& aBuffer,
                                 WorkerStructuredCloneClosure& aClosure)
 {
   AssertIsOnMainThread();
 
   JSAutoStructuredCloneBuffer buffer(Move(aBuffer));
+  const JSStructuredCloneCallbacks* callbacks =
+    WorkerStructuredCloneCallbacks(true);
+
+  class MOZ_STACK_CLASS AutoCloneBufferCleaner final
+  {
+  public:
+    AutoCloneBufferCleaner(JSAutoStructuredCloneBuffer& aBuffer,
+                           const JSStructuredCloneCallbacks* aCallbacks,
+                           WorkerStructuredCloneClosure& aClosure)
+      : mBuffer(aBuffer)
+      , mCallbacks(aCallbacks)
+      , mClosure(aClosure)
+    {}
+
+    ~AutoCloneBufferCleaner()
+    {
+      mBuffer.clear(mCallbacks, &mClosure);
+    }
+
+  private:
+    JSAutoStructuredCloneBuffer& mBuffer;
+    const JSStructuredCloneCallbacks* mCallbacks;
+    WorkerStructuredCloneClosure& mClosure;
+  };
 
   WorkerStructuredCloneClosure closure;
   closure.mClonedObjects.SwapElements(aClosure.mClonedObjects);
   MOZ_ASSERT(aClosure.mMessagePorts.IsEmpty());
   closure.mMessagePortIdentifiers.SwapElements(aClosure.mMessagePortIdentifiers);
 
+  AutoCloneBufferCleaner bufferCleaner(buffer, callbacks, closure);
+
   SharedWorker* sharedWorker;
   if (!mSharedWorkers.Get(aMessagePortSerial, &sharedWorker)) {
     // SharedWorker has already been unregistered?
     return true;
   }
 
   nsRefPtr<MessagePort> port = sharedWorker->Port();
   NS_ASSERTION(port, "SharedWorkers always have a port!");
@@ -3572,18 +3598,16 @@ WorkerPrivateParent<Derived>::DispatchMe
   JSContext* cx = jsapi.cx();
 
   JS::Rooted<JS::Value> data(cx);
   if (!buffer.read(cx, &data, WorkerStructuredCloneCallbacks(true),
                    &closure)) {
     return false;
   }
 
-  buffer.clear();
-
   nsRefPtr<MessageEvent> event = new MessageEvent(port, nullptr, nullptr);
   nsresult rv =
     event->InitMessageEvent(NS_LITERAL_STRING("message"), false, false, data,
                             EmptyString(), EmptyString(), nullptr);
   if (NS_FAILED(rv)) {
     xpc::Throw(cx, rv);
     return false;
   }
--- a/gfx/2d/DrawTargetCairo.cpp
+++ b/gfx/2d/DrawTargetCairo.cpp
@@ -654,19 +654,16 @@ DrawTargetCairo::GetType() const
     case CAIRO_SURFACE_TYPE_WIN32:
     case CAIRO_SURFACE_TYPE_BEOS:
     case CAIRO_SURFACE_TYPE_OS2:
     case CAIRO_SURFACE_TYPE_QUARTZ_IMAGE:
     case CAIRO_SURFACE_TYPE_SCRIPT:
     case CAIRO_SURFACE_TYPE_RECORDING:
     case CAIRO_SURFACE_TYPE_DRM:
     case CAIRO_SURFACE_TYPE_SUBSURFACE:
-#ifdef CAIRO_HAS_D2D_SURFACE
-    case CAIRO_SURFACE_TYPE_D2D:
-#endif
     case CAIRO_SURFACE_TYPE_TEE: // included to silence warning about unhandled enum value
       return DrawTargetType::SOFTWARE_RASTER;
     default:
       MOZ_CRASH("Unsupported cairo surface type");
     }
   }
   MOZ_ASSERT(false, "Could not determine DrawTargetType for DrawTargetCairo");
   return DrawTargetType::SOFTWARE_RASTER;
--- a/gfx/2d/DrawTargetD2D1.cpp
+++ b/gfx/2d/DrawTargetD2D1.cpp
@@ -45,17 +45,22 @@ DrawTargetD2D1::~DrawTargetD2D1()
     // MarkIndependent is running.
     RefPtr<SourceSurfaceD2D1> deathGrip = mSnapshot;
     // mSnapshot can be treated as independent of this DrawTarget since we know
     // this DrawTarget won't change again.
     deathGrip->MarkIndependent();
     // mSnapshot will be cleared now.
   }
 
-  mDC->EndDraw();
+  if (mDC) {
+    // The only way mDC can be null is if Init failed, but it can happen and the
+    // destructor is the only place where we need to check for it since the
+    // DrawTarget will destroyed right after Init fails.
+    mDC->EndDraw();
+  }
 
   // Targets depending on us can break that dependency, since we're obviously not going to
   // be modified in the future.
   for (auto iter = mDependentTargets.begin();
        iter != mDependentTargets.end(); iter++) {
     (*iter)->mDependingOnTargets.erase(this);
   }
   // Our dependencies on other targets no longer matter.
--- a/gfx/layers/ImageContainer.cpp
+++ b/gfx/layers/ImageContainer.cpp
@@ -27,17 +27,16 @@
 #include "mozilla/gfx/2D.h"
 
 #ifdef XP_MACOSX
 #include "mozilla/gfx/QuartzSupport.h"
 #include "MacIOSurfaceImage.h"
 #endif
 
 #ifdef XP_WIN
-#include "gfxD2DSurface.h"
 #include "gfxWindowsPlatform.h"
 #include <d3d10_1.h>
 #include "D3D9SurfaceImage.h"
 #include "D3D11ShareHandleImage.h"
 #endif
 
 namespace mozilla {
 namespace layers {
--- a/gfx/layers/apz/test/test_basic_pan.html
+++ b/gfx/layers/apz/test/test_basic_pan.html
@@ -40,17 +40,19 @@ window.onload = function() {
         // Dropping the touch slop to 0 makes the tests easier to write because
         // we can just do a one-pixel drag to get over the pan threshold rather
         // than having to hard-code some larger value.
         ["apz.touch_start_tolerance", "0.0"],
 
         // The B2G emulator is hella slow, and needs more than 300ms to run the
         // main-thread code that deals with layerizing subframes and running
         // touch listeners. In my local runs this needs to be at least 1000.
-        ["apz.content_response_timeout", "5000"]
+        // On try this sometimes needs to be as long as 8 seconds (bug 1176798)
+        // so we make it 15 seconds just to be extra safe.
+        ["apz.content_response_timeout", "15000"]
       ]
     }, testDone);
 };
 
   </script>
 </head>
 <body>
 </body>
--- a/gfx/layers/client/ContentClient.cpp
+++ b/gfx/layers/client/ContentClient.cpp
@@ -69,17 +69,17 @@ ContentClient::CreateContentClient(Compo
       backend != LayersBackend::LAYERS_BASIC) {
     return nullptr;
   }
 
   bool useDoubleBuffering = false;
 
 #ifdef XP_WIN
   if (backend == LayersBackend::LAYERS_D3D11) {
-    useDoubleBuffering = !!gfxWindowsPlatform::GetPlatform()->GetD2DDevice();
+    useDoubleBuffering = !!gfxWindowsPlatform::GetPlatform()->GetD3D10Device();
   } else
 #endif
 #ifdef MOZ_WIDGET_GTK
   // We can't use double buffering when using image content with
   // Xrender support on Linux, as ContentHostDoubleBuffered is not
   // suited for direct uploads to the server.
   if (!gfxPlatformGtk::GetPlatform()->UseImageOffscreenSurfaces() ||
       !gfxPlatformGtk::GetPlatform()->UseXRender())
--- a/gfx/layers/client/TextureClient.cpp
+++ b/gfx/layers/client/TextureClient.cpp
@@ -339,28 +339,28 @@ TextureClient::CreateForDrawing(ISurface
   int32_t maxTextureSize = aAllocator->GetMaxTextureSize();
 #endif
 
 #ifdef XP_WIN
   LayersBackend parentBackend = aAllocator->GetCompositorBackendType();
   if (parentBackend == LayersBackend::LAYERS_D3D11 &&
       (aMoz2DBackend == gfx::BackendType::DIRECT2D ||
         aMoz2DBackend == gfx::BackendType::DIRECT2D1_1) &&
-      gfxWindowsPlatform::GetPlatform()->GetD2DDevice() &&
+      gfxWindowsPlatform::GetPlatform()->GetD3D10Device() &&
       aSize.width <= maxTextureSize &&
       aSize.height <= maxTextureSize) {
     texture = new TextureClientD3D11(aAllocator, aFormat, aTextureFlags);
   }
   if (parentBackend == LayersBackend::LAYERS_D3D9 &&
       aMoz2DBackend == gfx::BackendType::CAIRO &&
       aAllocator->IsSameProcess() &&
       aSize.width <= maxTextureSize &&
       aSize.height <= maxTextureSize) {
     if (gfxWindowsPlatform::GetPlatform()->GetD3D9Device()) {
-      texture = new CairoTextureClientD3D9(aAllocator, aFormat, aTextureFlags);
+      texture = new TextureClientD3D9(aAllocator, aFormat, aTextureFlags);
     }
   }
 
   if (!texture && aFormat == SurfaceFormat::B8G8R8X8 &&
       aAllocator->IsSameProcess() &&
       aMoz2DBackend == gfx::BackendType::CAIRO) {
     if (aAllocator->IsSameProcess()) {
       texture = new TextureClientMemoryDIB(aAllocator, aFormat, aTextureFlags);
--- a/gfx/layers/client/TextureClient.h
+++ b/gfx/layers/client/TextureClient.h
@@ -497,17 +497,17 @@ protected:
   void MarkInvalid() { mValid = false; }
 
   /**
    * Should only be called *once* per texture, in TextureClient::InitIPDLActor.
    * Some texture implementations rely on the fact that the descriptor will be
    * deserialized.
    * Calling ToSurfaceDescriptor again after it has already returned true,
    * or never constructing a TextureHost with aDescriptor may result in a memory
-   * leak (see CairoTextureClientD3D9 for example).
+   * leak (see TextureClientD3D9 for example).
    */
   virtual bool ToSurfaceDescriptor(SurfaceDescriptor& aDescriptor) = 0;
 
   ISurfaceAllocator* GetAllocator()
   {
     return mAllocator;
   }
 
--- a/gfx/layers/d3d11/TextureD3D11.cpp
+++ b/gfx/layers/d3d11/TextureD3D11.cpp
@@ -4,17 +4,16 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "TextureD3D11.h"
 #include "CompositorD3D11.h"
 #include "gfxContext.h"
 #include "Effects.h"
 #include "mozilla/layers/YCbCrImageDataSerializer.h"
 #include "gfxWindowsPlatform.h"
-#include "gfxD2DSurface.h"
 #include "gfx2DGlue.h"
 #include "gfxPrefs.h"
 #include "ReadbackManagerD3D11.h"
 #include "mozilla/gfx/Logging.h"
 
 namespace mozilla {
 
 using namespace gfx;
--- a/gfx/layers/d3d9/TextureD3D9.cpp
+++ b/gfx/layers/d3d9/TextureD3D9.cpp
@@ -156,17 +156,17 @@ CompositingRenderTargetD3D9::BindRenderT
 
 IntSize
 CompositingRenderTargetD3D9::GetSize() const
 {
   return TextureSourceD3D9::GetSize();
 }
 
 /**
- * Helper method for DataToTexture and SurfaceToTexture.
+ * Helper method for DataToTexture.
  * The last three params are out params.
  * Returns the created texture, or null if we fail.
  */
 already_AddRefed<IDirect3DTexture9>
 TextureSourceD3D9::InitTextures(DeviceManagerD3D9* aDeviceManager,
                                 const IntSize &aSize,
                                 _D3DFORMAT aFormat,
                                 RefPtr<IDirect3DSurface9>& aSurface,
@@ -198,17 +198,17 @@ TextureSourceD3D9::InitTextures(DeviceMa
     gfxCriticalError() << "Failed to lock rect initialize texture in D3D9 " << hexa(hr);
     return nullptr;
   }
 
   return result.forget();
 }
 
 /**
- * Helper method for DataToTexture and SurfaceToTexture.
+ * Helper method for DataToTexture.
  */
 static void
 FinishTextures(DeviceManagerD3D9* aDeviceManager,
                IDirect3DTexture9* aTexture,
                IDirect3DSurface9* aSurface)
 {
   if (!aDeviceManager) {
     return;
@@ -269,57 +269,16 @@ TextureSourceD3D9::TextureToTexture(Devi
   HRESULT hr = aDeviceManager->device()->UpdateTexture(aTexture, texture);
   if (FAILED(hr)) {
     return nullptr;
   }
 
   return texture.forget();
 }
 
-already_AddRefed<IDirect3DTexture9>
-TextureSourceD3D9::SurfaceToTexture(DeviceManagerD3D9* aDeviceManager,
-                                    gfxWindowsSurface* aSurface,
-                                    const IntSize& aSize,
-                                    _D3DFORMAT aFormat)
-{
-  RefPtr<IDirect3DSurface9> surface;
-  D3DLOCKED_RECT lockedRect;
-
-  RefPtr<IDirect3DTexture9> texture = InitTextures(aDeviceManager, aSize, aFormat,
-                                                   surface, lockedRect);
-  if (!texture) {
-    return nullptr;
-  }
-
-  {
-    RefPtr<DrawTarget> dt =
-      Factory::CreateDrawTargetForData(BackendType::CAIRO,
-                                       reinterpret_cast<unsigned char*>(lockedRect.pBits),
-                                       aSize, lockedRect.Pitch,
-                                       gfxPlatform::GetPlatform()->Optimal2DFormatForContent(aSurface->GetContentType()));
-
-    if (dt) {
-        NativeSurface nativeSurf;
-        nativeSurf.mSize = aSize;
-        nativeSurf.mType = NativeSurfaceType::CAIRO_SURFACE;
-        // We don't know that this is actually the right format, but it's the best
-        // we can get for the content type. In practice this probably always works.
-        nativeSurf.mFormat = dt->GetFormat();
-        nativeSurf.mSurface = aSurface->CairoSurface();
-
-        RefPtr<SourceSurface> surf = dt->CreateSourceSurfaceFromNativeSurface(nativeSurf);
-        dt->CopySurface(surf, IntRect(IntPoint(), aSize), IntPoint());
-    }
-  }
-
-  FinishTextures(aDeviceManager, texture, surface);
-
-  return texture.forget();
-}
-
 DataTextureSourceD3D9::DataTextureSourceD3D9(gfx::SurfaceFormat aFormat,
                                              CompositorD3D9* aCompositor,
                                              TextureFlags aFlags,
                                              StereoMode aStereoMode)
   : mFormat(aFormat)
   , mCompositor(aCompositor)
   , mCurrentTile(0)
   , mFlags(aFlags)
@@ -435,91 +394,16 @@ DataTextureSourceD3D9::Update(gfx::DataS
         return false;
       }
     }
   }
 
   return true;
 }
 
-bool
-DataTextureSourceD3D9::Update(gfxWindowsSurface* aSurface)
-{
-  MOZ_ASSERT(aSurface);
-  if (!mCompositor || !mCompositor->device()) {
-    NS_WARNING("No D3D device to update the texture.");
-    return false;
-  }
-  mSize = aSurface->GetSize();
-
-  uint32_t bpp = 0;
-
-  _D3DFORMAT format = D3DFMT_A8R8G8B8;
-  mFormat = ImageFormatToSurfaceFormat(
-    gfxPlatform::GetPlatform()->OptimalFormatForContent(aSurface->GetContentType()));
-  switch (mFormat) {
-  case SurfaceFormat::B8G8R8X8:
-    format = D3DFMT_X8R8G8B8;
-    bpp = 4;
-    break;
-  case SurfaceFormat::B8G8R8A8:
-    format = D3DFMT_A8R8G8B8;
-    bpp = 4;
-    break;
-  case SurfaceFormat::A8:
-    format = D3DFMT_A8;
-    bpp = 1;
-    break;
-  default:
-    NS_WARNING("Bad image format");
-    return false;
-  }
-
-  int32_t maxSize = mCompositor->GetMaxTextureSize();
-  DeviceManagerD3D9* deviceManager = gfxWindowsPlatform::GetPlatform()->GetD3D9DeviceManager();
-  if ((mSize.width <= maxSize && mSize.height <= maxSize) ||
-      (mFlags & TextureFlags::DISALLOW_BIGIMAGE)) {
-    mTexture = SurfaceToTexture(deviceManager, aSurface, mSize, format);
-
-    if (!mTexture) {
-      NS_WARNING("Could not upload texture");
-      Reset();
-      return false;
-    }
-    mIsTiled = false;
-  } else {
-    mIsTiled = true;
-    uint32_t tileCount = GetRequiredTilesD3D9(mSize.width, maxSize) *
-                         GetRequiredTilesD3D9(mSize.height, maxSize);
-    mTileTextures.resize(tileCount);
-    mTexture = nullptr;
-    nsRefPtr<gfxImageSurface> imgSurface = aSurface->GetAsImageSurface();
-
-    for (uint32_t i = 0; i < tileCount; i++) {
-      IntRect tileRect = GetTileRect(i);
-      unsigned char* data = imgSurface->Data() +
-                            tileRect.y * imgSurface->Stride() +
-                            tileRect.x * bpp;
-      mTileTextures[i] = DataToTexture(deviceManager,
-                                       data,
-                                       imgSurface->Stride(),
-                                       IntSize(tileRect.width, tileRect.height),
-                                       format,
-                                       bpp);
-      if (!mTileTextures[i]) {
-        NS_WARNING("Could not upload texture");
-        Reset();
-        return false;
-      }
-    }
-  }
-
-  return true;
-}
-
 void
 DataTextureSourceD3D9::SetCompositor(Compositor* aCompositor)
 {
   MOZ_ASSERT(aCompositor);
   CompositorD3D9* d3dCompositor = static_cast<CompositorD3D9*>(aCompositor);
   if (mCompositor && mCompositor != d3dCompositor) {
     Reset();
   }
@@ -553,49 +437,49 @@ DataTextureSourceD3D9::GetTileRect(uint3
 }
 
 IntRect
 DataTextureSourceD3D9::GetTileRect()
 {
   return GetTileRect(mCurrentTile);
 }
 
-CairoTextureClientD3D9::CairoTextureClientD3D9(ISurfaceAllocator* aAllocator,
-                                               gfx::SurfaceFormat aFormat,
-                                               TextureFlags aFlags)
+TextureClientD3D9::TextureClientD3D9(ISurfaceAllocator* aAllocator,
+                                     gfx::SurfaceFormat aFormat,
+                                     TextureFlags aFlags)
   : TextureClient(aAllocator, aFlags)
   , mFormat(aFormat)
   , mIsLocked(false)
   , mNeedsClear(false)
   , mNeedsClearWhite(false)
   , mLockRect(false)
 {
-  MOZ_COUNT_CTOR(CairoTextureClientD3D9);
+  MOZ_COUNT_CTOR(TextureClientD3D9);
 }
 
-CairoTextureClientD3D9::~CairoTextureClientD3D9()
+TextureClientD3D9::~TextureClientD3D9()
 {
-  MOZ_COUNT_DTOR(CairoTextureClientD3D9);
+  MOZ_COUNT_DTOR(TextureClientD3D9);
 }
 
 already_AddRefed<TextureClient>
-CairoTextureClientD3D9::CreateSimilar(TextureFlags aFlags, TextureAllocationFlags aAllocFlags) const
+TextureClientD3D9::CreateSimilar(TextureFlags aFlags, TextureAllocationFlags aAllocFlags) const
 {
-  RefPtr<TextureClient> tex = new CairoTextureClientD3D9(mAllocator, mFormat,
-                                                         mFlags | aFlags);
+  RefPtr<TextureClient> tex = new TextureClientD3D9(mAllocator, mFormat,
+                                                    mFlags | aFlags);
 
   if (!tex->AllocateForSurface(mSize, aAllocFlags)) {
     return nullptr;
   }
 
   return tex.forget();
 }
 
 bool
-CairoTextureClientD3D9::Lock(OpenMode aMode)
+TextureClientD3D9::Lock(OpenMode aMode)
 {
   MOZ_ASSERT(!mIsLocked);
   if (!IsValid() || !IsAllocated()) {
     return false;
   }
 
   if (!gfxWindowsPlatform::GetPlatform()->GetD3D9Device()) {
     // If the device has failed then we should not lock the surface,
@@ -642,95 +526,91 @@ CairoTextureClientD3D9::Lock(OpenMode aM
     mDrawTarget->FillRect(Rect(0, 0, GetSize().width, GetSize().height), ColorPattern(Color(1.0, 1.0, 1.0, 1.0)));
     mNeedsClearWhite = false;
   }
 
   return true;
 }
 
 void
-CairoTextureClientD3D9::Unlock()
+TextureClientD3D9::Unlock()
 {
   MOZ_ASSERT(mIsLocked, "Unlocked called while the texture is not locked!");
   if (!mIsLocked) {
     return;
   }
 
   if (mDrawTarget) {
     mDrawTarget->Flush();
     mDrawTarget = nullptr;
   }
 
   if (mLockRect) {
     mD3D9Surface->UnlockRect();
     mLockRect = false;
   }
 
-  if (mSurface) {
-    mSurface = nullptr;
-  }
   mIsLocked = false;
 }
 
 bool
-CairoTextureClientD3D9::ToSurfaceDescriptor(SurfaceDescriptor& aOutDescriptor)
+TextureClientD3D9::ToSurfaceDescriptor(SurfaceDescriptor& aOutDescriptor)
 {
   MOZ_ASSERT(IsValid());
   if (!IsAllocated()) {
     return false;
   }
 
   mTexture->AddRef(); // Release in TextureHostD3D9::TextureHostD3D9
   aOutDescriptor = SurfaceDescriptorD3D9(reinterpret_cast<uintptr_t>(mTexture.get()));
   return true;
 }
 
 gfx::DrawTarget*
-CairoTextureClientD3D9::BorrowDrawTarget()
+TextureClientD3D9::BorrowDrawTarget()
 {
   MOZ_ASSERT(mIsLocked && mD3D9Surface);
   if (!mIsLocked || !mD3D9Surface) {
     NS_WARNING("Calling BorrowDrawTarget on an Unlocked TextureClient");
     return nullptr;
   }
 
   if (mDrawTarget) {
     return mDrawTarget;
   }
 
   if (ContentForFormat(mFormat) == gfxContentType::COLOR) {
-    mSurface = new gfxWindowsSurface(mD3D9Surface);
-    if (!mSurface || mSurface->CairoStatus()) {
+    nsRefPtr<gfxASurface> surface = new gfxWindowsSurface(mD3D9Surface);
+    if (!surface || surface->CairoStatus()) {
       NS_WARNING("Could not create surface for d3d9 surface");
-      mSurface = nullptr;
       return nullptr;
     }
+    mDrawTarget =
+      gfxPlatform::GetPlatform()->CreateDrawTargetForSurface(surface, mSize);
   } else {
     // gfxWindowsSurface don't support transparency so we can't use the d3d9
     // windows surface optimization.
     // Instead we have to use a gfxImageSurface and fallback for font drawing.
     D3DLOCKED_RECT rect;
     HRESULT hr = mD3D9Surface->LockRect(&rect, nullptr, 0);
     if (FAILED(hr) || !rect.pBits) {
       gfxCriticalError() << "Failed to lock rect borrowing the target in D3D9 " << hexa(hr);
       return nullptr;
     }
-    mSurface = new gfxImageSurface((uint8_t*)rect.pBits, mSize,
-                                   rect.Pitch, SurfaceFormatToImageFormat(mFormat));
+    mDrawTarget =
+     gfxPlatform::GetPlatform()->CreateDrawTargetForData((uint8_t*)rect.pBits, mSize,
+                                                         rect.Pitch, mFormat);
     mLockRect = true;
   }
 
-  mDrawTarget =
-    gfxPlatform::GetPlatform()->CreateDrawTargetForSurface(mSurface, mSize);
-
   return mDrawTarget;
 }
 
 bool
-CairoTextureClientD3D9::AllocateForSurface(gfx::IntSize aSize, TextureAllocationFlags aFlags)
+TextureClientD3D9::AllocateForSurface(gfx::IntSize aSize, TextureAllocationFlags aFlags)
 {
   MOZ_ASSERT(!IsAllocated());
   mSize = aSize;
   _D3DFORMAT format = SurfaceFormatToD3D9Format(mFormat);
 
   DeviceManagerD3D9* deviceManager = gfxWindowsPlatform::GetPlatform()->GetD3D9DeviceManager();
   if (!deviceManager ||
       !(mTexture = deviceManager->CreateTexture(mSize, format, D3DPOOL_SYSTEMMEM, nullptr))) {
@@ -822,17 +702,17 @@ SharedTextureClientD3D9::ToSurfaceDescri
 TextureHostD3D9::TextureHostD3D9(TextureFlags aFlags,
                                  const SurfaceDescriptorD3D9& aDescriptor)
   : TextureHost(aFlags)
   , mFormat(SurfaceFormat::UNKNOWN)
   , mIsLocked(false)
 {
   mTexture = reinterpret_cast<IDirect3DTexture9*>(aDescriptor.texture());
   MOZ_ASSERT(mTexture);
-  mTexture->Release(); // see AddRef in CairoTextureClientD3D9::ToSurfaceDescriptor
+  mTexture->Release(); // see AddRef in TextureClientD3D9::ToSurfaceDescriptor
   MOZ_ASSERT(mTexture);
   D3DSURFACE_DESC desc;
   HRESULT hr = mTexture->GetLevelDesc(0, &desc);
   if (!FAILED(hr)) {
     mFormat = D3D9FormatToSurfaceFormat(desc.Format);
     mSize.width = desc.Width;
     mSize.height = desc.Height;
   }
--- a/gfx/layers/d3d9/TextureD3D9.h
+++ b/gfx/layers/d3d9/TextureD3D9.h
@@ -71,22 +71,16 @@ protected:
   // aTexture should be in SYSTEMMEM, returns a texture in the default
   // pool (that is, in video memory).
   already_AddRefed<IDirect3DTexture9> TextureToTexture(
     DeviceManagerD3D9* aDeviceManager,
     IDirect3DTexture9* aTexture,
     const gfx::IntSize& aSize,
     _D3DFORMAT aFormat);
 
-  already_AddRefed<IDirect3DTexture9> SurfaceToTexture(
-    DeviceManagerD3D9* aDeviceManager,
-    gfxWindowsSurface* aSurface,
-    const gfx::IntSize& aSize,
-    _D3DFORMAT aFormat);
-
   gfx::IntSize mSize;
 
   // Linked list of all objects holding d3d9 textures.
   TextureSourceD3D9* mPreviousHost;
   TextureSourceD3D9* mNextHost;
   // The device manager that created our textures.
   DeviceManagerD3D9* mCreatingDeviceManager;
 
@@ -157,45 +151,41 @@ public:
     mCurrentTile = 0;
   }
 
   /**
    * Copy the content of aTexture using the GPU.
    */
   bool UpdateFromTexture(IDirect3DTexture9* aTexture, const nsIntRegion* aRegion);
 
-  // To use with DIBTextureHostD3D9
-
-  bool Update(gfxWindowsSurface* aSurface);
-
 protected:
   gfx::IntRect GetTileRect(uint32_t aTileIndex) const;
 
   void Reset();
 
   std::vector< RefPtr<IDirect3DTexture9> > mTileTextures;
   RefPtr<CompositorD3D9> mCompositor;
   gfx::SurfaceFormat mFormat;
   uint32_t mCurrentTile;
   TextureFlags mFlags;
   bool mIsTiled;
   bool mIterating;
 };
 
 /**
- * Can only be drawn into through Cairo and need a D3D9 context on the client side.
+ * Needs a D3D9 context on the client side.
  * The corresponding TextureHost is TextureHostD3D9.
  */
-class CairoTextureClientD3D9 : public TextureClient
+class TextureClientD3D9 : public TextureClient
 {
 public:
-  CairoTextureClientD3D9(ISurfaceAllocator* aAllocator, gfx::SurfaceFormat aFormat,
+  TextureClientD3D9(ISurfaceAllocator* aAllocator, gfx::SurfaceFormat aFormat,
                          TextureFlags aFlags);
 
-  virtual ~CairoTextureClientD3D9();
+  virtual ~TextureClientD3D9();
 
   // TextureClient
 
   virtual bool IsAllocated() const override { return !!mTexture; }
 
   virtual bool Lock(OpenMode aOpenMode) override;
 
   virtual void Unlock() override;
@@ -220,17 +210,16 @@ public:
   virtual already_AddRefed<TextureClient>
   CreateSimilar(TextureFlags aFlags = TextureFlags::DEFAULT,
                 TextureAllocationFlags aAllocFlags = ALLOC_DEFAULT) const override;
 
 private:
   RefPtr<IDirect3DTexture9> mTexture;
   nsRefPtr<IDirect3DSurface9> mD3D9Surface;
   RefPtr<gfx::DrawTarget> mDrawTarget;
-  nsRefPtr<gfxASurface> mSurface;
   gfx::IntSize mSize;
   gfx::SurfaceFormat mFormat;
   bool mIsLocked;
   bool mNeedsClear;
   bool mNeedsClearWhite;
   bool mLockRect;
 };
 
--- a/gfx/thebes/gfxASurface.cpp
+++ b/gfx/thebes/gfxASurface.cpp
@@ -22,19 +22,16 @@
 #include "gfxRect.h"
 
 #include "cairo.h"
 #include <algorithm>
 
 #ifdef CAIRO_HAS_WIN32_SURFACE
 #include "gfxWindowsSurface.h"
 #endif
-#ifdef CAIRO_HAS_D2D_SURFACE
-#include "gfxD2DSurface.h"
-#endif
 
 #ifdef MOZ_X11
 #include "gfxXlibSurface.h"
 #endif
 
 #ifdef CAIRO_HAS_QUARTZ_SURFACE
 #include "gfxQuartzSurface.h"
 #include "gfxQuartzImageSurface.h"
@@ -174,21 +171,16 @@ gfxASurface::Wrap (cairo_surface_t *csur
         result = new gfxImageSurface(csurf);
     }
 #ifdef CAIRO_HAS_WIN32_SURFACE
     else if (stype == CAIRO_SURFACE_TYPE_WIN32 ||
              stype == CAIRO_SURFACE_TYPE_WIN32_PRINTING) {
         result = new gfxWindowsSurface(csurf);
     }
 #endif
-#ifdef CAIRO_HAS_D2D_SURFACE
-    else if (stype == CAIRO_SURFACE_TYPE_D2D) {
-        result = new gfxD2DSurface(csurf);
-    }
-#endif
 #ifdef MOZ_X11
     else if (stype == CAIRO_SURFACE_TYPE_XLIB) {
         result = new gfxXlibSurface(csurf);
     }
 #endif
 #ifdef CAIRO_HAS_QUARTZ_SURFACE
     else if (stype == CAIRO_SURFACE_TYPE_QUARTZ) {
         result = new gfxQuartzSurface(csurf, aSize);
@@ -563,25 +555,20 @@ static const SurfaceMemoryReporterAttrs 
     {"gfx-surface-recording", nullptr},
     {"gfx-surface-vg", nullptr},
     {"gfx-surface-gl", nullptr},
     {"gfx-surface-drm", nullptr},
     {"gfx-surface-tee", nullptr},
     {"gfx-surface-xml", nullptr},
     {"gfx-surface-skia", nullptr},
     {"gfx-surface-subsurface", nullptr},
-    {"gfx-surface-d2d", nullptr},
 };
 
 PR_STATIC_ASSERT(MOZ_ARRAY_LENGTH(sSurfaceMemoryReporterAttrs) ==
                  size_t(gfxSurfaceType::Max));
-#ifdef CAIRO_HAS_D2D_SURFACE
-PR_STATIC_ASSERT(uint32_t(CAIRO_SURFACE_TYPE_D2D) ==
-                 uint32_t(gfxSurfaceType::D2D));
-#endif
 PR_STATIC_ASSERT(uint32_t(CAIRO_SURFACE_TYPE_SKIA) ==
                  uint32_t(gfxSurfaceType::Skia));
 
 /* Surface size memory reporting */
 
 static int64_t gSurfaceMemoryUsed[size_t(gfxSurfaceType::Max)] = { 0 };
 
 class SurfaceMemoryReporter final : public nsIMemoryReporter
--- a/gfx/thebes/gfxBlur.cpp
+++ b/gfx/thebes/gfxBlur.cpp
@@ -429,16 +429,21 @@ CreateBlurMask(const IntSize& aRectSize,
 
 static already_AddRefed<SourceSurface>
 CreateBoxShadow(DrawTarget& aDT, SourceSurface* aBlurMask, const gfxRGBA& aShadowColor)
 {
   IntSize blurredSize = aBlurMask->GetSize();
   gfxPlatform* platform = gfxPlatform::GetPlatform();
   RefPtr<DrawTarget> boxShadowDT =
     platform->CreateOffscreenContentDrawTarget(blurredSize, SurfaceFormat::B8G8R8A8);
+
+  if (!boxShadowDT) {
+    return nullptr;
+  }
+
   MOZ_ASSERT(boxShadowDT->GetType() == aDT.GetType());
 
   ColorPattern shadowColor(ToDeviceColor(aShadowColor));
   boxShadowDT->MaskSurface(shadowColor, aBlurMask, Point(0, 0));
   return boxShadowDT->Snapshot();
 }
 
 SourceSurface*
@@ -470,16 +475,20 @@ GetBlur(DrawTarget& aDT,
   RefPtr<SourceSurface> blurMask =
     CreateBlurMask(aRectSize, aCornerRadii, aBlurRadius, aExtendDestBy, aSlice, aDT);
 
   if (!blurMask) {
     return nullptr;
   }
 
   RefPtr<SourceSurface> boxShadow = CreateBoxShadow(aDT, blurMask, aShadowColor);
+  if (!boxShadow) {
+    return nullptr;
+  }
+
   CacheBlur(aDT, minSize, aBlurRadius, aCornerRadii, aShadowColor, aExtendDestBy, boxShadow);
   return boxShadow;
 }
 
 void
 gfxAlphaBoxBlur::ShutdownBlurCache()
 {
   delete gBlurCache;
deleted file mode 100644
--- a/gfx/thebes/gfxD2DSurface.cpp
+++ /dev/null
@@ -1,101 +0,0 @@
-/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "gfxD2DSurface.h"
-#include "cairo.h"
-#include "cairo-win32.h"
-#include "gfxWindowsPlatform.h"
-
-gfxD2DSurface::gfxD2DSurface(HWND aWnd, gfxContentType aContent)
-{
-    Init(cairo_d2d_surface_create_for_hwnd(
-        gfxWindowsPlatform::GetPlatform()->GetD2DDevice(),
-        aWnd,
-        (cairo_content_t)(int)aContent));
-}
-
-gfxD2DSurface::gfxD2DSurface(HANDLE handle, gfxContentType aContent)
-{
-    Init(cairo_d2d_surface_create_for_handle(
-        gfxWindowsPlatform::GetPlatform()->GetD2DDevice(),
-        handle,
-        (cairo_content_t)(int)aContent));
-}
-
-gfxD2DSurface::gfxD2DSurface(ID3D10Texture2D *texture, gfxContentType aContent)
-{
-    Init(cairo_d2d_surface_create_for_texture(
-        gfxWindowsPlatform::GetPlatform()->GetD2DDevice(),
-        texture,
-        (cairo_content_t)(int)aContent));
-}
-
-gfxD2DSurface::gfxD2DSurface(cairo_surface_t *csurf)
-{
-    Init(csurf, true);
-}
-
-gfxD2DSurface::gfxD2DSurface(const mozilla::gfx::IntSize& size,
-                             gfxImageFormat imageFormat)
-{
-    Init(cairo_d2d_surface_create(
-        gfxWindowsPlatform::GetPlatform()->GetD2DDevice(),
-        (cairo_format_t)(int)imageFormat,
-        size.width, size.height));
-}
-
-gfxD2DSurface::~gfxD2DSurface()
-{
-}
-
-void
-gfxD2DSurface::Present()
-{
-    cairo_d2d_present_backbuffer(CairoSurface());
-}
-
-void
-gfxD2DSurface::Scroll(const nsIntPoint &aDelta, const mozilla::gfx::IntRect &aClip)
-{
-    cairo_rectangle_t rect;
-    rect.x = aClip.x;
-    rect.y = aClip.y;
-    rect.width = aClip.width;
-    rect.height = aClip.height;
-    cairo_d2d_scroll(CairoSurface(), aDelta.x, aDelta.y, &rect);
-}
-
-ID3D10Texture2D*
-gfxD2DSurface::GetTexture()
-{
-  return cairo_d2d_surface_get_texture(CairoSurface());
-}
-
-HDC
-gfxD2DSurface::GetDC(bool aRetainContents)
-{
-    return cairo_d2d_get_dc(CairoSurface(), aRetainContents);
-}
-
-void
-gfxD2DSurface::ReleaseDC(const mozilla::gfx::IntRect *aUpdatedRect)
-{
-    if (!aUpdatedRect) {
-        return cairo_d2d_release_dc(CairoSurface(), nullptr);
-    }
-
-    cairo_rectangle_int_t rect;
-    rect.x = aUpdatedRect->x;
-    rect.y = aUpdatedRect->y;
-    rect.width = aUpdatedRect->width;
-    rect.height = aUpdatedRect->height;
-    cairo_d2d_release_dc(CairoSurface(), &rect);
-}
-
-const mozilla::gfx::IntSize gfxD2DSurface::GetSize() const
-{ 
-    return mozilla::gfx::IntSize(cairo_d2d_surface_get_width(mSurface),
-                      cairo_d2d_surface_get_height(mSurface));
-}
\ No newline at end of file
deleted file mode 100644
--- a/gfx/thebes/gfxD2DSurface.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#ifndef GFX_D2DSURFACE_H
-#define GFX_D2DSURFACE_H
-
-#include "gfxASurface.h"
-#include "nsPoint.h"
-
-#include <windows.h>
-
-struct ID3D10Texture2D;
-
-class gfxD2DSurface : public gfxASurface {
-public:
-
-    gfxD2DSurface(HWND wnd,
-                  gfxContentType aContent);
-
-    gfxD2DSurface(const mozilla::gfx::IntSize& size,
-                  gfxImageFormat imageFormat = gfxImageFormat::RGB24);
-
-    gfxD2DSurface(HANDLE handle, gfxContentType aContent);
-
-    gfxD2DSurface(ID3D10Texture2D *texture, gfxContentType aContent);
-
-    gfxD2DSurface(cairo_surface_t *csurf);
-
-    virtual ~gfxD2DSurface();
-
-    void Present();
-    void Scroll(const nsIntPoint &aDelta, const mozilla::gfx::IntRect &aClip);
-
-    virtual const mozilla::gfx::IntSize GetSize() const;
-
-    ID3D10Texture2D *GetTexture();
-
-    HDC GetDC(bool aRetainContents);
-    void ReleaseDC(const mozilla::gfx::IntRect *aUpdatedRect);
-};
-
-#endif /* GFX_D2DSURFACE_H */
--- a/gfx/thebes/gfxPlatform.cpp
+++ b/gfx/thebes/gfxPlatform.cpp
@@ -26,17 +26,16 @@
 #endif
 
 #include "nsXULAppAPI.h"
 #include "nsDirectoryServiceUtils.h"
 #include "nsDirectoryServiceDefs.h"
 
 #if defined(XP_WIN)
 #include "gfxWindowsPlatform.h"
-#include "gfxD2DSurface.h"
 #elif defined(XP_MACOSX)
 #include "gfxPlatformMac.h"
 #include "gfxQuartzSurface.h"
 #elif defined(MOZ_WIDGET_GTK)
 #include "gfxPlatformGtk.h"
 #elif defined(MOZ_WIDGET_QT)
 #include "gfxQtPlatform.h"
 #elif defined(ANDROID)
@@ -907,31 +906,16 @@ gfxPlatform::GetSourceSurfaceForSurface(
     // strong reference back to srcBuffer, creating a reference loop and a
     // memory leak. Not caching is fine since wrapping is cheap enough (no
     // copying) so we can just wrap again next time we're called.
     return aTarget->CreateSourceSurfaceFromNativeSurface(surf);
   }
 
   RefPtr<SourceSurface> srcBuffer;
 
-#ifdef XP_WIN
-  if (aSurface->GetType() == gfxSurfaceType::D2D &&
-      format != SurfaceFormat::A8) {
-    NativeSurface surf;
-    surf.mFormat = format;
-    surf.mType = NativeSurfaceType::D3D10_TEXTURE;
-    surf.mSurface = static_cast<gfxD2DSurface*>(aSurface)->GetTexture();
-    surf.mSize = aSurface->GetSize();
-    mozilla::gfx::DrawTarget *dt = static_cast<mozilla::gfx::DrawTarget*>(aSurface->GetData(&kDrawTarget));
-    if (dt) {
-      dt->Flush();
-    }
-    srcBuffer = aTarget->CreateSourceSurfaceFromNativeSurface(surf);
-  }
-#endif
   // Currently no other DrawTarget types implement CreateSourceSurfaceFromNativeSurface
 
   if (!srcBuffer) {
     // If aSurface wraps data, we can create a SourceSurfaceRawData that wraps
     // the same data, then optimize it for aTarget:
     RefPtr<DataSourceSurface> surf = GetWrappedDataSourceSurface(aSurface);
     if (surf) {
       srcBuffer = aTarget->OptimizeSourceSurface(surf);
--- a/gfx/thebes/gfxTypes.h
+++ b/gfx/thebes/gfxTypes.h
@@ -77,17 +77,16 @@ enum class gfxSurfaceType {
   Recording,
   VG,
   GL,
   DRM,
   Tee,
   XML,
   Skia,
   Subsurface,
-  D2D,
   Max
 };
 
 enum class gfxContentType {
   COLOR       = 0x1000,
   ALPHA       = 0x2000,
   COLOR_ALPHA = 0x3000,
   SENTINEL    = 0xffff
--- a/gfx/thebes/gfxWindowsPlatform.cpp
+++ b/gfx/thebes/gfxWindowsPlatform.cpp
@@ -50,18 +50,16 @@
 #include "gfxTextRun.h"
 #include "gfxUserFontSet.h"
 #include "nsWindowsHelpers.h"
 #include "gfx2DGlue.h"
 
 #include <string>
 
 #ifdef CAIRO_HAS_D2D_SURFACE
-#include "gfxD2DSurface.h"
-
 #include <d3d10_1.h>
 
 #include "mozilla/gfx/2D.h"
 
 #include "nsMemory.h"
 #endif
 
 #include <d3d11.h>
@@ -111,48 +109,16 @@ DCFromDrawTarget::DCFromDrawTarget(DrawT
 
 #ifdef CAIRO_HAS_D2D_SURFACE
 
 static const char *kFeatureLevelPref =
   "gfx.direct3d.last_used_feature_level_idx";
 static const int kSupportedFeatureLevels[] =
   { D3D10_FEATURE_LEVEL_10_1, D3D10_FEATURE_LEVEL_10_0 };
 
-class GfxD2DSurfaceReporter final : public nsIMemoryReporter
-{
-    ~GfxD2DSurfaceReporter() {}
-
-public:
-    NS_DECL_ISUPPORTS
-
-    NS_IMETHOD CollectReports(nsIHandleReportCallback* aHandleReport,
-                              nsISupports* aData, bool aAnonymize)
-    {
-        nsresult rv;
-
-        int64_t amount = cairo_d2d_get_image_surface_cache_usage();
-        rv = MOZ_COLLECT_REPORT(
-            "gfx-d2d-surface-cache", KIND_OTHER, UNITS_BYTES, amount,
-            "Memory used by the Direct2D internal surface cache.");
-        NS_ENSURE_SUCCESS(rv, rv);
-
-        cairo_device_t *device =
-            gfxWindowsPlatform::GetPlatform()->GetD2DDevice();
-        amount = device ? cairo_d2d_get_surface_vram_usage(device) : 0;
-        rv = MOZ_COLLECT_REPORT(
-            "gfx-d2d-surface-vram", KIND_OTHER, UNITS_BYTES, amount,
-            "Video memory used by D2D surfaces.");
-        NS_ENSURE_SUCCESS(rv, rv);
-
-        return NS_OK;
-    }
-};
-
-NS_IMPL_ISUPPORTS(GfxD2DSurfaceReporter, nsIMemoryReporter)
-
 #endif
 
 class GfxD2DVramReporter final : public nsIMemoryReporter
 {
     ~GfxD2DVramReporter() {}
 
 public:
     NS_DECL_ISUPPORTS
@@ -416,20 +382,16 @@ gfxWindowsPlatform::gfxWindowsPlatform()
 
     mUsingGDIFonts = false;
 
     /* 
      * Initialize COM 
      */ 
     CoInitialize(nullptr); 
 
-#ifdef CAIRO_HAS_D2D_SURFACE
-    RegisterStrongMemoryReporter(new GfxD2DSurfaceReporter());
-    mD2DDevice = nullptr;
-#endif
     RegisterStrongMemoryReporter(new GfxD2DVramReporter());
 
     if (gfxPrefs::Direct2DUse1_1()) {
       InitD3D11Devices();
     }
 
     UpdateRenderMode();
 
@@ -438,28 +400,21 @@ gfxWindowsPlatform::gfxWindowsPlatform()
     RegisterStrongMemoryReporter(new D3D9TextureReporter());
     RegisterStrongMemoryReporter(new D3D9SurfaceImageReporter());
     RegisterStrongMemoryReporter(new D3D9SharedTextureReporter());
 }
 
 gfxWindowsPlatform::~gfxWindowsPlatform()
 {
     mDeviceManager = nullptr;
+    mD3D10Device = nullptr;
     mD3D11Device = nullptr;
     mD3D11ContentDevice = nullptr;
     mD3D11ImageBridgeDevice = nullptr;
 
-    // not calling FT_Done_FreeType because cairo may still hold references to
-    // these FT_Faces.  See bug 458169.
-#ifdef CAIRO_HAS_D2D_SURFACE
-    if (mD2DDevice) {
-        cairo_release_device(mD2DDevice);
-    }
-#endif
-
     mozilla::gfx::Factory::D2DCleanup();
 
     mAdapter = nullptr;
 
     /* 
      * Uninitialize COM 
      */ 
     CoUninitialize();
@@ -543,22 +498,22 @@ gfxWindowsPlatform::UpdateRenderMode()
         tryD2D = false;
     }
 
     ID3D11Device *device = GetD3D11Device();
     if (isVistaOrHigher && !InSafeMode() && tryD2D && device &&
         mDoesD3D11TextureSharingWork) {
 
         VerifyD2DDevice(d2dForceEnabled);
-        if (mD2DDevice && GetD3D11Device()) {
+        if (mD3D10Device && GetD3D11Device()) {
             mRenderMode = RENDER_DIRECT2D;
             mUseDirectWrite = true;
         }
     } else {
-        mD2DDevice = nullptr;
+        mD3D10Device = nullptr;
     }
 #endif
 
 #ifdef CAIRO_HAS_DWRITE_FONT
     // Enable when it's preffed on -and- we're using Vista or higher. Or when
     // we're going to use D2D.
     if (!mDWriteFactory && (mUseDirectWrite && isVistaOrHigher)) {
         mozilla::ScopedGfxFeatureReporter reporter("DWrite");
@@ -626,34 +581,37 @@ gfxWindowsPlatform::CreateDevice(nsRefPt
   nsModuleHandle d3d10module(LoadLibrarySystem32(L"d3d10_1.dll"));
   if (!d3d10module)
     return E_FAIL;
   decltype(D3D10CreateDevice1)* createD3DDevice =
     (decltype(D3D10CreateDevice1)*) GetProcAddress(d3d10module, "D3D10CreateDevice1");
   if (!createD3DDevice)
     return E_FAIL;
 
-  nsRefPtr<ID3D10Device1> device;
+  ID3D10Device1* device = nullptr;
   HRESULT hr =
     createD3DDevice(adapter1, D3D10_DRIVER_TYPE_HARDWARE, nullptr,
 #ifdef DEBUG
                     // This isn't set because of bug 1078411
                     // D3D10_CREATE_DEVICE_DEBUG |
 #endif
                     D3D10_CREATE_DEVICE_BGRA_SUPPORT |
                     D3D10_CREATE_DEVICE_PREVENT_INTERNAL_THREADING_OPTIMIZATIONS,
                     static_cast<D3D10_FEATURE_LEVEL1>(kSupportedFeatureLevels[featureLevelIndex]),
-                    D3D10_1_SDK_VERSION, getter_AddRefs(device));
+                    D3D10_1_SDK_VERSION, &device);
 
   // If we fail here, the DirectX version or video card probably
   // changed.  We previously could use 10.1 but now we can't
   // anymore.  Revert back to doing a 10.0 check first before
   // the 10.1 check.
   if (device) {
-    mD2DDevice = cairo_d2d_create_device_from_d3d10device(device);
+    mD3D10Device = device;
+
+    // Leak the module while the D3D 10 device is being used.
+    d3d10module.disown();
 
     // Setup a pref for future launch optimizaitons when in main process.
     if (XRE_IsParentProcess()) {
       Preferences::SetInt(kFeatureLevelPref, featureLevelIndex);
     }
   }
 
   return device ? S_OK : hr;
@@ -664,33 +622,29 @@ void
 gfxWindowsPlatform::VerifyD2DDevice(bool aAttemptForce)
 {
 #ifdef CAIRO_HAS_D2D_SURFACE
     DriverInitCrashDetection detectCrashes;
     if (detectCrashes.DisableAcceleration()) {
       return;
     }
 
-    if (mD2DDevice) {
-        ID3D10Device1 *device = cairo_d2d_device_get_device(mD2DDevice);
-
-        if (SUCCEEDED(device->GetDeviceRemovedReason())) {
+    if (mD3D10Device) {
+        if (SUCCEEDED(mD3D10Device->GetDeviceRemovedReason())) {
             return;
         }
-        mD2DDevice = nullptr;
+        mD3D10Device = nullptr;
 
         // Surface cache needs to be invalidated since it may contain vector
         // images rendered with our old, broken D2D device.
         SurfaceCache::DiscardAll();
     }
 
     mozilla::ScopedGfxFeatureReporter reporter("D2D", aAttemptForce);
 
-    nsRefPtr<ID3D10Device1> device;
-
     int supportedFeatureLevelsCount = ArrayLength(kSupportedFeatureLevels);
 
     nsRefPtr<IDXGIAdapter1> adapter1 = GetDXGIAdapter();
 
     if (!adapter1) {
       // Unable to create adapter, abort acceleration.
       return;
     }
@@ -719,23 +673,19 @@ gfxWindowsPlatform::VerifyD2DDevice(bool
         hr = CreateDevice(adapter1, i);
         // If it failed then we don't have new hardware
         if (FAILED(hr)) {
           break;
         }
       }
     }
 
-    if (!mD2DDevice && aAttemptForce) {
-        mD2DDevice = cairo_d2d_create_device();
-    }
-
-    if (mD2DDevice) {
+    if (mD3D10Device) {
         reporter.SetSuccessful();
-        mozilla::gfx::Factory::SetDirect3D10Device(cairo_d2d_device_get_device(mD2DDevice));
+        mozilla::gfx::Factory::SetDirect3D10Device(mD3D10Device);
     }
 
     ScopedGfxFeatureReporter reporter1_1("D2D1.1");
 
     if (Factory::SupportsD2D1()) {
       reporter1_1.SetSuccessful();
     }
 #endif
@@ -774,27 +724,21 @@ gfxWindowsPlatform::CreatePlatformFontLi
 
 already_AddRefed<gfxASurface>
 gfxWindowsPlatform::CreateOffscreenSurface(const IntSize& size,
                                            gfxContentType contentType)
 {
     nsRefPtr<gfxASurface> surf = nullptr;
 
 #ifdef CAIRO_HAS_WIN32_SURFACE
-    if (mRenderMode == RENDER_GDI)
+    if (mRenderMode == RENDER_GDI || mRenderMode == RENDER_DIRECT2D)
         surf = new gfxWindowsSurface(size,
                                      OptimalFormatForContent(contentType));
 #endif
 
-#ifdef CAIRO_HAS_D2D_SURFACE
-    if (mRenderMode == RENDER_DIRECT2D)
-        surf = new gfxD2DSurface(size,
-                                 OptimalFormatForContent(contentType));
-#endif
-
     if (!surf || surf->CairoStatus()) {
         surf = new gfxImageSurface(size,
                                    OptimalFormatForContent(contentType));
     }
 
     return surf.forget();
 }
 
--- a/gfx/thebes/gfxWindowsPlatform.h
+++ b/gfx/thebes/gfxWindowsPlatform.h
@@ -235,20 +235,17 @@ public:
     IDWriteRenderingParams *GetRenderingParams(TextRenderingMode aRenderMode)
     { return mRenderingParams[aRenderMode]; }
 #else
     inline bool DWriteEnabled() { return false; }
 #endif
     void OnDeviceManagerDestroy(mozilla::layers::DeviceManagerD3D9* aDeviceManager);
     mozilla::layers::DeviceManagerD3D9* GetD3D9DeviceManager();
     IDirect3DDevice9* GetD3D9Device();
-#ifdef CAIRO_HAS_D2D_SURFACE
-    cairo_device_t *GetD2DDevice() { return mD2DDevice; }
-    ID3D10Device1 *GetD3D10Device() { return mD2DDevice ? cairo_d2d_device_get_device(mD2DDevice) : nullptr; }
-#endif
+    ID3D10Device1 *GetD3D10Device() { return mD3D10Device; }
     ID3D11Device *GetD3D11Device();
     ID3D11Device *GetD3D11ContentDevice();
     // Device to be used on the ImageBridge thread
     ID3D11Device *GetD3D11ImageBridgeDevice();
 
     // Create a D3D11 device to be used for DXVA decoding.
     already_AddRefed<ID3D11Device> CreateD3D11DecoderDevice();
 
@@ -286,21 +283,19 @@ private:
     bool mUsingGDIFonts;
 
 #ifdef CAIRO_HAS_DWRITE_FONT
     nsRefPtr<IDWriteFactory> mDWriteFactory;
     nsRefPtr<IDWriteTextAnalyzer> mDWriteAnalyzer;
     nsRefPtr<IDWriteRenderingParams> mRenderingParams[TEXT_RENDERING_COUNT];
     DWRITE_MEASURING_MODE mMeasuringMode;
 #endif
-#ifdef CAIRO_HAS_D2D_SURFACE
-    cairo_device_t *mD2DDevice;
-#endif
     mozilla::RefPtr<IDXGIAdapter1> mAdapter;
     nsRefPtr<mozilla::layers::DeviceManagerD3D9> mDeviceManager;
+    mozilla::RefPtr<ID3D10Device1> mD3D10Device;
     mozilla::RefPtr<ID3D11Device> mD3D11Device;
     mozilla::RefPtr<ID3D11Device> mD3D11ContentDevice;
     mozilla::RefPtr<ID3D11Device> mD3D11ImageBridgeDevice;
     bool mD3D11DeviceInitialized;
     mozilla::RefPtr<mozilla::layers::ReadbackManagerD3D11> mD3D11ReadbackManager;
     bool mIsWARP;
     bool mHasDeviceReset;
     bool mDoesD3D11TextureSharingWork;
--- a/gfx/thebes/moz.build
+++ b/gfx/thebes/moz.build
@@ -157,17 +157,16 @@ elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'qt
         ]
         SOURCES += [
             'gfxQtNativeRenderer.cpp',
             'gfxXlibSurface.cpp',
         ]
 
 elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
     EXPORTS += [
-        'gfxD2DSurface.h',
         'gfxDWriteFonts.h',
         'gfxGDIFont.h',
         'gfxGDIFontList.h',
         'gfxPDFSurface.h',
         'gfxPlatformFontList.h',
         'gfxWindowsNativeDrawing.h',
         'gfxWindowsPlatform.h',
         'gfxWindowsSurface.h',
@@ -180,17 +179,16 @@ elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'wi
         'gfxWindowsPlatform.cpp',
         'gfxWindowsSurface.cpp',
     ]
     if CONFIG['MOZ_ENABLE_DWRITE_FONT']:
         UNIFIED_SOURCES += [
             'gfxDWriteFontList.cpp',
         ]
         SOURCES += [
-            'gfxD2DSurface.cpp',
             'gfxDWriteCommon.cpp',
             'gfxDWriteFonts.cpp',
         ]
 
 # Are we targeting x86 or x64?  If so, build gfxAlphaRecoverySSE2.cpp.
 if CONFIG['INTEL_ARCHITECTURE']:
     SOURCES += ['gfxAlphaRecoverySSE2.cpp']
     # The file uses SSE2 intrinsics, so it needs special compile flags on some
--- a/js/public/StructuredClone.h
+++ b/js/public/StructuredClone.h
@@ -187,17 +187,17 @@ class JS_PUBLIC_API(JSAutoStructuredClon
     JSAutoStructuredCloneBuffer(JSAutoStructuredCloneBuffer&& other);
     JSAutoStructuredCloneBuffer& operator=(JSAutoStructuredCloneBuffer&& other);
 
     ~JSAutoStructuredCloneBuffer() { clear(); }
 
     uint64_t* data() const { return data_; }
     size_t nbytes() const { return nbytes_; }
 
-    void clear();
+    void clear(const JSStructuredCloneCallbacks* optionalCallbacks=nullptr, void* closure=nullptr);
 
     // Copy some memory. It will be automatically freed by the destructor.
     bool copy(const uint64_t* data, size_t nbytes, uint32_t version=JS_STRUCTURED_CLONE_VERSION);
 
     // Adopt some memory. It will be automatically freed by the destructor.
     // data must have been allocated by the JS engine (e.g., extracted via
     // JSAutoStructuredCloneBuffer::steal).
     void adopt(uint64_t* data, size_t nbytes, uint32_t version=JS_STRUCTURED_CLONE_VERSION);
--- a/js/src/jit/IonBuilder.cpp
+++ b/js/src/jit/IonBuilder.cpp
@@ -10306,18 +10306,20 @@ IonBuilder::getPropTryConstant(bool* emi
     if (!types->mightBeMIRType(MIRType_Object)) {
         // If we have not observed an object result here, don't look for a
         // singleton constant.
         trackOptimizationOutcome(TrackedOutcome::NotObject);
         return true;
     }
 
     JSObject* singleton = testSingletonPropertyTypes(obj, name);
-    if (!singleton)
-        return true;
+    if (!singleton) {
+        trackOptimizationOutcome(TrackedOutcome::NotSingleton);
+        return true;
+    }
 
     // Property access is a known constant -- safe to emit.
     obj->setImplicitlyUsedUnchecked();
 
     pushConstant(ObjectValue(*singleton));
 
     trackOptimizationSuccess();
     *emitted = true;
--- a/js/src/jit/MacroAssembler-inl.h
+++ b/js/src/jit/MacroAssembler-inl.h
@@ -54,17 +54,17 @@ MacroAssembler::PushWithPatch(ImmWord wo
 
 CodeOffsetLabel
 MacroAssembler::PushWithPatch(ImmPtr imm)
 {
     return PushWithPatch(ImmWord(uintptr_t(imm.value)));
 }
 
 // ===============================================================
-// Call functions.
+// Simple call functions.
 
 void
 MacroAssembler::call(const CallSiteDesc& desc, const Register reg)
 {
     call(reg);
     append(desc, currentOffset(), framePushed());
 }
 
--- a/js/src/jit/MacroAssembler.h
+++ b/js/src/jit/MacroAssembler.h
@@ -345,19 +345,27 @@ class MacroAssembler : public MacroAssem
     void reserveStack(uint32_t amount) PER_ARCH;
     void freeStack(uint32_t amount);
 
     // Warning: This method does not update the framePushed() counter.
     void freeStack(Register amount);
 
   public:
     // ===============================================================
-    // Call functions.
+    // Simple call functions.
 
-    using MacroAssemblerSpecific::call; // legacy
+    void call(Register reg) PER_ARCH;
+    void call(const Address& addr) PER_ARCH ONLY_X86_X64;
+    void call(Label* label) PER_ARCH;
+    void call(ImmWord imm) PER_ARCH;
+    // Call a target native function, which is neither traceable nor movable.
+    void call(ImmPtr imm) PER_ARCH;
+    void call(AsmJSImmPtr imm) PER_ARCH;
+    // Call a target JitCode, which must be traceable, and may be movable.
+    void call(JitCode* c) PER_ARCH;
 
     inline void call(const CallSiteDesc& desc, const Register reg);
     inline void call(const CallSiteDesc& desc, Label* label);
 
   public:
 
     // Emits a test of a value against all types in a TypeSet. A scratch
     // register is required.
--- a/js/src/jit/arm/Assembler-arm.h
+++ b/js/src/jit/arm/Assembler-arm.h
@@ -1633,19 +1633,16 @@ class Assembler : public AssemblerShared
 
     void Bind(uint8_t* rawCode, AbsoluteLabel* label, const void* address);
 
     // See Bind
     size_t labelOffsetToPatchOffset(size_t offset) {
         return actualOffset(offset);
     }
 
-    void call(Label* label);
-    void call(void* target);
-
     void as_bkpt();
 
   public:
     static void TraceJumpRelocations(JSTracer* trc, JitCode* code, CompactBufferReader& reader);
     static void TraceDataRelocations(JSTracer* trc, JitCode* code, CompactBufferReader& reader);
 
     static bool SupportsFloatingPoint() {
         return HasVFP();
--- a/js/src/jit/arm/MacroAssembler-arm.cpp
+++ b/js/src/jit/arm/MacroAssembler-arm.cpp
@@ -4117,41 +4117,41 @@ MacroAssemblerARMCompat::callWithABI(voi
     callWithABIPost(stackAdjust, result);
 }
 
 void
 MacroAssemblerARMCompat::callWithABI(AsmJSImmPtr imm, MoveOp::Type result)
 {
     uint32_t stackAdjust;
     callWithABIPre(&stackAdjust, /* callFromAsmJS = */ true);
-    call(imm);
+    asMasm().call(imm);
     callWithABIPost(stackAdjust, result);
 }
 
 void
 MacroAssemblerARMCompat::callWithABI(const Address& fun, MoveOp::Type result)
 {
     // Load the callee in r12, no instruction between the ldr and call should
     // clobber it. Note that we can't use fun.base because it may be one of the
     // IntArg registers clobbered before the call.
     ma_ldr(fun, r12);
     uint32_t stackAdjust;
     callWithABIPre(&stackAdjust);
-    call(r12);
+    asMasm().call(r12);
     callWithABIPost(stackAdjust, result);
 }
 
 void
 MacroAssemblerARMCompat::callWithABI(Register fun, MoveOp::Type result)
 {
     // Load the callee in r12, as above.
     ma_mov(fun, r12);
     uint32_t stackAdjust;
     callWithABIPre(&stackAdjust);
-    call(r12);
+    asMasm().call(r12);
     callWithABIPost(stackAdjust, result);
 }
 
 void
 MacroAssemblerARMCompat::handleFailureWithHandlerTail(void* handler)
 {
     // Reserve space for exception information.
     int size = (sizeof(ResumeFromException) + 7) & ~7;
@@ -5085,16 +5085,24 @@ MacroAssemblerARMCompat::profilerEnterFr
 }
 
 void
 MacroAssemblerARMCompat::profilerExitFrame()
 {
     branch(GetJitContext()->runtime->jitRuntime()->getProfilerExitFrameTail());
 }
 
+void
+MacroAssemblerARMCompat::callAndPushReturnAddress(Label* label)
+{
+    AutoForbidPools afp(this, 2);
+    ma_push(pc);
+    asMasm().call(label);
+}
+
 MacroAssembler&
 MacroAssemblerARMCompat::asMasm()
 {
     return *static_cast<MacroAssembler*>(this);
 }
 
 const MacroAssembler&
 MacroAssemblerARMCompat::asMasm() const
@@ -5235,8 +5243,60 @@ MacroAssembler::Pop(const ValueOperand& 
 
 void
 MacroAssembler::reserveStack(uint32_t amount)
 {
     if (amount)
         ma_sub(Imm32(amount), sp);
     adjustFrame(amount);
 }
+
+// ===============================================================
+// Simple call functions.
+
+void
+MacroAssembler::call(Register reg)
+{
+    as_blx(reg);
+}
+
+void
+MacroAssembler::call(Label* label)
+{
+    // For now, assume that it'll be nearby?
+    as_bl(label, Always);
+}
+
+void
+MacroAssembler::call(ImmWord imm)
+{
+    call(ImmPtr((void*)imm.value));
+}
+
+void
+MacroAssembler::call(ImmPtr imm)
+{
+    BufferOffset bo = m_buffer.nextOffset();
+    addPendingJump(bo, imm, Relocation::HARDCODED);
+    ma_call(imm);
+}
+
+void
+MacroAssembler::call(AsmJSImmPtr imm)
+{
+    movePtr(imm, CallReg);
+    call(CallReg);
+}
+
+void
+MacroAssembler::call(JitCode* c)
+{
+    BufferOffset bo = m_buffer.nextOffset();
+    addPendingJump(bo, ImmPtr(c->raw()), Relocation::JITCODE);
+    RelocStyle rs;
+    if (HasMOVWT())
+        rs = L_MOVWT;
+    else
+        rs = L_LDR;
+
+    ma_movPatchable(ImmPtr(c->raw()), ScratchRegister, Always, rs);
+    ma_callJitHalfPush(ScratchRegister);
+}
--- a/js/src/jit/arm/MacroAssembler-arm.h
+++ b/js/src/jit/arm/MacroAssembler-arm.h
@@ -533,17 +533,16 @@ class MacroAssemblerARMCompat : public M
     MoveResolver moveResolver_;
 
   public:
     MacroAssemblerARMCompat()
       : inCall_(false)
     { }
 
   public:
-    using MacroAssemblerARM::call;
 
     // Jumps + other functions that should be called from non-arm specific
     // code. Basically, an x86 front end on top of the ARM code.
     void j(Condition code , Label* dest)
     {
         as_b(dest, code);
     }
     void j(Label* dest)
@@ -562,52 +561,17 @@ class MacroAssemblerARMCompat : public M
     }
     void mov(Register src, Address dest) {
         MOZ_CRASH("NYI-IC");
     }
     void mov(Address src, Register dest) {
         MOZ_CRASH("NYI-IC");
     }
 
-    void call(const Register reg) {
-        as_blx(reg);
-    }
-    void call(Label* label) {
-        // For now, assume that it'll be nearby?
-        as_bl(label, Always);
-    }
-    void call(ImmWord imm) {
-        call(ImmPtr((void*)imm.value));
-    }
-    void call(ImmPtr imm) {
-        BufferOffset bo = m_buffer.nextOffset();
-        addPendingJump(bo, imm, Relocation::HARDCODED);
-        ma_call(imm);
-    }
-    void call(AsmJSImmPtr imm) {
-        movePtr(imm, CallReg);
-        call(CallReg);
-    }
-    void call(JitCode* c) {
-        BufferOffset bo = m_buffer.nextOffset();
-        addPendingJump(bo, ImmPtr(c->raw()), Relocation::JITCODE);
-        RelocStyle rs;
-        if (HasMOVWT())
-            rs = L_MOVWT;
-        else
-            rs = L_LDR;
-
-        ma_movPatchable(ImmPtr(c->raw()), ScratchRegister, Always, rs);
-        ma_callJitHalfPush(ScratchRegister);
-    }
-    void callAndPushReturnAddress(Label* label) {
-        AutoForbidPools afp(this, 2);
-        ma_push(pc);
-        call(label);
-    }
+    void callAndPushReturnAddress(Label* label);
 
     void branch(JitCode* c) {
         BufferOffset bo = m_buffer.nextOffset();
         addPendingJump(bo, ImmPtr(c->raw()), Relocation::JITCODE);
         RelocStyle rs;
         if (HasMOVWT())
             rs = L_MOVWT;
         else
--- a/js/src/jit/arm64/MacroAssembler-arm64.cpp
+++ b/js/src/jit/arm64/MacroAssembler-arm64.cpp
@@ -51,21 +51,38 @@ MacroAssemblerCompat::buildFakeExitFrame
     leaveNoPool();
 
     MOZ_ASSERT(framePushed() == initialDepth + ExitFrameLayout::Size());
 
     *offset = pseudoReturnOffset;
 }
 
 void
+MacroAssemblerCompat::callWithExitFrame(Label* target)
+{
+    uint32_t descriptor = MakeFrameDescriptor(framePushed(), JitFrame_IonJS);
+    Push(Imm32(descriptor)); // descriptor
+    asMasm().call(target);
+}
+
+void
 MacroAssemblerCompat::callWithExitFrame(JitCode* target)
 {
     uint32_t descriptor = MakeFrameDescriptor(framePushed(), JitFrame_IonJS);
     asMasm().Push(Imm32(descriptor));
-    call(target);
+    asMasm().call(target);
+}
+
+void
+MacroAssemblerCompat::callWithExitFrame(JitCode* target, Register dynStack)
+{
+    add32(Imm32(framePushed()), dynStack);
+    makeFrameDescriptor(dynStack, JitFrame_IonJS);
+    Push(dynStack); // descriptor
+    asMasm().call(target);
 }
 
 void
 MacroAssembler::alignFrameForICArguments(MacroAssembler::AfterICSaveLive& aic)
 {
     // Exists for MIPS compatibility.
 }
 
@@ -436,48 +453,48 @@ MacroAssemblerCompat::callWithABI(void* 
     AssertValidABIFunctionType(passedArgTypes_);
 # endif
     ABIFunctionType type = ABIFunctionType(passedArgTypes_);
     fun = vixl::Simulator::RedirectNativeFunction(fun, type);
 #endif // JS_SIMULATOR_ARM64
 
     uint32_t stackAdjust;
     callWithABIPre(&stackAdjust);
-    call(ImmPtr(fun));
+    asMasm().call(ImmPtr(fun));
     callWithABIPost(stackAdjust, result);
 }
 
 void
 MacroAssemblerCompat::callWithABI(Register fun, MoveOp::Type result)
 {
     movePtr(fun, ip0);
 
     uint32_t stackAdjust;
     callWithABIPre(&stackAdjust);
-    call(ip0);
+    asMasm().call(ip0);
     callWithABIPost(stackAdjust, result);
 }
 
 void
 MacroAssemblerCompat::callWithABI(AsmJSImmPtr imm, MoveOp::Type result)
 {
     uint32_t stackAdjust;
     callWithABIPre(&stackAdjust);
-    call(imm);
+    asMasm().call(imm);
     callWithABIPost(stackAdjust, result);
 }
 
 void
 MacroAssemblerCompat::callWithABI(Address fun, MoveOp::Type result)
 {
     loadPtr(fun, ip0);
 
     uint32_t stackAdjust;
     callWithABIPre(&stackAdjust);
-    call(ip0);
+    asMasm().call(ip0);
     callWithABIPost(stackAdjust, result);
 }
 
 void
 MacroAssemblerCompat::branchPtrInNurseryRange(Condition cond, Register ptr, Register temp,
                                               Label* label)
 {
     MOZ_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual);
@@ -679,10 +696,62 @@ MacroAssembler::Pop(const Register reg)
 
 void
 MacroAssembler::Pop(const ValueOperand& val)
 {
     pop(val);
     adjustFrame(-1 * int64_t(sizeof(int64_t)));
 }
 
+// ===============================================================
+// Simple call functions.
+
+void
+MacroAssembler::call(Register reg)
+{
+    syncStackPtr();
+    Blr(ARMRegister(reg, 64));
+}
+
+void
+MacroAssembler::call(Label* label)
+{
+    syncStackPtr();
+    Bl(label);
+}
+
+void
+MacroAssembler::call(ImmWord imm)
+{
+    call(ImmPtr((void*)imm.value));
+}
+
+void
+MacroAssembler::call(ImmPtr imm)
+{
+    syncStackPtr();
+    movePtr(imm, ip0);
+    Blr(vixl::ip0);
+}
+
+void
+MacroAssembler::call(AsmJSImmPtr imm)
+{
+    vixl::UseScratchRegisterScope temps(this);
+    const Register scratch = temps.AcquireX().asUnsized();
+    syncStackPtr();
+    movePtr(imm, scratch);
+    call(scratch);
+}
+
+void
+MacroAssembler::call(JitCode* c)
+{
+    vixl::UseScratchRegisterScope temps(this);
+    const ARMRegister scratch64 = temps.AcquireX();
+    syncStackPtr();
+    BufferOffset off = immPool64(scratch64, uint64_t(c->raw()));
+    addPendingJump(off, ImmPtr(c->raw()), Relocation::JITCODE);
+    blr(scratch64);
+}
+
 } // namespace jit
 } // namespace js
--- a/js/src/jit/arm64/MacroAssembler-arm64.h
+++ b/js/src/jit/arm64/MacroAssembler-arm64.h
@@ -2701,24 +2701,16 @@ class MacroAssemblerCompat : public vixl
     void handleFailureWithHandlerTail(void* handler);
 
     // FIXME: This is the same on all platforms. Can be common code?
     void makeFrameDescriptor(Register frameSizeReg, FrameType type) {
         lshiftPtr(Imm32(FRAMESIZE_SHIFT), frameSizeReg);
         orPtr(Imm32(type), frameSizeReg);
     }
 
-    void callWithExitFrame(JitCode* target, Register dynStack) {
-        add32(Imm32(framePushed()), dynStack);
-        makeFrameDescriptor(dynStack, JitFrame_IonJS);
-        Push(dynStack); // descriptor
-
-        call(target);
-    }
-
     // FIXME: See CodeGeneratorX64 calls to noteAsmJSGlobalAccess.
     void patchAsmJSGlobalAccess(CodeOffsetLabel patchAt, uint8_t* code,
                                 uint8_t* globalData, unsigned globalDataOffset)
     {
         MOZ_CRASH("patchAsmJSGlobalAccess");
     }
 
     void memIntToValue(const Address& src, const Address& dest) {
@@ -2732,82 +2724,30 @@ class MacroAssemblerCompat : public vixl
 
     void branchPtrInNurseryRange(Condition cond, Register ptr, Register temp, Label* label);
     void branchValueIsNurseryObject(Condition cond, ValueOperand value, Register temp, Label* label);
 
     // Builds an exit frame on the stack, with a return address to an internal
     // non-function. Returns offset to be passed to markSafepointAt().
     void buildFakeExitFrame(Register scratch, uint32_t* offset);
 
-    void callWithExitFrame(Label* target) {
-        uint32_t descriptor = MakeFrameDescriptor(framePushed(), JitFrame_IonJS);
-        Push(Imm32(descriptor)); // descriptor
-
-        call(target);
-    }
-
+    void callWithExitFrame(Label* target);
     void callWithExitFrame(JitCode* target);
+    void callWithExitFrame(JitCode* target, Register dynStack);
 
     void callJit(Register callee) {
         // AArch64 cannot read from the PC, so pushing must be handled callee-side.
         syncStackPtr();
         Blr(ARMRegister(callee, 64));
     }
 
     void appendCallSite(const CallSiteDesc& desc) {
         MOZ_CRASH("appendCallSite");
     }
 
-    void call(const CallSiteDesc& desc, Label* label) {
-        syncStackPtr();
-        call(label);
-        append(desc, currentOffset(), framePushed_);
-    }
-    void call(const CallSiteDesc& desc, Register reg) {
-        syncStackPtr();
-        call(reg);
-        append(desc, currentOffset(), framePushed_);
-    }
-    void call(const CallSiteDesc& desc, AsmJSImmPtr imm) {
-        syncStackPtr();
-        call(imm);
-        append(desc, currentOffset(), framePushed_);
-    }
-
-    void call(AsmJSImmPtr imm) {
-        vixl::UseScratchRegisterScope temps(this);
-        const Register scratch = temps.AcquireX().asUnsized();
-        syncStackPtr();
-        movePtr(imm, scratch);
-        call(scratch);
-    }
-
-    void call(Register target) {
-        syncStackPtr();
-        Blr(ARMRegister(target, 64));
-    }
-    // Call a target JitCode, which must be traceable, and may be movable.
-    void call(JitCode* target) {
-        vixl::UseScratchRegisterScope temps(this);
-        const ARMRegister scratch64 = temps.AcquireX();
-        syncStackPtr();
-        BufferOffset off = immPool64(scratch64, uint64_t(target->raw()));
-        addPendingJump(off, ImmPtr(target->raw()), Relocation::JITCODE);
-        blr(scratch64);
-    }
-    // Call a target native function, which is neither traceable nor movable.
-    void call(ImmPtr target) {
-        syncStackPtr();
-        movePtr(target, ip0);
-        Blr(vixl::ip0);
-    }
-    void call(Label* target) {
-        syncStackPtr();
-        Bl(target);
-    }
     void callExit(AsmJSImmPtr imm, uint32_t stackArgBytes) {
         MOZ_CRASH("callExit");
     }
 
     void callJitFromAsmJS(Register reg) {
         Blr(ARMRegister(reg, 64));
     }
 
--- a/js/src/jit/mips/MacroAssembler-mips.cpp
+++ b/js/src/jit/mips/MacroAssembler-mips.cpp
@@ -3440,42 +3440,42 @@ MacroAssemblerMIPSCompat::callWithABI(vo
     callWithABIPost(stackAdjust, result);
 }
 
 void
 MacroAssemblerMIPSCompat::callWithABI(AsmJSImmPtr imm, MoveOp::Type result)
 {
     uint32_t stackAdjust;
     callWithABIPre(&stackAdjust, /* callFromAsmJS = */ true);
-    call(imm);
+    asMasm().call(imm);
     callWithABIPost(stackAdjust, result);
 }
 
 void
 MacroAssemblerMIPSCompat::callWithABI(const Address& fun, MoveOp::Type result)
 {
     // Load the callee in t9, no instruction between the lw and call
     // should clobber it. Note that we can't use fun.base because it may
     // be one of the IntArg registers clobbered before the call.
     ma_lw(t9, Address(fun.base, fun.offset));
     uint32_t stackAdjust;
     callWithABIPre(&stackAdjust);
-    call(t9);
+    asMasm().call(t9);
     callWithABIPost(stackAdjust, result);
 
 }
 
 void
 MacroAssemblerMIPSCompat::callWithABI(Register fun, MoveOp::Type result)
 {
     // Load the callee in t9, as above.
     ma_move(t9, fun);
     uint32_t stackAdjust;
     callWithABIPre(&stackAdjust);
-    call(t9);
+    asMasm().call(t9);
     callWithABIPost(stackAdjust, result);
 }
 
 void
 MacroAssemblerMIPSCompat::handleFailureWithHandlerTail(void* handler)
 {
     // Reserve space for exception information.
     int size = (sizeof(ResumeFromException) + ABIStackAlignment) & ~(ABIStackAlignment - 1);
@@ -3771,8 +3771,54 @@ MacroAssembler::Pop(const ValueOperand& 
 
 void
 MacroAssembler::reserveStack(uint32_t amount)
 {
     if (amount)
         ma_subu(StackPointer, StackPointer, Imm32(amount));
     adjustFrame(amount);
 }
+
+// ===============================================================
+// Simple call functions.
+
+void
+MacroAssembler::call(Register reg)
+{
+    as_jalr(reg);
+    as_nop();
+}
+
+void
+MacroAssembler::call(Label* label)
+{
+    ma_bal(label);
+}
+
+void
+MacroAssembler::call(AsmJSImmPtr target)
+{
+    movePtr(target, CallReg);
+    call(CallReg);
+}
+
+void
+MacroAssembler::call(ImmWord target)
+{
+    call(ImmPtr((void*)target.value));
+}
+
+void
+MacroAssembler::call(ImmPtr target)
+{
+    BufferOffset bo = m_buffer.nextOffset();
+    addPendingJump(bo, target, Relocation::HARDCODED);
+    ma_call(target);
+}
+
+void
+MacroAssembler::call(JitCode* c)
+{
+    BufferOffset bo = m_buffer.nextOffset();
+    addPendingJump(bo, ImmPtr(c->raw()), Relocation::JITCODE);
+    ma_liPatchable(ScratchRegister, Imm32((uint32_t)c->raw()));
+    ma_callJitHalfPush(ScratchRegister);
+}
--- a/js/src/jit/mips/MacroAssembler-mips.h
+++ b/js/src/jit/mips/MacroAssembler-mips.h
@@ -400,44 +400,16 @@ class MacroAssemblerMIPSCompat : public 
     }
     void mov(Register src, Address dest) {
         MOZ_CRASH("NYI-IC");
     }
     void mov(Address src, Register dest) {
         MOZ_CRASH("NYI-IC");
     }
 
-    void call(const Register reg) {
-        as_jalr(reg);
-        as_nop();
-    }
-
-    void call(Label* label) {
-        ma_bal(label);
-    }
-
-    void call(ImmWord imm) {
-        call(ImmPtr((void*)imm.value));
-    }
-    void call(ImmPtr imm) {
-        BufferOffset bo = m_buffer.nextOffset();
-        addPendingJump(bo, imm, Relocation::HARDCODED);
-        ma_call(imm);
-    }
-    void call(AsmJSImmPtr imm) {
-        movePtr(imm, CallReg);
-        call(CallReg);
-    }
-    void call(JitCode* c) {
-        BufferOffset bo = m_buffer.nextOffset();
-        addPendingJump(bo, ImmPtr(c->raw()), Relocation::JITCODE);
-        ma_liPatchable(ScratchRegister, Imm32((uint32_t)c->raw()));
-        ma_callJitHalfPush(ScratchRegister);
-    }
-
     void callAndPushReturnAddress(Label* label) {
         ma_callJitHalfPush(label);
     }
 
     void branch(JitCode* c) {
         BufferOffset bo = m_buffer.nextOffset();
         addPendingJump(bo, ImmPtr(c->raw()), Relocation::JITCODE);
         ma_liPatchable(ScratchRegister, Imm32((uint32_t)c->raw()));
--- a/js/src/jit/x64/MacroAssembler-x64.cpp
+++ b/js/src/jit/x64/MacroAssembler-x64.cpp
@@ -318,26 +318,26 @@ MacroAssemblerX64::callWithABIPost(uint3
     inCall_ = false;
 }
 
 void
 MacroAssemblerX64::callWithABI(void* fun, MoveOp::Type result)
 {
     uint32_t stackAdjust;
     callWithABIPre(&stackAdjust);
-    call(ImmPtr(fun));
+    asMasm().call(ImmPtr(fun));
     callWithABIPost(stackAdjust, result);
 }
 
 void
 MacroAssemblerX64::callWithABI(AsmJSImmPtr imm, MoveOp::Type result)
 {
     uint32_t stackAdjust;
     callWithABIPre(&stackAdjust);
-    call(imm);
+    asMasm().call(imm);
     callWithABIPost(stackAdjust, result);
 }
 
 static bool
 IsIntArgReg(Register reg)
 {
     for (uint32_t i = 0; i < NumIntArgRegs; i++) {
         if (IntArgRegs[i] == reg)
@@ -356,17 +356,17 @@ MacroAssemblerX64::callWithABI(Address f
         moveResolver_.addMove(MoveOperand(fun.base), MoveOperand(r10), MoveOp::GENERAL);
         fun.base = r10;
     }
 
     MOZ_ASSERT(!IsIntArgReg(fun.base));
 
     uint32_t stackAdjust;
     callWithABIPre(&stackAdjust);
-    call(Operand(fun));
+    asMasm().call(fun);
     callWithABIPost(stackAdjust, result);
 }
 
 void
 MacroAssemblerX64::callWithABI(Register fun, MoveOp::Type result)
 {
     if (IsIntArgReg(fun)) {
         // Callee register may be clobbered for an argument. Move the callee to
@@ -374,17 +374,17 @@ MacroAssemblerX64::callWithABI(Register 
         moveResolver_.addMove(MoveOperand(fun), MoveOperand(r10), MoveOp::GENERAL);
         fun = r10;
     }
 
     MOZ_ASSERT(!IsIntArgReg(fun));
 
     uint32_t stackAdjust;
     callWithABIPre(&stackAdjust);
-    call(Operand(fun));
+    asMasm().call(fun);
     callWithABIPost(stackAdjust, result);
 }
 
 void
 MacroAssemblerX64::handleFailureWithHandlerTail(void* handler)
 {
     // Reserve space for exception information.
     subq(Imm32(sizeof(ResumeFromException)), rsp);
@@ -508,17 +508,17 @@ MacroAssemblerX64::storeUnboxedValue(Con
                                      MIRType slotType);
 
 void
 MacroAssemblerX64::callWithExitFrame(JitCode* target, Register dynStack)
 {
     addPtr(Imm32(asMasm().framePushed()), dynStack);
     makeFrameDescriptor(dynStack, JitFrame_IonJS);
     asMasm().Push(dynStack);
-    call(target);
+    asMasm().call(target);
 }
 
 void
 MacroAssemblerX64::branchPtrInNurseryRange(Condition cond, Register ptr, Register temp, Label* label)
 {
     MOZ_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual);
     MOZ_ASSERT(ptr != temp);
     MOZ_ASSERT(ptr != ScratchReg);
--- a/js/src/jit/x64/MacroAssembler-x64.h
+++ b/js/src/jit/x64/MacroAssembler-x64.h
@@ -84,17 +84,16 @@ class MacroAssemblerX64 : public MacroAs
     SimdMap simdMap_;
 
     void setupABICall(uint32_t arg);
 
   protected:
     MoveResolver moveResolver_;
 
   public:
-    using MacroAssemblerX86Shared::call;
     using MacroAssemblerX86Shared::callWithExitFrame;
     using MacroAssemblerX86Shared::branch32;
     using MacroAssemblerX86Shared::branchTest32;
     using MacroAssemblerX86Shared::load32;
     using MacroAssemblerX86Shared::store32;
 
     MacroAssemblerX64()
       : inCall_(false)
@@ -103,23 +102,16 @@ class MacroAssemblerX64 : public MacroAs
 
     // The buffer is about to be linked, make sure any constant pools or excess
     // bookkeeping has been flushed to the instruction stream.
     void finish();
 
     /////////////////////////////////////////////////////////////////
     // X64 helpers.
     /////////////////////////////////////////////////////////////////
-    void call(ImmWord target) {
-        mov(target, rax);
-        call(rax);
-    }
-    void call(ImmPtr target) {
-        call(ImmWord(uintptr_t(target.value)));
-    }
     void writeDataRelocation(const Value& val) {
         if (val.isMarkable()) {
             gc::Cell* cell = reinterpret_cast<gc::Cell*>(val.toGCThing());
             if (cell && gc::IsInsideNursery(cell))
                 embedsNurseryPointers_ = true;
             dataRelocations_.writeUnsigned(masm.currentOffset());
         }
     }
--- a/js/src/jit/x64/SharedICHelpers-x64.h
+++ b/js/src/jit/x64/SharedICHelpers-x64.h
@@ -37,17 +37,17 @@ EmitCallIC(CodeOffsetLabel* patchOffset,
     CodeOffsetLabel offset = masm.movWithPatch(ImmWord(-1), ICStubReg);
     *patchOffset = offset;
 
     // Load stub pointer into ICStubReg
     masm.loadPtr(Address(ICStubReg, (int32_t) ICEntry::offsetOfFirstStub()),
                  ICStubReg);
 
     // Call the stubcode.
-    masm.call(Operand(ICStubReg, ICStub::offsetOfStubCode()));
+    masm.call(Address(ICStubReg, ICStub::offsetOfStubCode()));
 }
 
 inline void
 EmitEnterTypeMonitorIC(MacroAssembler& masm,
                        size_t monitorStubOffset = ICMonitoredStub::offsetOfFirstMonitorStub())
 {
     // This is expected to be called from within an IC, when ICStubReg
     // is properly initialized to point to the stub.
@@ -225,17 +225,17 @@ EmitCallTypeUpdateIC(MacroAssembler& mas
     masm.push(ICStubReg);
 
     // This is expected to be called from within an IC, when ICStubReg
     // is properly initialized to point to the stub.
     masm.loadPtr(Address(ICStubReg, (int32_t) ICUpdatedStub::offsetOfFirstUpdateStub()),
                  ICStubReg);
 
     // Call the stubcode.
-    masm.call(Operand(ICStubReg, ICStub::offsetOfStubCode()));
+    masm.call(Address(ICStubReg, ICStub::offsetOfStubCode()));
 
     // Restore the old stub reg.
     masm.pop(ICStubReg);
 
     // The update IC will store 0 or 1 in R1.scratchReg() reflecting if the
     // value in R0 type-checked properly or not.
     Label success;
     masm.cmp32(R1.scratchReg(), Imm32(1));
--- a/js/src/jit/x86-shared/MacroAssembler-x86-shared.cpp
+++ b/js/src/jit/x86-shared/MacroAssembler-x86-shared.cpp
@@ -160,16 +160,34 @@ MacroAssemblerX86Shared::branchNegativeZ
                                                    Register scratch,
                                                    Label* label)
 {
     vmovd(reg, scratch);
     cmp32(scratch, Imm32(1));
     j(Overflow, label);
 }
 
+void
+MacroAssemblerX86Shared::callJit(Register callee)
+{
+    call(callee);
+}
+
+void
+MacroAssemblerX86Shared::callJitFromAsmJS(Register callee)
+{
+    call(callee);
+}
+
+void
+MacroAssemblerX86Shared::callAndPushReturnAddress(Label* label)
+{
+    call(label);
+}
+
 MacroAssembler&
 MacroAssemblerX86Shared::asMasm()
 {
     return *static_cast<MacroAssembler*>(this);
 }
 
 const MacroAssembler&
 MacroAssemblerX86Shared::asMasm() const
@@ -345,8 +363,55 @@ MacroAssembler::Pop(FloatRegister reg)
 }
 
 void
 MacroAssembler::Pop(const ValueOperand& val)
 {
     popValue(val);
     framePushed_ -= sizeof(Value);
 }
+
+// ===============================================================
+// Simple call functions.
+
+void
+MacroAssembler::call(Register reg)
+{
+    Assembler::call(reg);
+}
+
+void
+MacroAssembler::call(Label* label)
+{
+    Assembler::call(label);
+}
+
+void
+MacroAssembler::call(const Address& addr)
+{
+    Assembler::call(Operand(addr.base, addr.offset));
+}
+
+void
+MacroAssembler::call(AsmJSImmPtr target)
+{
+    mov(target, eax);
+    Assembler::call(eax);
+}
+
+void
+MacroAssembler::call(ImmWord target)
+{
+    mov(target, eax);
+    Assembler::call(eax);
+}
+
+void
+MacroAssembler::call(ImmPtr target)
+{
+    call(ImmWord(uintptr_t(target.value)));
+}
+
+void
+MacroAssembler::call(JitCode* target)
+{
+    Assembler::call(target);
+}
--- a/js/src/jit/x86-shared/MacroAssembler-x86-shared.h
+++ b/js/src/jit/x86-shared/MacroAssembler-x86-shared.h
@@ -1428,29 +1428,19 @@ class MacroAssemblerX86Shared : public A
     }
 
     // Builds an exit frame on the stack, with a return address to an internal
     // non-function. Returns offset to be passed to markSafepointAt().
     void buildFakeExitFrame(Register scratch, uint32_t* offset);
     void callWithExitFrame(Label* target);
     void callWithExitFrame(JitCode* target);
 
-    void callJit(Register callee) {
-        call(callee);
-    }
-    void callJitFromAsmJS(Register callee) {
-        call(callee);
-    }
-    void call(AsmJSImmPtr target) {
-        mov(target, eax);
-        call(eax);
-    }
-    void callAndPushReturnAddress(Label* label) {
-        call(label);
-    }
+    void callJit(Register callee);
+    void callJitFromAsmJS(Register callee);
+    void callAndPushReturnAddress(Label* label);
 
     void checkStackAlignment() {
         // Exists for ARM compatibility.
     }
 
     CodeOffsetLabel labelForPatch() {
         return CodeOffsetLabel(size());
     }
--- a/js/src/jit/x86/MacroAssembler-x86.cpp
+++ b/js/src/jit/x86/MacroAssembler-x86.cpp
@@ -323,44 +323,44 @@ MacroAssemblerX86::callWithABIPost(uint3
     inCall_ = false;
 }
 
 void
 MacroAssemblerX86::callWithABI(void* fun, MoveOp::Type result)
 {
     uint32_t stackAdjust;
     callWithABIPre(&stackAdjust);
-    call(ImmPtr(fun));
+    asMasm().call(ImmPtr(fun));
     callWithABIPost(stackAdjust, result);
 }
 
 void
 MacroAssemblerX86::callWithABI(AsmJSImmPtr fun, MoveOp::Type result)
 {
     uint32_t stackAdjust;
     callWithABIPre(&stackAdjust);
-    call(fun);
+    asMasm().call(fun);
     callWithABIPost(stackAdjust, result);
 }
 
 void
 MacroAssemblerX86::callWithABI(const Address& fun, MoveOp::Type result)
 {
     uint32_t stackAdjust;
     callWithABIPre(&stackAdjust);
-    call(Operand(fun));
+    asMasm().call(fun);
     callWithABIPost(stackAdjust, result);
 }
 
 void
 MacroAssemblerX86::callWithABI(Register fun, MoveOp::Type result)
 {
     uint32_t stackAdjust;
     callWithABIPre(&stackAdjust);
-    call(Operand(fun));
+    asMasm().call(fun);
     callWithABIPost(stackAdjust, result);
 }
 
 void
 MacroAssemblerX86::handleFailureWithHandlerTail(void* handler)
 {
     // Reserve space for exception information.
     subl(Imm32(sizeof(ResumeFromException)), esp);
@@ -501,17 +501,17 @@ MacroAssemblerX86::storeUnboxedValue(Con
                                      MIRType slotType);
 
 void
 MacroAssemblerX86::callWithExitFrame(JitCode* target, Register dynStack)
 {
     addPtr(ImmWord(asMasm().framePushed()), dynStack);
     makeFrameDescriptor(dynStack, JitFrame_IonJS);
     asMasm().Push(dynStack);
-    call(target);
+    asMasm().call(target);
 }
 
 void
 MacroAssemblerX86::branchPtrInNurseryRange(Condition cond, Register ptr, Register temp,
                                            Label* label)
 {
     MOZ_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual);
     MOZ_ASSERT(ptr != temp);
--- a/js/src/jit/x86/SharedICHelpers-x86.h
+++ b/js/src/jit/x86/SharedICHelpers-x86.h
@@ -38,17 +38,17 @@ EmitCallIC(CodeOffsetLabel* patchOffset,
     *patchOffset = offset;
 
     // Load stub pointer into ICStubReg
     masm.loadPtr(Address(ICStubReg, (int32_t) ICEntry::offsetOfFirstStub()),
                  ICStubReg);
 
     // Load stubcode pointer from BaselineStubEntry into ICTailCallReg
     // ICTailCallReg will always be unused in the contexts where ICs are called.
-    masm.call(Operand(ICStubReg, ICStub::offsetOfStubCode()));
+    masm.call(Address(ICStubReg, ICStub::offsetOfStubCode()));
 }
 
 inline void
 EmitEnterTypeMonitorIC(MacroAssembler& masm,
                        size_t monitorStubOffset = ICMonitoredStub::offsetOfFirstMonitorStub())
 {
     // This is expected to be called from within an IC, when ICStubReg
     // is properly initialized to point to the stub.
@@ -231,17 +231,17 @@ EmitCallTypeUpdateIC(MacroAssembler& mas
     masm.push(ICStubReg);
 
     // This is expected to be called from within an IC, when ICStubReg
     // is properly initialized to point to the stub.
     masm.loadPtr(Address(ICStubReg, (int32_t) ICUpdatedStub::offsetOfFirstUpdateStub()),
                  ICStubReg);
 
     // Call the stubcode.
-    masm.call(Operand(ICStubReg, ICStub::offsetOfStubCode()));
+    masm.call(Address(ICStubReg, ICStub::offsetOfStubCode()));
 
     // Restore the old stub reg.
     masm.pop(ICStubReg);
 
     // The update IC will store 0 or 1 in R1.scratchReg() reflecting if the
     // value in R0 type-checked properly or not.
     Label success;
     masm.cmp32(R1.scratchReg(), Imm32(1));
--- a/js/src/jit/x86/Trampoline-x86.cpp
+++ b/js/src/jit/x86/Trampoline-x86.cpp
@@ -269,17 +269,17 @@ JitRuntime::generateEnterJIT(JSContext* 
     // The call will push the return address on the stack, thus we check that
     // the stack would be aligned once the call is complete.
     masm.assertStackAlignment(JitStackAlignment, sizeof(uintptr_t));
 
     /***************************************************************
         Call passed-in code, get return value and fill in the
         passed in return value pointer
     ***************************************************************/
-    masm.call(Operand(ebp, ARG_JITCODE));
+    masm.call(Address(ebp, ARG_JITCODE));
 
     if (type == EnterJitBaseline) {
         // Baseline OSR will return here.
         masm.bind(returnLabel.src());
         masm.addCodeLabel(returnLabel);
     }
 
     // Pop arguments off the stack.
--- a/js/src/vm/SharedTypedArrayObject.cpp
+++ b/js/src/vm/SharedTypedArrayObject.cpp
@@ -2,16 +2,17 @@
  * 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/. */
 
 #include "vm/SharedTypedArrayObject.h"
 
 #include "mozilla/Alignment.h"
+#include "mozilla/Attributes.h"
 #include "mozilla/PodOperations.h"
 
 #include <string.h>
 #ifndef XP_WIN
 # include <sys/mman.h>
 #endif
 
 #include "jsapi.h"
@@ -92,17 +93,17 @@ class SharedTypedArrayObjectTemplate : p
     // This is the max value of 'byteOffset': one below the length.
     static const uint32_t MAX_BYTEOFFSET = MAX_LENGTH - 1;
 
   public:
     typedef NativeType ElementType;
     typedef SharedTypedArrayObjectTemplate<NativeType> ThisTypedArrayObject;
     typedef SharedArrayBufferObject BufferType;
 
-    static Scalar::Type ArrayTypeID() { return TypeIDOfType<NativeType>(); }
+    static MOZ_CONSTEXPR Scalar::Type ArrayTypeID() { return TypeIDOfType<NativeType>::id; }
     static bool ArrayTypeIsUnsigned() { return TypeIsUnsigned<NativeType>(); }
     static bool ArrayTypeIsFloatingPoint() { return TypeIsFloatingPoint<NativeType>(); }
 
     static const size_t BYTES_PER_ELEMENT = sizeof(ElementType);
 
     static inline const Class* protoClass()
     {
         return &SharedTypedArrayObject::protoClasses[ArrayTypeID()];
--- a/js/src/vm/StructuredClone.cpp
+++ b/js/src/vm/StructuredClone.cpp
@@ -1979,27 +1979,33 @@ JSAutoStructuredCloneBuffer::operator=(J
     MOZ_ASSERT(&other != this);
     clear();
     ownTransferables_ = other.ownTransferables_;
     other.steal(&data_, &nbytes_, &version_);
     return *this;
 }
 
 void
-JSAutoStructuredCloneBuffer::clear()
+JSAutoStructuredCloneBuffer::clear(const JSStructuredCloneCallbacks* optionalCallbacks,
+                                   void* optionalClosure)
 {
-    if (data_) {
-        if (ownTransferables_ == OwnsTransferablesIfAny)
-            DiscardTransferables(data_, nbytes_, callbacks_, closure_);
-        ownTransferables_ = NoTransferables;
-        js_free(data_);
-        data_ = nullptr;
-        nbytes_ = 0;
-        version_ = 0;
-    }
+    if (!data_)
+        return;
+
+    const JSStructuredCloneCallbacks* callbacks =
+        optionalCallbacks ?  optionalCallbacks : callbacks_;
+    void* closure = optionalClosure ?  optionalClosure : closure_;
+
+    if (ownTransferables_ == OwnsTransferablesIfAny)
+        DiscardTransferables(data_, nbytes_, callbacks, closure);
+    ownTransferables_ = NoTransferables;
+    js_free(data_);
+    data_ = nullptr;
+    nbytes_ = 0;
+    version_ = 0;
 }
 
 bool
 JSAutoStructuredCloneBuffer::copy(const uint64_t* srcData, size_t nbytes, uint32_t version)
 {
     // transferable objects cannot be copied
     if (StructuredCloneHasTransferObjects(data_, nbytes_))
         return false;
--- a/js/src/vm/TypedArrayCommon.h
+++ b/js/src/vm/TypedArrayCommon.h
@@ -51,26 +51,26 @@ ValueIsLength(const Value& v, uint32_t* 
 
         *len = length;
         return true;
     }
 
     return false;
 }
 
-template<typename NativeType> static inline Scalar::Type TypeIDOfType();
-template<> inline Scalar::Type TypeIDOfType<int8_t>() { return Scalar::Int8; }
-template<> inline Scalar::Type TypeIDOfType<uint8_t>() { return Scalar::Uint8; }
-template<> inline Scalar::Type TypeIDOfType<int16_t>() { return Scalar::Int16; }
-template<> inline Scalar::Type TypeIDOfType<uint16_t>() { return Scalar::Uint16; }
-template<> inline Scalar::Type TypeIDOfType<int32_t>() { return Scalar::Int32; }
-template<> inline Scalar::Type TypeIDOfType<uint32_t>() { return Scalar::Uint32; }
-template<> inline Scalar::Type TypeIDOfType<float>() { return Scalar::Float32; }
-template<> inline Scalar::Type TypeIDOfType<double>() { return Scalar::Float64; }
-template<> inline Scalar::Type TypeIDOfType<uint8_clamped>() { return Scalar::Uint8Clamped; }
+template<typename NativeType> struct TypeIDOfType;
+template<> struct TypeIDOfType<int8_t> { static const Scalar::Type id = Scalar::Int8; };
+template<> struct TypeIDOfType<uint8_t> { static const Scalar::Type id = Scalar::Uint8; };
+template<> struct TypeIDOfType<int16_t> { static const Scalar::Type id = Scalar::Int16; };
+template<> struct TypeIDOfType<uint16_t> { static const Scalar::Type id = Scalar::Uint16; };
+template<> struct TypeIDOfType<int32_t> { static const Scalar::Type id = Scalar::Int32; };
+template<> struct TypeIDOfType<uint32_t> { static const Scalar::Type id = Scalar::Uint32; };
+template<> struct TypeIDOfType<float> { static const Scalar::Type id = Scalar::Float32; };
+template<> struct TypeIDOfType<double> { static const Scalar::Type id = Scalar::Float64; };
+template<> struct TypeIDOfType<uint8_clamped> { static const Scalar::Type id = Scalar::Uint8Clamped; };
 
 inline bool
 IsAnyTypedArray(JSObject* obj)
 {
     return obj->is<TypedArrayObject>() || obj->is<SharedTypedArrayObject>();
 }
 
 inline uint32_t
--- a/js/src/vm/TypedArrayObject.cpp
+++ b/js/src/vm/TypedArrayObject.cpp
@@ -63,25 +63,16 @@ using JS::ToUint32;
  * the subclasses.
  */
 
 TypedArrayLayout TypedArrayObject::layout_(false, // shared
                                            true,  // neuterable
                                            &TypedArrayObject::classes[0],
                                            &TypedArrayObject::classes[Scalar::MaxTypedArrayViewType]);
 
-TypedArrayLayout::TypedArrayLayout(bool isShared, bool isNeuterable, const Class* firstClass,
-                                   const Class* maxClass)
-    : isShared_(isShared)
-    , isNeuterable_(isNeuterable)
-    , firstClass_(firstClass)
-    , maxClass_(maxClass)
-{
-}
-
 /* static */ int
 TypedArrayLayout::lengthOffset()
 {
     return NativeObject::getFixedSlotOffset(LENGTH_SLOT);
 }
 
 /* static */ int
 TypedArrayLayout::dataOffset()
@@ -201,17 +192,17 @@ namespace {
 template<typename NativeType>
 class TypedArrayObjectTemplate : public TypedArrayObject
 {
     friend class TypedArrayObject;
 
   public:
     typedef NativeType ElementType;
 
-    static Scalar::Type ArrayTypeID() { return TypeIDOfType<NativeType>(); }
+    static MOZ_CONSTEXPR Scalar::Type ArrayTypeID() { return TypeIDOfType<NativeType>::id; }
     static bool ArrayTypeIsUnsigned() { return TypeIsUnsigned<NativeType>(); }
     static bool ArrayTypeIsFloatingPoint() { return TypeIsFloatingPoint<NativeType>(); }
 
     static const size_t BYTES_PER_ELEMENT = sizeof(NativeType);
 
     static JSObject*
     createPrototype(JSContext* cx, JSProtoKey key)
     {
--- a/js/src/vm/TypedArrayObject.h
+++ b/js/src/vm/TypedArrayObject.h
@@ -2,16 +2,18 @@
  * 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 vm_TypedArrayObject_h
 #define vm_TypedArrayObject_h
 
+#include "mozilla/Attributes.h"
+
 #include "jsobj.h"
 
 #include "gc/Barrier.h"
 #include "js/Class.h"
 #include "vm/ArrayBufferObject.h"
 
 typedef struct JSProperty JSProperty;
 
@@ -38,17 +40,23 @@ namespace js {
 class TypedArrayLayout
 {
     const bool isShared_;
     const bool isNeuterable_;
     const Class* firstClass_;
     const Class* maxClass_;
 
   public:
-    TypedArrayLayout(bool isShared, bool isNeuterable, const Class* firstClass, const Class* maxClass);
+    MOZ_CONSTEXPR TypedArrayLayout(bool isShared, bool isNeuterable,
+                                   const Class* firstClass, const Class* maxClass)
+        : isShared_(isShared)
+        , isNeuterable_(isNeuterable)
+        , firstClass_(firstClass)
+        , maxClass_(maxClass)
+    {}
 
     // Underlying (Shared)ArrayBufferObject.
     static const size_t BUFFER_SLOT = 0;
     static_assert(BUFFER_SLOT == JS_TYPEDARRAYLAYOUT_BUFFER_SLOT,
                   "self-hosted code with burned-in constants must get the "
                   "right buffer slot");
 
     // Slot containing length of the view in number of typed elements.
--- a/layout/style/FontFaceSet.cpp
+++ b/layout/style/FontFaceSet.cpp
@@ -1780,8 +1780,11 @@ FontFaceSet::UserFontSet::CreateUserFont
                                uint32_t aLanguageOverride,
                                gfxSparseBitSet* aUnicodeRanges)
 {
   nsRefPtr<gfxUserFontEntry> entry =
     new FontFace::Entry(this, aFontFaceSrcList, aWeight, aStretch, aItalicStyle,
                         aFeatureSettings, aLanguageOverride, aUnicodeRanges);
   return entry.forget();
 }
+
+#undef LOG_ENABLED
+#undef LOG
--- a/layout/style/moz.build
+++ b/layout/style/moz.build
@@ -121,16 +121,17 @@ UNIFIED_SOURCES += [
     'CSSRuleList.cpp',
     'CSSStyleSheet.cpp',
     'CSSVariableDeclarations.cpp',
     'CSSVariableResolver.cpp',
     'CSSVariableValues.cpp',
     'Declaration.cpp',
     'ErrorReporter.cpp',
     'FontFace.cpp',
+    'FontFaceSet.cpp',
     'FontFaceSetIterator.cpp',
     'ImageLoader.cpp',
     'IncrementalClearCOMRuleArray.cpp',
     'Loader.cpp',
     'MediaQueryList.cpp',
     'nsAnimationManager.cpp',
     'nsComputedDOMStyle.cpp',
     'nsCSSAnonBoxes.cpp',
@@ -167,20 +168,18 @@ UNIFIED_SOURCES += [
     'nsTransitionManager.cpp',
     'RuleNodeCacheConditions.cpp',
     'RuleProcessorCache.cpp',
     'StyleAnimationValue.cpp',
     'StyleRule.cpp',
     'SVGAttrAnimationRuleProcessor.cpp',
 ]
 
-# FontFaceSet.cpp needs to be built separately because it redefines LOG.
 # nsCSSRuleProcessor.cpp needs to be built separately because it uses plarena.h.
 SOURCES += [
-    'FontFaceSet.cpp',
     'nsCSSRuleProcessor.cpp',
 ]
 
 EXTRA_COMPONENTS += [
     'CSSUnprefixingService.js',
     'CSSUnprefixingService.manifest',
 ]
 
--- a/mobile/android/chrome/content/WebappRT.js
+++ b/mobile/android/chrome/content/WebappRT.js
@@ -30,16 +30,17 @@ let WebappRT = {
     pref("extensions.enabledScopes", 1),
     // Auto-disable any add-ons that are "dropped in" to the profile
     pref("extensions.autoDisableScopes", 1),
     // Disable add-on installation via the web-exposed APIs
     pref("xpinstall.enabled", false),
     // Set a future policy version to avoid the telemetry prompt.
     pref("toolkit.telemetry.prompted", 999),
     pref("toolkit.telemetry.notifiedOptOut", 999),
+    pref("media.useAudioChannelAPI", true),
     pref("media.useAudioChannelService", true),
     pref("dom.mozTCPSocket.enabled", true),
 
     // Enabled system messages for web activity support
     pref("dom.sysmsg.enabled", true),
   ],
 
   init: function(aStatus, aUrl, aCallback) {
--- a/widget/android/nsWindow.cpp
+++ b/widget/android/nsWindow.cpp
@@ -177,17 +177,19 @@ nsWindow::DumpWindows(const nsTArray<nsW
 
 nsWindow::nsWindow() :
     mIsVisible(false),
     mParent(nullptr),
     mIMEMaskSelectionUpdate(false),
     mIMEMaskEventsCount(1), // Mask IME events since there's no focus yet
     mIMERanges(new TextRangeArray()),
     mIMEUpdatingContext(false),
-    mIMESelectionChanged(false)
+    mIMESelectionChanged(false),
+    mAwaitingFullScreen(false),
+    mIsFullScreen(false)
 {
 }
 
 nsWindow::~nsWindow()
 {
     gTopLevelWindows.RemoveElement(this);
     ALOG("nsWindow %p destructor", (void*)this);
     if (mLayerManager == sLayerManager) {
@@ -489,16 +491,22 @@ nsWindow::Resize(double aX,
 
     if (needSizeDispatch)
         OnSizeChanged(gfxIntSize(aWidth, aHeight));
 
     // Should we skip honoring aRepaint here?
     if (aRepaint && FindTopLevel() == nsWindow::TopWindow())
         RedrawAll();
 
+    nsIWidgetListener* listener = GetWidgetListener();
+    if (mAwaitingFullScreen && listener) {
+      listener->FullscreenChanged(mIsFullScreen);
+      mAwaitingFullScreen = false;
+    }
+
     return NS_OK;
 }
 
 void
 nsWindow::SetZIndex(int32_t aZIndex)
 {
     ALOG("nsWindow[%p]::SetZIndex %d ignored", (void*)this, aZIndex);
 }
@@ -625,17 +633,17 @@ NS_IMETHODIMP
 nsWindow::GetScreenBounds(nsIntRect &aRect)
 {
     LayoutDeviceIntPoint p = WidgetToScreenOffset();
 
     aRect.x = p.x;
     aRect.y = p.y;
     aRect.width = mBounds.width;
     aRect.height = mBounds.height;
-    
+
     return NS_OK;
 }
 
 LayoutDeviceIntPoint
 nsWindow::WidgetToScreenOffset()
 {
     LayoutDeviceIntPoint p(0, 0);
     nsWindow *w = this;
@@ -667,16 +675,18 @@ nsWindow::DispatchEvent(WidgetGUIEvent* 
         return mWidgetListener->HandleEvent(aEvent, mUseAttachedEvents);
     }
     return nsEventStatus_eIgnore;
 }
 
 NS_IMETHODIMP
 nsWindow::MakeFullScreen(bool aFullScreen, nsIScreen*)
 {
+    mIsFullScreen = aFullScreen;
+    mAwaitingFullScreen = true;
     GeckoAppShell::SetFullScreen(aFullScreen);
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsWindow::SetWindowClass(const nsAString& xulWinType)
 {
     return NS_OK;
@@ -2105,17 +2115,17 @@ nsWindow::SetInputContext(const InputCon
     }
 
     ALOGIME("IME: SetInputContext: s=0x%X, 0x%X, action=0x%X, 0x%X",
             aContext.mIMEState.mEnabled, aContext.mIMEState.mOpen,
             aAction.mCause, aAction.mFocusChange);
 
     // Ensure that opening the virtual keyboard is allowed for this specific
     // InputContext depending on the content.ime.strict.policy pref
-    if (aContext.mIMEState.mEnabled != IMEState::DISABLED && 
+    if (aContext.mIMEState.mEnabled != IMEState::DISABLED &&
         aContext.mIMEState.mEnabled != IMEState::PLUGIN &&
         Preferences::GetBool("content.ime.strict_policy", false) &&
         !aAction.ContentGotFocusByTrustedCause() &&
         !aAction.UserMightRequestOpenVKB()) {
         return;
     }
 
     IMEState::Enabled enabled = aContext.mIMEState.mEnabled;
--- a/widget/android/nsWindow.h
+++ b/widget/android/nsWindow.h
@@ -226,16 +226,19 @@ protected:
     bool mIMEMaskSelectionUpdate;
     int32_t mIMEMaskEventsCount; // Mask events when > 0
     nsRefPtr<mozilla::TextRangeArray> mIMERanges;
     bool mIMEUpdatingContext;
     nsAutoTArray<mozilla::AndroidGeckoEvent, 8> mIMEKeyEvents;
     nsAutoTArray<IMEChange, 4> mIMETextChanges;
     bool mIMESelectionChanged;
 
+    bool mAwaitingFullScreen;
+    bool mIsFullScreen;
+
     InputContext mInputContext;
 
     virtual nsresult NotifyIMEInternal(
                          const IMENotification& aIMENotification) override;
 
     static void DumpWindows();
     static void DumpWindows(const nsTArray<nsWindow*>& wins, int indent = 0);
     static void LogWindow(nsWindow *win, int index, int indent);