Bug 1355769 - Avoid malloc for nsHtml5ElementName when processing a non-interned element name. draft
authorHenri Sivonen <hsivonen@hsivonen.fi>
Wed, 12 Apr 2017 13:21:03 +0300
changeset 561918 67124240ada5193091af72bbd9cbe8fe9bbf2dd4
parent 561255 79ae719327d59e01326d79bdedff3282f638befe
child 561922 00cce9274df5d7f6f36620edfc9570ec950b35f3
child 563996 6a671da55d638b1f8be0e126123b91bb36395f22
child 563997 db82104252623c8b5cbedb983fbac6e5c735afa7
push id53895
push userbmo:hsivonen@hsivonen.fi
push dateThu, 13 Apr 2017 08:30:48 +0000
bugs1355769
milestone55.0a1
Bug 1355769 - Avoid malloc for nsHtml5ElementName when processing a non-interned element name. MozReview-Commit-ID: 4In5wo0flOB
parser/html/javasrc/ElementName.java
parser/html/javasrc/StackNode.java
parser/html/javasrc/Tokenizer.java
parser/html/javasrc/TreeBuilder.java
parser/html/moz.build
parser/html/nsHtml5ElementName.cpp
parser/html/nsHtml5ElementName.h
parser/html/nsHtml5ReleasableElementName.cpp
parser/html/nsHtml5ReleasableElementName.h
parser/html/nsHtml5StackNode.cpp
parser/html/nsHtml5StackNode.h
parser/html/nsHtml5Tokenizer.cpp
parser/html/nsHtml5Tokenizer.h
parser/html/nsHtml5TreeBuilder.cpp
--- a/parser/html/javasrc/ElementName.java
+++ b/parser/html/javasrc/ElementName.java
@@ -23,34 +23,33 @@
 package nu.validator.htmlparser.impl;
 
 import java.util.Arrays;
 
 import nu.validator.htmlparser.annotation.Inline;
 import nu.validator.htmlparser.annotation.Local;
 import nu.validator.htmlparser.annotation.NoLength;
 import nu.validator.htmlparser.annotation.Unsigned;
