Bug 1411893 - Introduce nsStaticAtom. r=froydnj,emilio. draft
authorNicholas Nethercote <nnethercote@mozilla.com>
Fri, 27 Oct 2017 10:31:13 +1100
changeset 687342 a881211b87715b334c06a577cb981de42dd5112b
parent 687341 ac1be2cb55e331a750ab061e612b2c53e2d536fb
child 737628 3c240a2b3b0271500ece93ac6347aa012ccd584b
push id86475
push usernnethercote@mozilla.com
push dateFri, 27 Oct 2017 05:19:04 +0000
reviewersfroydnj, emilio
bugs1411893
milestone58.0a1
Bug 1411893 - Introduce nsStaticAtom. r=froydnj,emilio. It's a sub-class of nsAtom, useful for cases where you know you are dealing exclusively with static atoms. The nice thing about it is that you can use raw nsStaticAtom pointers instead of RefPtr<>. (In fact, the AddRef/Release implementations ensure that we'll crash if we use RefPtr<nsStaticAtom>.) MozReview-Commit-ID: 4Q6QHX5h44V
accessible/base/ARIAMap.cpp
accessible/base/ARIAMap.h
accessible/base/ARIAStateMap.cpp
accessible/base/nsAccessibilityService.h
accessible/generic/DocAccessible.cpp
dom/base/Element.cpp
dom/base/Element.h
dom/base/FragmentOrElement.cpp
dom/base/nsIContent.h
dom/base/nsTreeSanitizer.cpp
dom/base/nsTreeSanitizer.h
dom/svg/SVGLength.cpp
dom/svg/SVGTests.cpp
dom/svg/SVGTests.h
dom/svg/SVGTransformListParser.cpp
dom/svg/nsSVGAngle.cpp
dom/svg/nsSVGElement.h
dom/svg/nsSVGEnum.h
dom/svg/nsSVGLength2.cpp
dom/xslt/xpath/txCoreFunctionCall.cpp
dom/xslt/xslt/txEXSLTFunctions.cpp
dom/xul/XULDocument.h
layout/base/nsCSSFrameConstructor.h
layout/style/CounterStyleManager.cpp
layout/style/nsCSSParser.cpp
layout/style/nsMediaFeatures.h
parser/html/nsHtml5AtomTable.cpp
parser/htmlparser/nsHTMLTags.cpp
parser/htmlparser/nsHTMLTags.h
xpcom/ds/nsAtom.h
xpcom/ds/nsAtomTable.cpp
xpcom/ds/nsStaticAtom.h
--- a/accessible/base/ARIAMap.cpp
+++ b/accessible/base/ARIAMap.cpp
@@ -1225,17 +1225,17 @@ static const EStateRule sWAIUnivStateMap
 
 /**
  * ARIA attribute map for attribute characteristics.
  * @note ARIA attributes that don't have any flags are not included here.
  */
 
 struct AttrCharacteristics
 {
-  nsAtom** attributeName;
+  nsStaticAtom** attributeName;
   const uint8_t characteristics;
 };
 
 static const AttrCharacteristics gWAIUnivAttrMap[] = {
   {&nsGkAtoms::aria_activedescendant,  ATTR_BYPASSOBJ                               },
   {&nsGkAtoms::aria_atomic,   ATTR_BYPASSOBJ_IF_FALSE | ATTR_VALTOKEN | ATTR_GLOBAL },
   {&nsGkAtoms::aria_busy,                               ATTR_VALTOKEN | ATTR_GLOBAL },
   {&nsGkAtoms::aria_checked,           ATTR_BYPASSOBJ | ATTR_VALTOKEN               }, /* exposes checkable obj attr */
--- a/accessible/base/ARIAMap.h
+++ b/accessible/base/ARIAMap.h
@@ -151,17 +151,17 @@ struct nsRoleMapEntry
 
   /**
    * Return ARIA role.
    */
   const nsDependentAtomString ARIARoleString() const
     { return nsDependentAtomString(*roleAtom); }
 
   // ARIA role: string representation such as "button"
-  nsAtom** roleAtom;
+  nsStaticAtom** roleAtom;
 
   // Role mapping rule: maps to enum Role
   mozilla::a11y::role role;
 
   // Role rule: whether to use mapped role or native semantics
   bool roleRule;
 
   // Value mapping rule: how to compute accessible value
--- a/accessible/base/ARIAStateMap.cpp
+++ b/accessible/base/ARIAStateMap.cpp
@@ -15,21 +15,21 @@ using namespace mozilla::a11y;
 using namespace mozilla::a11y::aria;
 
 /**
  * Used to store state map rule data for ARIA attribute of enum type.
  */
 struct EnumTypeData
 {
   // ARIA attribute name.
-  nsAtom* const mAttrName;
+  nsStaticAtom* const mAttrName;
 
   // States if the attribute value is matched to the enum value. Used as
   // nsIContent::AttrValuesArray, last item must be nullptr.
-  nsAtom* const* const mValues[4];
+  nsStaticAtom* const* const mValues[4];
 
   // States applied if corresponding enum values are matched.
   const uint64_t mStates[3];
 
   // States to clear in case of match.
   const uint64_t mClearState;
 };
 
--- a/accessible/base/nsAccessibilityService.h
+++ b/accessible/base/nsAccessibilityService.h
@@ -48,25 +48,25 @@ SelectionManager* SelectionMgr();
  * Returns the application accessible.
  */
 ApplicationAccessible* ApplicationAcc();
 xpcAccessibleApplication* XPCApplicationAcc();
 
 typedef Accessible* (New_Accessible)(nsIContent* aContent, Accessible* aContext);
 
 struct MarkupAttrInfo {
-  nsAtom** name;
-  nsAtom** value;
+  nsStaticAtom** name;
+  nsStaticAtom** value;
 
-  nsAtom** DOMAttrName;
-  nsAtom** DOMAttrValue;
+  nsStaticAtom** DOMAttrName;
+  nsStaticAtom** DOMAttrValue;
 };
 
 struct MarkupMapInfo {
-  nsAtom** tag;
+  nsStaticAtom** tag;
   New_Accessible* new_func;
   a11y::role role;
   MarkupAttrInfo attrs[4];
 };
 
 } // namespace a11y
 } // namespace mozilla
 
--- a/accessible/generic/DocAccessible.cpp
+++ b/accessible/generic/DocAccessible.cpp
@@ -57,17 +57,17 @@
 #endif
 
 using namespace mozilla;
 using namespace mozilla::a11y;
 
 ////////////////////////////////////////////////////////////////////////////////
 // Static member initialization
 
