Merge mozilla-inbound to mozilla-central. a=merge
authorAndreea Pavel <apavel@mozilla.com>
Tue, 20 Mar 2018 00:39:56 +0200
changeset 408884 bfb7edfd0436db388bb9e103b8ad817fc50bfdcf
parent 408815 48f43d2ad95ec075addce039f7fe7dcd8edbaf61 (current diff)
parent 408883 6b72f16720e50fe7f94c22ec344a3c6510660264 (diff)
child 408904 016a2d814c5a3f7440371134846bd0f78f213175
child 408926 12394cdb5c107bdb0841fce97d53340a9c086484
push id33663
push userapavel@mozilla.com
push dateMon, 19 Mar 2018 22:40:21 +0000
treeherdermozilla-central@bfb7edfd0436 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone61.0a1
first release with
nightly linux32
bfb7edfd0436 / 61.0a1 / 20180320100122 / files
nightly linux64
bfb7edfd0436 / 61.0a1 / 20180320100122 / files
nightly mac
bfb7edfd0436 / 61.0a1 / 20180320100122 / files
nightly win32
bfb7edfd0436 / 61.0a1 / 20180320100122 / files
nightly win64
bfb7edfd0436 / 61.0a1 / 20180320100122 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge mozilla-inbound to mozilla-central. a=merge
browser/base/content/browser.js
browser/base/content/tabbrowser.xml
dom/base/ShadowRoot.cpp
dom/base/nsGenericDOMDataNode.cpp
dom/base/nsGenericDOMDataNode.h
dom/interfaces/core/nsIDOMCharacterData.idl
dom/interfaces/core/nsIDOMComment.idl
dom/interfaces/core/nsIDOMProcessingInstruction.idl
dom/interfaces/core/nsIDOMText.idl
dom/interfaces/events/nsIDOMFocusEvent.idl
dom/interfaces/events/nsIDOMMouseScrollEvent.idl
dom/interfaces/events/nsIDOMScrollAreaEvent.idl
dom/interfaces/xul/nsIDOMXULCommandEvent.idl
editor/libeditor/HTMLAnonymousNodeEditor.cpp
media/libtheora/bug703135.patch
modules/libpref/init/all.js
toolkit/components/telemetry/Histograms.json
new file mode 100644
--- /dev/null
+++ b/accessible/atk/DOMtoATK.cpp
@@ -0,0 +1,161 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "DOMtoATK.h"
+#include "nsUTF8Utils.h"
+
+namespace mozilla {
+namespace a11y {
+
+namespace DOMtoATK {
+
+void
+AddBOMs(nsACString& aDest, const nsACString& aSource)
+{
+  uint32_t destlength = 0;
+
+  // First compute how much room we will need.
+  for (uint32_t srci = 0; srci < aSource.Length(); ) {
+    int bytes = UTF8traits::bytes(aSource[srci]);
+    if (bytes >= 4) {
+      // Non-BMP character, will add a BOM after it.
+      destlength += 3;
+    }
+    // Skip whole character encoding.
+    srci += bytes;
+    destlength += bytes;
+  }
+
+  uint32_t desti = 0; // Index within aDest.
+
+  // Add BOMs after non-BMP characters.
+  aDest.SetLength(destlength);
+  for (uint32_t srci = 0; srci < aSource.Length(); ) {
+    uint32_t bytes = UTF8traits::bytes(aSource[srci]);
+
+    MOZ_ASSERT(bytes <= aSource.Length() - srci, "We should have the whole sequence");
+
+    // Copy whole sequence.
+    aDest.Replace(desti, bytes, Substring(aSource, srci, bytes));
+    desti += bytes;
+    srci += bytes;
+
+    if (bytes >= 4) {
+      // More than 4 bytes in UTF-8 encoding exactly means more than 16 encoded
+      // bits.  This is thus a non-BMP character which needed a surrogate
+      // pair to get encoded in UTF-16, add a BOM after it.
+
+      // And add a BOM after it.
+      aDest.Replace(desti, 3, "\xEF\xBB\xBF");
+      desti += 3;
+    }
+  }
+  MOZ_ASSERT(desti == destlength, "Incoherency between computed length"
+                                  "and actually translated length");
+}
+
+void
+ATKStringConverterHelper::AdjustOffsets(gint* aStartOffset, gint* aEndOffset,
+                                        gint count)
+{
+  MOZ_ASSERT(!mAdjusted, "DOMtoATK::ATKStringConverterHelper::AdjustOffsets needs to be called only once");
+
+  if (*aStartOffset > 0) {
+    (*aStartOffset)--;
+    mStartShifted = true;
+  }
+
+  if (*aEndOffset != -1 && *aEndOffset < count) {
+    (*aEndOffset)++;
+    mEndShifted = true;
+  }
+
+#ifdef DEBUG
+  mAdjusted = true;
+#endif
+}
+
+gchar*
+ATKStringConverterHelper::FinishUTF16toUTF8(nsCString& aStr)
+{
+  int skip = 0;
+
+  if (mStartShifted) {
+    // AdjustOffsets added a leading character.
+
+    MOZ_ASSERT(aStr.Length() > 0, "There should be a leading character");
+    MOZ_ASSERT(static_cast<int>(aStr.Length()) >= UTF8traits::bytes(aStr.CharAt(0)),
+               "The leading character should be complete");
+
+    // drop first character
+    skip = UTF8traits::bytes(aStr.CharAt(0));
+  }
+
+  if (mEndShifted) {
+    // AdjustOffsets added a trailing character.
+
+    MOZ_ASSERT(aStr.Length() > 0, "There should be a trailing character");
+
+    int trail = -1;
+    // Find beginning of last character.
+    for (trail = aStr.Length() - 1; trail >= 0; trail--) {
+      if (!UTF8traits::isInSeq(aStr.CharAt(trail))) {
+        break;
+      }
+    }
+    MOZ_ASSERT(trail >= 0,
+               "There should be at least a whole trailing character");
+    MOZ_ASSERT(trail + UTF8traits::bytes(aStr.CharAt(trail)) == static_cast<int>(aStr.Length()),
+               "The trailing character should be complete");
+
+    // Drop the last character.
+    aStr.Truncate(trail);
+  }
+
+  // copy and return, libspi will free it
+  return g_strdup(aStr.get() + skip);
+}
+
+gchar*
+ATKStringConverterHelper::ConvertAdjusted(const nsAString& aStr)
+{
+  MOZ_ASSERT(mAdjusted, "DOMtoATK::ATKStringConverterHelper::AdjustOffsets needs to be called before ATKStringConverterHelper::ConvertAdjusted");
+
+  NS_ConvertUTF16toUTF8 cautoStr(aStr);
+  if (!cautoStr.get()) {
+    return nullptr;
+  }
+
+  nsAutoCString cautoStrBOMs;
+  AddBOMs(cautoStrBOMs, cautoStr);
+  return FinishUTF16toUTF8(cautoStrBOMs);
+}
+
+gchar*
+Convert(const nsAString& aStr)
+{
+  NS_ConvertUTF16toUTF8 cautoStr(aStr);
+  if (!cautoStr.get()) {
+    return nullptr;
+  }
+
+  nsAutoCString cautoStrBOMs;
+  AddBOMs(cautoStrBOMs, cautoStr);
+  return g_strdup(cautoStrBOMs.get());
+}
+
+void
+ConvertTexttoAsterisks(nsAString& aString)
+{
+  for (uint32_t i = 0; i < aString.Length(); i++) {
+    aString.ReplaceLiteral(i, 1, u"*");
+  }
+}
+
+}
+
+} // namespace a11y
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/accessible/atk/DOMtoATK.h
@@ -0,0 +1,163 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "AccessibleWrap.h"
+#include "nsString.h"
+#include "nsMai.h"
+
+/**
+ * ATK offsets are counted in unicode codepoints, while DOM offsets are counted
+ * in UTF-16 code units.  That makes a difference for non-BMP characters,
+ * which need two UTF-16 code units to be represented (a pair of surrogates),
+ * while they are just one unicode character.
+ *
+ * To keep synchronization between ATK offsets (unicode codepoints) and DOM
+ * offsets (UTF-16 code units), after translation from UTF-16 to UTF-8 we add a
+ * BOM after each non-BMP character (which would otherwise use 2 UTF-16
+ * code units for only 1 unicode codepoint).
+ *
+ * BOMs (Byte Order Marks, U+FEFF, also known as ZERO WIDTH NO-BREAK SPACE, but
+ * that usage is deprecated) normally only appear at the beginning of unicode
+ * files, but their occurrence within text (notably after cut&paste) is not
+ * uncommon, and are thus considered as non-text.
+ *
+ * Since the selection requested through ATK may not contain both surrogates
+ * at the ends of the selection, we need to fetch one UTF-16 code point more
+ * on both side, and get rid of it before returning the string to ATK. The
+ * ATKStringConverterHelper class maintains this, NewATKString should be used
+ * to call it properly.
+ *
+ * In the end,
+ * - if the start is between the high and low surrogates, the UTF-8 result
+ * includes a BOM from it but not the character
+ * - if the end is between the high and low surrogates, the UTF-8 result
+ * includes the character but *not* the BOM
+ * - all non-BMP characters that are fully in the string are in the UTF-8 result
+ * as character followed by BOM
+ */
+namespace mozilla {
+namespace a11y {
+
+namespace DOMtoATK
+{
+
+  /**
+   * Converts a string of accessible text into ATK gchar* string (by adding
+   * BOMs). This can be used when offsets do not need to be adjusted because
+   * ends of the string can not fall between surrogates.
+   */
+  gchar* Convert(const nsAString& aStr);
+
+  /**
+   * Add a BOM after each non-BMP character.
+   */
+  void AddBOMs(nsACString& aDest, const nsACString& aSource);
+
+  /**
+   * Replace all characters with asterisks (e.g. for password fields).
+   */
+  void ConvertTexttoAsterisks(nsAString& aString);
+
+  /**
+   * Parameterize conversion.
+   */
+  enum class AtkStringConvertFlags : uint32_t {
+    None                   = 0,
+    ConvertTextToAsterisks = 1 << 0,
+  };
+
+  MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(AtkStringConvertFlags)
+
+  class ATKStringConverterHelper {
+  public:
+    ATKStringConverterHelper(void) :
+#ifdef DEBUG
+      mAdjusted (false),
+#endif
+      mStartShifted (false),
+      mEndShifted (false) { }
+
+    /**
+     * In order to properly get non-BMP values, offsets need to be changed
+     * to get one character more on each end, so that ConvertUTF16toUTF8 can
+     * convert surrogates even if the originally requested offsets fall between
+     * them.
+     */
+    void AdjustOffsets(gint* aStartOffset, gint* aEndOffset, gint count);
+
+    /**
+     * Converts a string of accessible text with adjusted offsets into ATK
+     * gchar* string (by adding BOMs).  Note, AdjustOffsets has to be called
+     * before getting the text passed to this.
+     */
+    gchar* ConvertAdjusted(const nsAString& aStr);
+
+  private:
+    /**
+     * Remove the additional characters requested by PrepareUTF16toUTF8.
+     */
+    gchar* FinishUTF16toUTF8(nsCString& aStr);
+
+#ifdef DEBUG
+    bool mAdjusted;
+#endif
+    bool mStartShifted;
+    bool mEndShifted;
+  };
+
+  /**
+   * Get text from aAccessible, using ATKStringConverterHelper to properly
+   * introduce appropriate BOMs.
+   */
+  template <class AccessibleOrProxy>
+  gchar* NewATKString(AccessibleOrProxy* aAccessible,
+                      gint aStartOffset, gint aEndOffset,
+                      AtkStringConvertFlags aFlags)
+  {
+    gint startOffset = aStartOffset, endOffset = aEndOffset;
+    ATKStringConverterHelper converter;
+    converter.AdjustOffsets(&startOffset, &endOffset,
+                            gint(aAccessible->CharacterCount()));
+    nsAutoString str;
+    aAccessible->TextSubstring(startOffset, endOffset, str);
+    if (aFlags & AtkStringConvertFlags::ConvertTextToAsterisks)
+      ConvertTexttoAsterisks(str);
+    return converter.ConvertAdjusted(str);
+  }
+
+  /**
+   * Get a character from aAccessible, fetching more data as appropriate to
+   * properly get non-BMP characters or a BOM as appropriate.
+   */
+  template <class AccessibleCharAt>
+  gunichar ATKCharacter(AccessibleCharAt* aAccessible, gint aOffset)
+  {
+    // char16_t is unsigned short in Mozilla, gnuichar is guint32 in glib.
+    gunichar character = static_cast<gunichar>(aAccessible->CharAt(aOffset));
+
+    if (NS_IS_LOW_SURROGATE(character)) {
+      // Trailing surrogate, return BOM instead.
+      return 0xFEFF;
+    }
+
+    if (NS_IS_HIGH_SURROGATE(character)) {
+      // Heading surrogate, get the trailing surrogate and combine them.
+      gunichar characterLow = static_cast<gunichar>(aAccessible->CharAt(aOffset + 1));
+
+      if (!NS_IS_LOW_SURROGATE(characterLow)) {
+        // It should have been a trailing surrogate... Flag the error.
+        return 0xFFFD;
+      }
+      return SURROGATE_TO_UCS4(character, characterLow);
+    }
+
+    return character;
+  }
+
+}
+
+} // namespace a11y
+} // namespace mozilla
--- a/accessible/atk/moz.build
+++ b/accessible/atk/moz.build
@@ -9,16 +9,17 @@ EXPORTS.mozilla.a11y += [
     'HyperTextAccessibleWrap.h',
 ]
 
 SOURCES += [
     'AccessibleWrap.cpp',
     'ApplicationAccessibleWrap.cpp',
     'AtkSocketAccessible.cpp',
     'DocAccessibleWrap.cpp',
+    'DOMtoATK.cpp',
     'nsMaiHyperlink.cpp',
     'nsMaiInterfaceAction.cpp',
     'nsMaiInterfaceComponent.cpp',
     'nsMaiInterfaceDocument.cpp',
     'nsMaiInterfaceEditableText.cpp',
     'nsMaiInterfaceHyperlinkImpl.cpp',
     'nsMaiInterfaceHypertext.cpp',
     'nsMaiInterfaceImage.cpp',
--- a/accessible/atk/nsMaiInterfaceText.cpp
+++ b/accessible/atk/nsMaiInterfaceText.cpp
@@ -9,19 +9,22 @@
 #include "Accessible-inl.h"
 #include "HyperTextAccessible-inl.h"
 #include "nsMai.h"
 #include "ProxyAccessible.h"
 
 #include "nsIAccessibleTypes.h"
 #include "nsIPersistentProperties2.h"
 #include "nsISimpleEnumerator.h"
+#include "nsUTF8Utils.h"
 
 #include "mozilla/Likely.h"
 
+#include "DOMtoATK.h"
+
 using namespace mozilla;
 using namespace mozilla::a11y;
 
 static const char* sAtkTextAttrNames[ATK_TEXT_ATTR_LAST_DEFINED];
 
 void
 ConvertTextAttributeToAtkAttribute(const nsACString& aName,
                                    const nsAString& aValue,
@@ -123,44 +126,43 @@ ConvertToAtkTextAttributeSet(nsIPersiste
   return objAttributeSet;
 }
 
 static void
 ConvertTexttoAsterisks(AccessibleWrap* accWrap, nsAString& aString)
 {
   // convert each char to "*" when it's "password text"
   if (accWrap->NativeRole() == roles::PASSWORD_TEXT) {
-    for (uint32_t i = 0; i < aString.Length(); i++)
-      aString.ReplaceLiteral(i, 1, u"*");
+    DOMtoATK::ConvertTexttoAsterisks(aString);
   }
 }
 
 extern "C" {
 
 static gchar*
 getTextCB(AtkText *aText, gint aStartOffset, gint aEndOffset)
 {
   AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
   nsAutoString autoStr;
   if (accWrap) {
     HyperTextAccessible* text = accWrap->AsHyperText();
-    if (!text || !text->IsTextRole())
+    if (!text || !text->IsTextRole() || text->IsDefunct())
       return nullptr;
 
-    text->TextSubstring(aStartOffset, aEndOffset, autoStr);
+    return DOMtoATK::NewATKString(text, aStartOffset, aEndOffset,
+         accWrap->NativeRole() == roles::PASSWORD_TEXT ?
+           DOMtoATK::AtkStringConvertFlags::ConvertTextToAsterisks :
+           DOMtoATK::AtkStringConvertFlags::None);
 
-    ConvertTexttoAsterisks(accWrap, autoStr);
   } else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) {
-    proxy->TextSubstring(aStartOffset, aEndOffset, autoStr);
+    return DOMtoATK::NewATKString(proxy, aStartOffset, aEndOffset,
+         DOMtoATK::AtkStringConvertFlags::None);
   }
 
-  NS_ConvertUTF16toUTF8 cautoStr(autoStr);
-
-  //copy and return, libspi will free it.
-  return (cautoStr.get()) ? g_strdup(cautoStr.get()) : nullptr;
+  return nullptr;
 }
 
 static gchar*
 getTextAfterOffsetCB(AtkText *aText, gint aOffset,
                      AtkTextBoundary aBoundaryType,
                      gint *aStartOffset, gint *aEndOffset)
 {
     nsAutoString autoStr;
@@ -176,18 +178,18 @@ getTextAfterOffsetCB(AtkText *aText, gin
   } else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) {
     proxy->GetTextAfterOffset(aOffset, aBoundaryType, autoStr, &startOffset,
                               &endOffset);
   }
 
   *aStartOffset = startOffset;
   *aEndOffset = endOffset;
 
-  NS_ConvertUTF16toUTF8 cautoStr(autoStr);
-  return (cautoStr.get()) ? g_strdup(cautoStr.get()) : nullptr;
+  // libspi will free it.
+  return DOMtoATK::Convert(autoStr);
 }
 
 static gchar*
 getTextAtOffsetCB(AtkText *aText, gint aOffset,
                   AtkTextBoundary aBoundaryType,
                   gint *aStartOffset, gint *aEndOffset)
 {
   nsAutoString autoStr;
@@ -203,36 +205,34 @@ getTextAtOffsetCB(AtkText *aText, gint a
   } else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) {
     proxy->GetTextAtOffset(aOffset, aBoundaryType, autoStr, &startOffset,
                            &endOffset);
   }
 
   *aStartOffset = startOffset;
   *aEndOffset = endOffset;
 
-  NS_ConvertUTF16toUTF8 cautoStr(autoStr);
-  return (cautoStr.get()) ? g_strdup(cautoStr.get()) : nullptr;
+  // libspi will free it.
+  return DOMtoATK::Convert(autoStr);
 }
 
 static gunichar
 getCharacterAtOffsetCB(AtkText* aText, gint aOffset)
 {
   AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
   if (accWrap) {
     HyperTextAccessible* text = accWrap->AsHyperText();
     if (!text || !text->IsTextRole()) {
       return 0;
     }
-
-    // char16_t is unsigned short in Mozilla, gnuichar is guint32 in glib.
-    return static_cast<gunichar>(text->CharAt(aOffset));
+    return DOMtoATK::ATKCharacter(text, aOffset);
   }
 
   if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) {
-    return static_cast<gunichar>(proxy->CharAt(aOffset));
+    return DOMtoATK::ATKCharacter(proxy, aOffset);
   }
 
   return 0;
 }
 
 static gchar*
 getTextBeforeOffsetCB(AtkText *aText, gint aOffset,
                       AtkTextBoundary aBoundaryType,
@@ -252,18 +252,18 @@ getTextBeforeOffsetCB(AtkText *aText, gi
   } else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) {
     proxy->GetTextBeforeOffset(aOffset, aBoundaryType, autoStr, &startOffset,
                                &endOffset);
   }
 
   *aStartOffset = startOffset;
   *aEndOffset = endOffset;
 
-  NS_ConvertUTF16toUTF8 cautoStr(autoStr);
-  return (cautoStr.get()) ? g_strdup(cautoStr.get()) : nullptr;
+  // libspi will free it.
+  return DOMtoATK::Convert(autoStr);
 }
 
 static gint
 getCaretOffsetCB(AtkText *aText)
 {
   AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText));
   if (accWrap) {
     HyperTextAccessible* text = accWrap->AsHyperText();
--- a/accessible/generic/Accessible.cpp
+++ b/accessible/generic/Accessible.cpp
@@ -63,20 +63,16 @@
 #include "nsIURI.h"
 #include "nsArrayUtils.h"
 #include "nsIMutableArray.h"
 #include "nsIObserverService.h"
 #include "nsIServiceManager.h"
 #include "nsWhitespaceTokenizer.h"
 #include "nsAttrName.h"
 
-#ifdef DEBUG
-#include "nsIDOMCharacterData.h"
-#endif
-
 #include "mozilla/Assertions.h"
 #include "mozilla/BasicEvents.h"
 #include "mozilla/ErrorResult.h"
 #include "mozilla/EventStates.h"
 #include "mozilla/FloatingPoint.h"
 #include "mozilla/MouseEvents.h"
 #include "mozilla/Unused.h"
 #include "mozilla/Preferences.h"
--- a/accessible/generic/DocAccessible.cpp
+++ b/accessible/generic/DocAccessible.cpp
@@ -18,17 +18,16 @@
 #include "RootAccessible.h"
 #include "TreeWalker.h"
 #include "xpcAccessibleDocument.h"
 
 #include "nsIMutableArray.h"
 #include "nsICommandManager.h"
 #include "nsIDocShell.h"
 #include "nsIDocument.h"
-#include "nsIDOMCharacterData.h"
 #include "nsIDOMDocument.h"
 #include "nsPIDOMWindow.h"
 #include "nsIEditingSession.h"
 #include "nsIFrame.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsImageFrame.h"
 #include "nsIPersistentProperties2.h"
 #include "nsIPresShell.h"
--- a/accessible/ipc/win/HandlerProvider.cpp
+++ b/accessible/ipc/win/HandlerProvider.cpp
@@ -256,19 +256,22 @@ HandlerProvider::BuildStaticIA2Data(
   }
 }
 
 void
 HandlerProvider::BuildDynamicIA2Data(DynamicIA2Data* aOutIA2Data)
 {
   MOZ_ASSERT(aOutIA2Data);
   MOZ_ASSERT(NS_IsMainThread());
-  MOZ_ASSERT(mTargetUnk);
   MOZ_ASSERT(IsTargetInterfaceCacheable());
 
+  if (!mTargetUnk) {
+    return;
+  }
+
   RefPtr<NEWEST_IA2_INTERFACE> target;
   HRESULT hr = mTargetUnk.get()->QueryInterface(NEWEST_IA2_IID,
     getter_AddRefs(target));
   if (FAILED(hr)) {
     return;
   }
 
   hr = E_UNEXPECTED;
@@ -462,16 +465,21 @@ HandlerProvider::MarshalAs(REFIID aIid)
   }
   // Otherwise we juse return the identity.
   return aIid;
 }
 
 HRESULT
 HandlerProvider::DisconnectHandlerRemotes()
 {
+  // If a handlerProvider call is pending on another thread,
+  // CoDisconnectObject won't release this HandlerProvider immediately.
+  // However, the interceptor and its target (mTargetUnk) might be destroyed.
+  mTargetUnk = nullptr;
+
   IUnknown* unk = static_cast<IGeckoBackChannel*>(this);
   return ::CoDisconnectObject(unk, 0);
 }
 
 REFIID
 HandlerProvider::GetEffectiveOutParamIid(REFIID aCallIid,
                                          ULONG aCallMethod)
 {
@@ -539,16 +547,20 @@ HandlerProvider::put_HandlerControl(long
   return S_OK;
 }
 
 HRESULT
 HandlerProvider::Refresh(DynamicIA2Data* aOutData)
 {
   MOZ_ASSERT(mscom::IsCurrentThreadMTA());
 
+  if (!mTargetUnk) {
+    return CO_E_OBJNOTCONNECTED;
+  }
+
   if (!mscom::InvokeOnMainThread("HandlerProvider::BuildDynamicIA2Data",
                                  this, &HandlerProvider::BuildDynamicIA2Data,
                                  aOutData)) {
     return E_FAIL;
   }
 
   return S_OK;
 }
@@ -576,17 +588,21 @@ HandlerProvider::GetAllTextInfoMainThrea
                                           long* aNAttribRuns, HRESULT* result)
 {
   MOZ_ASSERT(aText);
   MOZ_ASSERT(aHyperlinks);
   MOZ_ASSERT(aNHyperlinks);
   MOZ_ASSERT(aAttribRuns);
   MOZ_ASSERT(aNAttribRuns);
   MOZ_ASSERT(NS_IsMainThread());
-  MOZ_ASSERT(mTargetUnk);
+
+  if (!mTargetUnk) {
+    *result = CO_E_OBJNOTCONNECTED;
+    return;
+  }
 
   RefPtr<IAccessibleHypertext2> ht;
   HRESULT hr = mTargetUnk->QueryInterface(IID_IAccessibleHypertext2,
                                           getter_AddRefs(ht));
   if (FAILED(hr)) {
     *result = hr;
     return;
   }
@@ -652,16 +668,20 @@ HRESULT
 HandlerProvider::get_AllTextInfo(BSTR* aText,
                                  IAccessibleHyperlink*** aHyperlinks,
                                  long* aNHyperlinks,
                                  IA2TextSegment** aAttribRuns,
                                  long* aNAttribRuns)
 {
   MOZ_ASSERT(mscom::IsCurrentThreadMTA());
 
+  if (!mTargetUnk) {
+    return CO_E_OBJNOTCONNECTED;
+  }
+
   HRESULT hr;
   if (!mscom::InvokeOnMainThread("HandlerProvider::GetAllTextInfoMainThread",
                                  this,
                                  &HandlerProvider::GetAllTextInfoMainThread,
                                  aText, aHyperlinks, aNHyperlinks,
                                  aAttribRuns, aNAttribRuns, &hr)) {
     return E_FAIL;
   }
@@ -672,17 +692,21 @@ HandlerProvider::get_AllTextInfo(BSTR* a
 void
 HandlerProvider::GetRelationsInfoMainThread(IARelationData** aRelations,
                                             long* aNRelations,
                                             HRESULT* hr)
 {
   MOZ_ASSERT(aRelations);
   MOZ_ASSERT(aNRelations);
   MOZ_ASSERT(NS_IsMainThread());
-  MOZ_ASSERT(mTargetUnk);
+
+  if (!mTargetUnk) {
+    *hr = CO_E_OBJNOTCONNECTED;
+    return;
+  }
 
   RefPtr<NEWEST_IA2_INTERFACE> acc;
   *hr = mTargetUnk.get()->QueryInterface(NEWEST_IA2_IID,
     getter_AddRefs(acc));
   if (FAILED(*hr)) {
     return;
   }
 
@@ -717,16 +741,20 @@ HandlerProvider::GetRelationsInfoMainThr
 }
 
 HRESULT
 HandlerProvider::get_RelationsInfo(IARelationData** aRelations,
                                    long* aNRelations)
 {
   MOZ_ASSERT(mscom::IsCurrentThreadMTA());
 
+  if (!mTargetUnk) {
+    return CO_E_OBJNOTCONNECTED;
+  }
+
   HRESULT hr;
   if (!mscom::InvokeOnMainThread("HandlerProvider::GetRelationsInfoMainThread",
                                  this,
                                  &HandlerProvider::GetRelationsInfoMainThread,
                                  aRelations, aNRelations, &hr)) {
     return E_FAIL;
   }
 
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -8341,39 +8341,16 @@ var gIdentityHandler = {
         browser.messageManager.sendAsyncMessage("webrtc:StopSharing", windowId);
         webrtcUI.forgetActivePermissionsFromBrowser(gBrowser.selectedBrowser);
       }
       SitePermissions.remove(gBrowser.currentURI, aPermission.id, browser);
 
       this._permissionReloadHint.removeAttribute("hidden");
       PanelView.forNode(this._identityPopupMainView)
                .descriptionHeightWorkaround();
-
-      // Set telemetry values for clearing a permission
-      let histogram = Services.telemetry.getKeyedHistogramById("WEB_PERMISSION_CLEARED");
-
-      let permissionType = 0;
-      if (aPermission.state == SitePermissions.ALLOW &&
-          aPermission.scope == SitePermissions.SCOPE_PERSISTENT) {
-        // 1 : clear permanently allowed permission
-        permissionType = 1;
-      } else if (aPermission.state == SitePermissions.BLOCK &&
-                 aPermission.scope == SitePermissions.SCOPE_PERSISTENT) {
-        // 2 : clear permanently blocked permission
-        permissionType = 2;
-      } else if (aPermission.state == SitePermissions.ALLOW) {
-        // 3 : clear temporary allowed permission
-        permissionType = 3;
-      } else if (aPermission.state == SitePermissions.BLOCK) {
-        // 4 : clear temporary blocked permission
-        permissionType = 4;
-      }
-
-      histogram.add("(all)", permissionType);
-      histogram.add(aPermission.id, permissionType);
     });
 
     container.appendChild(button);
 
     return container;
   },
 
   _createBlockedPopupIndicator() {
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -1913,22 +1913,28 @@
             this.removeAttribute("activemedia-blocked");
             modifiedAttrs.push("activemedia-blocked");
 
             browser.resumeMedia();
             hist.add(3 /* unblockByClickingIcon */);
             this.finishMediaBlockTimer();
           } else {
             if (browser.audioMuted) {
-              browser.unmute();
+              if (this.linkedPanel) {
+                // "Lazy Browser" should not invoke its unmute method
+                browser.unmute();
+              }
               this.removeAttribute("muted");
               BrowserUITelemetry.countTabMutingEvent("unmute", aMuteReason);
               hist.add(1 /* unmute */);
             } else {
-              browser.mute();
+              if (this.linkedPanel) {
+                // "Lazy Browser" should not invoke its mute method
+                browser.mute();
+              }
               this.setAttribute("muted", "true");
               BrowserUITelemetry.countTabMutingEvent("mute", aMuteReason);
               hist.add(0 /* mute */);
             }
             this.muteReason = aMuteReason || null;
             modifiedAttrs.push("muted");
           }
           gBrowser._tabAttrModified(this, modifiedAttrs);
--- a/browser/base/content/test/tabs/browser_bug_1387976_restore_lazy_tab_browser_muted_state.js
+++ b/browser/base/content/test/tabs/browser_bug_1387976_restore_lazy_tab_browser_muted_state.js
@@ -39,11 +39,12 @@ add_task(async function() {
   tab.toggleMuteAudio();
 
   ok("muted" in get_tab_state(tab), "Tab should be in a muted state");
 
   info("Restarting tab...");
   let restartedTab = await restartTab(tab);
 
   ok("muted" in get_tab_state(restartedTab), "Restored tab should still be in a muted state after restart");
+  ok(!restartedTab.linkedPanel, "Restored tab should not be inserted");
 
   BrowserTestUtils.removeTab(restartedTab);
 });
--- a/devtools/server/actors/object.js
+++ b/devtools/server/actors/object.js
@@ -1864,18 +1864,19 @@ DebuggerServer.ObjectActorPreviewers.Obj
       // Add preview for DOM element attributes.
       preview.attributes = {};
       preview.attributesLength = rawObj.attributes.length;
       for (let attr of rawObj.attributes) {
         preview.attributes[attr.nodeName] = hooks.createValueGrip(attr.value);
       }
     } else if (obj.class == "Attr") {
       preview.value = hooks.createValueGrip(rawObj.value);
-    } else if (rawObj instanceof Ci.nsIDOMText ||
-               rawObj instanceof Ci.nsIDOMComment) {
+    } else if (obj.class == "Text" ||
+               obj.class == "CDATASection" ||
+               obj.class == "Comment") {
       preview.textContent = hooks.createValueGrip(rawObj.textContent);
     }
 
     return true;
   },
 
   function DOMEvent({obj, hooks}, grip, rawObj) {
     if (isWorker || !rawObj || !(rawObj instanceof Ci.nsIDOMEvent)) {
--- a/dom/base/Attr.h
+++ b/dom/base/Attr.h
@@ -9,17 +9,16 @@
  */
 
 #ifndef mozilla_dom_Attr_h
 #define mozilla_dom_Attr_h
 
 #include "mozilla/Attributes.h"
 #include "nsIAttribute.h"
 #include "nsIDOMNode.h"
-#include "nsIDOMText.h"
 #include "nsIDOMNodeList.h"
 #include "nsString.h"
 #include "nsCOMPtr.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsStubMutationObserver.h"
 
 class nsIDocument;
 
rename from dom/base/nsGenericDOMDataNode.cpp
rename to dom/base/CharacterData.cpp
--- a/dom/base/nsGenericDOMDataNode.cpp
+++ b/dom/base/CharacterData.cpp
@@ -1,213 +1,197 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /*
- * Base class for DOM Core's nsIDOMComment, DocumentType, nsIDOMText,
- * CDATASection and nsIDOMProcessingInstruction nodes.
+ * Base class for DOM Core's Comment, DocumentType, Text,
+ * CDATASection and ProcessingInstruction nodes.
  */
 
+#include "mozilla/dom/CharacterData.h"
+
 #include "mozilla/DebugOnly.h"
 
-#include "nsGenericDOMDataNode.h"
 #include "mozilla/AsyncEventDispatcher.h"
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/HTMLSlotElement.h"
 #include "mozilla/dom/ShadowRoot.h"
 #include "nsIDocument.h"
 #include "nsIDOMDocument.h"
 #include "nsReadableUtils.h"
 #include "mozilla/InternalMutationEvent.h"
 #include "nsIURI.h"
 #include "nsIDOMEvent.h"
-#include "nsIDOMText.h"
 #include "nsCOMPtr.h"
 #include "nsDOMString.h"
 #include "nsChangeHint.h"
 #include "nsCOMArray.h"
 #include "nsNodeUtils.h"
 #include "mozilla/dom/DirectionalityUtils.h"
 #include "nsBindingManager.h"
 #include "nsCCUncollectableMarker.h"
 #include "mozAutoDocUpdate.h"
 #include "nsTextNode.h"
 #include "nsBidiUtils.h"
 #include "PLDHashTable.h"
 #include "mozilla/Sprintf.h"
 #include "nsWrapperCacheInlines.h"
 
-using namespace mozilla;
-using namespace mozilla::dom;
+namespace mozilla {
+namespace dom {
 
-nsGenericDOMDataNode::nsGenericDOMDataNode(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
+CharacterData::CharacterData(already_AddRefed<dom::NodeInfo>& aNodeInfo)
   : nsIContent(aNodeInfo)
 {
   MOZ_ASSERT(mNodeInfo->NodeType() == TEXT_NODE ||
              mNodeInfo->NodeType() == CDATA_SECTION_NODE ||
              mNodeInfo->NodeType() == COMMENT_NODE ||
              mNodeInfo->NodeType() == PROCESSING_INSTRUCTION_NODE ||
              mNodeInfo->NodeType() == DOCUMENT_TYPE_NODE,
              "Bad NodeType in aNodeInfo");
 }
 
-nsGenericDOMDataNode::nsGenericDOMDataNode(already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo)
+CharacterData::CharacterData(already_AddRefed<dom::NodeInfo>&& aNodeInfo)
   : nsIContent(aNodeInfo)
 {
   MOZ_ASSERT(mNodeInfo->NodeType() == TEXT_NODE ||
              mNodeInfo->NodeType() == CDATA_SECTION_NODE ||
              mNodeInfo->NodeType() == COMMENT_NODE ||
              mNodeInfo->NodeType() == PROCESSING_INSTRUCTION_NODE ||
              mNodeInfo->NodeType() == DOCUMENT_TYPE_NODE,
              "Bad NodeType in aNodeInfo");
 }
 
-nsGenericDOMDataNode::~nsGenericDOMDataNode()
+CharacterData::~CharacterData()
 {
   NS_PRECONDITION(!IsInUncomposedDoc(),
                   "Please remove this from the document properly");
   if (GetParent()) {
     NS_RELEASE(mParent);
   }
 }
 
-NS_IMPL_CYCLE_COLLECTION_CLASS(nsGenericDOMDataNode)
+NS_IMPL_CYCLE_COLLECTION_CLASS(CharacterData)
 
-NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(nsGenericDOMDataNode)
+NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(CharacterData)
 
-NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(nsGenericDOMDataNode)
+NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(CharacterData)
   return Element::CanSkip(tmp, aRemovingAllowed);
 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END
 
-NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(nsGenericDOMDataNode)
+NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(CharacterData)
   return Element::CanSkipInCC(tmp);
 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END
 
-NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(nsGenericDOMDataNode)
+NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(CharacterData)
   return Element::CanSkipThis(tmp);
 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END
 
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(nsGenericDOMDataNode)
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(CharacterData)
   if (MOZ_UNLIKELY(cb.WantDebugInfo())) {
     char name[40];
-    SprintfLiteral(name, "nsGenericDOMDataNode (len=%d)",
+    SprintfLiteral(name, "CharacterData (len=%d)",
                    tmp->mText.GetLength());
     cb.DescribeRefCountedNode(tmp->mRefCnt.get(), name);
   } else {
-    NS_IMPL_CYCLE_COLLECTION_DESCRIBE(nsGenericDOMDataNode, tmp->mRefCnt.get())
+    NS_IMPL_CYCLE_COLLECTION_DESCRIBE(CharacterData, tmp->mRefCnt.get())
   }
 
   if (!nsIContent::Traverse(tmp, cb)) {
     return NS_SUCCESS_INTERRUPTED_TRAVERSE;
   }
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
-NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsGenericDOMDataNode)
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(CharacterData)
   nsIContent::Unlink(tmp);
 
   // Clear flag here because unlinking slots will clear the
   // containing shadow root pointer.
   tmp->UnsetFlags(NODE_IS_IN_SHADOW_TREE);
 
   nsContentSlots* slots = tmp->GetExistingContentSlots();
   if (slots) {
     slots->Unlink();
   }
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
-NS_INTERFACE_MAP_BEGIN(nsGenericDOMDataNode)
+NS_INTERFACE_MAP_BEGIN(CharacterData)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
-  NS_INTERFACE_MAP_ENTRIES_CYCLE_COLLECTION(nsGenericDOMDataNode)
+  NS_INTERFACE_MAP_ENTRIES_CYCLE_COLLECTION(CharacterData)
   NS_INTERFACE_MAP_ENTRY(nsIContent)
   NS_INTERFACE_MAP_ENTRY(nsINode)
   NS_INTERFACE_MAP_ENTRY(nsIDOMEventTarget)
   NS_INTERFACE_MAP_ENTRY(mozilla::dom::EventTarget)
   NS_INTERFACE_MAP_ENTRY_TEAROFF(nsISupportsWeakReference,
                                  new nsNodeSupportsWeakRefTearoff(this))
   // DOM bindings depend on the identity pointer being the
   // same as nsINode (which nsIContent inherits).
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIContent)
 NS_INTERFACE_MAP_END
 
-NS_IMPL_MAIN_THREAD_ONLY_CYCLE_COLLECTING_ADDREF(nsGenericDOMDataNode)
-NS_IMPL_MAIN_THREAD_ONLY_CYCLE_COLLECTING_RELEASE_WITH_LAST_RELEASE(nsGenericDOMDataNode,
+NS_IMPL_MAIN_THREAD_ONLY_CYCLE_COLLECTING_ADDREF(CharacterData)
+NS_IMPL_MAIN_THREAD_ONLY_CYCLE_COLLECTING_RELEASE_WITH_LAST_RELEASE(CharacterData,
                                                                     nsNodeUtils::LastRelease(this))
 
 
 void
-nsGenericDOMDataNode::GetNodeValueInternal(nsAString& aNodeValue)
+CharacterData::GetNodeValueInternal(nsAString& aNodeValue)
 {
-  DebugOnly<nsresult> rv = GetData(aNodeValue);
-  NS_ASSERTION(NS_SUCCEEDED(rv), "GetData() failed!");
+  GetData(aNodeValue);
 }
 
 void
-nsGenericDOMDataNode::SetNodeValueInternal(const nsAString& aNodeValue,
+CharacterData::SetNodeValueInternal(const nsAString& aNodeValue,
                                            ErrorResult& aError)
 {
   aError = SetTextInternal(0, mText.GetLength(), aNodeValue.BeginReading(),
                            aNodeValue.Length(), true);
 }
 
 //----------------------------------------------------------------------
 
-// Implementation of nsIDOMCharacterData
+// Implementation of CharacterData
 
-nsresult
-nsGenericDOMDataNode::GetData(nsAString& aData) const
+void
+CharacterData::GetData(nsAString& aData) const
 {
   if (mText.Is2b()) {
     aData.Truncate();
     mText.AppendTo(aData);
   } else {
     // Must use Substring() since nsDependentCString() requires null
     // terminated strings.
 
     const char *data = mText.Get1b();
 
     if (data) {
       CopyASCIItoUTF16(Substring(data, data + mText.GetLength()), aData);
     } else {
       aData.Truncate();
     }
   }
-
-  return NS_OK;
-}
-
-nsresult
-nsGenericDOMDataNode::SetData(const nsAString& aData)
-{
-  return SetTextInternal(0, mText.GetLength(), aData.BeginReading(),
-                         aData.Length(), true);
-}
-
-nsresult
-nsGenericDOMDataNode::GetLength(uint32_t* aLength)
-{
-  *aLength = mText.GetLength();
-  return NS_OK;
-}
-
-nsresult
-nsGenericDOMDataNode::SubstringData(uint32_t aStart, uint32_t aCount,
-                                    nsAString& aReturn)
-{
-  ErrorResult rv;
-  SubstringData(aStart, aCount, aReturn, rv);
-  return rv.StealNSResult();
 }
 
 void
-nsGenericDOMDataNode::SubstringData(uint32_t aStart, uint32_t aCount,
-                                    nsAString& aReturn, ErrorResult& rv)
+CharacterData::SetData(const nsAString& aData, ErrorResult& aRv)
+{
+  nsresult rv = SetTextInternal(0, mText.GetLength(), aData.BeginReading(),
+                                aData.Length(), true);
+  if (NS_FAILED(rv)) {
+    aRv.Throw(rv);
+  }
+}
+
+void
+CharacterData::SubstringData(uint32_t aStart, uint32_t aCount,
+                             nsAString& aReturn, ErrorResult& rv)
 {
   aReturn.Truncate();
 
   uint32_t textLength = mText.GetLength();
   if (aStart > textLength) {
     rv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
     return;
   }
@@ -225,50 +209,59 @@ nsGenericDOMDataNode::SubstringData(uint
 
     const char *data = mText.Get1b() + aStart;
     CopyASCIItoUTF16(Substring(data, data + amount), aReturn);
   }
 }
 
 //----------------------------------------------------------------------
 
-nsresult
-nsGenericDOMDataNode::AppendData(const nsAString& aData)
+void
+CharacterData::AppendData(const nsAString& aData, ErrorResult& aRv)
 {
-  return SetTextInternal(mText.GetLength(), 0, aData.BeginReading(),
-                         aData.Length(), true);
+  InsertData(mText.GetLength(), aData, aRv);
+}
+
+void
+CharacterData::InsertData(uint32_t aOffset,
+                          const nsAString& aData,
+                          ErrorResult& aRv)
+{
+  nsresult rv = SetTextInternal(aOffset, 0, aData.BeginReading(),
+                                aData.Length(), true);
+  if (NS_FAILED(rv)) {
+    aRv.Throw(rv);
+  }
 }
 
-nsresult
-nsGenericDOMDataNode::InsertData(uint32_t aOffset,
-                                 const nsAString& aData)
+void
+CharacterData::DeleteData(uint32_t aOffset, uint32_t aCount, ErrorResult& aRv)
 {
-  return SetTextInternal(aOffset, 0, aData.BeginReading(),
-                         aData.Length(), true);
+  nsresult rv = SetTextInternal(aOffset, aCount, nullptr, 0, true);
+  if (NS_FAILED(rv)) {
+    aRv.Throw(rv);
+  }
+}
+
+void
+CharacterData::ReplaceData(uint32_t aOffset, uint32_t aCount,
+                           const nsAString& aData, ErrorResult& aRv)
+{
+  nsresult rv = SetTextInternal(aOffset, aCount, aData.BeginReading(),
+                                aData.Length(), true);
+  if (NS_FAILED(rv)) {
+    aRv.Throw(rv);
+  }  
 }
 
 nsresult
-nsGenericDOMDataNode::DeleteData(uint32_t aOffset, uint32_t aCount)
-{
-  return SetTextInternal(aOffset, aCount, nullptr, 0, true);
-}
-
-nsresult
-nsGenericDOMDataNode::ReplaceData(uint32_t aOffset, uint32_t aCount,
-                                  const nsAString& aData)
-{
-  return SetTextInternal(aOffset, aCount, aData.BeginReading(),
-                         aData.Length(), true);
-}
-
-nsresult
-nsGenericDOMDataNode::SetTextInternal(uint32_t aOffset, uint32_t aCount,
-                                      const char16_t* aBuffer,
-                                      uint32_t aLength, bool aNotify,
-                                      CharacterDataChangeInfo::Details* aDetails)
+CharacterData::SetTextInternal(uint32_t aOffset, uint32_t aCount,
+                               const char16_t* aBuffer,
+                               uint32_t aLength, bool aNotify,
+                               CharacterDataChangeInfo::Details* aDetails)
 {
   NS_PRECONDITION(aBuffer || !aLength,
                   "Null buffer passed to SetTextInternal!");
 
   // sanitize arguments
   uint32_t textLength = mText.GetLength();
   if (aOffset > textLength) {
     return NS_ERROR_DOM_INDEX_SIZE_ERR;
@@ -411,18 +404,18 @@ nsGenericDOMDataNode::SetTextInternal(ui
 }
 
 //----------------------------------------------------------------------
 
 // Implementation of nsIContent
 
 #ifdef DEBUG
 void
-nsGenericDOMDataNode::ToCString(nsAString& aBuf, int32_t aOffset,
-                                int32_t aLen) const
+CharacterData::ToCString(nsAString& aBuf, int32_t aOffset,
+                         int32_t aLen) const
 {
   if (mText.Is2b()) {
     const char16_t* cp = mText.Get2b() + aOffset;
     const char16_t* end = cp + aLen;
 
     while (cp < end) {
       char16_t ch = *cp++;
       if (ch == '&') {
@@ -460,19 +453,19 @@ nsGenericDOMDataNode::ToCString(nsAStrin
       }
     }
   }
 }
 #endif
 
 
 nsresult
-nsGenericDOMDataNode::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
-                                 nsIContent* aBindingParent,
-                                 bool aCompileEventHandlers)
+CharacterData::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
+                          nsIContent* aBindingParent,
+                          bool aCompileEventHandlers)
 {
   NS_PRECONDITION(aParent || aDocument, "Must have document if no parent!");
   NS_PRECONDITION(NODE_FROM(aParent, aDocument)->OwnerDoc() == OwnerDoc(),
                   "Must have the same owner document");
   NS_PRECONDITION(!aParent || aDocument == aParent->GetUncomposedDoc(),
                   "aDocument must be current doc of aParent");
   NS_PRECONDITION(!GetUncomposedDoc() && !IsInUncomposedDoc(),
                   "Already have a document.  Unbind first!");
@@ -569,17 +562,17 @@ nsGenericDOMDataNode::BindToTree(nsIDocu
   MOZ_ASSERT(aParent == GetParent(), "Bound to wrong parent");
   MOZ_ASSERT(aBindingParent == GetBindingParent(),
              "Bound to wrong binding parent");
 
   return NS_OK;
 }
 
 void
-nsGenericDOMDataNode::UnbindFromTree(bool aDeep, bool aNullParent)
+CharacterData::UnbindFromTree(bool aDeep, bool aNullParent)
 {
   // Unset frame flags; if we need them again later, they'll get set again.
   UnsetFlags(NS_CREATE_FRAME_IF_NON_WHITESPACE |
              NS_REFRAME_IF_WHITESPACE);
 
   nsIDocument* document = GetComposedDoc();
 
   if (aNullParent) {
@@ -621,295 +614,152 @@ nsGenericDOMDataNode::UnbindFromTree(boo
       slots->mContainingShadow = nullptr;
     }
   }
 
   nsNodeUtils::ParentChainChanged(this);
 }
 
 already_AddRefed<nsINodeList>
-nsGenericDOMDataNode::GetChildren(uint32_t aFilter)
+CharacterData::GetChildren(uint32_t aFilter)
 {
   return nullptr;
 }
 
 uint32_t
-nsGenericDOMDataNode::GetChildCount() const
+CharacterData::GetChildCount() const
 {
   return 0;
 }
 
 nsIContent *
-nsGenericDOMDataNode::GetChildAt_Deprecated(uint32_t aIndex) const
+CharacterData::GetChildAt_Deprecated(uint32_t aIndex) const
 {
   return nullptr;
 }
 
 
 int32_t
-nsGenericDOMDataNode::ComputeIndexOf(const nsINode* aPossibleChild) const
+CharacterData::ComputeIndexOf(const nsINode* aPossibleChild) const
 {
   return -1;
 }
 
 nsresult
-nsGenericDOMDataNode::InsertChildBefore(nsIContent* aKid,
-                                        nsIContent* aBeforeThis,
-                                        bool aNotify)
+CharacterData::InsertChildBefore(nsIContent* aKid,
+                                 nsIContent* aBeforeThis,
+                                 bool aNotify)
 {
   return NS_OK;
 }
 
 nsresult
-nsGenericDOMDataNode::InsertChildAt_Deprecated(nsIContent* aKid,
-                                               uint32_t aIndex,
-                                               bool aNotify)
+CharacterData::InsertChildAt_Deprecated(nsIContent* aKid,
+                                        uint32_t aIndex,
+                                        bool aNotify)
 {
   return NS_OK;
 }
 
 void
-nsGenericDOMDataNode::RemoveChildAt_Deprecated(uint32_t aIndex, bool aNotify)
+CharacterData::RemoveChildAt_Deprecated(uint32_t aIndex, bool aNotify)
 {
 }
 
 void
-nsGenericDOMDataNode::RemoveChildNode(nsIContent* aKid, bool aNotify)
+CharacterData::RemoveChildNode(nsIContent* aKid, bool aNotify)
 {
 }
 
 nsXBLBinding *
-nsGenericDOMDataNode::DoGetXBLBinding() const
+CharacterData::DoGetXBLBinding() const
 {
   return nullptr;
 }
 
 bool
-nsGenericDOMDataNode::IsNodeOfType(uint32_t aFlags) const
+CharacterData::IsNodeOfType(uint32_t aFlags) const
 {
   return !(aFlags & ~eDATA_NODE);
 }
 
 void
-nsGenericDOMDataNode::SaveSubtreeState()
+CharacterData::SaveSubtreeState()
 {
 }
 
 #ifdef DEBUG
 void
-nsGenericDOMDataNode::List(FILE* out, int32_t aIndent) const
+CharacterData::List(FILE* out, int32_t aIndent) const
 {
 }
 
 void
-nsGenericDOMDataNode::DumpContent(FILE* out, int32_t aIndent,
-                                  bool aDumpAll) const
+CharacterData::DumpContent(FILE* out, int32_t aIndent,
+                           bool aDumpAll) const
 {
 }
 #endif
 
 bool
-nsGenericDOMDataNode::IsLink(nsIURI** aURI) const
+CharacterData::IsLink(nsIURI** aURI) const
 {
   *aURI = nullptr;
   return false;
 }
 
 //----------------------------------------------------------------------
 
-// Implementation of the nsIDOMText interface
-
-nsresult
-nsGenericDOMDataNode::SplitData(uint32_t aOffset, nsIContent** aReturn,
-                                bool aCloneAfterOriginal)
-{
-  *aReturn = nullptr;
-  nsresult rv = NS_OK;
-  nsAutoString cutText;
-  uint32_t length = TextLength();
-
-  if (aOffset > length) {
-    return NS_ERROR_DOM_INDEX_SIZE_ERR;
-  }
-
-  uint32_t cutStartOffset = aCloneAfterOriginal ? aOffset : 0;
-  uint32_t cutLength = aCloneAfterOriginal ? length - aOffset : aOffset;
-  rv = SubstringData(cutStartOffset, cutLength, cutText);
-  if (NS_FAILED(rv)) {
-    return rv;
-  }
-
-  nsIDocument* document = GetComposedDoc();
-  mozAutoDocUpdate updateBatch(document, UPDATE_CONTENT_MODEL, true);
-
-  // Use Clone for creating the new node so that the new node is of same class
-  // as this node!
-  nsCOMPtr<nsIContent> newContent = CloneDataNode(mNodeInfo, false);
-  if (!newContent) {
-    return NS_ERROR_OUT_OF_MEMORY;
-  }
-  // nsRange expects the CharacterDataChanged notification is followed
-  // by an insertion of |newContent|. If you change this code,
-  // make sure you make the appropriate changes in nsRange.
-  newContent->SetText(cutText, true); // XXX should be false?
-
-  CharacterDataChangeInfo::Details details = {
-    CharacterDataChangeInfo::Details::eSplit, newContent
-  };
-  rv = SetTextInternal(cutStartOffset, cutLength, nullptr, 0, true,
-                       aCloneAfterOriginal ? &details : nullptr);
-  if (NS_FAILED(rv)) {
-    return rv;
-  }
-
-  nsCOMPtr<nsINode> parent = GetParentNode();
-  if (parent) {
-    nsCOMPtr<nsIContent> beforeNode = this;
-    if (aCloneAfterOriginal) {
-      beforeNode = beforeNode->GetNextSibling();
-    }
-    parent->InsertChildBefore(newContent, beforeNode, true);
-  }
-
-  newContent.swap(*aReturn);
-  return rv;
-}
-
-nsresult
-nsGenericDOMDataNode::SplitText(uint32_t aOffset, nsIDOMText** aReturn)
-{
-  nsCOMPtr<nsIContent> newChild;
-  nsresult rv = SplitData(aOffset, getter_AddRefs(newChild));
-  if (NS_SUCCEEDED(rv)) {
-    rv = CallQueryInterface(newChild, aReturn);
-  }
-  return rv;
-}
-
-static nsIContent*
-FirstLogicallyAdjacentTextNode(nsIContent* aNode)
-{
-  nsCOMPtr<nsIContent> parent = aNode->GetParent();
-
-  while (aNode) {
-    nsIContent* sibling = aNode->GetPreviousSibling();
-    if (!sibling || !sibling->IsNodeOfType(nsINode::eTEXT)) {
-      return aNode;
-    }
-    aNode = sibling;
-  }
-
-  return parent->GetFirstChild();
-}
-
-static nsIContent*
-LastLogicallyAdjacentTextNode(nsIContent* aNode)
-{
-  nsCOMPtr<nsIContent> parent = aNode->GetParent();
-
-  while (aNode) {
-    nsIContent* sibling = aNode->GetNextSibling();
-    if (!sibling) break;
-
-    if (!sibling->IsNodeOfType(nsINode::eTEXT)) {
-      return aNode;
-    }
-
-    aNode = sibling;
-  }
-
-  return parent->GetLastChild();
-}
-
-nsresult
-nsGenericDOMDataNode::GetWholeText(nsAString& aWholeText)
-{
-  nsIContent* parent = GetParent();
-
-  // Handle parent-less nodes
-  if (!parent)
-    return GetData(aWholeText);
-
-  int32_t index = parent->ComputeIndexOf(this);
-  NS_WARNING_ASSERTION(index >= 0,
-                       "Trying to use .wholeText with an anonymous"
-                       "text node child of a binding parent?");
-  NS_ENSURE_TRUE(index >= 0, NS_ERROR_DOM_NOT_SUPPORTED_ERR);
-  nsCOMPtr<nsIContent> first = FirstLogicallyAdjacentTextNode(this);
-  nsCOMPtr<nsIContent> last = LastLogicallyAdjacentTextNode(this);
-
-  aWholeText.Truncate();
-
-  nsCOMPtr<nsIDOMText> node;
-  nsAutoString tmp;
-
-  while (true) {
-    node = do_QueryInterface(first);
-    node->GetData(tmp);
-    aWholeText.Append(tmp);
-
-    if (first == last) {
-      break;
-    }
-
-    first = first->GetNextSibling();
-  }
-
-  return NS_OK;
-}
-
-//----------------------------------------------------------------------
-
 // Implementation of the nsIContent interface text functions
 
 const nsTextFragment *
-nsGenericDOMDataNode::GetText()
+CharacterData::GetText()
 {
   return &mText;
 }
 
 uint32_t
-nsGenericDOMDataNode::TextLength() const
+CharacterData::TextLength() const
 {
   return TextDataLength();
 }
 
 nsresult
-nsGenericDOMDataNode::SetText(const char16_t* aBuffer,
-                              uint32_t aLength,
-                              bool aNotify)
+CharacterData::SetText(const char16_t* aBuffer,
+                       uint32_t aLength,
+                       bool aNotify)
 {
   return SetTextInternal(0, mText.GetLength(), aBuffer, aLength, aNotify);
 }
 
 nsresult
-nsGenericDOMDataNode::AppendText(const char16_t* aBuffer,
-                                 uint32_t aLength,
-                                 bool aNotify)
+CharacterData::AppendText(const char16_t* aBuffer,
+                          uint32_t aLength,
+                          bool aNotify)
 {
   return SetTextInternal(mText.GetLength(), 0, aBuffer, aLength, aNotify);
 }
 
 bool
-nsGenericDOMDataNode::TextIsOnlyWhitespace()
+CharacterData::TextIsOnlyWhitespace()
 {
 
   MOZ_ASSERT(NS_IsMainThread());
   if (!ThreadSafeTextIsOnlyWhitespace()) {
     UnsetFlags(NS_TEXT_IS_ONLY_WHITESPACE);
     SetFlags(NS_CACHED_TEXT_IS_ONLY_WHITESPACE);
     return false;
   }
 
   SetFlags(NS_CACHED_TEXT_IS_ONLY_WHITESPACE | NS_TEXT_IS_ONLY_WHITESPACE);
   return true;
 }
 
 bool
-nsGenericDOMDataNode::ThreadSafeTextIsOnlyWhitespace() const
+CharacterData::ThreadSafeTextIsOnlyWhitespace() const
 {
   // FIXME: should this method take content language into account?
   if (mText.Is2b()) {
     // The fragment contains non-8bit characters and such characters
     // are never considered whitespace.
     //
     // FIXME(emilio): This is not quite true in presence of the
     // NS_MAYBE_MODIFIED_FREQUENTLY flag... But looks like we only set that on
@@ -935,17 +785,17 @@ nsGenericDOMDataNode::ThreadSafeTextIsOn
 
     ++cp;
   }
 
   return true;
 }
 
 bool
-nsGenericDOMDataNode::HasTextForTranslation()
+CharacterData::HasTextForTranslation()
 {
   if (NodeType() != TEXT_NODE &&
       NodeType() != CDATA_SECTION_NODE) {
     return false;
   }
 
   if (mText.Is2b()) {
     // The fragment contains non-8bit characters which means there
@@ -975,36 +825,38 @@ nsGenericDOMDataNode::HasTextForTranslat
       return true;
     }
   }
 
   return false;
 }
 
 void
-nsGenericDOMDataNode::AppendTextTo(nsAString& aResult)
+CharacterData::AppendTextTo(nsAString& aResult)
 {
   mText.AppendTo(aResult);
 }
 
 bool
-nsGenericDOMDataNode::AppendTextTo(nsAString& aResult,
-                                   const mozilla::fallible_t& aFallible)
+CharacterData::AppendTextTo(nsAString& aResult,
+                            const mozilla::fallible_t& aFallible)
 {
   return mText.AppendTo(aResult, aFallible);
 }
 
 already_AddRefed<nsAtom>
-nsGenericDOMDataNode::GetCurrentValueAtom()
+CharacterData::GetCurrentValueAtom()
 {
   nsAutoString val;
   GetData(val);
   return NS_Atomize(val);
 }
 
 void
-nsGenericDOMDataNode::AddSizeOfExcludingThis(nsWindowSizes& aSizes,
-                                             size_t* aNodeSize) const
+CharacterData::AddSizeOfExcludingThis(nsWindowSizes& aSizes,
+                                      size_t* aNodeSize) const
 {
   nsIContent::AddSizeOfExcludingThis(aSizes, aNodeSize);
   *aNodeSize += mText.SizeOfExcludingThis(aSizes.mState.mMallocSizeOf);
 }
 
+} // namespace dom
+} // namespace mozilla
rename from dom/base/nsGenericDOMDataNode.h
rename to dom/base/CharacterData.h
--- a/dom/base/nsGenericDOMDataNode.h
+++ b/dom/base/CharacterData.h
@@ -1,131 +1,123 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /*
- * Base class for DOM Core's nsIDOMComment, DocumentType, nsIDOMText,
- * CDATASection, and nsIDOMProcessingInstruction nodes.
+ * Base class for DOM Core's Comment, DocumentType, Text,
+ * CDATASection, and ProcessingInstruction nodes.
  */
 
-#ifndef nsGenericDOMDataNode_h___
-#define nsGenericDOMDataNode_h___
+#ifndef mozilla_dom_CharacterData_h
+#define mozilla_dom_CharacterData_h
 
 #include "mozilla/Attributes.h"
 #include "nsIContent.h"
 
 #include "nsTextFragment.h"
 #include "nsError.h"
 #include "mozilla/dom/Element.h"
 #include "nsCycleCollectionParticipant.h"
 
 #include "nsISMILAttr.h"
 #include "mozilla/dom/ShadowRoot.h"
 
 class nsIDocument;
-class nsIDOMText;
 
 namespace mozilla {
 namespace dom {
 class HTMLSlotElement;
 } // namespace dom
 } // namespace mozilla
 
-#define DATA_NODE_FLAG_BIT(n_) NODE_FLAG_BIT(NODE_TYPE_SPECIFIC_BITS_OFFSET + (n_))
+#define CHARACTER_DATA_FLAG_BIT(n_) NODE_FLAG_BIT(NODE_TYPE_SPECIFIC_BITS_OFFSET + (n_))
 
 // Data node specific flags
 enum {
   // This bit is set to indicate that if the text node changes to
   // non-whitespace, we may need to create a frame for it. This bit must
   // not be set on nodes that already have a frame.
-  NS_CREATE_FRAME_IF_NON_WHITESPACE =     DATA_NODE_FLAG_BIT(0),
+  NS_CREATE_FRAME_IF_NON_WHITESPACE =     CHARACTER_DATA_FLAG_BIT(0),
 
   // This bit is set to indicate that if the text node changes to
   // whitespace, we may need to reframe it (or its ancestors).
-  NS_REFRAME_IF_WHITESPACE =              DATA_NODE_FLAG_BIT(1),
+  NS_REFRAME_IF_WHITESPACE =              CHARACTER_DATA_FLAG_BIT(1),
 
   // This bit is set to indicate that we have a cached
   // TextIsOnlyWhitespace value
-  NS_CACHED_TEXT_IS_ONLY_WHITESPACE =     DATA_NODE_FLAG_BIT(2),
+  NS_CACHED_TEXT_IS_ONLY_WHITESPACE =     CHARACTER_DATA_FLAG_BIT(2),
 
   // This bit is only meaningful if the NS_CACHED_TEXT_IS_ONLY_WHITESPACE
   // bit is set, and if so it indicates whether we're only whitespace or
   // not.
-  NS_TEXT_IS_ONLY_WHITESPACE =            DATA_NODE_FLAG_BIT(3),
+  NS_TEXT_IS_ONLY_WHITESPACE =            CHARACTER_DATA_FLAG_BIT(3),
 
   // This bit is set if there is a NewlineProperty attached to the node
   // (used by nsTextFrame).
-  NS_HAS_NEWLINE_PROPERTY =               DATA_NODE_FLAG_BIT(4),
+  NS_HAS_NEWLINE_PROPERTY =               CHARACTER_DATA_FLAG_BIT(4),
 
   // This bit is set if there is a FlowLengthProperty attached to the node
   // (used by nsTextFrame).
-  NS_HAS_FLOWLENGTH_PROPERTY =            DATA_NODE_FLAG_BIT(5),
+  NS_HAS_FLOWLENGTH_PROPERTY =            CHARACTER_DATA_FLAG_BIT(5),
 
   // This bit is set if the node may be modified frequently.  This is typically
   // specified if the instance is in <input> or <textarea>.
-  NS_MAYBE_MODIFIED_FREQUENTLY =          DATA_NODE_FLAG_BIT(6),
+  NS_MAYBE_MODIFIED_FREQUENTLY =          CHARACTER_DATA_FLAG_BIT(6),
 };
 
 // Make sure we have enough space for those bits
 ASSERT_NODE_FLAGS_SPACE(NODE_TYPE_SPECIFIC_BITS_OFFSET + 7);
 
-#undef DATA_NODE_FLAG_BIT
+#undef CHARACTER_DATA_FLAG_BIT
 
-class nsGenericDOMDataNode : public nsIContent
+namespace mozilla {
+namespace dom {
+
+class CharacterData : public nsIContent
 {
 public:
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
 
   NS_DECL_ADDSIZEOFEXCLUDINGTHIS
 
-  explicit nsGenericDOMDataNode(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo);
-  explicit nsGenericDOMDataNode(already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo);
+  explicit CharacterData(already_AddRefed<dom::NodeInfo>& aNodeInfo);
+  explicit CharacterData(already_AddRefed<dom::NodeInfo>&& aNodeInfo);
 
   void MarkAsMaybeModifiedFrequently()
   {
     SetFlags(NS_MAYBE_MODIFIED_FREQUENTLY);
   }
 
+  NS_IMPL_FROMCONTENT_HELPER(CharacterData, IsCharacterData())
+
   virtual void GetNodeValueInternal(nsAString& aNodeValue) override;
   virtual void SetNodeValueInternal(const nsAString& aNodeValue,
-                                    mozilla::ErrorResult& aError) override;
-
-  // Implementation for nsIDOMCharacterData
-  nsresult GetData(nsAString& aData) const;
-  nsresult SetData(const nsAString& aData);
-  nsresult GetLength(uint32_t* aLength);
-  nsresult SubstringData(uint32_t aOffset, uint32_t aCount,
-                         nsAString& aReturn);
-  nsresult AppendData(const nsAString& aArg);
-  nsresult InsertData(uint32_t aOffset, const nsAString& aArg);
-  nsresult DeleteData(uint32_t aOffset, uint32_t aCount);
-  nsresult ReplaceData(uint32_t aOffset, uint32_t aCount,
-                       const nsAString& aArg);
+                                    ErrorResult& aError) override;
 
   // nsINode methods
   virtual uint32_t GetChildCount() const override;
   virtual nsIContent *GetChildAt_Deprecated(uint32_t aIndex) const override;
   virtual int32_t ComputeIndexOf(const nsINode* aPossibleChild) const override;
   virtual nsresult InsertChildBefore(nsIContent* aKid, nsIContent* aBeforeThis,
                                      bool aNotify) override;
   virtual nsresult InsertChildAt_Deprecated(nsIContent* aKid, uint32_t aIndex,
                                             bool aNotify) override;
   virtual void RemoveChildAt_Deprecated(uint32_t aIndex, bool aNotify) override;
   virtual void RemoveChildNode(nsIContent* aKid, bool aNotify) override;
   virtual void GetTextContentInternal(nsAString& aTextContent,
-                                      mozilla::OOMReporter& aError) override
+                                      OOMReporter& aError) override
   {
     GetNodeValue(aTextContent);
   }
   virtual void SetTextContentInternal(const nsAString& aTextContent,
                                       nsIPrincipal* aSubjectPrincipal,
-                                      mozilla::ErrorResult& aError) override
+                                      ErrorResult& aError) override
   {
     // Batch possible DOMSubtreeModified events.
     mozAutoSubtreeModified subtree(OwnerDoc(), nullptr);
     return SetNodeValue(aTextContent, aError);
   }
 
   // Implementation for nsIContent
   virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
@@ -148,114 +140,91 @@ public:
   virtual nsresult AppendText(const char16_t* aBuffer, uint32_t aLength,
                               bool aNotify) override;
   virtual bool TextIsOnlyWhitespace() override;
   bool ThreadSafeTextIsOnlyWhitespace() const final;
   virtual bool HasTextForTranslation() override;
   virtual void AppendTextTo(nsAString& aResult) override;
   MOZ_MUST_USE
   virtual bool AppendTextTo(nsAString& aResult,
-                            const mozilla::fallible_t&) override;
+                            const fallible_t&) override;
   virtual void SaveSubtreeState() override;
 
 #ifdef DEBUG
   virtual void List(FILE* out, int32_t aIndent) const override;
   virtual void DumpContent(FILE* out, int32_t aIndent, bool aDumpAll) const override;
 #endif
 
   virtual nsXBLBinding* DoGetXBLBinding() const override;
   virtual bool IsNodeOfType(uint32_t aFlags) const override;
   virtual bool IsLink(nsIURI** aURI) const override;
 
-  virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult,
+  virtual nsresult Clone(dom::NodeInfo *aNodeInfo, nsINode **aResult,
                          bool aPreallocateChildren) const override
   {
-    nsCOMPtr<nsINode> result = CloneDataNode(aNodeInfo, true);
+    RefPtr<CharacterData> result = CloneDataNode(aNodeInfo, true);
     result.forget(aResult);
 
     if (!*aResult) {
       return NS_ERROR_OUT_OF_MEMORY;
     }
 
     return NS_OK;
   }
 
-  nsresult SplitData(uint32_t aOffset, nsIContent** aReturn,
-                     bool aCloneAfterOriginal = true);
-
   // WebIDL API
-  // Our XPCOM GetData is just fine for WebIDL
-  virtual void SetData(const nsAString& aData, mozilla::ErrorResult& rv)
-  {
-    rv = SetData(aData);
-  }
+  void GetData(nsAString& aData) const;
+  virtual void SetData(const nsAString& aData, ErrorResult& rv);
   // nsINode::Length() returns the right thing for our length attribute
   void SubstringData(uint32_t aStart, uint32_t aCount, nsAString& aReturn,
-                     mozilla::ErrorResult& rv);
-  void AppendData(const nsAString& aData, mozilla::ErrorResult& rv)
-  {
-    rv = AppendData(aData);
-  }
-  void InsertData(uint32_t aOffset, const nsAString& aData,
-                  mozilla::ErrorResult& rv)
-  {
-    rv = InsertData(aOffset, aData);
-  }
-  void DeleteData(uint32_t aOffset, uint32_t aCount, mozilla::ErrorResult& rv)
-  {
-    rv = DeleteData(aOffset, aCount);
-  }
+                     ErrorResult& rv);
+  void AppendData(const nsAString& aData, ErrorResult& rv);
+  void InsertData(uint32_t aOffset, const nsAString& aData, ErrorResult& rv);
+  void DeleteData(uint32_t aOffset, uint32_t aCount, ErrorResult& rv);
   void ReplaceData(uint32_t aOffset, uint32_t aCount, const nsAString& aData,
-                   mozilla::ErrorResult& rv)
-  {
-    rv = ReplaceData(aOffset, aCount, aData);
-  }
+                   ErrorResult& rv);
 
   uint32_t TextDataLength() const
   {
     return mText.GetLength();
   }
 
   //----------------------------------------
 
 #ifdef DEBUG
   void ToCString(nsAString& aBuf, int32_t aOffset, int32_t aLen) const;
 #endif
 
-  NS_DECL_CYCLE_COLLECTION_SKIPPABLE_SCRIPT_HOLDER_CLASS(nsGenericDOMDataNode)
+  NS_DECL_CYCLE_COLLECTION_SKIPPABLE_SCRIPT_HOLDER_CLASS(CharacterData)
 
 protected:
-  virtual ~nsGenericDOMDataNode();
+  virtual ~CharacterData();
 
-  virtual mozilla::dom::Element* GetNameSpaceElement() override
+  virtual Element* GetNameSpaceElement() override
   {
     nsINode *parent = GetParentNode();
 
     return parent && parent->IsElement() ? parent->AsElement() : nullptr;
   }
 
-  nsresult SplitText(uint32_t aOffset, nsIDOMText** aReturn);
-
-  nsresult GetWholeText(nsAString& aWholeText);
-
   nsresult SetTextInternal(uint32_t aOffset, uint32_t aCount,
                            const char16_t* aBuffer, uint32_t aLength,
                            bool aNotify,
                            CharacterDataChangeInfo::Details* aDetails = nullptr);
 
   /**
    * Method to clone this node. This needs to be overriden by all derived
    * classes. If aCloneText is true the text content will be cloned too.
    *
    * @param aOwnerDocument the ownerDocument of the clone
    * @param aCloneText if true the text content will be cloned too
    * @return the clone
    */
-  virtual nsGenericDOMDataNode *CloneDataNode(mozilla::dom::NodeInfo *aNodeInfo,
-                                              bool aCloneText) const = 0;
+  virtual already_AddRefed<CharacterData>
+    CloneDataNode(dom::NodeInfo *aNodeInfo, bool aCloneText) const = 0;
 
   nsTextFragment mText;
 
 public:
   virtual bool OwnedOnlyByTheDOMTree() override
   {
     return GetParent() && mRefCnt.get() == 1;
   }
@@ -268,9 +237,12 @@ public:
   {
     mRefCnt.RemovePurple();
   }
 
 private:
   already_AddRefed<nsAtom> GetCurrentValueAtom();
 };
 
-#endif /* nsGenericDOMDataNode_h___ */
+} // namespace dom
+} // namespace mozilla
+
+#endif /* mozilla_dom_CharacterData_h */
--- a/dom/base/Comment.cpp
+++ b/dom/base/Comment.cpp
@@ -1,16 +1,16 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /*
- * Implementations of DOM Core's nsIDOMComment node.
+ * Implementations of DOM Core's Comment node.
  */
 
 #include "nsCOMPtr.h"
 #include "mozilla/dom/Comment.h"
 #include "mozilla/dom/CommentBinding.h"
 #include "mozilla/IntegerPrintfMacros.h"
 
 using namespace mozilla;
@@ -18,35 +18,34 @@ using namespace dom;
 
 namespace mozilla {
 namespace dom {
 
 Comment::~Comment()
 {
 }
 
-NS_IMPL_ISUPPORTS_INHERITED(Comment, nsGenericDOMDataNode, nsIDOMNode,
-                            nsIDOMCharacterData, nsIDOMComment)
+NS_IMPL_ISUPPORTS_INHERITED(Comment, CharacterData, nsIDOMNode)
 
 bool
 Comment::IsNodeOfType(uint32_t aFlags) const
 {
   return !(aFlags & ~(eCOMMENT | eDATA_NODE));
 }
 
-nsGenericDOMDataNode*
+already_AddRefed<CharacterData>
 Comment::CloneDataNode(mozilla::dom::NodeInfo *aNodeInfo, bool aCloneText) const
 {
   RefPtr<mozilla::dom::NodeInfo> ni = aNodeInfo;
-  Comment *it = new Comment(ni.forget());
-  if (it && aCloneText) {
+  RefPtr<Comment> it = new Comment(ni.forget());
+  if (aCloneText) {
     it->mText = mText;
   }
 
-  return it;
+  return it.forget();
 }
 
 #ifdef DEBUG
 void
 Comment::List(FILE* out, int32_t aIndent) const
 {
   int32_t indx;
   for (indx = aIndent; --indx >= 0; ) fputs("  ", out);
--- a/dom/base/Comment.h
+++ b/dom/base/Comment.h
@@ -3,62 +3,56 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_Comment_h
 #define mozilla_dom_Comment_h
 
 #include "mozilla/Attributes.h"
-#include "nsIDOMComment.h"
-#include "nsGenericDOMDataNode.h"
+#include "mozilla/dom/CharacterData.h"
+#include "nsIDOMNode.h"
 
 namespace mozilla {
 namespace dom {
 
-class Comment final : public nsGenericDOMDataNode,
-                      public nsIDOMComment
+class Comment final : public CharacterData,
+                      public nsIDOMNode
 {
 private:
   void Init()
   {
     MOZ_ASSERT(mNodeInfo->NodeType() == COMMENT_NODE,
                "Bad NodeType in aNodeInfo");
   }
 
   virtual ~Comment();
 
 public:
   explicit Comment(already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo)
-    : nsGenericDOMDataNode(aNodeInfo)
+    : CharacterData(aNodeInfo)
   {
     Init();
   }
 
   explicit Comment(nsNodeInfoManager* aNodeInfoManager)
-    : nsGenericDOMDataNode(aNodeInfoManager->GetCommentNodeInfo())
+    : CharacterData(aNodeInfoManager->GetCommentNodeInfo())
   {
     Init();
   }
 
   // nsISupports
   NS_DECL_ISUPPORTS_INHERITED
 
-  // nsIDOMCharacterData
-  NS_FORWARD_NSIDOMCHARACTERDATA(nsGenericDOMDataNode::)
-  using nsGenericDOMDataNode::SetData; // Prevent hiding overloaded virtual function.
-
-  // nsIDOMComment
-  // Empty interface
-
   // nsINode
   virtual bool IsNodeOfType(uint32_t aFlags) const override;
 
-  virtual nsGenericDOMDataNode* CloneDataNode(mozilla::dom::NodeInfo *aNodeInfo,
-                                              bool aCloneText) const override;
+  virtual already_AddRefed<CharacterData>
+    CloneDataNode(mozilla::dom::NodeInfo *aNodeInfo,
+                  bool aCloneText) const override;
 
   virtual nsIDOMNode* AsDOMNode() override { return this; }
 #ifdef DEBUG
   virtual void List(FILE* out, int32_t aIndent) const override;
   virtual void DumpContent(FILE* out = stdout, int32_t aIndent = 0,
                            bool aDumpAll = true) const override
   {
     return;
--- a/dom/base/DOMMatrix.cpp
+++ b/dom/base/DOMMatrix.cpp
@@ -7,19 +7,21 @@
 #include "mozilla/dom/DOMMatrix.h"
 
 #include "mozilla/dom/BindingUtils.h"
 #include "mozilla/dom/DOMMatrixBinding.h"
 #include "mozilla/dom/DOMPoint.h"
 #include "mozilla/dom/DOMPointBinding.h"
 #include "mozilla/dom/BindingDeclarations.h"
 #include "mozilla/dom/ToJSValue.h"
+#include "mozilla/RuleNodeCacheConditions.h"
 #include "mozilla/ServoCSSParser.h"
 #include "nsCSSParser.h"
 #include "nsStyleTransformMatrix.h"
+#include "nsGlobalWindowInner.h"
 
 #include <math.h>
 
 namespace mozilla {
 namespace dom {
 
 static const double radPerDegree = 2.0 * M_PI / 360.0;
 
--- a/dom/base/DirectionalityUtils.cpp
+++ b/dom/base/DirectionalityUtils.cpp
@@ -195,17 +195,17 @@
 
   11. If the value of the @dir attribute on a bdi element is changed to an
   invalid value (or if it's removed), determine the new directionality similar
   to the case 3 above.
 
   == Implemention Notes ==
   When a new node gets bound to the tree, the BindToTree function gets called.
   The reverse case is UnbindFromTree.
-  When the contents of a text node change, nsGenericDOMDataNode::SetTextInternal
+  When the contents of a text node change, CharacterData::SetTextInternal
   gets called.
   */
 
 #include "mozilla/dom/DirectionalityUtils.h"
 
 #include "nsINode.h"
 #include "nsIContent.h"
 #include "nsIDocument.h"
--- a/dom/base/DocumentType.cpp
+++ b/dom/base/DocumentType.cpp
@@ -45,38 +45,38 @@ DocumentType::WrapNode(JSContext *cx, JS
 {
   return DocumentTypeBinding::Wrap(cx, this, aGivenProto);
 }
 
 DocumentType::DocumentType(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo,
                            const nsAString& aPublicId,
                            const nsAString& aSystemId,
                            const nsAString& aInternalSubset) :
-  nsGenericDOMDataNode(aNodeInfo),
+  CharacterData(aNodeInfo),
   mPublicId(aPublicId),
   mSystemId(aSystemId),
   mInternalSubset(aInternalSubset)
 {
   MOZ_ASSERT(mNodeInfo->NodeType() == DOCUMENT_TYPE_NODE,
              "Bad NodeType in aNodeInfo");
 }
 
 DocumentType::~DocumentType()
 {
 }
 
-NS_IMPL_ISUPPORTS_INHERITED(DocumentType, nsGenericDOMDataNode, nsIDOMNode)
+NS_IMPL_ISUPPORTS_INHERITED(DocumentType, CharacterData, nsIDOMNode)
 
 bool
 DocumentType::IsNodeOfType(uint32_t aFlags) const
 {
   // Don't claim to be eDATA_NODE since we're just inheriting
-  // nsGenericDOMDataNode for convinience. Doctypes aren't really
+  // CharacterData for convenience. Doctypes aren't really
   // data nodes (they have a null .nodeValue and don't implement
-  // nsIDOMCharacterData)
+  // the DOM CharacterData interface)
   return false;
 }
 
 const nsTextFragment*
 DocumentType::GetText()
 {
   return nullptr;
 }
@@ -100,18 +100,18 @@ DocumentType::GetSystemId(nsAString& aSy
 }
 
 void
 DocumentType::GetInternalSubset(nsAString& aInternalSubset) const
 {
   aInternalSubset = mInternalSubset;
 }
 
-nsGenericDOMDataNode*
+already_AddRefed<CharacterData>
 DocumentType::CloneDataNode(mozilla::dom::NodeInfo *aNodeInfo, bool aCloneText) const
 {
   already_AddRefed<mozilla::dom::NodeInfo> ni = RefPtr<mozilla::dom::NodeInfo>(aNodeInfo).forget();
-  return new DocumentType(ni, mPublicId, mSystemId, mInternalSubset);
+  return do_AddRef(new DocumentType(ni, mPublicId, mSystemId, mInternalSubset));
 }
 
 } // namespace dom
 } // namespace mozilla
 
--- a/dom/base/DocumentType.h
+++ b/dom/base/DocumentType.h
@@ -7,31 +7,31 @@
 /*
  * Implementation of DOM Core's DocumentType node.
  */
 
 #ifndef DocumentType_h
 #define DocumentType_h
 
 #include "mozilla/Attributes.h"
+#include "mozilla/dom/CharacterData.h"
 #include "nsCOMPtr.h"
 #include "nsIDOMNode.h"
 #include "nsIContent.h"
-#include "nsGenericDOMDataNode.h"
 #include "nsString.h"
 
 namespace mozilla {
 namespace dom {
 
 // XXX DocumentType is currently implemented by inheriting the generic
 // CharacterData object, even though DocumentType is not character
 // data. This is done simply for convenience and should be changed if
 // this restricts what should be done for character data.
 
-class DocumentType final : public nsGenericDOMDataNode,
+class DocumentType final : public CharacterData,
                            public nsIDOMNode
 {
 public:
   DocumentType(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo,
                const nsAString& aPublicId,
                const nsAString& aSystemId,
                const nsAString& aInternalSubset);
 
@@ -50,18 +50,19 @@ public:
   virtual void SetNodeValueInternal(const nsAString& aNodeValue,
                                     mozilla::ErrorResult& aError) override
   {
   }
 
   // nsIContent overrides
   virtual const nsTextFragment* GetText() override;
 
-  virtual nsGenericDOMDataNode* CloneDataNode(mozilla::dom::NodeInfo *aNodeInfo,
-                                              bool aCloneText) const override;
+  virtual already_AddRefed<CharacterData>
+    CloneDataNode(mozilla::dom::NodeInfo *aNodeInfo,
+                  bool aCloneText) const override;
 
   virtual nsIDOMNode* AsDOMNode() override { return this; }
 
   // WebIDL API
   void GetName(nsAString& aName) const;
   void GetPublicId(nsAString& aPublicId) const;
   void GetSystemId(nsAString& aSystemId) const;
   void GetInternalSubset(nsAString& aInternalSubset) const;
--- a/dom/base/Selection.cpp
+++ b/dom/base/Selection.cpp
@@ -37,18 +37,16 @@
 #include <algorithm>
 #include "nsContentUtils.h"
 
 #include "nsGkAtoms.h"
 #include "nsLayoutUtils.h"
 #include "nsBidiPresUtils.h"
 #include "nsTextFrame.h"
 
-#include "nsIDOMText.h"
-
 #include "nsContentUtils.h"
 #include "nsThreadUtils.h"
 
 #include "nsPresContext.h"
 #include "nsIPresShell.h"
 #include "nsCaret.h"
 
 #include "nsITimer.h"
--- a/dom/base/ShadowRoot.cpp
+++ b/dom/base/ShadowRoot.cpp
@@ -271,25 +271,28 @@ ShadowRoot::RuleChanged(StyleSheet&, css
 
 void
 ShadowRoot::ApplicableRulesChanged()
 {
   if (!IsComposedDocParticipant()) {
     return;
   }
 
+  if (!IsComposedDocParticipant()) {
+    return;
+  }
+
   nsIDocument* doc = OwnerDoc();
   if (nsIPresShell* shell = doc->GetShell()) {
     doc->BeginUpdate(UPDATE_STYLE);
     shell->RecordShadowStyleChange(*this);
     doc->EndUpdate(UPDATE_STYLE);
   }
 }
 
-
 void
 ShadowRoot::InsertSheetAt(size_t aIndex, StyleSheet& aSheet)
 {
   DocumentOrShadowRoot::InsertSheetAt(aIndex, aSheet);
   if (aSheet.IsApplicable()) {
     InsertSheetIntoAuthorData(aIndex, aSheet);
   }
 }
--- a/dom/base/Text.cpp
+++ b/dom/base/Text.cpp
@@ -1,29 +1,138 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/dom/Text.h"
 #include "nsTextNode.h"
+#include "mozAutoDocUpdate.h"
 
 namespace mozilla {
 namespace dom {
 
 already_AddRefed<Text>
-Text::SplitText(uint32_t aOffset, ErrorResult& rv)
+Text::SplitText(uint32_t aOffset, ErrorResult& aRv)
 {
-  nsCOMPtr<nsIContent> newChild;
-  rv = SplitData(aOffset, getter_AddRefs(newChild));
-  if (rv.Failed()) {
+  nsAutoString cutText;
+  uint32_t length = TextLength();
+
+  if (aOffset > length) {
+    aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
+    return nullptr;
+  }
+
+  uint32_t cutStartOffset = aOffset;
+  uint32_t cutLength = length - aOffset;
+  SubstringData(cutStartOffset, cutLength, cutText, aRv);
+  if (aRv.Failed()) {
+    return nullptr;
+  }
+
+  nsIDocument* document = GetComposedDoc();
+  mozAutoDocUpdate updateBatch(document, UPDATE_CONTENT_MODEL, true);
+
+  // Use Clone for creating the new node so that the new node is of same class
+  // as this node!
+  RefPtr<CharacterData> clone = CloneDataNode(mNodeInfo, false);
+  MOZ_ASSERT(clone && clone->IsText());
+  RefPtr<Text> newContent = static_cast<Text*>(clone.get());
+
+  // nsRange expects the CharacterDataChanged notification is followed
+  // by an insertion of |newContent|. If you change this code,
+  // make sure you make the appropriate changes in nsRange.
+  newContent->SetText(cutText, true); // XXX should be false?
+
+  CharacterDataChangeInfo::Details details = {
+    CharacterDataChangeInfo::Details::eSplit, newContent
+  };
+  nsresult rv = SetTextInternal(cutStartOffset, cutLength, nullptr, 0, true,
+                                &details);
+  if (NS_FAILED(rv)) {
+    aRv.Throw(rv);
     return nullptr;
   }
-  return newChild.forget().downcast<Text>();
+
+  nsCOMPtr<nsINode> parent = GetParentNode();
+  if (parent) {
+    nsCOMPtr<nsIContent> beforeNode = GetNextSibling();
+    parent->InsertChildBefore(newContent, beforeNode, true);
+  }
+
+  return newContent.forget();
+}
+
+static Text*
+FirstLogicallyAdjacentTextNode(Text* aNode)
+{
+  do {
+    nsIContent* sibling = aNode->GetPreviousSibling();
+    if (!sibling || !sibling->IsText()) {
+      return aNode;
+    }
+    aNode = static_cast<Text*>(sibling);
+  } while (1);  // Must run out of previous siblings eventually!
+}
+
+static Text*
+LastLogicallyAdjacentTextNode(Text* aNode)
+{
+  do {
+    nsIContent* sibling = aNode->GetNextSibling();
+    if (!sibling || !sibling->IsText()) {
+      return aNode;
+    }
+
+    aNode = static_cast<Text*>(sibling);
+  } while (1); // Must run out of next siblings eventually!
+}
+
+void
+Text::GetWholeText(nsAString& aWholeText,
+                   ErrorResult& aRv)
+{
+  nsIContent* parent = GetParent();
+
+  // Handle parent-less nodes
+  if (!parent) {
+    GetData(aWholeText);
+    return;
+  }
+
+  int32_t index = parent->ComputeIndexOf(this);
+  NS_WARNING_ASSERTION(index >= 0,
+                       "Trying to use .wholeText with an anonymous"
+                       "text node child of a binding parent?");
+  if (NS_WARN_IF(index < 0)) {
+    aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
+    return;
+  }
+
+  Text* first = FirstLogicallyAdjacentTextNode(this);
+  Text* last = LastLogicallyAdjacentTextNode(this);
+
+  aWholeText.Truncate();
+
+  nsAutoString tmp;
+
+  while (true) {
+    first->GetData(tmp);
+    aWholeText.Append(tmp);
+
+    if (first == last) {
+      break;
+    }
+
+    nsIContent* next = first->GetNextSibling();
+    MOZ_ASSERT(next && next->IsText(),
+               "How did we run out of text before hitting `last`?");
+    first = static_cast<Text*>(next);
+  }
 }
 
 /* static */ already_AddRefed<Text>
 Text::Constructor(const GlobalObject& aGlobal,
                   const nsAString& aData, ErrorResult& aRv)
 {
   nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(aGlobal.GetAsSupports());
   if (!window || !window->GetDoc()) {
--- a/dom/base/Text.h
+++ b/dom/base/Text.h
@@ -2,55 +2,50 @@
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_Text_h
 #define mozilla_dom_Text_h
 
-#include "nsGenericDOMDataNode.h"
+#include "mozilla/dom/CharacterData.h"
 #include "mozilla/ErrorResult.h"
 
 namespace mozilla {
 namespace dom {
 
-class Text : public nsGenericDOMDataNode
+class Text : public CharacterData
 {
 public:
   explicit Text(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
-    : nsGenericDOMDataNode(aNodeInfo)
+    : CharacterData(aNodeInfo)
   {}
 
   explicit Text(already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo)
-    : nsGenericDOMDataNode(aNodeInfo)
+    : CharacterData(aNodeInfo)
   {}
 
-  using nsGenericDOMDataNode::GetWholeText;
-
   // WebIDL API
   already_AddRefed<Text> SplitText(uint32_t aOffset, ErrorResult& rv);
-  void GetWholeText(nsAString& aWholeText, ErrorResult& rv)
-  {
-    rv = GetWholeText(aWholeText);
-  }
+  void GetWholeText(nsAString& aWholeText, ErrorResult& rv);
 
   static already_AddRefed<Text>
   Constructor(const GlobalObject& aGlobal,
               const nsAString& aData, ErrorResult& aRv);
 };
 
 } // namespace dom
 } // namespace mozilla
 
 inline mozilla::dom::Text* nsINode::GetAsText()
 {
-  return IsNodeOfType(eTEXT) ? static_cast<mozilla::dom::Text*>(this)
-                             : nullptr;
+  return IsText()  ? static_cast<mozilla::dom::Text*>(this)
+                   : nullptr;
 }
 
 inline const mozilla::dom::Text* nsINode::GetAsText() const
 {
-  return IsNodeOfType(eTEXT) ? static_cast<const mozilla::dom::Text*>(this)
-                             : nullptr;
+  return IsText() ? static_cast<const mozilla::dom::Text*>(this)
+                  : nullptr;
 }
 
 #endif // mozilla_dom_Text_h
--- a/dom/base/moz.build
+++ b/dom/base/moz.build
@@ -68,17 +68,16 @@ EXPORTS += [
     'nsDOMCID.h',
     'nsDOMClassInfoID.h',
     'nsDOMJSUtils.h',
     'nsDOMNavigationTiming.h',
     'nsDOMString.h',
     'nsDOMTokenList.h',
     'nsFocusManager.h',
     'nsFrameMessageManager.h',
-    'nsGenericDOMDataNode.h',
     'nsGlobalWindow.h',  # Because binding headers include it.
     'nsGlobalWindowInner.h',  # Because binding headers include it.
     'nsGlobalWindowOuter.h',  # Because binding headers include it.
     'nsIAnimationObserver.h',
     'nsIAttribute.h',
     'nsIContent.h',
     'nsIContentInlines.h',
     'nsIContentIterator.h',
@@ -148,16 +147,17 @@ EXPORTS.mozilla += [
 
 EXPORTS.mozilla.dom += [
     '!UseCounterList.h',
     'AnonymousContent.h',
     'Attr.h',
     'BarProps.h',
     'BodyUtil.h',
     'BorrowedAttrInfo.h',
+    'CharacterData.h',
     'ChildIterator.h',
     'ChromeNodeList.h',
     'ChromeUtils.h',
     'Comment.h',
     'CustomElementRegistry.h',
     'DirectionalityUtils.h',
     'DispatcherTrait.h',
     'DocGroup.h',
@@ -226,16 +226,17 @@ if CONFIG['FUZZING']:
     ]
 
 UNIFIED_SOURCES += [
     'AnonymousContent.cpp',
     'Attr.cpp',
     'BarProps.cpp',
     'BodyUtil.cpp',
     'BorrowedAttrInfo.cpp',
+    'CharacterData.cpp',
     'ChildIterator.cpp',
     'ChromeNodeList.cpp',
     'ChromeUtils.cpp',
     'Comment.cpp',
     'Crypto.cpp',
     'CustomElementRegistry.cpp',
     'DirectionalityUtils.cpp',
     'DispatcherTrait.cpp',
@@ -291,17 +292,16 @@ UNIFIED_SOURCES += [
     'nsDOMMutationObserver.cpp',
     'nsDOMNavigationTiming.cpp',
     'nsDOMSerializer.cpp',
     'nsDOMTokenList.cpp',
     'nsDOMWindowList.cpp',
     'nsFocusManager.cpp',
     'nsFrameLoader.cpp',
     'nsGenConImageContent.cpp',
-    'nsGenericDOMDataNode.cpp',
     'nsGlobalWindowCommands.cpp',
     'nsHistory.cpp',
     'nsHTMLContentSerializer.cpp',
     'nsIGlobalObject.cpp',
     'nsINode.cpp',
     'nsInProcessTabChildGlobal.cpp',
     'nsJSEnvironment.cpp',
     'nsJSTimeoutHandler.cpp',
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -6710,18 +6710,22 @@ nsContentUtils::DispatchXULCommand(nsICo
 {
   NS_ENSURE_STATE(aTarget);
   nsIDocument* doc = aTarget->OwnerDoc();
   nsPresContext* presContext = doc->GetPresContext();
 
   RefPtr<XULCommandEvent> xulCommand = new XULCommandEvent(doc, presContext,
                                                            nullptr);
   xulCommand->InitCommandEvent(NS_LITERAL_STRING("command"), true, true,
-                               doc->GetInnerWindow(), 0, aCtrl, aAlt, aShift,
-                               aMeta, aSourceEvent, aInputSource);
+                               nsGlobalWindowInner::Cast(doc->GetInnerWindow()),
+                               0, aCtrl, aAlt, aShift,
+                               aMeta,
+                               aSourceEvent ?
+                                 aSourceEvent->InternalDOMEvent() : nullptr,
+                               aInputSource, IgnoreErrors());
 
   if (aShell) {
     nsEventStatus status = nsEventStatus_eIgnore;
     nsCOMPtr<nsIPresShell> kungFuDeathGrip = aShell;
     return aShell->HandleDOMEventWithTarget(aTarget, xulCommand, &status);
   }
 
   nsCOMPtr<EventTarget> target = do_QueryInterface(aTarget);
--- a/dom/base/nsContentUtils.h
+++ b/dom/base/nsContentUtils.h
@@ -2108,17 +2108,17 @@ public:
                                  nsACString& aOrigin);
   static nsresult GetASCIIOrigin(nsIURI* aURI, nsACString& aOrigin);
   static nsresult GetUTFOrigin(nsIPrincipal* aPrincipal,
                                nsAString& aOrigin);
   static nsresult GetUTFOrigin(nsIURI* aURI, nsAString& aOrigin);
 
   /**
    * This method creates and dispatches "command" event, which implements
-   * nsIDOMXULCommandEvent.
+   * XULCommandEvent.
    * If aShell is not null, dispatching goes via
    * nsIPresShell::HandleDOMEventWithTarget.
    */
   static nsresult DispatchXULCommand(nsIContent* aTarget,
                                      bool aTrusted,
                                      nsIDOMEvent* aSourceEvent = nullptr,
                                      nsIPresShell* aShell = nullptr,
                                      bool aCtrl = false,
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -68,18 +68,16 @@
 #include "mozilla/dom/ProcessingInstruction.h"
 #include "nsDOMString.h"
 #include "nsNodeUtils.h"
 #include "nsLayoutUtils.h" // for GetFrameForPoint
 #include "nsIFrame.h"
 #include "nsITabChild.h"
 
 #include "nsRange.h"
-#include "nsIDOMText.h"
-#include "nsIDOMComment.h"
 #include "mozilla/dom/DocumentType.h"
 #include "mozilla/dom/NodeIterator.h"
 #include "mozilla/dom/Promise.h"
 #include "mozilla/dom/PromiseNativeHandler.h"
 #include "mozilla/dom/TreeWalker.h"
 
 #include "nsIServiceManager.h"
 #include "mozilla/dom/ServiceWorkerManager.h"
--- a/dom/base/nsDocumentEncoder.cpp
+++ b/dom/base/nsDocumentEncoder.cpp
@@ -16,19 +16,16 @@
 #include "nsISupports.h"
 #include "nsIDocument.h"
 #include "nsIHTMLDocument.h"
 #include "nsCOMPtr.h"
 #include "nsIContentSerializer.h"
 #include "mozilla/Encoding.h"
 #include "nsIOutputStream.h"
 #include "nsIDOMElement.h"
-#include "nsIDOMText.h"
-#include "nsIDOMComment.h"
-#include "nsIDOMProcessingInstruction.h"
 #include "nsIDOMNodeList.h"
 #include "nsRange.h"
 #include "nsIDOMRange.h"
 #include "nsIDOMDocument.h"
 #include "nsGkAtoms.h"
 #include "nsIContent.h"
 #include "nsIScriptContext.h"
 #include "nsIScriptGlobalObject.h"
@@ -39,19 +36,22 @@
 #include "nsContentUtils.h"
 #include "nsElementTable.h"
 #include "nsNodeUtils.h"
 #include "nsUnicharUtils.h"
 #include "nsReadableUtils.h"
 #include "nsTArray.h"
 #include "nsIFrame.h"
 #include "nsStringBuffer.h"
+#include "mozilla/dom/Comment.h"
 #include "mozilla/dom/DocumentType.h"
 #include "mozilla/dom/Element.h"
+#include "mozilla/dom/ProcessingInstruction.h"
 #include "mozilla/dom/ShadowRoot.h"
+#include "mozilla/dom/Text.h"
 #include "nsLayoutUtils.h"
 #include "mozilla/ScopeExit.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 nsresult NS_NewDomSelection(nsISelection **aDomSelection);
 
@@ -413,23 +413,23 @@ nsDocumentEncoder::SerializeNodeStart(ns
     case nsINode::CDATA_SECTION_NODE:
     {
       mSerializer->AppendCDATASection(static_cast<nsIContent*>(node),
                                       aStartOffset, aEndOffset, aStr);
       break;
     }
     case nsINode::PROCESSING_INSTRUCTION_NODE:
     {
-      mSerializer->AppendProcessingInstruction(static_cast<nsIContent*>(node),
+      mSerializer->AppendProcessingInstruction(static_cast<ProcessingInstruction*>(node),
                                                aStartOffset, aEndOffset, aStr);
       break;
     }
     case nsINode::COMMENT_NODE:
     {
-      mSerializer->AppendComment(static_cast<nsIContent*>(node),
+      mSerializer->AppendComment(static_cast<Comment*>(node),
                                  aStartOffset, aEndOffset, aStr);
       break;
     }
     case nsINode::DOCUMENT_TYPE_NODE:
     {
       mSerializer->AppendDoctype(static_cast<DocumentType*>(node), aStr);
       break;
     }
@@ -1595,27 +1595,26 @@ nsHTMLCopyEncoder::GetPromotedPoint(Endp
 
   if (common == node)
     return NS_OK;
 
   if (aWhere == kStart)
   {
     // some special casing for text nodes
     nsCOMPtr<nsINode> t = do_QueryInterface(aNode);
-    if (IsTextNode(t))
+    if (auto nodeAsText = t->GetAsText())
     {
       // if not at beginning of text node, we are done
       if (offset >  0)
       {
         // unless everything before us in just whitespace.  NOTE: we need a more
         // general solution that truly detects all cases of non-significant
         // whitesace with no false alarms.
-        nsCOMPtr<nsIDOMCharacterData> nodeAsText = do_QueryInterface(aNode);
         nsAutoString text;
-        nodeAsText->SubstringData(0, offset, text);
+        nodeAsText->SubstringData(0, offset, text, IgnoreErrors());
         text.CompressWhitespace();
         if (!text.IsEmpty())
           return NS_OK;
         bResetPromotion = true;
       }
       // else
       rv = GetNodeLocation(aNode, address_of(parent), &offset);
       NS_ENSURE_SUCCESS(rv, rv);
@@ -1671,28 +1670,27 @@ nsHTMLCopyEncoder::GetPromotedPoint(Endp
       return rv;
     }
   }
 
   if (aWhere == kEnd)
   {
     // some special casing for text nodes
     nsCOMPtr<nsINode> n = do_QueryInterface(aNode);
-    if (IsTextNode(n))
+    if (auto nodeAsText = n->GetAsText())
     {
       // if not at end of text node, we are done
       uint32_t len = n->Length();
       if (offset < (int32_t)len)
       {
         // unless everything after us in just whitespace.  NOTE: we need a more
         // general solution that truly detects all cases of non-significant
         // whitespace with no false alarms.
-        nsCOMPtr<nsIDOMCharacterData> nodeAsText = do_QueryInterface(aNode);
         nsAutoString text;
-        nodeAsText->SubstringData(offset, len-offset, text);
+        nodeAsText->SubstringData(offset, len-offset, text, IgnoreErrors());
         text.CompressWhitespace();
         if (!text.IsEmpty())
           return NS_OK;
         bResetPromotion = true;
       }
       rv = GetNodeLocation(aNode, address_of(parent), &offset);
       NS_ENSURE_SUCCESS(rv, rv);
     }
--- a/dom/base/nsIContent.h
+++ b/dom/base/nsIContent.h
@@ -1004,29 +1004,29 @@ NS_DEFINE_STATIC_IID_ACCESSOR(nsIContent
 
 inline nsIContent* nsINode::AsContent()
 {
   MOZ_ASSERT(IsContent());
   return static_cast<nsIContent*>(this);
 }
 
 #define NS_IMPL_FROMCONTENT_HELPER(_class, _check)                             \
-  static _class* FromContent(nsIContent* aContent)                             \
+  static _class* FromContent(nsINode* aContent)                                \
   {                                                                            \
     return aContent->_check ? static_cast<_class*>(aContent) : nullptr;        \
   }                                                                            \
-  static const _class* FromContent(const nsIContent* aContent)                 \
+  static const _class* FromContent(const nsINode* aContent)                    \
   {                                                                            \
     return aContent->_check ? static_cast<const _class*>(aContent) : nullptr;  \
   }                                                                            \
-  static _class* FromContentOrNull(nsIContent* aContent)                       \
+  static _class* FromContentOrNull(nsINode* aContent)                          \
   {                                                                            \
     return aContent ? FromContent(aContent) : nullptr;                         \
   }                                                                            \
-  static const _class* FromContentOrNull(const nsIContent* aContent)           \
+  static const _class* FromContentOrNull(const nsINode* aContent)              \
   {                                                                            \
     return aContent ? FromContent(aContent) : nullptr;                         \
   }
 
 #define NS_IMPL_FROMCONTENT(_class, _nsid)                                     \
   NS_IMPL_FROMCONTENT_HELPER(_class, IsInNamespace(_nsid))
 
 #define NS_IMPL_FROMCONTENT_WITH_TAG(_class, _nsid, _tag)                      \
--- a/dom/base/nsIContentSerializer.h
+++ b/dom/base/nsIContentSerializer.h
@@ -11,18 +11,20 @@
 #include "nsStringFwd.h"
 
 class nsIContent;
 class nsIDocument;
 
 namespace mozilla {
 class Encoding;
 namespace dom {
+class Comment;
 class DocumentType;
 class Element;
+class ProcessingInstruction;
 } // namespace dom
 } // namespace mozilla
 
 #define NS_ICONTENTSERIALIZER_IID \
 { 0xb1ee32f2, 0xb8c4, 0x49b9, \
   { 0x93, 0xdf, 0xb6, 0xfa, 0xb5, 0xd5, 0x46, 0x88 } }
 
 class nsIContentSerializer : public nsISupports {
@@ -39,22 +41,23 @@ class nsIContentSerializer : public nsIS
 
   NS_IMETHOD AppendText(nsIContent* aText, int32_t aStartOffset,
                         int32_t aEndOffset, nsAString& aStr) = 0;
 
   NS_IMETHOD AppendCDATASection(nsIContent* aCDATASection,
                                 int32_t aStartOffset, int32_t aEndOffset,
                                 nsAString& aStr) = 0;
 
-  NS_IMETHOD AppendProcessingInstruction(nsIContent* aPI,
+  NS_IMETHOD AppendProcessingInstruction(mozilla::dom::ProcessingInstruction* aPI,
                                          int32_t aStartOffset,
                                          int32_t aEndOffset,
                                          nsAString& aStr) = 0;
 
-  NS_IMETHOD AppendComment(nsIContent* aComment, int32_t aStartOffset,
+  NS_IMETHOD AppendComment(mozilla::dom::Comment* aComment,
+                           int32_t aStartOffset,
                            int32_t aEndOffset, nsAString& aStr) = 0;
 
   NS_IMETHOD AppendDoctype(mozilla::dom::DocumentType* aDoctype,
                            nsAString& aStr) = 0;
 
   NS_IMETHOD AppendElementStart(mozilla::dom::Element* aElement,
                                 mozilla::dom::Element* aOriginalElement,
                                 nsAString& aStr) = 0;
--- a/dom/base/nsINode.cpp
+++ b/dom/base/nsINode.cpp
@@ -2380,32 +2380,16 @@ nsINode::UnbindObject(nsISupports* aObje
 {
   nsCOMArray<nsISupports>* objects =
     static_cast<nsCOMArray<nsISupports>*>(GetProperty(nsGkAtoms::keepobjectsalive));
   if (objects) {
     objects->RemoveObject(aObject);
   }
 }
 
-void
-nsINode::GetBoundMutationObservers(nsTArray<RefPtr<nsDOMMutationObserver> >& aResult)
-{
-  nsCOMArray<nsISupports>* objects =
-    static_cast<nsCOMArray<nsISupports>*>(GetProperty(nsGkAtoms::keepobjectsalive));
-  if (objects) {
-    for (int32_t i = 0; i < objects->Count(); ++i) {
-      nsCOMPtr<nsDOMMutationObserver> mo = do_QueryInterface(objects->ObjectAt(i));
-      if (mo) {
-        MOZ_ASSERT(!aResult.Contains(mo));
-        aResult.AppendElement(mo.forget());
-      }
-    }
-  }
-}
-
 already_AddRefed<AccessibleNode>
 nsINode::GetAccessibleNode()
 {
 #ifdef ACCESSIBILITY
   RefPtr<AccessibleNode> anode = new AccessibleNode(this);
   return anode.forget();
 #else
   return nullptr;
--- a/dom/base/nsINode.h
+++ b/dom/base/nsINode.h
@@ -401,18 +401,17 @@ public:
     /** xml processing instructions */
     ePROCESSING_INSTRUCTION = 1 << 4,
     /** comment nodes */
     eCOMMENT             = 1 << 5,
     /** form control elements */
     eHTML_FORM_CONTROL   = 1 << 6,
     /** document fragments */
     eDOCUMENT_FRAGMENT   = 1 << 7,
-    /** data nodes (comments, PIs, text). Nodes of this type always
-     returns a non-null value for nsIContent::GetText() */
+    /** character data nodes (comments, PIs, text). */
     eDATA_NODE           = 1 << 8,
     /** HTMLMediaElement */
     eMEDIA               = 1 << 9,
     /** animation elements */
     eANIMATION           = 1 << 10,
     /** filter elements that implement SVGFilterPrimitiveStandardAttributes */
     eFILTER              = 1 << 11,
     /** SVGGeometryElement */
@@ -494,23 +493,54 @@ public:
    * IsContent() is true.  This is defined inline in nsIContent.h.
    */
   nsIContent* AsContent();
   const nsIContent* AsContent() const
   {
     return const_cast<nsINode*>(this)->AsContent();
   }
 
+  /*
+   * Return whether the node is a Text node (which might be an actual
+   * textnode, or might be a CDATA section).
+   */
+  bool IsText() const
+  {
+    uint32_t nodeType = NodeType();
+    return nodeType == TEXT_NODE || nodeType == CDATA_SECTION_NODE;
+  }
+
   /**
    * Return this node as Text if it is one, otherwise null.  This is defined
    * inline in Text.h.
    */
   mozilla::dom::Text* GetAsText();
   const mozilla::dom::Text* GetAsText() const;
 
+  /*
+   * Return whether the node is a ProcessingInstruction node.
+   */
+  bool IsProcessingInstruction() const
+  {
+    return NodeType() == PROCESSING_INSTRUCTION_NODE;
+  }
+
+  /*
+   * Return whether the node is a CharacterData node (text, cdata,
+   * comment, processing instruction)
+   */
+  bool IsCharacterData() const
+  {
+    uint32_t nodeType = NodeType();
+    return nodeType == TEXT_NODE ||
+           nodeType == CDATA_SECTION_NODE ||
+           nodeType == PROCESSING_INSTRUCTION_NODE ||
+           nodeType == COMMENT_NODE;
+  }
+
   virtual nsIDOMNode* AsDOMNode() = 0;
 
   /**
    * Return if this node has any children.
    */
   bool HasChildren() const { return !!mFirstChild; }
 
   /**
@@ -1746,17 +1776,16 @@ protected:
 
 public:
   // Makes nsINode object to keep aObject alive.
   void BindObject(nsISupports* aObject);
   // After calling UnbindObject nsINode object doesn't keep
   // aObject alive anymore.
   void UnbindObject(nsISupports* aObject);
 
-  void GetBoundMutationObservers(nsTArray<RefPtr<nsDOMMutationObserver> >& aResult);
   void GenerateXPath(nsAString& aResult);
 
   already_AddRefed<mozilla::dom::Promise>
   Localize(JSContext* aCx, mozilla::dom::L10nCallback& aCallback, mozilla::ErrorResult& aRv);
 
   already_AddRefed<mozilla::dom::AccessibleNode> GetAccessibleNode();
 
   /**
--- a/dom/base/nsPlainTextSerializer.h
+++ b/dom/base/nsPlainTextSerializer.h
@@ -50,22 +50,29 @@ public:
                   bool aIsWholeDocument,
                   bool* aNeedsPreformatScanning) override;
 
   NS_IMETHOD AppendText(nsIContent* aText, int32_t aStartOffset,
                         int32_t aEndOffset, nsAString& aStr) override;
   NS_IMETHOD AppendCDATASection(nsIContent* aCDATASection,
                                 int32_t aStartOffset, int32_t aEndOffset,
                                 nsAString& aStr) override;
-  NS_IMETHOD AppendProcessingInstruction(nsIContent* aPI,
+  NS_IMETHOD AppendProcessingInstruction(mozilla::dom::ProcessingInstruction* aPI,
                                          int32_t aStartOffset,
                                          int32_t aEndOffset,
-                                         nsAString& aStr) override  { return NS_OK; }
-  NS_IMETHOD AppendComment(nsIContent* aComment, int32_t aStartOffset,
-                           int32_t aEndOffset, nsAString& aStr) override  { return NS_OK; }
+                                         nsAString& aStr) override
+  {
+    return NS_OK;
+  }
+  NS_IMETHOD AppendComment(mozilla::dom::Comment* aComment,
+                           int32_t aStartOffset,
+                           int32_t aEndOffset, nsAString& aStr) override
+  {
+    return NS_OK;
+  }
   NS_IMETHOD AppendDoctype(mozilla::dom::DocumentType* aDoctype,
                            nsAString& aStr) override  { return NS_OK; }
   NS_IMETHOD AppendElementStart(mozilla::dom::Element* aElement,
                                 mozilla::dom::Element* aOriginalElement,
                                 nsAString& aStr) override;
   NS_IMETHOD AppendElementEnd(mozilla::dom::Element* aElement,
                               nsAString& aStr) override;
   NS_IMETHOD Flush(nsAString& aStr) override;
--- a/dom/base/nsRange.cpp
+++ b/dom/base/nsRange.cpp
@@ -12,31 +12,31 @@
 #include "nsRange.h"
 
 #include "nsString.h"
 #include "nsReadableUtils.h"
 #include "nsIDOMNode.h"
 #include "nsIDOMDocumentFragment.h"
 #include "nsIContent.h"
 #include "nsIDocument.h"
-#include "nsIDOMText.h"
 #include "nsError.h"
 #include "nsIContentIterator.h"
 #include "nsINodeList.h"
 #include "nsGkAtoms.h"
 #include "nsContentUtils.h"
-#include "nsGenericDOMDataNode.h"
 #include "nsTextFrame.h"
+#include "mozilla/dom/CharacterData.h"
 #include "mozilla/dom/DocumentFragment.h"
 #include "mozilla/dom/DocumentType.h"
 #include "mozilla/dom/RangeBinding.h"
 #include "mozilla/dom/DOMRect.h"
 #include "mozilla/dom/DOMStringList.h"
 #include "mozilla/dom/ShadowRoot.h"
 #include "mozilla/dom/Selection.h"
+#include "mozilla/dom/Text.h"
 #include "mozilla/Telemetry.h"
 #include "mozilla/Likely.h"
 #include "nsCSSFrameConstructor.h"
 #include "nsStyleStruct.h"
 #include "nsStyleStructInlines.h"
 #include "nsComputedDOMStyle.h"
 #include "mozilla/dom/InspectorFontFace.h"
 
@@ -1892,31 +1892,31 @@ RangeSubtreeIterator::Init(nsRange *aRan
   // Grab the start point of the range and QI it to
   // a CharacterData pointer. If it is CharacterData store
   // a pointer to the node.
 
   ErrorResult rv;
   nsCOMPtr<nsINode> node = aRange->GetStartContainer(rv);
   if (!node) return NS_ERROR_FAILURE;
 
-  nsCOMPtr<nsIDOMCharacterData> startData = do_QueryInterface(node);
-  if (startData || (node->IsElement() &&
-                    node->AsElement()->GetChildCount() == aRange->GetStartOffset(rv))) {
+  if (node->IsCharacterData() ||
+      (node->IsElement() &&
+       node->AsElement()->GetChildCount() == aRange->GetStartOffset(rv))) {
     mStart = node;
   }
 
   // Grab the end point of the range and QI it to
   // a CharacterData pointer. If it is CharacterData store
   // a pointer to the node.
 
   node = aRange->GetEndContainer(rv);
   if (!node) return NS_ERROR_FAILURE;
 
-  nsCOMPtr<nsIDOMCharacterData> endData = do_QueryInterface(node);
-  if (endData || (node->IsElement() && aRange->GetEndOffset(rv) == 0)) {
+  if (node->IsCharacterData() ||
+      (node->IsElement() && aRange->GetEndOffset(rv) == 0)) {
     mEnd = node;
   }
 
   if (mStart && mStart == mEnd)
   {
     // The range starts and stops in the same CharacterData
     // node. Null out the end pointer so we only visit the
     // node once!
@@ -2166,18 +2166,17 @@ ValidateCurrentNode(nsRange* aRange, Ran
     // e.g., the iterator is done.
     return true;
   }
 
   nsresult res = nsRange::CompareNodeToRange(node, aRange, &before, &after);
   NS_ENSURE_SUCCESS(res, false);
 
   if (before || after) {
-    nsCOMPtr<nsIDOMCharacterData> charData = do_QueryInterface(node);
-    if (charData) {
+    if (node->IsCharacterData()) {
       // If we're dealing with the start/end container which is a character
       // node, pretend that the node is in the range.
       if (before && node == aRange->GetStartContainer()) {
         before = false;
       }
       if (after && node == aRange->GetEndContainer()) {
         after = false;
       }
@@ -2284,136 +2283,141 @@ nsRange::CutContents(DocumentFragment** 
     handled = false;
 
     // If it's CharacterData, make sure we might need to delete
     // part of the data, instead of removing the whole node.
     //
     // XXX_kin: We need to also handle ProcessingInstruction
     // XXX_kin: according to the spec.
 
-    nsCOMPtr<nsIDOMCharacterData> charData(do_QueryInterface(node));
-
-    if (charData)
-    {
+    if (auto charData = CharacterData::FromContent(node)) {
       uint32_t dataLength = 0;
 
-      if (node == startContainer)
-      {
-        if (node == endContainer)
-        {
+      if (node == startContainer) {
+        if (node == endContainer) {
           // This range is completely contained within a single text node.
           // Delete or extract the data between startOffset and endOffset.
 
-          if (endOffset > startOffset)
-          {
+          if (endOffset > startOffset) {
             if (retval) {
               nsAutoString cutValue;
-              rv = charData->SubstringData(startOffset, endOffset - startOffset,
-                                           cutValue);
-              NS_ENSURE_SUCCESS(rv, rv);
               ErrorResult err;
+              charData->SubstringData(startOffset, endOffset - startOffset,
+                                      cutValue, err);
+              if (NS_WARN_IF(err.Failed())) {
+                return err.StealNSResult();
+              }
               nsCOMPtr<nsINode> clone = node->CloneNode(false, err);
               if (NS_WARN_IF(err.Failed())) {
                 return err.StealNSResult();
               }
               clone->SetNodeValue(cutValue, err);
               if (NS_WARN_IF(err.Failed())) {
                 return err.StealNSResult();
               }
               nodeToResult = clone;
             }
 
             nsMutationGuard guard;
-            rv = charData->DeleteData(startOffset, endOffset - startOffset);
-            NS_ENSURE_SUCCESS(rv, rv);
+            ErrorResult err;
+            charData->DeleteData(startOffset, endOffset - startOffset, err);
+            if (NS_WARN_IF(err.Failed())) {
+              return err.StealNSResult();
+            }
             NS_ENSURE_STATE(!guard.Mutated(0) ||
                             ValidateCurrentNode(this, iter));
           }
 
           handled = true;
         }
-        else
-        {
+        else  {
           // Delete or extract everything after startOffset.
 
-          rv = charData->GetLength(&dataLength);
-          NS_ENSURE_SUCCESS(rv, rv);
+          dataLength = charData->Length();
 
           if (dataLength >= startOffset) {
             if (retval) {
               nsAutoString cutValue;
-              rv = charData->SubstringData(startOffset, dataLength, cutValue);
-              NS_ENSURE_SUCCESS(rv, rv);
               ErrorResult err;
+              charData->SubstringData(startOffset, dataLength, cutValue, err);
+              if (NS_WARN_IF(err.Failed())) {
+                return err.StealNSResult();
+              }
               nsCOMPtr<nsINode> clone = node->CloneNode(false, err);
               if (NS_WARN_IF(err.Failed())) {
                 return err.StealNSResult();
               }
               clone->SetNodeValue(cutValue, err);
               if (NS_WARN_IF(err.Failed())) {
                 return err.StealNSResult();
               }
               nodeToResult = clone;
             }
 
             nsMutationGuard guard;
-            rv = charData->DeleteData(startOffset, dataLength);
+            ErrorResult err;
+            charData->DeleteData(startOffset, dataLength, err);
+            if (NS_WARN_IF(err.Failed())) {
+              return err.StealNSResult();
+            }
             NS_ENSURE_SUCCESS(rv, rv);
             NS_ENSURE_STATE(!guard.Mutated(0) ||
                             ValidateCurrentNode(this, iter));
           }
 
           handled = true;
         }
       }
-      else if (node == endContainer)
-      {
+      else if (node == endContainer) {
         // Delete or extract everything before endOffset.
         if (retval) {
           nsAutoString cutValue;
-          rv = charData->SubstringData(0, endOffset, cutValue);
-          NS_ENSURE_SUCCESS(rv, rv);
           ErrorResult err;
+          charData->SubstringData(0, endOffset, cutValue, err);
+          if (NS_WARN_IF(err.Failed())) {
+            return err.StealNSResult();
+          }
           nsCOMPtr<nsINode> clone = node->CloneNode(false, err);
           if (NS_WARN_IF(err.Failed())) {
             return err.StealNSResult();
           }
           clone->SetNodeValue(cutValue, err);
           if (NS_WARN_IF(err.Failed())) {
             return err.StealNSResult();
           }
           nodeToResult = clone;
         }
 
         nsMutationGuard guard;
-        rv = charData->DeleteData(0, endOffset);
-        NS_ENSURE_SUCCESS(rv, rv);
+        ErrorResult err;
+        charData->DeleteData(0, endOffset, err);
+        if (NS_WARN_IF(err.Failed())) {
+          return err.StealNSResult();
+        }
         NS_ENSURE_STATE(!guard.Mutated(0) ||
                         ValidateCurrentNode(this, iter));
         handled = true;
       }
     }
 
-    if (!handled && (node == endContainer || node == startContainer))
-    {
+    if (!handled && (node == endContainer || node == startContainer)) {
       if (node && node->IsElement() &&
           ((node == endContainer && endOffset == 0) ||
            (node == startContainer &&
             node->AsElement()->GetChildCount() == startOffset))) {
         if (retval) {
           ErrorResult rv;
           nodeToResult = node->CloneNode(false, rv);
           NS_ENSURE_TRUE(!rv.Failed(), rv.StealNSResult());
         }
         handled = true;
       }
     }
 
-    if (!handled)
-    {
+    if (!handled) {
       // node was not handled above, so it must be completely contained
       // within the range. Just remove it from the tree!
       nodeToResult = node;
     }
 
     uint32_t parentCount = 0;
     // Set the result to document fragment if we have 'retval'.
     if (retval) {
@@ -2423,34 +2427,32 @@ nsRange::CutContents(DocumentFragment** 
         NS_ENSURE_STATE(nextNode);
 
         // Get node's and nextNode's common parent. Do this before moving
         // nodes from original DOM to result fragment.
         commonAncestor = nsContentUtils::GetCommonAncestor(node, nextNode);
         NS_ENSURE_STATE(commonAncestor);
 
         nsCOMPtr<nsINode> parentCounterNode = node;
-        while (parentCounterNode && parentCounterNode != commonAncestor)
-        {
+        while (parentCounterNode && parentCounterNode != commonAncestor) {
           ++parentCount;
           parentCounterNode = parentCounterNode->GetParentNode();
           NS_ENSURE_STATE(parentCounterNode);
         }
       }
 
       // Clone the parent hierarchy between commonAncestor and node.
       nsCOMPtr<nsINode> closestAncestor, farthestAncestor;
       rv = CloneParentsBetween(oldCommonAncestor, node,
                                getter_AddRefs(closestAncestor),
                                getter_AddRefs(farthestAncestor));
       NS_ENSURE_SUCCESS(rv, rv);
 
       ErrorResult res;
-      if (farthestAncestor)
-      {
+      if (farthestAncestor) {
         nsCOMPtr<nsINode> n = do_QueryInterface(commonCloneAncestor);
         n->AppendChild(*farthestAncestor, res);
         res.WouldReportJSException();
         if (NS_WARN_IF(res.Failed())) {
           return res.StealNSResult();
         }
       }
 
@@ -2478,18 +2480,17 @@ nsRange::CutContents(DocumentFragment** 
       }
       NS_ENSURE_STATE(!guard.Mutated(1) ||
                       ValidateCurrentNode(this, iter));
     }
 
     if (!iter.IsDone() && retval) {
       // Find the equivalent of commonAncestor in the cloned tree.
       nsCOMPtr<nsINode> newCloneAncestor = nodeToResult;
-      for (uint32_t i = parentCount; i; --i)
-      {
+      for (uint32_t i = parentCount; i; --i) {
         newCloneAncestor = newCloneAncestor->GetParentNode();
         NS_ENSURE_STATE(newCloneAncestor);
       }
       commonCloneAncestor = newCloneAncestor;
     }
   }
 
   rv = CollapseRangeAfterDelete(this);
@@ -2719,46 +2720,39 @@ nsRange::CloneContents(ErrorResult& aRv)
     }
 
     // If it's CharacterData, make sure we only clone what
     // is in the range.
     //
     // XXX_kin: We need to also handle ProcessingInstruction
     // XXX_kin: according to the spec.
 
-    nsCOMPtr<nsIDOMCharacterData> charData(do_QueryInterface(clone));
-
-    if (charData)
+    if (auto charData = CharacterData::FromContent(clone))
     {
       if (node == mEnd.Container()) {
         // We only need the data before mEndOffset, so get rid of any
         // data after it.
 
-        uint32_t dataLength = 0;
-        aRv = charData->GetLength(&dataLength);
-        if (aRv.Failed()) {
-          return nullptr;
-        }
-
+        uint32_t dataLength = charData->Length();
         if (dataLength > (uint32_t)mEnd.Offset())
         {
-          aRv = charData->DeleteData(mEnd.Offset(), dataLength - mEnd.Offset());
+          charData->DeleteData(mEnd.Offset(), dataLength - mEnd.Offset(), aRv);
           if (aRv.Failed()) {
             return nullptr;
           }
         }
       }
 
       if (node == mStart.Container()) {
         // We don't need any data before mStartOffset, so just
         // delete it!
 
         if (mStart.Offset() > 0)
         {
-          aRv = charData->DeleteData(0, mStart.Offset());
+          charData->DeleteData(0, mStart.Offset(), aRv);
           if (aRv.Failed()) {
             return nullptr;
           }
         }
       }
     }
 
     // Clone the parent hierarchy between commonAncestor and node.
@@ -2906,33 +2900,33 @@ nsRange::InsertNode(nsINode& aNode, Erro
     aRv.Throw(NS_ERROR_DOM_HIERARCHY_REQUEST_ERR);
     return;
   }
 
   // This is the node we'll be inserting before, and its parent
   nsCOMPtr<nsINode> referenceNode;
   nsCOMPtr<nsINode> referenceParentNode = tStartContainer;
 
-  nsCOMPtr<nsIDOMText> startTextNode(do_QueryInterface(tStartContainer));
+  RefPtr<Text> startTextNode =
+    tStartContainer ? tStartContainer->GetAsText() : nullptr;
   nsCOMPtr<nsINodeList> tChildList;
   if (startTextNode) {
     referenceParentNode = tStartContainer->GetParentNode();
     if (!referenceParentNode) {
       aRv.Throw(NS_ERROR_DOM_HIERARCHY_REQUEST_ERR);
       return;
     }
 
     referenceParentNode->EnsurePreInsertionValidity(aNode, tStartContainer,
                                                     aRv);
     if (aRv.Failed()) {
       return;
     }
 
-    nsCOMPtr<nsIDOMText> secondPart;
-    aRv = startTextNode->SplitText(tStartOffset, getter_AddRefs(secondPart));
+    RefPtr<Text> secondPart = startTextNode->SplitText(tStartOffset, aRv);
     if (aRv.Failed()) {
       return;
     }
 
     referenceNode = do_QueryInterface(secondPart);
   } else {
     tChildList = tStartContainer->ChildNodes();
 
@@ -3103,30 +3097,33 @@ nsRange::ToString(nsAString& aReturn)
   }
 
 #ifdef DEBUG_range
       printf("Range dump: -----------------------\n");
 #endif /* DEBUG */
 
   // effeciency hack for simple case
   if (mStart.Container() == mEnd.Container()) {
-    nsCOMPtr<nsIDOMText> textNode = do_QueryInterface(mStart.Container());
+    Text* textNode = mStart.Container() ? mStart.Container()->GetAsText() : nullptr;
 
     if (textNode)
     {
 #ifdef DEBUG_range
       // If debug, dump it:
-      nsCOMPtr<nsIContent> cN = do_QueryInterface(mStart.Container());
-      if (cN) cN->List(stdout);
+      textNode->List(stdout);
       printf("End Range dump: -----------------------\n");
 #endif /* DEBUG */
 
       // grab the text
-      if (NS_FAILED(textNode->SubstringData(mStart.Offset(),mEnd.Offset()-mStart.Offset(),aReturn)))
+      IgnoredErrorResult rv;
+      textNode->SubstringData(mStart.Offset(), mEnd.Offset() - mStart.Offset(),
+                              aReturn, rv);
+      if (rv.Failed()) {
         return NS_ERROR_UNEXPECTED;
+      }
       return NS_OK;
     }
   }
 
   /* complex case: mStart.Container() != mEnd.Container(), or mStartParent not a text
      node revisit - there are potential optimizations here and also tradeoffs.
   */
 
@@ -3141,26 +3138,26 @@ nsRange::ToString(nsAString& aReturn)
   while (!iter->IsDone())
   {
     nsINode *n = iter->GetCurrentNode();
 
 #ifdef DEBUG_range
     // If debug, dump it:
     n->List(stdout);
 #endif /* DEBUG */
-    nsCOMPtr<nsIDOMText> textNode(do_QueryInterface(n));
+    Text* textNode = n->GetAsText();
     if (textNode) // if it's a text node, get the text
     {
       if (n == mStart.Container()) { // only include text past start offset
-        uint32_t strLength;
-        textNode->GetLength(&strLength);
-        textNode->SubstringData(mStart.Offset(),strLength-mStart.Offset(),tempString);
+        uint32_t strLength = textNode->Length();
+        textNode->SubstringData(mStart.Offset(), strLength-mStart.Offset(),
+                                tempString, IgnoreErrors());
         aReturn += tempString;
       } else if (n == mEnd.Container()) { // only include text before end offset
-        textNode->SubstringData(0,mEnd.Offset(),tempString);
+        textNode->SubstringData(0, mEnd.Offset(), tempString, IgnoreErrors());
         aReturn += tempString;
       } else { // grab the whole kit-n-kaboodle
         textNode->GetData(tempString);
         aReturn += tempString;
       }
     }
 
     iter->Next();
@@ -3234,17 +3231,17 @@ GetTextFrameForContent(nsIContent* aCont
   nsIDocument* doc = aContent->OwnerDoc();
   nsIPresShell* presShell = doc->GetShell();
   if (!presShell) {
     return nullptr;
   }
 
   const bool frameWillBeUnsuppressed =
     presShell->FrameConstructor()->EnsureFrameForTextNodeIsCreatedAfterFlush(
-      static_cast<nsGenericDOMDataNode*>(aContent));
+      static_cast<CharacterData*>(aContent));
   if (aFlushLayout) {
     doc->FlushPendingNotifications(FlushType::Layout);
   } else if (frameWillBeUnsuppressed) {
     doc->FlushPendingNotifications(FlushType::Frames);
   }
 
   nsIFrame* frame = aContent->GetPrimaryFrame();
   if (!frame || !frame->IsTextFrame()) {
@@ -3747,17 +3744,17 @@ ElementIsVisibleNoFlush(Element* aElemen
   RefPtr<nsStyleContext> sc =
     nsComputedDOMStyle::GetStyleContextNoFlush(aElement, nullptr);
   return sc && sc->StyleVisibility()->IsVisible();
 }
 
 static void
 AppendTransformedText(InnerTextAccumulator& aResult, nsIContent* aContainer)
 {
-  auto textNode = static_cast<nsGenericDOMDataNode*>(aContainer);
+  auto textNode = static_cast<CharacterData*>(aContainer);
 
   nsIFrame* frame = textNode->GetPrimaryFrame();
   if (!IsVisibleAndNotInReplacedElement(frame)) {
     return;
   }
 
   nsIFrame::RenderedText text =
     frame->GetRenderedText(0, aContainer->GetChildCount());
--- a/dom/base/nsStyleLinkElement.cpp
+++ b/dom/base/nsStyleLinkElement.cpp
@@ -18,17 +18,16 @@
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/FragmentOrElement.h"
 #include "mozilla/dom/HTMLLinkElement.h"
 #include "mozilla/dom/ShadowRoot.h"
 #include "mozilla/dom/SRILogHelper.h"
 #include "mozilla/Preferences.h"
 #include "nsIContent.h"
 #include "nsIDocument.h"
-#include "nsIDOMComment.h"
 #include "nsIDOMNode.h"
 #include "nsUnicharUtils.h"
 #include "nsCRT.h"
 #include "nsXPCOMCIDInternal.h"
 #include "nsUnicharInputStream.h"
 #include "nsContentUtils.h"
 #include "nsStyleUtil.h"
 #include "nsQueryObject.h"
--- a/dom/base/nsTextNode.cpp
+++ b/dom/base/nsTextNode.cpp
@@ -1,16 +1,16 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /*
- * Implementation of DOM Core's nsIDOMText node.
+ * Implementation of DOM Core's Text node.
  */
 
 #include "nsTextNode.h"
 #include "mozilla/dom/TextBinding.h"
 #include "nsContentUtils.h"
 #include "mozilla/dom/DirectionalityUtils.h"
 #include "nsIDOMEventListener.h"
 #include "nsIDocument.h"
@@ -50,29 +50,29 @@ public:
                               nsIContent* aBindingParent,
                               bool aCompileEventHandlers) override;
   virtual void UnbindFromTree(bool aDeep = true,
                               bool aNullParent = true) override;
 
   NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTECHANGED
   NS_DECL_NSIMUTATIONOBSERVER_NODEWILLBEDESTROYED
 
-  virtual nsGenericDOMDataNode *CloneDataNode(mozilla::dom::NodeInfo *aNodeInfo,
-                                              bool aCloneText) const override
+  virtual already_AddRefed<CharacterData>
+    CloneDataNode(mozilla::dom::NodeInfo *aNodeInfo,
+                  bool aCloneText) const override
   {
     already_AddRefed<mozilla::dom::NodeInfo> ni =
       RefPtr<mozilla::dom::NodeInfo>(aNodeInfo).forget();
-    nsAttributeTextNode *it = new nsAttributeTextNode(ni,
-                                                      mNameSpaceID,
-                                                      mAttrName);
-    if (it && aCloneText) {
+    RefPtr<nsAttributeTextNode> it =
+      new nsAttributeTextNode(ni, mNameSpaceID, mAttrName);
+    if (aCloneText) {
       it->mText = mText;
     }
 
-    return it;
+    return it.forget();
   }
 
   // Public method for the event to run
   void UpdateText() {
     UpdateText(true);
   }
 
 private:
@@ -94,72 +94,71 @@ private:
 };
 
 nsTextNode::~nsTextNode()
 {
 }
 
 // Use the CC variant of this, even though this class does not define
 // a new CC participant, to make QIing to the CC interfaces faster.
-NS_IMPL_ISUPPORTS_CYCLE_COLLECTION_INHERITED(nsTextNode, nsGenericDOMDataNode, nsIDOMNode,
-                                             nsIDOMText, nsIDOMCharacterData)
+NS_IMPL_ISUPPORTS_CYCLE_COLLECTION_INHERITED(nsTextNode, CharacterData, nsIDOMNode)
 
 JSObject*
 nsTextNode::WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto)
 {
   return TextBinding::Wrap(aCx, this, aGivenProto);
 }
 
 bool
 nsTextNode::IsNodeOfType(uint32_t aFlags) const
 {
   return !(aFlags & ~(eTEXT | eDATA_NODE));
 }
 
-nsGenericDOMDataNode*
+already_AddRefed<CharacterData>
 nsTextNode::CloneDataNode(mozilla::dom::NodeInfo *aNodeInfo, bool aCloneText) const
 {
   already_AddRefed<mozilla::dom::NodeInfo> ni = RefPtr<mozilla::dom::NodeInfo>(aNodeInfo).forget();
-  nsTextNode *it = new nsTextNode(ni);
+  RefPtr<nsTextNode> it = new nsTextNode(ni);
   if (aCloneText) {
     it->mText = mText;
   }
 
-  return it;
+  return it.forget();
 }
 
 nsresult
 nsTextNode::AppendTextForNormalize(const char16_t* aBuffer, uint32_t aLength,
                                    bool aNotify, nsIContent* aNextSibling)
 {
   CharacterDataChangeInfo::Details details = {
     CharacterDataChangeInfo::Details::eMerge, aNextSibling
   };
   return SetTextInternal(mText.GetLength(), 0, aBuffer, aLength, aNotify, &details);
 }
 
 nsresult
 nsTextNode::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
                        nsIContent* aBindingParent, bool aCompileEventHandlers)
 {
-  nsresult rv = nsGenericDOMDataNode::BindToTree(aDocument, aParent,
-                                                 aBindingParent,
-                                                 aCompileEventHandlers);
+  nsresult rv = CharacterData::BindToTree(aDocument, aParent,
+                                          aBindingParent,
+                                          aCompileEventHandlers);
   NS_ENSURE_SUCCESS(rv, rv);
 
   SetDirectionFromNewTextNode(this);
 
   return NS_OK;
 }
 
 void nsTextNode::UnbindFromTree(bool aDeep, bool aNullParent)
 {
   ResetDirectionSetByTextNode(this);
 
-  nsGenericDOMDataNode::UnbindFromTree(aDeep, aNullParent);
+  CharacterData::UnbindFromTree(aDeep, aNullParent);
 }
 
 bool
 nsTextNode::IsShadowDOMEnabled(JSContext* aCx, JSObject* aObject)
 {
   return nsDocument::IsShadowDOMEnabled(aCx, aObject);
 }
 
--- a/dom/base/nsTextNode.h
+++ b/dom/base/nsTextNode.h
@@ -3,31 +3,31 @@
 /* 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 nsTextNode_h
 #define nsTextNode_h
 
 /*
- * Implementation of DOM Core's nsIDOMText node.
+ * Implementation of DOM Core's Text node.
  */
 
 #include "mozilla/Attributes.h"
 #include "mozilla/dom/Text.h"
-#include "nsIDOMText.h"
+#include "nsIDOMNode.h"
 #include "nsDebug.h"
 
 class nsNodeInfoManager;
 
 /**
  * Class used to implement DOM text nodes
  */
 class nsTextNode : public mozilla::dom::Text,
-                   public nsIDOMText
+                   public nsIDOMNode
 {
 private:
   void Init()
   {
     MOZ_ASSERT(mNodeInfo->NodeType() == TEXT_NODE,
                "Bad NodeType in aNodeInfo");
   }
 
@@ -42,28 +42,22 @@ public:
     : mozilla::dom::Text(aNodeInfoManager->GetTextNodeInfo())
   {
     Init();
   }
 
   // nsISupports
   NS_DECL_ISUPPORTS_INHERITED
 
-  // nsIDOMCharacterData
-  NS_FORWARD_NSIDOMCHARACTERDATA(nsGenericDOMDataNode::)
-  using nsGenericDOMDataNode::SetData; // Prevent hiding overloaded virtual function.
-
-  // nsIDOMText
-  NS_FORWARD_NSIDOMTEXT(nsGenericDOMDataNode::)
-
   // nsINode
   virtual bool IsNodeOfType(uint32_t aFlags) const override;
 
-  virtual nsGenericDOMDataNode* CloneDataNode(mozilla::dom::NodeInfo *aNodeInfo,
-                                              bool aCloneText) const override;
+  virtual already_AddRefed<CharacterData>
+    CloneDataNode(mozilla::dom::NodeInfo *aNodeInfo,
+                  bool aCloneText) const override;
 
   virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
                               nsIContent* aBindingParent,
                               bool aCompileEventHandlers) override;
   virtual void UnbindFromTree(bool aDeep = true,
                               bool aNullParent = true) override;
 
   nsresult AppendTextForNormalize(const char16_t* aBuffer, uint32_t aLength,
--- a/dom/base/nsXMLContentSerializer.cpp
+++ b/dom/base/nsXMLContentSerializer.cpp
@@ -8,33 +8,33 @@
  * nsIContentSerializer implementation that can be used with an
  * nsIDocumentEncoder to convert an XML DOM to an XML string that
  * could be parsed into more or less the original DOM.
  */
 
 #include "nsXMLContentSerializer.h"
 
 #include "nsGkAtoms.h"
-#include "nsIDOMProcessingInstruction.h"
-#include "nsIDOMComment.h"
 #include "nsIContent.h"
 #include "nsIContentInlines.h"
 #include "nsIDocument.h"
 #include "nsIDocumentEncoder.h"
 #include "nsElementTable.h"
 #include "nsNameSpaceManager.h"
 #include "nsTextFragment.h"
 #include "nsString.h"
 #include "mozilla/Sprintf.h"
 #include "nsUnicharUtils.h"
 #include "nsCRT.h"
 #include "nsContentUtils.h"
 #include "nsAttrName.h"
+#include "mozilla/dom/Comment.h"
 #include "mozilla/dom/DocumentType.h"
 #include "mozilla/dom/Element.h"
+#include "mozilla/dom/ProcessingInstruction.h"
 #include "mozilla/intl/LineBreaker.h"
 #include "nsParserConstants.h"
 #include "mozilla/Encoding.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 #define kXMLNS "xmlns"
@@ -249,33 +249,28 @@ nsXMLContentSerializer::AppendCDATASecti
   NS_ENSURE_TRUE(AppendToStringConvertLF(data, aStr), NS_ERROR_OUT_OF_MEMORY);
 
   NS_ENSURE_TRUE(AppendToString(NS_LITERAL_STRING("]]>"), aStr), NS_ERROR_OUT_OF_MEMORY);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsXMLContentSerializer::AppendProcessingInstruction(nsIContent* aPI,
+nsXMLContentSerializer::AppendProcessingInstruction(ProcessingInstruction* aPI,
                                                     int32_t aStartOffset,
                                                     int32_t aEndOffset,
                                                     nsAString& aStr)
 {
-  nsCOMPtr<nsIDOMProcessingInstruction> pi = do_QueryInterface(aPI);
-  NS_ENSURE_ARG(pi);
-  nsresult rv;
   nsAutoString target, data, start;
 
   NS_ENSURE_TRUE(MaybeAddNewlineForRootNode(aStr), NS_ERROR_OUT_OF_MEMORY);
 
-  rv = pi->GetTarget(target);
-  if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
+  aPI->GetTarget(target);
 
-  rv = pi->GetData(data);
-  if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
+  aPI->GetData(data);
 
   NS_ENSURE_TRUE(start.AppendLiteral("<?", mozilla::fallible), NS_ERROR_OUT_OF_MEMORY);
   NS_ENSURE_TRUE(start.Append(target, mozilla::fallible), NS_ERROR_OUT_OF_MEMORY);
 
   if (mDoRaw || PreLevel() > 0) {
     NS_ENSURE_TRUE(AppendToString(start, aStr), NS_ERROR_OUT_OF_MEMORY);
   }
   else if (mDoFormat) {
@@ -298,28 +293,23 @@ nsXMLContentSerializer::AppendProcessing
   NS_ENSURE_TRUE(AppendToString(NS_LITERAL_STRING("?>"), aStr), NS_ERROR_OUT_OF_MEMORY);
 
   MaybeFlagNewlineForRootNode(aPI);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsXMLContentSerializer::AppendComment(nsIContent* aComment,
+nsXMLContentSerializer::AppendComment(Comment* aComment,
                                       int32_t aStartOffset,
                                       int32_t aEndOffset,
                                       nsAString& aStr)
 {
-  nsCOMPtr<nsIDOMComment> comment = do_QueryInterface(aComment);
-  NS_ENSURE_ARG(comment);
-  nsresult rv;
   nsAutoString data;
-
-  rv = comment->GetData(data);
-  if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
+  aComment->GetData(data);
 
   int32_t dataLength = data.Length();
   if (aStartOffset || (aEndOffset != -1 && aEndOffset < dataLength)) {
     int32_t length =
       (aEndOffset == -1) ? dataLength : std::min(aEndOffset, dataLength);
     length -= aStartOffset;
 
     nsAutoString frag;
--- a/dom/base/nsXMLContentSerializer.h
+++ b/dom/base/nsXMLContentSerializer.h
@@ -45,22 +45,23 @@ class nsXMLContentSerializer : public ns
 
   NS_IMETHOD AppendText(nsIContent* aText, int32_t aStartOffset,
                         int32_t aEndOffset, nsAString& aStr) override;
 
   NS_IMETHOD AppendCDATASection(nsIContent* aCDATASection,
                                 int32_t aStartOffset, int32_t aEndOffset,
                                 nsAString& aStr) override;
 
-  NS_IMETHOD AppendProcessingInstruction(nsIContent* aPI,
+  NS_IMETHOD AppendProcessingInstruction(mozilla::dom::ProcessingInstruction* aPI,
                                          int32_t aStartOffset,
                                          int32_t aEndOffset,
                                          nsAString& aStr) override;
 
-  NS_IMETHOD AppendComment(nsIContent* aComment, int32_t aStartOffset,
+  NS_IMETHOD AppendComment(mozilla::dom::Comment* aComment,
+                           int32_t aStartOffset,
                            int32_t aEndOffset, nsAString& aStr) override;
 
   NS_IMETHOD AppendDoctype(mozilla::dom::DocumentType* aDoctype,
                            nsAString& aStr) override;
 
   NS_IMETHOD AppendElementStart(mozilla::dom::Element* aElement,
                                 mozilla::dom::Element* aOriginalElement,
                                 nsAString& aStr) override;
--- a/dom/base/test/test_bug352728.html
+++ b/dom/base/test/test_bug352728.html
@@ -46,18 +46,17 @@ function testCharacterData(aNode, aText)
 
 function testComment(aText)
 {
   try {
     var comment = document.createComment(aText);
     var types = [ Comment, CharacterData, Node ];
     checkTypes(comment, "comment", types);
 
-    var interfaces = [ "nsIDOMComment", "nsIDOMCharacterData", "nsIDOMNode",
-                       "nsIDOMEventTarget" ];
+    var interfaces = [ "nsIDOMNode", "nsIDOMEventTarget" ];
     checkInterfaces(comment, "comment", interfaces);
 
     testCharacterData(comment, aText);
     is(comment.nodeName, "#comment", "Check nodeName");
     is(comment.nodeType, Node.COMMENT_NODE, "Check nodeType");
   } catch (e) {
     ok(0, "Correct functioning of comment stuff", "something broke: " + e);
   }
@@ -77,18 +76,17 @@ function testCDATASection(aText, aShould
 
 function testPI(aTarget, aData, aShouldSucceed, aReason)
 {
   try {
     var pi = document.createProcessingInstruction(aTarget, aData);
     var types = [ ProcessingInstruction, Node ];
     checkTypes(pi, "processing instruction", types);
 
-    var interfaces = [ "nsIDOMProcessingInstruction", "nsIDOMNode",
-                       "nsIDOMEventTarget" ];
+    var interfaces = [ "nsIDOMNode", "nsIDOMEventTarget" ];
     checkInterfaces(pi, "processing instruction", interfaces);
 
     is(pi.target, aTarget, "Check target");
     is(pi.data, aData, "Check data");
     is(pi.nodeName, aTarget, "Check nodeName");
     is(pi.nodeValue, aData, "Check nodeValue");
     is(pi.localName, undefined, "Check localName")
     is(pi.namespaceURI, undefined, "Check namespaceURI");
--- a/dom/base/test/test_bug352728.xhtml
+++ b/dom/base/test/test_bug352728.xhtml
@@ -70,18 +70,17 @@ function testCharacterData(aNode, aText)
 
 function testComment(aText)
 {
   try {
     var comment = document.createComment(aText);
     var types = [ Comment, CharacterData, Node ];
     checkTypes(comment, "comment", types);
 
-    var interfaces = [ "nsIDOMComment", "nsIDOMCharacterData", "nsIDOMNode",
-                       "nsIDOMEventTarget" ];
+    var interfaces = [ "nsIDOMNode", "nsIDOMEventTarget" ];
     checkInterfaces(comment, "comment", interfaces);
 
     testCharacterData(comment, aText);
     is(comment.nodeName, "#comment", "Check nodeName");
     is(comment.nodeType, Node.COMMENT_NODE, "Check nodeType");
   } catch (e) {
     ok(0, "Correct functioning of comment stuff", "something broke: " + e);
   }
@@ -89,18 +88,17 @@ function testComment(aText)
 
 function testCDATASection(aText, aShouldSucceed)
 {
   try {
     var cdataSection = document.createCDATASection(aText);
     var types = [ CDATASection, CharacterData, Node ];
     checkTypes(cdataSection, "CDATA section", types);
 
-    var interfaces = [ "nsIDOMCharacterData",
-                       "nsIDOMNode", "nsIDOMEventTarget" ];
+    var interfaces = [ "nsIDOMNode", "nsIDOMEventTarget" ];
     checkInterfaces(cdataSection, "CDATA section", interfaces);
 
     testCharacterData(cdataSection, aText);
     is(cdataSection.nodeName, "#cdata-section", "Check nodeName");
     is(cdataSection.nodeType, Node.CDATA_SECTION_NODE, "Check nodeType");
 
     if (!aShouldSucceed) {
       ok(0, "Invalid CDATA section creation",
@@ -121,18 +119,17 @@ function testCDATASection(aText, aShould
 
 function testPI(aTarget, aData, aShouldSucceed, aReason)
 {
   try {
     var pi = document.createProcessingInstruction(aTarget, aData);
     var types = [ ProcessingInstruction, Node ];
     checkTypes(pi, "processing instruction", types);
 
-    var interfaces = [ "nsIDOMProcessingInstruction", "nsIDOMNode",
-                       "nsIDOMEventTarget" ];
+    var interfaces = [ "nsIDOMNode", "nsIDOMEventTarget" ];
     checkInterfaces(pi, "processing instruction", interfaces);
 
     is(pi.target, aTarget, "Check target");
     is(pi.data, aData, "Check data");
     is(pi.nodeName, aTarget, "Check nodeName");
     is(pi.nodeValue, aData, "Check nodeValue");
     is(pi.localName, undefined, "Check localName")
     is(pi.namespaceURI, undefined, "Check namespaceURI");
--- a/dom/base/test/test_mutationobservers.html
+++ b/dom/base/test/test_mutationobservers.html
@@ -144,19 +144,16 @@ function runTest() {
       is(records[0].type, "attributes", "Should have got attributes record");
       is(records[0].target, div, "Should have got div as target");
       is(records[0].attributeName, "foo", "Should have got record about foo attribute");
       observer.disconnect();
       then(testThisBind);
       m = null;
     });
   m.observe(div, { attributes: true, attributeFilter: ["foo"] });
-  is(SpecialPowers.wrap(div).getBoundMutationObservers()[0].getObservingInfo()[0].attributes, true);
-  is(SpecialPowers.wrap(div).getBoundMutationObservers()[0].getObservingInfo()[0].attributeFilter.length, 1)
-  is(SpecialPowers.wrap(div).getBoundMutationObservers()[0].getObservingInfo()[0].attributeFilter[0], "foo")
   div.setAttribute("foo", "bar");
 }
 
 // 'this' handling when fn.bind() is used.
 function testThisBind() {
   var child = div.appendChild(document.createElement("div"));
   var gchild = child.appendChild(document.createElement("div"));
   m = new M((function(records, observer) {
@@ -175,19 +172,16 @@ function testThisBind() {
       is(records[2].target, gchild, "Should have got div as target");
       is(records[2].attributeName, "foo", "Should have got record about foo attribute");
       is(records[2].oldValue, null, "oldValue should be bar2");
       observer.disconnect();
       then(testCharacterData);
       m = null;
     }).bind(window));
   m.observe(div, { attributes: true, attributeOldValue: true, subtree: true });
-  is(SpecialPowers.wrap(div).getBoundMutationObservers()[0].getObservingInfo()[0].attributes, true)
-  is(SpecialPowers.wrap(div).getBoundMutationObservers()[0].getObservingInfo()[0].attributeOldValue, true)
-  is(SpecialPowers.wrap(div).getBoundMutationObservers()[0].getObservingInfo()[0].subtree, true)
   div.setAttribute("foo", "bar2");
   div.removeAttribute("foo");
   div.removeChild(child);
   child.removeChild(gchild);
   div.appendChild(gchild);
   div.removeChild(gchild);
   gchild.setAttribute("foo", "bar");
 }
@@ -221,20 +215,16 @@ function testCharacterData() {
 
   div.appendChild(document.createTextNode("foo"));
   m.observe(div, { characterData: true, subtree: true });
   m2.observe(div, { characterData: true, characterDataOldValue: true, subtree: true});
   // If observing the same node twice, only the latter option should apply.
   m3.observe(div, { characterData: true, subtree: true });
   m3.observe(div, { characterData: true, subtree: false });
   m4.observe(div.firstChild, { characterData: true, subtree: false });
-  
-  is(SpecialPowers.wrap(div).getBoundMutationObservers().length, 3)
-  is(SpecialPowers.wrap(div).getBoundMutationObservers()[2].getObservingInfo()[0].characterData, true)
-  is(SpecialPowers.wrap(div).getBoundMutationObservers()[2].getObservingInfo()[0].subtree, false)
 
   div.firstChild.data = "bar";
 }
 
 function testChildList() {
   var fc = div.firstChild;
   m = new M(function(records, observer) {
       is(records[0].type, "childList", "Should have got childList");
@@ -298,28 +288,22 @@ function testChildList4() {
       is(records[2].target, t1, "target should be the textnode");
       is(records[2].oldValue, "Hello ", "oldValue was 'Hello '");
       observer.disconnect();
       then(testChildList5);
       m = null;
     };
   m = new M(callback);
   m.observe(df, { childList: true, characterData: true, characterDataOldValue: true, subtree: true });
-  is(SpecialPowers.wrap(df).getBoundMutationObservers()[0].getObservingInfo()[0].childList, true)
-  is(SpecialPowers.wrap(df).getBoundMutationObservers()[0].getObservingInfo()[0].characterData, true)
-  is(SpecialPowers.wrap(df).getBoundMutationObservers()[0].getObservingInfo()[0].characterDataOldValue, true)
-  is(SpecialPowers.wrap(df).getBoundMutationObservers()[0].getObservingInfo()[0].subtree, true)
-  ok(SpecialPowers.compare(SpecialPowers.wrap(df).getBoundMutationObservers()[0].mutationCallback, callback))
   m.observe(div, { childList: true });
-  is(SpecialPowers.wrap(df).getBoundMutationObservers()[0].getObservingInfo().length, 2)
-  
+
   // Make sure transient observers aren't leaked.
   var leakTest = new M(function(){});
   leakTest.observe(div, { characterData: true, subtree: true });
-  
+
   div.insertBefore(df, s2);
   s1.firstChild.data = "bar"; // This should *not* create a record.
   t1.data = "Hello the whole "; // This should create a record.
 }
 
 function testChildList5() {
   div.textContent = null;
   var c1 = div.appendChild(document.createElement("div"));
@@ -573,18 +557,16 @@ function testTakeRecords() {
       is(records[1].attributeName, "foo", "");
       is(records[1].oldValue, "bar", "");
       observer.disconnect();
       div.removeEventListener("DOMAttrModified", mutationListener);
       then(testExpandos);
       m = null;
     });
   m.observe(div, { attributes: true, attributeOldValue: true });
-  // Note, [0] points to a mutation observer which is there for a leak test!
-  ok(SpecialPowers.compare(SpecialPowers.wrap(div).getBoundMutationObservers()[1], m));
   var mutationEventCount = 0;
   div.addEventListener("DOMAttrModified", mutationListener);
   div.setAttribute("foo", "bar");
   div.setAttribute("foo", "bar");
   is(mutationEventCount, 1, "Should have got only one mutation event!");
 }
 
 function testExpandos() {
--- a/dom/base/test/unit/head_xml.js
+++ b/dom/base/test/unit/head_xml.js
@@ -12,20 +12,18 @@ const nsIProperties        = I.nsIProper
 const nsIFileInputStream   = I.nsIFileInputStream;
 const nsIInputStream       = I.nsIInputStream;
 
 const nsIDOMParser         = I.nsIDOMParser;
 const nsIDOMSerializer     = I.nsIDOMSerializer;
 const nsIDOMDocument       = I.nsIDOMDocument;
 const nsIDOMElement        = I.nsIDOMElement;
 const nsIDOMNode           = I.nsIDOMNode;
-const nsIDOMCharacterData  = I.nsIDOMCharacterData;
 const nsIDOMNodeList       = I.nsIDOMNodeList;
 const nsIDOMXULElement     = I.nsIDOMXULElement;
-const nsIDOMProcessingInstruction = I.nsIDOMProcessingInstruction;
 
 function DOMParser() {
   var parser = C["@mozilla.org/xmlextras/domparser;1"].createInstance(nsIDOMParser);
   parser.init();
   return parser;
 }
 
 var __testsDirectory = null;
@@ -95,28 +93,24 @@ function do_compare_attrs(e1, e2) {
       }
       Assert.equal(att.value, att2.value);
     }
   }
 }
 
 function do_check_equiv(dom1, dom2) {
   Assert.equal(dom1.nodeType, dom2.nodeType);
-  // There's no classinfo around, so we'll need to do some QIing to
-  // make sure the right interfaces are flattened as needed.
   switch (dom1.nodeType) {
   case nsIDOMNode.PROCESSING_INSTRUCTION_NODE:
-    Assert.equal(dom1.QueryInterface(nsIDOMProcessingInstruction).target, 
-                 dom2.QueryInterface(nsIDOMProcessingInstruction).target);
+    Assert.equal(dom1.target, dom2.target);
     Assert.equal(dom1.data, dom2.data);
   case nsIDOMNode.TEXT_NODE:
   case nsIDOMNode.CDATA_SECTION_NODE:
   case nsIDOMNode.COMMENT_NODE:
-    Assert.equal(dom1.QueryInterface(nsIDOMCharacterData).data,
-                 dom2.QueryInterface(nsIDOMCharacterData).data);
+    Assert.equal(dom1.data, dom2.data);
     break;
   case nsIDOMNode.ELEMENT_NODE:
     Assert.equal(dom1.namespaceURI, dom2.namespaceURI);
     Assert.equal(dom1.localName, dom2.localName);
     // Compare attrs in both directions -- do_compare_attrs does a
     // subset check.
     do_compare_attrs(dom1, dom2);
     do_compare_attrs(dom2, dom1);
--- a/dom/base/test/unit/test_range.js
+++ b/dom/base/test/unit/test_range.js
@@ -335,16 +335,21 @@ function do_extract_test(doc) {
 /**
  * Miscellaneous tests not covered above.
  */
 function run_miscellaneous_tests() {
   var filePath = "test_delete_range.xml";
   getParsedDocument(filePath).then(do_miscellaneous_tests);
 }
 
+function isText(node) {
+  return node.nodeType == node.TEXT_NODE ||
+         node.nodeType == node.CDATA_SECTION_NODE;
+}
+
 function do_miscellaneous_tests(doc) {
   var tests = doc.getElementsByTagName("test");
 
   // Let's try some invalid inputs to our DOM range and see what happens.
   var currentTest = tests.item(0);
   var baseSource = currentTest.firstChild;
   var baseResult = baseSource.nextSibling;
   var baseExtract = baseResult.nextSibling;
@@ -355,17 +360,17 @@ function do_miscellaneous_tests(doc) {
   var startContainer = baseRange.startContainer;
   var endContainer = baseRange.endContainer;
   var startOffset = baseRange.startOffset;
   var endOffset = baseRange.endOffset;
 
   // Text range manipulation.
   if ((endOffset > startOffset) &&
       (startContainer == endContainer) &&
-      (startContainer instanceof Ci.nsIDOMText)) {
+      isText(startContainer)) {
     // Invalid start node
     try {
       baseRange.setStart(null, 0);
       do_throw("Should have thrown NOT_OBJECT_ERR!");
     } catch (e) {
       Assert.equal(e.constructor.name, "TypeError");
     }
 
@@ -381,17 +386,17 @@ function do_miscellaneous_tests(doc) {
     try {
       baseRange.setStart(startContainer, -1);
       do_throw("Should have thrown IndexSizeError!");
     } catch (e) {
       Assert.equal(e.name, "IndexSizeError");
     }
   
     // Invalid index
-    var newOffset = startContainer instanceof Ci.nsIDOMText ?
+    var newOffset = isText(startContainer) ?
                       startContainer.nodeValue.length + 1 :
                       startContainer.childNodes.length + 1;
     try {
       baseRange.setStart(startContainer, newOffset);
       do_throw("Should have thrown IndexSizeError!");
     } catch (e) {
       Assert.equal(e.name, "IndexSizeError");
     }
@@ -444,17 +449,18 @@ function do_miscellaneous_tests(doc) {
   doc = parser.parseFromString("<!-- foo --><foo/>", "application/xml");
   Assert.ok(doc instanceof Ci.nsIDOMDocument);
   Assert.equal(doc.childNodes.length, 2);
   baseRange = doc.createRange();
   baseRange.setStart(doc.firstChild, 1);
   baseRange.setEnd(doc.firstChild, 2);
   var frag = baseRange.extractContents();
   Assert.equal(frag.childNodes.length, 1);
-  Assert.ok(frag.firstChild instanceof Ci.nsIDOMComment);
+  Assert.ok(ChromeUtils.getClassName(frag.firstChild) == "Comment");
+  Assert.equal(frag.firstChild.nodeType, frag.COMMENT_NODE);
   Assert.equal(frag.firstChild.nodeValue, "f");
 
   /* smaug also requested attribute tests.  Sadly, those are not yet supported
      in ranges - see https://bugzilla.mozilla.org/show_bug.cgi?id=302775.
    */
 }
 
 function run_test() {
--- a/dom/bindings/Bindings.conf
+++ b/dom/bindings/Bindings.conf
@@ -135,17 +135,16 @@ DOMInterfaces = {
     'nativeType': 'nsDOMCaretPosition',
 },
 
 'ChannelWrapper': {
     'nativeType': 'mozilla::extensions::ChannelWrapper',
 },
 
 'CharacterData': {
-    'nativeType': 'nsGenericDOMDataNode',
     'concrete': False
 },
 
 'console': {
     'nativeType': 'mozilla::dom::Console',
 },
 
 'ConsoleInstance': {
new file mode 100644
--- /dev/null
+++ b/dom/canvas/crashtests/1443671.html
@@ -0,0 +1,8 @@
+<!DOCTYPE html>
+<html>
+<script>
+try { o1 = document.createElement('canvas') } catch (e) {}
+try { o2 = o1.transferControlToOffscreen() } catch (e) {}
+try { o2.getContext("webgl", { }) } catch (e) {}
+</script>
+</html>
--- a/dom/canvas/crashtests/crashtests.list
+++ b/dom/canvas/crashtests/crashtests.list
@@ -46,8 +46,9 @@ load 1305085-1.html
 load 1305312-1.html
 load 1305850.html
 load 1334366-1.html
 load 1334647-1.html
 load 1349067.html
 pref(gfx.offscreencanvas.enabled,true) load 1348976-1.html
 load 1357092.html
 load 1441613.html
+pref(gfx.offscreencanvas.enabled,true) load 1443671.html
--- a/dom/events/Event.h
+++ b/dom/events/Event.h
@@ -34,16 +34,17 @@ class DragEvent;
 class EventTarget;
 class EventMessageAutoOverride;
 // ExtendableEvent is a ServiceWorker event that is not
 // autogenerated since it has some extra methods.
 class ExtendableEvent;
 class KeyboardEvent;
 class TimeEvent;
 class WantsPopupControlCheck;
+class XULCommandEvent;
 #define GENERATED_EVENT(EventClass_) class EventClass_;
 #include "mozilla/dom/GeneratedEventList.h"
 #undef GENERATED_EVENT
 
 // Dummy class so we can cast through it to get from nsISupports to
 // Event subclasses with only two non-ambiguous static casts.
 class EventBase : public nsIDOMEvent
 {
@@ -127,16 +128,22 @@ public:
   }
 
   // DragEvent has a non-autogeneratable initDragEvent.
   virtual DragEvent* AsDragEvent()
   {
     return nullptr;
   }
 
+  // XULCommandEvent has a non-autogeneratable initCommandEvent.
+  virtual XULCommandEvent* AsXULCommandEvent()
+  {
+    return nullptr;
+  }
+
   // nsIDOMEvent Interface
   NS_DECL_NSIDOMEVENT
 
   void InitPresContextData(nsPresContext* aPresContext);
 
   // Returns true if the event should be trusted.
   bool Init(EventTarget* aGlobal);
 
--- a/dom/events/FocusEvent.cpp
+++ b/dom/events/FocusEvent.cpp
@@ -6,40 +6,30 @@
 
 #include "mozilla/dom/FocusEvent.h"
 #include "mozilla/ContentEvents.h"
 #include "prtime.h"
 
 namespace mozilla {
 namespace dom {
 
-NS_IMPL_ISUPPORTS_INHERITED(FocusEvent, UIEvent, nsIDOMFocusEvent)
-
 FocusEvent::FocusEvent(EventTarget* aOwner,
                        nsPresContext* aPresContext,
                        InternalFocusEvent* aEvent)
   : UIEvent(aOwner, aPresContext,
             aEvent ? aEvent : new InternalFocusEvent(false, eFocus))
 {
   if (aEvent) {
     mEventIsInternal = false;
   } else {
     mEventIsInternal = true;
     mEvent->mTime = PR_Now();
   }
 }
 
-NS_IMETHODIMP
-FocusEvent::GetRelatedTarget(nsIDOMEventTarget** aRelatedTarget)
-{
-  NS_ENSURE_ARG_POINTER(aRelatedTarget);
-  *aRelatedTarget = GetRelatedTarget().take();
-  return NS_OK;
-}
-
 already_AddRefed<EventTarget>
 FocusEvent::GetRelatedTarget()
 {
   return
     EnsureWebAccessibleRelatedTarget(mEvent->AsFocusEvent()->mRelatedTarget);
 }
 
 void
--- a/dom/events/FocusEvent.h
+++ b/dom/events/FocusEvent.h
@@ -4,30 +4,24 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 #ifndef mozilla_dom_FocusEvent_h_
 #define mozilla_dom_FocusEvent_h_
 
 #include "mozilla/dom/FocusEventBinding.h"
 #include "mozilla/dom/UIEvent.h"
 #include "mozilla/EventForwards.h"
-#include "nsIDOMFocusEvent.h"
 
 namespace mozilla {
 namespace dom {
 
-class FocusEvent : public UIEvent,
-                   public nsIDOMFocusEvent
+class FocusEvent : public UIEvent
 {
 public:
-  NS_DECL_ISUPPORTS_INHERITED
-  NS_DECL_NSIDOMFOCUSEVENT
-
-  // Forward to base class
-  NS_FORWARD_TO_UIEVENT
+  NS_INLINE_DECL_REFCOUNTING_INHERITED(FocusEvent, UIEvent)
 
   virtual JSObject* WrapObjectInternal(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override
   {
     return FocusEventBinding::Wrap(aCx, this, aGivenProto);
   }
 
   FocusEvent(EventTarget* aOwner,
              nsPresContext* aPresContext,
--- a/dom/events/MouseScrollEvent.cpp
+++ b/dom/events/MouseScrollEvent.cpp
@@ -2,17 +2,16 @@
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/dom/MouseScrollEvent.h"
 #include "mozilla/MouseEvents.h"
 #include "prtime.h"
-#include "nsIDOMMouseScrollEvent.h"
 
 namespace mozilla {
 namespace dom {
 
 MouseScrollEvent::MouseScrollEvent(EventTarget* aOwner,
                                    nsPresContext* aPresContext,
                                    WidgetMouseScrollEvent* aEvent)
   : MouseEvent(aOwner, aPresContext,
@@ -52,25 +51,25 @@ MouseScrollEvent::InitMouseScrollEvent(c
 {
   NS_ENSURE_TRUE_VOID(!mEvent->mFlags.mIsBeingDispatched);
 
   MouseEvent::InitMouseEvent(aType, aCanBubble, aCancelable, aView, aDetail,
                              aScreenX, aScreenY, aClientX, aClientY,
                              aCtrlKey, aAltKey, aShiftKey, aMetaKey, aButton,
                              aRelatedTarget);
   mEvent->AsMouseScrollEvent()->mIsHorizontal =
-    (aAxis == nsIDOMMouseScrollEvent::HORIZONTAL_AXIS);
+    (aAxis == MouseScrollEventBinding::HORIZONTAL_AXIS);
 }
 
 int32_t
 MouseScrollEvent::Axis()
 {
   return mEvent->AsMouseScrollEvent()->mIsHorizontal ?
-          static_cast<int32_t>(nsIDOMMouseScrollEvent::HORIZONTAL_AXIS) :
-          static_cast<int32_t>(nsIDOMMouseScrollEvent::VERTICAL_AXIS);
+    MouseScrollEventBinding::HORIZONTAL_AXIS :
+    MouseScrollEventBinding::VERTICAL_AXIS;
 }
 
 } // namespace dom
 } // namespace mozilla
 
 using namespace mozilla;
 using namespace dom;
 
--- a/dom/events/XULCommandEvent.cpp
+++ b/dom/events/XULCommandEvent.cpp
@@ -28,122 +28,72 @@ XULCommandEvent::XULCommandEvent(EventTa
 
 NS_IMPL_ADDREF_INHERITED(XULCommandEvent, UIEvent)
 NS_IMPL_RELEASE_INHERITED(XULCommandEvent, UIEvent)
 
 NS_IMPL_CYCLE_COLLECTION_INHERITED(XULCommandEvent, UIEvent,
                                    mSourceEvent)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(XULCommandEvent)
-  NS_INTERFACE_MAP_ENTRY(nsIDOMXULCommandEvent)
 NS_INTERFACE_MAP_END_INHERITING(UIEvent)
 
 bool
 XULCommandEvent::AltKey()
 {
   return mEvent->AsInputEvent()->IsAlt();
 }
 
-NS_IMETHODIMP
-XULCommandEvent::GetAltKey(bool* aIsDown)
-{
-  NS_ENSURE_ARG_POINTER(aIsDown);
-  *aIsDown = AltKey();
-  return NS_OK;
-}
-
 bool
 XULCommandEvent::CtrlKey()
 {
   return mEvent->AsInputEvent()->IsControl();
 }
 
-NS_IMETHODIMP
-XULCommandEvent::GetCtrlKey(bool* aIsDown)
-{
-  NS_ENSURE_ARG_POINTER(aIsDown);
-  *aIsDown = CtrlKey();
-  return NS_OK;
-}
-
 bool
 XULCommandEvent::ShiftKey()
 {
   return mEvent->AsInputEvent()->IsShift();
 }
 
-NS_IMETHODIMP
-XULCommandEvent::GetShiftKey(bool* aIsDown)
-{
-  NS_ENSURE_ARG_POINTER(aIsDown);
-  *aIsDown = ShiftKey();
-  return NS_OK;
-}
-
 bool
 XULCommandEvent::MetaKey()
 {
   return mEvent->AsInputEvent()->IsMeta();
 }
 
-NS_IMETHODIMP
-XULCommandEvent::GetMetaKey(bool* aIsDown)
-{
-  NS_ENSURE_ARG_POINTER(aIsDown);
-  *aIsDown = MetaKey();
-  return NS_OK;
-}
-
 uint16_t
 XULCommandEvent::InputSource()
 {
   return mInputSource;
 }
 
-NS_IMETHODIMP
-XULCommandEvent::GetInputSource(uint16_t* aInputSource)
-{
-  NS_ENSURE_ARG_POINTER(aInputSource);
-  *aInputSource = InputSource();
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-XULCommandEvent::GetSourceEvent(nsIDOMEvent** aSourceEvent)
-{
-  NS_ENSURE_ARG_POINTER(aSourceEvent);
-  nsCOMPtr<nsIDOMEvent> event = GetSourceEvent();
-  event.forget(aSourceEvent);
-  return NS_OK;
-}
-
-NS_IMETHODIMP
+void
 XULCommandEvent::InitCommandEvent(const nsAString& aType,
                                   bool aCanBubble,
                                   bool aCancelable,
-                                  mozIDOMWindow* aView,
+                                  nsGlobalWindowInner* aView,
                                   int32_t aDetail,
                                   bool aCtrlKey,
                                   bool aAltKey,
                                   bool aShiftKey,
                                   bool aMetaKey,
-                                  nsIDOMEvent* aSourceEvent,
-                                  uint16_t aInputSource)
+                                  Event* aSourceEvent,
+                                  uint16_t aInputSource,
+                                  ErrorResult& aRv)
 {
-  NS_ENSURE_TRUE(!mEvent->mFlags.mIsBeingDispatched, NS_OK);
+  if (NS_WARN_IF(mEvent->mFlags.mIsBeingDispatched)) {
+    return;
+  }
 
-  auto* view = nsGlobalWindowInner::Cast(nsPIDOMWindowInner::From(aView));
-  UIEvent::InitUIEvent(aType, aCanBubble, aCancelable, view, aDetail);
+  UIEvent::InitUIEvent(aType, aCanBubble, aCancelable, aView, aDetail);
 
   mEvent->AsInputEvent()->InitBasicModifiers(aCtrlKey, aAltKey,
                                              aShiftKey, aMetaKey);
   mSourceEvent = aSourceEvent;
   mInputSource = aInputSource;
-
-  return NS_OK;
 }
 
 } // namespace dom
 } // namespace mozilla
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
--- a/dom/events/XULCommandEvent.h
+++ b/dom/events/XULCommandEvent.h
@@ -1,46 +1,45 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-// This class implements a XUL "command" event.  See nsIDOMXULCommandEvent.idl
+// This class implements a XUL "command" event.  See XULCommandEvent.webidl
 
 #ifndef mozilla_dom_XULCommandEvent_h_
 #define mozilla_dom_XULCommandEvent_h_
 
 #include "mozilla/dom/UIEvent.h"
 #include "mozilla/dom/XULCommandEventBinding.h"
-#include "nsIDOMXULCommandEvent.h"
 
 namespace mozilla {
 namespace dom {
 
-class XULCommandEvent : public UIEvent,
-                        public nsIDOMXULCommandEvent
+class XULCommandEvent : public UIEvent
 {
 public:
   XULCommandEvent(EventTarget* aOwner,
                   nsPresContext* aPresContext,
                   WidgetInputEvent* aEvent);
 
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(XULCommandEvent, UIEvent)
-  NS_DECL_NSIDOMXULCOMMANDEVENT
-
-  // Forward our inherited virtual methods to the base class
-  NS_FORWARD_TO_UIEVENT
 
   virtual JSObject* WrapObjectInternal(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override
   {
     return XULCommandEventBinding::Wrap(aCx, this, aGivenProto);
   }
 
+  virtual XULCommandEvent* AsXULCommandEvent() override
+  {
+    return this;
+  }
+
   bool AltKey();
   bool CtrlKey();
   bool ShiftKey();
   bool MetaKey();
   uint16_t InputSource();
 
   already_AddRefed<Event> GetSourceEvent()
   {
@@ -51,22 +50,18 @@ public:
 
   void InitCommandEvent(const nsAString& aType,
                         bool aCanBubble, bool aCancelable,
                         nsGlobalWindowInner* aView,
                         int32_t aDetail,
                         bool aCtrlKey, bool aAltKey,
                         bool aShiftKey, bool aMetaKey,
                         Event* aSourceEvent,
-                        uint16_t aInputSource)
-  {
-    InitCommandEvent(aType, aCanBubble, aCancelable, aView->AsInner(),
-                     aDetail, aCtrlKey, aAltKey, aShiftKey, aMetaKey,
-                     aSourceEvent, aInputSource);
-  }
+                        uint16_t aInputSource,
+                        ErrorResult& aRv);
 
 protected:
   ~XULCommandEvent() {}
 
   nsCOMPtr<nsIDOMEvent> mSourceEvent;
   uint16_t mInputSource;
 };
 
--- a/dom/html/nsTextEditorState.cpp
+++ b/dom/html/nsTextEditorState.cpp
@@ -9,17 +9,16 @@
 
 #include "nsCOMPtr.h"
 #include "nsIPresShell.h"
 #include "nsView.h"
 #include "nsCaret.h"
 #include "nsEditorCID.h"
 #include "nsLayoutCID.h"
 #include "nsITextControlFrame.h"
-#include "nsIDOMCharacterData.h"
 #include "nsIDOMDocument.h"
 #include "nsContentCreatorFunctions.h"
 #include "nsTextControlFrame.h"
 #include "nsIControllers.h"
 #include "nsITransactionManager.h"
 #include "nsIControllerContext.h"
 #include "nsAttrValue.h"
 #include "nsAttrValueInlines.h"
--- a/dom/interfaces/base/domstubs.idl
+++ b/dom/interfaces/base/domstubs.idl
@@ -11,25 +11,21 @@ class nsWrapperCache;
 
 [ptr] native nsWrapperCachePtr(nsWrapperCache);
 
 typedef unsigned long long DOMTimeStamp;
 typedef double DOMHighResTimeStamp;
 typedef unsigned long long nsViewID;
 
 // Core
-interface nsIDOMCharacterData;
-interface nsIDOMComment;
 interface nsIDOMDocument;
 interface nsIDOMDocumentFragment;
 interface nsIDOMElement;
 interface nsIDOMNode;
 interface nsIDOMNodeList;
-interface nsIDOMProcessingInstruction;
-interface nsIDOMText;
 
 // Needed for raises() in our IDL
 %{C++
 namespace mozilla {
 namespace dom {
 class DOMException;
 }
 }
--- a/dom/interfaces/core/moz.build
+++ b/dom/interfaces/core/moz.build
@@ -3,24 +3,20 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 with Files("**"):
     BUG_COMPONENT = ("Core", "DOM")
 
 XPIDL_SOURCES += [
-    'nsIDOMCharacterData.idl',
-    'nsIDOMComment.idl',
     'nsIDOMDocument.idl',
     'nsIDOMDocumentFragment.idl',
     'nsIDOMDOMException.idl',
     'nsIDOMElement.idl',
     'nsIDOMNode.idl',
     'nsIDOMNodeList.idl',
     'nsIDOMNSEditableElement.idl',
-    'nsIDOMProcessingInstruction.idl',
-    'nsIDOMText.idl',
     'nsIDOMXMLDocument.idl',
 ]
 
 XPIDL_MODULE = 'dom_core'
 
deleted file mode 100644
--- a/dom/interfaces/core/nsIDOMCharacterData.idl
+++ /dev/null
@@ -1,39 +0,0 @@
-/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "nsIDOMNode.idl"
-
-/**
- * The nsIDOMCharacterData interface extends nsIDOMNode with a set of 
- * attributes and methods for accessing character data in the DOM.
- * 
- * For more information on this interface please see 
- * http://www.w3.org/TR/DOM-Level-2-Core/
- */
-
-[uuid(4109a2d2-e7af-445d-bb72-c7c9b875f35e)]
-interface nsIDOMCharacterData : nsIDOMNode
-{
-           attribute DOMString            data;
-                                  // raises(DOMException) on setting
-                                  // raises(DOMException) on retrieval
-
-  readonly attribute unsigned long        length;
-  DOMString                 substringData(in unsigned long offset, 
-                                          in unsigned long count)
-                                  raises(DOMException);
-  void                      appendData(in DOMString arg)
-                                  raises(DOMException);
-  void                      insertData(in unsigned long offset, 
-                                       in DOMString arg)
-                                  raises(DOMException);
-  void                      deleteData(in unsigned long offset, 
-                                       in unsigned long count)
-                                  raises(DOMException);
-  void                      replaceData(in unsigned long offset, 
-                                        in unsigned long count, 
-                                        in DOMString arg)
-                                  raises(DOMException);
-};
deleted file mode 100644
--- a/dom/interfaces/core/nsIDOMComment.idl
+++ /dev/null
@@ -1,20 +0,0 @@
-/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "nsIDOMCharacterData.idl"
-
-/**
- * The nsIDOMComment interface inherits from nsIDOMCharacterData and represents 
- * the content of a comment, i.e., all the characters between the starting 
- * '<!--' and ending '-->'.
- * 
- * For more information on this interface please see 
- * http://www.w3.org/TR/DOM-Level-2-Core/
- */
-
-[uuid(e7866ff8-b7fc-494f-87c0-fb017d8a4d30)]
-interface nsIDOMComment : nsIDOMCharacterData
-{
-};
deleted file mode 100644
--- a/dom/interfaces/core/nsIDOMProcessingInstruction.idl
+++ /dev/null
@@ -1,22 +0,0 @@
-/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "nsIDOMCharacterData.idl"
-
-/**
- * The nsIDOMProcessingInstruction interface represents a 
- * "processing instruction", used in XML as a way to keep processor-specific 
- * information in the text of the document.
- *
- * For more information on this interface please see 
- * http://www.w3.org/TR/DOM-Level-2-Core/ and
- * http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html
- */
-
-[uuid(5a139df7-04d0-438d-bd18-d8122564258f)]
-interface nsIDOMProcessingInstruction : nsIDOMCharacterData
-{
-  readonly attribute DOMString        target;
-};
deleted file mode 100644
--- a/dom/interfaces/core/nsIDOMText.idl
+++ /dev/null
@@ -1,29 +0,0 @@
-/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "nsIDOMCharacterData.idl"
-
-/**
- * The nsIDOMText interface inherits from nsIDOMCharacterData and represents 
- * the textual content (termed character data in XML) of an Element or Attr.
- *
- * For more information on this interface please see 
- * http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html
- */
-
-[uuid(67273994-6aff-4091-9de9-b788a249f783)]
-interface nsIDOMText : nsIDOMCharacterData
-{
-  nsIDOMText                      splitText(in unsigned long offset)
-                                       raises(DOMException);
-
-  /**
-   * The concatenation of all logically adjacent text nodes with this text
-   * node, where "logically adjacent" consists of all text nodes which can be
-   * reached by traversing the document tree in either direction without
-   * passing an element, comment, or processing-instruction boundary.  
-   */
-  readonly attribute DOMString wholeText;
-};
--- a/dom/interfaces/events/moz.build
+++ b/dom/interfaces/events/moz.build
@@ -7,20 +7,17 @@
 with Files("**"):
     BUG_COMPONENT = ("Core", "DOM: Events")
 
 XPIDL_SOURCES += [
     'nsIDOMCustomEvent.idl',
     'nsIDOMEvent.idl',
     'nsIDOMEventListener.idl',
     'nsIDOMEventTarget.idl',
-    'nsIDOMFocusEvent.idl',
     'nsIDOMMouseEvent.idl',
-    'nsIDOMMouseScrollEvent.idl',
     'nsIDOMNotifyPaintEvent.idl',
     'nsIDOMNSEvent.idl',
-    'nsIDOMScrollAreaEvent.idl',
     'nsIDOMUIEvent.idl',
     'nsIDOMWheelEvent.idl',
 ]
 
 XPIDL_MODULE = 'dom_events'
 
deleted file mode 100644
--- a/dom/interfaces/events/nsIDOMFocusEvent.idl
+++ /dev/null
@@ -1,12 +0,0 @@
-/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "nsIDOMUIEvent.idl"
-
-[builtinclass, uuid(ceab9fcd-2cae-42cb-b692-effa7ec48848)]
-interface nsIDOMFocusEvent : nsIDOMUIEvent
-{
-  readonly attribute nsIDOMEventTarget  relatedTarget;
-};
deleted file mode 100644
--- a/dom/interfaces/events/nsIDOMMouseScrollEvent.idl
+++ /dev/null
@@ -1,13 +0,0 @@
-/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "nsIDOMMouseEvent.idl"
-
-[builtinclass, uuid(327bdd54-f772-4015-b856-9692154a066c)]
-interface nsIDOMMouseScrollEvent : nsIDOMMouseEvent
-{
-  const long HORIZONTAL_AXIS = 1;
-  const long VERTICAL_AXIS = 2;
-};
deleted file mode 100644
--- a/dom/interfaces/events/nsIDOMScrollAreaEvent.idl
+++ /dev/null
@@ -1,11 +0,0 @@
-/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "nsIDOMUIEvent.idl"
-
-[builtinclass, uuid(5883e564-e676-4652-9421-7df6132016b2)]
-interface nsIDOMScrollAreaEvent : nsIDOMUIEvent
-{
-};
--- a/dom/interfaces/xul/moz.build
+++ b/dom/interfaces/xul/moz.build
@@ -6,17 +6,16 @@
 
 with Files("**"):
     BUG_COMPONENT = ("Core", "XUL")
 
 XPIDL_SOURCES += [
     'nsIDOMXULButtonElement.idl',
     'nsIDOMXULCheckboxElement.idl',
     'nsIDOMXULCommandDispatcher.idl',
-    'nsIDOMXULCommandEvent.idl',
     'nsIDOMXULContainerElement.idl',
     'nsIDOMXULControlElement.idl',
     'nsIDOMXULDescriptionElement.idl',
     'nsIDOMXULElement.idl',
     'nsIDOMXULLabeledControlEl.idl',
     'nsIDOMXULLabelElement.idl',
     'nsIDOMXULMenuListElement.idl',
     'nsIDOMXULMultSelectCntrlEl.idl',
deleted file mode 100644
--- a/dom/interfaces/xul/nsIDOMXULCommandEvent.idl
+++ /dev/null
@@ -1,52 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim:set ts=2 sw=2 sts=2 et cindent: */
-/* 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/. */
-
-/**
- * This interface is supported by command events, which are dispatched to
- * XUL elements as a result of mouse or keyboard activation.
- */
-
-#include "nsIDOMUIEvent.idl"
-
-[builtinclass, uuid(564496b4-1174-48ec-927d-edeb66b86757)]
-interface nsIDOMXULCommandEvent : nsIDOMUIEvent
-{
-  /**
-   * Command events support the same set of modifier keys as mouse and key
-   * events.
-   */
-  readonly attribute boolean ctrlKey;
-  readonly attribute boolean shiftKey;
-  readonly attribute boolean altKey;
-  readonly attribute boolean metaKey;
-
-  /**
-   * The input source, if this event was triggered by a mouse event.
-  */
-  readonly attribute unsigned short inputSource;
-
-  /**
-   * If the command event was redispatched because of a command= attribute
-   * on the original target, sourceEvent will be set to the original DOM Event.
-   * Otherwise, sourceEvent is null.
-   */
-  readonly attribute nsIDOMEvent sourceEvent;
-
-  /**
-   * Creates a new command event with the given attributes.
-   */
-  void initCommandEvent(in DOMString typeArg,
-                        in boolean canBubbleArg,
-                        in boolean cancelableArg,
-                        in mozIDOMWindow viewArg,
-                        in long detailArg,
-                        in boolean ctrlKeyArg,
-                        in boolean altKeyArg,
-                        in boolean shiftKeyArg,
-                        in boolean metaKeyArg,
-                        in nsIDOMEvent sourceEvent,
-                        in unsigned short inputSource);
-};
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -2158,16 +2158,70 @@ ContentParent::~ContentParent()
   if (IsForJSPlugin()) {
     MOZ_ASSERT(!sJSPluginContentParents ||
                !sJSPluginContentParents->Get(mJSPluginID));
   } else {
     MOZ_ASSERT(!sBrowserContentParents ||
                !sBrowserContentParents->Contains(mRemoteType) ||
                !sBrowserContentParents->Get(mRemoteType)->Contains(this));
   }
+#ifdef NIGHTLY_BUILD
+  MessageChannel* channel = GetIPCChannel();
+
+  if (channel && !channel->Unsound_IsClosed()) {
+    nsString friendlyName;
+    FriendlyName(friendlyName, false);
+
+    AddRef();
+    nsrefcnt refcnt = Release();
+    uint32_t numQueuedMessages = 0;
+    numQueuedMessages = channel->Unsound_NumQueuedMessages();
+
+    nsPrintfCString msg("queued-ipc-messages/content-parent"
+                        "(%s, pid=%d, %s, 0x%p, refcnt=%" PRIuPTR
+                        ", numQueuedMessages=%d, remoteType=%s, "
+                        "mCalledClose=%s, mCalledKillHard=%s, "
+                        "mShutdownPending=%s, mIPCOpen=%s)",
+                        NS_ConvertUTF16toUTF8(friendlyName).get(),
+                        Pid(), "open channel",
+                        static_cast<nsIContentParent*>(this), refcnt,
+                        numQueuedMessages,
+                        NS_ConvertUTF16toUTF8(mRemoteType).get(),
+                        mCalledClose ? "true" : "false",
+                        mCalledKillHard ? "true" : "false",
+                        mShutdownPending ? "true" : "false",
+                        mIPCOpen ? "true" : "false");
+    CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("IPCFatalErrorMsg"),
+                                       msg);
+    switch (channel->GetChannelState__TotallyRacy()) {
+        case ChannelOpening:
+            MOZ_CRASH("MessageChannel destroyed without being closed " \
+                      "(mChannelState == ChannelOpening).");
+            break;
+        case ChannelConnected:
+            MOZ_CRASH("MessageChannel destroyed without being closed " \
+                      "(mChannelState == ChannelConnected).");
+            break;
+        case ChannelTimeout:
+            MOZ_CRASH("MessageChannel destroyed without being closed " \
+                      "(mChannelState == ChannelTimeout).");
+            break;
+        case ChannelClosing:
+            MOZ_CRASH("MessageChannel destroyed without being closed " \
+                      "(mChannelState == ChannelClosing).");
+            break;
+        case ChannelError:
+            MOZ_CRASH("MessageChannel destroyed without being closed " \
+                      "(mChannelState == ChannelError).");
+            break;
+        default:
+            MOZ_CRASH("MessageChannel destroyed without being closed.");
+    }
+  }
+#endif
 }
 
 void
 ContentParent::InitInternal(ProcessPriority aInitialPriority)
 {
   Telemetry::Accumulate(Telemetry::CONTENT_PROCESS_LAUNCH_TIME_MS,
                         static_cast<uint32_t>((TimeStamp::Now() - mLaunchTS)
                                               .ToMilliseconds()));
--- a/dom/security/test/mixedcontentblocker/file_frameNavigation_blankTarget.html
+++ b/dom/security/test/mixedcontentblocker/file_frameNavigation_blankTarget.html
@@ -12,17 +12,18 @@ https://bugzilla.mozilla.org/show_bug.cg
 <a href="http://example.com/tests/dom/security/test/mixedcontentblocker/file_frameNavigation_innermost.html?blankTarget" id="blankTarget" target="_blank">Go to http site</a>
 
 <script>
   var blankTarget = document.getElementById("blankTarget");
   blankTarget.click();
 
   var observer = {
     observe: function(subject, topic, data) {
-      if(topic == "content-document-global-created" && data =="http://example.com") {
+      //Subject location check added for Bug 1391823 to avoid removeAsyncObserver from being called multiple times
+      if(topic == "content-document-global-created" && data =="http://example.com" && subject.location.href == "http://example.com/tests/dom/security/test/mixedcontentblocker/file_frameNavigation_innermost.html?blankTarget") {
          parent.parent.postMessage({"test": "blankTarget", "msg": "opened an http link with target=_blank from a secure page"}, "http://mochi.test:8888");
          SpecialPowers.removeAsyncObserver(observer, "content-document-global-created");
       }
     }
   }
   SpecialPowers.addAsyncObserver(observer, "content-document-global-created");
 
 </script>
--- a/dom/webbrowserpersist/WebBrowserPersistLocalDocument.cpp
+++ b/dom/webbrowserpersist/WebBrowserPersistLocalDocument.cpp
@@ -13,32 +13,31 @@
 #include "mozilla/dom/HTMLAreaElement.h"
 #include "mozilla/dom/HTMLInputElement.h"
 #include "mozilla/dom/HTMLLinkElement.h"
 #include "mozilla/dom/HTMLObjectElement.h"
 #include "mozilla/dom/HTMLOptionElement.h"
 #include "mozilla/dom/HTMLSharedElement.h"
 #include "mozilla/dom/HTMLTextAreaElement.h"
 #include "mozilla/dom/NodeFilterBinding.h"
+#include "mozilla/dom/ProcessingInstruction.h"
 #include "mozilla/dom/TabParent.h"
 #include "mozilla/dom/TreeWalker.h"
 #include "mozilla/Unused.h"
 #include "nsComponentManagerUtils.h"
 #include "nsContentUtils.h"
 #include "nsContentCID.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsDOMAttributeMap.h"
 #include "nsFrameLoader.h"
 #include "nsIComponentRegistrar.h"
 #include "nsIContent.h"
-#include "nsIDOMComment.h"
 #include "nsIDOMDocument.h"
 #include "nsIDOMNode.h"
 #include "nsIDOMNodeList.h"
-#include "nsIDOMProcessingInstruction.h"
 #include "nsIDOMWindowUtils.h"
 #include "nsIDocShell.h"
 #include "nsIDocument.h"
 #include "nsIDocumentEncoder.h"
 #include "nsILoadContext.h"
 #include "nsIProtocolHandler.h"
 #include "nsISHEntry.h"
 #include "nsISupportsPrimitives.h"
@@ -426,53 +425,47 @@ ResourceReader::OnWalkAttribute(nsIDOMNo
     ExtractAttribute(aNode, aAttribute, aNamespaceURI, uriSpec);
     if (uriSpec.IsEmpty()) {
         return NS_OK;
     }
     return OnWalkURI(uriSpec);
 }
 
 static nsresult
-GetXMLStyleSheetLink(nsIDOMProcessingInstruction *aPI, nsAString &aHref)
+GetXMLStyleSheetLink(dom::ProcessingInstruction *aPI, nsAString &aHref)
 {
-    nsresult rv;
     nsAutoString data;
-    rv = aPI->GetData(data);
-    NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
+    aPI->GetData(data);
 
     nsContentUtils::GetPseudoAttributeValue(data, nsGkAtoms::href, aHref);
     return NS_OK;
 }
 
 nsresult
 ResourceReader::OnWalkDOMNode(nsIDOMNode* aNode)
 {
-    nsresult rv;
+    nsCOMPtr<nsIContent> content = do_QueryInterface(aNode);
+    if (!content) {
+        return NS_OK;
+    }
 
     // Fixup xml-stylesheet processing instructions
-    nsCOMPtr<nsIDOMProcessingInstruction> nodeAsPI = do_QueryInterface(aNode);
-    if (nodeAsPI) {
+    if (auto nodeAsPI = dom::ProcessingInstruction::FromContent(content)) {
         nsAutoString target;
-        rv = nodeAsPI->GetTarget(target);
-        NS_ENSURE_SUCCESS(rv, rv);
+        nodeAsPI->GetTarget(target);
         if (target.EqualsLiteral("xml-stylesheet")) {
             nsAutoString href;
             GetXMLStyleSheetLink(nodeAsPI, href);
             if (!href.IsEmpty()) {
                 return OnWalkURI(NS_ConvertUTF16toUTF8(href));
             }
         }
         return NS_OK;
     }
 
-    nsCOMPtr<nsIContent> content = do_QueryInterface(aNode);
-    if (!content) {
-        return NS_OK;
-    }
-
     // Test the node to see if it's an image, frame, iframe, css, js
     if (content->IsHTMLElement(nsGkAtoms::img)) {
         return OnWalkAttribute(aNode, "src");
     }
 
     if (content->IsSVGElement(nsGkAtoms::img)) {
         return OnWalkAttribute(aNode, "href", "http://www.w3.org/1999/xlink");
     }
@@ -597,17 +590,17 @@ private:
     nsresult FixupNode(nsINode *aNodeIn, bool *aSerializeCloneKids,
                        nsINode **aNodeOut);
     nsresult GetNodeToFixup(nsINode* aNodeIn, nsINode** aNodeOut);
     nsresult FixupURI(nsAString& aURI);
     nsresult FixupAttribute(nsINode* aNode,
                             const char* aAttribute,
                             const char* aNamespaceURI = "");
     nsresult FixupAnchor(nsINode* aNode);
-    nsresult FixupXMLStyleSheetLink(nsIDOMProcessingInstruction* aPI,
+    nsresult FixupXMLStyleSheetLink(dom::ProcessingInstruction* aPI,
                                     const nsAString& aHref);
 
     using IWBP = nsIWebBrowserPersist;
 };
 
 NS_IMPL_ISUPPORTS(PersistNodeFixup, nsIDocumentEncoderNodeFixup)
 
 PersistNodeFixup::PersistNodeFixup(WebBrowserPersistLocalDocument* aParent,
@@ -782,25 +775,23 @@ AppendXMLAttr(const nsAString& key, cons
                 aBuffer.Append(aValue[i]);
                 break;
         }
     }
     aBuffer.Append('"');
 }
 
 nsresult
-PersistNodeFixup::FixupXMLStyleSheetLink(nsIDOMProcessingInstruction* aPI,
+PersistNodeFixup::FixupXMLStyleSheetLink(dom::ProcessingInstruction* aPI,
                                          const nsAString& aHref)
 {
     NS_ENSURE_ARG_POINTER(aPI);
-    nsresult rv = NS_OK;
 
     nsAutoString data;
-    rv = aPI->GetData(data);
-    NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
+    aPI->GetData(data);
 
     nsAutoString href;
     nsContentUtils::GetPseudoAttributeValue(data,
                                             nsGkAtoms::href,
                                             href);
 
     // Construct and set a new data value for the xml-stylesheet
     if (!aHref.IsEmpty() && !href.IsEmpty())
@@ -839,20 +830,20 @@ PersistNodeFixup::FixupXMLStyleSheetLink
             AppendXMLAttr(NS_LITERAL_STRING("type"), type, newData);
         }
         if (!charset.IsEmpty()) {
             AppendXMLAttr(NS_LITERAL_STRING("charset"), charset, newData);
         }
         if (!alternate.IsEmpty()) {
             AppendXMLAttr(NS_LITERAL_STRING("alternate"), alternate, newData);
         }
-        aPI->SetData(newData);
+        aPI->SetData(newData, IgnoreErrors());
     }
 
-    return rv;
+    return NS_OK;
 }
 
 NS_IMETHODIMP
 PersistNodeFixup::FixupNode(nsIDOMNode *aNodeIn,
                             bool *aSerializeCloneKids,
                             nsIDOMNode **aNodeOut)
 {
     nsCOMPtr<nsINode> nodeIn = do_QueryInterface(aNodeIn);
@@ -879,32 +870,35 @@ PersistNodeFixup::FixupNode(nsINode* aNo
     *aSerializeCloneKids = false;
 
     uint16_t type = aNodeIn->NodeType();
     if (type != nsINode::ELEMENT_NODE &&
         type != nsINode::PROCESSING_INSTRUCTION_NODE) {
         return NS_OK;
     }
 
+    MOZ_ASSERT(aNodeIn->IsContent());
+
     // Fixup xml-stylesheet processing instructions
-    nsCOMPtr<nsIDOMProcessingInstruction> nodeAsPI = do_QueryInterface(aNodeIn);
-    if (nodeAsPI) {
+    if (auto nodeAsPI =
+          dom::ProcessingInstruction::FromContent(aNodeIn->AsContent())) {
         nsAutoString target;
         nodeAsPI->GetTarget(target);
         if (target.EqualsLiteral("xml-stylesheet"))
         {
             nsresult rv = GetNodeToFixup(aNodeIn, aNodeOut);
             if (NS_SUCCEEDED(rv) && *aNodeOut) {
-                nsCOMPtr<nsIDOMProcessingInstruction> outNode =
-                    do_QueryInterface(*aNodeOut);
+                MOZ_ASSERT((*aNodeOut)->IsProcessingInstruction());
+                auto nodeAsPI =
+                  static_cast<dom::ProcessingInstruction*>(*aNodeOut);
                 nsAutoString href;
                 GetXMLStyleSheetLink(nodeAsPI, href);
                 if (!href.IsEmpty()) {
                     FixupURI(href);
-                    FixupXMLStyleSheetLink(outNode, href);
+                    FixupXMLStyleSheetLink(nodeAsPI, href);
                 }
             }
         }
         return NS_OK;
     }
 
     nsCOMPtr<nsIContent> content = do_QueryInterface(aNodeIn);
     if (!content) {
--- a/dom/webidl/Node.webidl
+++ b/dom/webidl/Node.webidl
@@ -99,18 +99,16 @@ interface Node : EventTarget {
   boolean isDefaultNamespace(DOMString? namespace);
 
   // Mozilla-specific stuff
   [ChromeOnly]
   readonly attribute Principal nodePrincipal;
   [ChromeOnly]
   readonly attribute URI? baseURIObject;
   [ChromeOnly]
-  sequence<MutationObserver> getBoundMutationObservers();
-  [ChromeOnly]
   DOMString generateXPath();
 
   /**
    * This method provides a fast-path for the Fluent localization system to
    * bypass the slowdowns in performance during initial document translation.
    * The slowdowns are specific to XBL+Stylo.
    * To learn more, see bug 1441037.
    *
--- a/dom/webidl/XULCommandEvent.webidl
+++ b/dom/webidl/XULCommandEvent.webidl
@@ -1,26 +1,46 @@
 /* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/.
  */
 
+/**
+ * This interface is supported by command events, which are dispatched to
+ * XUL elements as a result of mouse or keyboard activation.
+ */
 [Func="IsChromeOrXBL"]
 interface XULCommandEvent : UIEvent
 {
+  /**
+   * Command events support the same set of modifier keys as mouse and key
+   * events.
+   */
   readonly attribute boolean ctrlKey;
   readonly attribute boolean shiftKey;
   readonly attribute boolean altKey;
   readonly attribute boolean metaKey;
 
+  /**
+   * The input source, if this event was triggered by a mouse event.
+   */
   readonly attribute unsigned short inputSource;
 
+  /**
+   * If the command event was redispatched because of a command= attribute
+   * on the original target, sourceEvent will be set to the original DOM Event.
+   * Otherwise, sourceEvent is null.
+   */
   readonly attribute Event? sourceEvent;
 
+  /**
+   * Creates a new command event with the given attributes.
+   */
+  [Throws]
   void initCommandEvent(DOMString type,
                         optional boolean canBubble = false,
                         optional boolean cancelable = false,
                         optional Window? view = null,
                         optional long detail = 0,
                         optional boolean ctrlKey = false,
                         optional boolean altKey = false,
                         optional boolean shiftKey = false,
--- a/dom/xml/CDATASection.cpp
+++ b/dom/xml/CDATASection.cpp
@@ -10,41 +10,40 @@
 
 namespace mozilla {
 namespace dom {
 
 CDATASection::~CDATASection()
 {
 }
 
-NS_IMPL_ISUPPORTS_INHERITED(CDATASection, nsGenericDOMDataNode, nsIDOMNode,
-                            nsIDOMCharacterData, nsIDOMText)
+NS_IMPL_ISUPPORTS_INHERITED(CDATASection, CharacterData, nsIDOMNode)
 
 JSObject*
 CDATASection::WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto)
 {
   return CDATASectionBinding::Wrap(aCx, this, aGivenProto);
 }
 
 bool
 CDATASection::IsNodeOfType(uint32_t aFlags) const
 {
   return !(aFlags & ~(eTEXT | eDATA_NODE));
 }
 
-nsGenericDOMDataNode*
+already_AddRefed<CharacterData>
 CDATASection::CloneDataNode(mozilla::dom::NodeInfo *aNodeInfo, bool aCloneText) const
 {
   RefPtr<mozilla::dom::NodeInfo> ni = aNodeInfo;
-  CDATASection *it = new CDATASection(ni.forget());
-  if (it && aCloneText) {
+  RefPtr<CDATASection> it = new CDATASection(ni.forget());
+  if (aCloneText) {
     it->mText = mText;
   }
 
-  return it;
+  return it.forget();
 }
 
 #ifdef DEBUG
 void
 CDATASection::List(FILE* out, int32_t aIndent) const
 {
   int32_t index;
   for (index = aIndent; --index >= 0; ) fputs("  ", out);
--- a/dom/xml/CDATASection.h
+++ b/dom/xml/CDATASection.h
@@ -4,22 +4,23 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_CDATASection_h
 #define mozilla_dom_CDATASection_h
 
 #include "mozilla/Attributes.h"
 #include "mozilla/dom/Text.h"
+#include "nsIDOMNode.h"
 
 namespace mozilla {
 namespace dom {
 
 class CDATASection final : public Text,
-                           public nsIDOMText
+                           public nsIDOMNode
 {
 private:
   void Init()
   {
     MOZ_ASSERT(mNodeInfo->NodeType() == CDATA_SECTION_NODE,
                "Bad NodeType in aNodeInfo");
   }
 
@@ -38,28 +39,22 @@ public:
                                          CDATA_SECTION_NODE))
   {
     Init();
   }
 
   // nsISupports
   NS_DECL_ISUPPORTS_INHERITED
 
-  // nsIDOMCharacterData
-  NS_FORWARD_NSIDOMCHARACTERDATA(nsGenericDOMDataNode::)
-  using nsGenericDOMDataNode::SetData; // Prevent hiding overloaded virtual function.
-
-  // nsIDOMText
-  NS_FORWARD_NSIDOMTEXT(nsGenericDOMDataNode::)
-
   // nsINode
   virtual bool IsNodeOfType(uint32_t aFlags) const override;
 
-  virtual nsGenericDOMDataNode* CloneDataNode(mozilla::dom::NodeInfo *aNodeInfo,
-                                              bool aCloneText) const override;
+  virtual already_AddRefed<CharacterData>
+    CloneDataNode(mozilla::dom::NodeInfo *aNodeInfo,
+                  bool aCloneText) const override;
 
   virtual nsIDOMNode* AsDOMNode() override { return this; }
 #ifdef DEBUG
   virtual void List(FILE* out, int32_t aIndent) const override;
   virtual void DumpContent(FILE* out, int32_t aIndent,bool aDumpAll) const override;
 #endif
 
 protected:
--- a/dom/xml/ProcessingInstruction.cpp
+++ b/dom/xml/ProcessingInstruction.cpp
@@ -43,71 +43,61 @@ NS_NewXMLProcessingInstruction(nsNodeInf
   return instance.forget();
 }
 
 namespace mozilla {
 namespace dom {
 
 ProcessingInstruction::ProcessingInstruction(already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
                                              const nsAString& aData)
-  : nsGenericDOMDataNode(Move(aNodeInfo))
+  : CharacterData(Move(aNodeInfo))
 {
   MOZ_ASSERT(mNodeInfo->NodeType() == nsINode::PROCESSING_INSTRUCTION_NODE,
              "Bad NodeType in aNodeInfo");
 
   SetTextInternal(0, mText.GetLength(),
                   aData.BeginReading(), aData.Length(),
                   false);  // Don't notify (bug 420429).
 }
 
 ProcessingInstruction::~ProcessingInstruction()
 {
 }
 
-NS_IMPL_ISUPPORTS_INHERITED(ProcessingInstruction, nsGenericDOMDataNode,
-                            nsIDOMNode, nsIDOMCharacterData,
-                            nsIDOMProcessingInstruction)
+NS_IMPL_ISUPPORTS_INHERITED(ProcessingInstruction, CharacterData, nsIDOMNode)
 
 JSObject*
 ProcessingInstruction::WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto)
 {
   return ProcessingInstructionBinding::Wrap(aCx, this, aGivenProto);
 }
 
-NS_IMETHODIMP
-ProcessingInstruction::GetTarget(nsAString& aTarget)
-{
-  aTarget = NodeName();
-
-  return NS_OK;
-}
-
 bool
 ProcessingInstruction::GetAttrValue(nsAtom *aName, nsAString& aValue)
 {
   nsAutoString data;
 
   GetData(data);
   return nsContentUtils::GetPseudoAttributeValue(data, aName, aValue);
 }
 
 bool
 ProcessingInstruction::IsNodeOfType(uint32_t aFlags) const
 {
   return !(aFlags & ~(ePROCESSING_INSTRUCTION | eDATA_NODE));
 }
 
-nsGenericDOMDataNode*
+already_AddRefed<CharacterData>
 ProcessingInstruction::CloneDataNode(mozilla::dom::NodeInfo *aNodeInfo,
                                      bool aCloneText) const
 {
   nsAutoString data;
-  nsGenericDOMDataNode::GetData(data);
+  GetData(data);
   RefPtr<mozilla::dom::NodeInfo> ni = aNodeInfo;
-  return new ProcessingInstruction(ni.forget(), data);
+  return do_AddRef(new ProcessingInstruction(ni.forget(), data));
 }
 
 #ifdef DEBUG
 void
 ProcessingInstruction::List(FILE* out, int32_t aIndent) const
 {
   int32_t index;
   for (index = aIndent; --index >= 0; ) fputs("  ", out);
--- a/dom/xml/ProcessingInstruction.h
+++ b/dom/xml/ProcessingInstruction.h
@@ -3,58 +3,55 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_ProcessingInstruction_h
 #define mozilla_dom_ProcessingInstruction_h
 
 #include "mozilla/Attributes.h"
-#include "nsIDOMProcessingInstruction.h"
-#include "nsGenericDOMDataNode.h"
+#include "mozilla/dom/CharacterData.h"
+#include "nsIDOMNode.h"
 #include "nsAString.h"
 
 namespace mozilla {
 namespace dom {
 
-class ProcessingInstruction : public nsGenericDOMDataNode,
-                              public nsIDOMProcessingInstruction
+class ProcessingInstruction : public CharacterData,
+                              public nsIDOMNode
 {
 public:
   ProcessingInstruction(already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
                         const nsAString& aData);
 
   // nsISupports
   NS_DECL_ISUPPORTS_INHERITED
 
-  // nsIDOMCharacterData
-  NS_FORWARD_NSIDOMCHARACTERDATA(nsGenericDOMDataNode::)
-  using nsGenericDOMDataNode::SetData; // Prevent hiding overloaded virtual function.
-
-  // nsIDOMProcessingInstruction
-  NS_DECL_NSIDOMPROCESSINGINSTRUCTION
-
   // nsINode
   virtual bool IsNodeOfType(uint32_t aFlags) const override;
 
-  virtual nsGenericDOMDataNode* CloneDataNode(mozilla::dom::NodeInfo *aNodeInfo,
-                                              bool aCloneText) const override;
+  virtual already_AddRefed<CharacterData>
+    CloneDataNode(mozilla::dom::NodeInfo *aNodeInfo,
+                  bool aCloneText) const override;
 
 #ifdef DEBUG
   virtual void List(FILE* out, int32_t aIndent) const override;
   virtual void DumpContent(FILE* out, int32_t aIndent, bool aDumpAll) const override;
 #endif
 
   virtual nsIDOMNode* AsDOMNode() override { return this; }
 
   // WebIDL API
-  void GetTarget(nsString& aTarget)
+  void GetTarget(nsAString& aTarget)
   {
     aTarget = NodeName();
   }
+
+  NS_IMPL_FROMCONTENT_HELPER(ProcessingInstruction, IsProcessingInstruction())
+
 protected:
   virtual ~ProcessingInstruction();
 
   /**
    * This will parse the content of the PI, to extract the value of the pseudo
    * attribute with the name specified in aName. See
    * http://www.w3.org/TR/xml-stylesheet/#NT-StyleSheetPI for the specification
    * which is used to parse the content of the PI.
--- a/dom/xml/XMLStylesheetProcessingInstruction.cpp
+++ b/dom/xml/XMLStylesheetProcessingInstruction.cpp
@@ -12,17 +12,16 @@
 namespace mozilla {
 namespace dom {
 
 // nsISupports implementation
 
 NS_IMPL_ISUPPORTS_CYCLE_COLLECTION_INHERITED(XMLStylesheetProcessingInstruction,
                                              ProcessingInstruction,
                                              nsIDOMNode,
-                                             nsIDOMProcessingInstruction,
                                              nsIStyleSheetLinkingElement)
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(XMLStylesheetProcessingInstruction)
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(XMLStylesheetProcessingInstruction,
                                                   ProcessingInstruction)
   tmp->nsStyleLinkElement::Traverse(cb);
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
@@ -74,17 +73,17 @@ XMLStylesheetProcessingInstruction::Unbi
 }
 
 // nsIDOMNode
 
 void
 XMLStylesheetProcessingInstruction::SetNodeValueInternal(const nsAString& aNodeValue,
                                                          ErrorResult& aError)
 {
-  nsGenericDOMDataNode::SetNodeValueInternal(aNodeValue, aError);
+  CharacterData::SetNodeValueInternal(aNodeValue, aError);
   if (!aError.Failed()) {
     UpdateStyleSheetInternal(nullptr, nullptr, true);
   }
 }
 
 // nsStyleLinkElement
 
 void
@@ -173,20 +172,20 @@ XMLStylesheetProcessingInstruction::GetS
     return;
   }
 
   // If we get here we assume that we're loading a css file, so set the
   // type to 'text/css'
   aType.AssignLiteral("text/css");
 }
 
-nsGenericDOMDataNode*
+already_AddRefed<CharacterData>
 XMLStylesheetProcessingInstruction::CloneDataNode(mozilla::dom::NodeInfo *aNodeInfo,
                                                   bool aCloneText) const
 {
   nsAutoString data;
-  nsGenericDOMDataNode::GetData(data);
+  GetData(data);
   RefPtr<mozilla::dom::NodeInfo> ni = aNodeInfo;
-  return new XMLStylesheetProcessingInstruction(ni.forget(), data);
+  return do_AddRef(new XMLStylesheetProcessingInstruction(ni.forget(), data));
 }
 
 } // namespace dom
 } // namespace mozilla
--- a/dom/xml/XMLStylesheetProcessingInstruction.h
+++ b/dom/xml/XMLStylesheetProcessingInstruction.h
@@ -59,35 +59,35 @@ public:
   // nsIStyleSheetLinkingElement
   virtual void OverrideBaseURI(nsIURI* aNewBaseURI) override;
 
   // nsStyleLinkElement
   void GetCharset(nsAString& aCharset) override;
 
   virtual void SetData(const nsAString& aData, mozilla::ErrorResult& rv) override
   {
-    nsGenericDOMDataNode::SetData(aData, rv);
+    CharacterData::SetData(aData, rv);
     if (rv.Failed()) {
       return;
     }
     UpdateStyleSheetInternal(nullptr, nullptr, true);
   }
-  using ProcessingInstruction::SetData; // Prevent hiding overloaded virtual function.
 
 protected:
   virtual ~XMLStylesheetProcessingInstruction();
 
   nsCOMPtr<nsIURI> mOverriddenBaseURI;
 
   already_AddRefed<nsIURI>
     GetStyleSheetURL(bool* aIsInline, nsIPrincipal** aTriggeringPrincipal) final;
   void GetStyleSheetInfo(nsAString& aTitle,
                          nsAString& aType,
                          nsAString& aMedia,
                          bool* aIsAlternate) final;
-  nsGenericDOMDataNode* CloneDataNode(mozilla::dom::NodeInfo* aNodeInfo,
-                                      bool aCloneText) const final;
+  already_AddRefed<CharacterData>
+    CloneDataNode(mozilla::dom::NodeInfo* aNodeInfo,
+                  bool aCloneText) const final;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_XMLStylesheetProcessingInstruction_h
--- a/dom/xml/nsXMLContentSink.cpp
+++ b/dom/xml/nsXMLContentSink.cpp
@@ -8,17 +8,16 @@
 #include "nsXMLContentSink.h"
 #include "nsIParser.h"
 #include "nsIDocument.h"
 #include "nsIContent.h"
 #include "nsIURI.h"
 #include "nsNetUtil.h"
 #include "nsIDocShell.h"
 #include "nsIStyleSheetLinkingElement.h"
-#include "nsIDOMComment.h"
 #include "nsHTMLParts.h"
 #include "nsCRT.h"
 #include "mozilla/StyleSheetInlines.h"
 #include "mozilla/css/Loader.h"
 #include "nsGkAtoms.h"
 #include "nsContentUtils.h"
 #include "nsIScriptContext.h"
 #include "nsNameSpaceManager.h"
@@ -38,17 +37,16 @@
 #include "nsIChannel.h"
 #include "nsIPrincipal.h"
 #include "nsXMLPrettyPrinter.h"
 #include "nsNodeInfoManager.h"
 #include "nsContentCreatorFunctions.h"
 #include "nsIContentPolicy.h"
 #include "nsContentPolicyUtils.h"
 #include "nsError.h"
-#include "nsIDOMProcessingInstruction.h"
 #include "nsNodeUtils.h"
 #include "nsIScriptGlobalObject.h"
 #include "nsIHTMLDocument.h"
 #include "mozAutoDocUpdate.h"
 #include "nsMimeTypes.h"
 #include "nsHtml5SVGLoadDispatcher.h"
 #include "nsTextNode.h"
 #include "mozilla/dom/CDATASection.h"
@@ -213,17 +211,17 @@ nsXMLContentSink::MaybePrettyPrint()
   rv = printer->PrettyPrint(mDocument, &isPrettyPrinting);
   NS_ENSURE_SUCCESS(rv, rv);
 
   mPrettyPrinting = isPrettyPrinting;
   return NS_OK;
 }
 
 static void
-CheckXSLTParamPI(nsIDOMProcessingInstruction* aPi,
+CheckXSLTParamPI(ProcessingInstruction* aPi,
                  nsIDocumentTransformer* aProcessor,
                  nsIDocument* aDocument)
 {
   nsAutoString target, data;
   aPi->GetTarget(target);
 
   // Check for namespace declarations
   if (target.EqualsLiteral("xslt-param-namespace")) {
@@ -277,18 +275,17 @@ nsXMLContentSink::DidBuildModel(bool aTe
     // stop observing in order to avoid crashing when replacing content
     mDocument->RemoveObserver(this);
     mIsDocumentObserver = false;
 
     // Check for xslt-param and xslt-param-namespace PIs
     for (nsIContent* child = mDocument->GetFirstChild();
          child;
          child = child->GetNextSibling()) {
-      if (child->IsNodeOfType(nsINode::ePROCESSING_INSTRUCTION)) {
-        nsCOMPtr<nsIDOMProcessingInstruction> pi = do_QueryInterface(child);
+      if (auto pi = ProcessingInstruction::FromContent(child)) {
         CheckXSLTParamPI(pi, mXSLTProcessor, mDocument);
       }
       else if (child->IsElement()) {
         // Only honor PIs in the prolog
         break;
       }
     }
 
--- a/dom/xslt/xpath/XPathExpression.cpp
+++ b/dom/xslt/xpath/XPathExpression.cpp
@@ -4,24 +4,24 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/Move.h"
 #include "XPathExpression.h"
 #include "txExpr.h"
 #include "txExprResult.h"
 #include "txIXPathContext.h"
 #include "nsError.h"
-#include "nsIDOMCharacterData.h"
 #include "nsDOMClassInfoID.h"
 #include "nsIDOMDocument.h"
 #include "nsINode.h"
 #include "XPathResult.h"
 #include "txURIUtils.h"
 #include "txXPathTreeWalker.h"
 #include "mozilla/dom/BindingUtils.h"
+#include "mozilla/dom/Text.h"
 #include "mozilla/dom/XPathResultBinding.h"
 
 using mozilla::Move;
 
 namespace mozilla {
 namespace dom {
 
 class EvalContextImpl : public txIEvalContext
@@ -121,25 +121,20 @@ XPathExpression::EvaluateWithContext(nsI
             return nullptr;
         }
     }
 
     uint16_t nodeType = aContextNode.NodeType();
 
     if (nodeType == nsINode::TEXT_NODE ||
         nodeType == nsINode::CDATA_SECTION_NODE) {
-        nsCOMPtr<nsIDOMCharacterData> textNode =
-            do_QueryInterface(&aContextNode);
-        if (!textNode) {
-            aRv.Throw(NS_ERROR_FAILURE);
-            return nullptr;
-        }
+        Text* textNode = aContextNode.GetAsText();
+        MOZ_ASSERT(textNode);
 
-        uint32_t textLength;
-        textNode->GetLength(&textLength);
+        uint32_t textLength = textNode->Length();
         if (textLength == 0) {
             aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
             return nullptr;
         }
 
         // XXX Need to get logical XPath text node for CDATASection
         //     and Text nodes.
     }
--- a/dom/xslt/xpath/txMozillaXPathTreeWalker.cpp
+++ b/dom/xslt/xpath/txMozillaXPathTreeWalker.cpp
@@ -3,17 +3,16 @@
  * 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 "txXPathTreeWalker.h"
 #include "nsAtom.h"
 #include "nsIAttribute.h"
 #include "nsIDOMDocument.h"
 #include "nsIDOMElement.h"
-#include "nsIDOMProcessingInstruction.h"
 #include "nsINode.h"
 #include "nsPrintfCString.h"
 #include "nsReadableUtils.h"
 #include "nsString.h"
 #include "nsTextFragment.h"
 #include "txXMLUtils.h"
 #include "txLog.h"
 #include "nsUnicharUtils.h"
--- a/dom/xslt/xslt/txMozillaXSLTProcessor.cpp
+++ b/dom/xslt/xslt/txMozillaXSLTProcessor.cpp
@@ -4,17 +4,16 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "txMozillaXSLTProcessor.h"
 #include "nsContentCID.h"
 #include "nsError.h"
 #include "nsIChannel.h"
 #include "mozilla/dom/Element.h"
 #include "nsIDOMElement.h"
-#include "nsIDOMText.h"
 #include "nsIDocument.h"
 #include "nsIDOMDocument.h"
 #include "nsIDOMDocumentFragment.h"
 #include "nsIDOMNodeList.h"
 #include "nsIIOService.h"
 #include "nsILoadGroup.h"
 #include "nsIStringBundle.h"
 #include "nsIURI.h"
--- a/dom/xul/nsXULElement.cpp
+++ b/dom/xul/nsXULElement.cpp
@@ -79,25 +79,25 @@
 
 #include "nsReadableUtils.h"
 #include "nsIFrame.h"
 #include "nsNodeInfoManager.h"
 #include "nsXBLBinding.h"
 #include "nsXULTooltipListener.h"
 #include "mozilla/EventDispatcher.h"
 #include "mozAutoDocUpdate.h"
-#include "nsIDOMXULCommandEvent.h"
 #include "nsCCUncollectableMarker.h"
 #include "nsICSSDeclaration.h"
 #include "nsLayoutUtils.h"
 
 #include "mozilla/dom/XULElementBinding.h"
 #include "mozilla/dom/BoxObject.h"
 #include "mozilla/dom/HTMLIFrameElement.h"
 #include "mozilla/dom/MutationEventBinding.h"
+#include "mozilla/dom/XULCommandEvent.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 #ifdef XUL_PROTOTYPE_ATTRIBUTE_METERING
 uint32_t             nsXULPrototypeAttribute::gNumElements;
 uint32_t             nsXULPrototypeAttribute::gNumAttributes;
 uint32_t             nsXULPrototypeAttribute::gNumCacheTests;
@@ -1359,21 +1359,20 @@ nsXULElement::DispatchXULCommand(const E
         // sourceEvent will be the original command event that we're
         // handling.
         nsCOMPtr<nsIDOMEvent> domEvent = aVisitor.mDOMEvent;
         uint16_t inputSource = nsIDOMMouseEvent::MOZ_SOURCE_UNKNOWN;
         while (domEvent) {
             Event* event = domEvent->InternalDOMEvent();
             NS_ENSURE_STATE(!SameCOMIdentity(event->GetOriginalTarget(),
                                              commandElt));
-            nsCOMPtr<nsIDOMXULCommandEvent> commandEvent =
-                do_QueryInterface(domEvent);
+            RefPtr<XULCommandEvent> commandEvent = event->AsXULCommandEvent();
             if (commandEvent) {
-                commandEvent->GetSourceEvent(getter_AddRefs(domEvent));
-                commandEvent->GetInputSource(&inputSource);
+                domEvent = commandEvent->GetSourceEvent();
+                inputSource = commandEvent->InputSource();
             } else {
                 domEvent = nullptr;
             }
         }
         WidgetInputEvent* orig = aVisitor.mEvent->AsInputEvent();
         nsContentUtils::DispatchXULCommand(
           commandElt,
           orig->IsTrusted(),
@@ -1401,22 +1400,21 @@ nsXULElement::GetEventTargetParent(Event
         return NS_OK;
     }
     if (aVisitor.mEvent->mMessage == eXULCommand &&
         aVisitor.mEvent->mClass == eInputEventClass &&
         aVisitor.mEvent->mOriginalTarget == static_cast<nsIContent*>(this) &&
         !IsXULElement(nsGkAtoms::command)) {
         // Check that we really have an xul command event. That will be handled
         // in a special way.
-        nsCOMPtr<nsIDOMXULCommandEvent> xulEvent =
-            do_QueryInterface(aVisitor.mDOMEvent);
         // See if we have a command elt.  If so, we execute on the command
         // instead of on our content element.
         nsAutoString command;
-        if (xulEvent &&
+        if (aVisitor.mDOMEvent &&
+            aVisitor.mDOMEvent->InternalDOMEvent()->AsXULCommandEvent() &&
             GetAttr(kNameSpaceID_None, nsGkAtoms::command, command) &&
             !command.IsEmpty()) {
             // Stop building the event target chain for the original event.
             // We don't want it to propagate to any DOM nodes.
             aVisitor.mCanHandle = false;
             aVisitor.mAutomaticChromeDispatch = false;
             // Dispatch XUL command in PreHandleEvent to prevent it breaks event
             // target chain creation
--- a/editor/libeditor/CompositionTransaction.cpp
+++ b/editor/libeditor/CompositionTransaction.cpp
@@ -99,44 +99,45 @@ CompositionTransaction::DoTransaction()
 
   // Fail before making any changes if there's no selection controller
   nsCOMPtr<nsISelectionController> selCon;
   mEditorBase->GetSelectionController(getter_AddRefs(selCon));
   NS_ENSURE_TRUE(selCon, NS_ERROR_NOT_INITIALIZED);
 
   // Advance caret: This requires the presentation shell to get the selection.
   if (mReplaceLength == 0) {
-    nsresult rv = mTextNode->InsertData(mOffset, mStringToInsert);
-    if (NS_WARN_IF(NS_FAILED(rv))) {
-      return rv;
+    ErrorResult rv;
+    mTextNode->InsertData(mOffset, mStringToInsert, rv);
+    if (NS_WARN_IF(rv.Failed())) {
+      return rv.StealNSResult();
     }
     mEditorBase->RangeUpdaterRef().
                    SelAdjInsertText(*mTextNode, mOffset, mStringToInsert);
   } else {
     uint32_t replaceableLength = mTextNode->TextLength() - mOffset;
-    nsresult rv =
-      mTextNode->ReplaceData(mOffset, mReplaceLength, mStringToInsert);
-    if (NS_WARN_IF(NS_FAILED(rv))) {
-      return rv;
+    ErrorResult rv;
+    mTextNode->ReplaceData(mOffset, mReplaceLength, mStringToInsert, rv);
+    if (NS_WARN_IF(rv.Failed())) {
+      return rv.StealNSResult();
     }
     mEditorBase->RangeUpdaterRef().
                    SelAdjDeleteText(mTextNode, mOffset, mReplaceLength);
     mEditorBase->RangeUpdaterRef().
                    SelAdjInsertText(*mTextNode, mOffset, mStringToInsert);
 
     // If IME text node is multiple node, ReplaceData doesn't remove all IME
     // text.  So we need remove remained text into other text node.
     if (replaceableLength < mReplaceLength) {
       int32_t remainLength = mReplaceLength - replaceableLength;
       nsCOMPtr<nsINode> node = mTextNode->GetNextSibling();
       while (node && node->IsNodeOfType(nsINode::eTEXT) &&
              remainLength > 0) {
         Text* text = static_cast<Text*>(node.get());
         uint32_t textLength = text->TextLength();
-        text->DeleteData(0, remainLength);
+        text->DeleteData(0, remainLength, IgnoreErrors());
         mEditorBase->RangeUpdaterRef().SelAdjDeleteText(text, 0, remainLength);
         remainLength -= textLength;
         node = node->GetNextSibling();
       }
     }
   }
 
   nsresult rv = SetSelectionForRanges();
@@ -152,21 +153,24 @@ CompositionTransaction::UndoTransaction(
     return NS_ERROR_NOT_INITIALIZED;
   }
 
   // Get the selection first so we'll fail before making any changes if we
   // can't get it
   RefPtr<Selection> selection = mEditorBase->GetSelection();
   NS_ENSURE_TRUE(selection, NS_ERROR_NOT_INITIALIZED);
 
-  nsresult rv = mTextNode->DeleteData(mOffset, mStringToInsert.Length());
-  NS_ENSURE_SUCCESS(rv, rv);
+  ErrorResult err;
+  mTextNode->DeleteData(mOffset, mStringToInsert.Length(), err);
+  if (NS_WARN_IF(err.Failed())) {
+    return err.StealNSResult();
+  }
 
   // set the selection to the insertion point where the string was removed
-  rv = selection->Collapse(mTextNode, mOffset);
+  nsresult rv = selection->Collapse(mTextNode, mOffset);
   NS_ASSERTION(NS_SUCCEEDED(rv),
                "Selection could not be collapsed after undo of IME insert.");
   NS_ENSURE_SUCCESS(rv, rv);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
--- a/editor/libeditor/DeleteRangeTransaction.cpp
+++ b/editor/libeditor/DeleteRangeTransaction.cpp
@@ -141,18 +141,18 @@ DeleteRangeTransaction::CreateTxnsToDele
     int32_t numToDel;
     if (aStart == aEnd) {
       numToDel = 1;
     } else {
       numToDel = aEnd.Offset() - aStart.Offset();
       MOZ_DIAGNOSTIC_ASSERT(numToDel > 0);
     }
 
-    RefPtr<nsGenericDOMDataNode> charDataNode =
-      static_cast<nsGenericDOMDataNode*>(aStart.Container());
+    RefPtr<CharacterData> charDataNode =
+      static_cast<CharacterData*>(aStart.Container());
 
     RefPtr<DeleteTextTransaction> deleteTextTransaction =
       DeleteTextTransaction::MaybeCreate(*mEditorBase, *charDataNode,
                                          aStart.Offset(), numToDel);
     // If the text node isn't editable, it should be never undone/redone.
     // So, the transaction shouldn't be recorded.
     if (NS_WARN_IF(!deleteTextTransaction)) {
       return NS_ERROR_FAILURE;
@@ -206,18 +206,18 @@ DeleteRangeTransaction::CreateTxnsToDele
     startOffset = 0;
     numToDelete = aPoint.Offset();
   }
 
   if (!numToDelete) {
     return NS_OK;
   }
 
-  RefPtr<nsGenericDOMDataNode> dataNode =
-    static_cast<nsGenericDOMDataNode*>(aPoint.Container());
+  RefPtr<CharacterData> dataNode =
+    static_cast<CharacterData*>(aPoint.Container());
   RefPtr<DeleteTextTransaction> deleteTextTransaction =
     DeleteTextTransaction::MaybeCreate(*mEditorBase, *dataNode,
                                        startOffset, numToDelete);
   // If the text node isn't editable, it should be never undone/redone.
   // So, the transaction shouldn't be recorded.
   if (NS_WARN_IF(!deleteTextTransaction)) {
     return NS_ERROR_FAILURE;
   }
--- a/editor/libeditor/DeleteTextTransaction.cpp
+++ b/editor/libeditor/DeleteTextTransaction.cpp
@@ -18,30 +18,30 @@
 
 namespace mozilla {
 
 using namespace dom;
 
 // static
 already_AddRefed<DeleteTextTransaction>
 DeleteTextTransaction::MaybeCreate(EditorBase& aEditorBase,
-                                   nsGenericDOMDataNode& aCharData,
+                                   CharacterData& aCharData,
                                    uint32_t aOffset,
                                    uint32_t aLengthToDelete)
 {
   RefPtr<DeleteTextTransaction> transaction =
     new DeleteTextTransaction(aEditorBase, aCharData, aOffset, aLengthToDelete);
   return transaction.forget();
 }
 
 // static
 already_AddRefed<DeleteTextTransaction>
 DeleteTextTransaction::MaybeCreateForPreviousCharacter(
                          EditorBase& aEditorBase,
-                         nsGenericDOMDataNode& aCharData,
+                         CharacterData& aCharData,
                          uint32_t aOffset)
 {
   if (NS_WARN_IF(!aOffset)) {
     return nullptr;
   }
 
   nsAutoString data;
   aCharData.GetData(data);
@@ -60,17 +60,17 @@ DeleteTextTransaction::MaybeCreateForPre
   return DeleteTextTransaction::MaybeCreate(aEditorBase, aCharData,
                                             offset, length);
 }
 
 // static
 already_AddRefed<DeleteTextTransaction>
 DeleteTextTransaction::MaybeCreateForNextCharacter(
                          EditorBase& aEditorBase,
-                         nsGenericDOMDataNode& aCharData,
+                         CharacterData& aCharData,
                          uint32_t aOffset)
 {
   nsAutoString data;
   aCharData.GetData(data);
   if (NS_WARN_IF(aOffset >= data.Length()) ||
       NS_WARN_IF(data.IsEmpty())) {
     return nullptr;
   }
@@ -82,17 +82,17 @@ DeleteTextTransaction::MaybeCreateForNex
     ++length;
   }
   return DeleteTextTransaction::MaybeCreate(aEditorBase, aCharData,
                                             aOffset, length);
 }
 
 DeleteTextTransaction::DeleteTextTransaction(
                          EditorBase& aEditorBase,
-                         nsGenericDOMDataNode& aCharData,
+                         CharacterData& aCharData,
                          uint32_t aOffset,
                          uint32_t aLengthToDelete)
   : mEditorBase(&aEditorBase)
   , mCharData(&aCharData)
   , mOffset(aOffset)
   , mLengthToDelete(aLengthToDelete)
 {
   NS_ASSERTION(mCharData->Length() >= aOffset + aLengthToDelete,
@@ -118,22 +118,25 @@ DeleteTextTransaction::CanDoIt() const
 NS_IMETHODIMP
 DeleteTextTransaction::DoTransaction()
 {
   if (NS_WARN_IF(!mEditorBase) || NS_WARN_IF(!mCharData)) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
   // Get the text that we're about to delete
-  nsresult rv = mCharData->SubstringData(mOffset, mLengthToDelete,
-                                         mDeletedText);
-  MOZ_ASSERT(NS_SUCCEEDED(rv));
-  rv = mCharData->DeleteData(mOffset, mLengthToDelete);
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return rv;
+  ErrorResult err;
+  mCharData->SubstringData(mOffset, mLengthToDelete, mDeletedText, err);
+  if (NS_WARN_IF(err.Failed())) {
+    return err.StealNSResult();
+  }
+
+  mCharData->DeleteData(mOffset, mLengthToDelete, err);
+  if (NS_WARN_IF(err.Failed())) {
+    return err.StealNSResult();
   }
 
   mEditorBase->RangeUpdaterRef().
                  SelAdjDeleteText(mCharData, mOffset, mLengthToDelete);
 
   // Only set selection to deletion point if editor gives permission
   if (mEditorBase->GetShouldTxnSetSelection()) {
     RefPtr<Selection> selection = mEditorBase->GetSelection();
@@ -153,12 +156,14 @@ DeleteTextTransaction::DoTransaction()
 //XXX: We may want to store the selection state and restore it properly.  Was
 //     it an insertion point or an extended selection?
 NS_IMETHODIMP
 DeleteTextTransaction::UndoTransaction()
 {
   if (NS_WARN_IF(!mCharData)) {
     return NS_ERROR_NOT_INITIALIZED;
   }
-  return mCharData->InsertData(mOffset, mDeletedText);
+  ErrorResult rv;
+  mCharData->InsertData(mOffset, mDeletedText, rv);
+  return rv.StealNSResult();
 }
 
 } // namespace mozilla
--- a/editor/libeditor/DeleteTextTransaction.h
+++ b/editor/libeditor/DeleteTextTransaction.h
@@ -2,71 +2,71 @@
 /* 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 DeleteTextTransaction_h
 #define DeleteTextTransaction_h
 
 #include "mozilla/EditTransactionBase.h"
+#include "mozilla/dom/CharacterData.h"
 #include "nsCOMPtr.h"
 #include "nsCycleCollectionParticipant.h"
-#include "nsGenericDOMDataNode.h"
 #include "nsID.h"
 #include "nsString.h"
 #include "nscore.h"
 
 namespace mozilla {
 
 class EditorBase;
 class RangeUpdater;
 
 /**
  * A transaction that removes text from a content node.
  */
 class DeleteTextTransaction final : public EditTransactionBase
 {
 protected:
   DeleteTextTransaction(EditorBase& aEditorBase,
-                        nsGenericDOMDataNode& aCharData,
+                        dom::CharacterData& aCharData,
                         uint32_t aOffset,
                         uint32_t aLengthToDelete);
 
 public:
 
   /**
    * Creates a delete text transaction to remove given range.  This returns
    * nullptr if it cannot modify the text node.
    *
    * @param aEditorBase         The provider of basic editing operations.
    * @param aCharData           The content node to remove text from.
    * @param aOffset             The location in aElement to begin the deletion.
    * @param aLenthToDelete      The length to delete.
    */
   static already_AddRefed<DeleteTextTransaction>
   MaybeCreate(EditorBase& aEditorBase,
-              nsGenericDOMDataNode& aCharData,
+              dom::CharacterData& aCharData,
               uint32_t aOffset,
               uint32_t aLengthToDelete);
 
   /**
    * Creates a delete text transaction to remove a previous or next character.
    * Those methods MAY return nullptr.
    *
    * @param aEditorBase         The provider of basic editing operations.
    * @param aCharData           The content node to remove text from.
    * @param aOffset             The location in aElement to begin the deletion.
    */
   static already_AddRefed<DeleteTextTransaction>
   MaybeCreateForPreviousCharacter(EditorBase& aEditorBase,
-                                  nsGenericDOMDataNode& aCharData,
+                                  dom::CharacterData& aCharData,
                                   uint32_t aOffset);
   static already_AddRefed<DeleteTextTransaction>
   MaybeCreateForNextCharacter(EditorBase& aEditorBase,
-                              nsGenericDOMDataNode& aCharData,
+                              dom::CharacterData& aCharData,
                               uint32_t aOffset);
 
   /**
    * CanDoIt() returns true if there are enough members and can modify the
    * text.  Otherwise, false.
    */
   bool CanDoIt() const;
 
@@ -80,17 +80,17 @@ public:
 
   uint32_t LengthToDelete() { return mLengthToDelete; }
 
 protected:
   // The provider of basic editing operations.
   RefPtr<EditorBase> mEditorBase;
 
   // The CharacterData node to operate upon.
-  RefPtr<nsGenericDOMDataNode> mCharData;
+  RefPtr<dom::CharacterData> mCharData;
 
   // The offset into mCharData where the deletion is to take place.
   uint32_t mOffset;
 
   // The length to delete.
   uint32_t mLengthToDelete;
 
   // The text that was deleted.
--- a/editor/libeditor/EditorBase.cpp
+++ b/editor/libeditor/EditorBase.cpp
@@ -42,16 +42,17 @@
 #include "mozilla/Preferences.h"        // for Preferences
 #include "mozilla/RangeBoundary.h"      // for RawRangeBoundary, RangeBoundary
 #include "mozilla/dom/Selection.h"      // for Selection, etc.
 #include "mozilla/Services.h"           // for GetObserverService
 #include "mozilla/TextComposition.h"    // for TextComposition
 #include "mozilla/TextInputListener.h"  // for TextInputListener
 #include "mozilla/TextServicesDocument.h" // for TextServicesDocument
 #include "mozilla/TextEvents.h"
+#include "mozilla/dom/CharacterData.h"  // for CharacterData
 #include "mozilla/dom/Element.h"        // for Element, nsINode::AsElement
 #include "mozilla/dom/HTMLBodyElement.h"
 #include "mozilla/dom/Text.h"
 #include "mozilla/dom/Event.h"
 #include "nsAString.h"                  // for nsAString::Length, etc.
 #include "nsCCUncollectableMarker.h"    // for nsCCUncollectableMarker
 #include "nsCaret.h"                    // for nsCaret
 #include "nsCaseTreatment.h"
@@ -64,17 +65,16 @@
 #include "nsError.h"                    // for NS_OK, etc.
 #include "nsFocusManager.h"             // for nsFocusManager
 #include "nsFrameSelection.h"           // for nsFrameSelection
 #include "nsGenericHTMLElement.h"       // for nsGenericHTMLElement
 #include "nsGkAtoms.h"                  // for nsGkAtoms, nsGkAtoms::dir
 #include "nsIAbsorbingTransaction.h"    // for nsIAbsorbingTransaction
 #include "nsAtom.h"                    // for nsAtom
 #include "nsIContent.h"                 // for nsIContent
-#include "nsIDOMCharacterData.h"        // for nsIDOMCharacterData
 #include "nsIDOMDocument.h"             // for nsIDOMDocument
 #include "nsIDOMElement.h"              // for nsIDOMElement
 #include "nsIDOMEvent.h"                // for nsIDOMEvent
 #include "nsIDOMEventListener.h"        // for nsIDOMEventListener
 #include "nsIDOMEventTarget.h"          // for nsIDOMEventTarget
 #include "nsIDOMMouseEvent.h"           // for nsIDOMMouseEvent
 #include "nsIDOMNode.h"                 // for nsIDOMNode, etc.
 #include "nsIDOMNodeList.h"             // for nsIDOMNodeList
@@ -2910,19 +2910,18 @@ EditorBase::InsertTextIntoTextNodeImpl(c
     htmlEditRules->DidInsertText(insertedTextNode, insertedOffset,
                                  aStringToInsert);
   }
 
   // let listeners know what happened
   if (!mActionListeners.IsEmpty()) {
     AutoActionListenerArray listeners(mActionListeners);
     for (auto& listener : listeners) {
-      listener->DidInsertText(
-        static_cast<nsIDOMCharacterData*>(insertedTextNode->AsDOMNode()),
-        insertedOffset, aStringToInsert, rv);
+      listener->DidInsertText(insertedTextNode, insertedOffset,
+                              aStringToInsert, rv);
     }
   }
 
   // Added some cruft here for bug 43366.  Layout was crashing because we left
   // an empty text node lying around in the document.  So I delete empty text
   // nodes caused by IME.  I have to mark the IME transaction as "fixed", which
   // means that furure IME txns won't merge with it.  This is because we don't
   // want future IME txns trying to put their text into a node that is no
@@ -3038,25 +3037,26 @@ EditorBase::SetTextImpl(Selection& aSele
 
   AutoRules beginRulesSniffing(this, EditAction::setText,
                                nsIEditor::eNext);
 
   // Let listeners know what's up
   if (!mActionListeners.IsEmpty() && length) {
     AutoActionListenerArray listeners(mActionListeners);
     for (auto& listener : listeners) {
-      listener->WillDeleteText(
-        static_cast<nsIDOMCharacterData*>(aCharData.AsDOMNode()), 0, length);
+      listener->WillDeleteText(&aCharData, 0, length);
     }
   }
 
   // We don't support undo here, so we don't really need all of the transaction
   // machinery, therefore we can run our transaction directly, breaking all of
   // the rules!
-  nsresult rv = aCharData.SetData(aString);
+  ErrorResult res;
+  aCharData.SetData(aString, res);
+  nsresult rv = res.StealNSResult();
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   {
     // Create a nested scope to not overwrite rv from the outer scope.
     RefPtr<Selection> selection = GetSelection();
     DebugOnly<nsresult> rv = selection->Collapse(&aCharData, aString.Length());
@@ -3077,69 +3077,61 @@ EditorBase::SetTextImpl(Selection& aSele
     }
   }
 
   // Let listeners know what happened
   if (!mActionListeners.IsEmpty()) {
     AutoActionListenerArray listeners(mActionListeners);
     for (auto& listener : listeners) {
       if (length) {
-        listener->DidDeleteText(
-          static_cast<nsIDOMCharacterData*>(aCharData.AsDOMNode()), 0,
-          length, rv);
+        listener->DidDeleteText(&aCharData, 0, length, rv);
       }
       if (!aString.IsEmpty()) {
-        listener->DidInsertText(
-          static_cast<nsIDOMCharacterData*>(aCharData.AsDOMNode()), 0,
-          aString, rv);
+        listener->DidInsertText(&aCharData, 0, aString, rv);
       }
     }
   }
 
   return rv;
 }
 
 nsresult
-EditorBase::DeleteText(nsGenericDOMDataNode& aCharData,
+EditorBase::DeleteText(CharacterData& aCharData,
                        uint32_t aOffset,
                        uint32_t aLength)
 {
   RefPtr<DeleteTextTransaction> transaction =
     DeleteTextTransaction::MaybeCreate(*this, aCharData, aOffset, aLength);
   if (NS_WARN_IF(!transaction)) {
     return NS_ERROR_FAILURE;
   }
 
   AutoRules beginRulesSniffing(this, EditAction::deleteText,
                                nsIEditor::ePrevious);
 
   // Let listeners know what's up
   if (!mActionListeners.IsEmpty()) {
     AutoActionListenerArray listeners(mActionListeners);
     for (auto& listener : listeners) {
-      listener->WillDeleteText(
-          static_cast<nsIDOMCharacterData*>(GetAsDOMNode(&aCharData)), aOffset,
-          aLength);
+      listener->WillDeleteText(&aCharData, aOffset, aLength);
     }
   }
 
   nsresult rv = DoTransaction(transaction);
 
   if (mRules && mRules->AsHTMLEditRules()) {
     RefPtr<HTMLEditRules> htmlEditRules = mRules->AsHTMLEditRules();
     htmlEditRules->DidDeleteText(&aCharData, aOffset, aLength);
   }
 
   // Let listeners know what happened
   if (!mActionListeners.IsEmpty()) {
     AutoActionListenerArray listeners(mActionListeners);
     for (auto& listener : listeners) {
-      listener->DidDeleteText(
-          static_cast<nsIDOMCharacterData*>(GetAsDOMNode(&aCharData)), aOffset,
-          aLength, rv);
+      listener->DidDeleteText(&aCharData, aOffset, aLength, rv);
     }
   }
 
   return rv;
 }
 
 struct SavedRange final
 {
@@ -3214,20 +3206,20 @@ EditorBase::SplitNodeImpl(const EditorDO
   if (!aStartOfRightNode.IsStartOfContainer()) {
     // If it's a text node, just shuffle around some text
     Text* rightAsText = aStartOfRightNode.GetContainerAsText();
     Text* leftAsText = aNewLeftNode.GetAsText();
     if (rightAsText && leftAsText) {
       // Fix right node
       nsAutoString leftText;
       rightAsText->SubstringData(0, aStartOfRightNode.Offset(),
-                                 leftText);
-      rightAsText->DeleteData(0, aStartOfRightNode.Offset());
+                                 leftText, IgnoreErrors());
+      rightAsText->DeleteData(0, aStartOfRightNode.Offset(), IgnoreErrors());
       // Fix left node
-      leftAsText->GetAsText()->SetData(leftText);
+      leftAsText->GetAsText()->SetData(leftText, IgnoreErrors());
     } else {
       MOZ_DIAGNOSTIC_ASSERT(!rightAsText && !leftAsText);
       // Otherwise it's an interior node, so shuffle around the children. Go
       // through list backwards so deletes don't interfere with the iteration.
       if (!firstChildOfRightNode) {
         MoveAllChildren(*aStartOfRightNode.GetContainer(),
                         EditorRawDOMPoint(&aNewLeftNode, 0), aError);
         NS_WARNING_ASSERTION(!aError.Failed(),
@@ -3384,17 +3376,17 @@ EditorBase::JoinNodesImpl(nsINode* aNode
   // OK, ready to do join now.
   // If it's a text node, just shuffle around some text.
   if (IsTextNode(aNodeToKeep) && IsTextNode(aNodeToJoin)) {
     nsAutoString rightText;
     nsAutoString leftText;
     aNodeToKeep->GetAsText()->GetData(rightText);
     aNodeToJoin->GetAsText()->GetData(leftText);
     leftText += rightText;
-    aNodeToKeep->GetAsText()->SetData(leftText);
+    aNodeToKeep->GetAsText()->SetData(leftText, IgnoreErrors());
   } else {
     // Otherwise it's an interior node, so shuffle around the children.
     nsCOMPtr<nsINodeList> childNodes = aNodeToJoin->ChildNodes();
     MOZ_ASSERT(childNodes);
 
     // Remember the first child in aNodeToKeep, we'll insert all the children of aNodeToJoin in front of it
     // GetFirstChild returns nullptr firstNode if aNodeToKeep has no children, that's OK.
     nsCOMPtr<nsIContent> firstNode = aNodeToKeep->GetFirstChild();
@@ -4354,17 +4346,18 @@ EditorBase::DeleteSelectionImpl(EDirecti
                                   getter_AddRefs(deleteNode),
                                   &deleteCharOffset,
                                   &deleteCharLength);
     if (NS_WARN_IF(!deleteSelectionTransaction)) {
       return NS_ERROR_FAILURE;
     }
   }
 
-  nsCOMPtr<nsIDOMCharacterData> deleteCharData(do_QueryInterface(deleteNode));
+  RefPtr<CharacterData> deleteCharData =
+    CharacterData::FromContentOrNull(deleteNode);
   AutoRules beginRulesSniffing(this, EditAction::deleteSelection, aAction);
 
   if (mRules && mRules->AsHTMLEditRules()) {
     if (!deleteNode) {
       RefPtr<HTMLEditRules> htmlEditRules = mRules->AsHTMLEditRules();
       htmlEditRules->WillDeleteSelection(selection);
     } else if (!deleteCharData) {
       RefPtr<HTMLEditRules> htmlEditRules = mRules->AsHTMLEditRules();
@@ -4676,18 +4669,18 @@ EditorBase::CreateTxnForDeleteRange(nsRa
     nsCOMPtr<nsIContent> priorNode = GetPreviousEditableNode(*node);
     if (NS_WARN_IF(!priorNode)) {
       return nullptr;
     }
 
     // there is a priorNode, so delete its last child (if chardata, delete the
     // last char). if it has no children, delete it
     if (priorNode->IsNodeOfType(nsINode::eDATA_NODE)) {
-      RefPtr<nsGenericDOMDataNode> priorNodeAsCharData =
-        static_cast<nsGenericDOMDataNode*>(priorNode.get());
+      RefPtr<CharacterData> priorNodeAsCharData =
+        static_cast<CharacterData*>(priorNode.get());
       uint32_t length = priorNode->Length();
       // Bail out for empty chardata XXX: Do we want to do something else?
       if (NS_WARN_IF(!length)) {
         return nullptr;
       }
       RefPtr<DeleteTextTransaction> deleteTextTransaction =
         DeleteTextTransaction::MaybeCreateForPreviousCharacter(
                                  *this, *priorNodeAsCharData, length);
@@ -4716,18 +4709,18 @@ EditorBase::CreateTxnForDeleteRange(nsRa
     nsCOMPtr<nsIContent> nextNode = GetNextEditableNode(*node);
     if (NS_WARN_IF(!nextNode)) {
       return nullptr;
     }
 
     // there is a nextNode, so delete its first child (if chardata, delete the
     // first char). if it has no children, delete it
     if (nextNode->IsNodeOfType(nsINode::eDATA_NODE)) {
-      RefPtr<nsGenericDOMDataNode> nextNodeAsCharData =
-        static_cast<nsGenericDOMDataNode*>(nextNode.get());
+      RefPtr<CharacterData> nextNodeAsCharData =
+        static_cast<CharacterData*>(nextNode.get());
       uint32_t length = nextNode->Length();
       // Bail out for empty chardata XXX: Do we want to do something else?
       if (NS_WARN_IF(!length)) {
         return nullptr;
       }
       RefPtr<DeleteTextTransaction> deleteTextTransaction =
         DeleteTextTransaction::MaybeCreateForNextCharacter(
                                  *this, *nextNodeAsCharData, 0);
@@ -4749,18 +4742,18 @@ EditorBase::CreateTxnForDeleteRange(nsRa
     nextNode.forget(aRemovingNode);
     return deleteNodeTransaction.forget();
   }
 
   if (node->IsNodeOfType(nsINode::eDATA_NODE)) {
     if (NS_WARN_IF(aAction != ePrevious && aAction != eNext)) {
       return nullptr;
     }
-    RefPtr<nsGenericDOMDataNode> nodeAsCharData =
-      static_cast<nsGenericDOMDataNode*>(node.get());
+    RefPtr<CharacterData> nodeAsCharData =
+      static_cast<CharacterData*>(node.get());
     // We have chardata, so delete a char at the proper offset
     RefPtr<DeleteTextTransaction> deleteTextTransaction =
       aAction == ePrevious ?
         DeleteTextTransaction::MaybeCreateForPreviousCharacter(
                                  *this, *nodeAsCharData, offset) :
         DeleteTextTransaction::MaybeCreateForNextCharacter(
                                  *this, *nodeAsCharData, offset);
     if (NS_WARN_IF(!deleteTextTransaction)) {
@@ -4796,18 +4789,18 @@ EditorBase::CreateTxnForDeleteRange(nsRa
   if (NS_WARN_IF(!selectedNode)) {
     return nullptr;
   }
 
   if (selectedNode->IsNodeOfType(nsINode::eDATA_NODE)) {
     if (NS_WARN_IF(aAction != ePrevious && aAction != eNext)) {
       return nullptr;
     }
-    RefPtr<nsGenericDOMDataNode> selectedNodeAsCharData =
-      static_cast<nsGenericDOMDataNode*>(selectedNode.get());
+    RefPtr<CharacterData> selectedNodeAsCharData =
+      static_cast<CharacterData*>(selectedNode.get());
     // we are deleting from a chardata node, so do a character deletion
     uint32_t position = 0;
     if (aAction == ePrevious) {
       position = selectedNode->Length();
     }
     RefPtr<DeleteTextTransaction> deleteTextTransaction =
       aAction == ePrevious ?
         DeleteTextTransaction::MaybeCreateForPreviousCharacter(
--- a/editor/libeditor/EditorBase.h
+++ b/editor/libeditor/EditorBase.h
@@ -557,17 +557,17 @@ protected:
    */
   already_AddRefed<EditTransactionBase>
     CreateTxnForDeleteRange(nsRange* aRangeToDelete,
                             EDirection aAction,
                             nsINode** aRemovingNode,
                             int32_t* aOffset,
                             int32_t* aLength);
 
-  nsresult DeleteText(nsGenericDOMDataNode& aElement,
+  nsresult DeleteText(dom::CharacterData& aElement,
                       uint32_t aOffset, uint32_t aLength);
 
   /**
    * This method first deletes the selection, if it's not collapsed.  Then if
    * the selection lies in a CharacterData node, it splits it.  If the
    * selection is at this point collapsed in a CharacterData node, it's
    * adjusted to be collapsed right before or after the node instead (which is
    * always possible, since the node was split).
--- a/editor/libeditor/EditorEventListener.cpp
+++ b/editor/libeditor/EditorEventListener.cpp
@@ -26,17 +26,16 @@
 #include "nsIClipboard.h"               // for nsIClipboard, etc.
 #include "nsIContent.h"                 // for nsIContent
 #include "nsIController.h"              // for nsIController
 #include "nsID.h"
 #include "mozilla/dom/DOMStringList.h"
 #include "mozilla/dom/DataTransfer.h"
 #include "mozilla/dom/DragEvent.h"
 #include "nsIDOMDocument.h"             // for nsIDOMDocument
-#include "nsIDOMElement.h"              // for nsIDOMElement
 #include "nsIDOMEvent.h"                // for nsIDOMEvent
 #include "nsIDOMEventTarget.h"          // for nsIDOMEventTarget
 #include "nsIDOMMouseEvent.h"           // for nsIDOMMouseEvent
 #include "nsIDOMNode.h"                 // for nsIDOMNode
 #include "nsIDocument.h"                // for nsIDocument
 #include "nsIFocusManager.h"            // for nsIFocusManager
 #include "nsIFormControl.h"             // for nsIFormControl, etc.
 #include "nsINode.h"                    // for nsINode, ::NODE_IS_EDITABLE, etc.
@@ -215,24 +214,22 @@ EditorEventListener::InstallToEditor()
 void
 EditorEventListener::Disconnect()
 {
   if (DetachedFromEditor()) {
     return;
   }
   UninstallFromEditor();
 
-  nsIFocusManager* fm = nsFocusManager::GetFocusManager();
+  nsFocusManager* fm = nsFocusManager::GetFocusManager();
   if (fm) {
-    nsCOMPtr<nsIDOMElement> domFocus;
-    fm->GetFocusedElement(getter_AddRefs(domFocus));
-    nsCOMPtr<nsINode> focusedElement = do_QueryInterface(domFocus);
+    nsIContent* focusedContent = fm->GetFocusedContent();
     mozilla::dom::Element* root = mEditorBase->GetRoot();
-    if (focusedElement && root &&
-        nsContentUtils::ContentIsDescendantOf(focusedElement, root)) {
+    if (focusedContent && root &&
+        nsContentUtils::ContentIsDescendantOf(focusedContent, root)) {
       // Reset the Selection ancestor limiter and SelectionController state
       // that EditorBase::InitializeSelection set up.
       mEditorBase->FinalizeSelection();
     }
   }
 
   mEditorBase = nullptr;
 }
@@ -1097,35 +1094,32 @@ EditorEventListener::Focus(InternalFocus
     // contenteditable editor.  So, the editableRoot value is invalid for
     // the plain text editor, and it will be set to the wrong limiter of
     // the selection.  However, fortunately, actual bugs are not found yet.
     nsCOMPtr<nsIContent> editableRoot = editorBase->FindSelectionRoot(content);
 
     // make sure that the element is really focused in case an earlier
     // listener in the chain changed the focus.
     if (editableRoot) {
-      nsIFocusManager* fm = nsFocusManager::GetFocusManager();
+      nsFocusManager* fm = nsFocusManager::GetFocusManager();
       NS_ENSURE_TRUE(fm, NS_OK);
 
-      nsCOMPtr<nsIDOMElement> element;
-      fm->GetFocusedElement(getter_AddRefs(element));
-      if (!element) {
+      nsIContent* focusedContent = fm->GetFocusedContent();
+      if (!focusedContent) {
         return NS_OK;
       }
 
       nsCOMPtr<nsIDOMEventTarget> originalTarget =
         aFocusEvent->GetOriginalDOMEventTarget();
 
       nsCOMPtr<nsIContent> originalTargetAsContent =
         do_QueryInterface(originalTarget);
-      nsCOMPtr<nsIContent> focusedElementAsContent =
-        do_QueryInterface(element);
 
       if (!SameCOMIdentity(
-            focusedElementAsContent->FindFirstNonChromeOnlyAccessContent(),
+            focusedContent->FindFirstNonChromeOnlyAccessContent(),
             originalTargetAsContent->FindFirstNonChromeOnlyAccessContent())) {
         return NS_OK;
       }
     }
   }
 
   editorBase->OnFocus(target);
   if (DetachedFromEditorOrDefaultPrevented(aFocusEvent)) {
@@ -1145,22 +1139,21 @@ nsresult
 EditorEventListener::Blur(InternalFocusEvent* aBlurEvent)
 {
   if (NS_WARN_IF(!aBlurEvent) || DetachedFromEditor()) {
     return NS_OK;
   }
 
   // check if something else is focused. If another element is focused, then
   // we should not change the selection.
-  nsIFocusManager* fm = nsFocusManager::GetFocusManager();
+  nsFocusManager* fm = nsFocusManager::GetFocusManager();
   NS_ENSURE_TRUE(fm, NS_OK);
 
-  nsCOMPtr<nsIDOMElement> element;
-  fm->GetFocusedElement(getter_AddRefs(element));
-  if (!element) {
+  nsIContent* content = fm->GetFocusedContent();
+  if (!content || !content->IsElement()) {
     RefPtr<EditorBase> editorBase(mEditorBase);
     editorBase->FinalizeSelection();
   }
   return NS_OK;
 }
 
 void
 EditorEventListener::SpellCheckIfNeeded()
--- a/editor/libeditor/HTMLAbsPositionEditor.cpp
+++ b/editor/libeditor/HTMLAbsPositionEditor.cpp
@@ -308,17 +308,17 @@ HTMLEditor::ShowGrabber(Element& aElemen
   mGrabber = CreateGrabber(*parentContent);
   NS_ENSURE_TRUE(mGrabber, NS_ERROR_FAILURE);
 
   // and set its position
   return RefreshGrabber();
 }
 
 nsresult
-HTMLEditor::StartMoving(nsIDOMElement* aHandle)
+HTMLEditor::StartMoving()
 {
   nsCOMPtr<nsIContent> parentContent = mGrabber->GetParent();
   if (NS_WARN_IF(!parentContent) || NS_WARN_IF(!mAbsolutelyPositionedObject)) {
     return NS_ERROR_FAILURE;
   }
 
   // now, let's create the resizing shadow
   mPositioningShadow =
--- a/editor/libeditor/HTMLAnonymousNodeEditor.cpp
+++ b/editor/libeditor/HTMLAnonymousNodeEditor.cpp
@@ -13,17 +13,16 @@
 #include "nsComputedDOMStyle.h"
 #include "nsDebug.h"
 #include "nsError.h"
 #include "nsGenericHTMLElement.h"
 #include "nsGkAtoms.h"
 #include "nsAtom.h"
 #include "nsIContent.h"
 #include "nsID.h"
-#include "nsIDOMElement.h"
 #include "nsIDOMEventTarget.h"
 #include "nsIDOMNode.h"
 #include "nsIDOMWindow.h"
 #include "nsIDocument.h"
 #include "nsIDocumentObserver.h"
 #include "nsIHTMLAbsPosEditor.h"
 #include "nsIHTMLInlineTableEditor.h"
 #include "nsIHTMLObjectResizer.h"
--- a/editor/libeditor/HTMLEditRules.cpp
+++ b/editor/libeditor/HTMLEditRules.cpp
@@ -34,17 +34,16 @@
 #include "nsContentUtils.h"
 #include "nsDebug.h"
 #include "nsError.h"
 #include "nsGkAtoms.h"
 #include "nsAtom.h"
 #include "nsIContent.h"
 #include "nsIContentIterator.h"
 #include "nsID.h"
-#include "nsIDOMCharacterData.h"
 #include "nsIDOMDocument.h"
 #include "nsIDOMElement.h"
 #include "nsIDOMNode.h"
 #include "nsIFrame.h"
 #include "nsIHTMLAbsPosEditor.h"
 #include "nsIHTMLDocument.h"
 #include "nsINode.h"
 #include "nsLiteralString.h"
@@ -2788,28 +2787,28 @@ HTMLEditRules::WillDeleteSelection(Selec
 
         // Check endpoints for possible text deletion.  We can assume that if
         // text node is found, we can delete to end or to begining as
         // appropriate, since the case where both sel endpoints in same text
         // node was already handled (we wouldn't be here)
         if (startNode->GetAsText() &&
             startNode->Length() > static_cast<uint32_t>(startOffset)) {
           // Delete to last character
-          OwningNonNull<nsGenericDOMDataNode> dataNode =
-            *static_cast<nsGenericDOMDataNode*>(startNode.get());
+          OwningNonNull<CharacterData> dataNode =
+            *static_cast<CharacterData*>(startNode.get());
           NS_ENSURE_STATE(mHTMLEditor);
           rv = mHTMLEditor->DeleteText(dataNode, startOffset,
                                        startNode->Length() - startOffset);
           NS_ENSURE_SUCCESS(rv, rv);
         }
         if (endNode->GetAsText() && endOffset) {
           // Delete to first character
           NS_ENSURE_STATE(mHTMLEditor);
-          OwningNonNull<nsGenericDOMDataNode> dataNode =
-            *static_cast<nsGenericDOMDataNode*>(endNode.get());
+          OwningNonNull<CharacterData> dataNode =
+            *static_cast<CharacterData*>(endNode.get());
           rv = mHTMLEditor->DeleteText(dataNode, 0, endOffset);
           NS_ENSURE_SUCCESS(rv, rv);
         }
 
         if (join) {
           EditActionResult ret = TryToJoinBlocks(*leftParent, *rightParent);
           MOZ_ASSERT(*aHandled);
           *aCancel |= ret.Canceled();
--- a/editor/libeditor/HTMLEditRules.h
+++ b/editor/libeditor/HTMLEditRules.h
@@ -13,19 +13,17 @@
 #include "nsCOMPtr.h"
 #include "nsIEditor.h"
 #include "nsIHTMLEditor.h"
 #include "nsISupportsImpl.h"
 #include "nsTArray.h"
 #include "nscore.h"
 
 class nsAtom;
-class nsIDOMCharacterData;
 class nsIDOMDocument;
-class nsIDOMElement;
 class nsIDOMNode;
 class nsIEditor;
 class nsINode;
 class nsRange;
 
 namespace mozilla {
 
 class EditActionResult;
--- a/editor/libeditor/HTMLEditor.cpp
+++ b/editor/libeditor/HTMLEditor.cpp
@@ -3189,17 +3189,17 @@ HTMLEditor::DeleteNode(nsIDOMNode* aNode
                  !IsMozEditorBogusNode(content))) {
     return NS_ERROR_FAILURE;
   }
 
   return EditorBase::DeleteNode(aNode);
 }
 
 nsresult
-HTMLEditor::DeleteText(nsGenericDOMDataNode& aCharData,
+HTMLEditor::DeleteText(CharacterData& aCharData,
                        uint32_t aOffset,
                        uint32_t aLength)
 {
   // Do nothing if the node is read-only
   if (!IsModifiableNode(&aCharData)) {
     return NS_ERROR_FAILURE;
   }
 
--- a/editor/libeditor/HTMLEditor.h
+++ b/editor/libeditor/HTMLEditor.h
@@ -16,17 +16,16 @@
 #include "mozilla/UniquePtr.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/File.h"
 
 #include "nsAttrName.h"
 #include "nsCOMPtr.h"
 #include "nsICSSLoaderObserver.h"
 #include "nsIDocumentObserver.h"
-#include "nsIDOMElement.h"
 #include "nsIDOMEventListener.h"
 #include "nsIEditorMailSupport.h"
 #include "nsIEditorStyleSheets.h"
 #include "nsIEditorUtils.h"
 #include "nsIHTMLAbsPosEditor.h"
 #include "nsIHTMLEditor.h"
 #include "nsIHTMLInlineTableEditor.h"
 #include "nsIHTMLObjectResizer.h"
@@ -34,16 +33,17 @@
 #include "nsPoint.h"
 #include "nsStubMutationObserver.h"
 #include "nsTArray.h"
 
 class nsDocumentFragment;
 class nsITransferable;
 class nsIClipboard;
 class nsIDOMDocument;
+class nsIDOMElement;
 class nsIDOMMouseEvent;
 class nsILinkHandler;
 class nsTableWrapperFrame;
 class nsIDOMRange;
 class nsRange;
 class nsISelection;
 
 namespace mozilla {
@@ -381,17 +381,17 @@ public:
 
   virtual bool AreNodesSameType(nsIContent* aNode1,
                                 nsIContent* aNode2) override;
 
   NS_IMETHOD DeleteSelectionImpl(EDirection aAction,
                                  EStripWrappers aStripWrappers) override;
   nsresult DeleteNode(nsINode* aNode);
   NS_IMETHOD DeleteNode(nsIDOMNode* aNode) override;
-  nsresult DeleteText(nsGenericDOMDataNode& aTextNode, uint32_t aOffset,
+  nsresult DeleteText(dom::CharacterData& aTextNode, uint32_t aOffset,
                       uint32_t aLength);
   virtual nsresult
   InsertTextImpl(nsIDocument& aDocument,
                  const nsAString& aStringToInsert,
                  const EditorRawDOMPoint& aPointToInsert,
                  EditorRawDOMPoint* aPointAfterInsertedString =
                    nullptr) override;
   virtual bool IsModifiableNode(nsINode* aNode) override;
@@ -1327,17 +1327,17 @@ protected:
   nsresult ShowGrabber(Element& aElement);
 
   /**
    * hide the grabber if it shown.
    */
   void HideGrabber();
 
   ManualNACPtr CreateGrabber(nsIContent& aParentContent);
-  nsresult StartMoving(nsIDOMElement* aHandle);
+  nsresult StartMoving();
   nsresult SetFinalPosition(int32_t aX, int32_t aY);
   void AddPositioningOffset(int32_t& aX, int32_t& aY);
   void SnapToGrid(int32_t& newX, int32_t& newY);
   nsresult GrabberClicked();
   nsresult EndMoving();
   nsresult GetTemporaryStyleForFocusedPositionedElement(Element& aElement,
                                                         nsAString& aReturn);
 
--- a/editor/libeditor/HTMLEditorDataTransfer.cpp
+++ b/editor/libeditor/HTMLEditorDataTransfer.cpp
@@ -33,17 +33,16 @@
 #include "nsIScriptError.h"
 #include "nsContentUtils.h"
 #include "nsDebug.h"
 #include "nsDependentSubstring.h"
 #include "nsError.h"
 #include "nsGkAtoms.h"
 #include "nsIClipboard.h"
 #include "nsIContent.h"
-#include "nsIDOMComment.h"
 #include "nsIDOMDocument.h"
 #include "nsIDOMDocumentFragment.h"
 #include "nsIDOMElement.h"
 #include "nsIDOMNode.h"
 #include "nsIDocument.h"
 #include "nsIFile.h"
 #include "nsIInputStream.h"
 #include "nsIMIMEService.h"
@@ -2004,18 +2003,17 @@ nsresult FindTargetNode(nsINode *aStart,
     }
     return NS_OK;
   }
 
   do {
     // Is this child the magical cookie?
     if (child->IsNodeOfType(nsINode::eCOMMENT)) {
       nsAutoString data;
-      nsresult rv = static_cast<Comment*>(child.get())->GetData(data);
-      NS_ENSURE_SUCCESS(rv, rv);
+      static_cast<Comment*>(child.get())->GetData(data);
 
       if (data.EqualsLiteral(kInsertCookie)) {
         // Yes it is! Return an error so we bubble out and short-circuit the
         // search.
         aResult = aStart;
 
         child->Remove();
 
--- a/editor/libeditor/HTMLEditorObjectResizer.cpp
+++ b/editor/libeditor/HTMLEditorObjectResizer.cpp
@@ -818,17 +818,17 @@ HTMLEditor::OnMouseMove(nsIDOMMouseEvent
     int32_t xThreshold =
       LookAndFeel::GetInt(LookAndFeel::eIntID_DragThresholdX, 1);
     int32_t yThreshold =
       LookAndFeel::GetInt(LookAndFeel::eIntID_DragThresholdY, 1);
 
     if (DeprecatedAbs(clientX - mOriginalX) * 2 >= xThreshold ||
         DeprecatedAbs(clientY - mOriginalY) * 2 >= yThreshold) {
       mGrabberClicked = false;
-      StartMoving(nullptr);
+      StartMoving();
     }
   }
   if (mIsMoving) {
     int32_t clientX, clientY;
     aMouseEvent->GetClientX(&clientX);
     aMouseEvent->GetClientY(&clientY);
 
     int32_t newX = mPositionedObjectX + clientX - mOriginalX;
--- a/editor/libeditor/HTMLInlineTableEditor.cpp
+++ b/editor/libeditor/HTMLInlineTableEditor.cpp
@@ -7,17 +7,16 @@
 #include "HTMLEditUtils.h"
 #include "mozilla/dom/Element.h"
 #include "nsAString.h"
 #include "nsCOMPtr.h"
 #include "nsDebug.h"
 #include "nsError.h"
 #include "nsGenericHTMLElement.h"
 #include "nsIContent.h"
-#include "nsIDOMElement.h"
 #include "nsIDOMEventTarget.h"
 #include "nsIDOMNode.h"
 #include "nsIHTMLObjectResizer.h"
 #include "nsIPresShell.h"
 #include "nsLiteralString.h"
 #include "nsReadableUtils.h"
 #include "nsString.h"
 #include "nscore.h"
--- a/editor/libeditor/HTMLStyleEditor.cpp
+++ b/editor/libeditor/HTMLStyleEditor.cpp
@@ -22,17 +22,16 @@
 #include "nsCaseTreatment.h"
 #include "nsComponentManagerUtils.h"
 #include "nsDebug.h"
 #include "nsError.h"
 #include "nsGkAtoms.h"
 #include "nsAtom.h"
 #include "nsIContent.h"
 #include "nsIContentIterator.h"
-#include "nsIDOMElement.h"
 #include "nsNameSpaceManager.h"
 #include "nsINode.h"
 #include "nsISupportsImpl.h"
 #include "nsLiteralString.h"
 #include "nsRange.h"
 #include "nsReadableUtils.h"
 #include "nsString.h"
 #include "nsStringFwd.h"
--- a/editor/libeditor/HTMLURIRefObject.cpp
+++ b/editor/libeditor/HTMLURIRefObject.cpp
@@ -44,17 +44,16 @@
 #include "mozilla/mozalloc.h"
 #include "mozilla/dom/Attr.h"
 #include "mozilla/dom/Element.h"
 #include "nsAString.h"
 #include "nsDebug.h"
 #include "nsDOMAttributeMap.h"
 #include "nsError.h"
 #include "nsID.h"
-#include "nsIDOMElement.h"
 #include "nsIDOMNode.h"
 #include "nsISupportsUtils.h"
 #include "nsString.h"
 #include "nsGkAtoms.h"
 
 namespace mozilla {
 
 // String classes change too often and I can't keep up.
--- a/editor/libeditor/InsertTextTransaction.cpp
+++ b/editor/libeditor/InsertTextTransaction.cpp
@@ -60,19 +60,20 @@ NS_INTERFACE_MAP_END_INHERITING(EditTran
 
 NS_IMETHODIMP
 InsertTextTransaction::DoTransaction()
 {
   if (NS_WARN_IF(!mEditorBase) || NS_WARN_IF(!mTextNode)) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
-  nsresult rv = mTextNode->InsertData(mOffset, mStringToInsert);
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return rv;
+  ErrorResult rv;
+  mTextNode->InsertData(mOffset, mStringToInsert, rv);
+  if (NS_WARN_IF(rv.Failed())) {
+    return rv.StealNSResult();
   }
 
   // Only set selection to insertion point if editor gives permission
   if (mEditorBase->GetShouldTxnSetSelection()) {
     RefPtr<Selection> selection = mEditorBase->GetSelection();
     if (NS_WARN_IF(!selection)) {
       return NS_ERROR_FAILURE;
     }
@@ -87,17 +88,19 @@ InsertTextTransaction::DoTransaction()
                  SelAdjInsertText(*mTextNode, mOffset, mStringToInsert);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 InsertTextTransaction::UndoTransaction()
 {
-  return mTextNode->DeleteData(mOffset, mStringToInsert.Length());
+  ErrorResult rv;
+  mTextNode->DeleteData(mOffset, mStringToInsert.Length(), rv);
+  return rv.StealNSResult();
 }
 
 NS_IMETHODIMP
 InsertTextTransaction::Merge(nsITransaction* aTransaction,
                              bool* aDidMerge)
 {
   if (!aTransaction || !aDidMerge) {
     return NS_OK;
--- a/editor/libeditor/JoinNodeTransaction.cpp
+++ b/editor/libeditor/JoinNodeTransaction.cpp
@@ -1,21 +1,21 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "JoinNodeTransaction.h"
 
 #include "mozilla/EditorBase.h"         // for EditorBase
+#include "mozilla/dom/Text.h"
 #include "nsAString.h"
 #include "nsDebug.h"                    // for NS_ASSERTION, etc.
 #include "nsError.h"                    // for NS_ERROR_NULL_POINTER, etc.
 #include "nsIContent.h"                 // for nsIContent
-#include "nsIDOMCharacterData.h"        // for nsIDOMCharacterData
 #include "nsIEditor.h"                  // for EditorBase::IsModifiableNode
 #include "nsISupportsImpl.h"            // for QueryInterface, etc.
 
 namespace mozilla {
 
 using namespace dom;
 
 // static
@@ -101,17 +101,20 @@ JoinNodeTransaction::UndoTransaction()
       NS_WARN_IF(!mLeftNode) ||
       NS_WARN_IF(!mRightNode)) {
     return NS_ERROR_NOT_INITIALIZED;
   }
 
   // First, massage the existing node so it is in its post-split state
   ErrorResult rv;
   if (mRightNode->GetAsText()) {
-    rv = mRightNode->GetAsText()->DeleteData(0, mOffset);
+    mRightNode->GetAsText()->DeleteData(0, mOffset, rv);
+    if (rv.Failed()) {
+      return rv.StealNSResult();
+    }
   } else {
     nsCOMPtr<nsIContent> child = mRightNode->GetFirstChild();
     for (uint32_t i = 0; i < mOffset; i++) {
       if (rv.Failed()) {
         return rv.StealNSResult();
       }
       if (!child) {
         return NS_ERROR_NULL_POINTER;
--- a/editor/libeditor/SelectionState.cpp
+++ b/editor/libeditor/SelectionState.cpp
@@ -8,17 +8,16 @@
 #include "mozilla/Assertions.h"         // for MOZ_ASSERT, etc.
 #include "mozilla/EditorUtils.h"        // for EditorUtils
 #include "mozilla/dom/Selection.h"      // for Selection
 #include "nsAString.h"                  // for nsAString::Length
 #include "nsCycleCollectionParticipant.h"
 #include "nsDebug.h"                    // for NS_ENSURE_TRUE, etc.
 #include "nsError.h"                    // for NS_OK, etc.
 #include "nsIContent.h"                 // for nsIContent
-#include "nsIDOMCharacterData.h"        // for nsIDOMCharacterData
 #include "nsIDOMNode.h"                 // for nsIDOMNode
 #include "nsISupportsImpl.h"            // for nsRange::Release
 #include "nsRange.h"                    // for nsRange
 
 namespace mozilla {
 
 using namespace dom;
 
@@ -474,25 +473,16 @@ RangeUpdater::SelAdjDeleteText(nsIConten
         item->mEndOffset = 0;
       }
     }
   }
   return NS_OK;
 }
 
 nsresult
-RangeUpdater::SelAdjDeleteText(nsIDOMCharacterData* aTextNode,
-                               int32_t aOffset,
-                               int32_t aLength)
-{
-  nsCOMPtr<nsIContent> textNode = do_QueryInterface(aTextNode);
-  return SelAdjDeleteText(textNode, aOffset, aLength);
-}
-
-nsresult
 RangeUpdater::WillReplaceContainer()
 {
   if (mLock) {
     return NS_ERROR_UNEXPECTED;
   }
   mLock = true;
   return NS_OK;
 }
--- a/editor/libeditor/SelectionState.h
+++ b/editor/libeditor/SelectionState.h
@@ -9,17 +9,16 @@
 #include "mozilla/EditorDOMPoint.h"
 #include "nsCOMPtr.h"
 #include "nsIDOMNode.h"
 #include "nsINode.h"
 #include "nsTArray.h"
 #include "nscore.h"
 
 class nsCycleCollectionTraversalCallback;
-class nsIDOMCharacterData;
 class nsRange;
 namespace mozilla {
 class RangeUpdater;
 namespace dom {
 class Selection;
 class Text;
 } // namespace dom
 
@@ -117,18 +116,16 @@ public:
                            nsINode& aRightNode,
                            nsINode& aParent,
                            int32_t aOffset,
                            int32_t aOldLeftNodeLength);
   void SelAdjInsertText(dom::Text& aTextNode, int32_t aOffset,
                         const nsAString &aString);
   nsresult SelAdjDeleteText(nsIContent* aTextNode, int32_t aOffset,
                             int32_t aLength);
-  nsresult SelAdjDeleteText(nsIDOMCharacterData* aTextNode,
-                            int32_t aOffset, int32_t aLength);
   // the following gravity routines need will/did sandwiches, because the other
   // gravity routines will be called inside of these sandwiches, but should be
   // ignored.
   nsresult WillReplaceContainer();
   nsresult DidReplaceContainer(dom::Element* aOriginalNode,
                                dom::Element* aNewNode);
   nsresult WillRemoveContainer();
   nsresult DidRemoveContainer(nsINode* aNode, nsINode* aParent,
--- a/editor/libeditor/SplitNodeTransaction.cpp
+++ b/editor/libeditor/SplitNodeTransaction.cpp
@@ -140,20 +140,20 @@ SplitNodeTransaction::RedoTransaction()
       NS_WARN_IF(!mStartOfRightNode.IsSet())) {
     return NS_ERROR_NOT_INITIALIZED;
   }
 
   // First, massage the existing node so it is in its post-split state
   if (mStartOfRightNode.IsInTextNode()) {
     Text* rightNodeAsText = mStartOfRightNode.GetContainerAsText();
     MOZ_DIAGNOSTIC_ASSERT(rightNodeAsText);
-    nsresult rv =
-      rightNodeAsText->DeleteData(0, mStartOfRightNode.Offset());
-    if (NS_WARN_IF(NS_FAILED(rv))) {
-      return rv;
+    ErrorResult rv;
+    rightNodeAsText->DeleteData(0, mStartOfRightNode.Offset(), rv);
+    if (NS_WARN_IF(rv.Failed())) {
+      return rv.StealNSResult();
     }
   } else {
     nsCOMPtr<nsIContent> child =
       mStartOfRightNode.GetContainer()->GetFirstChild();
     nsCOMPtr<nsIContent> nextSibling;
     for (uint32_t i = 0; i < mStartOfRightNode.Offset(); i++) {
       // XXX This must be bad behavior.  Perhaps, we should work with
       //     mStartOfRightNode::GetChild().  Even if some children
--- a/editor/libeditor/TextEditRules.cpp
+++ b/editor/libeditor/TextEditRules.cpp
@@ -1295,21 +1295,17 @@ TextEditRules::WillOutputText(Selection*
   // just empty.
   if (!text) {
     aOutString->Truncate();
     *aHandled = true;
     return NS_OK;
   }
 
   // Otherwise, the text is the value.
-  nsresult rv = text->GetData(*aOutString);
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    // Fall back to the expensive path if it fails.
-    return NS_OK;
-  }
+  text->GetData(*aOutString);
 
   *aHandled = true;
   return NS_OK;
 }
 
 nsresult
 TextEditRules::DidOutputText(Selection* aSelection,
                              nsresult aResult)
@@ -1620,17 +1616,18 @@ TextEditRules::HideLastPWInput()
   NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER);
   uint32_t start, end;
   nsContentUtils::GetSelectionInTextControl(selection, mTextEditor->GetRoot(),
                                             start, end);
 
   nsCOMPtr<nsINode> selNode = GetTextNode(selection);
   NS_ENSURE_TRUE(selNode, NS_OK);
 
-  selNode->GetAsText()->ReplaceData(mLastStart, mLastLength, hiddenText);
+  selNode->GetAsText()->ReplaceData(mLastStart, mLastLength, hiddenText,
+                                    IgnoreErrors());
   // XXXbz Selection::Collapse/Extend take int32_t, but there are tons of
   // callsites... Converting all that is a battle for another day.
   selection->Collapse(selNode, start);
   if (start != end) {
     selection->Extend(selNode, end);
   }
   return NS_OK;
 }
--- a/editor/libeditor/TextEditUtils.cpp
+++ b/editor/libeditor/TextEditUtils.cpp
@@ -9,17 +9,16 @@
 #include "mozilla/TextEditor.h"
 #include "mozilla/dom/Element.h"
 #include "nsAString.h"
 #include "nsCOMPtr.h"
 #include "nsCaseTreatment.h"
 #include "nsDebug.h"
 #include "nsError.h"
 #include "nsGkAtoms.h"
-#include "nsIDOMElement.h"
 #include "nsIDOMNode.h"
 #include "nsNameSpaceManager.h"
 #include "nsLiteralString.h"
 #include "nsString.h"
 
 namespace mozilla {
 
 /******************************************************************************
--- a/editor/libeditor/TextEditor.cpp
+++ b/editor/libeditor/TextEditor.cpp
@@ -32,17 +32,16 @@
 #include "nsDebug.h"
 #include "nsDependentSubstring.h"
 #include "nsError.h"
 #include "nsGkAtoms.h"
 #include "nsIClipboard.h"
 #include "nsIContent.h"
 #include "nsIContentIterator.h"
 #include "nsIDOMDocument.h"
-#include "nsIDOMElement.h"
 #include "nsIDOMEventTarget.h"
 #include "nsIDOMNode.h"
 #include "nsIDocumentEncoder.h"
 #include "nsINode.h"
 #include "nsIPresShell.h"
 #include "nsISelectionController.h"
 #include "nsISupportsPrimitives.h"
 #include "nsITransferable.h"
@@ -1648,18 +1647,20 @@ TextEditor::SelectEntireDocument(Selecti
   }
 
   // Protect the edit rules object from dying
   RefPtr<TextEditRules> rules(mRules);
 
   // is doc empty?
   if (rules->DocumentIsEmpty()) {
     // get root node
-    nsCOMPtr<nsIDOMElement> rootElement = do_QueryInterface(GetRoot());
-    NS_ENSURE_TRUE(rootElement, NS_ERROR_FAILURE);
+    Element* rootElement = GetRoot();
+    if (NS_WARN_IF(!rootElement)) {
+      return NS_ERROR_FAILURE;
+    }
 
     // if it's empty don't select entire doc - that would select the bogus node
     return aSelection->Collapse(rootElement, 0);
   }
 
   SelectionBatcher selectionBatcher(aSelection);
   nsresult rv = EditorBase::SelectEntireDocument(aSelection);
   NS_ENSURE_SUCCESS(rv, rv);
--- a/editor/libeditor/TextEditor.h
+++ b/editor/libeditor/TextEditor.h
@@ -12,17 +12,16 @@
 #include "nsIEditor.h"
 #include "nsIEditorMailSupport.h"
 #include "nsIPlaintextEditor.h"
 #include "nsISupportsImpl.h"
 #include "nscore.h"
 
 class nsIContent;
 class nsIDOMDocument;
-class nsIDOMElement;
 class nsIDOMEvent;
 class nsIDOMNode;
 class nsIDocumentEncoder;
 class nsIOutputStream;
 class nsISelectionController;
 class nsITransferable;
 
 namespace mozilla {
--- a/editor/libeditor/TextEditorTest.cpp
+++ b/editor/libeditor/TextEditorTest.cpp
@@ -8,17 +8,16 @@
 #include "TextEditorTest.h"
 
 #include <stdio.h>
 
 #include "nsDebug.h"
 #include "nsError.h"
 #include "nsGkAtoms.h"
 #include "nsIDocument.h"
-#include "nsIDOMCharacterData.h"
 #include "nsIDOMDocument.h"
 #include "nsIDOMNode.h"
 #include "nsIDOMNodeList.h"
 #include "nsIEditor.h"
 #include "nsIHTMLEditor.h"
 #include "nsINodeList.h"
 #include "nsIPlaintextEditor.h"
 #include "nsISelection.h"
--- a/editor/nsIEditActionListener.idl
+++ b/editor/nsIEditActionListener.idl
@@ -74,47 +74,47 @@ interface nsIEditActionListener : nsISup
    */
   void DidJoinNodes(in nsIDOMNode aLeftNode,
                           in nsIDOMNode aRightNode,
                           in nsIDOMNode aParent,
                           in nsresult    aResult);
 
   /**
    * Called after the editor inserts text.
-   * @param aTextNode   This node getting inserted text
+   * @param aTextNode   This node getting inserted text.  Should be a CharacterData after bug 1444991.
    * @param aOffset     The offset in aTextNode to insert at.
    * @param aString     The string that gets inserted.
    * @param aResult     The result of the insert text operation.
    */
-  void DidInsertText(in nsIDOMCharacterData aTextNode,
-                           in long                aOffset,
-                           in DOMString           aString,
-                           in nsresult            aResult);
+  void DidInsertText(in nsISupports aTextNode,
+                     in long                aOffset,
+                     in DOMString           aString,
+                     in nsresult            aResult);
 
   /**
    * Called before the editor deletes text.
-   * @param aTextNode   This node getting text deleted
+   * @param aTextNode   This node getting text deleted.  Should be a CharacterData after bug 1444991.
    * @param aOffset     The offset in aTextNode to delete at.
    * @param aLength     The amount of text to delete.
    */
-  void WillDeleteText(in nsIDOMCharacterData aTextNode,
-                            in long                aOffset,
-                            in long                aLength);
+  void WillDeleteText(in nsISupports aTextNode,
+                      in long                aOffset,
+                      in long                aLength);
 
   /**
    * Called before the editor deletes text.
-   * @param aTextNode   This node getting text deleted
+   * @param aTextNode   This node getting text deleted.  Should be a CharacterData after bug 1444991.
    * @param aOffset     The offset in aTextNode to delete at.
    * @param aLength     The amount of text to delete.
    * @param aResult     The result of the delete text operation.
    */
-  void DidDeleteText(in nsIDOMCharacterData aTextNode,
-                           in long                aOffset,
-                           in long                aLength,
-                           in nsresult              aResult);
+  void DidDeleteText(in nsISupports aTextNode,
+                     in long                aOffset,
+                     in long                aLength,
+                     in nsresult              aResult);
 
   /**
    * Called before the editor deletes the selection.
    * @param aSelection   The selection to be deleted
    */
   void WillDeleteSelection(in nsISelection aSelection);
 
   /**
--- a/editor/spellchecker/EditorSpellCheck.cpp
+++ b/editor/spellchecker/EditorSpellCheck.cpp
@@ -18,17 +18,16 @@
 #include "nsAString.h"                  // for nsAString::IsEmpty, etc
 #include "nsComponentManagerUtils.h"    // for do_CreateInstance
 #include "nsDebug.h"                    // for NS_ENSURE_TRUE, etc
 #include "nsDependentSubstring.h"       // for Substring
 #include "nsError.h"                    // for NS_ERROR_NOT_INITIALIZED, etc
 #include "nsIContent.h"                 // for nsIContent
 #include "nsIContentPrefService2.h"     // for nsIContentPrefService2, etc
 #include "nsIDOMDocument.h"             // for nsIDOMDocument
-#include "nsIDOMElement.h"              // for nsIDOMElement
 #include "nsIDocument.h"                // for nsIDocument
 #include "nsIEditor.h"                  // for nsIEditor
 #include "nsIHTMLEditor.h"              // for nsIHTMLEditor
 #include "nsILoadContext.h"
 #include "nsISelection.h"               // for nsISelection
 #include "nsISupportsBase.h"            // for nsISupports
 #include "nsISupportsUtils.h"           // for NS_ADDREF
 #include "nsITextServicesFilter.h"      // for nsITextServicesFilter
@@ -732,20 +731,17 @@ EditorSpellCheck::UpdateCurrentDictionar
   RefPtr<EditorSpellCheck> kungFuDeathGrip = this;
 
   // Get language with html5 algorithm
   nsCOMPtr<nsIContent> rootContent;
   nsCOMPtr<nsIHTMLEditor> htmlEditor = do_QueryInterface(mEditor);
   if (htmlEditor) {
     rootContent = htmlEditor->GetActiveEditingHost();
   } else {
-    nsCOMPtr<nsIDOMElement> rootElement;
-    rv = mEditor->GetRootElement(getter_AddRefs(rootElement));
-    NS_ENSURE_SUCCESS(rv, rv);
-    rootContent = do_QueryInterface(rootElement);
+    rootContent = mEditor->AsEditorBase()->GetRoot();
   }
 
   // Try to get topmost document's document element for embedded mail editor.
   uint32_t flags = 0;
   mEditor->GetFlags(&flags);
   if (flags & nsIPlaintextEditor::eEditorMailMask) {
     nsCOMPtr<nsIDocument> ownerDoc = rootContent->OwnerDoc();
     NS_ENSURE_TRUE(ownerDoc, NS_ERROR_FAILURE);
--- a/editor/spellchecker/TextServicesDocument.cpp
+++ b/editor/spellchecker/TextServicesDocument.cpp
@@ -15,17 +15,16 @@
 #include "nsDependentSubstring.h"       // for Substring
 #include "nsError.h"                    // for NS_OK, NS_ERROR_FAILURE, etc
 #include "nsFilteredContentIterator.h"  // for nsFilteredContentIterator
 #include "nsGenericHTMLElement.h"       // for nsGenericHTMLElement
 #include "nsIContent.h"                 // for nsIContent, etc
 #include "nsIContentIterator.h"         // for nsIContentIterator
 #include "nsID.h"                       // for NS_GET_IID
 #include "nsIDOMDocument.h"             // for nsIDOMDocument
-#include "nsIDOMElement.h"              // for nsIDOMElement
 #include "nsIDOMNode.h"                 // for nsIDOMNode, etc
 #include "nsIEditor.h"                  // for nsIEditor, etc
 #include "nsINode.h"                    // for nsINode
 #include "nsIPlaintextEditor.h"         // for nsIPlaintextEditor
 #include "nsISelection.h"               // for nsISelection
 #include "nsISelectionController.h"     // for nsISelectionController, etc
 #include "nsISupportsBase.h"            // for nsISupports
 #include "nsISupportsUtils.h"           // for NS_IF_ADDREF, NS_ADDREF, etc
@@ -3243,34 +3242,34 @@ NS_IMETHODIMP
 TextServicesDocument::DidCreateNode(const nsAString& aTag,
                                     nsIDOMNode* aNewNode,
                                     nsresult aResult)
 {
   return NS_OK;
 }
 
 NS_IMETHODIMP
-TextServicesDocument::DidInsertText(nsIDOMCharacterData* aTextNode,
+TextServicesDocument::DidInsertText(nsISupports* aTextNode,
                                     int32_t aOffset,
                                     const nsAString& aString,
                                     nsresult aResult)
 {
   return NS_OK;
 }
 
 NS_IMETHODIMP
-TextServicesDocument::WillDeleteText(nsIDOMCharacterData* aTextNode,
+TextServicesDocument::WillDeleteText(nsISupports* aTextNode,
                                      int32_t aOffset,
                                      int32_t aLength)
 {
   return NS_OK;
 }
 
 NS_IMETHODIMP
-TextServicesDocument::DidDeleteText(nsIDOMCharacterData* aTextNode,
+TextServicesDocument::DidDeleteText(nsISupports* aTextNode,
                                     int32_t aOffset,
                                     int32_t aLength,
                                     nsresult aResult)
 {
   return NS_OK;
 }
 
 NS_IMETHODIMP
--- a/editor/spellchecker/TextServicesDocument.h
+++ b/editor/spellchecker/TextServicesDocument.h
@@ -11,17 +11,16 @@
 #include "nsIEditActionListener.h"
 #include "nsISupportsImpl.h"
 #include "nsStringFwd.h"
 #include "nsTArray.h"
 #include "nscore.h"
 
 class nsIContent;
 class nsIContentIterator;
-class nsIDOMCharacterData;
 class nsIDOMDocument;
 class nsIDOMNode;
 class nsIEditor;
 class nsINode;
 class nsISelection;
 class nsISelectionController;
 class nsITextServicesFilter;
 class nsRange;
--- a/gfx/skia/skia/src/core/SkTDynamicHash.h
+++ b/gfx/skia/skia/src/core/SkTDynamicHash.h
@@ -236,29 +236,30 @@ private:
                 return;
             }
             index = this->nextIndex(index, round);
         }
         SkASSERT(fCapacity == 0);
     }
 
     void maybeGrow() {
-        if (100 * (fCount + fDeleted + 1) > fCapacity * kGrowPercent) {
+        if (100 * (int64_t(fCount + fDeleted) + 1) > int64_t(fCapacity) * kGrowPercent) {
+            SkASSERT_RELEASE(fCapacity <= std::numeric_limits<int>::max() / 2);
             this->resize(fCapacity > 0 ? fCapacity * 2 : 4);
         }
     }
 
     void resize(int newCapacity) {
         SkDEBUGCODE(int oldCount = fCount;)
         int oldCapacity = fCapacity;
         SkAutoTMalloc<T*> oldArray(fArray);
 
         fCount = fDeleted = 0;
         fCapacity = newCapacity;
-        fArray = (T**)sk_calloc_throw(sizeof(T*) * fCapacity);
+        fArray = (T**)sk_calloc_throw(fCapacity, sizeof(T*));
 
         for (int i = 0; i < oldCapacity; i++) {
             T* entry = oldArray[i];
             if (Empty() != entry && Deleted() != entry) {
                 this->innerAdd(entry);
             }
         }
         SkASSERT(oldCount == fCount);
--- a/gfx/skia/skia/src/gpu/ops/GrSmallPathRenderer.cpp
+++ b/gfx/skia/skia/src/gpu/ops/GrSmallPathRenderer.cpp
@@ -530,18 +530,22 @@ private:
     bool addBMPathToAtlas(GrMeshDrawOp::Target* target, FlushInfo* flushInfo,
                           GrDrawOpAtlas* atlas, ShapeData* shapeData, const GrShape& shape,
                           const SkMatrix& ctm) const {
         const SkRect& bounds = shape.bounds();
         if (bounds.isEmpty()) {
             return false;
         }
         SkMatrix drawMatrix(ctm);
-        drawMatrix.set(SkMatrix::kMTransX, SkScalarFraction(ctm.get(SkMatrix::kMTransX)));
-        drawMatrix.set(SkMatrix::kMTransY, SkScalarFraction(ctm.get(SkMatrix::kMTransY)));
+        SkScalar tx = ctm.getTranslateX();
+        SkScalar ty = ctm.getTranslateY();
+        tx -= SkScalarFloorToScalar(tx);
+        ty -= SkScalarFloorToScalar(ty);
+        drawMatrix.set(SkMatrix::kMTransX, tx);
+        drawMatrix.set(SkMatrix::kMTransY, ty);
         SkRect shapeDevBounds;
         drawMatrix.mapRect(&shapeDevBounds, bounds);
         SkScalar dx = SkScalarFloorToScalar(shapeDevBounds.fLeft);
         SkScalar dy = SkScalarFloorToScalar(shapeDevBounds.fTop);
 
         // get integer boundary
         SkIRect devPathBounds;
         shapeDevBounds.roundOut(&devPathBounds);
@@ -629,18 +633,18 @@ private:
                            size_t vertexStride,
                            const SkMatrix& ctm,
                            const ShapeData* shapeData) const {
         SkPoint* positions = reinterpret_cast<SkPoint*>(offset);
 
         SkRect bounds = shapeData->fBounds;
         SkRect translatedBounds(bounds);
         if (!fUsesDistanceField) {
-            translatedBounds.offset(SkScalarTruncToScalar(ctm.get(SkMatrix::kMTransX)),
-                                  SkScalarTruncToScalar(ctm.get(SkMatrix::kMTransY)));
+            translatedBounds.offset(SkScalarFloorToScalar(ctm.get(SkMatrix::kMTransX)),
+                                    SkScalarFloorToScalar(ctm.get(SkMatrix::kMTransY)));
         }
 
         // vertex positions
         // TODO make the vertex attributes a struct
         if (fUsesDistanceField && !ctm.hasPerspective()) {
             GrQuad quad;
             quad.setFromMappedRect(translatedBounds, ctm);
             intptr_t positionOffset = offset;
@@ -651,21 +655,22 @@ private:
             *position = quad.point(1);
             positionOffset += vertexStride;
             position = (SkPoint*)positionOffset;
             *position = quad.point(2);
             positionOffset += vertexStride;
             position = (SkPoint*)positionOffset;
             *position = quad.point(3);
         } else {
-            SkPointPriv::SetRectTriStrip(positions, translatedBounds.left(),
-                                       translatedBounds.top(),
-                                       translatedBounds.right(),
-                                       translatedBounds.bottom(),
-                                       vertexStride);
+            SkPointPriv::SetRectTriStrip(positions,
+                                         translatedBounds.left(),
+                                         translatedBounds.top(),
+                                         translatedBounds.right(),
+                                         translatedBounds.bottom(),
+                                         vertexStride);
         }
 
         // colors
         for (int i = 0; i < kVerticesPerQuad; i++) {
             GrColor* colorPtr = (GrColor*)(offset + sizeof(SkPoint) + i * vertexStride);
             *colorPtr = color;
         }
 
--- a/gfx/skia/skia/src/gpu/ops/GrSmallPathRenderer.h
+++ b/gfx/skia/skia/src/gpu/ops/GrSmallPathRenderer.h
@@ -91,18 +91,20 @@ private:
                 // We require the upper left 2x2 of the matrix to match exactly for a cache hit.
                 SkScalar sx = ctm.get(SkMatrix::kMScaleX);
                 SkScalar sy = ctm.get(SkMatrix::kMScaleY);
                 SkScalar kx = ctm.get(SkMatrix::kMSkewX);
                 SkScalar ky = ctm.get(SkMatrix::kMSkewY);
                 SkScalar tx = ctm.get(SkMatrix::kMTransX);
                 SkScalar ty = ctm.get(SkMatrix::kMTransY);
                 // Allow 8 bits each in x and y of subpixel positioning.
-                SkFixed fracX = SkScalarToFixed(SkScalarFraction(tx)) & 0x0000FF00;
-                SkFixed fracY = SkScalarToFixed(SkScalarFraction(ty)) & 0x0000FF00;
+                tx -= SkScalarFloorToScalar(tx);
+                ty -= SkScalarFloorToScalar(ty);
+                SkFixed fracX = SkScalarToFixed(tx) & 0x0000FF00;
+                SkFixed fracY = SkScalarToFixed(ty) & 0x0000FF00;
                 int shapeKeySize = shape.unstyledKeySize();
                 fKey.reset(5 + shapeKeySize);
                 fKey[0] = SkFloat2Bits(sx);
                 fKey[1] = SkFloat2Bits(sy);
                 fKey[2] = SkFloat2Bits(kx);
                 fKey[3] = SkFloat2Bits(ky);
                 fKey[4] = fracX | (fracY >> 8);
                 shape.writeUnstyledKey(&fKey[5]);
--- a/gfx/skia/skia/src/ports/SkFontHost_mac.cpp
+++ b/gfx/skia/skia/src/ports/SkFontHost_mac.cpp
@@ -1660,25 +1660,40 @@ SkStreamAsset* SkTypeface_Mac::onOpenStr
     }
 
     // get table tags
     int numTables = this->countTables();
     SkTDArray<SkFontTableTag> tableTags;
     tableTags.setCount(numTables);
     this->getTableTags(tableTags.begin());
 
-    // calc total size for font, save sizes
+    // see if there are any required 'typ1' tables (see Adobe Technical Note #5180)
+    bool couldBeTyp1 = false;
+    constexpr SkFontTableTag TYPE1Tag = SkSetFourByteTag('T', 'Y', 'P', '1');
+    constexpr SkFontTableTag CIDTag = SkSetFourByteTag('C', 'I', 'D', ' ');
+    // get the table sizes and accumulate the total size of the font
     SkTDArray<size_t> tableSizes;
     size_t totalSize = sizeof(SkSFNTHeader) + sizeof(SkSFNTHeader::TableDirectoryEntry) * numTables;
     for (int tableIndex = 0; tableIndex < numTables; ++tableIndex) {
+        if (TYPE1Tag == tableTags[tableIndex] || CIDTag == tableTags[tableIndex]) {
+            couldBeTyp1 = true;
+        }
+
         size_t tableSize = this->getTableSize(tableTags[tableIndex]);
         totalSize += (tableSize + 3) & ~3;
         *tableSizes.append() = tableSize;
     }
 
+    // sometimes CoreGraphics incorrectly thinks a font is kCTFontFormatPostScript
+    // it is exceedingly unlikely that this is the case, so double check
+    // see https://crbug.com/809763
+    if (fontType == SkSFNTHeader::fontType_PostScript::TAG && !couldBeTyp1) {
+        fontType = SkSFNTHeader::fontType_OpenTypeCFF::TAG;
+    }
+
     // reserve memory for stream, and zero it (tables must be zero padded)
     SkMemoryStream* stream = new SkMemoryStream(totalSize);
     char* dataStart = (char*)stream->getMemoryBase();
     sk_bzero(dataStart, totalSize);
     char* dataPtr = dataStart;
 
     // compute font header entries
     uint16_t entrySelector = 0;
--- a/gfx/skia/skia/src/shaders/SkImageShader.cpp
+++ b/gfx/skia/skia/src/shaders/SkImageShader.cpp
@@ -434,22 +434,26 @@ bool SkImageShader::onAppendStages(const
                                          : SkRasterPipeline::clamp_a);
         }
         append_gamut_transform(p, alloc, info.colorSpace(), rec.fDstCS,
                                fClampAsIfUnpremul ? kUnpremul_SkAlphaType : kPremul_SkAlphaType);
         return true;
     };
 
     if (quality == kLow_SkFilterQuality            &&
-        info.colorType() == kRGBA_8888_SkColorType &&
+        (info.colorType() == kRGBA_8888_SkColorType ||
+         info.colorType() == kBGRA_8888_SkColorType) &&
         fTileModeX == SkShader::kClamp_TileMode    &&
         fTileModeY == SkShader::kClamp_TileMode    &&
         !is_srgb) {
 
         p->append(SkRasterPipeline::bilerp_clamp_8888, gather);
+        if (info.colorType() == kBGRA_8888_SkColorType) {
+            p->append(SkRasterPipeline::swap_rb);
+        }
         return append_misc();
     }
 
     SkJumper_SamplerCtx* sampler = nullptr;
     if (quality != kNone_SkFilterQuality) {
         sampler = alloc->make<SkJumper_SamplerCtx>();
     }
 
--- a/js/public/Value.h
+++ b/js/public/Value.h
@@ -260,30 +260,23 @@ constexpr uint64_t CanonicalizedNaNBits 
  */
 static MOZ_ALWAYS_INLINE double
 GenericNaN()
 {
   return mozilla::SpecificNaN<double>(detail::CanonicalizedNaNSignBit,
                                       detail::CanonicalizedNaNSignificand);
 }
 
-/* MSVC with PGO miscompiles this function. */
-#if defined(_MSC_VER)
-# pragma optimize("g", off)
-#endif
 static inline double
 CanonicalizeNaN(double d)
 {
     if (MOZ_UNLIKELY(mozilla::IsNaN(d)))
         return GenericNaN();
     return d;
 }
-#if defined(_MSC_VER)
-# pragma optimize("", on)
-#endif
 
 /**
  * JS::Value is the interface for a single JavaScript Engine value.  A few
  * general notes on JS::Value:
  *
  * - JS::Value has setX() and isX() members for X in
  *
  *     { Int32, Double, String, Symbol, Boolean, Undefined, Null, Object, Magic }
--- a/js/src/jit/BaselineBailouts.cpp
+++ b/js/src/jit/BaselineBailouts.cpp
@@ -622,21 +622,21 @@ IsPrologueBailout(const SnapshotIterator
 //         |            |  CalleeToken  |
 //         |            +---------------+
 //         +------------|  Descr(Rect)  |
 //                      +---------------+
 //                      |  ReturnAddr   | <-- return into ArgumentsRectifier after call
 //                      +===============+
 //
 static bool
-InitFromBailout(JSContext* cx, jsbytecode* callerPC,
+InitFromBailout(JSContext* cx, size_t frameNo,
                 HandleFunction fun, HandleScript script,
                 SnapshotIterator& iter, bool invalidate, BaselineStackBuilder& builder,
                 MutableHandle<GCVector<Value>> startFrameFormals, MutableHandleFunction nextCallee,
-                jsbytecode** callPC, const ExceptionBailoutInfo* excInfo)
+                const ExceptionBailoutInfo* excInfo)
 {
     // The Baseline frames we will reconstruct on the heap are not rooted, so GC
     // must be suppressed here.
     MOZ_ASSERT(cx->suppressGC);
 
     MOZ_ASSERT(script->hasBaselineScript());
 
     // Are we catching an exception?
@@ -822,32 +822,32 @@ InitFromBailout(JSContext* cx, jsbytecod
 
         size_t thisvOffset = builder.framePushed() + JitFrameLayout::offsetOfThis();
         builder.valuePointerAtStackOffset(thisvOffset).set(thisv);
 
         MOZ_ASSERT(iter.numAllocations() >= CountArgSlots(script, fun));
         JitSpew(JitSpew_BaselineBailouts, "      frame slots %u, nargs %zu, nfixed %zu",
                 iter.numAllocations(), fun->nargs(), script->nfixed());
 
-        if (!callerPC) {
+        if (frameNo == 0) {
             // This is the first frame. Store the formals in a Vector until we
             // are done. Due to UCE and phi elimination, we could store an
             // UndefinedValue() here for formals we think are unused, but
             // locals may still reference the original argument slot
             // (MParameter/LArgument) and expect the original Value.
             MOZ_ASSERT(startFrameFormals.empty());
             if (!startFrameFormals.resize(fun->nargs()))
                 return false;
         }
 
         for (uint32_t i = 0; i < fun->nargs(); i++) {
             Value arg = iter.read();
             JitSpew(JitSpew_BaselineBailouts, "      arg %d = %016" PRIx64,
                         (int) i, *((uint64_t*) &arg));
-            if (callerPC) {
+            if (frameNo > 0) {
                 size_t argOffset = builder.framePushed() + JitFrameLayout::offsetOfActualArg(i);
                 builder.valuePointerAtStackOffset(argOffset).set(arg);
             } else {
                 startFrameFormals[i].set(arg);
             }
         }
     }
 
@@ -1072,19 +1072,16 @@ InitFromBailout(JSContext* cx, jsbytecod
             BailoutKindString(bailoutKind));
 #endif
 
     bool pushedNewTarget = IsConstructorCallPC(pc);
 
     // If this was the last inline frame, or we are bailing out to a catch or
     // finally block in this frame, then unpacking is almost done.
     if (!iter.moreFrames() || catchingException) {
-        // Last frame, so PC for call to next frame is set to nullptr.
-        *callPC = nullptr;
-
         // If the bailout was a resumeAfter, and the opcode is monitored,
         // then the bailed out state should be in a position to enter
         // into the ICTypeMonitor chain for the op.
         bool enterMonitorChain = false;
         if (resumeAfter && (CodeSpec[op].format & JOF_TYPESET)) {
             // Not every monitored op has a monitored fallback stub, e.g.
             // JSOP_NEWOBJECT, which always returns the same type for a
             // particular script/pc location.
@@ -1253,18 +1250,16 @@ InitFromBailout(JSContext* cx, jsbytecod
                      script->lineno());
             cx->runtime()->geckoProfiler().markEvent(buf);
             js_free(buf);
         }
 
         return true;
     }
 
-    *callPC = pc;
-
     // Write out descriptor of BaselineJS frame.
     size_t baselineFrameDescr = MakeFrameDescriptor((uint32_t) builder.framePushed(),
                                                     JitFrame_BaselineJS,
                                                     BaselineStubFrameLayout::Size());
     if (!builder.writeWord(baselineFrameDescr, "Descriptor"))
         return false;
 
     // Calculate and write out return address.
@@ -1628,18 +1623,16 @@ jit::BailoutIonToBaseline(JSContext* cx,
         JitSpew(JitSpew_BaselineBailouts, "  Constructing!");
     else
         JitSpew(JitSpew_BaselineBailouts, "  Not constructing!");
 
     JitSpew(JitSpew_BaselineBailouts, "  Restoring frames:");
     size_t frameNo = 0;
 
     // Reconstruct baseline frames using the builder.
-    RootedScript caller(cx);
-    jsbytecode* callerPC = nullptr;
     RootedFunction fun(cx, callee);
     Rooted<GCVector<Value>> startFrameFormals(cx, GCVector<Value>(cx));
 
     gc::AutoSuppressGC suppress(cx);
 
     while (true) {
         // Skip recover instructions as they are already recovered by |initInstructionResults|.
         snapIter.settleOnFrame();
@@ -1658,37 +1651,33 @@ jit::BailoutIonToBaseline(JSContext* cx,
         // If we are bailing out to a catch or finally block in this frame,
         // pass excInfo to InitFromBailout and don't unpack any other frames.
         bool handleException = (catchingException && excInfo->frameNo() == frameNo);
 
         // We also need to pass excInfo if we're bailing out in place for
         // debug mode.
         bool passExcInfo = handleException || propagatingExceptionForDebugMode;
 
-        jsbytecode* callPC = nullptr;
         RootedFunction nextCallee(cx, nullptr);
-        if (!InitFromBailout(cx, callerPC, fun, scr,
+        if (!InitFromBailout(cx, frameNo, fun, scr,
                              snapIter, invalidate, builder, &startFrameFormals,
-                             &nextCallee, &callPC, passExcInfo ? excInfo : nullptr))
+                             &nextCallee, passExcInfo ? excInfo : nullptr))
         {
             return BAILOUT_RETURN_FATAL_ERROR;
         }
 
         if (!snapIter.moreFrames()) {
-            MOZ_ASSERT(!callPC);
+            MOZ_ASSERT(!nextCallee);
             break;
         }
 
         if (handleException)
             break;
 
         MOZ_ASSERT(nextCallee);
-        MOZ_ASSERT(callPC);
-        caller = scr;
-        callerPC = callPC;
         fun = nextCallee;
         scr = fun->existingScript();
 
         frameNo++;
 
         snapIter.nextInstruction();
     }
     JitSpew(JitSpew_BaselineBailouts, "  Done restoring frames");
--- a/js/src/jit/BaselineInspector.cpp
+++ b/js/src/jit/BaselineInspector.cpp
@@ -767,16 +767,19 @@ AddCacheIRGlobalGetter(ICCacheIR_Monitor
     //
     //   GuardShape objId
     //   globalId = LoadEnclosingEnvironment objId
     //   GuardShape globalId
     //   <holderId = LoadObject <holder>>
     //   <GuardShape holderId>
     //   CallNativeGetterResult globalId
 
+    if (innerized)
+        return false;
+
     CacheIRReader reader(stub->stubInfo());
 
     ObjOperandId objId = ObjOperandId(0);
     if (!reader.matchOp(CacheOp::GuardShape, objId))
         return false;
     Shape* globalLexicalShape = stub->stubInfo()->getStubField<Shape*>(stub, reader.stubOffset());
 
     if (!reader.matchOp(CacheOp::LoadEnclosingEnvironment, objId))
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -3031,16 +3031,22 @@ CodeGenerator::visitOsiPoint(LOsiPoint* 
 
 #ifdef CHECK_OSIPOINT_REGISTERS
     if (shouldVerifyOsiPointRegs(safepoint))
         verifyOsiPointRegs(safepoint);
 #endif
 }
 
 void
+CodeGenerator::visitPhi(LPhi* lir)
+{
+    MOZ_CRASH("Unexpected LPhi in CodeGenerator");
+}
+
+void
 CodeGenerator::visitGoto(LGoto* lir)
 {
     jumpToBlock(lir->target());
 }
 
 // Out-of-line path to execute any move groups between the start of a loop
 // header and its interrupt check, then invoke the interrupt handler.
 class OutOfLineInterruptCheckImplicit : public OutOfLineCodeBase<CodeGenerator>
@@ -5798,19 +5804,21 @@ CodeGenerator::generateBody()
 
             setElement(*iter); // needed to encode correct snapshot location.
 
 #ifdef DEBUG
             emitDebugForceBailing(*iter);
 #endif
 
             switch (iter->op()) {
-#define LIROP(op) case LNode::Opcode::op: visit##op(iter->to##op()); break;
+#ifndef JS_CODEGEN_NONE
+# define LIROP(op) case LNode::Opcode::op: visit##op(iter->to##op()); break;
     LIR_OPCODE_LIST(LIROP)
-#undef LIROP
+# undef LIROP
+#endif
               case LNode::Opcode::Invalid:
               default:
                 MOZ_CRASH("Invalid LIR op");
             }
 
             // Track the end native offset of optimizations.
             if (iter->mirRaw() && iter->mirRaw()->trackedOptimizations())
                 extendTrackedOptimizationsEntry(iter->mirRaw()->trackedOptimizations());
@@ -7056,16 +7064,192 @@ CodeGenerator::visitGetNextEntryForItera
         emitGetNextEntryForIterator<MapIteratorObject, ValueMap>(lir);
     } else {
         MOZ_ASSERT(lir->mir()->mode() == MGetNextEntryForIterator::Set);
         emitGetNextEntryForIterator<SetIteratorObject, ValueSet>(lir);
     }
 }
 
 void
+CodeGenerator::emitWasmCallBase(MWasmCall* mir, bool needsBoundsCheck)
+{
+    if (mir->spIncrement())
+        masm.freeStack(mir->spIncrement());
+
+    MOZ_ASSERT((sizeof(wasm::Frame) + masm.framePushed()) % WasmStackAlignment == 0);
+    static_assert(WasmStackAlignment >= ABIStackAlignment &&
+                  WasmStackAlignment % ABIStackAlignment == 0,
+                  "The wasm stack alignment should subsume the ABI-required alignment");
+
+#ifdef DEBUG
+    Label ok;
+    masm.branchTestStackPtr(Assembler::Zero, Imm32(WasmStackAlignment - 1), &ok);
+    masm.breakpoint();
+    masm.bind(&ok);
+#endif
+
+    // LWasmCallBase::isCallPreserved() assumes that all MWasmCalls preserve the
+    // TLS and pinned regs. The only case where where we don't have to reload
+    // the TLS and pinned regs is when the callee preserves them.
+    bool reloadRegs = true;
+
+    const wasm::CallSiteDesc& desc = mir->desc();
+    const wasm::CalleeDesc& callee = mir->callee();
+    switch (callee.which()) {
+      case wasm::CalleeDesc::Func:
+        masm.call(desc, callee.funcIndex());
+        reloadRegs = false;
+        break;
+      case wasm::CalleeDesc::Import:
+        masm.wasmCallImport(desc, callee);
+        break;
+      case wasm::CalleeDesc::AsmJSTable:
+      case wasm::CalleeDesc::WasmTable:
+        masm.wasmCallIndirect(desc, callee, needsBoundsCheck);
+        reloadRegs = callee.which() == wasm::CalleeDesc::WasmTable && callee.wasmTableIsExternal();
+        break;
+      case wasm::CalleeDesc::Builtin:
+        masm.call(desc, callee.builtin());
+        reloadRegs = false;
+        break;
+      case wasm::CalleeDesc::BuiltinInstanceMethod:
+        masm.wasmCallBuiltinInstanceMethod(desc, mir->instanceArg(), callee.builtin());
+        break;
+    }
+
+    if (reloadRegs) {
+        masm.loadWasmTlsRegFromFrame();
+        masm.loadWasmPinnedRegsFromTls();
+    }
+
+    if (mir->spIncrement())
+        masm.reserveStack(mir->spIncrement());
+}
+
+void
+CodeGenerator::visitWasmCall(LWasmCall* ins)
+{
+    emitWasmCallBase(ins->mir(), ins->needsBoundsCheck());
+}
+
+void
+CodeGenerator::visitWasmCallVoid(LWasmCallVoid* ins)
+{
+    emitWasmCallBase(ins->mir(), ins->needsBoundsCheck());
+}
+
+void
+CodeGenerator::visitWasmCallI64(LWasmCallI64* ins)
+{
+    emitWasmCallBase(ins->mir(), ins->needsBoundsCheck());
+}
+
+void
+CodeGenerator::visitWasmLoadGlobalVar(LWasmLoadGlobalVar* ins)
+{
+    MWasmLoadGlobalVar* mir = ins->mir();
+
+    MIRType type = mir->type();
+    MOZ_ASSERT(IsNumberType(type) || IsSimdType(type));
+
+    Register tls = ToRegister(ins->tlsPtr());
+    Address addr(tls, offsetof(wasm::TlsData, globalArea) + mir->globalDataOffset());
+    switch (type) {
+      case MIRType::Int32:
+        masm.load32(addr, ToRegister(ins->output()));
+        break;
+      case MIRType::Float32:
+        masm.loadFloat32(addr, ToFloatRegister(ins->output()));
+        break;
+      case MIRType::Double:
+        masm.loadDouble(addr, ToFloatRegister(ins->output()));
+        break;
+      // Aligned access: code is aligned on PageSize + there is padding
+      // before the global data section.
+      case MIRType::Int8x16:
+      case MIRType::Int16x8:
+      case MIRType::Int32x4:
+      case MIRType::Bool8x16:
+      case MIRType::Bool16x8:
+      case MIRType::Bool32x4:
+        masm.loadInt32x4(addr, ToFloatRegister(ins->output()));
+        break;
+      case MIRType::Float32x4:
+        masm.loadFloat32x4(addr, ToFloatRegister(ins->output()));
+        break;
+      default:
+        MOZ_CRASH("unexpected type in visitWasmLoadGlobalVar");
+    }
+}
+
+void
+CodeGenerator::visitWasmStoreGlobalVar(LWasmStoreGlobalVar* ins)
+{
+    MWasmStoreGlobalVar* mir = ins->mir();
+
+    MIRType type = mir->value()->type();
+    MOZ_ASSERT(IsNumberType(type) || IsSimdType(type));
+
+    Register tls = ToRegister(ins->tlsPtr());
+    Address addr(tls, offsetof(wasm::TlsData, globalArea) + mir->globalDataOffset());
+    switch (type) {
+      case MIRType::Int32:
+        masm.store32(ToRegister(ins->value()), addr);
+        break;
+      case MIRType::Float32:
+        masm.storeFloat32(ToFloatRegister(ins->value()), addr);
+        break;
+      case MIRType::Double:
+        masm.storeDouble(ToFloatRegister(ins->value()), addr);
+        break;
+      // Aligned access: code is aligned on PageSize + there is padding
+      // before the global data section.
+      case MIRType::Int8x16:
+      case MIRType::Int16x8:
+      case MIRType::Int32x4:
+      case MIRType::Bool8x16:
+      case MIRType::Bool16x8:
+      case MIRType::Bool32x4:
+        masm.storeInt32x4(ToFloatRegister(ins->value()), addr);
+        break;
+      case MIRType::Float32x4:
+        masm.storeFloat32x4(ToFloatRegister(ins->value()), addr);
+        break;
+      default:
+        MOZ_CRASH("unexpected type in visitWasmStoreGlobalVar");
+    }
+}
+
+void
+CodeGenerator::visitWasmLoadGlobalVarI64(LWasmLoadGlobalVarI64* ins)
+{
+    MWasmLoadGlobalVar* mir = ins->mir();
+    MOZ_ASSERT(mir->type() == MIRType::Int64);
+
+    Register tls = ToRegister(ins->tlsPtr());
+    Address addr(tls, offsetof(wasm::TlsData, globalArea) + mir->globalDataOffset());
+
+    Register64 output = ToOutRegister64(ins);
+    masm.load64(addr, output);
+}
+
+void
+CodeGenerator::visitWasmStoreGlobalVarI64(LWasmStoreGlobalVarI64* ins)
+{
+    MWasmStoreGlobalVar* mir = ins->mir();
+    MOZ_ASSERT(mir->value()->type() == MIRType::Int64);
+
+    Register tls = ToRegister(ins->tlsPtr());
+    Address addr(tls, offsetof(wasm::TlsData, globalArea) + mir->globalDataOffset());
+
+    Register64 value = ToRegister64(ins->value());
+    masm.store64(value, addr);
+}
+
+void
 CodeGenerator::visitTypedArrayLength(LTypedArrayLength* lir)
 {
     Register obj = ToRegister(lir->object());
     Register out = ToRegister(lir->output());
     masm.unboxInt32(Address(obj, TypedArrayObject::lengthOffset()), out);
 }
 
 void
@@ -10265,17 +10449,17 @@ CodeGenerator::link(JSContext* cx, Compi
 
         entry.firstStub()->toFallbackStub()->fixupICEntry(&entry);
     }
 
     // for generating inline caches during the execution.
     if (runtimeData_.length())
         ionScript->copyRuntimeData(&runtimeData_[0]);
     if (icList_.length())
-        ionScript->copyICEntries(&icList_[0], masm);
+        ionScript->copyICEntries(&icList_[0]);
 
     for (size_t i = 0; i < icInfo_.length(); i++) {
         IonIC& ic = ionScript->getICFromIndex(i);
         Assembler::PatchDataWithValueCheck(CodeLocationLabel(code, icInfo_[i].icOffsetForJump),
                                            ImmPtr(ic.codeRawPtr()),
                                            ImmPtr((void*)-1));
         Assembler::PatchDataWithValueCheck(CodeLocationLabel(code, icInfo_[i].icOffsetForPush),
                                            ImmPtr(&ic),
--- a/js/src/jit/CodeGenerator.h
+++ b/js/src/jit/CodeGenerator.h
@@ -67,430 +67,139 @@ class CodeGenerator final : public CodeG
     MOZ_MUST_USE bool generateBody();
 
     ConstantOrRegister toConstantOrRegister(LInstruction* lir, size_t n, MIRType type);
 
   public:
     CodeGenerator(MIRGenerator* gen, LIRGraph* graph, MacroAssembler* masm = nullptr);
     ~CodeGenerator();
 
-  public:
     MOZ_MUST_USE bool generate();
     MOZ_MUST_USE bool generateWasm(wasm::SigIdDesc sigId, wasm::BytecodeOffset trapOffset,
                                    wasm::FuncOffsets* offsets);
+
     MOZ_MUST_USE bool link(JSContext* cx, CompilerConstraintList* constraints);
     MOZ_MUST_USE bool linkSharedStubs(JSContext* cx);
 
-    void visitOsiPoint(LOsiPoint* lir);
-    void visitGoto(LGoto* lir);
-    void visitTableSwitch(LTableSwitch* ins);
-    void visitTableSwitchV(LTableSwitchV* ins);
-    void visitCloneLiteral(LCloneLiteral* lir);
-    void visitParameter(LParameter* lir);
-    void visitCallee(LCallee* lir);
-    void visitIsConstructing(LIsConstructing* lir);
-    void visitStart(LStart* lir);
-    void visitReturn(LReturn* ret);
-    void visitDefVar(LDefVar* lir);
-    void visitDefLexical(LDefLexical* lir);
-    void visitDefFun(LDefFun* lir);
-    void visitOsrEntry(LOsrEntry* lir);
-    void visitOsrEnvironmentChain(LOsrEnvironmentChain* lir);
-    void visitOsrValue(LOsrValue* lir);
-    void visitOsrReturnValue(LOsrReturnValue* lir);
-    void visitOsrArgumentsObject(LOsrArgumentsObject* lir);
-    void visitStackArgT(LStackArgT* lir);
-    void visitStackArgV(LStackArgV* lir);
-    void visitMoveGroup(LMoveGroup* group);
-    void visitValueToInt32(LValueToInt32* lir);
-    void visitValueToDouble(LValueToDouble* lir);
-    void visitValueToFloat32(LValueToFloat32* lir);
-    void visitFloat32ToDouble(LFloat32ToDouble* lir);
-    void visitDoubleToFloat32(LDoubleToFloat32* lir);
-    void visitInt32ToFloat32(LInt32ToFloat32* lir);
-    void visitInt32ToDouble(LInt32ToDouble* lir);
     void emitOOLTestObject(Register objreg, Label* ifTruthy, Label* ifFalsy, Register scratch);
-    void visitTestOAndBranch(LTestOAndBranch* lir);
-    void visitTestVAndBranch(LTestVAndBranch* lir);
-    void visitFunctionDispatch(LFunctionDispatch* lir);
-    void visitObjectGroupDispatch(LObjectGroupDispatch* lir);
-    void visitBooleanToString(LBooleanToString* lir);
     void emitIntToString(Register input, Register output, Label* ool);
-    void visitIntToString(LIntToString* lir);
-    void visitDoubleToString(LDoubleToString* lir);
-    void visitValueToString(LValueToString* lir);
-    void visitValueToObject(LValueToObject* lir);
-    void visitValueToObjectOrNull(LValueToObjectOrNull* lir);
-    void visitInteger(LInteger* lir);
-    void visitInteger64(LInteger64* lir);
-    void visitRegExp(LRegExp* lir);
-    void visitRegExpMatcher(LRegExpMatcher* lir);
+
     void visitOutOfLineRegExpMatcher(OutOfLineRegExpMatcher* ool);
-    void visitRegExpSearcher(LRegExpSearcher* lir);
     void visitOutOfLineRegExpSearcher(OutOfLineRegExpSearcher* ool);
-    void visitRegExpTester(LRegExpTester* lir);
     void visitOutOfLineRegExpTester(OutOfLineRegExpTester* ool);
-    void visitRegExpPrototypeOptimizable(LRegExpPrototypeOptimizable* lir);
     void visitOutOfLineRegExpPrototypeOptimizable(OutOfLineRegExpPrototypeOptimizable* ool);
-    void visitRegExpInstanceOptimizable(LRegExpInstanceOptimizable* lir);
     void visitOutOfLineRegExpInstanceOptimizable(OutOfLineRegExpInstanceOptimizable* ool);
-    void visitGetFirstDollarIndex(LGetFirstDollarIndex* lir);
-    void visitStringReplace(LStringReplace* lir);
+
+    void visitOutOfLineLambdaArrow(OutOfLineLambdaArrow* ool);
+
+    void visitOutOfLineTypeOfV(OutOfLineTypeOfV* ool);
+
+    template <SwitchTableType tableType>
+    void visitOutOfLineSwitch(OutOfLineSwitch<tableType>* ool);
+
+    void visitOutOfLineIsCallable(OutOfLineIsCallable* ool);
+    void visitOutOfLineIsConstructor(OutOfLineIsConstructor* ool);
+
+    void visitOutOfLineNaNToZero(OutOfLineNaNToZero* ool);
+
+    void visitCheckOverRecursedFailure(CheckOverRecursedFailure* ool);
+
+    void visitOutOfLineUnboxFloatingPoint(OutOfLineUnboxFloatingPoint* ool);
+    void visitOutOfLineStoreElementHole(OutOfLineStoreElementHole* ool);
+
+    void visitOutOfLineICFallback(OutOfLineICFallback* ool);
+
+    void visitOutOfLineInterruptCheckImplicit(OutOfLineInterruptCheckImplicit* ins);
+
+    void visitOutOfLineCallPostWriteBarrier(OutOfLineCallPostWriteBarrier* ool);
+    void visitOutOfLineCallPostWriteElementBarrier(OutOfLineCallPostWriteElementBarrier* ool);
+
+    void visitOutOfLineNewArray(OutOfLineNewArray* ool);
+    void visitOutOfLineNewObject(OutOfLineNewObject* ool);
+
+  private:
     void emitSharedStub(ICStub::Kind kind, LInstruction* lir);
-    void visitBinarySharedStub(LBinarySharedStub* lir);
-    void visitUnarySharedStub(LUnarySharedStub* lir);
-    void visitNullarySharedStub(LNullarySharedStub* lir);
-    void visitClassConstructor(LClassConstructor* lir);
-    void visitLambda(LLambda* lir);
-    void visitOutOfLineLambdaArrow(OutOfLineLambdaArrow* ool);
-    void visitLambdaArrow(LLambdaArrow* lir);
-    void visitLambdaForSingleton(LLambdaForSingleton* lir);
-    void visitSetFunName(LSetFunName* lir);
-    void visitPointer(LPointer* lir);
-    void visitKeepAliveObject(LKeepAliveObject* lir);
-    void visitSlots(LSlots* lir);
-    void visitLoadSlotT(LLoadSlotT* lir);
-    void visitLoadSlotV(LLoadSlotV* lir);
-    void visitStoreSlotT(LStoreSlotT* lir);
-    void visitStoreSlotV(LStoreSlotV* lir);
-    void visitElements(LElements* lir);
-    void visitConvertElementsToDoubles(LConvertElementsToDoubles* lir);
-    void visitMaybeToDoubleElement(LMaybeToDoubleElement* lir);
-    void visitMaybeCopyElementsForWrite(LMaybeCopyElementsForWrite* lir);
-    void visitGuardShape(LGuardShape* guard);
-    void visitGuardObjectGroup(LGuardObjectGroup* guard);
-    void visitGuardObjectIdentity(LGuardObjectIdentity* guard);
-    void visitGuardReceiverPolymorphic(LGuardReceiverPolymorphic* lir);
-    void visitGuardUnboxedExpando(LGuardUnboxedExpando* lir);
-    void visitLoadUnboxedExpando(LLoadUnboxedExpando* lir);
-    void visitTypeBarrierV(LTypeBarrierV* lir);
-    void visitTypeBarrierO(LTypeBarrierO* lir);
+
     void emitPostWriteBarrier(const LAllocation* obj);
     void emitPostWriteBarrier(Register objreg);
     void emitPostWriteBarrierS(Address address, Register prev, Register next);
+
     template <class LPostBarrierType, MIRType nurseryType>
     void visitPostWriteBarrierCommon(LPostBarrierType* lir, OutOfLineCode* ool);
     template <class LPostBarrierType>
     void visitPostWriteBarrierCommonV(LPostBarrierType* lir, OutOfLineCode* ool);
-    void visitPostWriteBarrierO(LPostWriteBarrierO* lir);
-    void visitPostWriteElementBarrierO(LPostWriteElementBarrierO* lir);
-    void visitPostWriteBarrierV(LPostWriteBarrierV* lir);
-    void visitPostWriteElementBarrierV(LPostWriteElementBarrierV* lir);
-    void visitPostWriteBarrierS(LPostWriteBarrierS* lir);
-    void visitPostWriteElementBarrierS(LPostWriteElementBarrierS* lir);
-    void visitOutOfLineCallPostWriteBarrier(OutOfLineCallPostWriteBarrier* ool);
-    void visitOutOfLineCallPostWriteElementBarrier(OutOfLineCallPostWriteElementBarrier* ool);
-    void visitCallNative(LCallNative* call);
+
     void emitCallInvokeFunction(LInstruction* call, Register callereg,
                                 bool isConstructing, bool ignoresReturnValue,
                                 uint32_t argc, uint32_t unusedStack);
-    void visitCallGeneric(LCallGeneric* call);
     void emitCallInvokeFunctionShuffleNewTarget(LCallKnown *call,
                                                 Register calleeReg,
                                                 uint32_t numFormals,
                                                 uint32_t unusedStack);
-    void visitCallKnown(LCallKnown* call);
     template<typename T> void emitApplyGeneric(T* apply);
     template<typename T> void emitCallInvokeFunction(T* apply, Register extraStackSize);
     void emitAllocateSpaceForApply(Register argcreg, Register extraStackSpace, Label* end);
     void emitCopyValuesForApply(Register argvSrcBase, Register argvIndex, Register copyreg,
                                 size_t argvSrcOffset, size_t argvDstOffset);
     void emitPopArguments(Register extraStackSize);
     void emitPushArguments(LApplyArgsGeneric* apply, Register extraStackSpace);
-    void visitApplyArgsGeneric(LApplyArgsGeneric* apply);
     void emitPushArguments(LApplyArrayGeneric* apply, Register extraStackSpace);
-    void visitApplyArrayGeneric(LApplyArrayGeneric* apply);
-    void visitBail(LBail* lir);
-    void visitUnreachable(LUnreachable* unreachable);
-    void visitEncodeSnapshot(LEncodeSnapshot* lir);
-    void visitGetDynamicName(LGetDynamicName* lir);
-    void visitCallDirectEval(LCallDirectEval* lir);
-    void visitDoubleToInt32(LDoubleToInt32* lir);
-    void visitFloat32ToInt32(LFloat32ToInt32* lir);
+
     void visitNewArrayCallVM(LNewArray* lir);
-    void visitNewArray(LNewArray* lir);
-    void visitOutOfLineNewArray(OutOfLineNewArray* ool);
-    void visitNewArrayCopyOnWrite(LNewArrayCopyOnWrite* lir);
-    void visitNewArrayDynamicLength(LNewArrayDynamicLength* lir);
-    void visitNewIterator(LNewIterator* lir);
-    void visitNewTypedArray(LNewTypedArray* lir);
-    void visitNewTypedArrayDynamicLength(LNewTypedArrayDynamicLength* lir);
     void visitNewObjectVMCall(LNewObject* lir);
-    void visitNewObject(LNewObject* lir);
-    void visitOutOfLineNewObject(OutOfLineNewObject* ool);
-    void visitNewTypedObject(LNewTypedObject* lir);
-    void visitSimdBox(LSimdBox* lir);
-    void visitSimdUnbox(LSimdUnbox* lir);
-    void visitNewNamedLambdaObject(LNewNamedLambdaObject* lir);
-    void visitNewCallObject(LNewCallObject* lir);
-    void visitNewSingletonCallObject(LNewSingletonCallObject* lir);
-    void visitNewStringObject(LNewStringObject* lir);
-    void visitNewDerivedTypedObject(LNewDerivedTypedObject* lir);
-    void visitInitElem(LInitElem* lir);
-    void visitInitElemGetterSetter(LInitElemGetterSetter* lir);
-    void visitMutateProto(LMutateProto* lir);
-    void visitInitPropGetterSetter(LInitPropGetterSetter* lir);
-    void visitCreateThis(LCreateThis* lir);
-    void visitCreateThisWithProto(LCreateThisWithProto* lir);
-    void visitCreateThisWithTemplate(LCreateThisWithTemplate* lir);
-    void visitCreateArgumentsObject(LCreateArgumentsObject* lir);
-    void visitGetArgumentsObjectArg(LGetArgumentsObjectArg* lir);
-    void visitSetArgumentsObjectArg(LSetArgumentsObjectArg* lir);
-    void visitReturnFromCtor(LReturnFromCtor* lir);
-    void visitComputeThis(LComputeThis* lir);
-    void visitImplicitThis(LImplicitThis* lir);
-    void visitArrayLength(LArrayLength* lir);
-    void visitSetArrayLength(LSetArrayLength* lir);
-    void visitGetNextEntryForIterator(LGetNextEntryForIterator* lir);
-    void visitTypedArrayLength(LTypedArrayLength* lir);
-    void visitTypedArrayElements(LTypedArrayElements* lir);
-    void visitSetDisjointTypedElements(LSetDisjointTypedElements* lir);
-    void visitTypedObjectElements(LTypedObjectElements* lir);
-    void visitSetTypedObjectOffset(LSetTypedObjectOffset* lir);
-    void visitTypedObjectDescr(LTypedObjectDescr* ins);
-    void visitStringLength(LStringLength* lir);
-    void visitSubstr(LSubstr* lir);
-    void visitInitializedLength(LInitializedLength* lir);
-    void visitSetInitializedLength(LSetInitializedLength* lir);
-    void visitNotO(LNotO* ins);
-    void visitNotV(LNotV* ins);
-    void visitBoundsCheck(LBoundsCheck* lir);
-    void visitBoundsCheckRange(LBoundsCheckRange* lir);
-    void visitBoundsCheckLower(LBoundsCheckLower* lir);
-    void visitSpectreMaskIndex(LSpectreMaskIndex* lir);
-    void visitLoadFixedSlotV(LLoadFixedSlotV* ins);
-    void visitLoadFixedSlotAndUnbox(LLoadFixedSlotAndUnbox* lir);
-    void visitLoadFixedSlotT(LLoadFixedSlotT* ins);
-    void visitStoreFixedSlotV(LStoreFixedSlotV* ins);
-    void visitStoreFixedSlotT(LStoreFixedSlotT* ins);
+
     void emitGetPropertyPolymorphic(LInstruction* lir, Register obj, Register expandoScratch,
                                     Register scratch, const TypedOrValueRegister& output);
-    void visitGetPropertyPolymorphicV(LGetPropertyPolymorphicV* ins);
-    void visitGetPropertyPolymorphicT(LGetPropertyPolymorphicT* ins);
     void emitSetPropertyPolymorphic(LInstruction* lir, Register obj, Register expandoScratch,
                                     Register scratch, const ConstantOrRegister& value);
-    void visitSetPropertyPolymorphicV(LSetPropertyPolymorphicV* ins);
-    void visitSetPropertyPolymorphicT(LSetPropertyPolymorphicT* ins);
-    void visitAbsI(LAbsI* lir);
-    void visitAtan2D(LAtan2D* lir);
-    void visitHypot(LHypot* lir);
-    void visitPowI(LPowI* lir);
-    void visitPowD(LPowD* lir);
-    void visitPowV(LPowV* lir);
-    void visitMathFunctionD(LMathFunctionD* ins);
-    void visitMathFunctionF(LMathFunctionF* ins);
-    void visitModD(LModD* ins);
-    void visitMinMaxI(LMinMaxI* lir);
-    void visitBinaryV(LBinaryV* lir);
     void emitCompareS(LInstruction* lir, JSOp op, Register left, Register right, Register output);
-    void visitCompareS(LCompareS* lir);
-    void visitCompareStrictS(LCompareStrictS* lir);
-    void visitCompareVM(LCompareVM* lir);
-    void visitIsNullOrLikeUndefinedV(LIsNullOrLikeUndefinedV* lir);
-    void visitIsNullOrLikeUndefinedT(LIsNullOrLikeUndefinedT* lir);
-    void visitIsNullOrLikeUndefinedAndBranchV(LIsNullOrLikeUndefinedAndBranchV* lir);
-    void visitIsNullOrLikeUndefinedAndBranchT(LIsNullOrLikeUndefinedAndBranchT* lir);
     void emitSameValue(FloatRegister left, FloatRegister right, FloatRegister temp,
                        Register output);
-    void visitSameValueD(LSameValueD* lir);
-    void visitSameValueV(LSameValueV* lir);
-    void visitSameValueVM(LSameValueVM* lir);
+
     void emitConcat(LInstruction* lir, Register lhs, Register rhs, Register output);
-    void visitConcat(LConcat* lir);
-    void visitCharCodeAt(LCharCodeAt* lir);
-    void visitFromCharCode(LFromCharCode* lir);
-    void visitFromCodePoint(LFromCodePoint* lir);
-    void visitStringConvertCase(LStringConvertCase* lir);
-    void visitSinCos(LSinCos *lir);
-    void visitStringSplit(LStringSplit* lir);
-    void visitFunctionEnvironment(LFunctionEnvironment* lir);
-    void visitHomeObject(LHomeObject* lir);
-    void visitHomeObjectSuperBase(LHomeObjectSuperBase* lir);
-    void visitNewLexicalEnvironmentObject(LNewLexicalEnvironmentObject* lir);
-    void visitCopyLexicalEnvironmentObject(LCopyLexicalEnvironmentObject* lir);
-    void visitCallGetProperty(LCallGetProperty* lir);
-    void visitCallGetElement(LCallGetElement* lir);
-    void visitCallSetElement(LCallSetElement* lir);
-    void visitCallInitElementArray(LCallInitElementArray* lir);
-    void visitThrow(LThrow* lir);
-    void visitTypeOfV(LTypeOfV* lir);
-    void visitOutOfLineTypeOfV(OutOfLineTypeOfV* ool);
-    void visitToAsync(LToAsync* lir);
-    void visitToAsyncGen(LToAsyncGen* lir);
-    void visitToAsyncIter(LToAsyncIter* lir);
-    void visitToIdV(LToIdV* lir);
     template<typename T> void emitLoadElementT(LLoadElementT* lir, const T& source);
-    void visitLoadElementT(LLoadElementT* lir);
-    void visitLoadElementV(LLoadElementV* load);
-    void visitLoadElementHole(LLoadElementHole* lir);
-    void visitLoadUnboxedPointerV(LLoadUnboxedPointerV* lir);
-    void visitLoadUnboxedPointerT(LLoadUnboxedPointerT* lir);
-    void visitUnboxObjectOrNull(LUnboxObjectOrNull* lir);
-    template <SwitchTableType tableType>
-    void visitOutOfLineSwitch(OutOfLineSwitch<tableType>* ool);
-    void visitLoadElementFromStateV(LLoadElementFromStateV* lir);
-    void visitStoreElementT(LStoreElementT* lir);
-    void visitStoreElementV(LStoreElementV* lir);
+
     template <typename T> void emitStoreElementHoleT(T* lir);
     template <typename T> void emitStoreElementHoleV(T* lir);
-    void visitStoreElementHoleT(LStoreElementHoleT* lir);
-    void visitStoreElementHoleV(LStoreElementHoleV* lir);
-    void visitFallibleStoreElementV(LFallibleStoreElementV* lir);
-    void visitFallibleStoreElementT(LFallibleStoreElementT* lir);
-    void visitStoreUnboxedPointer(LStoreUnboxedPointer* lir);
-    void visitConvertUnboxedObjectToNative(LConvertUnboxedObjectToNative* lir);
+
     void emitArrayPopShift(LInstruction* lir, const MArrayPopShift* mir, Register obj,
                            Register elementsTemp, Register lengthTemp, TypedOrValueRegister out);
-    void visitArrayPopShiftV(LArrayPopShiftV* lir);
-    void visitArrayPopShiftT(LArrayPopShiftT* lir);
     void emitArrayPush(LInstruction* lir, Register obj,
                        const ConstantOrRegister& value, Register elementsTemp, Register length);
-    void visitArrayPushV(LArrayPushV* lir);
-    void visitArrayPushT(LArrayPushT* lir);
-    void visitArraySlice(LArraySlice* lir);
-    void visitArrayJoin(LArrayJoin* lir);
-    void visitLoadUnboxedScalar(LLoadUnboxedScalar* lir);
-    void visitLoadTypedArrayElementHole(LLoadTypedArrayElementHole* lir);
-    void visitStoreUnboxedScalar(LStoreUnboxedScalar* lir);
-    void visitStoreTypedArrayElementHole(LStoreTypedArrayElementHole* lir);
-    void visitAtomicIsLockFree(LAtomicIsLockFree* lir);
-    void visitGuardSharedTypedArray(LGuardSharedTypedArray* lir);
-    void visitClampIToUint8(LClampIToUint8* lir);
-    void visitClampDToUint8(LClampDToUint8* lir);
-    void visitClampVToUint8(LClampVToUint8* lir);
-    void visitGetIteratorCache(LGetIteratorCache* lir);
-    void visitIteratorMore(LIteratorMore* lir);
-    void visitIsNoIterAndBranch(LIsNoIterAndBranch* lir);
-    void visitIteratorEnd(LIteratorEnd* lir);
-    void visitArgumentsLength(LArgumentsLength* lir);
-    void visitGetFrameArgument(LGetFrameArgument* lir);
-    void visitSetFrameArgumentT(LSetFrameArgumentT* lir);
-    void visitSetFrameArgumentC(LSetFrameArgumentC* lir);
-    void visitSetFrameArgumentV(LSetFrameArgumentV* lir);
-    void visitRunOncePrologue(LRunOncePrologue* lir);
+
     void emitRest(LInstruction* lir, Register array, Register numActuals,
                   Register temp0, Register temp1, unsigned numFormals,
                   JSObject* templateObject, bool saveAndRestore, Register resultreg);
-    void visitRest(LRest* lir);
-    void visitCallSetProperty(LCallSetProperty* ins);
-    void visitCallDeleteProperty(LCallDeleteProperty* lir);
-    void visitCallDeleteElement(LCallDeleteElement* lir);
-    void visitBitNotV(LBitNotV* lir);
-    void visitBitOpV(LBitOpV* lir);
     void emitInstanceOf(LInstruction* ins, JSObject* prototypeObject);
-    void visitInCache(LInCache* ins);
-    void visitInArray(LInArray* ins);
-    void visitInstanceOfO(LInstanceOfO* ins);
-    void visitInstanceOfV(LInstanceOfV* ins);
-    void visitInstanceOfCache(LInstanceOfCache* ins);
-    void visitGetDOMProperty(LGetDOMProperty* lir);
-    void visitGetDOMMemberV(LGetDOMMemberV* lir);
-    void visitGetDOMMemberT(LGetDOMMemberT* lir);
-    void visitSetDOMProperty(LSetDOMProperty* lir);
-    void visitCallDOMNative(LCallDOMNative* lir);
-    void visitCallGetIntrinsicValue(LCallGetIntrinsicValue* lir);
-    void visitCallBindVar(LCallBindVar* lir);
+
     enum CallableOrConstructor {
         Callable,
         Constructor
     };
     template <CallableOrConstructor mode>
     void emitIsCallableOrConstructor(Register object, Register output, Label* failure);
-    void visitIsCallableO(LIsCallableO* lir);
-    void visitIsCallableV(LIsCallableV* lir);
-    void visitOutOfLineIsCallable(OutOfLineIsCallable* ool);
-    void visitIsConstructor(LIsConstructor* lir);
-    void visitOutOfLineIsConstructor(OutOfLineIsConstructor* ool);
-    void visitIsArrayO(LIsArrayO* lir);
-    void visitIsArrayV(LIsArrayV* lir);
-    void visitIsTypedArray(LIsTypedArray* lir);
-    void visitIsObject(LIsObject* lir);
-    void visitIsObjectAndBranch(LIsObjectAndBranch* lir);
-    void visitHasClass(LHasClass* lir);
-    void visitObjectClassToString(LObjectClassToString* lir);
-    void visitWasmParameter(LWasmParameter* lir);
-    void visitWasmParameterI64(LWasmParameterI64* lir);
-    void visitWasmReturn(LWasmReturn* ret);
-    void visitWasmReturnI64(LWasmReturnI64* ret);
-    void visitWasmReturnVoid(LWasmReturnVoid* ret);
-    void visitLexicalCheck(LLexicalCheck* ins);
-    void visitThrowRuntimeLexicalError(LThrowRuntimeLexicalError* ins);
-    void visitGlobalNameConflictsCheck(LGlobalNameConflictsCheck* ins);
-    void visitDebugger(LDebugger* ins);
-    void visitNewTarget(LNewTarget* ins);
-    void visitArrowNewTarget(LArrowNewTarget* ins);
-    void visitCheckReturn(LCheckReturn* ins);
-    void visitCheckIsObj(LCheckIsObj* ins);
-    void visitCheckIsCallable(LCheckIsCallable* ins);
-    void visitCheckObjCoercible(LCheckObjCoercible* ins);
-    void visitDebugCheckSelfHosted(LDebugCheckSelfHosted* ins);
-    void visitNaNToZero(LNaNToZero* ins);
-    void visitOutOfLineNaNToZero(OutOfLineNaNToZero* ool);
-    void visitFinishBoundFunctionInit(LFinishBoundFunctionInit* lir);
-    void visitIsPackedArray(LIsPackedArray* lir);
-    void visitGetPrototypeOf(LGetPrototypeOf* lir);
-
-    void visitCheckOverRecursed(LCheckOverRecursed* lir);
-    void visitCheckOverRecursedFailure(CheckOverRecursedFailure* ool);
-
-    void visitUnboxFloatingPoint(LUnboxFloatingPoint* lir);
-    void visitOutOfLineUnboxFloatingPoint(OutOfLineUnboxFloatingPoint* ool);
-    void visitOutOfLineStoreElementHole(OutOfLineStoreElementHole* ool);
 
     void loadJSScriptForBlock(MBasicBlock* block, Register reg);
     void loadOutermostJSScript(Register reg);
 
-    void visitOutOfLineICFallback(OutOfLineICFallback* ool);
-
-    void visitGetPropertyCacheV(LGetPropertyCacheV* ins);
-    void visitGetPropertyCacheT(LGetPropertyCacheT* ins);
-    void visitGetPropSuperCacheV(LGetPropSuperCacheV* ins);
-    void visitBindNameCache(LBindNameCache* ins);
-    void visitCallSetProperty(LInstruction* ins);
-    void visitSetPropertyCache(LSetPropertyCache* ins);
-    void visitGetNameCache(LGetNameCache* ins);
-    void visitHasOwnCache(LHasOwnCache* ins);
-
-    void visitAssertRangeI(LAssertRangeI* ins);
-    void visitAssertRangeD(LAssertRangeD* ins);
-    void visitAssertRangeF(LAssertRangeF* ins);
-    void visitAssertRangeV(LAssertRangeV* ins);
-
-    void visitAssertResultV(LAssertResultV* ins);
-    void visitAssertResultT(LAssertResultT* ins);
-
 #ifdef DEBUG
     void emitAssertResultV(const ValueOperand output, const TemporaryTypeSet* typeset);
     void emitAssertObjectOrStringResult(Register input, MIRType type, const TemporaryTypeSet* typeset);
 #endif
 
-    void visitInterruptCheck(LInterruptCheck* lir);
-    void visitOutOfLineInterruptCheckImplicit(OutOfLineInterruptCheckImplicit* ins);
-    void visitWasmInterruptCheck(LWasmInterruptCheck* lir);
-    void visitWasmTrap(LWasmTrap* lir);
-    void visitWasmLoadTls(LWasmLoadTls* ins);
-    void visitWasmBoundsCheck(LWasmBoundsCheck* ins);
-    void visitWasmAlignmentCheck(LWasmAlignmentCheck* ins);
-    void visitRecompileCheck(LRecompileCheck* ins);
-    void visitRotate(LRotate* ins);
-
-    void visitRandom(LRandom* ins);
-    void visitSignExtendInt32(LSignExtendInt32* ins);
-
 #ifdef DEBUG
     void emitDebugForceBailing(LInstruction* lir);
 #endif
 
     IonScriptCounts* extractScriptCounts() {
         IonScriptCounts* counts = scriptCounts_;
         scriptCounts_ = nullptr;  // prevent delete in dtor
         return counts;
     }
 
-  private:
     void addGetPropertyCache(LInstruction* ins, LiveRegisterSet liveRegs,
                              TypedOrValueRegister value, const ConstantOrRegister& id,
                              TypedOrValueRegister output, Register maybeTemp,
                              GetPropertyResultFlags flags);
     void addSetPropertyCache(LInstruction* ins, LiveRegisterSet liveRegs, Register objReg,
                              Register temp, FloatRegister tempDouble,
                              FloatRegister tempF32, const ConstantOrRegister& id,
                              const ConstantOrRegister& value,
@@ -507,16 +216,18 @@ class CodeGenerator final : public CodeG
                                    Register temp2);
 
     template <class IteratorObject, class OrderedHashTable>
     void emitGetNextEntryForIterator(LGetNextEntryForIterator* lir);
 
     template <class OrderedHashTable>
     void emitLoadIteratorValues(Register result, Register temp, Register front);
 
+    void emitWasmCallBase(MWasmCall* mir, bool needsBoundsCheck);
+
     IonScriptCounts* maybeCreateScriptCounts();
 
     // This function behaves like testValueTruthy with the exception that it can
     // choose to let control flow fall through when the object is truthy, as
     // an optimization. Use testValueTruthy when it's required to branch to one
     // of the two labels.
     void testValueTruthyKernel(const ValueOperand& value,
                                const LDefinition* scratch1, const LDefinition* scratch2,
@@ -620,14 +331,18 @@ class CodeGenerator final : public CodeG
     // Instead of saving the pointers, we just save the index of the Read
     // Barriered objects in a bit mask.
     uint32_t simdTemplatesToReadBarrier_;
 
     // Bit mask of JitCompartment stubs that are to be read-barriered.
     uint32_t compartmentStubsToReadBarrier_;
 
     void addSimdTemplateToReadBarrier(SimdType simdType);
+
+#define LIR_OP(op) void visit##op(L##op* ins);
+    LIR_OPCODE_LIST(LIR_OP)
+#undef LIR_OP
 };
 
 } // namespace jit
 } // namespace js
 
 #endif /* jit_CodeGenerator_h */
--- a/js/src/jit/Ion.cpp
+++ b/js/src/jit/Ion.cpp
@@ -1142,25 +1142,25 @@ IonScript::copyOsiIndices(const OsiIndex
 
 void
 IonScript::copyRuntimeData(const uint8_t* data)
 {
     memcpy(runtimeData(), data, runtimeSize());
 }
 
 void
-IonScript::copyICEntries(const uint32_t* icEntries, MacroAssembler& masm)
+IonScript::copyICEntries(const uint32_t* icEntries)
 {
     memcpy(icIndex(), icEntries, numICs() * sizeof(uint32_t));
 
     // Jumps in the caches reflect the offset of those jumps in the compiled
     // code, not the absolute positions of the jumps. Update according to the
     // final code address now.
     for (size_t i = 0; i < numICs(); i++)
-        getICFromIndex(i).updateBaseAddress(method_, masm);
+        getICFromIndex(i).updateBaseAddress(method_);
 }
 
 const SafepointIndex*
 IonScript::getSafepointIndex(uint32_t disp) const
 {
     MOZ_ASSERT(safepointIndexEntries_ > 0);
 
     const SafepointIndex* table = safepointIndices();
--- a/js/src/jit/IonCode.h
+++ b/js/src/jit/IonCode.h
@@ -520,17 +520,17 @@ struct IonScript
     void unlinkFromRuntime(FreeOp* fop);
     void copySnapshots(const SnapshotWriter* writer);
     void copyRecovers(const RecoverWriter* writer);
     void copyBailoutTable(const SnapshotOffset* table);
     void copyConstants(const Value* vp);
     void copySafepointIndices(const SafepointIndex* firstSafepointIndex);
     void copyOsiIndices(const OsiIndex* firstOsiIndex);
     void copyRuntimeData(const uint8_t* data);
-    void copyICEntries(const uint32_t* caches, MacroAssembler& masm);
+    void copyICEntries(const uint32_t* caches);
     void copySafepoints(const SafepointWriter* writer);
     void copyPatchableBackedges(JSContext* cx, JitCode* code,
                                 PatchableBackedgeInfo* backedges,
                                 MacroAssembler& masm);
 
     bool invalidated() const {
         return invalidationCount_ != 0;
     }
--- a/js/src/jit/IonIC.cpp
+++ b/js/src/jit/IonIC.cpp
@@ -11,20 +11,20 @@
 
 #include "jit/MacroAssembler-inl.h"
 #include "vm/Interpreter-inl.h"
 
 using namespace js;
 using namespace js::jit;
 
 void
-IonIC::updateBaseAddress(JitCode* code, MacroAssembler& masm)
+IonIC::updateBaseAddress(JitCode* code)
 {
-    fallbackLabel_.repoint(code, &masm);
-    rejoinLabel_.repoint(code, &masm);
+    fallbackLabel_.repoint(code);
+    rejoinLabel_.repoint(code);
 
     codeRaw_ = fallbackLabel_.raw();
 }
 
 Register
 IonIC::scratchRegisterForEntryJump()
 {
     switch (kind_) {
--- a/js/src/jit/IonIC.h
+++ b/js/src/jit/IonIC.h
@@ -168,17 +168,17 @@ class IonIC
         MOZ_ASSERT(kind_ == CacheKind::In);
         return (IonInIC*)this;
     }
     IonInstanceOfIC* asInstanceOfIC() {
         MOZ_ASSERT(kind_ == CacheKind::InstanceOf);
         return (IonInstanceOfIC*)this;
     }
 
-    void updateBaseAddress(JitCode* code, MacroAssembler& masm);
+    void updateBaseAddress(JitCode* code);
 
     // Returns the Register to use as scratch when entering IC stubs. This
     // should either be an output register or a temp.
     Register scratchRegisterForEntryJump();
 
     void trace(JSTracer* trc);
 
     void attachCacheIRStub(JSContext* cx, const CacheIRWriter& writer, CacheKind kind,
--- a/js/src/jit/LIR.h
+++ b/js/src/jit/LIR.h
@@ -939,20 +939,16 @@ class LElementVisitor
         }
     }
 
     LElementVisitor()
       : ins_(nullptr),
         lastPC_(nullptr),
         lastNotInlinedPC_(nullptr)
     {}
-
-#define VISIT_INS(op) void visit##op(L##op*) { MOZ_CRASH("NYI: " #op); }
-    LIR_OPCODE_LIST(VISIT_INS)
-#undef VISIT_INS
 };
 
 typedef InlineList<LInstruction>::iterator LInstructionIterator;
 typedef InlineList<LInstruction>::reverse_iterator LInstructionReverseIterator;
 
 class MPhi;
 
 // Phi is a pseudo-instruction that emits no code, and is an annotation for the
--- a/js/src/jit/arm/CodeGenerator-arm.cpp
+++ b/js/src/jit/arm/CodeGenerator-arm.cpp
@@ -60,17 +60,17 @@ CodeGeneratorARM::emitBranch(Assembler::
 
 void
 OutOfLineBailout::accept(CodeGeneratorARM* codegen)
 {
     codegen->visitOutOfLineBailout(this);
 }
 
 void
-CodeGeneratorARM::visitTestIAndBranch(LTestIAndBranch* test)
+CodeGenerator::visitTestIAndBranch(LTestIAndBranch* test)
 {
     const LAllocation* opd = test->getOperand(0);
     MBasicBlock* ifTrue = test->ifTrue();
     MBasicBlock* ifFalse = test->ifFalse();
 
     // Test the operand
     masm.as_cmp(ToRegister(opd), Imm8(0));
 
@@ -80,17 +80,17 @@ CodeGeneratorARM::visitTestIAndBranch(LT
         jumpToBlock(ifFalse, Assembler::Zero);
     } else {
         jumpToBlock(ifFalse, Assembler::Zero);
         jumpToBlock(ifTrue);
     }
 }
 
 void
-CodeGeneratorARM::visitCompare(LCompare* comp)
+CodeGenerator::visitCompare(LCompare* comp)
 {
     Assembler::Condition cond = JSOpToCondition(comp->mir()->compareType(), comp->jsop());
     const LAllocation* left = comp->getOperand(0);
     const LAllocation* right = comp->getOperand(1);
     const LDefinition* def = comp->getDef(0);
 
     ScratchRegisterScope scratch(masm);
 
@@ -102,17 +102,17 @@ CodeGeneratorARM::visitCompare(LCompare*
         SecondScratchRegisterScope scratch2(masm);
         masm.ma_cmp(ToRegister(left), Operand(ToAddress(right)), scratch, scratch2);
     }
     masm.ma_mov(Imm32(0), ToRegister(def));
     masm.ma_mov(Imm32(1), ToRegister(def), cond);
 }
 
 void
-CodeGeneratorARM::visitCompareAndBranch(LCompareAndBranch* comp)
+CodeGenerator::visitCompareAndBranch(LCompareAndBranch* comp)
 {
     Assembler::Condition cond = JSOpToCondition(comp->cmpMir()->compareType(), comp->jsop());
     const LAllocation* left = comp->left();
     const LAllocation* right = comp->right();
 
     ScratchRegisterScope scratch(masm);
 
     if (right->isConstant()) {
@@ -219,77 +219,77 @@ CodeGeneratorARM::visitOutOfLineBailout(
     ScratchRegisterScope scratch(masm);
     masm.ma_mov(Imm32(ool->snapshot()->snapshotOffset()), scratch);
     masm.ma_push(scratch); // BailoutStack::padding_
     masm.ma_push(scratch); // BailoutStack::snapshotOffset_
     masm.ma_b(&deoptLabel_);
 }
 
 void
-CodeGeneratorARM::visitMinMaxD(LMinMaxD* ins)
+CodeGenerator::visitMinMaxD(LMinMaxD* ins)
 {
     FloatRegister first = ToFloatRegister(ins->first());
     FloatRegister second = ToFloatRegister(ins->second());
 
     MOZ_ASSERT(first == ToFloatRegister(ins->output()));
 
     if (ins->mir()->isMax())
         masm.maxDouble(second, first, true);
     else
         masm.minDouble(second, first, true);
 }
 
 void
-CodeGeneratorARM::visitMinMaxF(LMinMaxF* ins)
+CodeGenerator::visitMinMaxF(LMinMaxF* ins)
 {
     FloatRegister first = ToFloatRegister(ins->first());
     FloatRegister second = ToFloatRegister(ins->second());
 
     MOZ_ASSERT(first == ToFloatRegister(ins->output()));
 
     if (ins->mir()->isMax())
         masm.maxFloat32(second, first, true);
     else
         masm.minFloat32(second, first, true);
 }
 
 void
-CodeGeneratorARM::visitAbsD(LAbsD* ins)
+CodeGenerator::visitAbsD(LAbsD* ins)
 {
     FloatRegister input = ToFloatRegister(ins->input());
     MOZ_ASSERT(input == ToFloatRegister(ins->output()));
     masm.ma_vabs(input, input);
 }
 
 void
-CodeGeneratorARM::visitAbsF(LAbsF* ins)
+CodeGenerator::visitAbsF(LAbsF* ins)
 {
     FloatRegister input = ToFloatRegister(ins->input());
     MOZ_ASSERT(input == ToFloatRegister(ins->output()));
     masm.ma_vabs_f32(input, input);
 }
 
 void
-CodeGeneratorARM::visitSqrtD(LSqrtD* ins)
+CodeGenerator::visitSqrtD(LSqrtD* ins)
 {
     FloatRegister input = ToFloatRegister(ins->input());
     FloatRegister output = ToFloatRegister(ins->output());
     masm.ma_vsqrt(input, output);
 }
 
 void
-CodeGeneratorARM::visitSqrtF(LSqrtF* ins)
+CodeGenerator::visitSqrtF(LSqrtF* ins)
 {
     FloatRegister input = ToFloatRegister(ins->input());
     FloatRegister output = ToFloatRegister(ins->output());
     masm.ma_vsqrt_f32(input, output);
 }
 
 void
-CodeGeneratorARM::visitAddI(LAddI* ins)
+CodeGenerator::visitAddI(LAddI* ins)
 {
     const LAllocation* lhs = ins->getOperand(0);
     const LAllocation* rhs = ins->getOperand(1);
     const LDefinition* dest = ins->getDef(0);
 
     ScratchRegisterScope scratch(masm);
 
     if (rhs->isConstant())
@@ -299,33 +299,33 @@ CodeGeneratorARM::visitAddI(LAddI* ins)
     else
         masm.ma_add(ToRegister(lhs), Operand(ToAddress(rhs)), ToRegister(dest), SetCC);
 
     if (ins->snapshot())
         bailoutIf(Assembler::Overflow, ins->snapshot());
 }
 
 void
-CodeGeneratorARM::visitAddI64(LAddI64* lir)
+CodeGenerator::visitAddI64(LAddI64* lir)
 {
     const LInt64Allocation lhs = lir->getInt64Operand(LAddI64::Lhs);
     const LInt64Allocation rhs = lir->getInt64Operand(LAddI64::Rhs);
 
     MOZ_ASSERT(ToOutRegister64(lir) == ToRegister64(lhs));
 
     if (IsConstant(rhs)) {
         masm.add64(Imm64(ToInt64(rhs)), ToRegister64(lhs));
         return;
     }
 
     masm.add64(ToOperandOrRegister64(rhs), ToRegister64(lhs));
 }
 
 void
-CodeGeneratorARM::visitSubI(LSubI* ins)
+CodeGenerator::visitSubI(LSubI* ins)
 {
     const LAllocation* lhs = ins->getOperand(0);
     const LAllocation* rhs = ins->getOperand(1);
     const LDefinition* dest = ins->getDef(0);
 
     ScratchRegisterScope scratch(masm);
 
     if (rhs->isConstant())
@@ -335,33 +335,33 @@ CodeGeneratorARM::visitSubI(LSubI* ins)
     else
         masm.ma_sub(ToRegister(lhs), Operand(ToAddress(rhs)), ToRegister(dest), SetCC);
 
     if (ins->snapshot())
         bailoutIf(Assembler::Overflow, ins->snapshot());
 }
 
 void
-CodeGeneratorARM::visitSubI64(LSubI64* lir)
+CodeGenerator::visitSubI64(LSubI64* lir)
 {
     const LInt64Allocation lhs = lir->getInt64Operand(LSubI64::Lhs);
     const LInt64Allocation rhs = lir->getInt64Operand(LSubI64::Rhs);
 
     MOZ_ASSERT(ToOutRegister64(lir) == ToRegister64(lhs));
 
     if (IsConstant(rhs)) {
         masm.sub64(Imm64(ToInt64(rhs)), ToRegister64(lhs));
         return;
     }
 
     masm.sub64(ToOperandOrRegister64(rhs), ToRegister64(lhs));
 }
 
 void
-CodeGeneratorARM::visitMulI(LMulI* ins)
+CodeGenerator::visitMulI(LMulI* ins)
 {
     const LAllocation* lhs = ins->getOperand(0);
     const LAllocation* rhs = ins->getOperand(1);
     const LDefinition* dest = ins->getDef(0);
     MMul* mul = ins->mir();
     MOZ_ASSERT_IF(mul->mode() == MMul::Integer, !mul->canBeNegativeZero() && !mul->canOverflow());
 
     if (rhs->isConstant()) {
@@ -470,17 +470,17 @@ CodeGeneratorARM::visitMulI(LMulI* ins)
             bailoutIf(Assembler::Signed, ins->snapshot());
 
             masm.bind(&done);
         }
     }
 }
 
 void
-CodeGeneratorARM::visitMulI64(LMulI64* lir)
+CodeGenerator::visitMulI64(LMulI64* lir)
 {
     const LInt64Allocation lhs = lir->getInt64Operand(LMulI64::Lhs);
     const LInt64Allocation rhs = lir->getInt64Operand(LMulI64::Rhs);
 
     MOZ_ASSERT(ToRegister64(lhs) == ToOutRegister64(lir));
 
     if (IsConstant(rhs)) {
         int64_t constant = ToInt64(rhs);
@@ -580,17 +580,17 @@ CodeGeneratorARM::divICommon(MDiv* mir, 
         masm.as_cmp(rhs, Imm8(0));
         MOZ_ASSERT(mir->fallible());
         bailoutIf(Assembler::LessThan, snapshot);
         masm.bind(&nonzero);
     }
 }
 
 void
-CodeGeneratorARM::visitDivI(LDivI* ins)
+CodeGenerator::visitDivI(LDivI* ins)
 {
     Register lhs = ToRegister(ins->lhs());
     Register rhs = ToRegister(ins->rhs());
     Register temp = ToRegister(ins->getTemp(0));
     Register output = ToRegister(ins->output());
     MDiv* mir = ins->mir();
 
     Label done;
@@ -613,17 +613,17 @@ CodeGeneratorARM::visitDivI(LDivI* ins)
 }
 
 extern "C" {
     extern MOZ_EXPORT int64_t __aeabi_idivmod(int,int);
     extern MOZ_EXPORT int64_t __aeabi_uidivmod(int,int);
 }
 
 void
-CodeGeneratorARM::visitSoftDivI(LSoftDivI* ins)
+CodeGenerator::visitSoftDivI(LSoftDivI* ins)
 {
     Register lhs = ToRegister(ins->lhs());
     Register rhs = ToRegister(ins->rhs());
     Register output = ToRegister(ins->output());
     MDiv* mir = ins->mir();
 
     Label done;
     divICommon(mir, lhs, rhs, output, ins->snapshot(), done);
@@ -647,17 +647,17 @@ CodeGeneratorARM::visitSoftDivI(LSoftDiv
         masm.as_cmp(r1, Imm8(0));
         bailoutIf(Assembler::NonZero, ins->snapshot());
     }
 
     masm.bind(&done);
 }
 
 void
-CodeGeneratorARM::visitDivPowTwoI(LDivPowTwoI* ins)
+CodeGenerator::visitDivPowTwoI(LDivPowTwoI* ins)
 {
     MDiv* mir = ins->mir();
     Register lhs = ToRegister(ins->numerator());
     Register output = ToRegister(ins->output());
     int32_t shift = ins->shift();
 
     if (shift == 0) {
         masm.ma_mov(lhs, output);
@@ -739,17 +739,17 @@ CodeGeneratorARM::modICommon(MMod* mir, 
         } else {
             MOZ_ASSERT(mir->fallible());
             bailoutIf(Assembler::Equal, snapshot);
         }
     }
 }
 
 void
-CodeGeneratorARM::visitModI(LModI* ins)
+CodeGenerator::visitModI(LModI* ins)
 {
     Register lhs = ToRegister(ins->lhs());
     Register rhs = ToRegister(ins->rhs());
     Register output = ToRegister(ins->output());
     Register callTemp = ToRegister(ins->callTemp());
     MMod* mir = ins->mir();
 
     // Save the lhs in case we end up with a 0 that should be a -0.0 because lhs < 0.
@@ -776,17 +776,17 @@ CodeGeneratorARM::visitModI(LModI* ins)
             bailoutIf(Assembler::Signed, ins->snapshot());
         }
     }
 
     masm.bind(&done);
 }
 
 void
-CodeGeneratorARM::visitSoftModI(LSoftModI* ins)
+CodeGenerator::visitSoftModI(LSoftModI* ins)
 {
     // Extract the registers from this instruction.
     Register lhs = ToRegister(ins->lhs());
     Register rhs = ToRegister(ins->rhs());
     Register output = ToRegister(ins->output());
     Register callTemp = ToRegister(ins->callTemp());
     MMod* mir = ins->mir();
     Label done;
@@ -850,17 +850,17 @@ CodeGeneratorARM::visitSoftModI(LSoftMod
             bailoutIf(Assembler::Signed, ins->snapshot());
         }
     }
 
     masm.bind(&done);
 }
 
 void
-CodeGeneratorARM::visitModPowTwoI(LModPowTwoI* ins)
+CodeGenerator::visitModPowTwoI(LModPowTwoI* ins)
 {
     Register in = ToRegister(ins->getOperand(0));
     Register out = ToRegister(ins->getDef(0));
     MMod* mir = ins->mir();
     Label fin;
     // bug 739870, jbramley has a different sequence that may help with speed
     // here.
 
@@ -879,17 +879,17 @@ CodeGeneratorARM::visitModPowTwoI(LModPo
         } else {
             // -0|0 == 0
         }
     }
     masm.bind(&fin);
 }
 
 void
-CodeGeneratorARM::visitModMaskI(LModMaskI* ins)
+CodeGenerator::visitModMaskI(LModMaskI* ins)
 {
     Register src = ToRegister(ins->getOperand(0));
     Register dest = ToRegister(ins->getDef(0));
     Register tmp1 = ToRegister(ins->getTemp(0));
     Register tmp2 = ToRegister(ins->getTemp(1));
     MMod* mir = ins->mir();
 
     ScratchRegisterScope scratch(masm);
@@ -903,29 +903,29 @@ CodeGeneratorARM::visitModMaskI(LModMask
             bailoutIf(Assembler::Zero, ins->snapshot());
         } else {
             // -0|0 == 0
         }
     }
 }
 
 void
-CodeGeneratorARM::visitBitNotI(LBitNotI* ins)
+CodeGenerator::visitBitNotI(LBitNotI* ins)
 {
     const LAllocation* input = ins->getOperand(0);
     const LDefinition* dest = ins->getDef(0);
     // This will not actually be true on arm. We can not an imm8m in order to
     // get a wider range of numbers
     MOZ_ASSERT(!input->isConstant());
 
     masm.ma_mvn(ToRegister(input), ToRegister(dest));
 }
 
 void
-CodeGeneratorARM::visitBitOpI(LBitOpI* ins)
+CodeGenerator::visitBitOpI(LBitOpI* ins)
 {
     const LAllocation* lhs = ins->getOperand(0);
     const LAllocation* rhs = ins->getOperand(1);
     const LDefinition* dest = ins->getDef(0);
 
     ScratchRegisterScope scratch(masm);
 
     // All of these bitops should be either imm32's, or integer registers.
@@ -949,17 +949,17 @@ CodeGeneratorARM::visitBitOpI(LBitOpI* i
             masm.ma_and(ToRegister(rhs), ToRegister(lhs), ToRegister(dest));
         break;
       default:
         MOZ_CRASH("unexpected binary opcode");
     }
 }
 
 void
-CodeGeneratorARM::visitShiftI(LShiftI* ins)
+CodeGenerator::visitShiftI(LShiftI* ins)
 {
     Register lhs = ToRegister(ins->lhs());
     const LAllocation* rhs = ins->rhs();
     Register dest = ToRegister(ins->output());
 
     if (rhs->isConstant()) {
         int32_t shift = ToInt32(rhs) & 0x1F;
         switch (ins->bitop()) {
@@ -1013,17 +1013,17 @@ CodeGeneratorARM::visitShiftI(LShiftI* i
             break;
           default:
             MOZ_CRASH("Unexpected shift op");
         }
     }
 }
 
 void
-CodeGeneratorARM::visitUrshD(LUrshD* ins)
+CodeGenerator::visitUrshD(LUrshD* ins)
 {
     Register lhs = ToRegister(ins->lhs());
     Register temp = ToRegister(ins->temp());
 
     const LAllocation* rhs = ins->rhs();
     FloatRegister out = ToFloatRegister(ins->output());
 
     if (rhs->isConstant()) {
@@ -1036,46 +1036,46 @@ CodeGeneratorARM::visitUrshD(LUrshD* ins
         masm.as_and(temp, ToRegister(rhs), Imm8(0x1F));
         masm.ma_lsr(temp, lhs, temp);
     }
 
     masm.convertUInt32ToDouble(temp, out);
 }
 
 void
-CodeGeneratorARM::visitClzI(LClzI* ins)
+CodeGenerator::visitClzI(LClzI* ins)
 {
     Register input = ToRegister(ins->input());
     Register output = ToRegister(ins->output());
 
     masm.clz32(input, output, /* knownNotZero = */ false);
 }
 
 void
-CodeGeneratorARM::visitCtzI(LCtzI* ins)
+CodeGenerator::visitCtzI(LCtzI* ins)
 {
     Register input = ToRegister(ins->input());
     Register output = ToRegister(ins->output());
 
     masm.ctz32(input, output, /* knownNotZero = */ false);
 }
 
 void
-CodeGeneratorARM::visitPopcntI(LPopcntI* ins)
+CodeGenerator::visitPopcntI(LPopcntI* ins)
 {
     Register input = ToRegister(ins->input());
     Register output = ToRegister(ins->output());
 
     Register tmp = ToRegister(ins->temp());
 
     masm.popcnt32(input, output, tmp);
 }
 
 void
-CodeGeneratorARM::visitPowHalfD(LPowHalfD* ins)
+CodeGenerator::visitPowHalfD(LPowHalfD* ins)
 {
     FloatRegister input = ToFloatRegister(ins->input());
     FloatRegister output = ToFloatRegister(ins->output());
     ScratchDoubleScope scratch(masm);
 
     Label done;
 
     // Masm.pow(-Infinity, 0.5) == Infinity.
@@ -1204,17 +1204,17 @@ CodeGeneratorARM::emitTableSwitchDispatc
         CodeLabel cl;
         masm.writeCodePointer(&cl);
         masm.propagateOOM(ool->addCodeLabel(cl));
     }
     addOutOfLineCode(ool, mir);
 }
 
 void
-CodeGeneratorARM::visitMathD(LMathD* math)
+CodeGenerator::visitMathD(LMathD* math)
 {
     FloatRegister src1 = ToFloatRegister(math->getOperand(0));
     FloatRegister src2 = ToFloatRegister(math->getOperand(1));
     FloatRegister output = ToFloatRegister(math->getDef(0));
 
     switch (math->jsop()) {
       case JSOP_ADD:
         masm.ma_vadd(src1, src2, output);
@@ -1229,17 +1229,17 @@ CodeGeneratorARM::visitMathD(LMathD* mat
         masm.ma_vdiv(src1, src2, output);
         break;
       default:
         MOZ_CRASH("unexpected opcode");
     }
 }
 
 void
-CodeGeneratorARM::visitMathF(LMathF* math)
+CodeGenerator::visitMathF(LMathF* math)
 {
     FloatRegister src1 = ToFloatRegister(math->getOperand(0));
     FloatRegister src2 = ToFloatRegister(math->getOperand(1));
     FloatRegister output = ToFloatRegister(math->getDef(0));
 
     switch (math->jsop()) {
       case JSOP_ADD:
         masm.ma_vadd_f32(src1, src2, output);
@@ -1254,70 +1254,70 @@ CodeGeneratorARM::visitMathF(LMathF* mat
         masm.ma_vdiv_f32(src1, src2, output);
         break;
       default:
         MOZ_CRASH("unexpected opcode");
     }
 }
 
 void
-CodeGeneratorARM::visitFloor(LFloor* lir)
+CodeGenerator::visitFloor(LFloor* lir)
 {
     FloatRegister input = ToFloatRegister(lir->input());
     Register output = ToRegister(lir->output());
     Label bail;
     masm.floor(input, output, &bail);
     bailoutFrom(&bail, lir->snapshot());
 }
 
 void
-CodeGeneratorARM::visitFloorF(LFloorF* lir)
+CodeGenerator::visitFloorF(LFloorF* lir)
 {
     FloatRegister input = ToFloatRegister(lir->input());
     Register output = ToRegister(lir->output());
     Label bail;
     masm.floorf(input, output, &bail);
     bailoutFrom(&bail, lir->snapshot());
 }
 
 void
-CodeGeneratorARM::visitCeil(LCeil* lir)
+CodeGenerator::visitCeil(LCeil* lir)
 {
     FloatRegister input = ToFloatRegister(lir->input());
     Register output = ToRegister(lir->output());
     Label bail;
     masm.ceil(input, output, &bail);
     bailoutFrom(&bail, lir->snapshot());
 }
 
 void
-CodeGeneratorARM::visitCeilF(LCeilF* lir)
+CodeGenerator::visitCeilF(LCeilF* lir)
 {
     FloatRegister input = ToFloatRegister(lir->input());
     Register output = ToRegister(lir->output());
     Label bail;
     masm.ceilf(input, output, &bail);
     bailoutFrom(&bail, lir->snapshot());
 }
 
 void
-CodeGeneratorARM::visitRound(LRound* lir)
+CodeGenerator::visitRound(LRound* lir)
 {
     FloatRegister input = ToFloatRegister(lir->input());
     Register output = ToRegister(lir->output());
     FloatRegister tmp = ToFloatRegister(lir->temp());
     Label bail;
     // Output is either correct, or clamped. All -0 cases have been translated
     // to a clamped case.
     masm.round(input, output, &bail, tmp);
     bailoutFrom(&bail, lir->snapshot());
 }
 
 void
-CodeGeneratorARM::visitRoundF(LRoundF* lir)
+CodeGenerator::visitRoundF(LRoundF* lir)
 {
     FloatRegister input = ToFloatRegister(lir->input());
     Register output = ToRegister(lir->output());
     FloatRegister tmp = ToFloatRegister(lir->temp());
     Label bail;
     // Output is either correct, or clamped. All -0 cases have been translated
     // to a clamped case.
     masm.roundf(input, output, &bail, tmp);
@@ -1333,23 +1333,23 @@ CodeGeneratorARM::emitRoundDouble(FloatR
     masm.ma_vcvt_F64_I32(src, scratch);
     masm.ma_vxfer(scratch, dest);
     masm.ma_cmp(dest, Imm32(0x7fffffff), scratchReg);
     masm.ma_cmp(dest, Imm32(0x80000000), scratchReg, Assembler::NotEqual);
     masm.ma_b(fail, Assembler::Equal);
 }
 
 void
-CodeGeneratorARM::visitTruncateDToInt32(LTruncateDToInt32* ins)
+CodeGenerator::visitTruncateDToInt32(LTruncateDToInt32* ins)
 {
     emitTruncateDouble(ToFloatRegister(ins->input()), ToRegister(ins->output()), ins->mir());
 }
 
 void
-CodeGeneratorARM::visitTruncateFToInt32(LTruncateFToInt32* ins)
+CodeGenerator::visitTruncateFToInt32(LTruncateFToInt32* ins)
 {
     emitTruncateFloat32(ToFloatRegister(ins->input()), ToRegister(ins->output()), ins->mir());
 }
 
 static const uint32_t FrameSizes[] = { 128, 256, 512, 1024 };
 
 FrameSizeClass
 FrameSizeClass::FromDepth(uint32_t frameDepth)
@@ -1389,47 +1389,47 @@ ValueOperand
 CodeGeneratorARM::ToTempValue(LInstruction* ins, size_t pos)
 {
     Register typeReg = ToRegister(ins->getTemp(pos + TYPE_INDEX));
     Register payloadReg = ToRegister(ins->getTemp(pos + PAYLOAD_INDEX));
     return ValueOperand(typeReg, payloadReg);
 }
 
 void
-CodeGeneratorARM::visitValue(LValue* value)
+CodeGenerator::visitValue(LValue* value)
 {
     const ValueOperand out = ToOutValue(value);
 
     masm.moveValue(value->value(), out);
 }
 
 void
-CodeGeneratorARM::visitBox(LBox* box)
+CodeGenerator::visitBox(LBox* box)
 {
     const LDefinition* type = box->getDef(TYPE_INDEX);
 
     MOZ_ASSERT(!box->getOperand(0)->isConstant());
 
     // On arm, the input operand and the output payload have the same virtual
     // register. All that needs to be written is the type tag for the type
     // definition.
     masm.ma_mov(Imm32(MIRTypeToTag(box->type())), ToRegister(type));
 }
 
 void
-CodeGeneratorARM::visitBoxFloatingPoint(LBoxFloatingPoint* box)
+CodeGenerator::visitBoxFloatingPoint(LBoxFloatingPoint* box)
 {
     const AnyRegister in = ToAnyRegister(box->getOperand(0));
     const ValueOperand out = ToOutValue(box);
 
     masm.moveValue(TypedOrValueRegister(box->type(), in), out);
 }
 
 void
-CodeGeneratorARM::visitUnbox(LUnbox* unbox)
+CodeGenerator::visitUnbox(LUnbox* unbox)
 {
     // Note that for unbox, the type and payload indexes are switched on the
     // inputs.
     MUnbox* mir = unbox->mir();
     Register type = ToRegister(unbox->type());
 
     mozilla::Maybe<ScratchRegisterScope> scratch;
     scratch.emplace(masm);
@@ -1446,115 +1446,115 @@ CodeGeneratorARM::visitUnbox(LUnbox* unb
         scratch.reset();
         masm.assumeUnreachable("Infallible unbox type mismatch");
         masm.bind(&ok);
 #endif
     }
 }
 
 void
-CodeGeneratorARM::visitDouble(LDouble* ins)
+CodeGenerator::visitDouble(LDouble* ins)
 {
     const LDefinition* out = ins->getDef(0);
     masm.loadConstantDouble(ins->getDouble(), ToFloatRegister(out));
 }
 
 void
-CodeGeneratorARM::visitFloat32(LFloat32* ins)
+CodeGenerator::visitFloat32(LFloat32* ins)
 {
     const LDefinition* out = ins->getDef(0);
     masm.loadConstantFloat32(ins->getFloat(), ToFloatRegister(out));
 }
 
 void
 CodeGeneratorARM::splitTagForTest(const ValueOperand& value, ScratchTagScope& tag)
 {
     MOZ_ASSERT(value.typeReg() == tag);
 }
 
 void
-CodeGeneratorARM::visitTestDAndBranch(LTestDAndBranch* test)
+CodeGenerator::visitTestDAndBranch(LTestDAndBranch* test)
 {
     const LAllocation* opd = test->input();
     masm.ma_vcmpz(ToFloatRegister(opd));
     masm.as_vmrs(pc);
 
     MBasicBlock* ifTrue = test->ifTrue();
     MBasicBlock* ifFalse = test->ifFalse();
     // If the compare set the 0 bit, then the result is definately false.
     jumpToBlock(ifFalse, Assembler::Zero);
     // It is also false if one of the operands is NAN, which is shown as
     // Overflow.
     jumpToBlock(ifFalse, Assembler::Overflow);
     jumpToBlock(ifTrue);
 }
 
 void
-CodeGeneratorARM::visitTestFAndBranch(LTestFAndBranch* test)
+CodeGenerator::visitTestFAndBranch(LTestFAndBranch* test)
 {
     const LAllocation* opd = test->input();
     masm.ma_vcmpz_f32(ToFloatRegister(opd));
     masm.as_vmrs(pc);
 
     MBasicBlock* ifTrue = test->ifTrue();
     MBasicBlock* ifFalse = test->ifFalse();
     // If the compare set the 0 bit, then the result is definately false.
     jumpToBlock(ifFalse, Assembler::Zero);
     // It is also false if one of the operands is NAN, which is shown as
     // Overflow.
     jumpToBlock(ifFalse, Assembler::Overflow);
     jumpToBlock(ifTrue);
 }
 
 void
-CodeGeneratorARM::visitCompareD(LCompareD* comp)
+CodeGenerator::visitCompareD(LCompareD* comp)
 {
     FloatRegister lhs = ToFloatRegister(comp->left());
     FloatRegister rhs = ToFloatRegister(comp->right());
 
     Assembler::DoubleCondition cond = JSOpToDoubleCondition(comp->mir()->jsop());
     masm.compareDouble(lhs, rhs);
     masm.emitSet(Assembler::ConditionFromDoubleCondition(cond), ToRegister(comp->output()));
 }
 
 void
-CodeGeneratorARM::visitCompareF(LCompareF* comp)
+CodeGenerator::visitCompareF(LCompareF* comp)
 {
     FloatRegister lhs = ToFloatRegister(comp->left());
     FloatRegister rhs = ToFloatRegister(comp->right());
 
     Assembler::DoubleCondition cond = JSOpToDoubleCondition(comp->mir()->jsop());
     masm.compareFloat(lhs, rhs);
     masm.emitSet(Assembler::ConditionFromDoubleCondition(cond), ToRegister(comp->output()));
 }
 
 void
-CodeGeneratorARM::visitCompareDAndBranch(LCompareDAndBranch* comp)
+CodeGenerator::visitCompareDAndBranch(LCompareDAndBranch* comp)
 {
     FloatRegister lhs = ToFloatRegister(comp->left());
     FloatRegister rhs = ToFloatRegister(comp->right());
 
     Assembler::DoubleCondition cond = JSOpToDoubleCondition(comp->cmpMir()->jsop());
     masm.compareDouble(lhs, rhs);
     emitBranch(Assembler::ConditionFromDoubleCondition(cond), comp->ifTrue(), comp->ifFalse());
 }
 
 void
-CodeGeneratorARM::visitCompareFAndBranch(LCompareFAndBranch* comp)
+CodeGenerator::visitCompareFAndBranch(LCompareFAndBranch* comp)
 {
     FloatRegister lhs = ToFloatRegister(comp->left());
     FloatRegister rhs = ToFloatRegister(comp->right());
 
     Assembler::DoubleCondition cond = JSOpToDoubleCondition(comp->cmpMir()->jsop());
     masm.compareFloat(lhs, rhs);
     emitBranch(Assembler::ConditionFromDoubleCondition(cond), comp->ifTrue(), comp->ifFalse());
 }
 
 void
-CodeGeneratorARM::visitCompareB(LCompareB* lir)
+CodeGenerator::visitCompareB(LCompareB* lir)
 {
     MCompare* mir = lir->mir();
 
     const ValueOperand lhs = ToValue(lir, LCompareB::Lhs);
     const LAllocation* rhs = lir->rhs();
     const Register output = ToRegister(lir->output());
 
     MOZ_ASSERT(mir->jsop() == JSOP_STRICTEQ || mir->jsop() == JSOP_STRICTNE);
@@ -1574,17 +1574,17 @@ CodeGeneratorARM::visitCompareB(LCompare
     {
         masm.move32(Imm32(mir->jsop() == JSOP_STRICTNE), output);
     }
 
     masm.bind(&done);
 }
 
 void
-CodeGeneratorARM::visitCompareBAndBranch(LCompareBAndBranch* lir)
+CodeGenerator::visitCompareBAndBranch(LCompareBAndBranch* lir)
 {
     MCompare* mir = lir->cmpMir();
     const ValueOperand lhs = ToValue(lir, LCompareBAndBranch::Lhs);
     const LAllocation* rhs = lir->rhs();
 
     MOZ_ASSERT(mir->jsop() == JSOP_STRICTEQ || mir->jsop() == JSOP_STRICTNE);
 
     Assembler::Condition cond = masm.testBoolean(Assembler::NotEqual, lhs);
@@ -1593,17 +1593,17 @@ CodeGeneratorARM::visitCompareBAndBranch
     if (rhs->isConstant())
         masm.cmp32(lhs.payloadReg(), Imm32(rhs->toConstant()->toBoolean()));
     else
         masm.cmp32(lhs.payloadReg(), ToRegister(rhs));
     emitBranch(JSOpToCondition(mir->compareType(), mir->jsop()), lir->ifTrue(), lir->ifFalse());
 }
 
 void
-CodeGeneratorARM::visitCompareBitwise(LCompareBitwise* lir)
+CodeGenerator::visitCompareBitwise(LCompareBitwise* lir)
 {
     MCompare* mir = lir->mir();
     Assembler::Condition cond = JSOpToCondition(mir->compareType(), mir->jsop());
     const ValueOperand lhs = ToValue(lir, LCompareBitwise::LhsInput);
     const ValueOperand rhs = ToValue(lir, LCompareBitwise::RhsInput);
     const Register output = ToRegister(lir->output());
 
     MOZ_ASSERT(mir->jsop() == JSOP_EQ || mir->jsop() == JSOP_STRICTEQ ||
@@ -1621,17 +1621,17 @@ CodeGeneratorARM::visitCompareBitwise(LC
     {
         masm.move32(Imm32(cond == Assembler::NotEqual), output);
     }
 
     masm.bind(&done);
 }
 
 void
-CodeGeneratorARM::visitCompareBitwiseAndBranch(LCompareBitwiseAndBranch* lir)
+CodeGenerator::visitCompareBitwiseAndBranch(LCompareBitwiseAndBranch* lir)
 {
     MCompare* mir = lir->cmpMir();
     Assembler::Condition cond = JSOpToCondition(mir->compareType(), mir->jsop());
     const ValueOperand lhs = ToValue(lir, LCompareBitwiseAndBranch::LhsInput);
     const ValueOperand rhs = ToValue(lir, LCompareBitwiseAndBranch::RhsInput);
 
     MOZ_ASSERT(mir->jsop() == JSOP_EQ || mir->jsop() == JSOP_STRICTEQ ||
                mir->jsop() == JSOP_NE || mir->jsop() == JSOP_STRICTNE);
@@ -1640,59 +1640,59 @@ CodeGeneratorARM::visitCompareBitwiseAnd
 
     masm.cmp32(lhs.typeReg(), rhs.typeReg());
     jumpToBlock(notEqual, Assembler::NotEqual);
     masm.cmp32(lhs.payloadReg(), rhs.payloadReg());
     emitBranch(cond, lir->ifTrue(), lir->ifFalse());
 }
 
 void
-CodeGeneratorARM::visitBitAndAndBranch(LBitAndAndBranch* baab)
+CodeGenerator::visitBitAndAndBranch(LBitAndAndBranch* baab)
 {
     ScratchRegisterScope scratch(masm);
     if (baab->right()->isConstant())
         masm.ma_tst(ToRegister(baab->left()), Imm32(ToInt32(baab->right())), scratch);
     else
         masm.ma_tst(ToRegister(baab->left()), ToRegister(baab->right()));
     emitBranch(baab->cond(), baab->ifTrue(), baab->ifFalse());
 }
 
 void
-CodeGeneratorARM::visitWasmUint32ToDouble(LWasmUint32ToDouble* lir)
+CodeGenerator::visitWasmUint32ToDouble(LWasmUint32ToDouble* lir)
 {
     masm.convertUInt32ToDouble(ToRegister(lir->input()), ToFloatRegister(lir->output()));
 }
 
 void
-CodeGeneratorARM::visitWasmUint32ToFloat32(LWasmUint32ToFloat32* lir)
+CodeGenerator::visitWasmUint32ToFloat32(LWasmUint32ToFloat32* lir)
 {
     masm.convertUInt32ToFloat32(ToRegister(lir->input()), ToFloatRegister(lir->output()));
 }
 
 void
-CodeGeneratorARM::visitNotI(LNotI* ins)
+CodeGenerator::visitNotI(LNotI* ins)
 {
     // It is hard to optimize !x, so just do it the basic way for now.
     masm.as_cmp(ToRegister(ins->input()), Imm8(0));
     masm.emitSet(Assembler::Equal, ToRegister(ins->output()));
 }
 
 void
-CodeGeneratorARM::visitNotI64(LNotI64* lir)
+CodeGenerator::visitNotI64(LNotI64* lir)
 {
     Register64 input = ToRegister64(lir->getInt64Operand(0));
     Register output = ToRegister(lir->output());
 
     masm.ma_orr(input.low, input.high, output);
     masm.as_cmp(output, Imm8(0));
     masm.emitSet(Assembler::Equal, output);
 }
 
 void
-CodeGeneratorARM::visitNotD(LNotD* ins)
+CodeGenerator::visitNotD(LNotD* ins)
 {
     // Since this operation is not, we want to set a bit if the double is
     // falsey, which means 0.0, -0.0 or NaN. When comparing with 0, an input of
     // 0 will set the Z bit (30) and NaN will set the V bit (28) of the APSR.
     FloatRegister opd = ToFloatRegister(ins->input());
     Register dest = ToRegister(ins->output());
 
     // Do the compare.
@@ -1710,17 +1710,17 @@ CodeGeneratorARM::visitNotD(LNotD* ins)
         masm.as_vmrs(pc);
         masm.ma_mov(Imm32(0), dest);
         masm.ma_mov(Imm32(1), dest, Assembler::Equal);
         masm.ma_mov(Imm32(1), dest, Assembler::Overflow);
     }
 }
 
 void
-CodeGeneratorARM::visitNotF(LNotF* ins)
+CodeGenerator::visitNotF(LNotF* ins)
 {
     // Since this operation is not, we want to set a bit if the double is
     // falsey, which means 0.0, -0.0 or NaN. When comparing with 0, an input of
     // 0 will set the Z bit (30) and NaN will set the V bit (28) of the APSR.
     FloatRegister opd = ToFloatRegister(ins->input());
     Register dest = ToRegister(ins->output());
 
     // Do the compare.
@@ -1762,29 +1762,29 @@ CodeGeneratorARM::generateInvalidateEpil
     masm.jump(thunk);
 
     // We should never reach this point in JIT code -- the invalidation thunk
     // should pop the invalidated JS frame and return directly to its caller.
     masm.assumeUnreachable("Should have returned directly to its caller instead of here.");
 }
 
 void
-CodeGeneratorARM::visitLoadTypedArrayElementStatic(LLoadTypedArrayElementStatic* ins)
+CodeGenerator::visitLoadTypedArrayElementStatic(LLoadTypedArrayElementStatic* ins)
 {
     MOZ_CRASH("NYI");
 }
 
 void
-CodeGeneratorARM::visitStoreTypedArrayElementStatic(LStoreTypedArrayElementStatic* ins)
+CodeGenerator::visitStoreTypedArrayElementStatic(LStoreTypedArrayElementStatic* ins)
 {
     MOZ_CRASH("NYI");
 }
 
 void
-CodeGeneratorARM::visitCompareExchangeTypedArrayElement(LCompareExchangeTypedArrayElement* lir)
+CodeGenerator::visitCompareExchangeTypedArrayElement(LCompareExchangeTypedArrayElement* lir)
 {
     Register elements = ToRegister(lir->elements());
     AnyRegister output = ToAnyRegister(lir->output());
     Register temp = lir->temp()->isBogusTemp() ? InvalidReg : ToRegister(lir->temp());
 
     Register oldval = ToRegister(lir->oldval());
     Register newval = ToRegister(lir->newval());
 
@@ -1796,17 +1796,17 @@ CodeGeneratorARM::visitCompareExchangeTy
         masm.compareExchangeJS(arrayType, Synchronization::Full(), dest, oldval, newval, temp, output);
     } else {
         BaseIndex dest(elements, ToRegister(lir->index()), ScaleFromElemWidth(width));
         masm.compareExchangeJS(arrayType, Synchronization::Full(), dest, oldval, newval, temp, output);
     }
 }
 
 void
-CodeGeneratorARM::visitAtomicExchangeTypedArrayElement(LAtomicExchangeTypedArrayElement* lir)
+CodeGenerator::visitAtomicExchangeTypedArrayElement(LAtomicExchangeTypedArrayElement* lir)
 {
     Register elements = ToRegister(lir->elements());
     AnyRegister output = ToAnyRegister(lir->output());
     Register temp = lir->temp()->isBogusTemp() ? InvalidReg : ToRegister(lir->temp());
 
     Register value = ToRegister(lir->value());
 
     Scalar::Type arrayType = lir->mir()->arrayType();
@@ -1817,17 +1817,17 @@ CodeGeneratorARM::visitAtomicExchangeTyp
         masm.atomicExchangeJS(arrayType, Synchronization::Full(), dest, value, temp, output);
     } else {
         BaseIndex dest(elements, ToRegister(lir->index()), ScaleFromElemWidth(width));
         masm.atomicExchangeJS(arrayType, Synchronization::Full(), dest, value, temp, output);
     }
 }
 
 void
-CodeGeneratorARM::visitAtomicTypedArrayElementBinop(LAtomicTypedArrayElementBinop* lir)
+CodeGenerator::visitAtomicTypedArrayElementBinop(LAtomicTypedArrayElementBinop* lir)
 {
     MOZ_ASSERT(lir->mir()->hasUses());
 
     AnyRegister output = ToAnyRegister(lir->output());
     Register elements = ToRegister(lir->elements());
     Register flagTemp = ToRegister(lir->temp1());
     Register outTemp = lir->temp2()->isBogusTemp() ? InvalidReg : ToRegister(lir->temp2());
     Register value = ToRegister(lir->value());
@@ -1842,17 +1842,17 @@ CodeGeneratorARM::visitAtomicTypedArrayE
     } else {
         BaseIndex mem(elements, ToRegister(lir->index()), ScaleFromElemWidth(width));
         masm.atomicFetchOpJS(arrayType, Synchronization::Full(), lir->mir()->operation(), value,
                              mem, flagTemp, outTemp, output);
     }
 }
 
 void
-CodeGeneratorARM::visitAtomicTypedArrayElementBinopForEffect(LAtomicTypedArrayElementBinopForEffect* lir)
+CodeGenerator::visitAtomicTypedArrayElementBinopForEffect(LAtomicTypedArrayElementBinopForEffect* lir)
 {
     MOZ_ASSERT(!lir->mir()->hasUses());
 
     Register elements = ToRegister(lir->elements());
     Register flagTemp = ToRegister(lir->flagTemp());
     Register value = ToRegister(lir->value());
     Scalar::Type arrayType = lir->mir()->arrayType();
     int width = Scalar::byteSize(arrayType);
@@ -1864,17 +1864,17 @@ CodeGeneratorARM::visitAtomicTypedArrayE
     } else {
         BaseIndex mem(elements, ToRegister(lir->index()), ScaleFromElemWidth(width));
         masm.atomicEffectOpJS(arrayType, Synchronization::Full(), lir->mir()->operation(), value,
                               mem, flagTemp);
     }
 }
 
 void
-CodeGeneratorARM::visitWasmSelect(LWasmSelect* ins)
+CodeGenerator::visitWasmSelect(LWasmSelect* ins)
 {
     MIRType mirType = ins->mir()->type();
 
     Register cond = ToRegister(ins->condExpr());
     masm.as_cmp(cond, Imm8(0));
 
     if (mirType == MIRType::Int32) {
         Register falseExpr = ToRegister(ins->falseExpr());
@@ -1893,17 +1893,17 @@ CodeGeneratorARM::visitWasmSelect(LWasmS
         masm.moveDouble(falseExpr, out, Assembler::Zero);
     else if (mirType == MIRType::Float32)
         masm.moveFloat32(falseExpr, out, Assembler::Zero);
     else
         MOZ_CRASH("unhandled type in visitWasmSelect!");
 }
 
 void
-CodeGeneratorARM::visitWasmReinterpret(LWasmReinterpret* lir)
+CodeGenerator::visitWasmReinterpret(LWasmReinterpret* lir)
 {
     MOZ_ASSERT(gen->compilingWasm());
     MWasmReinterpret* ins = lir->mir();
 
     MIRType to = ins->type();
     DebugOnly<MIRType> from = ins->input()->type();
 
     switch (to) {
@@ -1919,17 +1919,17 @@ CodeGeneratorARM::visitWasmReinterpret(L
       case MIRType::Int64:
         MOZ_CRASH("not handled by this LIR opcode");
       default:
         MOZ_CRASH("unexpected WasmReinterpret");
     }
 }
 
 void
-CodeGeneratorARM::visitAsmJSLoadHeap(LAsmJSLoadHeap* ins)
+CodeGenerator::visitAsmJSLoadHeap(LAsmJSLoadHeap* ins)
 {
     const MAsmJSLoadHeap* mir = ins->mir();
     MOZ_ASSERT(mir->offset() == 0);
 
     const LAllocation* ptr = ins->ptr();
     const LAllocation* boundsCheckLimit = ins->boundsCheckLimit();
 
     bool isSigned;
@@ -2017,23 +2017,23 @@ CodeGeneratorARM::emitWasmLoad(T* lir)
 
     if (resultType == MIRType::Int64)
         masm.wasmLoadI64(mir->access(), HeapReg, ptr, ptr, ToOutRegister64(lir));
     else
         masm.wasmLoad(mir->access(), HeapReg, ptr, ptr, ToAnyRegister(lir->output()));
 }
 
 void
-CodeGeneratorARM::visitWasmLoad(LWasmLoad* lir)
+CodeGenerator::visitWasmLoad(LWasmLoad* lir)
 {
     emitWasmLoad(lir);
 }
 
 void
-CodeGeneratorARM::visitWasmLoadI64(LWasmLoadI64* lir)
+CodeGenerator::visitWasmLoadI64(LWasmLoadI64* lir)
 {
     emitWasmLoad(lir);
 }
 
 template<typename T>
 void
 CodeGeneratorARM::emitWasmUnalignedLoad(T* lir)
 {
@@ -2053,29 +2053,29 @@ CodeGeneratorARM::emitWasmUnalignedLoad(
         masm.wasmUnalignedLoadFP(mir->access(), HeapReg, ptr, ptr, ToFloatRegister(lir->output()),
                                  tmp1, tmp2, tmp3);
     } else {
         masm.wasmUnalignedLoad(mir->access(), HeapReg, ptr, ptr, ToRegister(lir->output()), tmp1);
     }
 }
 
 void
-CodeGeneratorARM::visitWasmUnalignedLoad(LWasmUnalignedLoad* lir)
+CodeGenerator::visitWasmUnalignedLoad(LWasmUnalignedLoad* lir)
 {
     emitWasmUnalignedLoad(lir);
 }
 
 void
-CodeGeneratorARM::visitWasmUnalignedLoadI64(LWasmUnalignedLoadI64* lir)
+CodeGenerator::visitWasmUnalignedLoadI64(LWasmUnalignedLoadI64* lir)
 {
     emitWasmUnalignedLoad(lir);
 }
 
 void
-CodeGeneratorARM::visitWasmAddOffset(LWasmAddOffset* lir)
+CodeGenerator::visitWasmAddOffset(LWasmAddOffset* lir)
 {
     MWasmAddOffset* mir = lir->mir();
     Register base = ToRegister(lir->base());
     Register out = ToRegister(lir->output());
 
     ScratchRegisterScope scratch(masm);
     masm.ma_add(base, Imm32(mir->offset()), out, scratch, SetCC);
 
@@ -2102,23 +2102,23 @@ CodeGeneratorARM::emitWasmStore(T* lir)
         masm.wasmStoreI64(mir->access(), ToRegister64(lir->getInt64Operand(lir->ValueIndex)),
                           HeapReg, ptr, ptr);
     else
         masm.wasmStore(mir->access(), ToAnyRegister(lir->getOperand(lir->ValueIndex)), HeapReg,
                        ptr, ptr);
 }
 
 void
-CodeGeneratorARM::visitWasmStore(LWasmStore* lir)
+CodeGenerator::visitWasmStore(LWasmStore* lir)
 {
     emitWasmStore(lir);
 }
 
 void
-CodeGeneratorARM::visitWasmStoreI64(LWasmStoreI64* lir)
+CodeGenerator::visitWasmStoreI64(LWasmStoreI64* lir)
 {
     emitWasmStore(lir);
 }
 
 template<typename T>
 void
 CodeGeneratorARM::emitWasmUnalignedStore(T* lir)
 {
@@ -2135,29 +2135,29 @@ CodeGeneratorARM::emitWasmUnalignedStore
         FloatRegister value = ToFloatRegister(lir->getOperand(LWasmUnalignedStore::ValueIndex));
         masm.wasmUnalignedStoreFP(mir->access(), value, HeapReg, ptr, ptr, valOrTmp);
     } else {
         masm.wasmUnalignedStore(mir->access(), valOrTmp, HeapReg, ptr, ptr, Register::Invalid());
     }
 }
 
 void
-CodeGeneratorARM::visitWasmUnalignedStore(LWasmUnalignedStore* lir)
+CodeGenerator::visitWasmUnalignedStore(LWasmUnalignedStore* lir)
 {
     emitWasmUnalignedStore(lir);
 }
 
 void
-CodeGeneratorARM::visitWasmUnalignedStoreI64(LWasmUnalignedStoreI64* lir)
+CodeGenerator::visitWasmUnalignedStoreI64(LWasmUnalignedStoreI64* lir)
 {
     emitWasmUnalignedStore(lir);
 }
 
 void
-CodeGeneratorARM::visitAsmJSStoreHeap(LAsmJSStoreHeap* ins)
+CodeGenerator::visitAsmJSStoreHeap(LAsmJSStoreHeap* ins)
 {
     const MAsmJSStoreHeap* mir = ins->mir();
     MOZ_ASSERT(mir->offset() == 0);
 
     const LAllocation* ptr = ins->ptr();
     const LAllocation* boundsCheckLimit = ins->boundsCheckLimit();
 
     bool isSigned;
@@ -2212,17 +2212,17 @@ CodeGeneratorARM::visitAsmJSStoreHeap(LA
             ScratchRegisterScope scratch(masm);
             Register value = ToRegister(ins->value());
             masm.ma_dataTransferN(IsStore, size, isSigned, HeapReg, ptrReg, value, scratch, Offset, cond);
         }
     }
 }
 
 void
-CodeGeneratorARM::visitWasmCompareExchangeHeap(LWasmCompareExchangeHeap* ins)
+CodeGenerator::visitWasmCompareExchangeHeap(LWasmCompareExchangeHeap* ins)
 {
     MWasmCompareExchangeHeap* mir = ins->mir();
 
     Scalar::Type vt = mir->access().type();
     const LAllocation* ptr = ins->ptr();
     Register ptrReg = ToRegister(ptr);
     BaseIndex srcAddr(HeapReg, ptrReg, TimesOne, mir->access().offset());
 
@@ -2231,32 +2231,32 @@ CodeGeneratorARM::visitWasmCompareExchan
     Register oldval = ToRegister(ins->oldValue());
     Register newval = ToRegister(ins->newValue());
     Register out = ToRegister(ins->output());
 
     masm.compareExchange(vt, Synchronization::Full(), srcAddr, oldval, newval, out);
 }
 
 void
-CodeGeneratorARM::visitWasmAtomicExchangeHeap(LWasmAtomicExchangeHeap* ins)
+CodeGenerator::visitWasmAtomicExchangeHeap(LWasmAtomicExchangeHeap* ins)
 {
     MWasmAtomicExchangeHeap* mir = ins->mir();
 
     Scalar::Type vt = mir->access().type();
     Register ptrReg = ToRegister(ins->ptr());
     Register value = ToRegister(ins->value());
     Register output = ToRegister(ins->output());
     BaseIndex srcAddr(HeapReg, ptrReg, TimesOne, mir->access().offset());
     MOZ_ASSERT(ins->addrTemp()->isBogusTemp());
 
     masm.atomicExchange(vt, Synchronization::Full(), srcAddr, value, output);
 }
 
 void
-CodeGeneratorARM::visitWasmAtomicBinopHeap(LWasmAtomicBinopHeap* ins)
+CodeGenerator::visitWasmAtomicBinopHeap(LWasmAtomicBinopHeap* ins)
 {
     MWasmAtomicBinopHeap* mir = ins->mir();
     MOZ_ASSERT(mir->hasUses());
 
     Scalar::Type vt = mir->access().type();
     Register ptrReg = ToRegister(ins->ptr());
     Register flagTemp = ToRegister(ins->flagTemp());
     Register output = ToRegister(ins->output());
@@ -2265,34 +2265,34 @@ CodeGeneratorARM::visitWasmAtomicBinopHe
     MOZ_ASSERT(ins->addrTemp()->isBogusTemp());
 
     BaseIndex srcAddr(HeapReg, ptrReg, TimesOne, mir->access().offset());
     masm.atomicFetchOp(vt, Synchronization::Full(), op, ToRegister(value), srcAddr, flagTemp,
                        output);
 }
 
 void
-CodeGeneratorARM::visitWasmAtomicBinopHeapForEffect(LWasmAtomicBinopHeapForEffect* ins)
+CodeGenerator::visitWasmAtomicBinopHeapForEffect(LWasmAtomicBinopHeapForEffect* ins)
 {
     MWasmAtomicBinopHeap* mir = ins->mir();
     MOZ_ASSERT(!mir->hasUses());
 
     Scalar::Type vt = mir->access().type();
     Register ptrReg = ToRegister(ins->ptr());
     Register flagTemp = ToRegister(ins->flagTemp());
     const LAllocation* value = ins->value();
     AtomicOp op = mir->operation();
     MOZ_ASSERT(ins->addrTemp()->isBogusTemp());
 
     BaseIndex srcAddr(HeapReg, ptrReg, TimesOne, mir->access().offset());
     masm.atomicEffectOp(vt, Synchronization::Full(), op, ToRegister(value), srcAddr, flagTemp);
 }
 
 void
-CodeGeneratorARM::visitWasmStackArg(LWasmStackArg* ins)
+CodeGenerator::visitWasmStackArg(LWasmStackArg* ins)
 {
     const MWasmStackArg* mir = ins->mir();
     Address dst(StackPointer, mir->spOffset());
     ScratchRegisterScope scratch(masm);
     SecondScratchRegisterScope scratch2(masm);
 
     if (ins->arg()->isConstant()) {
         masm.ma_mov(Imm32(ToInt32(ins->arg())), scratch);
@@ -2301,17 +2301,17 @@ CodeGeneratorARM::visitWasmStackArg(LWas
         if (ins->arg()->isGeneralReg())
             masm.ma_str(ToRegister(ins->arg()), dst, scratch);
         else
             masm.ma_vstr(ToFloatRegister(ins->arg()), dst, scratch);
     }
 }
 
 void
-CodeGeneratorARM::visitUDiv(LUDiv* ins)
+CodeGenerator::visitUDiv(LUDiv* ins)
 {
     Register lhs = ToRegister(ins->lhs());
     Register rhs = ToRegister(ins->rhs());
     Register output = ToRegister(ins->output());
 
     Label done;
     generateUDivModZeroCheck(rhs, output, &done, ins->snapshot(), ins->mir());
 
@@ -2335,17 +2335,17 @@ CodeGeneratorARM::visitUDiv(LUDiv* ins)
         bailoutIf(Assembler::NotEqual, ins->snapshot());
     }
 
     if (done.used())
         masm.bind(&done);
 }
 
 void
-CodeGeneratorARM::visitUMod(LUMod* ins)
+CodeGenerator::visitUMod(LUMod* ins)
 {
     Register lhs = ToRegister(ins->lhs());
     Register rhs = ToRegister(ins->rhs());
     Register output = ToRegister(ins->output());
 
     Label done;
     generateUDivModZeroCheck(rhs, output, &done, ins->snapshot(), ins->mir());
 
@@ -2392,17 +2392,17 @@ CodeGeneratorARM::generateUDivModZeroChe
             // Bailout for divide by zero
             MOZ_ASSERT(mir->fallible());
             bailoutIf(Assembler::Equal, snapshot);
         }
     }
 }
 
 void
-CodeGeneratorARM::visitSoftUDivOrMod(LSoftUDivOrMod* ins)
+CodeGenerator::visitSoftUDivOrMod(LSoftUDivOrMod* ins)
 {
     Register lhs = ToRegister(ins->lhs());
     Register rhs = ToRegister(ins->rhs());
     Register output = ToRegister(ins->output());
 
     MOZ_ASSERT(lhs == r0);
     MOZ_ASSERT(rhs == r1);
     MOZ_ASSERT(output == r0);
@@ -2447,69 +2447,58 @@ CodeGeneratorARM::visitSoftUDivOrMod(LSo
         masm.as_cmp(output, Imm8(0));
         bailoutIf(Assembler::LessThan, ins->snapshot());
     }
 
     masm.bind(&done);
 }
 
 void
-CodeGeneratorARM::visitEffectiveAddress(LEffectiveAddress* ins)
+CodeGenerator::visitEffectiveAddress(LEffectiveAddress* ins)
 {
     const MEffectiveAddress* mir = ins->mir();
     Register base = ToRegister(ins->base());
     Register index = ToRegister(ins->index());
     Register output = ToRegister(ins->output());
 
     ScratchRegisterScope scratch(masm);
 
     masm.as_add(output, base, lsl(index, mir->scale()));
     masm.ma_add(Imm32(mir->displacement()), output, scratch);
 }
 
 void
-CodeGeneratorARM::visitNegI(LNegI* ins)
+CodeGenerator::visitNegI(LNegI* ins)
 {
     Register input = ToRegister(ins->input());
     masm.ma_neg(input, ToRegister(ins->output()));
 }
 
 void
-CodeGeneratorARM::visitNegD(LNegD* ins)
+CodeGenerator::visitNegD(LNegD* ins)
 {
     FloatRegister input = ToFloatRegister(ins->input());
     masm.ma_vneg(input, ToFloatRegister(ins->output()));
 }
 
 void
-CodeGeneratorARM::visitNegF(LNegF* ins)
+CodeGenerator::visitNegF(LNegF* ins)
 {
     FloatRegister input = ToFloatRegister(ins->input());
     masm.ma_vneg_f32(input, ToFloatRegister(ins->output()));
 }
 
 void
-CodeGeneratorARM::visitMemoryBarrier(LMemoryBarrier* ins)
+CodeGenerator::visitMemoryBarrier(LMemoryBarrier* ins)
 {
     masm.memoryBarrier(ins->type());
 }
 
 void
-CodeGeneratorARM::setReturnDoubleRegs(LiveRegisterSet* regs)
-{
-    MOZ_ASSERT(ReturnFloat32Reg.code_ == FloatRegisters::s0);
-    MOZ_ASSERT(ReturnDoubleReg.code_ == FloatRegisters::s0);
-    FloatRegister s1 = {FloatRegisters::s1, VFPRegister::Single};
-    regs->add(ReturnFloat32Reg);
-    regs->add(s1);
-    regs->add(ReturnDoubleReg);
-}
-
-void
-CodeGeneratorARM::visitWasmTruncateToInt32(LWasmTruncateToInt32* lir)
+CodeGenerator::visitWasmTruncateToInt32(LWasmTruncateToInt32* lir)
 {
     auto input = ToFloatRegister(lir->input());
     auto output = ToRegister(lir->output());
 
     MWasmTruncateToInt32* mir = lir->mir();
     MIRType fromType = mir->input()->type();
 
     OutOfLineWasmTruncateCheck* ool = nullptr;
@@ -2524,17 +2513,17 @@ CodeGeneratorARM::visitWasmTruncateToInt
                              oolEntry);
 
     if (!lir->mir()->isSaturating()) {
         masm.bind(ool->rejoin());
     }
 }
 
 void
-CodeGeneratorARM::visitWasmTruncateToInt64(LWasmTruncateToInt64* lir)
+CodeGenerator::visitWasmTruncateToInt64(LWasmTruncateToInt64* lir)
 {
     FloatRegister input = ToFloatRegister(lir->input());
     FloatRegister inputDouble = input;
     Register64 output = ToOutRegister64(lir);
 
     MWasmTruncateToInt64* mir = lir->mir();
     MIRType fromType = mir->input()->type();
 
@@ -2594,17 +2583,17 @@ CodeGeneratorARM::visitOutOfLineWasmTrun
         return;
 
     masm.outOfLineWasmTruncateToIntCheck(ool->input(), ool->fromType(), ool->toType(),
                                          ool->isUnsigned(), ool->rejoin(),
                                          ool->bytecodeOffset());
 }
 
 void
-CodeGeneratorARM::visitInt64ToFloatingPointCall(LInt64ToFloatingPointCall* lir)
+CodeGenerator::visitInt64ToFloatingPointCall(LInt64ToFloatingPointCall* lir)
 {
     Register64 input = ToRegister64(lir->getInt64Operand(0));
 
     MInt64ToFloatingPoint* mir = lir->mir();
     MIRType toType = mir->type();
 
     masm.setupWasmABICall();
     masm.passABIArg(input.high);
@@ -2621,17 +2610,17 @@ CodeGeneratorARM::visitInt64ToFloatingPo
     masm.callWithABI(mir->bytecodeOffset(), callee, result);
 
     DebugOnly<FloatRegister> output(ToFloatRegister(lir->output()));
     MOZ_ASSERT_IF(toType == MIRType::Double, output.value == ReturnDoubleReg);
     MOZ_ASSERT_IF(toType == MIRType::Float32, output.value == ReturnFloat32Reg);
 }
 
 void
-CodeGeneratorARM::visitCopySignF(LCopySignF* ins)
+CodeGenerator::visitCopySignF(LCopySignF* ins)
 {
     FloatRegister lhs = ToFloatRegister(ins->getOperand(0));
     FloatRegister rhs = ToFloatRegister(ins->getOperand(1));
     FloatRegister output = ToFloatRegister(ins->getDef(0));
 
     Register lhsi = ToRegister(ins->getTemp(0));
     Register rhsi = ToRegister(ins->getTemp(1));
 
@@ -2648,17 +2637,17 @@ CodeGeneratorARM::visitCopySignF(LCopySi
 
     // Combine.
     masm.ma_orr(lhsi, rhsi, rhsi);
 
     masm.ma_vxfer(rhsi, output);
 }
 
 void
-CodeGeneratorARM::visitCopySignD(LCopySignD* ins)
+CodeGenerator::visitCopySignD(LCopySignD* ins)
 {
     FloatRegister lhs = ToFloatRegister(ins->getOperand(0));
     FloatRegister rhs = ToFloatRegister(ins->getOperand(1));
     FloatRegister output = ToFloatRegister(ins->getDef(0));
 
     Register lhsi = ToRegister(ins->getTemp(0));
     Register rhsi = ToRegister(ins->getTemp(1));
 
@@ -2678,41 +2667,41 @@ CodeGeneratorARM::visitCopySignD(LCopySi
     masm.ma_orr(lhsi, rhsi, rhsi);
 
     // Reconstruct the output.
     masm.as_vxfer(lhsi, InvalidReg, lhs, Assembler::FloatToCore, Assembler::Always, 0);
     masm.ma_vxfer(lhsi, rhsi, output);
 }
 
 void
-CodeGeneratorARM::visitWrapInt64ToInt32(LWrapInt64ToInt32* lir)
+CodeGenerator::visitWrapInt64ToInt32(LWrapInt64ToInt32* lir)
 {
     const LInt64Allocation& input = lir->getInt64Operand(0);
     Register output = ToRegister(lir->output());
 
     if (lir->mir()->bottomHalf())
         masm.move32(ToRegister(input.low()), output);
     else
         masm.move32(ToRegister(input.high()), output);
 }
 
 void
-CodeGeneratorARM::visitExtendInt32ToInt64(LExtendInt32ToInt64* lir)
+CodeGenerator::visitExtendInt32ToInt64(LExtendInt32ToInt64* lir)
 {
     Register64 output = ToOutRegister64(lir);
     MOZ_ASSERT(ToRegister(lir->input()) == output.low);
 
     if (lir->mir()->isUnsigned())
         masm.ma_mov(Imm32(0), output.high);
     else
         masm.ma_asr(Imm32(31), output.low, output.high);
 }
 
 void
-CodeGeneratorARM::visitSignExtendInt64(LSignExtendInt64* lir)
+CodeGenerator::visitSignExtendInt64(LSignExtendInt64* lir)
 {
     Register64 input = ToRegister64(lir->getInt64Operand(0));
     Register64 output = ToOutRegister64(lir);
     switch (lir->mode()) {
       case MSignExtendInt64::Byte:
         masm.move8SignExtend(input.low, output.low);
         break;
       case MSignExtendInt64::Half:
@@ -2742,17 +2731,17 @@ WasmGetTemporaryForDivOrMod(Register64 l
     if (lhs != rhs) {
         regs.take(rhs.low);
         regs.take(rhs.high);
     }
     return regs.takeAny();
 }
 
 void
-CodeGeneratorARM::visitDivOrModI64(LDivOrModI64* lir)
+CodeGenerator::visitDivOrModI64(LDivOrModI64* lir)
 {
     Register64 lhs = ToRegister64(lir->getInt64Operand(LDivOrModI64::Lhs));
     Register64 rhs = ToRegister64(lir->getInt64Operand(LDivOrModI64::Rhs));
     Register64 output = ToOutRegister64(lir);
 
     MOZ_ASSERT(output == ReturnReg64);
 
     Label done;
@@ -2793,17 +2782,17 @@ CodeGeneratorARM::visitDivOrModI64(LDivO
         masm.callWithABI(lir->bytecodeOffset(), wasm::SymbolicAddress::DivI64);
 
     MOZ_ASSERT(ReturnReg64 == output);
 
     masm.bind(&done);
 }
 
 void
-CodeGeneratorARM::visitUDivOrModI64(LUDivOrModI64* lir)
+CodeGenerator::visitUDivOrModI64(LUDivOrModI64* lir)
 {
     Register64 lhs = ToRegister64(lir->getInt64Operand(LDivOrModI64::Lhs));
     Register64 rhs = ToRegister64(lir->getInt64Operand(LDivOrModI64::Rhs));
 
     MOZ_ASSERT(ToOutRegister64(lir) == ReturnReg64);
 
     // Prevent divide by zero.
     if (lir->canBeDivideByZero()) {
@@ -2824,17 +2813,17 @@ CodeGeneratorARM::visitUDivOrModI64(LUDi
     MDefinition* mir = lir->mir();
     if (mir->isMod())
         masm.callWithABI(lir->bytecodeOffset(), wasm::SymbolicAddress::UModI64);
     else
         masm.callWithABI(lir->bytecodeOffset(), wasm::SymbolicAddress::UDivI64);
 }
 
 void
-CodeGeneratorARM::visitCompareI64(LCompareI64* lir)
+CodeGenerator::visitCompareI64(LCompareI64* lir)
 {
     MCompare* mir = lir->mir();
     MOZ_ASSERT(mir->compareType() == MCompare::Compare_Int64 ||
                mir->compareType() == MCompare::Compare_UInt64);
 
     const LInt64Allocation lhs = lir->getInt64Operand(LCompareI64::Lhs);
     const LInt64Allocation rhs = lir->getInt64Operand(LCompareI64::Rhs);
     Register64 lhsRegs = ToRegister64(lhs);
@@ -2854,17 +2843,17 @@ CodeGeneratorARM::visitCompareI64(LCompa
         masm.branch64(condition, lhsRegs, rhsRegs, &done);
     }
 
     masm.move32(Imm32(0), output);
     masm.bind(&done);
 }
 
 void
-CodeGeneratorARM::visitCompareI64AndBranch(LCompareI64AndBranch* lir)
+CodeGenerator::visitCompareI64AndBranch(LCompareI64AndBranch* lir)
 {
     MCompare* mir = lir->cmpMir();
     MOZ_ASSERT(mir->compareType() == MCompare::Compare_Int64 ||
                mir->compareType() == MCompare::Compare_UInt64);
 
     const LInt64Allocation lhs = lir->getInt64Operand(LCompareI64::Lhs);
     const LInt64Allocation rhs = lir->getInt64Operand(LCompareI64::Rhs);
     Register64 lhsRegs = ToRegister64(lhs);
@@ -2888,17 +2877,17 @@ CodeGeneratorARM::visitCompareI64AndBran
         masm.branch64(condition, lhsRegs, imm, trueLabel, falseLabel);
     } else {
         Register64 rhsRegs = ToRegister64(rhs);
         masm.branch64(condition, lhsRegs, rhsRegs, trueLabel, falseLabel);
     }
 }
 
 void
-CodeGeneratorARM::visitShiftI64(LShiftI64* lir)
+CodeGenerator::visitShiftI64(LShiftI64* lir)
 {
     const LInt64Allocation lhs = lir->getInt64Operand(LShiftI64::Lhs);
     LAllocation* rhs = lir->getOperand(LShiftI64::Rhs);
 
     MOZ_ASSERT(ToOutRegister64(lir) == ToRegister64(lhs));
 
     if (rhs->isConstant()) {
         int32_t shift = int32_t(rhs->toConstant()->toInt64() & 0x3F);
@@ -2932,17 +2921,17 @@ CodeGeneratorARM::visitShiftI64(LShiftI6
         masm.rshift64(ToRegister(rhs), ToRegister64(lhs));
         break;
       default:
         MOZ_CRASH("Unexpected shift op");
     }
 }
 
 void
-CodeGeneratorARM::visitBitOpI64(LBitOpI64* lir)
+CodeGenerator::visitBitOpI64(LBitOpI64* lir)
 {
     const LInt64Allocation lhs = lir->getInt64Operand(LBitOpI64::Lhs);
     const LInt64Allocation rhs = lir->getInt64Operand(LBitOpI64::Rhs);
 
     MOZ_ASSERT(ToOutRegister64(lir) == ToRegister64(lhs));
 
     switch (lir->bitop()) {
       case JSOP_BITOR:
@@ -2964,17 +2953,17 @@ CodeGeneratorARM::visitBitOpI64(LBitOpI6
             masm.and64(ToOperandOrRegister64(rhs), ToRegister64(lhs));
         break;
       default:
         MOZ_CRASH("unexpected binary opcode");
     }
 }
 
 void
-CodeGeneratorARM::visitRotateI64(LRotateI64* lir)
+CodeGenerator::visitRotateI64(LRotateI64* lir)
 {
     MRotate* mir = lir->mir();
     LAllocation* count = lir->count();
 
     Register64 input = ToRegister64(lir->input());
     Register64 output = ToOutRegister64(lir);
     Register temp = ToTempRegisterOrInvalid(lir->temp());
 
@@ -2992,28 +2981,28 @@ CodeGeneratorARM::visitRotateI64(LRotate
         if (mir->isLeftRotate())
             masm.rotateLeft64(ToRegister(count), input, output, temp);
         else
             masm.rotateRight64(ToRegister(count), input, output, temp);
     }
 }
 
 void
-CodeGeneratorARM::visitWasmStackArgI64(LWasmStackArgI64* ins)
+CodeGenerator::visitWasmStackArgI64(LWasmStackArgI64* ins)
 {
     const MWasmStackArg* mir = ins->mir();
     Address dst(StackPointer, mir->spOffset());
     if (IsConstant(ins->arg()))
         masm.store64(Imm64(ToInt64(ins->arg())), dst);
     else
         masm.store64(ToRegister64(ins->arg()), dst);
 }
 
 void
-CodeGeneratorARM::visitWasmSelectI64(LWasmSelectI64* lir)
+CodeGenerator::visitWasmSelectI64(LWasmSelectI64* lir)
 {
     Register cond = ToRegister(lir->condExpr());
     const LInt64Allocation falseExpr = lir->falseExpr();
 
     Register64 out = ToOutRegister64(lir);
     MOZ_ASSERT(ToRegister64(lir->trueExpr()) == out, "true expr is reused for input");
 
     masm.as_cmp(cond, Imm8(0));
@@ -3023,126 +3012,372 @@ CodeGeneratorARM::visitWasmSelectI64(LWa
     } else {
         ScratchRegisterScope scratch(masm);
         masm.ma_ldr(ToAddress(falseExpr.low()), out.low, scratch, Offset, Assembler::Equal);
         masm.ma_ldr(ToAddress(falseExpr.high()), out.high, scratch, Offset, Assembler::Equal);
     }
 }
 
 void
-CodeGeneratorARM::visitWasmReinterpretFromI64(LWasmReinterpretFromI64* lir)
+CodeGenerator::visitWasmReinterpretFromI64(LWasmReinterpretFromI64* lir)
 {
     MOZ_ASSERT(lir->mir()->type() == MIRType::Double);
     MOZ_ASSERT(lir->mir()->input()->type() == MIRType::Int64);
     Register64 input = ToRegister64(lir->getInt64Operand(0));
     FloatRegister output = ToFloatRegister(lir->output());
 
     masm.ma_vxfer(input.low, input.high, output);
 }
 
 void
-CodeGeneratorARM::visitWasmReinterpretToI64(LWasmReinterpretToI64* lir)
+CodeGenerator::visitWasmReinterpretToI64(LWasmReinterpretToI64* lir)
 {
     MOZ_ASSERT(lir->mir()->type() == MIRType::Int64);
     MOZ_ASSERT(lir->mir()->input()->type() == MIRType::Double);
     FloatRegister input = ToFloatRegister(lir->getOperand(0));
     Register64 output = ToOutRegister64(lir);
 
     masm.ma_vxfer(input, output.low, output.high);
 }
 
 void
-CodeGeneratorARM::visitPopcntI64(LPopcntI64* lir)
+CodeGenerator::visitPopcntI64(LPopcntI64* lir)
 {
     Register64 input = ToRegister64(lir->getInt64Operand(0));
     Register64 output = ToOutRegister64(lir);
     Register temp = ToRegister(lir->getTemp(0));
 
     masm.popcnt64(input, output, temp);
 }
 
 void
-CodeGeneratorARM::visitClzI64(LClzI64* lir)
+CodeGenerator::visitClzI64(LClzI64* lir)
 {
     Register64 input = ToRegister64(lir->getInt64Operand(0));
     Register64 output = ToOutRegister64(lir);
 
     masm.clz64(input, output.low);
     masm.move32(Imm32(0), output.high);
 }
 
 void
-CodeGeneratorARM::visitCtzI64(LCtzI64* lir)
+CodeGenerator::visitCtzI64(LCtzI64* lir)
 {
     Register64 input = ToRegister64(lir->getInt64Operand(0));
     Register64 output = ToOutRegister64(lir);
 
     masm.ctz64(input, output.low);
     masm.move32(Imm32(0), output.high);
 }
 
 void
-CodeGeneratorARM::visitTestI64AndBranch(LTestI64AndBranch* lir)
+CodeGenerator::visitTestI64AndBranch(LTestI64AndBranch* lir)
 {
     Register64 input = ToRegister64(lir->getInt64Operand(0));
 
     masm.as_cmp(input.high, Imm8(0));
     jumpToBlock(lir->ifTrue(), Assembler::NonZero);
     masm.as_cmp(input.low, Imm8(0));
     emitBranch(Assembler::NonZero, lir->ifTrue(), lir->ifFalse());
 }
 
 void
-CodeGeneratorARM::visitWasmAtomicLoadI64(LWasmAtomicLoadI64* lir)
+CodeGenerator::visitWasmAtomicLoadI64(LWasmAtomicLoadI64* lir)
 {
     Register ptr = ToRegister(lir->ptr());
     Register64 output = ToOutRegister64(lir);
     Register64 tmp(InvalidReg, InvalidReg);
 
     BaseIndex addr(HeapReg, ptr, TimesOne, lir->mir()->access().offset());
     masm.atomicLoad64(Synchronization::Full(), addr, tmp, output);
 }
 
 void
-CodeGeneratorARM::visitWasmAtomicStoreI64(LWasmAtomicStoreI64* lir)
+CodeGenerator::visitWasmAtomicStoreI64(LWasmAtomicStoreI64* lir)
 {
     Register ptr = ToRegister(lir->ptr());
     Register64 value = ToRegister64(lir->value());
     Register64 tmp(ToRegister(lir->tmpHigh()), ToRegister(lir->tmpLow()));
 
     BaseIndex addr(HeapReg, ptr, TimesOne, lir->mir()->access().offset());
     masm.atomicExchange64(Synchronization::Full(), addr, value, tmp);
 }
 
 void
-CodeGeneratorARM::visitWasmCompareExchangeI64(LWasmCompareExchangeI64* lir)
+CodeGenerator::visitWasmCompareExchangeI64(LWasmCompareExchangeI64* lir)
 {
     Register ptr = ToRegister(lir->ptr());
     Register64 expected = ToRegister64(lir->expected());
     Register64 replacement = ToRegister64(lir->replacement());
     Register64 out = ToOutRegister64(lir);
 
     BaseIndex addr(HeapReg, ptr, TimesOne, lir->mir()->access().offset());
     masm.compareExchange64(Synchronization::Full(), addr, expected, replacement, out);
 }
 
 void
-CodeGeneratorARM::visitWasmAtomicBinopI64(LWasmAtomicBinopI64* lir)
+CodeGenerator::visitWasmAtomicBinopI64(LWasmAtomicBinopI64* lir)
 {
     Register ptr = ToRegister(lir->ptr());
     Register64 value = ToRegister64(lir->value());
     Register64 out = ToOutRegister64(lir);
 
     BaseIndex addr(HeapReg, ptr, TimesOne, lir->access().offset());
     Register64 tmp(ToRegister(lir->tmpHigh()), ToRegister(lir->tmpLow()));
     masm.atomicFetchOp64(Synchronization::Full(), lir->operation(), value, addr, tmp, out);
 }
 
 void
-CodeGeneratorARM::visitWasmAtomicExchangeI64(LWasmAtomicExchangeI64* lir)
+CodeGenerator::visitWasmAtomicExchangeI64(LWasmAtomicExchangeI64* lir)
 {
     Register ptr = ToRegister(lir->ptr());
     Register64 value = ToRegister64(lir->value());
     Register64 out = ToOutRegister64(lir);
 
     BaseIndex addr(HeapReg, ptr, TimesOne, lir->access().offset());
     masm.atomicExchange64(Synchronization::Full(), addr, value, out);
 }
+
+void
+CodeGenerator::visitSimdSplatX4(LSimdSplatX4* lir)
+{
+    MOZ_CRASH("NYI");
+}
+
+void
+CodeGenerator::visitSimd128Int(LSimd128Int* ins)
+{
+    MOZ_CRASH("NYI");
+}
+
+void
+CodeGenerator::visitSimd128Float(LSimd128Float* ins)
+{
+    MOZ_CRASH("NYI");
+}
+
+void
+CodeGenerator::visitSimdExtractElementI(LSimdExtractElementI* ins)
+{
+    MOZ_CRASH("NYI");
+}
+
+void
+CodeGenerator::visitSimdExtractElementF(LSimdExtractElementF* ins)
+{
+    MOZ_CRASH("NYI");
+}
+
+void
+CodeGenerator::visitSimdBinaryCompIx4(LSimdBinaryCompIx4* lir)
+{
+    MOZ_CRASH("NYI");
+}
+
+void
+CodeGenerator::visitSimdBinaryCompFx4(LSimdBinaryCompFx4* lir)
+{
+    MOZ_CRASH("NYI");
+}
+
+void
+CodeGenerator::visitSimdBinaryArithIx4(LSimdBinaryArithIx4* lir)
+{
+    MOZ_CRASH("NYI");
+}
+
+void
+CodeGenerator::visitSimdBinaryArithFx4(LSimdBinaryArithFx4* lir)
+{
+    MOZ_CRASH("NYI");
+}
+
+void
+CodeGenerator::visitSimdBinaryBitwise(LSimdBinaryBitwise* lir)
+{
+    MOZ_CRASH("NYI");
+}