-import nu.validator.htmlparser.annotation.Virtual;
 import nu.validator.htmlparser.common.Interner;
 
 public final class ElementName
 // uncomment when regenerating self
 //        implements Comparable<ElementName>
 {
 
     /**
      * The mask for extracting the dispatch group.
      */
     public static final int GROUP_MASK = 127;
 
     /**
      * Indicates that the element is not a pre-interned element. Forbidden
      * on preinterned elements.
      */
-    public static final int CUSTOM = (1 << 30);
+    public static final int NOT_INTERNED = (1 << 30);
 
     /**
      * Indicates that the element is in the "special" category. This bit
      * should not be pre-set on MathML or SVG specials--only on HTML specials.
      */
     public static final int SPECIAL = (1 << 29);
 
     /**
@@ -80,50 +79,55 @@ public final class ElementName
      */
     public static final int HTML_INTEGRATION_POINT = (1 << 24);
 
     /**
      * The element has an optional end tag.
      */
     public static final int OPTIONAL_END_TAG = (1 << 23);
 
-    public static final ElementName NULL_ELEMENT_NAME = new ElementName(null);
+    private @Local String name;
 
-    public final @Local String name;
-
-    public final @Local String camelCaseName;
+    private @Local String camelCaseName;
 
     /**
      * The lowest 7 bits are the dispatch group. The high bits are flags.
      */
     public final int flags;
 
+    @Inline public @Local String getName() {
+        return name;
+    }
+
+    @Inline public @Local String getCamelCaseName() {
+        return camelCaseName;
+    }
+
     @Inline public int getFlags() {
         return flags;
     }
 
     public int getGroup() {
         return flags & GROUP_MASK;
     }
 
-    public boolean isCustom() {
-        return (flags & CUSTOM) != 0;
+    public boolean isInterned() {
+        return (flags & NOT_INTERNED) == 0;
     }
 
     static ElementName elementNameByBuffer(@NoLength char[] buf, int offset, int length, Interner interner) {
         @Unsigned int hash = ElementName.bufToHash(buf, length);
         int index = Arrays.binarySearch(ElementName.ELEMENT_HASHES, hash);
         if (index < 0) {
-            return new ElementName(Portability.newLocalNameFromBuffer(buf, offset, length, interner));
+            return null;
         } else {
             ElementName elementName = ElementName.ELEMENT_NAMES[index];
             @Local String name = elementName.name;
             if (!Portability.localEqualsBuffer(name, buf, offset, length)) {
-                return new ElementName(Portability.newLocalNameFromBuffer(buf,
-                        offset, length, interner));
+                return null;
             }
             return elementName;
         }
     }
 
     /**
      * This method has to return a unique positive integer for each well-known
      * lower-cased element name.
@@ -163,33 +167,32 @@ public final class ElementName
 
     private ElementName(@Local String name, @Local String camelCaseName,
             int flags) {
         this.name = name;
         this.camelCaseName = camelCaseName;
         this.flags = flags;
     }
 
-    protected ElementName(@Local String name) {
-        this.name = name;
-        this.camelCaseName = name;
-        this.flags = TreeBuilder.OTHER | CUSTOM;
+    public ElementName() {
+        this.name = null;
+        this.camelCaseName = null;
+        this.flags = TreeBuilder.OTHER | NOT_INTERNED;
     }
 
-    @Virtual void release() {
-        // No-op in Java.
-        // Implement as delete this in subclass.
-        // Be sure to release the local name
+    public void destructor() {
+        // The translator adds refcount debug code here.
     }
 
-    @SuppressWarnings("unused") @Virtual private void destructor() {
-    }
-
-    @Virtual public ElementName cloneElementName(Interner interner) {
-        return this;
+    public void setNameForNonInterned(@Local String name) {
+        // No need to worry about refcounting the local name, because in the
+        // C++ case the scoped atom table remembers its own atoms.
+        this.name = name;
+        this.camelCaseName = name;
+        assert this.flags == (TreeBuilder.OTHER | NOT_INTERNED);
     }
 
     // START CODE ONLY USED FOR GENERATING CODE uncomment and run to regenerate
 
 //    /**
 //     * @see java.lang.Object#toString()
 //     */
 //    @Override public String toString() {
--- a/parser/html/javasrc/StackNode.java
+++ b/parser/html/javasrc/StackNode.java
@@ -1,28 +1,28 @@
 /*
  * Copyright (c) 2007 Henri Sivonen
  * Copyright (c) 2007-2011 Mozilla Foundation
  *
- * Permission is hereby granted, free of charge, to any person obtaining a 
- * copy of this software and associated documentation files (the "Software"), 
- * to deal in the Software without restriction, including without limitation 
- * the rights to use, copy, modify, merge, publish, distribute, sublicense, 
- * and/or sell copies of the Software, and to permit persons to whom the 
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
  * Software is furnished to do so, subject to the following conditions:
  *
- * The above copyright notice and this permission notice shall be included in 
+ * The above copyright notice and this permission notice shall be included in
  * all copies or substantial portions of the Software.
  *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  * DEALINGS IN THE SOFTWARE.
  */
 
 package nu.validator.htmlparser.impl;
 
 import nu.validator.htmlparser.annotation.Inline;
 import nu.validator.htmlparser.annotation.Local;
 import nu.validator.htmlparser.annotation.NsUri;
@@ -41,17 +41,17 @@ final class StackNode<T> {
     // Only used on the list of formatting elements
     HtmlAttributes attributes;
 
     private int refcount = 1;
 
     // [NOCPP[
 
     private final TaintableLocatorImpl locator;
-    
+
     public TaintableLocatorImpl getLocator() {
         return locator;
     }
 
     // ]NOCPP]
 
     @Inline public int getFlags() {
         return flags;
@@ -73,28 +73,28 @@ final class StackNode<T> {
         return (flags & ElementName.FOSTER_PARENTING) != 0;
     }
 
     public boolean isHtmlIntegrationPoint() {
         return (flags & ElementName.HTML_INTEGRATION_POINT) != 0;
     }
 
     // [NOCPP[
-    
+
     public boolean isOptionalEndTag() {
         return (flags & ElementName.OPTIONAL_END_TAG) != 0;
     }
-    
+
     // ]NOCPP]
 
     /**
      * Constructor for copying. This doesn't take another <code>StackNode</code>
      * because in C++ the caller is reponsible for reobtaining the local names
      * from another interner.
-     * 
+     *
      * @param flags
      * @param ns
      * @param name
      * @param node
      * @param popName
      * @param attributes
      */
     StackNode(int flags, @NsUri String ns, @Local String name, T node,
@@ -112,131 +112,131 @@ final class StackNode<T> {
         this.refcount = 1;
         // [NOCPP[
         this.locator = locator;
         // ]NOCPP]
     }
 
     /**
      * Short hand for well-known HTML elements.
-     * 
+     *
      * @param elementName
      * @param node
      */
     StackNode(ElementName elementName, T node
     // [NOCPP[
             , TaintableLocatorImpl locator
     // ]NOCPP]
     ) {
         this.flags = elementName.getFlags();
-        this.name = elementName.name;
-        this.popName = elementName.name;
+        this.name = elementName.getName();
+        this.popName = elementName.getName();
         this.ns = "http://www.w3.org/1999/xhtml";
         this.node = node;
         this.attributes = null;
         this.refcount = 1;
-        assert !elementName.isCustom() : "Don't use this constructor for custom elements.";
+        assert elementName.isInterned() : "Don't use this constructor for custom elements.";
         // [NOCPP[
         this.locator = locator;
         // ]NOCPP]
     }
 
     /**
      * Constructor for HTML formatting elements.
-     * 
+     *
      * @param elementName
      * @param node
      * @param attributes
      */
     StackNode(ElementName elementName, T node, HtmlAttributes attributes
     // [NOCPP[
             , TaintableLocatorImpl locator
     // ]NOCPP]
     ) {
         this.flags = elementName.getFlags();
-        this.name = elementName.name;
-        this.popName = elementName.name;
+        this.name = elementName.getName();
+        this.popName = elementName.getName();
         this.ns = "http://www.w3.org/1999/xhtml";
         this.node = node;
         this.attributes = attributes;
         this.refcount = 1;
-        assert !elementName.isCustom() : "Don't use this constructor for custom elements.";
+        assert elementName.isInterned() : "Don't use this constructor for custom elements.";
         // [NOCPP[
         this.locator = locator;
         // ]NOCPP]
     }
 
     /**
      * The common-case HTML constructor.
-     * 
+     *
      * @param elementName
      * @param node
      * @param popName
      */
     StackNode(ElementName elementName, T node, @Local String popName
     // [NOCPP[
             , TaintableLocatorImpl locator
     // ]NOCPP]
     ) {
         this.flags = elementName.getFlags();
-        this.name = elementName.name;
+        this.name = elementName.getName();
         this.popName = popName;
         this.ns = "http://www.w3.org/1999/xhtml";
         this.node = node;
         this.attributes = null;
         this.refcount = 1;
         // [NOCPP[
         this.locator = locator;
         // ]NOCPP]
     }
 
     /**
      * Constructor for SVG elements. Note that the order of the arguments is
      * what distinguishes this from the HTML constructor. This is ugly, but
      * AFAICT the least disruptive way to make this work with Java's generics
      * and without unnecessary branches. :-(
-     * 
+     *
      * @param elementName
      * @param popName
      * @param node
      */
     StackNode(ElementName elementName, @Local String popName, T node
     // [NOCPP[
             , TaintableLocatorImpl locator
     // ]NOCPP]
     ) {
         this.flags = prepareSvgFlags(elementName.getFlags());
-        this.name = elementName.name;
+        this.name = elementName.getName();
         this.popName = popName;
         this.ns = "http://www.w3.org/2000/svg";
         this.node = node;
         this.attributes = null;
         this.refcount = 1;
         // [NOCPP[
         this.locator = locator;
         // ]NOCPP]
     }
 
     /**
      * Constructor for MathML.
-     * 
+     *
      * @param elementName
      * @param node
      * @param popName
      * @param markAsIntegrationPoint
      */
     StackNode(ElementName elementName, T node, @Local String popName,
             boolean markAsIntegrationPoint
             // [NOCPP[
             , TaintableLocatorImpl locator
     // ]NOCPP]
     ) {
         this.flags = prepareMathFlags(elementName.getFlags(),
                 markAsIntegrationPoint);
-        this.name = elementName.name;
+        this.name = elementName.getName();
         this.popName = popName;
         this.ns = "http://www.w3.org/1998/Math/MathML";
         this.node = node;
         this.attributes = null;
         this.refcount = 1;
         // [NOCPP[
         this.locator = locator;
         // ]NOCPP]
--- a/parser/html/javasrc/Tokenizer.java
+++ b/parser/html/javasrc/Tokenizer.java
@@ -410,21 +410,29 @@ public class Tokenizer implements Locato
     private char[] endTagExpectationAsArray; // not @Auto!
 
     /**
      * <code>true</code> if tokenizing an end tag
      */
     protected boolean endTag;
 
     /**
-     * The current tag token name.
+     * The current tag token name. One of
+     * 1) null,
+     * 2) non-owning reference to nonInternedTagName
+     * 3) non-owning reference to a pre-interned ElementName
      */
     private ElementName tagName = null;
 
     /**
+     * The recycled ElementName instance for the non-pre-interned cases.
+     */
+    private ElementName nonInternedTagName = null;
+
+    /**
      * The current attribute name.
      */
     protected AttributeName attributeName = null;
 
     // [NOCPP[
 
     /**
      * Whether comment tokens are emitted.
@@ -513,16 +521,17 @@ public class Tokenizer implements Locato
         this.encodingDeclarationHandler = null;
         this.newAttributesEachTime = newAttributesEachTime;
         // &CounterClockwiseContourIntegral; is the longest valid char ref and
         // the semicolon never gets appended to the buffer.
         this.charRefBuf = new char[32];
         this.bmpChar = new char[1];
         this.astralChar = new char[2];
         this.tagName = null;
+        this.nonInternedTagName = new ElementName();
         this.attributeName = null;
         this.doctypeName = null;
         this.publicIdentifier = null;
         this.systemIdentifier = null;
         this.attributes = null;
     }
 
     // ]NOCPP]
@@ -542,16 +551,17 @@ public class Tokenizer implements Locato
         this.newAttributesEachTime = false;
         // ]NOCPP]
         // &CounterClockwiseContourIntegral; is the longest valid char ref and
         // the semicolon never gets appended to the buffer.
         this.charRefBuf = new char[32];
         this.bmpChar = new char[1];
         this.astralChar = new char[2];
         this.tagName = null;
+        this.nonInternedTagName = new ElementName();
         this.attributeName = null;
         this.doctypeName = null;
         this.publicIdentifier = null;
         this.systemIdentifier = null;
         // [NOCPP[
         this.attributes = null;
         // ]NOCPP]
         // CPPONLY: this.attributes = tokenHandler.HasBuilder() ? new HtmlAttributes(mappingLangToXmlLang) : null;
@@ -687,16 +697,17 @@ public class Tokenizer implements Locato
             @Local String endTagExpectation) {
         this.stateSave = specialTokenizerState;
         if (specialTokenizerState == Tokenizer.DATA) {
             return;
         }
         @Auto char[] asArray = Portability.newCharArrayFromLocal(endTagExpectation);
         this.endTagExpectation = ElementName.elementNameByBuffer(asArray, 0,
                 asArray.length, interner);
+        assert this.endTagExpectation != null;
         endTagExpectationToArray();
     }
 
     /**
      * Sets the tokenizer state and the associated element name. This should
      * only ever used to put the tokenizer into one of the states that have
      * a special end tag expectation.
      *
@@ -1087,16 +1098,21 @@ public class Tokenizer implements Locato
         }
         SAXParseException spe = new SAXParseException(message, this);
         errorHandler.warning(spe);
     }
 
     private void strBufToElementNameString() {
         tagName = ElementName.elementNameByBuffer(strBuf, 0, strBufLen,
                 interner);
+        if (tagName == null) {
+            nonInternedTagName.setNameForNonInterned(Portability.newLocalNameFromBuffer(strBuf, 0, strBufLen,
+                interner));
+            tagName = nonInternedTagName;
+        }
         clearStrBufAfterUse();
     }
 
     private int emitCurrentTagToken(boolean selfClosing, int pos)
             throws SAXException {
         cstart = pos + 1;
         maybeErrSlashInEndTag(selfClosing);
         stateSave = Tokenizer.DATA;
@@ -1119,17 +1135,16 @@ public class Tokenizer implements Locato
             // CPPONLY: if (viewingXmlSource) {
             // CPPONLY:   assert newAttributesEachTime;
             // CPPONLY:   Portability.delete(attributes);
             // CPPONLY:   attributes = null;
             // CPPONLY: } else {
             tokenHandler.startTag(tagName, attrs, selfClosing);
             // CPPONLY: }
         }
-        tagName.release();
         tagName = null;
         if (newAttributesEachTime) {
             attributes = null;
         } else {
             attributes.clear(mappingLangToXmlLang);
         }
         /*
          * The token handler may have called setStateAndEndTagExpectation
@@ -6632,20 +6647,18 @@ public class Tokenizer implements Locato
         if (systemIdentifier != null) {
             Portability.releaseString(systemIdentifier);
             systemIdentifier = null;
         }
         if (publicIdentifier != null) {
             Portability.releaseString(publicIdentifier);
             publicIdentifier = null;
         }
-        if (tagName != null) {
-            tagName.release();
-            tagName = null;
-        }
+        tagName = null;
+        nonInternedTagName.setNameForNonInterned(null);
         if (attributeName != null) {
             attributeName.release();
             attributeName = null;
         }
         tokenHandler.endTokenization();
         if (attributes != null) {
             // [NOCPP[
             attributes = null;
@@ -6717,17 +6730,16 @@ public class Tokenizer implements Locato
         candidate = -1;
         charRefBufMark = 0;
         value = 0;
         seenDigits = false;
         endTag = false;
         shouldSuspend = false;
         initDoctypeFields();
         if (tagName != null) {
-            tagName.release();
             tagName = null;
         }
         if (attributeName != null) {
             attributeName.release();
             attributeName = null;
         }
         if (newAttributesEachTime) {
             if (attributes != null) {
@@ -6783,23 +6795,27 @@ public class Tokenizer implements Locato
 
         Portability.releaseString(publicIdentifier);
         if (other.publicIdentifier == null) {
             publicIdentifier = null;
         } else {
             publicIdentifier = Portability.newStringFromString(other.publicIdentifier);
         }
 
-        if (tagName != null) {
-            tagName.release();
-        }
         if (other.tagName == null) {
             tagName = null;
+        } else if (other.tagName.isInterned()) {
+            tagName = other.tagName;
         } else {
-            tagName = other.tagName.cloneElementName(interner);
+            // In the C++ case, We might be loading state from another
+            // tokenizer that has atoms from a different tokenizer-scoped
+            // atom table. Therefore, we have to obtain the correspoding
+            // atom from our own atom table.
+            nonInternedTagName.setNameForNonInterned(Portability.newLocalFromLocal(other.tagName.getName(), interner));
+            tagName = nonInternedTagName;
         }
 
         if (attributeName != null) {
             attributeName.release();
         }
         if (other.attributeName == null) {
             attributeName = null;
         } else {
@@ -7040,16 +7056,18 @@ public class Tokenizer implements Locato
      *            the encodingDeclarationHandler to set
      */
     public void setEncodingDeclarationHandler(
             EncodingDeclarationHandler encodingDeclarationHandler) {
         this.encodingDeclarationHandler = encodingDeclarationHandler;
     }
 
     void destructor() {
+        Portability.delete(nonInternedTagName);
+        nonInternedTagName = null;
         // The translator will write refcount tracing stuff here
         Portability.delete(attributes);
         attributes = null;
     }
 
     // [NOCPP[
 
     /**
--- a/parser/html/javasrc/TreeBuilder.java
+++ b/parser/html/javasrc/TreeBuilder.java
@@ -627,17 +627,17 @@ public abstract class TreeBuilder<T> imp
                 if ("title" == contextName || "desc" == contextName
                         || "foreignObject" == contextName) {
                     // These elements are all alike and we don't care about
                     // the exact name.
                     elementName = ElementName.FOREIGNOBJECT;
                 }
                 // This is the SVG variant of the StackNode constructor.
                 StackNode<T> node = new StackNode<T>(elementName,
-                        elementName.camelCaseName, elt
+                        elementName.getCamelCaseName(), elt
                         // [NOCPP[
                         , errorHandler == null ? null
                                 : new TaintableLocatorImpl(tokenizer)
                 // ]NOCPP]
                 );
                 currentPtr++;
                 stack[currentPtr] = node;
                 tokenizer.setStateAndEndTagExpectation(Tokenizer.DATA,
@@ -658,17 +658,17 @@ public abstract class TreeBuilder<T> imp
                     // Blink does not check the encoding attribute of the
                     // annotation-xml element innerHTML is being set on.
                     // Let's do the same at least until
                     // https://www.w3.org/Bugs/Public/show_bug.cgi?id=26783
                     // is resolved.
                 }
                 // This is the MathML variant of the StackNode constructor.
                 StackNode<T> node = new StackNode<T>(elementName, elt,
-                        elementName.name, false
+                        elementName.getName(), false
                         // [NOCPP[
                         , errorHandler == null ? null
                                 : new TaintableLocatorImpl(tokenizer)
                 // ]NOCPP]
                 );
                 currentPtr++;
                 stack[currentPtr] = node;
                 tokenizer.setStateAndEndTagExpectation(Tokenizer.DATA,
@@ -1665,17 +1665,17 @@ public abstract class TreeBuilder<T> imp
             }
         }
         // ]NOCPP]
 
         int eltPos;
         needToDropLF = false;
         starttagloop: for (;;) {
             int group = elementName.getGroup();
-            @Local String name = elementName.name;
+            @Local String name = elementName.getName();
             if (isInForeign()) {
                 StackNode<T> currentNode = stack[currentPtr];
                 @NsUri String currNs = currentNode.ns;
                 if (!(currentNode.isHtmlIntegrationPoint() || (currNs == "http://www.w3.org/1998/Math/MathML" && ((currentNode.getGroup() == MI_MO_MN_MS_MTEXT && group != MGLYPH_OR_MALIGNMARK) || (currentNode.getGroup() == ANNOTATION_XML && group == SVG))))) {
                     switch (group) {
                         case B_OR_BIG_OR_CODE_OR_EM_OR_I_OR_S_OR_SMALL_OR_STRIKE_OR_STRONG_OR_TT_OR_U:
                         case DIV_OR_BLOCKQUOTE_OR_CENTER_OR_MENU:
                         case BODY:
@@ -2224,17 +2224,17 @@ public abstract class TreeBuilder<T> imp
                                 appendToCurrentNodeAndPushFormattingElementMayFoster(
                                         elementName,
                                         attributes);
                                 attributes = null; // CPP
                                 break starttagloop;
                             case B_OR_BIG_OR_CODE_OR_EM_OR_I_OR_S_OR_SMALL_OR_STRIKE_OR_STRONG_OR_TT_OR_U:
                             case FONT:
                                 reconstructTheActiveFormattingElements();
-                                maybeForgetEarlierDuplicateFormattingElement(elementName.name, attributes);
+                                maybeForgetEarlierDuplicateFormattingElement(elementName.getName(), attributes);
                                 appendToCurrentNodeAndPushFormattingElementMayFoster(
                                         elementName,
                                         attributes);
                                 attributes = null; // CPP
                                 break starttagloop;
                             case NOBR:
                                 reconstructTheActiveFormattingElements();
                                 if (TreeBuilder.NOT_FOUND_ON_STACK != findLastInScope("nobr")) {
@@ -3376,17 +3376,17 @@ public abstract class TreeBuilder<T> imp
         }
     }
 
     public final void endTag(ElementName elementName) throws SAXException {
         flushCharacters();
         needToDropLF = false;
         int eltPos;
         int group = elementName.getGroup();
-        @Local String name = elementName.name;
+        @Local String name = elementName.getName();
         endtagloop: for (;;) {
             if (isInForeign()) {
                 if (stack[currentPtr].name != name) {
                     if (currentPtr == 0) {
                         errStrayEndTag(name);
                     } else {
                         errEndTagDidNotMatchCurrentOpenElement(name, stack[currentPtr].popName);
                     }
@@ -5301,19 +5301,19 @@ public abstract class TreeBuilder<T> imp
         // This method can't be called for custom elements
         HtmlAttributes clone = attributes.cloneAttributes(null);
         // Attributes must not be read after calling createElement, because
         // createElement may delete attributes in C++.
         T elt;
         StackNode<T> current = stack[currentPtr];
         if (current.isFosterParenting()) {
             fatal();
-            elt = createAndInsertFosterParentedElement("http://www.w3.org/1999/xhtml", elementName.name, attributes);
+            elt = createAndInsertFosterParentedElement("http://www.w3.org/1999/xhtml", elementName.getName(), attributes);
         } else {
-            elt = createElement("http://www.w3.org/1999/xhtml", elementName.name, attributes, current.node);
+            elt = createElement("http://www.w3.org/1999/xhtml", elementName.getName(), attributes, current.node);
             appendElement(elt, current.node);
         }
         StackNode<T> node = new StackNode<T>(elementName, elt, clone
                 // [NOCPP[
                 , errorHandler == null ? null : new TaintableLocatorImpl(tokenizer)
         // ]NOCPP]
         );
         push(node);
@@ -5324,36 +5324,36 @@ public abstract class TreeBuilder<T> imp
     private void appendToCurrentNodeAndPushElement(ElementName elementName,
             HtmlAttributes attributes)
             throws SAXException {
         // [NOCPP[
         checkAttributes(attributes, "http://www.w3.org/1999/xhtml");
         // ]NOCPP]
         // This method can't be called for custom elements
         T currentNode = stack[currentPtr].node;
-        T elt = createElement("http://www.w3.org/1999/xhtml", elementName.name, attributes, currentNode);
+        T elt = createElement("http://www.w3.org/1999/xhtml", elementName.getName(), attributes, currentNode);
         appendElement(elt, currentNode);
         if (ElementName.TEMPLATE == elementName) {
             elt = getDocumentFragmentForTemplate(elt);
         }
         StackNode<T> node = new StackNode<T>(elementName, elt
                 // [NOCPP[
                 , errorHandler == null ? null : new TaintableLocatorImpl(tokenizer)
         // ]NOCPP]
         );
         push(node);
     }
 
     private void appendToCurrentNodeAndPushElementMayFoster(ElementName elementName,
             HtmlAttributes attributes)
             throws SAXException {
-        @Local String popName = elementName.name;
+        @Local String popName = elementName.getName();
         // [NOCPP[
         checkAttributes(attributes, "http://www.w3.org/1999/xhtml");
-        if (elementName.isCustom()) {
+        if (!elementName.isInterned()) {
             popName = checkPopName(popName);
         }
         // ]NOCPP]
         T elt;
         StackNode<T> current = stack[currentPtr];
         if (current.isFosterParenting()) {
             fatal();
             elt = createAndInsertFosterParentedElement("http://www.w3.org/1999/xhtml", popName, attributes);
@@ -5367,20 +5367,20 @@ public abstract class TreeBuilder<T> imp
         // ]NOCPP]
         );
         push(node);
     }
 
     private void appendToCurrentNodeAndPushElementMayFosterMathML(
             ElementName elementName, HtmlAttributes attributes)
             throws SAXException {
-        @Local String popName = elementName.name;
+        @Local String popName = elementName.getName();
         // [NOCPP[
         checkAttributes(attributes, "http://www.w3.org/1998/Math/MathML");
-        if (elementName.isCustom()) {
+        if (!elementName.isInterned()) {
             popName = checkPopName(popName);
         }
         // ]NOCPP]
         boolean markAsHtmlIntegrationPoint = false;
         if (ElementName.ANNOTATION_XML == elementName
                 && annotationXmlEncodingPermitsHtml(attributes)) {
             markAsHtmlIntegrationPoint = true;
         }
@@ -5423,20 +5423,20 @@ public abstract class TreeBuilder<T> imp
                 "application/xhtml+xml", encoding)
                 || Portability.lowerCaseLiteralEqualsIgnoreAsciiCaseString(
                         "text/html", encoding);
     }
 
     private void appendToCurrentNodeAndPushElementMayFosterSVG(
             ElementName elementName, HtmlAttributes attributes)
             throws SAXException {
-        @Local String popName = elementName.camelCaseName;
+        @Local String popName = elementName.getCamelCaseName();
         // [NOCPP[
         checkAttributes(attributes, "http://www.w3.org/2000/svg");
-        if (elementName.isCustom()) {
+        if (!elementName.isInterned()) {
             popName = checkPopName(popName);
         }
         // ]NOCPP]
         T elt;
         StackNode<T> current = stack[currentPtr];
         if (current.isFosterParenting()) {
             fatal();
             elt = createAndInsertFosterParentedElement("http://www.w3.org/2000/svg", popName, attributes);
@@ -5459,20 +5459,20 @@ public abstract class TreeBuilder<T> imp
         checkAttributes(attributes, "http://www.w3.org/1999/xhtml");
         // ]NOCPP]
         // Can't be called for custom elements
         T elt;
         T formOwner = form == null || fragment || isTemplateContents() ? null : form;
         StackNode<T> current = stack[currentPtr];
         if (current.isFosterParenting()) {
             fatal();
-            elt = createAndInsertFosterParentedElement("http://www.w3.org/1999/xhtml", elementName.name,
+            elt = createAndInsertFosterParentedElement("http://www.w3.org/1999/xhtml", elementName.getName(),
                     attributes, formOwner);
         } else {
-            elt = createElement("http://www.w3.org/1999/xhtml", elementName.name,
+            elt = createElement("http://www.w3.org/1999/xhtml", elementName.getName(),
                     attributes, formOwner, current.node);
             appendElement(elt, current.node);
         }
         StackNode<T> node = new StackNode<T>(elementName, elt
                 // [NOCPP[
                 , errorHandler == null ? null : new TaintableLocatorImpl(tokenizer)
         // ]NOCPP]
         );
@@ -5499,20 +5499,20 @@ public abstract class TreeBuilder<T> imp
         }
         elementPushed("http://www.w3.org/1999/xhtml", name, elt);
         elementPopped("http://www.w3.org/1999/xhtml", name, elt);
     }
 
     private void appendVoidElementToCurrentMayFoster(
             ElementName elementName, HtmlAttributes attributes)
             throws SAXException {
-        @Local String popName = elementName.name;
+        @Local String popName = elementName.getName();
         // [NOCPP[
         checkAttributes(attributes, "http://www.w3.org/1999/xhtml");
-        if (elementName.isCustom()) {
+        if (!elementName.isInterned()) {
             popName = checkPopName(popName);
         }
         // ]NOCPP]
         T elt;
         StackNode<T> current = stack[currentPtr];
         if (current.isFosterParenting()) {
             fatal();
             elt = createAndInsertFosterParentedElement("http://www.w3.org/1999/xhtml", popName, attributes);
@@ -5522,20 +5522,20 @@ public abstract class TreeBuilder<T> imp
         }
         elementPushed("http://www.w3.org/1999/xhtml", popName, elt);
         elementPopped("http://www.w3.org/1999/xhtml", popName, elt);
     }
 
     private void appendVoidElementToCurrentMayFosterSVG(
             ElementName elementName, HtmlAttributes attributes)
             throws SAXException {
-        @Local String popName = elementName.camelCaseName;
+        @Local String popName = elementName.getCamelCaseName();
         // [NOCPP[
         checkAttributes(attributes, "http://www.w3.org/2000/svg");
-        if (elementName.isCustom()) {
+        if (!elementName.isInterned()) {
             popName = checkPopName(popName);
         }
         // ]NOCPP]
         T elt;
         StackNode<T> current = stack[currentPtr];
         if (current.isFosterParenting()) {
             fatal();
             elt = createAndInsertFosterParentedElement("http://www.w3.org/2000/svg", popName, attributes);
@@ -5545,20 +5545,20 @@ public abstract class TreeBuilder<T> imp
         }
         elementPushed("http://www.w3.org/2000/svg", popName, elt);
         elementPopped("http://www.w3.org/2000/svg", popName, elt);
     }
 
     private void appendVoidElementToCurrentMayFosterMathML(
             ElementName elementName, HtmlAttributes attributes)
             throws SAXException {
-        @Local String popName = elementName.name;
+        @Local String popName = elementName.getName();
         // [NOCPP[
         checkAttributes(attributes, "http://www.w3.org/1998/Math/MathML");
-        if (elementName.isCustom()) {
+        if (!elementName.isInterned()) {
             popName = checkPopName(popName);
         }
         // ]NOCPP]
         T elt;
         StackNode<T> current = stack[currentPtr];
         if (current.isFosterParenting()) {
             fatal();
             elt = createAndInsertFosterParentedElement("http://www.w3.org/1998/Math/MathML", popName, attributes);
--- a/parser/html/moz.build
+++ b/parser/html/moz.build
@@ -67,17 +67,16 @@ UNIFIED_SOURCES += [
     'nsHtml5NamedCharacters.cpp',
     'nsHtml5NamedCharactersAccel.cpp',
     'nsHtml5OplessBuilder.cpp',
     'nsHtml5OwningUTF16Buffer.cpp',
     'nsHtml5Parser.cpp',
     'nsHtml5PlainTextUtils.cpp',
     'nsHtml5Portability.cpp',
     'nsHtml5ReleasableAttributeName.cpp',
-    'nsHtml5ReleasableElementName.cpp',
     'nsHtml5Speculation.cpp',
     'nsHtml5SpeculativeLoad.cpp',
     'nsHtml5StackNode.cpp',
     'nsHtml5StateSnapshot.cpp',
     'nsHtml5StreamListener.cpp',
     'nsHtml5StreamParser.cpp',
     'nsHtml5String.cpp',
     'nsHtml5StringParser.cpp',
--- a/parser/html/nsHtml5ElementName.cpp
+++ b/parser/html/nsHtml5ElementName.cpp
@@ -48,81 +48,76 @@
 #include "nsHtml5AttributeName.h"
 #include "nsHtml5HtmlAttributes.h"
 #include "nsHtml5StackNode.h"
 #include "nsHtml5UTF16Buffer.h"
 #include "nsHtml5StateSnapshot.h"
 #include "nsHtml5Portability.h"
 
 #include "nsHtml5ElementName.h"
-#include "nsHtml5ReleasableElementName.h"
 
-nsHtml5ElementName* nsHtml5ElementName::ELT_NULL_ELEMENT_NAME = nullptr;
 int32_t 
 nsHtml5ElementName::getGroup()
 {
   return flags & NS_HTML5ELEMENT_NAME_GROUP_MASK;
 }
 
-bool 
-nsHtml5ElementName::isCustom()
+bool
+nsHtml5ElementName::isInterned()
 {
-  return (flags & NS_HTML5ELEMENT_NAME_CUSTOM);
+  return !(flags & NS_HTML5ELEMENT_NAME_NOT_INTERNED);
 }
 
 nsHtml5ElementName* 
 nsHtml5ElementName::elementNameByBuffer(char16_t* buf, int32_t offset, int32_t length, nsHtml5AtomTable* interner)
 {
   uint32_t hash = nsHtml5ElementName::bufToHash(buf, length);
   int32_t index = nsHtml5ElementName::ELEMENT_HASHES.binarySearch(hash);
   if (index < 0) {
-    return new nsHtml5ReleasableElementName(nsHtml5Portability::newLocalNameFromBuffer(buf, offset, length, interner));
+    return nullptr;
   } else {
     nsHtml5ElementName* elementName = nsHtml5ElementName::ELEMENT_NAMES[index];
     nsIAtom* name = elementName->name;
     if (!nsHtml5Portability::localEqualsBuffer(name, buf, offset, length)) {
-      return new nsHtml5ReleasableElementName(nsHtml5Portability::newLocalNameFromBuffer(buf, offset, length, interner));
+      return nullptr;
     }
     return elementName;
   }
 }
 
 
 nsHtml5ElementName::nsHtml5ElementName(nsIAtom* name, nsIAtom* camelCaseName, int32_t flags)
   : name(name),
     camelCaseName(camelCaseName),
     flags(flags)
 {
   MOZ_COUNT_CTOR(nsHtml5ElementName);
 }
 
-
-nsHtml5ElementName::nsHtml5ElementName(nsIAtom* name)
-  : name(name),
-    camelCaseName(name),
-    flags(NS_HTML5TREE_BUILDER_OTHER | NS_HTML5ELEMENT_NAME_CUSTOM)
+nsHtml5ElementName::nsHtml5ElementName()
+  : name(nullptr)
+  , camelCaseName(nullptr)
+  , flags(NS_HTML5TREE_BUILDER_OTHER | NS_HTML5ELEMENT_NAME_NOT_INTERNED)
 {
   MOZ_COUNT_CTOR(nsHtml5ElementName);
 }
 
-void 
-nsHtml5ElementName::release()
-{
-}
-
 
 nsHtml5ElementName::~nsHtml5ElementName()
 {
   MOZ_COUNT_DTOR(nsHtml5ElementName);
 }
 
-nsHtml5ElementName* 
-nsHtml5ElementName::cloneElementName(nsHtml5AtomTable* interner)
+void
+nsHtml5ElementName::setNameForNonInterned(nsIAtom* name)
 {
-  return this;
+  this->name = name;
+  this->camelCaseName = name;
+  MOZ_ASSERT(this->flags ==
+             (NS_HTML5TREE_BUILDER_OTHER | NS_HTML5ELEMENT_NAME_NOT_INTERNED));
 }
 
 nsHtml5ElementName* nsHtml5ElementName::ELT_BIG = nullptr;
 nsHtml5ElementName* nsHtml5ElementName::ELT_BDO = nullptr;
 nsHtml5ElementName* nsHtml5ElementName::ELT_COL = nullptr;
 nsHtml5ElementName* nsHtml5ElementName::ELT_DEL = nullptr;
 nsHtml5ElementName* nsHtml5ElementName::ELT_DFN = nullptr;
 nsHtml5ElementName* nsHtml5ElementName::ELT_DIR = nullptr;
@@ -362,17 +357,16 @@ static int32_t const ELEMENT_HASHES_DATA
   2008851557, 2008994116, 2021937364, 2051837468, 2060065124, 2068523853,
   2068523856, 2070023911, 2083120164, 2085266636, 2091479332, 2092255447,
   2092557349
 };
 staticJArray<int32_t,int32_t> nsHtml5ElementName::ELEMENT_HASHES = { ELEMENT_HASHES_DATA, MOZ_ARRAY_LENGTH(ELEMENT_HASHES_DATA) };
 void
 nsHtml5ElementName::initializeStatics()
 {
-  ELT_NULL_ELEMENT_NAME = new nsHtml5ElementName(nullptr);
   ELT_BIG = new nsHtml5ElementName(nsHtml5Atoms::big, nsHtml5Atoms::big, NS_HTML5TREE_BUILDER_B_OR_BIG_OR_CODE_OR_EM_OR_I_OR_S_OR_SMALL_OR_STRIKE_OR_STRONG_OR_TT_OR_U);
   ELT_BDO = new nsHtml5ElementName(nsHtml5Atoms::bdo, nsHtml5Atoms::bdo, NS_HTML5TREE_BUILDER_OTHER);
   ELT_COL = new nsHtml5ElementName(nsHtml5Atoms::col, nsHtml5Atoms::col, NS_HTML5TREE_BUILDER_COL | NS_HTML5ELEMENT_NAME_SPECIAL);
   ELT_DEL = new nsHtml5ElementName(nsHtml5Atoms::del, nsHtml5Atoms::del, NS_HTML5TREE_BUILDER_OTHER);
   ELT_DFN = new nsHtml5ElementName(nsHtml5Atoms::dfn, nsHtml5Atoms::dfn, NS_HTML5TREE_BUILDER_OTHER);
   ELT_DIR = new nsHtml5ElementName(nsHtml5Atoms::dir, nsHtml5Atoms::dir, NS_HTML5TREE_BUILDER_ADDRESS_OR_ARTICLE_OR_ASIDE_OR_DETAILS_OR_DIALOG_OR_DIR_OR_FIGCAPTION_OR_FIGURE_OR_FOOTER_OR_HEADER_OR_HGROUP_OR_MAIN_OR_NAV_OR_SECTION_OR_SUMMARY | NS_HTML5ELEMENT_NAME_SPECIAL);
   ELT_DIV = new nsHtml5ElementName(nsHtml5Atoms::div, nsHtml5Atoms::div, NS_HTML5TREE_BUILDER_DIV_OR_BLOCKQUOTE_OR_CENTER_OR_MENU | NS_HTML5ELEMENT_NAME_SPECIAL);
   ELT_IMG = new nsHtml5ElementName(nsHtml5Atoms::img, nsHtml5Atoms::img, NS_HTML5TREE_BUILDER_IMG | NS_HTML5ELEMENT_NAME_SPECIAL);
@@ -1179,17 +1173,16 @@ nsHtml5ElementName::initializeStatics()
   ELEMENT_NAMES[202] = ELT_RUBY;
   ELEMENT_NAMES[203] = ELT_SUMMARY;
   ELEMENT_NAMES[204] = ELT_TBODY;
 }
 
 void
 nsHtml5ElementName::releaseStatics()
 {
-  delete ELT_NULL_ELEMENT_NAME;
   delete ELT_BIG;
   delete ELT_BDO;
   delete ELT_COL;
   delete ELT_DEL;
   delete ELT_DFN;
   delete ELT_DIR;
   delete ELT_DIV;
   delete ELT_IMG;
--- a/parser/html/nsHtml5ElementName.h
+++ b/parser/html/nsHtml5ElementName.h
@@ -52,67 +52,71 @@ class nsHtml5AttributeName;
 class nsHtml5HtmlAttributes;
 class nsHtml5UTF16Buffer;
 class nsHtml5StateSnapshot;
 class nsHtml5Portability;
 
 
 class nsHtml5ElementName
 {
-  public:
-    static nsHtml5ElementName* ELT_NULL_ELEMENT_NAME;
-    nsIAtom* name;
-    nsIAtom* camelCaseName;
-    int32_t flags;
-    inline int32_t getFlags()
-    {
-      return flags;
-    }
+private:
+  nsIAtom* name;
+  nsIAtom* camelCaseName;
+
+public:
+  int32_t flags;
+  inline nsIAtom* getName() { return name; }
+
+  inline nsIAtom* getCamelCaseName() { return camelCaseName; }
+
+  inline int32_t getFlags() { return flags; }
+
+  int32_t getGroup();
+  bool isInterned();
+  static nsHtml5ElementName* elementNameByBuffer(char16_t* buf,
+                                                 int32_t offset,
+                                                 int32_t length,
+                                                 nsHtml5AtomTable* interner);
 
-    int32_t getGroup();
-    bool isCustom();
-    static nsHtml5ElementName* elementNameByBuffer(char16_t* buf, int32_t offset, int32_t length, nsHtml5AtomTable* interner);
-  private:
-    inline static uint32_t bufToHash(char16_t* buf, int32_t length)
-    {
-      uint32_t len = length;
-      uint32_t first = buf[0];
-      first <<= 19;
-      uint32_t second = 1 << 23;
-      uint32_t third = 0;
-      uint32_t fourth = 0;
-      uint32_t fifth = 0;
-      if (length >= 4) {
-        second = buf[length - 4];
-        second <<= 4;
-        third = buf[length - 3];
-        third <<= 9;
-        fourth = buf[length - 2];
-        fourth <<= 14;
-        fifth = buf[length - 1];
-        fifth <<= 24;
-      } else if (length == 3) {
-        second = buf[1];
-        second <<= 4;
-        third = buf[2];
-        third <<= 9;
-      } else if (length == 2) {
-        second = buf[1];
-        second <<= 24;
-      }
-      return len + first + second + third + fourth + fifth;
+private:
+  inline static uint32_t bufToHash(char16_t* buf, int32_t length)
+  {
+    uint32_t len = length;
+    uint32_t first = buf[0];
+    first <<= 19;
+    uint32_t second = 1 << 23;
+    uint32_t third = 0;
+    uint32_t fourth = 0;
+    uint32_t fifth = 0;
+    if (length >= 4) {
+      second = buf[length - 4];
+      second <<= 4;
+      third = buf[length - 3];
+      third <<= 9;
+      fourth = buf[length - 2];
+      fourth <<= 14;
+      fifth = buf[length - 1];
+      fifth <<= 24;
+    } else if (length == 3) {
+      second = buf[1];
+      second <<= 4;
+      third = buf[2];
+      third <<= 9;
+    } else if (length == 2) {
+      second = buf[1];
+      second <<= 24;
+    }
+    return len + first + second + third + fourth + fifth;
     }
 
     nsHtml5ElementName(nsIAtom* name, nsIAtom* camelCaseName, int32_t flags);
-  protected:
-    explicit nsHtml5ElementName(nsIAtom* name);
   public:
-    virtual void release();
-    virtual ~nsHtml5ElementName();
-    virtual nsHtml5ElementName* cloneElementName(nsHtml5AtomTable* interner);
+    nsHtml5ElementName();
+    ~nsHtml5ElementName();
+    void setNameForNonInterned(nsIAtom* name);
     static nsHtml5ElementName* ELT_BIG;
     static nsHtml5ElementName* ELT_BDO;
     static nsHtml5ElementName* ELT_COL;
     static nsHtml5ElementName* ELT_DEL;
     static nsHtml5ElementName* ELT_DFN;
     static nsHtml5ElementName* ELT_DIR;
     static nsHtml5ElementName* ELT_DIV;
     static nsHtml5ElementName* ELT_IMG;
@@ -308,27 +312,26 @@ class nsHtml5ElementName
     static nsHtml5ElementName* ELT_FECOLORMATRIX;
     static nsHtml5ElementName* ELT_FECONVOLVEMATRIX;
     static nsHtml5ElementName* ELT_ISINDEX;
     static nsHtml5ElementName* ELT_BODY;
     static nsHtml5ElementName* ELT_FEMORPHOLOGY;
     static nsHtml5ElementName* ELT_RUBY;
     static nsHtml5ElementName* ELT_SUMMARY;
     static nsHtml5ElementName* ELT_TBODY;
-
   private:
     static nsHtml5ElementName** ELEMENT_NAMES;
     static staticJArray<int32_t,int32_t> ELEMENT_HASHES;
   public:
     static void initializeStatics();
     static void releaseStatics();
 };
 
 #define NS_HTML5ELEMENT_NAME_GROUP_MASK 127
-#define NS_HTML5ELEMENT_NAME_CUSTOM (1 << 30)
+#define NS_HTML5ELEMENT_NAME_NOT_INTERNED (1 << 30)
 #define NS_HTML5ELEMENT_NAME_SPECIAL (1 << 29)
 #define NS_HTML5ELEMENT_NAME_FOSTER_PARENTING (1 << 28)
 #define NS_HTML5ELEMENT_NAME_SCOPING (1 << 27)
 #define NS_HTML5ELEMENT_NAME_SCOPING_AS_SVG (1 << 26)
 #define NS_HTML5ELEMENT_NAME_SCOPING_AS_MATHML (1 << 25)
 #define NS_HTML5ELEMENT_NAME_HTML_INTEGRATION_POINT (1 << 24)
 #define NS_HTML5ELEMENT_NAME_OPTIONAL_END_TAG (1 << 23)
 
deleted file mode 100644
--- a/parser/html/nsHtml5ReleasableElementName.cpp
+++ /dev/null
@@ -1,30 +0,0 @@
-/* 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 "nsHtml5ReleasableElementName.h"
-
-nsHtml5ReleasableElementName::nsHtml5ReleasableElementName(nsIAtom* name)
-  : nsHtml5ElementName(name)
-{
-}
-
-void
-nsHtml5ReleasableElementName::release()
-{
-  delete this;
-}
-
-nsHtml5ElementName* 
-nsHtml5ReleasableElementName::cloneElementName(nsHtml5AtomTable* aInterner)
-{
-  nsIAtom* l = name;
-  if (aInterner) {
-    if (!l->IsStaticAtom()) {
-      nsAutoString str;
-      l->ToString(str);
-      l = aInterner->GetAtom(str);
-    }
-  }
-  return new nsHtml5ReleasableElementName(l);
-}
deleted file mode 100644
--- a/parser/html/nsHtml5ReleasableElementName.h
+++ /dev/null
@@ -1,19 +0,0 @@
-/* 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 nsHtml5ReleasableElementName_h
-#define nsHtml5ReleasableElementName_h
-
-#include "nsHtml5ElementName.h"
-#include "mozilla/Attributes.h"
-
-class nsHtml5ReleasableElementName final : public nsHtml5ElementName
-{
-  public:
-    explicit nsHtml5ReleasableElementName(nsIAtom* name);
-    virtual void release();
-    virtual nsHtml5ElementName* cloneElementName(nsHtml5AtomTable* interner);
-};
-
-#endif // nsHtml5ReleasableElementName_h
--- a/parser/html/nsHtml5StackNode.cpp
+++ b/parser/html/nsHtml5StackNode.cpp
@@ -1,28 +1,28 @@
 /*
  * Copyright (c) 2007 Henri Sivonen
  * Copyright (c) 2007-2011 Mozilla Foundation
  *
- * Permission is hereby granted, free of charge, to any person obtaining a 
- * copy of this software and associated documentation files (the "Software"), 
- * to deal in the Software without restriction, including without limitation 
- * the rights to use, copy, modify, merge, publish, distribute, sublicense, 
- * and/or sell copies of the Software, and to permit persons to whom the 
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
  * Software is furnished to do so, subject to the following conditions:
  *
- * The above copyright notice and this permission notice shall be included in 
+ * The above copyright notice and this permission notice shall be included in
  * all copies or substantial portions of the Software.
  *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  * DEALINGS IN THE SOFTWARE.
  */
 
 /*
  * THIS IS A GENERATED FILE. PLEASE DO NOT EDIT.
  * Please edit StackNode.java instead and regenerate.
  */
 
@@ -93,79 +93,86 @@ nsHtml5StackNode::nsHtml5StackNode(int32
     ns(ns),
     node(node),
     attributes(attributes),
     refcount(1)
 {
   MOZ_COUNT_CTOR(nsHtml5StackNode);
 }
 
-
-nsHtml5StackNode::nsHtml5StackNode(nsHtml5ElementName* elementName, nsIContentHandle* node)
-  : flags(elementName->getFlags()),
-    name(elementName->name),
-    popName(elementName->name),
-    ns(kNameSpaceID_XHTML),
-    node(node),
-    attributes(nullptr),
-    refcount(1)
+nsHtml5StackNode::nsHtml5StackNode(nsHtml5ElementName* elementName,
+                                   nsIContentHandle* node)
+  : flags(elementName->getFlags())
+  , name(elementName->getName())
+  , popName(elementName->getName())
+  , ns(kNameSpaceID_XHTML)
+  , node(node)
+  , attributes(nullptr)
+  , refcount(1)
 {
   MOZ_COUNT_CTOR(nsHtml5StackNode);
-  MOZ_ASSERT(!elementName->isCustom(), "Don't use this constructor for custom elements.");
+  MOZ_ASSERT(elementName->isInterned(),
+             "Don't use this constructor for custom elements.");
 }
 
-
-nsHtml5StackNode::nsHtml5StackNode(nsHtml5ElementName* elementName, nsIContentHandle* node, nsHtml5HtmlAttributes* attributes)
-  : flags(elementName->getFlags()),
-    name(elementName->name),
-    popName(elementName->name),
-    ns(kNameSpaceID_XHTML),
-    node(node),
-    attributes(attributes),
-    refcount(1)
+nsHtml5StackNode::nsHtml5StackNode(nsHtml5ElementName* elementName,
+                                   nsIContentHandle* node,
+                                   nsHtml5HtmlAttributes* attributes)
+  : flags(elementName->getFlags())
+  , name(elementName->getName())
+  , popName(elementName->getName())
+  , ns(kNameSpaceID_XHTML)
+  , node(node)
+  , attributes(attributes)
+  , refcount(1)
 {
   MOZ_COUNT_CTOR(nsHtml5StackNode);
-  MOZ_ASSERT(!elementName->isCustom(), "Don't use this constructor for custom elements.");
+  MOZ_ASSERT(elementName->isInterned(),
+             "Don't use this constructor for custom elements.");
 }
 
-
-nsHtml5StackNode::nsHtml5StackNode(nsHtml5ElementName* elementName, nsIContentHandle* node, nsIAtom* popName)
-  : flags(elementName->getFlags()),
-    name(elementName->name),
-    popName(popName),
-    ns(kNameSpaceID_XHTML),
-    node(node),
-    attributes(nullptr),
-    refcount(1)
+nsHtml5StackNode::nsHtml5StackNode(nsHtml5ElementName* elementName,
+                                   nsIContentHandle* node,
+                                   nsIAtom* popName)
+  : flags(elementName->getFlags())
+  , name(elementName->getName())
+  , popName(popName)
+  , ns(kNameSpaceID_XHTML)
+  , node(node)
+  , attributes(nullptr)
+  , refcount(1)
 {
   MOZ_COUNT_CTOR(nsHtml5StackNode);
 }
 
-
-nsHtml5StackNode::nsHtml5StackNode(nsHtml5ElementName* elementName, nsIAtom* popName, nsIContentHandle* node)
-  : flags(prepareSvgFlags(elementName->getFlags())),
-    name(elementName->name),
-    popName(popName),
-    ns(kNameSpaceID_SVG),
-    node(node),
-    attributes(nullptr),
-    refcount(1)
+nsHtml5StackNode::nsHtml5StackNode(nsHtml5ElementName* elementName,
+                                   nsIAtom* popName,
+                                   nsIContentHandle* node)
+  : flags(prepareSvgFlags(elementName->getFlags()))
+  , name(elementName->getName())
+  , popName(popName)
+  , ns(kNameSpaceID_SVG)
+  , node(node)
+  , attributes(nullptr)
+  , refcount(1)
 {
   MOZ_COUNT_CTOR(nsHtml5StackNode);
 }
 
-
-nsHtml5StackNode::nsHtml5StackNode(nsHtml5ElementName* elementName, nsIContentHandle* node, nsIAtom* popName, bool markAsIntegrationPoint)
-  : flags(prepareMathFlags(elementName->getFlags(), markAsIntegrationPoint)),
-    name(elementName->name),
-    popName(popName),
-    ns(kNameSpaceID_MathML),
-    node(node),
-    attributes(nullptr),
-    refcount(1)
+nsHtml5StackNode::nsHtml5StackNode(nsHtml5ElementName* elementName,
+                                   nsIContentHandle* node,
+                                   nsIAtom* popName,
+                                   bool markAsIntegrationPoint)
+  : flags(prepareMathFlags(elementName->getFlags(), markAsIntegrationPoint))
+  , name(elementName->getName())
+  , popName(popName)
+  , ns(kNameSpaceID_MathML)
+  , node(node)
+  , attributes(nullptr)
+  , refcount(1)
 {
   MOZ_COUNT_CTOR(nsHtml5StackNode);
 }
 
 int32_t 
 nsHtml5StackNode::prepareSvgFlags(int32_t flags)
 {
   flags &= ~(NS_HTML5ELEMENT_NAME_FOSTER_PARENTING | NS_HTML5ELEMENT_NAME_SCOPING | NS_HTML5ELEMENT_NAME_SPECIAL | NS_HTML5ELEMENT_NAME_OPTIONAL_END_TAG);
--- a/parser/html/nsHtml5StackNode.h
+++ b/parser/html/nsHtml5StackNode.h
@@ -1,28 +1,28 @@
 /*
  * Copyright (c) 2007 Henri Sivonen
  * Copyright (c) 2007-2011 Mozilla Foundation
  *
- * Permission is hereby granted, free of charge, to any person obtaining a 
- * copy of this software and associated documentation files (the "Software"), 
- * to deal in the Software without restriction, including without limitation 
- * the rights to use, copy, modify, merge, publish, distribute, sublicense, 
- * and/or sell copies of the Software, and to permit persons to whom the 
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
  * Software is furnished to do so, subject to the following conditions:
  *
- * The above copyright notice and this permission notice shall be included in 
+ * The above copyright notice and this permission notice shall be included in
  * all copies or substantial portions of the Software.
  *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  * DEALINGS IN THE SOFTWARE.
  */
 
 /*
  * THIS IS A GENERATED FILE. PLEASE DO NOT EDIT.
  * Please edit StackNode.java instead and regenerate.
  */
 
--- a/parser/html/nsHtml5Tokenizer.cpp
+++ b/parser/html/nsHtml5Tokenizer.cpp
@@ -83,30 +83,33 @@ static char16_t const IFRAME_ARR_DATA[] 
 staticJArray<char16_t,int32_t> nsHtml5Tokenizer::IFRAME_ARR = { IFRAME_ARR_DATA, MOZ_ARRAY_LENGTH(IFRAME_ARR_DATA) };
 static char16_t const NOEMBED_ARR_DATA[] = { 'n', 'o', 'e', 'm', 'b', 'e', 'd' };
 staticJArray<char16_t,int32_t> nsHtml5Tokenizer::NOEMBED_ARR = { NOEMBED_ARR_DATA, MOZ_ARRAY_LENGTH(NOEMBED_ARR_DATA) };
 static char16_t const NOSCRIPT_ARR_DATA[] = { 'n', 'o', 's', 'c', 'r', 'i', 'p', 't' };
 staticJArray<char16_t,int32_t> nsHtml5Tokenizer::NOSCRIPT_ARR = { NOSCRIPT_ARR_DATA, MOZ_ARRAY_LENGTH(NOSCRIPT_ARR_DATA) };
 static char16_t const NOFRAMES_ARR_DATA[] = { 'n', 'o', 'f', 'r', 'a', 'm', 'e', 's' };
 staticJArray<char16_t,int32_t> nsHtml5Tokenizer::NOFRAMES_ARR = { NOFRAMES_ARR_DATA, MOZ_ARRAY_LENGTH(NOFRAMES_ARR_DATA) };
 
-nsHtml5Tokenizer::nsHtml5Tokenizer(nsHtml5TreeBuilder* tokenHandler, bool viewingXmlSource)
-  : tokenHandler(tokenHandler),
-    encodingDeclarationHandler(nullptr),
-    charRefBuf(jArray<char16_t,int32_t>::newJArray(32)),
-    bmpChar(jArray<char16_t,int32_t>::newJArray(1)),
-    astralChar(jArray<char16_t,int32_t>::newJArray(2)),
-    tagName(nullptr),
-    attributeName(nullptr),
-    doctypeName(nullptr),
-    publicIdentifier(nullptr),
-    systemIdentifier(nullptr),
-    attributes(tokenHandler->HasBuilder() ? new nsHtml5HtmlAttributes(0) : nullptr),
-    newAttributesEachTime(!tokenHandler->HasBuilder()),
-    viewingXmlSource(viewingXmlSource)
+nsHtml5Tokenizer::nsHtml5Tokenizer(nsHtml5TreeBuilder* tokenHandler,
+                                   bool viewingXmlSource)
+  : tokenHandler(tokenHandler)
+  , encodingDeclarationHandler(nullptr)
+  , charRefBuf(jArray<char16_t, int32_t>::newJArray(32))
+  , bmpChar(jArray<char16_t, int32_t>::newJArray(1))
+  , astralChar(jArray<char16_t, int32_t>::newJArray(2))
+  , tagName(nullptr)
+  , nonInternedTagName(new nsHtml5ElementName())
+  , attributeName(nullptr)
+  , doctypeName(nullptr)
+  , publicIdentifier(nullptr)
+  , systemIdentifier(nullptr)
+  , attributes(tokenHandler->HasBuilder() ? new nsHtml5HtmlAttributes(0)
+                                          : nullptr)
+  , newAttributesEachTime(!tokenHandler->HasBuilder())
+  , viewingXmlSource(viewingXmlSource)
 {
   MOZ_COUNT_CTOR(nsHtml5Tokenizer);
 }
 
 void 
 nsHtml5Tokenizer::setInterner(nsHtml5AtomTable* interner)
 {
   this->interner = interner;
@@ -130,16 +133,17 @@ void
 nsHtml5Tokenizer::setStateAndEndTagExpectation(int32_t specialTokenizerState, nsIAtom* endTagExpectation)
 {
   this->stateSave = specialTokenizerState;
   if (specialTokenizerState == NS_HTML5TOKENIZER_DATA) {
     return;
   }
   autoJArray<char16_t,int32_t> asArray = nsHtml5Portability::newCharArrayFromLocal(endTagExpectation);
   this->endTagExpectation = nsHtml5ElementName::elementNameByBuffer(asArray, 0, asArray.length, interner);
+  MOZ_ASSERT(!!this->endTagExpectation);
   endTagExpectationToArray();
 }
 
 void 
 nsHtml5Tokenizer::setStateAndEndTagExpectation(int32_t specialTokenizerState, nsHtml5ElementName* endTagExpectation)
 {
   this->stateSave = specialTokenizerState;
   this->endTagExpectation = endTagExpectation;
@@ -278,16 +282,22 @@ nsHtml5Tokenizer::flushChars(char16_t* b
   }
   cstart = INT32_MAX;
 }
 
 void 
 nsHtml5Tokenizer::strBufToElementNameString()
 {
   tagName = nsHtml5ElementName::elementNameByBuffer(strBuf, 0, strBufLen, interner);
+  if (!tagName) {
+    nonInternedTagName->setNameForNonInterned(
+      nsHtml5Portability::newLocalNameFromBuffer(
+        strBuf, 0, strBufLen, interner));
+    tagName = nonInternedTagName;
+  }
   clearStrBufAfterUse();
 }
 
 int32_t 
 nsHtml5Tokenizer::emitCurrentTagToken(bool selfClosing, int32_t pos)
 {
   cstart = pos + 1;
   maybeErrSlashInEndTag(selfClosing);
@@ -306,17 +316,16 @@ nsHtml5Tokenizer::emitCurrentTagToken(bo
     if (viewingXmlSource) {
       MOZ_ASSERT(newAttributesEachTime);
       delete attributes;
       attributes = nullptr;
     } else {
       tokenHandler->startTag(tagName, attrs, selfClosing);
     }
   }
-  tagName->release();
   tagName = nullptr;
   if (newAttributesEachTime) {
     attributes = nullptr;
   } else {
     attributes->clear(0);
   }
   return stateSave;
 }
@@ -3942,20 +3951,18 @@ nsHtml5Tokenizer::end()
   if (systemIdentifier) {
     systemIdentifier.Release();
     systemIdentifier = nullptr;
   }
   if (publicIdentifier) {
     publicIdentifier.Release();
     publicIdentifier = nullptr;
   }
-  if (tagName) {
-    tagName->release();
-    tagName = nullptr;
-  }
+  tagName = nullptr;
+  nonInternedTagName->setNameForNonInterned(nullptr);
   if (attributeName) {
     attributeName->release();
     attributeName = nullptr;
   }
   tokenHandler->endTokenization();
   if (attributes) {
     attributes->clear(0);
   }
@@ -3990,17 +3997,16 @@ nsHtml5Tokenizer::resetToDataState()
   candidate = -1;
   charRefBufMark = 0;
   value = 0;
   seenDigits = false;
   endTag = false;
   shouldSuspend = false;
   initDoctypeFields();
   if (tagName) {
-    tagName->release();
     tagName = nullptr;
   }
   if (attributeName) {
     attributeName->release();
     attributeName = nullptr;
   }
   if (newAttributesEachTime) {
     if (attributes) {
@@ -4050,23 +4056,25 @@ nsHtml5Tokenizer::loadState(nsHtml5Token
     systemIdentifier = nsHtml5Portability::newStringFromString(other->systemIdentifier);
   }
   publicIdentifier.Release();
   if (!other->publicIdentifier) {
     publicIdentifier = nullptr;
   } else {
     publicIdentifier = nsHtml5Portability::newStringFromString(other->publicIdentifier);
   }
-  if (tagName) {
-    tagName->release();
-  }
   if (!other->tagName) {
     tagName = nullptr;
+  } else if (other->tagName->isInterned()) {
+    tagName = other->tagName;
   } else {
-    tagName = other->tagName->cloneElementName(interner);
+    nonInternedTagName->setNameForNonInterned(
+      nsHtml5Portability::newLocalFromLocal(other->tagName->getName(),
+                                            interner));
+    tagName = nonInternedTagName;
   }
   if (attributeName) {
     attributeName->release();
   }
   if (!other->attributeName) {
     attributeName = nullptr;
   } else {
     attributeName = other->attributeName->cloneAttributeName(interner);
@@ -4094,16 +4102,18 @@ nsHtml5Tokenizer::setEncodingDeclaration
 {
   this->encodingDeclarationHandler = encodingDeclarationHandler;
 }
 
 
 nsHtml5Tokenizer::~nsHtml5Tokenizer()
 {
   MOZ_COUNT_DTOR(nsHtml5Tokenizer);
+  delete nonInternedTagName;
+  nonInternedTagName = nullptr;
   delete attributes;
   attributes = nullptr;
 }
 
 void
 nsHtml5Tokenizer::initializeStatics()
 {
 }
--- a/parser/html/nsHtml5Tokenizer.h
+++ b/parser/html/nsHtml5Tokenizer.h
@@ -117,16 +117,18 @@ class nsHtml5Tokenizer
   protected:
     nsHtml5ElementName* endTagExpectation;
   private:
     jArray<char16_t,int32_t> endTagExpectationAsArray;
   protected:
     bool endTag;
   private:
     nsHtml5ElementName* tagName;
+    nsHtml5ElementName* nonInternedTagName;
+
   protected:
     nsHtml5AttributeName* attributeName;
   private:
     nsIAtom* doctypeName;
     nsHtml5String publicIdentifier;
     nsHtml5String systemIdentifier;
     nsHtml5HtmlAttributes* attributes;
     bool newAttributesEachTime;
--- a/parser/html/nsHtml5TreeBuilder.cpp
+++ b/parser/html/nsHtml5TreeBuilder.cpp
@@ -97,29 +97,31 @@ nsHtml5TreeBuilder::startTokenization(ns
     } else {
       elt = createHtmlElementSetAsRoot(tokenizer->emptyAttributes());
     }
     if (contextNamespace == kNameSpaceID_SVG) {
       nsHtml5ElementName* elementName = nsHtml5ElementName::ELT_SVG;
       if (nsHtml5Atoms::title == contextName || nsHtml5Atoms::desc == contextName || nsHtml5Atoms::foreignObject == contextName) {
         elementName = nsHtml5ElementName::ELT_FOREIGNOBJECT;
       }
-      nsHtml5StackNode* node = new nsHtml5StackNode(elementName, elementName->camelCaseName, elt);
+      nsHtml5StackNode* node =
+        new nsHtml5StackNode(elementName, elementName->getCamelCaseName(), elt);
       currentPtr++;
       stack[currentPtr] = node;
       tokenizer->setStateAndEndTagExpectation(NS_HTML5TOKENIZER_DATA, contextName);
       mode = NS_HTML5TREE_BUILDER_FRAMESET_OK;
     } else if (contextNamespace == kNameSpaceID_MathML) {
       nsHtml5ElementName* elementName = nsHtml5ElementName::ELT_MATH;
       if (nsHtml5Atoms::mi == contextName || nsHtml5Atoms::mo == contextName || nsHtml5Atoms::mn == contextName || nsHtml5Atoms::ms == contextName || nsHtml5Atoms::mtext == contextName) {
         elementName = nsHtml5ElementName::ELT_MTEXT;
       } else if (nsHtml5Atoms::annotation_xml == contextName) {
         elementName = nsHtml5ElementName::ELT_ANNOTATION_XML;
       }
-      nsHtml5StackNode* node = new nsHtml5StackNode(elementName, elt, elementName->name, false);
+      nsHtml5StackNode* node =
+        new nsHtml5StackNode(elementName, elt, elementName->getName(), false);
       currentPtr++;
       stack[currentPtr] = node;
       tokenizer->setStateAndEndTagExpectation(NS_HTML5TOKENIZER_DATA, contextName);
       mode = NS_HTML5TREE_BUILDER_FRAMESET_OK;
     } else {
       nsHtml5StackNode* node = new nsHtml5StackNode(nsHtml5ElementName::ELT_HTML, elt);
       currentPtr++;
       stack[currentPtr] = node;
@@ -605,17 +607,17 @@ nsHtml5TreeBuilder::endTokenization()
 void 
 nsHtml5TreeBuilder::startTag(nsHtml5ElementName* elementName, nsHtml5HtmlAttributes* attributes, bool selfClosing)
 {
   flushCharacters();
   int32_t eltPos;
   needToDropLF = false;
   starttagloop: for (; ; ) {
     int32_t group = elementName->getGroup();
-    nsIAtom* name = elementName->name;
+    nsIAtom* name = elementName->getName();
     if (isInForeign()) {
       nsHtml5StackNode* currentNode = stack[currentPtr];
       int32_t currNs = currentNode->ns;
       if (!(currentNode->isHtmlIntegrationPoint() || (currNs == kNameSpaceID_MathML && ((currentNode->getGroup() == NS_HTML5TREE_BUILDER_MI_MO_MN_MS_MTEXT && group != NS_HTML5TREE_BUILDER_MGLYPH_OR_MALIGNMARK) || (currentNode->getGroup() == NS_HTML5TREE_BUILDER_ANNOTATION_XML && group == NS_HTML5TREE_BUILDER_SVG))))) {
         switch(group) {
           case NS_HTML5TREE_BUILDER_B_OR_BIG_OR_CODE_OR_EM_OR_I_OR_S_OR_SMALL_OR_STRIKE_OR_STRONG_OR_TT_OR_U:
           case NS_HTML5TREE_BUILDER_DIV_OR_BLOCKQUOTE_OR_CENTER_OR_MENU:
           case NS_HTML5TREE_BUILDER_BODY:
@@ -1139,17 +1141,18 @@ nsHtml5TreeBuilder::startTag(nsHtml5Elem
               reconstructTheActiveFormattingElements();
               appendToCurrentNodeAndPushFormattingElementMayFoster(elementName, attributes);
               attributes = nullptr;
               NS_HTML5_BREAK(starttagloop);
             }
             case NS_HTML5TREE_BUILDER_B_OR_BIG_OR_CODE_OR_EM_OR_I_OR_S_OR_SMALL_OR_STRIKE_OR_STRONG_OR_TT_OR_U:
             case NS_HTML5TREE_BUILDER_FONT: {
               reconstructTheActiveFormattingElements();
-              maybeForgetEarlierDuplicateFormattingElement(elementName->name, attributes);
+              maybeForgetEarlierDuplicateFormattingElement(
+                elementName->getName(), attributes);
               appendToCurrentNodeAndPushFormattingElementMayFoster(elementName, attributes);
               attributes = nullptr;
               NS_HTML5_BREAK(starttagloop);
             }
             case NS_HTML5TREE_BUILDER_NOBR: {
               reconstructTheActiveFormattingElements();
               if (NS_HTML5TREE_BUILDER_NOT_FOUND_ON_STACK != findLastInScope(nsHtml5Atoms::nobr)) {
                 errFooSeenWhenFooOpen(name);
@@ -2221,17 +2224,17 @@ nsHtml5TreeBuilder::checkMetaCharset(nsH
 
 void 
 nsHtml5TreeBuilder::endTag(nsHtml5ElementName* elementName)
 {
   flushCharacters();
   needToDropLF = false;
   int32_t eltPos;
   int32_t group = elementName->getGroup();
-  nsIAtom* name = elementName->name;
+  nsIAtom* name = elementName->getName();
   for (; ; ) {
     if (isInForeign()) {
       if (stack[currentPtr]->name != name) {
         if (!currentPtr) {
           errStrayEndTag(name);
         } else {
           errEndTagDidNotMatchCurrentOpenElement(name, stack[currentPtr]->popName);
         }
@@ -3997,61 +4000,64 @@ nsHtml5TreeBuilder::appendToCurrentNodeA
 void 
 nsHtml5TreeBuilder::appendToCurrentNodeAndPushFormattingElementMayFoster(nsHtml5ElementName* elementName, nsHtml5HtmlAttributes* attributes)
 {
   nsHtml5HtmlAttributes* clone = attributes->cloneAttributes(nullptr);
   nsIContentHandle* elt;
   nsHtml5StackNode* current = stack[currentPtr];
   if (current->isFosterParenting()) {
 
-    elt = createAndInsertFosterParentedElement(kNameSpaceID_XHTML, elementName->name, attributes);
+    elt = createAndInsertFosterParentedElement(
+      kNameSpaceID_XHTML, elementName->getName(), attributes);
   } else {
-    elt = createElement(kNameSpaceID_XHTML, elementName->name, attributes, current->node);
+    elt = createElement(
+      kNameSpaceID_XHTML, elementName->getName(), attributes, current->node);
     appendElement(elt, current->node);
   }
   nsHtml5StackNode* node = new nsHtml5StackNode(elementName, elt, clone);
   push(node);
   append(node);
   node->retain();
 }
 
 void 
 nsHtml5TreeBuilder::appendToCurrentNodeAndPushElement(nsHtml5ElementName* elementName, nsHtml5HtmlAttributes* attributes)
 {
   nsIContentHandle* currentNode = stack[currentPtr]->node;
-  nsIContentHandle* elt = createElement(kNameSpaceID_XHTML, elementName->name, attributes, currentNode);
+  nsIContentHandle* elt = createElement(
+    kNameSpaceID_XHTML, elementName->getName(), attributes, currentNode);
   appendElement(elt, currentNode);
   if (nsHtml5ElementName::ELT_TEMPLATE == elementName) {
     elt = getDocumentFragmentForTemplate(elt);
   }
   nsHtml5StackNode* node = new nsHtml5StackNode(elementName, elt);
   push(node);
 }
 
 void 
 nsHtml5TreeBuilder::appendToCurrentNodeAndPushElementMayFoster(nsHtml5ElementName* elementName, nsHtml5HtmlAttributes* attributes)
 {
-  nsIAtom* popName = elementName->name;
+  nsIAtom* popName = elementName->getName();
   nsIContentHandle* elt;
   nsHtml5StackNode* current = stack[currentPtr];
   if (current->isFosterParenting()) {
 
     elt = createAndInsertFosterParentedElement(kNameSpaceID_XHTML, popName, attributes);
   } else {
     elt = createElement(kNameSpaceID_XHTML, popName, attributes, current->node);
     appendElement(elt, current->node);
   }
   nsHtml5StackNode* node = new nsHtml5StackNode(elementName, elt, popName);
   push(node);
 }
 
 void 
 nsHtml5TreeBuilder::appendToCurrentNodeAndPushElementMayFosterMathML(nsHtml5ElementName* elementName, nsHtml5HtmlAttributes* attributes)
 {
-  nsIAtom* popName = elementName->name;
+  nsIAtom* popName = elementName->getName();
   bool markAsHtmlIntegrationPoint = false;
   if (nsHtml5ElementName::ELT_ANNOTATION_XML == elementName && annotationXmlEncodingPermitsHtml(attributes)) {
     markAsHtmlIntegrationPoint = true;
   }
   nsIContentHandle* elt;
   nsHtml5StackNode* current = stack[currentPtr];
   if (current->isFosterParenting()) {
 
@@ -4073,17 +4079,17 @@ nsHtml5TreeBuilder::annotationXmlEncodin
     return false;
   }
   return nsHtml5Portability::lowerCaseLiteralEqualsIgnoreAsciiCaseString("application/xhtml+xml", encoding) || nsHtml5Portability::lowerCaseLiteralEqualsIgnoreAsciiCaseString("text/html", encoding);
 }
 
 void 
 nsHtml5TreeBuilder::appendToCurrentNodeAndPushElementMayFosterSVG(nsHtml5ElementName* elementName, nsHtml5HtmlAttributes* attributes)
 {
-  nsIAtom* popName = elementName->camelCaseName;
+  nsIAtom* popName = elementName->getCamelCaseName();
   nsIContentHandle* elt;
   nsHtml5StackNode* current = stack[currentPtr];
   if (current->isFosterParenting()) {
 
     elt = createAndInsertFosterParentedElement(kNameSpaceID_SVG, popName, attributes);
   } else {
     elt = createElement(kNameSpaceID_SVG, popName, attributes, current->node);
     appendElement(elt, current->node);
@@ -4095,19 +4101,24 @@ nsHtml5TreeBuilder::appendToCurrentNodeA
 void 
 nsHtml5TreeBuilder::appendToCurrentNodeAndPushElementMayFoster(nsHtml5ElementName* elementName, nsHtml5HtmlAttributes* attributes, nsIContentHandle* form)
 {
   nsIContentHandle* elt;
   nsIContentHandle* formOwner = !form || fragment || isTemplateContents() ? nullptr : form;
   nsHtml5StackNode* current = stack[currentPtr];
   if (current->isFosterParenting()) {
 
-    elt = createAndInsertFosterParentedElement(kNameSpaceID_XHTML, elementName->name, attributes, formOwner);
+    elt = createAndInsertFosterParentedElement(
+      kNameSpaceID_XHTML, elementName->getName(), attributes, formOwner);
   } else {
-    elt = createElement(kNameSpaceID_XHTML, elementName->name, attributes, formOwner, current->node);
+    elt = createElement(kNameSpaceID_XHTML,
+                        elementName->getName(),
+                        attributes,
+                        formOwner,
+                        current->node);
     appendElement(elt, current->node);
   }
   nsHtml5StackNode* node = new nsHtml5StackNode(elementName, elt);
   push(node);
 }
 
 void 
 nsHtml5TreeBuilder::appendVoidElementToCurrentMayFoster(nsIAtom* name, nsHtml5HtmlAttributes* attributes, nsIContentHandle* form)
@@ -4124,51 +4135,51 @@ nsHtml5TreeBuilder::appendVoidElementToC
   }
   elementPushed(kNameSpaceID_XHTML, name, elt);
   elementPopped(kNameSpaceID_XHTML, name, elt);
 }
 
 void 
 nsHtml5TreeBuilder::appendVoidElementToCurrentMayFoster(nsHtml5ElementName* elementName, nsHtml5HtmlAttributes* attributes)
 {
-  nsIAtom* popName = elementName->name;
+  nsIAtom* popName = elementName->getName();
   nsIContentHandle* elt;
   nsHtml5StackNode* current = stack[currentPtr];
   if (current->isFosterParenting()) {
 
     elt = createAndInsertFosterParentedElement(kNameSpaceID_XHTML, popName, attributes);
   } else {
     elt = createElement(kNameSpaceID_XHTML, popName, attributes, current->node);
     appendElement(elt, current->node);
   }
   elementPushed(kNameSpaceID_XHTML, popName, elt);
   elementPopped(kNameSpaceID_XHTML, popName, elt);
 }
 
 void 
 nsHtml5TreeBuilder::appendVoidElementToCurrentMayFosterSVG(nsHtml5ElementName* elementName, nsHtml5HtmlAttributes* attributes)
 {
-  nsIAtom* popName = elementName->camelCaseName;
+  nsIAtom* popName = elementName->getCamelCaseName();
   nsIContentHandle* elt;
   nsHtml5StackNode* current = stack[currentPtr];
   if (current->isFosterParenting()) {
 
     elt = createAndInsertFosterParentedElement(kNameSpaceID_SVG, popName, attributes);
   } else {
     elt = createElement(kNameSpaceID_SVG, popName, attributes, current->node);
     appendElement(elt, current->node);
   }
   elementPushed(kNameSpaceID_SVG, popName, elt);
   elementPopped(kNameSpaceID_SVG, popName, elt);
 }
 
 void 
 nsHtml5TreeBuilder::appendVoidElementToCurrentMayFosterMathML(nsHtml5ElementName* elementName, nsHtml5HtmlAttributes* attributes)
 {
-  nsIAtom* popName = elementName->name;
+  nsIAtom* popName = elementName->getName();
   nsIContentHandle* elt;
   nsHtml5StackNode* current = stack[currentPtr];
   if (current->isFosterParenting()) {
 
     elt = createAndInsertFosterParentedElement(kNameSpaceID_MathML, popName, attributes);
   } else {
     elt = createElement(kNameSpaceID_MathML, popName, attributes, current->node);
     appendElement(elt, current->node);