-static nsAtom** kRelationAttrs[] =
+static nsStaticAtom** kRelationAttrs[] =
 {
   &nsGkAtoms::aria_labelledby,
   &nsGkAtoms::aria_describedby,
   &nsGkAtoms::aria_details,
   &nsGkAtoms::aria_owns,
   &nsGkAtoms::aria_controls,
   &nsGkAtoms::aria_flowto,
   &nsGkAtoms::aria_errormessage,
--- a/dom/base/Element.cpp
+++ b/dom/base/Element.cpp
@@ -3415,38 +3415,37 @@ static void
 nsDOMTokenListPropertyDestructor(void *aObject, nsAtom *aProperty,
                                  void *aPropertyValue, void *aData)
 {
   nsDOMTokenList* list =
     static_cast<nsDOMTokenList*>(aPropertyValue);
   NS_RELEASE(list);
 }
 
-static nsAtom** sPropertiesToTraverseAndUnlink[] =
+static nsStaticAtom** sPropertiesToTraverseAndUnlink[] =
   {
     &nsGkAtoms::sandbox,
     &nsGkAtoms::sizes,
     &nsGkAtoms::dirAutoSetBy,
     nullptr
   };
 
 // static
-nsAtom***
+nsStaticAtom***
 Element::HTMLSVGPropertiesToTraverseAndUnlink()
 {
   return sPropertiesToTraverseAndUnlink;
 }
 
 nsDOMTokenList*
 Element::GetTokenList(nsAtom* aAtom,
                       const DOMTokenListSupportedTokenArray aSupportedTokens)
 {
 #ifdef DEBUG
-  nsAtom*** props =
-    HTMLSVGPropertiesToTraverseAndUnlink();
+  nsStaticAtom*** props = HTMLSVGPropertiesToTraverseAndUnlink();
   bool found = false;
   for (uint32_t i = 0; props[i]; ++i) {
     if (*props[i] == aAtom) {
       found = true;
       break;
     }
   }
   MOZ_ASSERT(found, "Trying to use an unknown tokenlist!");
--- a/dom/base/Element.h
+++ b/dom/base/Element.h
@@ -805,34 +805,34 @@ public:
 #endif
 
   void Describe(nsAString& aOutDescription) const override;
 
   /*
    * Attribute Mapping Helpers
    */
   struct MappedAttributeEntry {
-    nsAtom** attribute;
+    nsStaticAtom** attribute;
   };
 
   /**
    * A common method where you can just pass in a list of maps to check
    * for attribute dependence. Most implementations of
    * IsAttributeMapped should use this function as a default
    * handler.
    */
   template<size_t N>
   static bool
   FindAttributeDependence(const nsAtom* aAttribute,
                           const MappedAttributeEntry* const (&aMaps)[N])
   {
     return FindAttributeDependence(aAttribute, aMaps, N);
   }
 
-  static nsAtom*** HTMLSVGPropertiesToTraverseAndUnlink();
+  static nsStaticAtom*** HTMLSVGPropertiesToTraverseAndUnlink();
 
 private:
   void DescribeAttribute(uint32_t index, nsAString& aOutDescription) const;
 
   static bool
   FindAttributeDependence(const nsAtom* aAttribute,
                           const MappedAttributeEntry* const aMaps[],
                           uint32_t aMapCount);
--- a/dom/base/FragmentOrElement.cpp
+++ b/dom/base/FragmentOrElement.cpp
@@ -1465,17 +1465,17 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Fr
 
   if (tmp->HasProperties()) {
     if (tmp->IsElement()) {
       Element* elem = tmp->AsElement();
       elem->UnlinkIntersectionObservers();
     }
 
     if (tmp->IsHTMLElement() || tmp->IsSVGElement()) {
-      nsAtom*** props = Element::HTMLSVGPropertiesToTraverseAndUnlink();
+      nsStaticAtom*** props = Element::HTMLSVGPropertiesToTraverseAndUnlink();
       for (uint32_t i = 0; props[i]; ++i) {
         tmp->DeleteProperty(*props[i]);
       }
       if (tmp->MayHaveAnimations()) {
         nsAtom** effectProps = EffectSet::GetEffectSetPropertyAtoms();
         for (uint32_t i = 0; effectProps[i]; ++i) {
           tmp->DeleteProperty(effectProps[i]);
         }
@@ -2052,17 +2052,17 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_
       if (observers) {
         for (auto iter = observers->Iter(); !iter.Done(); iter.Next()) {
           DOMIntersectionObserver* observer = iter.Key();
           cb.NoteXPCOMChild(observer);
         }
       }
     }
     if (tmp->IsHTMLElement() || tmp->IsSVGElement()) {
-      nsAtom*** props = Element::HTMLSVGPropertiesToTraverseAndUnlink();
+      nsStaticAtom*** props = Element::HTMLSVGPropertiesToTraverseAndUnlink();
       for (uint32_t i = 0; props[i]; ++i) {
         nsISupports* property =
           static_cast<nsISupports*>(tmp->GetProperty(*props[i]));
         cb.NoteXPCOMChild(property);
       }
       if (tmp->MayHaveAnimations()) {
         nsAtom** effectProps = EffectSet::GetEffectSetPropertyAtoms();
         for (uint32_t i = 0; effectProps[i]; ++i) {
--- a/dom/base/nsIContent.h
+++ b/dom/base/nsIContent.h
@@ -478,17 +478,17 @@ public:
    *                     be kNameSpaceID_Unknown.
    * @param aName The name atom of the attribute.  Must not be null.
    * @param aValues a nullptr-terminated array of pointers to atom values to test
    *                against.
    * @param aCaseSensitive Whether to do a case-sensitive compare on the values.
    * @return ATTR_MISSING, ATTR_VALUE_NO_MATCH or the non-negative index
    * indicating the first value of aValues that matched
    */
-  typedef nsAtom* const* const AttrValuesArray;
+  typedef nsStaticAtom* const* const AttrValuesArray;
   virtual int32_t FindAttrValueIn(int32_t aNameSpaceID,
                                   nsAtom* aName,
                                   AttrValuesArray* aValues,
                                   nsCaseTreatment aCaseSensitive) const
   {
     return ATTR_MISSING;
   }
 
--- a/dom/base/nsTreeSanitizer.cpp
+++ b/dom/base/nsTreeSanitizer.cpp
@@ -27,17 +27,17 @@
 #include "nsIDocument.h"
 #include "nsQueryObject.h"
 
 using namespace mozilla;
 
 //
 // Thanks to Mark Pilgrim and Sam Ruby for the initial whitelist
 //
-nsAtom** const kElementsHTML[] = {
+nsStaticAtom** const kElementsHTML[] = {
   &nsGkAtoms::a,
   &nsGkAtoms::abbr,
   &nsGkAtoms::acronym,
   &nsGkAtoms::address,
   &nsGkAtoms::area,
   &nsGkAtoms::article,
   &nsGkAtoms::aside,
   &nsGkAtoms::audio,
@@ -142,17 +142,17 @@ nsAtom** const kElementsHTML[] = {
   &nsGkAtoms::u,
   &nsGkAtoms::ul,
   &nsGkAtoms::var,
   &nsGkAtoms::video,
   &nsGkAtoms::wbr,
   nullptr
 };
 
-nsAtom** const kAttributesHTML[] = {
+nsStaticAtom** const kAttributesHTML[] = {
   &nsGkAtoms::abbr,
   &nsGkAtoms::accept,
   &nsGkAtoms::acceptcharset,
   &nsGkAtoms::accesskey,
   &nsGkAtoms::action,
   &nsGkAtoms::alt,
   &nsGkAtoms::as,
   &nsGkAtoms::autocomplete,
@@ -248,17 +248,17 @@ nsAtom** const kAttributesHTML[] = {
   &nsGkAtoms::type,
   &nsGkAtoms::usemap,
   &nsGkAtoms::value,
   &nsGkAtoms::width,
   &nsGkAtoms::wrap,
   nullptr
 };
 
-nsAtom** const kPresAttributesHTML[] = {
+nsStaticAtom** const kPresAttributesHTML[] = {
   &nsGkAtoms::align,
   &nsGkAtoms::background,
   &nsGkAtoms::bgcolor,
   &nsGkAtoms::border,
   &nsGkAtoms::cellpadding,
   &nsGkAtoms::cellspacing,
   &nsGkAtoms::color,
   &nsGkAtoms::compact,
@@ -267,27 +267,27 @@ nsAtom** const kPresAttributesHTML[] = {
   &nsGkAtoms::noshade,
   &nsGkAtoms::pointSize,
   &nsGkAtoms::size,
   &nsGkAtoms::valign,
   &nsGkAtoms::vspace,
   nullptr
 };
 
-nsAtom** const kURLAttributesHTML[] = {
+nsStaticAtom** const kURLAttributesHTML[] = {
   &nsGkAtoms::action,
   &nsGkAtoms::href,
   &nsGkAtoms::src,
   &nsGkAtoms::longdesc,
   &nsGkAtoms::cite,
   &nsGkAtoms::background,
   nullptr
 };
 
-nsAtom** const kElementsSVG[] = {
+nsStaticAtom** const kElementsSVG[] = {
   &nsGkAtoms::a, // a
   &nsGkAtoms::circle, // circle
   &nsGkAtoms::clipPath, // clipPath
   &nsGkAtoms::colorProfile, // color-profile
   &nsGkAtoms::cursor, // cursor
   &nsGkAtoms::defs, // defs
   &nsGkAtoms::desc, // desc
   &nsGkAtoms::ellipse, // ellipse
@@ -357,17 +357,17 @@ nsAtom** const kElementsSVG[] = {
   &nsGkAtoms::tref, // tref
   &nsGkAtoms::tspan, // tspan
   &nsGkAtoms::use, // use
   &nsGkAtoms::view, // view
   // vkern
   nullptr
 };
 
-nsAtom** const kAttributesSVG[] = {
+nsStaticAtom** const kAttributesSVG[] = {
   // accent-height
   &nsGkAtoms::accumulate, // accumulate
   &nsGkAtoms::additive, // additive
   &nsGkAtoms::alignment_baseline, // alignment-baseline
   // alphabetic
   &nsGkAtoms::amplitude, // amplitude
   // arabic-form
   // ascent
@@ -590,22 +590,22 @@ nsAtom** const kAttributesSVG[] = {
   &nsGkAtoms::y1, // y1
   &nsGkAtoms::y2, // y2
   &nsGkAtoms::yChannelSelector, // yChannelSelector
   &nsGkAtoms::z, // z
   &nsGkAtoms::zoomAndPan, // zoomAndPan
   nullptr
 };
 
-nsAtom** const kURLAttributesSVG[] = {
+nsStaticAtom** const kURLAttributesSVG[] = {
   &nsGkAtoms::href,
   nullptr
 };
 
-nsAtom** const kElementsMathML[] = {
+nsStaticAtom** const kElementsMathML[] = {
    &nsGkAtoms::abs_, // abs
    &nsGkAtoms::_and, // and
    &nsGkAtoms::annotation_, // annotation
    &nsGkAtoms::annotation_xml_, // annotation-xml
    &nsGkAtoms::apply_, // apply
    &nsGkAtoms::approx_, // approx
    &nsGkAtoms::arccos_, // arccos
    &nsGkAtoms::arccosh_, // arccosh
@@ -794,17 +794,17 @@ nsAtom** const kElementsMathML[] = {
    &nsGkAtoms::uplimit_, // uplimit
    &nsGkAtoms::variance_, // variance
    &nsGkAtoms::vector_, // vector
    &nsGkAtoms::vectorproduct_, // vectorproduct
    &nsGkAtoms::xor_, // xor
   nullptr
 };
 
-nsAtom** const kAttributesMathML[] = {
+nsStaticAtom** const kAttributesMathML[] = {
    &nsGkAtoms::accent_, // accent
    &nsGkAtoms::accentunder_, // accentunder
    &nsGkAtoms::actiontype_, // actiontype
    &nsGkAtoms::align, // align
    &nsGkAtoms::alignmentscope_, // alignmentscope
    &nsGkAtoms::alt, // alt
    &nsGkAtoms::altimg_, // altimg
    &nsGkAtoms::altimg_height_, // altimg-height
@@ -912,17 +912,17 @@ nsAtom** const kAttributesMathML[] = {
    &nsGkAtoms::symmetric_, // symmetric
    &nsGkAtoms::type, // type
    &nsGkAtoms::voffset_, // voffset
    &nsGkAtoms::width, // width
    &nsGkAtoms::xref_, // xref
   nullptr
 };
 
-nsAtom** const kURLAttributesMathML[] = {
+nsStaticAtom** const kURLAttributesMathML[] = {
   &nsGkAtoms::href,
   &nsGkAtoms::src,
   &nsGkAtoms::cdgroup_,
   &nsGkAtoms::altimg_,
   &nsGkAtoms::definitionURL_,
   nullptr
 };
 
@@ -990,19 +990,19 @@ nsTreeSanitizer::MustFlatten(int32_t aNa
   }
   if (aNamespace == kNameSpaceID_MathML) {
     return !sElementsMathML->GetEntry(aLocal);
   }
   return true;
 }
 
 bool
-nsTreeSanitizer::IsURL(nsAtom** const* aURLs, nsAtom* aLocalName)
+nsTreeSanitizer::IsURL(nsStaticAtom** const* aURLs, nsAtom* aLocalName)
 {
-  nsAtom** atomPtrPtr;
+  nsStaticAtom** atomPtrPtr;
   while ((atomPtrPtr = *aURLs)) {
     if (*atomPtrPtr == aLocalName) {
       return true;
     }
     ++aURLs;
   }
   return false;
 }
@@ -1158,17 +1158,17 @@ nsTreeSanitizer::SanitizeStyleSheet(cons
     }
   }
   return didSanitize;
 }
 
 void
 nsTreeSanitizer::SanitizeAttributes(mozilla::dom::Element* aElement,
                                     nsTHashtable<nsRefPtrHashKey<nsAtom>>* aAllowed,
-                                    nsAtom** const* aURLs,
+                                    nsStaticAtom** const* aURLs,
                                     bool aAllowXLink,
                                     bool aAllowStyle,
                                     bool aAllowDangerousSrc)
 {
   uint32_t ac = aElement->GetAttrCount();
 
   for (int32_t i = ac - 1; i >= 0; --i) {
     const nsAttrName* attrName = aElement->GetAttrNameAt(i);
--- a/dom/base/nsTreeSanitizer.h
+++ b/dom/base/nsTreeSanitizer.h
@@ -108,17 +108,17 @@ class MOZ_STACK_CLASS nsTreeSanitizer {
 
     /**
      * Checks if a given local name (for an attribute) is on the given list
      * of URL attribute names.
      * @param aURLs the list of URL attribute names
      * @param aLocalName the name to search on the list
      * @return true if aLocalName is on the aURLs list and false otherwise
      */
-    bool IsURL(nsAtom** const* aURLs, nsAtom* aLocalName);
+    bool IsURL(nsStaticAtom** const* aURLs, nsAtom* aLocalName);
 
     /**
      * Removes dangerous attributes from the element. If the style attribute
      * is allowed, its value is sanitized. The values of URL attributes are
      * sanitized, except src isn't sanitized when it is allowed to remain
      * potentially dangerous.
      *
      * @param aElement the element whose attributes should be sanitized
@@ -126,17 +126,17 @@ class MOZ_STACK_CLASS nsTreeSanitizer {
      * @param aURLs the local names of URL-valued attributes
      * @param aAllowXLink whether XLink attributes are allowed
      * @param aAllowStyle whether the style attribute is allowed
      * @param aAllowDangerousSrc whether to leave the value of the src
      *                           attribute unsanitized
      */
     void SanitizeAttributes(mozilla::dom::Element* aElement,
                             nsTHashtable<nsRefPtrHashKey<nsAtom>>* aAllowed,
-                            nsAtom** const* aURLs,
+                            nsStaticAtom** const* aURLs,
                             bool aAllowXLink,
                             bool aAllowStyle,
                             bool aAllowDangerousSrc);
 
     /**
      * Remove the named URL attribute from the element if the URL fails a
      * security check.
      *
--- a/dom/svg/SVGLength.cpp
+++ b/dom/svg/SVGLength.cpp
@@ -179,17 +179,17 @@ SVGLength::GetUserUnitsPerPercent(const 
     }
   }
   return std::numeric_limits<float>::quiet_NaN();
 }
 
 // Helpers:
 
 // These items must be at the same index as the nsIDOMSVGLength constants!
-static nsAtom** const unitMap[] =
+static nsStaticAtom** const unitMap[] =
 {
   nullptr, /* SVG_LENGTHTYPE_UNKNOWN */
   nullptr, /* SVG_LENGTHTYPE_NUMBER */
   &nsGkAtoms::percentage,
   &nsGkAtoms::em,
   &nsGkAtoms::ex,
   &nsGkAtoms::px,
   &nsGkAtoms::cm,
--- a/dom/svg/SVGTests.cpp
+++ b/dom/svg/SVGTests.cpp
@@ -10,17 +10,17 @@
 #include "mozilla/dom/SVGSwitchElement.h"
 #include "nsCharSeparatedTokenizer.h"
 #include "nsStyleUtil.h"
 #include "mozilla/Preferences.h"
 
 namespace mozilla {
 namespace dom {
 
-nsAtom** SVGTests::sStringListNames[3] =
+nsStaticAtom** SVGTests::sStringListNames[3] =
 {
   &nsGkAtoms::requiredFeatures,
   &nsGkAtoms::requiredExtensions,
   &nsGkAtoms::systemLanguage,
 };
 
 SVGTests::SVGTests()
 {
--- a/dom/svg/SVGTests.h
+++ b/dom/svg/SVGTests.h
@@ -8,16 +8,17 @@
 #define mozilla_dom_SVGTests_h
 
 #include "nsStringFwd.h"
 #include "SVGStringList.h"
 #include "nsCOMPtr.h"
 
 class nsAttrValue;
 class nsAtom;
+class nsStaticAtom;
 
 namespace mozilla {
 class DOMSVGStringList;
 
 #define MOZILLA_DOMSVGTESTS_IID \
    { 0x92370da8, 0xda28, 0x4895, \
      {0x9b, 0x1b, 0xe0, 0x06, 0x0d, 0xb7, 0x3f, 0xc3 } }
 
@@ -97,17 +98,17 @@ public:
   virtual bool IsInChromeDoc() const = 0;
 
 protected:
   virtual ~SVGTests() {}
 
 private:
   enum { FEATURES, EXTENSIONS, LANGUAGE };
   SVGStringList mStringListAttributes[3];
-  static nsAtom** sStringListNames[3];
+  static nsStaticAtom** sStringListNames[3];
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(SVGTests, MOZILLA_DOMSVGTESTS_IID)
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_SVGTests_h
--- a/dom/svg/SVGTransformListParser.cpp
+++ b/dom/svg/SVGTransformListParser.cpp
@@ -63,17 +63,17 @@ SVGTransformListParser::ParseTransform()
   }
 
   if (start == mIter) {
     // Didn't read anything
     return false;
   }
 
   const nsAString& transform = Substring(start.get(), mIter.get());
-  nsAtom* keyAtom = NS_GetStaticAtom(transform);
+  nsStaticAtom* keyAtom = NS_GetStaticAtom(transform);
 
   if (!keyAtom || !SkipWsp()) {
     return false;
   }
 
   if (keyAtom == nsGkAtoms::translate) {
     return ParseTranslate();
   }
--- a/dom/svg/nsSVGAngle.cpp
+++ b/dom/svg/nsSVGAngle.cpp
@@ -15,17 +15,17 @@
 #include "nsTextFormatter.h"
 #include "SVGAngle.h"
 #include "SVGAnimatedAngle.h"
 #include "SVGOrientSMILType.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
-static nsAtom** const unitMap[] =
+static nsStaticAtom** const unitMap[] =
 {
   nullptr, /* SVG_ANGLETYPE_UNKNOWN */
   nullptr, /* SVG_ANGLETYPE_UNSPECIFIED */
   &nsGkAtoms::deg,
   &nsGkAtoms::rad,
   &nsGkAtoms::grad
 };
 
@@ -62,17 +62,17 @@ GetUnitString(nsAString& unit, uint16_t 
 }
 
 static uint16_t
 GetUnitTypeForString(const nsAString& unitStr)
 {
   if (unitStr.IsEmpty())
     return SVG_ANGLETYPE_UNSPECIFIED;
 
-  nsAtom *unitAtom = NS_GetStaticAtom(unitStr);
+  nsStaticAtom* unitAtom = NS_GetStaticAtom(unitStr);
 
   if (unitAtom) {
     for (uint32_t i = 0 ; i < ArrayLength(unitMap) ; i++) {
       if (unitMap[i] && *unitMap[i] == unitAtom) {
         return i;
       }
     }
   }
--- a/dom/svg/nsSVGElement.h
+++ b/dom/svg/nsSVGElement.h
@@ -365,17 +365,17 @@ protected:
   // !StoresOwnData.
   void DidChangeValue(nsAtom* aName, const nsAttrValue& aEmptyOrOldValue,
                       nsAttrValue& aNewValue);
   void MaybeSerializeAttrBeforeRemoval(nsAtom* aName, bool aNotify);
 
   static nsAtom* GetEventNameForAttr(nsAtom* aAttr);
 
   struct LengthInfo {
-    nsAtom** mName;
+    nsStaticAtom** mName;
     float     mDefaultValue;
     uint8_t   mDefaultUnitType;
     uint8_t   mCtxType;
   };
 
   struct LengthAttributesInfo {
     nsSVGLength2* mLengths;
     LengthInfo*   mLengthInfo;
@@ -386,17 +386,17 @@ protected:
                          uint32_t aLengthCount) :
       mLengths(aLengths), mLengthInfo(aLengthInfo), mLengthCount(aLengthCount)
       {}
 
     void Reset(uint8_t aAttrEnum);
   };
 
   struct NumberInfo {
-    nsAtom** mName;
+    nsStaticAtom** mName;
     float     mDefaultValue;
     bool mPercentagesAllowed;
   };
 
   struct NumberAttributesInfo {
     nsSVGNumber2* mNumbers;
     NumberInfo*   mNumberInfo;
     uint32_t      mNumberCount;
@@ -406,17 +406,17 @@ protected:
                          uint32_t aNumberCount) :
       mNumbers(aNumbers), mNumberInfo(aNumberInfo), mNumberCount(aNumberCount)
       {}
 
     void Reset(uint8_t aAttrEnum);
   };
 
   struct NumberPairInfo {
-    nsAtom** mName;
+    nsStaticAtom** mName;
     float     mDefaultValue1;
     float     mDefaultValue2;
   };
 
   struct NumberPairAttributesInfo {
     nsSVGNumberPair* mNumberPairs;
     NumberPairInfo*  mNumberPairInfo;
     uint32_t         mNumberPairCount;
@@ -427,17 +427,17 @@ protected:
       mNumberPairs(aNumberPairs), mNumberPairInfo(aNumberPairInfo),
       mNumberPairCount(aNumberPairCount)
       {}
 
     void Reset(uint8_t aAttrEnum);
   };
 
   struct IntegerInfo {
-    nsAtom** mName;
+    nsStaticAtom** mName;
     int32_t   mDefaultValue;
   };
 
   struct IntegerAttributesInfo {
     nsSVGInteger* mIntegers;
     IntegerInfo*  mIntegerInfo;
     uint32_t      mIntegerCount;
 
@@ -446,17 +446,17 @@ protected:
                           uint32_t aIntegerCount) :
       mIntegers(aIntegers), mIntegerInfo(aIntegerInfo), mIntegerCount(aIntegerCount)
       {}
 
     void Reset(uint8_t aAttrEnum);
   };
 
   struct IntegerPairInfo {
-    nsAtom** mName;
+    nsStaticAtom** mName;
     int32_t   mDefaultValue1;
     int32_t   mDefaultValue2;
   };
 
   struct IntegerPairAttributesInfo {
     nsSVGIntegerPair* mIntegerPairs;
     IntegerPairInfo*  mIntegerPairInfo;
     uint32_t          mIntegerPairCount;
@@ -467,17 +467,17 @@ protected:
       mIntegerPairs(aIntegerPairs), mIntegerPairInfo(aIntegerPairInfo),
       mIntegerPairCount(aIntegerPairCount)
       {}
 
     void Reset(uint8_t aAttrEnum);
   };
 
   struct AngleInfo {
-    nsAtom** mName;
+    nsStaticAtom** mName;
     float     mDefaultValue;
     uint8_t   mDefaultUnitType;
   };
 
   struct AngleAttributesInfo {
     nsSVGAngle* mAngles;
     AngleInfo*  mAngleInfo;
     uint32_t    mAngleCount;
@@ -487,17 +487,17 @@ protected:
                         uint32_t aAngleCount) :
       mAngles(aAngles), mAngleInfo(aAngleInfo), mAngleCount(aAngleCount)
       {}
 
     void Reset(uint8_t aAttrEnum);
   };
 
   struct BooleanInfo {
-    nsAtom**    mName;
+    nsStaticAtom** mName;
     bool mDefaultValue;
   };
 
   struct BooleanAttributesInfo {
     nsSVGBoolean* mBooleans;
     BooleanInfo*  mBooleanInfo;
     uint32_t      mBooleanCount;
 
@@ -508,17 +508,17 @@ protected:
       {}
 
     void Reset(uint8_t aAttrEnum);
   };
 
   friend class nsSVGEnum;
 
   struct EnumInfo {
-    nsAtom**         mName;
+    nsStaticAtom**    mName;
     nsSVGEnumMapping* mMapping;
     uint16_t          mDefaultValue;
   };
 
   struct EnumAttributesInfo {
     nsSVGEnum* mEnums;
     EnumInfo*  mEnumInfo;
     uint32_t   mEnumCount;
@@ -528,17 +528,17 @@ protected:
                        uint32_t aEnumCount) :
       mEnums(aEnums), mEnumInfo(aEnumInfo), mEnumCount(aEnumCount)
       {}
 
     void Reset(uint8_t aAttrEnum);
   };
 
   struct NumberListInfo {
-    nsAtom** mName;
+    nsStaticAtom** mName;
   };
 
   struct NumberListAttributesInfo {
     SVGAnimatedNumberList* mNumberLists;
     NumberListInfo*        mNumberListInfo;
     uint32_t               mNumberListCount;
 
     NumberListAttributesInfo(SVGAnimatedNumberList *aNumberLists,
@@ -548,17 +548,17 @@ protected:
       , mNumberListInfo(aNumberListInfo)
       , mNumberListCount(aNumberListCount)
     {}
 
     void Reset(uint8_t aAttrEnum);
   };
 
   struct LengthListInfo {
-    nsAtom** mName;
+    nsStaticAtom** mName;
     uint8_t   mAxis;
     /**
      * Flag to indicate whether appending zeros to the end of the list would
      * change the rendering of the SVG for the attribute in question. For x and
      * y on the <text> element this is true, but for dx and dy on <text> this
      * is false. This flag is fed down to SVGLengthListSMILType so it can
      * determine if it can sensibly animate from-to lists of different lengths,
      * which is desirable in the case of dx and dy.
@@ -578,17 +578,17 @@ protected:
       , mLengthListInfo(aLengthListInfo)
       , mLengthListCount(aLengthListCount)
     {}
 
     void Reset(uint8_t aAttrEnum);
   };
 
   struct StringInfo {
-    nsAtom**    mName;
+    nsStaticAtom** mName;
     int32_t      mNamespaceID;
     bool mIsAnimatable;
   };
 
   struct StringAttributesInfo {
     nsSVGString*  mStrings;
     StringInfo*   mStringInfo;
     uint32_t      mStringCount;
@@ -600,17 +600,17 @@ protected:
       {}
 
     void Reset(uint8_t aAttrEnum);
   };
 
   friend class mozilla::DOMSVGStringList;
 
   struct StringListInfo {
-    nsAtom**    mName;
+    nsStaticAtom** mName;
   };
 
   struct StringListAttributesInfo {
     SVGStringList*    mStringLists;
     StringListInfo*   mStringListInfo;
     uint32_t          mStringListCount;
 
     StringListAttributesInfo(SVGStringList  *aStringLists,
--- a/dom/svg/nsSVGEnum.h
+++ b/dom/svg/nsSVGEnum.h
@@ -22,17 +22,17 @@ namespace mozilla {
 namespace dom {
 class SVGAnimationElement;
 } // namespace dom
 } // namespace mozilla
 
 typedef uint8_t nsSVGEnumValue;
 
 struct nsSVGEnumMapping {
-  nsAtom **mKey;
+  nsStaticAtom** mKey;
   nsSVGEnumValue mVal;
 };
 
 class nsSVGEnum
 {
 public:
   void Init(uint8_t aAttrEnum, uint16_t aValue) {
     mAnimVal = mBaseVal = uint8_t(aValue);
--- a/dom/svg/nsSVGLength2.cpp
+++ b/dom/svg/nsSVGLength2.cpp
@@ -17,17 +17,17 @@
 #include "nsSVGIntegrationUtils.h"
 #include "nsTextFormatter.h"
 #include "DOMSVGLength.h"
 #include "LayoutLogging.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
-static nsAtom** const unitMap[] =
+static nsStaticAtom** const unitMap[] =
 {
   nullptr, /* SVG_LENGTHTYPE_UNKNOWN */
   nullptr, /* SVG_LENGTHTYPE_NUMBER */
   &nsGkAtoms::percentage,
   &nsGkAtoms::em,
   &nsGkAtoms::ex,
   &nsGkAtoms::px,
   &nsGkAtoms::cm,
--- a/dom/xslt/xpath/txCoreFunctionCall.cpp
+++ b/dom/xslt/xpath/txCoreFunctionCall.cpp
@@ -19,17 +19,17 @@
 
 using namespace mozilla;
 
 struct txCoreFunctionDescriptor
 {
     int8_t mMinParams;
     int8_t mMaxParams;
     Expr::ResultType mReturnType;
-    nsAtom** mName;
+    nsStaticAtom** mName;
 };
 
 // This must be ordered in the same order as txCoreFunctionCall::eType.
 // If you change one, change the other.
 static const txCoreFunctionDescriptor descriptTable[] =
 {
     { 1, 1, Expr::NUMBER_RESULT,  &nsGkAtoms::count }, // COUNT
     { 1, 1, Expr::NODESET_RESULT, &nsGkAtoms::id }, // ID
--- a/dom/xslt/xslt/txEXSLTFunctions.cpp
+++ b/dom/xslt/xslt/txEXSLTFunctions.cpp
@@ -164,17 +164,17 @@ static const char * const sTypes[] = {
 // ------------------------------------------------------------------
 
 struct txEXSLTFunctionDescriptor
 {
     int8_t mMinParams;
     int8_t mMaxParams;
     Expr::ResultType mReturnType;
     int32_t mNamespaceID;
-    nsAtom** mName;
+    nsStaticAtom** mName;
     const char* mNamespaceURI;
 };
 
 static const char kEXSLTCommonNS[] = "http://exslt.org/common";
 static const char kEXSLTSetsNS[] = "http://exslt.org/sets";
 static const char kEXSLTStringsNS[] = "http://exslt.org/strings";
 static const char kEXSLTMathNS[] = "http://exslt.org/math";
 static const char kEXSLTDatesAndTimesNS[] = "http://exslt.org/dates-and-times";
--- a/dom/xul/XULDocument.h
+++ b/dom/xul/XULDocument.h
@@ -284,18 +284,16 @@ protected:
 
     already_AddRefed<nsPIWindowRoot> GetWindowRoot();
 
     static void DirectionChanged(const char* aPrefName, void* aData);
 
     // pseudo constants
     static int32_t gRefCnt;
 
-    static nsAtom** kIdentityAttrs[];
-
     static nsIRDFService* gRDFService;
     static nsIRDFResource* kNC_persist;
     static nsIRDFResource* kNC_attribute;
     static nsIRDFResource* kNC_value;
 
     static LazyLogModule gXULLog;
 
     nsresult
--- a/layout/base/nsCSSFrameConstructor.h
+++ b/layout/base/nsCSSFrameConstructor.h
@@ -776,19 +776,19 @@ private:
     nsICSSAnonBoxPseudo * const * const mAnonBoxPseudo;
   };
 
   /* Structure representing a mapping of an atom to a FrameConstructionData.
      This can be used with non-static atoms, assuming that the nsAtom* is
      stored somewhere that this struct can point to (that is, a static
      nsAtom*) and that it's allocated before the struct is ever used. */
   struct FrameConstructionDataByTag {
-    // Pointer to nsAtom* is used because we want to initialize this
+    // Pointer to nsStaticAtom* is used because we want to initialize this
     // statically, so before our atom tables are set up.
-    const nsAtom * const * const mTag;
+    const nsStaticAtom * const * const mTag;
     const FrameConstructionData mData;
   };
 
   /* Structure representing a mapping of an integer to a
      FrameConstructionData. There are no magic integer values here. */
   struct FrameConstructionDataByInt {
     /* Could be used for display or whatever else */
     const int32_t mInt;
--- a/layout/style/CounterStyleManager.cpp
+++ b/layout/style/CounterStyleManager.cpp
@@ -570,23 +570,23 @@ SystemUsesNegativeSign(uint8_t aSystem)
     default:
       return false;
   }
 }
 
 class BuiltinCounterStyle : public CounterStyle
 {
 public:
-  constexpr BuiltinCounterStyle(int32_t aStyle, nsAtom** aName)
+  constexpr BuiltinCounterStyle(int32_t aStyle, nsStaticAtom** aName)
     : CounterStyle(aStyle)
     , mName(aName)
   {
   }
 
-  virtual nsAtom* GetStyleName() const final;
+  virtual nsStaticAtom* GetStyleName() const final;
   virtual void GetPrefix(nsAString& aResult) override;
   virtual void GetSuffix(nsAString& aResult) override;
   virtual void GetSpokenCounterText(CounterValue aOrdinal,
                                     WritingMode aWritingMode,
                                     nsAString& aResult,
                                     bool& aIsBullet) override;
   virtual bool IsBullet() override;
 
@@ -610,20 +610,20 @@ protected:
   {
   }
 
 private:
   // The atom for the name of the builtin counter style.
   // Extra indirection to point to nsGkAtoms members rather than the
   // nsAtom, because members of nsGkAtoms are updated at runtime but
   // we want to construct BuiltinCounterStyle at compile time.
-  nsAtom** const mName;
+  nsStaticAtom** const mName;
 };
 
-/* virtual */ nsAtom*
+/* virtual */ nsStaticAtom*
 BuiltinCounterStyle::GetStyleName() const
 {
   return *mName;
 }
 
 /* virtual */ void
 BuiltinCounterStyle::GetPrefix(nsAString& aResult)
 {
--- a/layout/style/nsCSSParser.cpp
+++ b/layout/style/nsCSSParser.cpp
@@ -7954,17 +7954,18 @@ CSSParserImpl::ParseCounter(nsCSSValue& 
     // get optional type
     int32_t typeItem = eCSSUnit_Counters == unit ? 2 : 1;
     nsCSSValue& type = val->Item(typeItem);
     if (ExpectSymbol(',', true)) {
       if (!ParseCounterStyleNameValue(type) && !ParseSymbols(type)) {
         break;
       }
     } else {
-      type.SetAtomIdentValue(do_AddRef(nsGkAtoms::decimal));
+      type.SetAtomIdentValue(
+        do_AddRef(static_cast<nsAtom*>(nsGkAtoms::decimal)));
     }
 
     if (!ExpectSymbol(')', true)) {
       break;
     }
 
     aValue.SetArrayValue(val, unit);
     return true;
--- a/layout/style/nsMediaFeatures.h
+++ b/layout/style/nsMediaFeatures.h
@@ -17,17 +17,17 @@ class nsCSSValue;
 
 struct nsMediaFeature;
 typedef void (*nsMediaFeatureValueGetter)(nsPresContext* aPresContext,
                                           const nsMediaFeature* aFeature,
                                           nsCSSValue& aResult);
 
 struct nsMediaFeature
 {
-  nsAtom **mName; // extra indirection to point to nsGkAtoms members
+  nsStaticAtom** mName; // extra indirection to point to nsGkAtoms members
 
   enum RangeType { eMinMaxAllowed, eMinMaxNotAllowed };
   RangeType mRangeType;
 
   enum ValueType {
     // All value types allow eCSSUnit_Null to indicate that no value
     // was given (in addition to the types listed below).
     eLength,     // values are eCSSUnit_Pixel
--- a/parser/html/nsHtml5AtomTable.cpp
+++ b/parser/html/nsHtml5AtomTable.cpp
@@ -45,17 +45,17 @@ nsHtml5AtomTable::GetAtom(const nsAStrin
 #endif
 
   uint32_t index = mozilla::HashString(aKey) % RECENTLY_USED_PARSER_ATOMS_SIZE;
   nsAtom* cachedAtom = mRecentlyUsedParserAtoms[index];
   if (cachedAtom && cachedAtom->Equals(aKey)) {
     return cachedAtom;
   }
 
-  nsAtom* atom = NS_GetStaticAtom(aKey);
+  nsStaticAtom* atom = NS_GetStaticAtom(aKey);
   if (atom) {
     mRecentlyUsedParserAtoms[index] = atom;
     return atom;
   }
   nsHtml5AtomEntry* entry = mTable.PutEntry(aKey);
   if (!entry) {
     return nullptr;
   }
--- a/parser/htmlparser/nsHTMLTags.cpp
+++ b/parser/htmlparser/nsHTMLTags.cpp
@@ -48,17 +48,17 @@ static PLHashNumber
 HTMLTagsHashCodeAtom(const void *key)
 {
   return NS_PTR_TO_INT32(key) >> 2;
 }
 
 #define NS_HTMLTAG_NAME_MAX_LENGTH 10
 
 // This would use NS_STATIC_ATOM_DEFN if it wasn't an array.
-nsAtom* nsHTMLTags::sTagAtomTable[eHTMLTag_userdefined - 1];
+nsStaticAtom* nsHTMLTags::sTagAtomTable[eHTMLTag_userdefined - 1];
 
 #define HTML_TAG(_tag, _classname, _interfacename) \
   NS_STATIC_ATOM_BUFFER(_tag, #_tag)
 #define HTML_OTHER(_tag)
 #include "nsHTMLTagList.h"
 #undef HTML_TAG
 #undef HTML_OTHER
 
--- a/parser/htmlparser/nsHTMLTags.h
+++ b/parser/htmlparser/nsHTMLTags.h
@@ -71,17 +71,17 @@ public:
   }
 
 #ifdef DEBUG
   static void TestTagTable();
 #endif
 
 private:
   // This would use NS_STATIC_ATOM_DECL if it wasn't an array.
-  static nsAtom* sTagAtomTable[eHTMLTag_userdefined - 1];
+  static nsStaticAtom* sTagAtomTable[eHTMLTag_userdefined - 1];
   static const char16_t* const sTagUnicodeTable[];
 
   static int32_t gTableRefCount;
   static PLHashTable* gTagTable;
   static PLHashTable* gTagAtomTable;
 };
 
 #endif /* nsHTMLTags_h___ */
--- a/xpcom/ds/nsAtom.h
+++ b/xpcom/ds/nsAtom.h
@@ -6,19 +6,16 @@
 
 #ifndef nsAtom_h
 #define nsAtom_h
 
 #include "nsISupportsImpl.h"
 #include "nsString.h"
 #include "nsStringBuffer.h"
 
-// This class would be |final| if it wasn't for nsICSSAnonBoxPseudo and
-// nsICSSPseudoElement, which are trivial subclasses used to ensure only
-// certain atoms are passed to certain functions.
 class nsAtom
 {
 public:
   size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
 
   enum class AtomKind : uint8_t {
     DynamicAtom = 0,
     StaticAtom = 1,
@@ -80,34 +77,59 @@ public:
   MozExternalRefCountType Release();
 
   typedef mozilla::TrueType HasThreadSafeRefCnt;
 
 private:
   friend class nsAtomFriend;
   friend class nsHtml5AtomEntry;
 
-  // Construction and destruction is done entirely by |friend|s.
+  // Dynamic atom construction is done by |friend|s.
   nsAtom(AtomKind aKind, const nsAString& aString, uint32_t aHash);
+
+protected:
   nsAtom(const char16_t* aString, uint32_t aLength, uint32_t aHash);
-protected:
+
   ~nsAtom();
 
-private:
   mozilla::ThreadSafeAutoRefCnt mRefCnt;
   uint32_t mLength: 30;
   uint32_t mKind: 2; // nsAtom::AtomKind
   uint32_t mHash;
   // WARNING! For static atoms, this is a pointer to a static char buffer. For
   // non-static atoms it points to the chars in an nsStringBuffer. This means
   // that nsStringBuffer::FromData(mString) calls are only valid for non-static
   // atoms.
   char16_t* mString;
 };
 
+// A trivial subclass of nsAtom that can be used for known static atoms. The
+// main advantage of this class is that it doesn't require refcounting, so you
+// can use |nsStaticAtom*| in contrast with |RefPtr<nsAtom>|.
+//
+// This class would be |final| if it wasn't for nsICSSAnonBoxPseudo and
+// nsICSSPseudoElement, which are trivial subclasses used to ensure only
+// certain atoms are passed to certain functions.
+class nsStaticAtom : public nsAtom
+{
+public:
+  // These are deleted so it's impossible to RefPtr<nsStaticAtom>. Raw
+  // nsStaticAtom atoms should be used instead.
+  MozExternalRefCountType AddRef() = delete;
+  MozExternalRefCountType Release() = delete;
+
+private:
+  friend class nsAtomFriend;
+
+  // Construction is done entirely by |friend|s.
+  nsStaticAtom(const char16_t* aString, uint32_t aLength, uint32_t aHash)
+    : nsAtom(aString, aLength, aHash)
+  {}
+};
+
 // The four forms of NS_Atomize (for use with |RefPtr<nsAtom>|) return the
 // atom for the string given. At any given time there will always be one atom
 // representing a given string. Atoms are intended to make string comparison
 // cheaper by simplifying it to pointer equality. A pointer to the atom that
 // does not own a reference is not guaranteed to be valid.
 
 // Find an atom that matches the given UTF-8 string. The string is assumed to
 // be zero terminated. Never returns null.
@@ -126,17 +148,17 @@ already_AddRefed<nsAtom> NS_Atomize(cons
 // An optimized version of the method above for the main thread.
 already_AddRefed<nsAtom> NS_AtomizeMainThread(const nsAString& aUTF16String);
 
 // Return a count of the total number of atoms currently alive in the system.
 nsrefcnt NS_GetNumberOfAtoms();
 
 // Return a pointer for a static atom for the string or null if there's no
 // static atom for this string.
-nsAtom* NS_GetStaticAtom(const nsAString& aUTF16String);
+nsStaticAtom* NS_GetStaticAtom(const nsAString& aUTF16String);
 
 // Seal the static atom table.
 void NS_SealStaticAtomTable();
 
 class nsAtomString : public nsString
 {
 public:
   explicit nsAtomString(const nsAtom* aAtom) { aAtom->ToString(*this); }
--- a/xpcom/ds/nsAtomTable.cpp
+++ b/xpcom/ds/nsAtomTable.cpp
@@ -450,17 +450,17 @@ public:
   {
     return HashString(*aKey);
   }
 
   enum { ALLOW_MEMMOVE = true };
 
   // Static atoms aren't really refcounted. Because these entries live in a
   // global hashtable, this reference is essentially owning.
-  nsAtom* MOZ_OWNING_REF mAtom;
+  nsStaticAtom* MOZ_OWNING_REF mAtom;
 };
 
 /**
  * A hashtable of static atoms that existed at app startup. This hashtable
  * helps nsHtml5AtomTable.
  */
 typedef nsTHashtable<StaticAtomEntry> StaticAtomTable;
 static StaticAtomTable* gStaticAtomTable = nullptr;
@@ -581,39 +581,40 @@ nsAtomFriend::RegisterStaticAtoms(const 
                      "Atom table has already been sealed!");
 
   if (!gStaticAtomTable) {
     gStaticAtomTable = new StaticAtomTable();
   }
 
   for (uint32_t i = 0; i < aCount; ++i) {
     const char16_t* string = aSetup[i].mString;
-    nsAtom** atomp = aSetup[i].mAtom;
+    nsStaticAtom** atomp = aSetup[i].mAtom;
 
     MOZ_ASSERT(nsCRT::IsAscii(string));
 
     uint32_t stringLen = NS_strlen(string);
 
     uint32_t hash;
     AtomTableEntry* he = GetAtomHashEntry(string, stringLen, &hash);
 
-    nsAtom* atom = he->mAtom;
-    if (atom) {
+    nsStaticAtom* atom;
+    if (he->mAtom) {
       // Disallow creating a dynamic atom, and then later, while the
       // dynamic atom is still alive, registering that same atom as a
       // static atom.  It causes subtle bugs, and we're programming in
       // C++ here, not Smalltalk.
-      if (!atom->IsStaticAtom()) {
+      if (!he->mAtom->IsStaticAtom()) {
         nsAutoCString name;
-        atom->ToUTF8String(name);
+        he->mAtom->ToUTF8String(name);
         MOZ_CRASH_UNSAFE_PRINTF(
           "Static atom registration for %s should be pushed back", name.get());
       }
+      atom = static_cast<nsStaticAtom*>(he->mAtom);
     } else {
-      atom = new nsAtom(string, stringLen, hash);
+      atom = new nsStaticAtom(string, stringLen, hash);
       he->mAtom = atom;
     }
     *atomp = atom;
 
     if (!gStaticAtomTableSealed) {
       StaticAtomEntry* entry =
         gStaticAtomTable->PutEntry(nsDependentAtomString(atom));
       MOZ_ASSERT(atom->IsStaticAtom());
@@ -752,17 +753,17 @@ NS_GetNumberOfAtoms(void)
 }
 
 int32_t
 NS_GetUnusedAtomCount(void)
 {
   return gUnusedAtomCount;
 }
 
-nsAtom*
+nsStaticAtom*
 NS_GetStaticAtom(const nsAString& aUTF16String)
 {
   NS_PRECONDITION(gStaticAtomTable, "Static atom table not created yet.");
   NS_PRECONDITION(gStaticAtomTableSealed, "Static atom table not sealed yet.");
   StaticAtomEntry* entry = gStaticAtomTable->GetEntry(aUTF16String);
   return entry ? entry->mAtom : nullptr;
 }
 
--- a/xpcom/ds/nsStaticAtom.h
+++ b/xpcom/ds/nsStaticAtom.h
@@ -4,17 +4,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef nsStaticAtom_h__
 #define nsStaticAtom_h__
 
 #include <stdint.h>
 
-class nsAtom;
+class nsStaticAtom;
 
 // The following macros are used to define static atoms, typically in
 // conjunction with a .h file that defines the names and values of the atoms.
 //
 // For example, the .h file might be called MyAtomList.h and look like this:
 //
 //   MY_ATOM(one, "one")
 //   MY_ATOM(two, "two")
@@ -43,82 +43,82 @@ class nsAtom;
 //     #undef MY_ATOM
 //   };
 //
 // The macros expand to the following:
 //
 //   class MyAtoms
 //   {
 //   public:
-//     static nsAtom* one;
-//     static nsAtom* two;
-//     static nsAtom* three;
+//     static nsStaticAtom* one;
+//     static nsStaticAtom* two;
+//     static nsStaticAtom* three;
 //   };
 //
-//   nsAtom* MyAtoms::one;
-//   nsAtom* MyAtoms::two;
-//   nsAtom* MyAtoms::three;
+//   nsStaticAtom* MyAtoms::one;
+//   nsStaticAtom* MyAtoms::two;
+//   nsStaticAtom* MyAtoms::three;
 //
 //   static const char16_t one_buffer[4] = u"one";     // plus a static_assert
 //   static const char16_t two_buffer[4] = u"two";     // plus a static_assert
 //   static const char16_t three_buffer[6] = u"three"; // plus a static_assert
 //
 //   static const nsStaticAtomSetup sMyAtomSetup[] = {
 //     { one_buffer, &MyAtoms::one },
 //     { two_buffer, &MyAtoms::two },
 //     { three_buffer, &MyAtoms::three },
 //   };
 //
 // When RegisterStaticAtoms(sMyAtomSetup) is called it iterates over
 // sMyAtomSetup[]. E.g. for the first atom it does roughly the following:
-// - MyAtoms::one = new nsAtom(one_buffer)
+// - MyAtoms::one = new nsStaticAtom(one_buffer)
 // - inserts MyAtoms::one into the atom table
 
 // The declaration of the pointer to the static atom, which must be within a
 // class.
 #define NS_STATIC_ATOM_DECL(name_) \
-  static nsAtom* name_;
+  static nsStaticAtom* name_;
 
-// Like NS_STATIC_ATOM_DECL, but for sub-classes of nsAtom.
+// Like NS_STATIC_ATOM_DECL, but for sub-classes of nsStaticAtom.
 #define NS_STATIC_ATOM_SUBCLASS_DECL(type_, name_) \
   static type_* name_;
 
 // The definition of the pointer to the static atom. Initially null, it is
-// set by RegisterStaticAtoms() to point to a heap-allocated nsAtom.
+// set by RegisterStaticAtoms() to point to a heap-allocated nsStaticAtom.
 #define NS_STATIC_ATOM_DEFN(class_, name_) \
-  nsAtom* class_::name_;
+  nsStaticAtom* class_::name_;
 
-// Like NS_STATIC_ATOM_DEFN, but for sub-classes of nsAtom.
+// Like NS_STATIC_ATOM_DEFN, but for sub-classes of nsStaticAtom.
 #define NS_STATIC_ATOM_SUBCLASS_DEFN(type_, class_, name_) \
   type_* class_::name_;
 
 // The buffer of 16-bit chars that constitute the static atom.
 //
 // Note that |value_| is an 8-bit string, and so |sizeof(value_)| is equal
 // to the number of chars (including the terminating '\0'). The |u""| prefix
 // converts |value_| to a 16-bit string, which is what is assigned.
 #define NS_STATIC_ATOM_BUFFER(name_, value_) \
   static const char16_t name_##_buffer[sizeof(value_)] = u"" value_; \
   static_assert(sizeof(value_[0]) == 1, "non-8-bit static atom literal");
 
 // The StaticAtomSetup. Used only during start-up.
 #define NS_STATIC_ATOM_SETUP(class_, name_) \
   { name_##_buffer, &class_::name_ },
 
-// Like NS_STATIC_ATOM_SUBCLASS, but for sub-classes of nsAtom.
+// Like NS_STATIC_ATOM_SUBCLASS, but for sub-classes of nsStaticAtom.
 #define NS_STATIC_ATOM_SUBCLASS_SETUP(class_, name_) \
-  { name_##_buffer, reinterpret_cast<nsAtom**>(&class_::name_) },
+  { name_##_buffer, reinterpret_cast<nsStaticAtom**>(&class_::name_) },
 
 // Holds data used to initialize large number of atoms during startup. Use
 // NS_STATIC_ATOM_SETUP to initialize these structs. They should never be
 // accessed directly other than from nsAtomTable.cpp.
 struct nsStaticAtomSetup
 {
   const char16_t* const mString;
-  nsAtom** const mAtom;
+  nsStaticAtom** const mAtom;
 };
 
 // Register an array of static atoms with the atom table.
 template<uint32_t N>
 void
 NS_RegisterStaticAtoms(const nsStaticAtomSetup (&aSetup)[N])
 {
   extern void RegisterStaticAtoms(const nsStaticAtomSetup* aSetup,