Bug 1347737 - Introduce a new non-heap-allocated type for holding nsStringBuffer* in the HTML parser. r=wchen.
authorHenri Sivonen <hsivonen@hsivonen.fi>
Mon, 20 Mar 2017 14:45:15 +0200
changeset 351935 9a4a83630f4cb1ee667f208599eaff95b7d9dc82
parent 351934 0612106ae03e11754741fa615abcb0e6c350f5f8
child 351936 c0e6cf04adb9a36293e170a223c76eb46891a381
push id31623
push userarchaeopteryx@coole-files.de
push dateSat, 08 Apr 2017 20:46:02 +0000
treeherdermozilla-central@21c4aca1ae60 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerswchen
bugs1347737
milestone55.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1347737 - Introduce a new non-heap-allocated type for holding nsStringBuffer* in the HTML parser. r=wchen. MozReview-Commit-ID: Gn9fXroxQhY
parser/html/moz.build
parser/html/nsHtml5ArrayCopy.h
parser/html/nsHtml5AttributeName.cpp
parser/html/nsHtml5AttributeName.h
parser/html/nsHtml5ElementName.cpp
parser/html/nsHtml5ElementName.h
parser/html/nsHtml5Highlighter.cpp
parser/html/nsHtml5Highlighter.h
parser/html/nsHtml5HtmlAttributes.cpp
parser/html/nsHtml5HtmlAttributes.h
parser/html/nsHtml5MetaScanner.cpp
parser/html/nsHtml5MetaScanner.h
parser/html/nsHtml5MetaScannerCppSupplement.h
parser/html/nsHtml5PlainTextUtils.cpp
parser/html/nsHtml5Portability.cpp
parser/html/nsHtml5Portability.h
parser/html/nsHtml5SpeculativeLoad.h
parser/html/nsHtml5StackNode.cpp
parser/html/nsHtml5StackNode.h
parser/html/nsHtml5StateSnapshot.cpp
parser/html/nsHtml5StateSnapshot.h
parser/html/nsHtml5StreamParser.cpp
parser/html/nsHtml5StreamParser.h
parser/html/nsHtml5String.cpp
parser/html/nsHtml5String.h
parser/html/nsHtml5Tokenizer.cpp
parser/html/nsHtml5Tokenizer.h
parser/html/nsHtml5TreeBuilder.cpp
parser/html/nsHtml5TreeBuilder.h
parser/html/nsHtml5TreeBuilderCppSupplement.h
parser/html/nsHtml5TreeOperation.cpp
parser/html/nsHtml5UTF16Buffer.cpp
parser/html/nsHtml5UTF16Buffer.h
parser/html/nsHtml5ViewSourceUtils.cpp
--- a/parser/html/moz.build
+++ b/parser/html/moz.build
@@ -34,16 +34,17 @@ EXPORTS += [
     'nsHtml5OwningUTF16Buffer.h',
     'nsHtml5Parser.h',
     'nsHtml5PlainTextUtils.h',
     'nsHtml5RefPtr.h',
     'nsHtml5Speculation.h',
     'nsHtml5SpeculativeLoad.h',
     'nsHtml5StreamListener.h',
     'nsHtml5StreamParser.h',
+    'nsHtml5String.h',
     'nsHtml5StringParser.h',
     'nsHtml5SVGLoadDispatcher.h',
     'nsHtml5TreeOperation.h',
     'nsHtml5TreeOpExecutor.h',
     'nsHtml5TreeOpStage.h',
     'nsHtml5UTF16Buffer.h',
     'nsHtml5UTF16BufferHSupplement.h',
     'nsHtml5ViewSourceUtils.h',
@@ -73,16 +74,17 @@ UNIFIED_SOURCES += [
     'nsHtml5ReleasableAttributeName.cpp',
     'nsHtml5ReleasableElementName.cpp',
     'nsHtml5Speculation.cpp',
     'nsHtml5SpeculativeLoad.cpp',
     'nsHtml5StackNode.cpp',
     'nsHtml5StateSnapshot.cpp',
     'nsHtml5StreamListener.cpp',
     'nsHtml5StreamParser.cpp',
+    'nsHtml5String.cpp',
     'nsHtml5StringParser.cpp',
     'nsHtml5SVGLoadDispatcher.cpp',
     'nsHtml5Tokenizer.cpp',
     'nsHtml5TreeBuilder.cpp',
     'nsHtml5TreeOperation.cpp',
     'nsHtml5TreeOpExecutor.cpp',
     'nsHtml5TreeOpStage.cpp',
     'nsHtml5UTF16Buffer.cpp',
--- a/parser/html/nsHtml5ArrayCopy.h
+++ b/parser/html/nsHtml5ArrayCopy.h
@@ -46,20 +46,21 @@ class nsHtml5ArrayCopy {
     }
 
     static inline void
     arraycopy(int32_t* source, int32_t* target, int32_t length)
     {
       memcpy(target, source, size_t(length) * sizeof(int32_t));
     }
 
-    static inline void
-    arraycopy(nsString** source, nsString** target, int32_t length)
+    static inline void arraycopy(nsHtml5String* source,
+                                 nsHtml5String* target,
+                                 int32_t length)
     {
-      memcpy(target, source, size_t(length) * sizeof(nsString*));
+      memcpy(target, source, size_t(length) * sizeof(nsHtml5String));
     }
 
     static inline void
     arraycopy(nsHtml5AttributeName** source, nsHtml5AttributeName** target, int32_t length)
     {
       memcpy(target, source, size_t(length) * sizeof(nsHtml5AttributeName*));
     }
 
--- a/parser/html/nsHtml5AttributeName.cpp
+++ b/parser/html/nsHtml5AttributeName.cpp
@@ -24,17 +24,17 @@
  * THIS IS A GENERATED FILE. PLEASE DO NOT EDIT.
  * Please edit AttributeName.java instead and regenerate.
  */
 
 #define nsHtml5AttributeName_cpp__
 
 #include "nsIAtom.h"
 #include "nsHtml5AtomTable.h"
-#include "nsString.h"
+#include "nsHtml5String.h"
 #include "nsNameSpaceManager.h"
 #include "nsIContent.h"
 #include "nsTraceRefcnt.h"
 #include "jArray.h"
 #include "nsHtml5ArrayCopy.h"
 #include "nsAHtml5TreeBuilderState.h"
 #include "nsHtml5Atoms.h"
 #include "nsHtml5ByteReadable.h"
--- a/parser/html/nsHtml5AttributeName.h
+++ b/parser/html/nsHtml5AttributeName.h
@@ -25,17 +25,17 @@
  * Please edit AttributeName.java instead and regenerate.
  */
 
 #ifndef nsHtml5AttributeName_h
 #define nsHtml5AttributeName_h
 
 #include "nsIAtom.h"
 #include "nsHtml5AtomTable.h"
-#include "nsString.h"
+#include "nsHtml5String.h"
 #include "nsNameSpaceManager.h"
 #include "nsIContent.h"
 #include "nsTraceRefcnt.h"
 #include "jArray.h"
 #include "nsHtml5ArrayCopy.h"
 #include "nsAHtml5TreeBuilderState.h"
 #include "nsHtml5Atoms.h"
 #include "nsHtml5ByteReadable.h"
--- a/parser/html/nsHtml5ElementName.cpp
+++ b/parser/html/nsHtml5ElementName.cpp
@@ -24,17 +24,17 @@
  * THIS IS A GENERATED FILE. PLEASE DO NOT EDIT.
  * Please edit ElementName.java instead and regenerate.
  */
 
 #define nsHtml5ElementName_cpp__
 
 #include "nsIAtom.h"
 #include "nsHtml5AtomTable.h"
-#include "nsString.h"
+#include "nsHtml5String.h"
 #include "nsNameSpaceManager.h"
 #include "nsIContent.h"
 #include "nsTraceRefcnt.h"
 #include "jArray.h"
 #include "nsHtml5ArrayCopy.h"
 #include "nsAHtml5TreeBuilderState.h"
 #include "nsHtml5Atoms.h"
 #include "nsHtml5ByteReadable.h"
--- a/parser/html/nsHtml5ElementName.h
+++ b/parser/html/nsHtml5ElementName.h
@@ -25,17 +25,17 @@
  * Please edit ElementName.java instead and regenerate.
  */
 
 #ifndef nsHtml5ElementName_h
 #define nsHtml5ElementName_h
 
 #include "nsIAtom.h"
 #include "nsHtml5AtomTable.h"
-#include "nsString.h"
+#include "nsHtml5String.h"
 #include "nsNameSpaceManager.h"
 #include "nsIContent.h"
 #include "nsTraceRefcnt.h"
 #include "jArray.h"
 #include "nsHtml5ArrayCopy.h"
 #include "nsAHtml5TreeBuilderState.h"
 #include "nsHtml5Atoms.h"
 #include "nsHtml5ByteReadable.h"
--- a/parser/html/nsHtml5Highlighter.cpp
+++ b/parser/html/nsHtml5Highlighter.cpp
@@ -86,31 +86,31 @@ nsHtml5Highlighter::Start(const nsAutoSt
   Push(nsGkAtoms::head, nullptr);
 
   Push(nsGkAtoms::title, nullptr);
   // XUL will add the "Source of: " prefix.
   uint32_t length = aTitle.Length();
   if (length > INT32_MAX) {
     length = INT32_MAX;
   }
-  AppendCharacters(aTitle.get(), 0, (int32_t)length);
+  AppendCharacters(aTitle.BeginReading(), 0, (int32_t)length);
   Pop(); // title
 
   Push(nsGkAtoms::link, nsHtml5ViewSourceUtils::NewLinkAttributes());
 
   mOpQueue.AppendElement()->Init(eTreeOpUpdateStyleSheet, CurrentNode());
 
   Pop(); // link
 
   Pop(); // head
 
   Push(nsGkAtoms::body, nsHtml5ViewSourceUtils::NewBodyAttributes());
 
   nsHtml5HtmlAttributes* preAttrs = new nsHtml5HtmlAttributes(0);
-  nsString* preId = new nsString(NS_LITERAL_STRING("line1"));
+  nsHtml5String preId = nsHtml5Portability::newStringFromLiteral("line1");
   preAttrs->addAttribute(nsHtml5AttributeName::ATTR_ID, preId, -1);
   Push(nsGkAtoms::pre, preAttrs);
 
   StartCharacters();
 
   mOpQueue.AppendElement()->Init(eTreeOpStartLayout);
 }
 
@@ -613,29 +613,29 @@ nsHtml5Highlighter::FlushOps()
   if (hasOps) {
     mOpSink->MoveOpsFrom(mOpQueue);
   }
   return hasOps;
 }
 
 void
 nsHtml5Highlighter::MaybeLinkifyAttributeValue(nsHtml5AttributeName* aName,
-                                               nsString* aValue)
+                                               nsHtml5String aValue)
 {
   if (!(nsHtml5AttributeName::ATTR_HREF == aName ||
         nsHtml5AttributeName::ATTR_SRC == aName ||
         nsHtml5AttributeName::ATTR_ACTION == aName ||
         nsHtml5AttributeName::ATTR_CITE == aName ||
         nsHtml5AttributeName::ATTR_BACKGROUND == aName ||
         nsHtml5AttributeName::ATTR_LONGDESC == aName ||
         nsHtml5AttributeName::ATTR_XLINK_HREF == aName ||
         nsHtml5AttributeName::ATTR_DEFINITIONURL == aName)) {
     return;
   }
-  AddViewSourceHref(*aValue);
+  AddViewSourceHref(aValue);
 }
 
 void
 nsHtml5Highlighter::CompletedNamedCharacterReference()
 {
   AddClass(sEntity);
 }
 
@@ -712,37 +712,37 @@ nsHtml5Highlighter::AppendCharacters(con
 
 void
 nsHtml5Highlighter::AddClass(const char16_t* aClass)
 {
   mOpQueue.AppendElement()->InitAddClass(CurrentNode(), aClass);
 }
 
 void
-nsHtml5Highlighter::AddViewSourceHref(const nsString& aValue)
+nsHtml5Highlighter::AddViewSourceHref(nsHtml5String aValue)
 {
   char16_t* bufferCopy = new char16_t[aValue.Length() + 1];
-  memcpy(bufferCopy, aValue.get(), aValue.Length() * sizeof(char16_t));
+  aValue.CopyToBuffer(bufferCopy);
   bufferCopy[aValue.Length()] = 0;
 
   mOpQueue.AppendElement()->Init(eTreeOpAddViewSourceHref,
                                  bufferCopy,
                                  aValue.Length(),
                                  CurrentNode());
 }
 
 void
-nsHtml5Highlighter::AddBase(const nsString& aValue)
+nsHtml5Highlighter::AddBase(nsHtml5String aValue)
 {
   if(mSeenBase) {
     return;
   }
   mSeenBase = true;
   char16_t* bufferCopy = new char16_t[aValue.Length() + 1];
-  memcpy(bufferCopy, aValue.get(), aValue.Length() * sizeof(char16_t));
+  aValue.CopyToBuffer(bufferCopy);
   bufferCopy[aValue.Length()] = 0;
 
   mOpQueue.AppendElement()->Init(eTreeOpAddViewSourceBase,
                                  bufferCopy,
                                  aValue.Length());
 }
 
 void
--- a/parser/html/nsHtml5Highlighter.h
+++ b/parser/html/nsHtml5Highlighter.h
@@ -73,17 +73,17 @@ class nsHtml5Highlighter
      * Linkify the current attribute value if the attribute name is one of
      * known URL attributes. (When executing tree ops, javascript: URLs will
      * not be linkified, though.)
      *
      * @param aName the name of the attribute
      * @param aValue the value of the attribute
      */
     void MaybeLinkifyAttributeValue(nsHtml5AttributeName* aName,
-                                    nsString* aValue);
+                                    nsHtml5String aValue);
 
     /**
      * Inform the highlighter that the tokenizer successfully completed a
      * named character reference.
      */
     void CompletedNamedCharacterReference();
 
     /**
@@ -142,17 +142,17 @@ class nsHtml5Highlighter
      */
     void AddErrorToCurrentSlash(const char* aMsgId);
     
     /**
      * Enqueues a tree op for adding base to the urls with the view-source:
      *
      * @param aValue the base URL to add
      */
-    void AddBase(const nsString& aValue);
+    void AddBase(nsHtml5String aValue);
 
   private:
 
     /**
      * Starts a span with no class.
      */
     void StartSpan();
 
@@ -267,18 +267,18 @@ class nsHtml5Highlighter
                           int32_t aLength);
 
     /**
      * Enqueues a tree op for adding an href attribute with the view-source:
      * URL scheme to the current node.
      *
      * @param aValue the (potentially relative) URL to link to
      */
-    void AddViewSourceHref(const nsString& aValue);
-    
+    void AddViewSourceHref(nsHtml5String aValue);
+
     /**
      * The state we are transitioning away from.
      */
     int32_t mState;
 
     /**
      * The index of the first UTF-16 code unit in mBuffer that hasn't been
      * flushed yet.
--- a/parser/html/nsHtml5HtmlAttributes.cpp
+++ b/parser/html/nsHtml5HtmlAttributes.cpp
@@ -25,17 +25,17 @@
  * THIS IS A GENERATED FILE. PLEASE DO NOT EDIT.
  * Please edit HtmlAttributes.java instead and regenerate.
  */
 
 #define nsHtml5HtmlAttributes_cpp__
 
 #include "nsIAtom.h"
 #include "nsHtml5AtomTable.h"
-#include "nsString.h"
+#include "nsHtml5String.h"
 #include "nsNameSpaceManager.h"
 #include "nsIContent.h"
 #include "nsTraceRefcnt.h"
 #include "jArray.h"
 #include "nsHtml5ArrayCopy.h"
 #include "nsAHtml5TreeBuilderState.h"
 #include "nsHtml5Atoms.h"
 #include "nsHtml5ByteReadable.h"
@@ -53,21 +53,21 @@
 #include "nsHtml5StateSnapshot.h"
 #include "nsHtml5Portability.h"
 
 #include "nsHtml5HtmlAttributes.h"
 
 nsHtml5HtmlAttributes* nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES = nullptr;
 
 nsHtml5HtmlAttributes::nsHtml5HtmlAttributes(int32_t mode)
-  : mode(mode),
-    length(0),
-    names(jArray<nsHtml5AttributeName*,int32_t>::newJArray(8)),
-    values(jArray<nsString*,int32_t>::newJArray(8)),
-    lines(jArray<int32_t,int32_t>::newJArray(8))
+  : mode(mode)
+  , length(0)
+  , names(jArray<nsHtml5AttributeName*, int32_t>::newJArray(8))
+  , values(jArray<nsHtml5String, int32_t>::newJArray(8))
+  , lines(jArray<int32_t, int32_t>::newJArray(8))
 {
   MOZ_COUNT_CTOR(nsHtml5HtmlAttributes);
 }
 
 
 nsHtml5HtmlAttributes::~nsHtml5HtmlAttributes()
 {
   MOZ_COUNT_DTOR(nsHtml5HtmlAttributes);
@@ -80,17 +80,17 @@ nsHtml5HtmlAttributes::getIndex(nsHtml5A
   for (int32_t i = 0; i < length; i++) {
     if (names[i] == name) {
       return i;
     }
   }
   return -1;
 }
 
-nsString* 
+nsHtml5String
 nsHtml5HtmlAttributes::getValue(nsHtml5AttributeName* name)
 {
   int32_t index = getIndex(name);
   if (index == -1) {
     return nullptr;
   } else {
     return getValueNoBoundsCheck(index);
   }
@@ -118,17 +118,17 @@ nsHtml5HtmlAttributes::getURINoBoundsChe
 
 nsIAtom* 
 nsHtml5HtmlAttributes::getPrefixNoBoundsCheck(int32_t index)
 {
   MOZ_ASSERT(index < length && index >= 0, "Index out of bounds");
   return names[index]->getPrefix(mode);
 }
 
-nsString* 
+nsHtml5String
 nsHtml5HtmlAttributes::getValueNoBoundsCheck(int32_t index)
 {
   MOZ_ASSERT(index < length && index >= 0, "Index out of bounds");
   return values[index];
 }
 
 nsHtml5AttributeName* 
 nsHtml5HtmlAttributes::getAttributeNameNoBoundsCheck(int32_t index)
@@ -139,25 +139,28 @@ nsHtml5HtmlAttributes::getAttributeNameN
 
 int32_t 
 nsHtml5HtmlAttributes::getLineNoBoundsCheck(int32_t index)
 {
   MOZ_ASSERT(index < length && index >= 0, "Index out of bounds");
   return lines[index];
 }
 
-void 
-nsHtml5HtmlAttributes::addAttribute(nsHtml5AttributeName* name, nsString* value, int32_t line)
+void
+nsHtml5HtmlAttributes::addAttribute(nsHtml5AttributeName* name,
+                                    nsHtml5String value,
+                                    int32_t line)
 {
   if (names.length == length) {
     int32_t newLen = length << 1;
     jArray<nsHtml5AttributeName*,int32_t> newNames = jArray<nsHtml5AttributeName*,int32_t>::newJArray(newLen);
     nsHtml5ArrayCopy::arraycopy(names, newNames, names.length);
     names = newNames;
-    jArray<nsString*,int32_t> newValues = jArray<nsString*,int32_t>::newJArray(newLen);
+    jArray<nsHtml5String, int32_t> newValues =
+      jArray<nsHtml5String, int32_t>::newJArray(newLen);
     nsHtml5ArrayCopy::arraycopy(values, newValues, values.length);
     values = newValues;
     jArray<int32_t,int32_t> newLines = jArray<int32_t,int32_t>::newJArray(newLen);
     nsHtml5ArrayCopy::arraycopy(lines, newLines, lines.length);
     lines = newLines;
   }
   names[length] = name;
   values[length] = value;
@@ -166,27 +169,27 @@ nsHtml5HtmlAttributes::addAttribute(nsHt
 }
 
 void 
 nsHtml5HtmlAttributes::clear(int32_t m)
 {
   for (int32_t i = 0; i < length; i++) {
     names[i]->release();
     names[i] = nullptr;
-    nsHtml5Portability::releaseString(values[i]);
+    values[i].Release();
     values[i] = nullptr;
   }
   length = 0;
   mode = m;
 }
 
 void 
 nsHtml5HtmlAttributes::releaseValue(int32_t i)
 {
-  nsHtml5Portability::releaseString(values[i]);
+  values[i].Release();
 }
 
 void 
 nsHtml5HtmlAttributes::clearWithoutReleasingContents()
 {
   for (int32_t i = 0; i < length; i++) {
     names[i] = nullptr;
     values[i] = nullptr;
--- a/parser/html/nsHtml5HtmlAttributes.h
+++ b/parser/html/nsHtml5HtmlAttributes.h
@@ -26,17 +26,17 @@
  * Please edit HtmlAttributes.java instead and regenerate.
  */
 
 #ifndef nsHtml5HtmlAttributes_h
 #define nsHtml5HtmlAttributes_h
 
 #include "nsIAtom.h"
 #include "nsHtml5AtomTable.h"
-#include "nsString.h"
+#include "nsHtml5String.h"
 #include "nsNameSpaceManager.h"
 #include "nsIContent.h"
 #include "nsTraceRefcnt.h"
 #include "jArray.h"
 #include "nsHtml5ArrayCopy.h"
 #include "nsAHtml5TreeBuilderState.h"
 #include "nsHtml5Atoms.h"
 #include "nsHtml5ByteReadable.h"
@@ -59,31 +59,33 @@ class nsHtml5Portability;
 class nsHtml5HtmlAttributes
 {
   public:
     static nsHtml5HtmlAttributes* EMPTY_ATTRIBUTES;
   private:
     int32_t mode;
     int32_t length;
     autoJArray<nsHtml5AttributeName*,int32_t> names;
-    autoJArray<nsString*,int32_t> values;
+    autoJArray<nsHtml5String, int32_t> values;
     autoJArray<int32_t,int32_t> lines;
   public:
     explicit nsHtml5HtmlAttributes(int32_t mode);
     ~nsHtml5HtmlAttributes();
     int32_t getIndex(nsHtml5AttributeName* name);
-    nsString* getValue(nsHtml5AttributeName* name);
+    nsHtml5String getValue(nsHtml5AttributeName* name);
     int32_t getLength();
     nsIAtom* getLocalNameNoBoundsCheck(int32_t index);
     int32_t getURINoBoundsCheck(int32_t index);
     nsIAtom* getPrefixNoBoundsCheck(int32_t index);
-    nsString* getValueNoBoundsCheck(int32_t index);
+    nsHtml5String getValueNoBoundsCheck(int32_t index);
     nsHtml5AttributeName* getAttributeNameNoBoundsCheck(int32_t index);
     int32_t getLineNoBoundsCheck(int32_t index);
-    void addAttribute(nsHtml5AttributeName* name, nsString* value, int32_t line);
+    void addAttribute(nsHtml5AttributeName* name,
+                      nsHtml5String value,
+                      int32_t line);
     void clear(int32_t m);
     void releaseValue(int32_t i);
     void clearWithoutReleasingContents();
     bool contains(nsHtml5AttributeName* name);
     void adjustForMath();
     void adjustForSvg();
     nsHtml5HtmlAttributes* cloneAttributes(nsHtml5AtomTable* interner);
     bool equalsAnother(nsHtml5HtmlAttributes* other);
--- a/parser/html/nsHtml5MetaScanner.cpp
+++ b/parser/html/nsHtml5MetaScanner.cpp
@@ -25,17 +25,17 @@
  * THIS IS A GENERATED FILE. PLEASE DO NOT EDIT.
  * Please edit MetaScanner.java instead and regenerate.
  */
 
 #define nsHtml5MetaScanner_cpp__
 
 #include "nsIAtom.h"
 #include "nsHtml5AtomTable.h"
-#include "nsString.h"
+#include "nsHtml5String.h"
 #include "nsNameSpaceManager.h"
 #include "nsIContent.h"
 #include "nsTraceRefcnt.h"
 #include "jArray.h"
 #include "nsHtml5ArrayCopy.h"
 #include "nsAHtml5TreeBuilderState.h"
 #include "nsHtml5Atoms.h"
 #include "nsHtml5ByteReadable.h"
@@ -81,18 +81,18 @@ nsHtml5MetaScanner::nsHtml5MetaScanner(n
 {
   MOZ_COUNT_CTOR(nsHtml5MetaScanner);
 }
 
 
 nsHtml5MetaScanner::~nsHtml5MetaScanner()
 {
   MOZ_COUNT_DTOR(nsHtml5MetaScanner);
-  nsHtml5Portability::releaseString(content);
-  nsHtml5Portability::releaseString(charset);
+  content.Release();
+  charset.Release();
 }
 
 void 
 nsHtml5MetaScanner::stateLoop(int32_t state)
 {
   int32_t c = -1;
   bool reconsume = false;
   stateloop: for (; ; ) {
@@ -766,37 +766,38 @@ nsHtml5MetaScanner::handleAttributeValue
     return;
   }
 }
 
 bool 
 nsHtml5MetaScanner::handleTag()
 {
   bool stop = handleTagInner();
-  nsHtml5Portability::releaseString(content);
+  content.Release();
   content = nullptr;
-  nsHtml5Portability::releaseString(charset);
+  charset.Release();
   charset = nullptr;
   httpEquivState = NS_HTML5META_SCANNER_HTTP_EQUIV_NOT_SEEN;
   return stop;
 }
 
 bool 
 nsHtml5MetaScanner::handleTagInner()
 {
   if (!!charset && tryCharset(charset)) {
     return true;
   }
   if (!!content && httpEquivState == NS_HTML5META_SCANNER_HTTP_EQUIV_CONTENT_TYPE) {
-    nsString* extract = nsHtml5TreeBuilder::extractCharsetFromContent(content, treeBuilder);
+    nsHtml5String extract =
+      nsHtml5TreeBuilder::extractCharsetFromContent(content, treeBuilder);
     if (!extract) {
       return false;
     }
     bool success = tryCharset(extract);
-    nsHtml5Portability::releaseString(extract);
+    extract.Release();
     return success;
   }
   return false;
 }
 
 void
 nsHtml5MetaScanner::initializeStatics()
 {
--- a/parser/html/nsHtml5MetaScanner.h
+++ b/parser/html/nsHtml5MetaScanner.h
@@ -26,17 +26,17 @@
  * Please edit MetaScanner.java instead and regenerate.
  */
 
 #ifndef nsHtml5MetaScanner_h
 #define nsHtml5MetaScanner_h
 
 #include "nsIAtom.h"
 #include "nsHtml5AtomTable.h"
-#include "nsString.h"
+#include "nsHtml5String.h"
 #include "nsNameSpaceManager.h"
 #include "nsIContent.h"
 #include "nsTraceRefcnt.h"
 #include "jArray.h"
 #include "nsHtml5ArrayCopy.h"
 #include "nsAHtml5TreeBuilderState.h"
 #include "nsHtml5Atoms.h"
 #include "nsHtml5ByteReadable.h"
@@ -71,18 +71,18 @@ class nsHtml5MetaScanner
     int32_t charsetIndex;
     int32_t httpEquivIndex;
     int32_t contentTypeIndex;
   protected:
     int32_t stateSave;
   private:
     int32_t strBufLen;
     autoJArray<char16_t,int32_t> strBuf;
-    nsString* content;
-    nsString* charset;
+    nsHtml5String content;
+    nsHtml5String charset;
     int32_t httpEquivState;
     nsHtml5TreeBuilder* treeBuilder;
   public:
     explicit nsHtml5MetaScanner(nsHtml5TreeBuilder* tb);
     ~nsHtml5MetaScanner();
   protected:
     void stateLoop(int32_t state);
   private:
@@ -95,17 +95,18 @@ class nsHtml5MetaScanner
       return c;
     }
 
     void addToBuffer(int32_t c);
     void handleAttributeValue();
     bool handleTag();
     bool handleTagInner();
   protected:
-    bool tryCharset(nsString* encoding);
+    bool tryCharset(nsHtml5String encoding);
+
   public:
     static void initializeStatics();
     static void releaseStatics();
 
 #include "nsHtml5MetaScannerHSupplement.h"
 };
 
 #define NS_HTML5META_SCANNER_NO 0
--- a/parser/html/nsHtml5MetaScannerCppSupplement.h
+++ b/parser/html/nsHtml5MetaScannerCppSupplement.h
@@ -14,23 +14,25 @@ nsHtml5MetaScanner::sniff(nsHtml5ByteRea
 {
   readable = bytes;
   stateLoop(stateSave);
   readable = nullptr;
   charset.Assign(mCharset);
 }
 
 bool
-nsHtml5MetaScanner::tryCharset(nsString* charset)
+nsHtml5MetaScanner::tryCharset(nsHtml5String charset)
 {
   // This code needs to stay in sync with
   // nsHtml5StreamParser::internalEncodingDeclaration. Unfortunately, the
   // trickery with member fields here leads to some copy-paste reuse. :-(
   nsAutoCString label;
-  CopyUTF16toUTF8(*charset, label);
+  nsString charset16; // Not Auto, because using it to hold nsStringBuffer*
+  charset.ToString(charset16);
+  CopyUTF16toUTF8(charset16, label);
   nsAutoCString encoding;
   if (!EncodingUtils::FindEncodingForLabel(label, encoding)) {
     return false;
   }
   if (encoding.EqualsLiteral("UTF-16BE") ||
       encoding.EqualsLiteral("UTF-16LE")) {
     mCharset.AssignLiteral("UTF-8");
     return true;
--- a/parser/html/nsHtml5PlainTextUtils.cpp
+++ b/parser/html/nsHtml5PlainTextUtils.cpp
@@ -1,40 +1,43 @@
 /* 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 "nsHtml5PlainTextUtils.h"
 #include "nsHtml5AttributeName.h"
+#include "nsHtml5Portability.h"
 #include "nsIServiceManager.h"
 #include "nsIStringBundle.h"
 #include "mozilla/Preferences.h"
+#include "nsHtml5String.h"
 
 // static
 nsHtml5HtmlAttributes*
 nsHtml5PlainTextUtils::NewLinkAttributes()
 {
   nsHtml5HtmlAttributes* linkAttrs = new nsHtml5HtmlAttributes(0);
-  nsString* rel = new nsString(NS_LITERAL_STRING("alternate stylesheet"));
+  nsHtml5String rel =
+    nsHtml5Portability::newStringFromLiteral("alternate stylesheet");
   linkAttrs->addAttribute(nsHtml5AttributeName::ATTR_REL, rel, -1);
-  nsString* type = new nsString(NS_LITERAL_STRING("text/css"));
+  nsHtml5String type = nsHtml5Portability::newStringFromLiteral("text/css");
   linkAttrs->addAttribute(nsHtml5AttributeName::ATTR_TYPE, type, -1);
-  nsString* href = new nsString(
-      NS_LITERAL_STRING("resource://gre-resources/plaintext.css"));
+  nsHtml5String href = nsHtml5Portability::newStringFromLiteral(
+    "resource://gre-resources/plaintext.css");
   linkAttrs->addAttribute(nsHtml5AttributeName::ATTR_HREF, href, -1);
 
   nsresult rv;
   nsCOMPtr<nsIStringBundleService> bundleService = do_GetService(NS_STRINGBUNDLE_CONTRACTID, &rv);
   NS_ASSERTION(NS_SUCCEEDED(rv) && bundleService, "The bundle service could not be loaded");
   nsCOMPtr<nsIStringBundle> bundle;
   rv = bundleService->CreateBundle("chrome://global/locale/browser.properties",
                                    getter_AddRefs(bundle));
   NS_ASSERTION(NS_SUCCEEDED(rv) && bundle, "chrome://global/locale/browser.properties could not be loaded");
   nsXPIDLString title;
   if (bundle) {
     bundle->GetStringFromName(u"plainText.wordWrap", getter_Copies(title));
   }
 
-  nsString* titleCopy = new nsString(title);
-  linkAttrs->addAttribute(nsHtml5AttributeName::ATTR_TITLE, titleCopy, -1);
+  linkAttrs->addAttribute(
+    nsHtml5AttributeName::ATTR_TITLE, nsHtml5String::FromString(title), -1);
   return linkAttrs;
 }
--- a/parser/html/nsHtml5Portability.cpp
+++ b/parser/html/nsHtml5Portability.cpp
@@ -11,144 +11,111 @@
 nsIAtom*
 nsHtml5Portability::newLocalNameFromBuffer(char16_t* buf, int32_t offset, int32_t length, nsHtml5AtomTable* interner)
 {
   NS_ASSERTION(!offset, "The offset should always be zero here.");
   NS_ASSERTION(interner, "Didn't get an atom service.");
   return interner->GetAtom(nsDependentSubstring(buf, buf + length));
 }
 
-nsString*
-nsHtml5Portability::newStringFromBuffer(char16_t* buf, int32_t offset, int32_t length, nsHtml5TreeBuilder* treeBuilder)
+nsHtml5String
+nsHtml5Portability::newStringFromBuffer(char16_t* buf,
+                                        int32_t offset,
+                                        int32_t length,
+                                        nsHtml5TreeBuilder* treeBuilder)
 {
-  nsString* str = new nsString();
-  bool succeeded = str->Append(buf + offset, length, mozilla::fallible);
-  if (!succeeded) {
-    str->Assign(char16_t(0xFFFD));
-    treeBuilder->MarkAsBroken(NS_ERROR_OUT_OF_MEMORY);
-  }
-  return str;
+  return nsHtml5String::FromBuffer(buf + offset, length, treeBuilder);
 }
 
-nsString*
+nsHtml5String
 nsHtml5Portability::newEmptyString()
 {
-  return new nsString();
+  return nsHtml5String::EmptyString();
 }
 
-nsString*
+nsHtml5String
 nsHtml5Portability::newStringFromLiteral(const char* literal)
 {
-  nsString* str = new nsString();
-  str->AssignASCII(literal);
-  return str;
+  return nsHtml5String::FromLiteral(literal);
 }
 
-nsString*
-nsHtml5Portability::newStringFromString(nsString* string) {
-  nsString* newStr = new nsString();
-  newStr->Assign(*string);
-  return newStr;
+nsHtml5String
+nsHtml5Portability::newStringFromString(nsHtml5String string)
+{
+  return string.Clone();
 }
 
 jArray<char16_t,int32_t>
 nsHtml5Portability::newCharArrayFromLocal(nsIAtom* local)
 {
   nsAutoString temp;
   local->ToString(temp);
   int32_t len = temp.Length();
   jArray<char16_t,int32_t> arr = jArray<char16_t,int32_t>::newJArray(len);
   memcpy(arr, temp.BeginReading(), len * sizeof(char16_t));
   return arr;
 }
 
-jArray<char16_t,int32_t>
-nsHtml5Portability::newCharArrayFromString(nsString* string)
+jArray<char16_t, int32_t>
+nsHtml5Portability::newCharArrayFromString(nsHtml5String string)
 {
-  int32_t len = string->Length();
+  MOZ_RELEASE_ASSERT(string);
+  uint32_t len = string.Length();
+  MOZ_RELEASE_ASSERT(len < INT32_MAX);
   jArray<char16_t,int32_t> arr = jArray<char16_t,int32_t>::newJArray(len);
-  memcpy(arr, string->BeginReading(), len * sizeof(char16_t));
+  string.CopyToBuffer(arr);
   return arr;
 }
 
 nsIAtom*
 nsHtml5Portability::newLocalFromLocal(nsIAtom* local, nsHtml5AtomTable* interner)
 {
   NS_PRECONDITION(local, "Atom was null.");
   NS_PRECONDITION(interner, "Atom table was null");
   if (!local->IsStaticAtom()) {
     nsAutoString str;
     local->ToString(str);
     local = interner->GetAtom(str);
   }
   return local;
 }
 
-void
-nsHtml5Portability::releaseString(nsString* str)
-{
-  delete str;
-}
-
 bool
 nsHtml5Portability::localEqualsBuffer(nsIAtom* local, char16_t* buf, int32_t offset, int32_t length)
 {
   return local->Equals(buf + offset, length);
 }
 
 bool
-nsHtml5Portability::lowerCaseLiteralIsPrefixOfIgnoreAsciiCaseString(const char* lowerCaseLiteral, nsString* string)
+nsHtml5Portability::lowerCaseLiteralIsPrefixOfIgnoreAsciiCaseString(
+  const char* lowerCaseLiteral,
+  nsHtml5String string)
 {
-  if (!string) {
-    return false;
-  }
-  const char* litPtr = lowerCaseLiteral;
-  const char16_t* strPtr = string->BeginReading();
-  const char16_t* end = string->EndReading();
-  char16_t litChar;
-  while ((litChar = *litPtr)) {
-    NS_ASSERTION(!(litChar >= 'A' && litChar <= 'Z'), "Literal isn't in lower case.");
-    if (strPtr == end) {
-      return false;
-    }
-    char16_t strChar = *strPtr;
-    if (strChar >= 'A' && strChar <= 'Z') {
-      strChar += 0x20;
-    }
-    if (litChar != strChar) {
-      return false;
-    }
-    ++litPtr;
-    ++strPtr;
-  }
-  return true;
+  return string.LowerCaseStartsWithASCII(lowerCaseLiteral);
 }
 
 bool
-nsHtml5Portability::lowerCaseLiteralEqualsIgnoreAsciiCaseString(const char* lowerCaseLiteral, nsString* string)
+nsHtml5Portability::lowerCaseLiteralEqualsIgnoreAsciiCaseString(
+  const char* lowerCaseLiteral,
+  nsHtml5String string)
 {
-  if (!string) {
-    return false;
-  }
-  return string->LowerCaseEqualsASCII(lowerCaseLiteral);
+  return string.LowerCaseEqualsASCII(lowerCaseLiteral);
 }
 
 bool
-nsHtml5Portability::literalEqualsString(const char* literal, nsString* string)
+nsHtml5Portability::literalEqualsString(const char* literal,
+                                        nsHtml5String string)
 {
-  if (!string) {
-    return false;
-  }
-  return string->EqualsASCII(literal);
+  return string.EqualsASCII(literal);
 }
 
 bool
-nsHtml5Portability::stringEqualsString(nsString* one, nsString* other)
+nsHtml5Portability::stringEqualsString(nsHtml5String one, nsHtml5String other)
 {
-  return one->Equals(*other);
+  return one.Equals(other);
 }
 
 void
 nsHtml5Portability::initializeStatics()
 {
 }
 
 void
--- a/parser/html/nsHtml5Portability.h
+++ b/parser/html/nsHtml5Portability.h
@@ -25,17 +25,17 @@
  * Please edit Portability.java instead and regenerate.
  */
 
 #ifndef nsHtml5Portability_h
 #define nsHtml5Portability_h
 
 #include "nsIAtom.h"
 #include "nsHtml5AtomTable.h"
-#include "nsString.h"
+#include "nsHtml5String.h"
 #include "nsNameSpaceManager.h"
 #include "nsIContent.h"
 #include "nsTraceRefcnt.h"
 #include "jArray.h"
 #include "nsHtml5ArrayCopy.h"
 #include "nsAHtml5TreeBuilderState.h"
 #include "nsHtml5Atoms.h"
 #include "nsHtml5ByteReadable.h"
@@ -54,29 +54,36 @@ class nsHtml5HtmlAttributes;
 class nsHtml5UTF16Buffer;
 class nsHtml5StateSnapshot;
 
 
 class nsHtml5Portability
 {
   public:
     static nsIAtom* newLocalNameFromBuffer(char16_t* buf, int32_t offset, int32_t length, nsHtml5AtomTable* interner);
-    static nsString* newStringFromBuffer(char16_t* buf, int32_t offset, int32_t length, nsHtml5TreeBuilder* treeBuilder);
-    static nsString* newEmptyString();
-    static nsString* newStringFromLiteral(const char* literal);
-    static nsString* newStringFromString(nsString* string);
+    static nsHtml5String newStringFromBuffer(char16_t* buf,
+                                             int32_t offset,
+                                             int32_t length,
+                                             nsHtml5TreeBuilder* treeBuilder);
+    static nsHtml5String newEmptyString();
+    static nsHtml5String newStringFromLiteral(const char* literal);
+    static nsHtml5String newStringFromString(nsHtml5String string);
     static jArray<char16_t,int32_t> newCharArrayFromLocal(nsIAtom* local);
-    static jArray<char16_t,int32_t> newCharArrayFromString(nsString* string);
+    static jArray<char16_t, int32_t> newCharArrayFromString(
+      nsHtml5String string);
     static nsIAtom* newLocalFromLocal(nsIAtom* local, nsHtml5AtomTable* interner);
-    static void releaseString(nsString* str);
     static bool localEqualsBuffer(nsIAtom* local, char16_t* buf, int32_t offset, int32_t length);
-    static bool lowerCaseLiteralIsPrefixOfIgnoreAsciiCaseString(const char* lowerCaseLiteral, nsString* string);
-    static bool lowerCaseLiteralEqualsIgnoreAsciiCaseString(const char* lowerCaseLiteral, nsString* string);
-    static bool literalEqualsString(const char* literal, nsString* string);
-    static bool stringEqualsString(nsString* one, nsString* other);
+    static bool lowerCaseLiteralIsPrefixOfIgnoreAsciiCaseString(
+      const char* lowerCaseLiteral,
+      nsHtml5String string);
+    static bool lowerCaseLiteralEqualsIgnoreAsciiCaseString(
+      const char* lowerCaseLiteral,
+      nsHtml5String string);
+    static bool literalEqualsString(const char* literal, nsHtml5String string);
+    static bool stringEqualsString(nsHtml5String one, nsHtml5String other);
     static void initializeStatics();
     static void releaseStatics();
 };
 
 
 
 #endif
 
--- a/parser/html/nsHtml5SpeculativeLoad.h
+++ b/parser/html/nsHtml5SpeculativeLoad.h
@@ -30,55 +30,67 @@ enum eHtml5SpeculativeLoad {
   eSpeculativeLoadPreconnect
 };
 
 class nsHtml5SpeculativeLoad {
   public:
     nsHtml5SpeculativeLoad();
     ~nsHtml5SpeculativeLoad();
 
-    inline void InitBase(const nsAString& aUrl)
+    inline void InitBase(nsHtml5String aUrl)
     {
       NS_PRECONDITION(mOpCode == eSpeculativeLoadUninitialized,
                       "Trying to reinitialize a speculative load!");
       mOpCode = eSpeculativeLoadBase;
-      mUrl.Assign(aUrl);
+      aUrl.ToString(mUrl);
     }
 
-    inline void InitMetaCSP(const nsAString& aCSP) {
+    inline void InitMetaCSP(nsHtml5String aCSP)
+    {
       NS_PRECONDITION(mOpCode == eSpeculativeLoadUninitialized,
                       "Trying to reinitialize a speculative load!");
       mOpCode = eSpeculativeLoadCSP;
+      nsString csp; // Not Auto, because using it to hold nsStringBuffer*
+      aCSP.ToString(csp);
       mMetaCSP.Assign(
-        nsContentUtils::TrimWhitespace<nsContentUtils::IsHTMLWhitespace>(aCSP));
+        nsContentUtils::TrimWhitespace<nsContentUtils::IsHTMLWhitespace>(csp));
     }
 
-    inline void InitMetaReferrerPolicy(const nsAString& aReferrerPolicy) {
+    inline void InitMetaReferrerPolicy(nsHtml5String aReferrerPolicy)
+    {
       NS_PRECONDITION(mOpCode == eSpeculativeLoadUninitialized,
                       "Trying to reinitialize a speculative load!");
       mOpCode = eSpeculativeLoadMetaReferrer;
+      nsString
+        referrerPolicy; // Not Auto, because using it to hold nsStringBuffer*
+      aReferrerPolicy.ToString(referrerPolicy);
       mReferrerPolicy.Assign(
-        nsContentUtils::TrimWhitespace<nsContentUtils::IsHTMLWhitespace>(aReferrerPolicy));
+        nsContentUtils::TrimWhitespace<nsContentUtils::IsHTMLWhitespace>(
+          referrerPolicy));
     }
 
-    inline void InitImage(const nsAString& aUrl,
-                          const nsAString& aCrossOrigin,
-                          const nsAString& aReferrerPolicy,
-                          const nsAString& aSrcset,
-                          const nsAString& aSizes)
+    inline void InitImage(nsHtml5String aUrl,
+                          nsHtml5String aCrossOrigin,
+                          nsHtml5String aReferrerPolicy,
+                          nsHtml5String aSrcset,
+                          nsHtml5String aSizes)
     {
       NS_PRECONDITION(mOpCode == eSpeculativeLoadUninitialized,
                       "Trying to reinitialize a speculative load!");
       mOpCode = eSpeculativeLoadImage;
-      mUrl.Assign(aUrl);
-      mCrossOrigin.Assign(aCrossOrigin);
+      aUrl.ToString(mUrl);
+      aCrossOrigin.ToString(mCrossOrigin);
+      nsString
+        referrerPolicy; // Not Auto, because using it to hold nsStringBuffer*
+      aReferrerPolicy.ToString(referrerPolicy);
       mReferrerPolicy.Assign(
-        nsContentUtils::TrimWhitespace<nsContentUtils::IsHTMLWhitespace>(aReferrerPolicy));
-      mSrcset.Assign(aSrcset);
-      mSizes.Assign(aSizes);
+        nsContentUtils::TrimWhitespace<nsContentUtils::IsHTMLWhitespace>(
+          referrerPolicy));
+      aSrcset.ToString(mSrcset);
+      aSizes.ToString(mSizes);
     }
 
     // <picture> elements have multiple <source> nodes followed by an <img>,
     // where we use the first valid source, which may be the img. Because we
     // can't determine validity at this point without parsing CSS and getting
     // main thread state, we push preload operations for picture pushed and
     // popped, so that the target of the preload ops can determine what picture
     // and nesting level each source/img from the main preloading code exists
@@ -92,78 +104,79 @@ class nsHtml5SpeculativeLoad {
 
     inline void InitEndPicture()
     {
       NS_PRECONDITION(mOpCode == eSpeculativeLoadUninitialized,
                       "Trying to reinitialize a speculative load!");
       mOpCode = eSpeculativeLoadEndPicture;
     }
 
-    inline void InitPictureSource(const nsAString& aSrcset,
-                                  const nsAString& aSizes,
-                                  const nsAString& aType,
-                                  const nsAString& aMedia)
+    inline void InitPictureSource(nsHtml5String aSrcset,
+                                  nsHtml5String aSizes,
+                                  nsHtml5String aType,
+                                  nsHtml5String aMedia)
     {
       NS_PRECONDITION(mOpCode == eSpeculativeLoadUninitialized,
                       "Trying to reinitialize a speculative load!");
       mOpCode = eSpeculativeLoadPictureSource;
-      mSrcset.Assign(aSrcset);
-      mSizes.Assign(aSizes);
-      mTypeOrCharsetSourceOrDocumentMode.Assign(aType);
-      mMedia.Assign(aMedia);
+      aSrcset.ToString(mSrcset);
+      aSizes.ToString(mSizes);
+      aType.ToString(mTypeOrCharsetSourceOrDocumentMode);
+      aMedia.ToString(mMedia);
     }
 
-    inline void InitScript(const nsAString& aUrl,
-                           const nsAString& aCharset,
-                           const nsAString& aType,
-                           const nsAString& aCrossOrigin,
-                           const nsAString& aIntegrity,
+    inline void InitScript(nsHtml5String aUrl,
+                           nsHtml5String aCharset,
+                           nsHtml5String aType,
+                           nsHtml5String aCrossOrigin,
+                           nsHtml5String aIntegrity,
                            bool aParserInHead)
     {
       NS_PRECONDITION(mOpCode == eSpeculativeLoadUninitialized,
                       "Trying to reinitialize a speculative load!");
       mOpCode = aParserInHead ?
           eSpeculativeLoadScriptFromHead : eSpeculativeLoadScript;
-      mUrl.Assign(aUrl);
-      mCharset.Assign(aCharset);
-      mTypeOrCharsetSourceOrDocumentMode.Assign(aType);
-      mCrossOrigin.Assign(aCrossOrigin);
-      mIntegrity.Assign(aIntegrity);
+      aUrl.ToString(mUrl);
+      aCharset.ToString(mCharset);
+      aType.ToString(mTypeOrCharsetSourceOrDocumentMode);
+      aCrossOrigin.ToString(mCrossOrigin);
+      aIntegrity.ToString(mIntegrity);
     }
 
-    inline void InitStyle(const nsAString& aUrl, const nsAString& aCharset,
-                          const nsAString& aCrossOrigin,
-                          const nsAString& aIntegrity)
+    inline void InitStyle(nsHtml5String aUrl,
+                          nsHtml5String aCharset,
+                          nsHtml5String aCrossOrigin,
+                          nsHtml5String aIntegrity)
     {
       NS_PRECONDITION(mOpCode == eSpeculativeLoadUninitialized,
                       "Trying to reinitialize a speculative load!");
       mOpCode = eSpeculativeLoadStyle;
-      mUrl.Assign(aUrl);
-      mCharset.Assign(aCharset);
-      mCrossOrigin.Assign(aCrossOrigin);
-      mIntegrity.Assign(aIntegrity);
+      aUrl.ToString(mUrl);
+      aCharset.ToString(mCharset);
+      aCrossOrigin.ToString(mCrossOrigin);
+      aIntegrity.ToString(mIntegrity);
     }
 
     /**
      * "Speculative" manifest loads aren't truly speculative--if a manifest
      * gets loaded, we are committed to it. There can never be a <script>
      * before the manifest, so the situation of having to undo a manifest due
      * to document.write() never arises. The reason why a parser
      * thread-discovered manifest gets loaded via the speculative load queue
      * as opposed to tree operation queue is that the manifest must get
      * processed before any actual speculative loads such as scripts. Thus,
      * manifests seen by the parser thread have to maintain the queue order
      * relative to true speculative loads. See bug 541079.
      */
-    inline void InitManifest(const nsAString& aUrl)
+    inline void InitManifest(nsHtml5String aUrl)
     {
       NS_PRECONDITION(mOpCode == eSpeculativeLoadUninitialized,
                       "Trying to reinitialize a speculative load!");
       mOpCode = eSpeculativeLoadManifest;
-      mUrl.Assign(aUrl);
+      aUrl.ToString(mUrl);
     }
 
     /**
      * "Speculative" charset setting isn't truly speculative. If the charset
      * is set via this operation, we are committed to it unless chardet or
      * a late meta cause a reload. The reason why a parser
      * thread-discovered charset gets communicated via the speculative load
      * queue as opposed to tree operation queue is that the charset change
@@ -190,24 +203,23 @@ class nsHtml5SpeculativeLoad {
     inline void InitSetDocumentMode(nsHtml5DocumentMode aMode)
     {
       NS_PRECONDITION(mOpCode == eSpeculativeLoadUninitialized,
                       "Trying to reinitialize a speculative load!");
       mOpCode = eSpeculativeLoadSetDocumentMode;
       mTypeOrCharsetSourceOrDocumentMode.Assign((char16_t)aMode);
     }
 
-    inline void InitPreconnect(const nsAString& aUrl,
-                               const nsAString& aCrossOrigin)
+    inline void InitPreconnect(nsHtml5String aUrl, nsHtml5String aCrossOrigin)
     {
       NS_PRECONDITION(mOpCode == eSpeculativeLoadUninitialized,
                       "Trying to reinitialize a speculative load!");
       mOpCode = eSpeculativeLoadPreconnect;
-      mUrl.Assign(aUrl);
-      mCrossOrigin.Assign(aCrossOrigin);
+      aUrl.ToString(mUrl);
+      aCrossOrigin.ToString(mCrossOrigin);
     }
 
     void Perform(nsHtml5TreeOpExecutor* aExecutor);
 
   private:
     eHtml5SpeculativeLoad mOpCode;
     nsString mUrl;
     nsString mReferrerPolicy;
--- a/parser/html/nsHtml5StackNode.cpp
+++ b/parser/html/nsHtml5StackNode.cpp
@@ -25,17 +25,17 @@
  * THIS IS A GENERATED FILE. PLEASE DO NOT EDIT.
  * Please edit StackNode.java instead and regenerate.
  */
 
 #define nsHtml5StackNode_cpp__
 
 #include "nsIAtom.h"
 #include "nsHtml5AtomTable.h"
-#include "nsString.h"
+#include "nsHtml5String.h"
 #include "nsNameSpaceManager.h"
 #include "nsIContent.h"
 #include "nsTraceRefcnt.h"
 #include "jArray.h"
 #include "nsHtml5ArrayCopy.h"
 #include "nsAHtml5TreeBuilderState.h"
 #include "nsHtml5Atoms.h"
 #include "nsHtml5ByteReadable.h"
--- a/parser/html/nsHtml5StackNode.h
+++ b/parser/html/nsHtml5StackNode.h
@@ -26,17 +26,17 @@
  * Please edit StackNode.java instead and regenerate.
  */
 
 #ifndef nsHtml5StackNode_h
 #define nsHtml5StackNode_h
 
 #include "nsIAtom.h"
 #include "nsHtml5AtomTable.h"
-#include "nsString.h"
+#include "nsHtml5String.h"
 #include "nsNameSpaceManager.h"
 #include "nsIContent.h"
 #include "nsTraceRefcnt.h"
 #include "jArray.h"
 #include "nsHtml5ArrayCopy.h"
 #include "nsAHtml5TreeBuilderState.h"
 #include "nsHtml5Atoms.h"
 #include "nsHtml5ByteReadable.h"
--- a/parser/html/nsHtml5StateSnapshot.cpp
+++ b/parser/html/nsHtml5StateSnapshot.cpp
@@ -24,17 +24,17 @@
  * THIS IS A GENERATED FILE. PLEASE DO NOT EDIT.
  * Please edit StateSnapshot.java instead and regenerate.
  */
 
 #define nsHtml5StateSnapshot_cpp__
 
 #include "nsIAtom.h"
 #include "nsHtml5AtomTable.h"
-#include "nsString.h"
+#include "nsHtml5String.h"
 #include "nsNameSpaceManager.h"
 #include "nsIContent.h"
 #include "nsTraceRefcnt.h"
 #include "jArray.h"
 #include "nsHtml5ArrayCopy.h"
 #include "nsAHtml5TreeBuilderState.h"
 #include "nsHtml5Atoms.h"
 #include "nsHtml5ByteReadable.h"
--- a/parser/html/nsHtml5StateSnapshot.h
+++ b/parser/html/nsHtml5StateSnapshot.h
@@ -25,17 +25,17 @@
  * Please edit StateSnapshot.java instead and regenerate.
  */
 
 #ifndef nsHtml5StateSnapshot_h
 #define nsHtml5StateSnapshot_h
 
 #include "nsIAtom.h"
 #include "nsHtml5AtomTable.h"
-#include "nsString.h"
+#include "nsHtml5String.h"
 #include "nsNameSpaceManager.h"
 #include "nsIContent.h"
 #include "nsTraceRefcnt.h"
 #include "jArray.h"
 #include "nsHtml5ArrayCopy.h"
 #include "nsAHtml5TreeBuilderState.h"
 #include "nsHtml5Atoms.h"
 #include "nsHtml5ByteReadable.h"
--- a/parser/html/nsHtml5StreamParser.cpp
+++ b/parser/html/nsHtml5StreamParser.cpp
@@ -1275,28 +1275,30 @@ nsHtml5StreamParser::PreferredForInterna
     return false;
   }
 
   aEncoding.Assign(newEncoding);
   return true;
 }
 
 bool
-nsHtml5StreamParser::internalEncodingDeclaration(nsString* aEncoding)
+nsHtml5StreamParser::internalEncodingDeclaration(nsHtml5String aEncoding)
 {
   // This code needs to stay in sync with
   // nsHtml5MetaScanner::tryCharset. Unfortunately, the
   // trickery with member fields there leads to some copy-paste reuse. :-(
   NS_ASSERTION(IsParserThread(), "Wrong thread!");
   if (mCharsetSource >= kCharsetFromMetaTag) { // this threshold corresponds to "confident" in the HTML5 spec
     return false;
   }
 
+  nsString newEncoding16; // Not Auto, because using it to hold nsStringBuffer*
+  aEncoding.ToString(newEncoding16);
   nsAutoCString newEncoding;
-  CopyUTF16toUTF8(*aEncoding, newEncoding);
+  CopyUTF16toUTF8(newEncoding16, newEncoding);
 
   if (!PreferredForInternalEncodingDecl(newEncoding)) {
     return false;
   }
 
   if (mReparseForbidden) {
     // This mReparseForbidden check happens after the call to
     // PreferredForInternalEncodingDecl so that if that method calls
--- a/parser/html/nsHtml5StreamParser.h
+++ b/parser/html/nsHtml5StreamParser.h
@@ -139,17 +139,17 @@ class nsHtml5StreamParser : public nsICh
      */
     NS_IMETHOD Notify(const char* aCharset, nsDetectionConfident aConf) override;
 
     // EncodingDeclarationHandler
     // https://hg.mozilla.org/projects/htmlparser/file/tip/src/nu/validator/htmlparser/common/EncodingDeclarationHandler.java
     /**
      * Tree builder uses this to report a late <meta charset>
      */
-    bool internalEncodingDeclaration(nsString* aEncoding);
+    bool internalEncodingDeclaration(nsHtml5String aEncoding);
 
     // Not from an external interface
 
     /**
      *  Call this method once you've created a parser, and want to instruct it
      *  about what charset to load
      *
      *  @param   aCharset the charset of a document
new file mode 100644
--- /dev/null
+++ b/parser/html/nsHtml5String.cpp
@@ -0,0 +1,225 @@
+/* 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 "nsHtml5String.h"
+#include "nsCharTraits.h"
+#include "nsUTF8Utils.h"
+#include "nsHtml5TreeBuilder.h"
+
+nsHtml5String::nsHtml5String(already_AddRefed<nsStringBuffer> aBuffer,
+                             uint32_t aLength)
+  : mBuffer(aBuffer.take())
+  , mLength(aLength)
+{
+  if (mBuffer) {
+    MOZ_ASSERT(aLength);
+  } else {
+    MOZ_ASSERT(!aLength || aLength == UINT32_MAX);
+  }
+}
+
+void
+nsHtml5String::ToString(nsAString& aString)
+{
+  if (mBuffer) {
+    mBuffer->ToString(mLength, aString);
+  } else {
+    aString.Truncate();
+    if (mLength) {
+      aString.SetIsVoid(true);
+    }
+  }
+}
+
+void
+nsHtml5String::CopyToBuffer(char16_t* aBuffer)
+{
+  if (mBuffer) {
+    memcpy(aBuffer, mBuffer->Data(), mLength * sizeof(char16_t));
+  }
+}
+
+bool
+nsHtml5String::LowerCaseEqualsASCII(const char* aLowerCaseLiteral)
+{
+  if (!mBuffer) {
+    if (mLength) {
+      // This string is null
+      return false;
+    }
+    // this string is empty
+    return !(*aLowerCaseLiteral);
+  }
+  return !nsCharTraits<char16_t>::compareLowerCaseToASCIINullTerminated(
+    reinterpret_cast<char16_t*>(mBuffer->Data()), Length(), aLowerCaseLiteral);
+}
+
+bool
+nsHtml5String::EqualsASCII(const char* aLiteral)
+{
+  if (!mBuffer) {
+    if (mLength) {
+      // This string is null
+      return false;
+    }
+    // this string is empty
+    return !(*aLiteral);
+  }
+  return !nsCharTraits<char16_t>::compareASCIINullTerminated(
+    reinterpret_cast<char16_t*>(mBuffer->Data()), Length(), aLiteral);
+}
+
+bool
+nsHtml5String::LowerCaseStartsWithASCII(const char* aLowerCaseLiteral)
+{
+  if (!mBuffer) {
+    if (mLength) {
+      // This string is null
+      return false;
+    }
+    // this string is empty
+    return !(*aLowerCaseLiteral);
+  }
+  const char* litPtr = aLowerCaseLiteral;
+  const char16_t* strPtr = reinterpret_cast<char16_t*>(mBuffer->Data());
+  const char16_t* end = strPtr + Length();
+  char16_t litChar;
+  while ((litChar = *litPtr) && (strPtr != end)) {
+    MOZ_ASSERT(!(litChar >= 'A' && litChar <= 'Z'),
+               "Literal isn't in lower case.");
+    char16_t strChar = *strPtr;
+    if (strChar >= 'A' && strChar <= 'Z') {
+      strChar += 0x20;
+    }
+    if (litChar != strChar) {
+      return false;
+    }
+    ++litPtr;
+    ++strPtr;
+  }
+  return true;
+}
+
+bool
+nsHtml5String::Equals(nsHtml5String aOther)
+{
+  MOZ_ASSERT(operator bool());
+  MOZ_ASSERT(aOther);
+  if (mLength != aOther.mLength) {
+    return false;
+  }
+  if (!mBuffer) {
+    return true;
+  }
+  MOZ_ASSERT(aOther.mBuffer);
+  return !memcmp(
+    mBuffer->Data(), aOther.mBuffer->Data(), Length() * sizeof(char16_t));
+}
+
+nsHtml5String
+nsHtml5String::Clone()
+{
+  MOZ_ASSERT(operator bool());
+  RefPtr<nsStringBuffer> ref(mBuffer);
+  return nsHtml5String(ref.forget(), mLength);
+}
+
+void
+nsHtml5String::Release()
+{
+  if (mBuffer) {
+    mBuffer->Release();
+    mBuffer = nullptr;
+  }
+  mLength = UINT32_MAX;
+}
+
+// static
+nsHtml5String
+nsHtml5String::FromBuffer(char16_t* aBuffer,
+                          int32_t aLength,
+                          nsHtml5TreeBuilder* aTreeBuilder)
+{
+  if (!aLength) {
+    return nsHtml5String(nullptr, 0U);
+  }
+  // Work with nsStringBuffer directly to make sure that storage is actually
+  // nsStringBuffer and to make sure the allocation strategy matches
+  // nsAttrValue::GetStringBuffer, so that it doesn't need to reallocate and
+  // copy.
+  RefPtr<nsStringBuffer> buffer(
+    nsStringBuffer::Alloc((aLength + 1) * sizeof(char16_t)));
+  if (!buffer) {
+    if (!aTreeBuilder) {
+      MOZ_CRASH("Out of memory.");
+    }
+    aTreeBuilder->MarkAsBroken(NS_ERROR_OUT_OF_MEMORY);
+    buffer = nsStringBuffer::Alloc(2 * sizeof(char16_t));
+    if (!buffer) {
+      MOZ_CRASH(
+        "Out of memory so badly that couldn't even allocate placeholder.");
+    }
+    char16_t* data = reinterpret_cast<char16_t*>(buffer->Data());
+    data[0] = 0xFFFD;
+    data[1] = 0;
+    return nsHtml5String(buffer.forget(), 1);
+  }
+  char16_t* data = reinterpret_cast<char16_t*>(buffer->Data());
+  memcpy(data, aBuffer, aLength * sizeof(char16_t));
+  data[aLength] = 0;
+  return nsHtml5String(buffer.forget(), aLength);
+}
+
+// static
+nsHtml5String
+nsHtml5String::FromLiteral(const char* aLiteral)
+{
+  size_t length = std::strlen(aLiteral);
+  if (!length) {
+    return nsHtml5String(nullptr, 0U);
+  }
+  // Work with nsStringBuffer directly to make sure that storage is actually
+  // nsStringBuffer and to make sure the allocation strategy matches
+  // nsAttrValue::GetStringBuffer, so that it doesn't need to reallocate and
+  // copy.
+  RefPtr<nsStringBuffer> buffer(
+    nsStringBuffer::Alloc((length + 1) * sizeof(char16_t)));
+  if (!buffer) {
+    MOZ_CRASH("Out of memory.");
+  }
+  char16_t* data = reinterpret_cast<char16_t*>(buffer->Data());
+  LossyConvertEncoding8to16 converter(data);
+  converter.write(aLiteral, length);
+  data[length] = 0;
+  return nsHtml5String(buffer.forget(), length);
+}
+
+// static
+nsHtml5String
+nsHtml5String::FromString(const nsAString& aString)
+{
+  auto length = aString.Length();
+  if (!length) {
+    return nsHtml5String(nullptr, 0U);
+  }
+  RefPtr<nsStringBuffer> buffer = nsStringBuffer::FromString(aString);
+  if (buffer) {
+    return nsHtml5String(buffer.forget(), length);
+  }
+  buffer = nsStringBuffer::Alloc((length + 1) * sizeof(char16_t));
+  if (!buffer) {
+    MOZ_CRASH("Out of memory.");
+  }
+  char16_t* data = reinterpret_cast<char16_t*>(buffer->Data());
+  memcpy(data, aString.BeginReading(), length * sizeof(char16_t));
+  data[length] = 0;
+  return nsHtml5String(buffer.forget(), length);
+}
+
+// static
+nsHtml5String
+nsHtml5String::EmptyString()
+{
+  return nsHtml5String(nullptr, 0U);
+}
new file mode 100644
--- /dev/null
+++ b/parser/html/nsHtml5String.h
@@ -0,0 +1,95 @@
+/* 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 nsHtml5String_h
+#define nsHtml5String_h
+
+#include "nsString.h"
+
+class nsHtml5TreeBuilder;
+
+/**
+ * A pass-by-value type that combines an unsafe `nsStringBuffer*` with its
+ * logical length (`uint32_t`). (`nsStringBuffer` knows its capacity but not
+ * its logical length, i.e. how much of the capacity is in use.)
+ *
+ * Holding or passing this type is as unsafe as holding or passing
+ * `nsStringBuffer*`.
+ *
+ * Empty strings and null strings are distinct. Since an empty nsString does
+ * not have a an `nsStringBuffer`, both empty and null `nsHtml5String` have
+ * `nullptr` as `mBuffer`. If `mBuffer` is `nullptr`, the empty case is marked
+ * with `mLength` being zero and the null case with `mLength` being non-zero.
+ */
+class nsHtml5String final
+{
+public:
+  /**
+   * Default constructor.
+   */
+  inline nsHtml5String()
+    : nsHtml5String(nullptr)
+  {
+  }
+
+  /**
+   * Constructor from nullptr.
+   */
+  inline MOZ_IMPLICIT nsHtml5String(decltype(nullptr))
+    : mBuffer(nullptr)
+    , mLength(UINT32_MAX)
+  {
+  }
+
+  inline uint32_t Length() const { return mBuffer ? mLength : 0; }
+
+  /**
+   * False iff the string is logically null
+   */
+  inline MOZ_IMPLICIT operator bool() const { return !(!mBuffer && mLength); }
+
+  void ToString(nsAString& aString);
+
+  void CopyToBuffer(char16_t* aBuffer);
+
+  bool LowerCaseEqualsASCII(const char* aLowerCaseLiteral);
+
+  bool EqualsASCII(const char* aLiteral);
+
+  bool LowerCaseStartsWithASCII(const char* aLowerCaseLiteral);
+
+  bool Equals(nsHtml5String aOther);
+
+  nsHtml5String Clone();
+
+  void Release();
+
+  static nsHtml5String FromBuffer(char16_t* aBuffer,
+                                  int32_t aLength,
+                                  nsHtml5TreeBuilder* aTreeBuilder);
+
+  static nsHtml5String FromLiteral(const char* aLiteral);
+
+  static nsHtml5String FromString(const nsAString& aString);
+
+  static nsHtml5String EmptyString();
+
+private:
+  /**
+   * Constructor from raw parts.
+   */
+  nsHtml5String(already_AddRefed<nsStringBuffer> aBuffer, uint32_t aLength);
+
+  /**
+   * nullptr if the string is logically null or logically empty
+   */
+  nsStringBuffer* mBuffer;
+
+  /**
+   * The length of the string. non-zero if the string is logically null.
+   */
+  uint32_t mLength;
+};
+
+#endif // nsHtml5String_h
--- a/parser/html/nsHtml5Tokenizer.cpp
+++ b/parser/html/nsHtml5Tokenizer.cpp
@@ -27,17 +27,17 @@
  * THIS IS A GENERATED FILE. PLEASE DO NOT EDIT.
  * Please edit Tokenizer.java instead and regenerate.
  */
 
 #define nsHtml5Tokenizer_cpp__
 
 #include "nsIAtom.h"
 #include "nsHtml5AtomTable.h"
-#include "nsString.h"
+#include "nsHtml5String.h"
 #include "nsIContent.h"
 #include "nsTraceRefcnt.h"
 #include "jArray.h"
 #include "nsHtml5DocumentMode.h"
 #include "nsHtml5ArrayCopy.h"
 #include "nsHtml5NamedCharacters.h"
 #include "nsHtml5NamedCharactersAccel.h"
 #include "nsHtml5Atoms.h"
@@ -107,18 +107,19 @@ nsHtml5Tokenizer::nsHtml5Tokenizer(nsHtm
 }
 
 void 
 nsHtml5Tokenizer::setInterner(nsHtml5AtomTable* interner)
 {
   this->interner = interner;
 }
 
-void 
-nsHtml5Tokenizer::initLocation(nsString* newPublicId, nsString* newSystemId)
+void
+nsHtml5Tokenizer::initLocation(nsHtml5String newPublicId,
+                               nsHtml5String newSystemId)
 {
   this->systemId = newSystemId;
   this->publicId = newPublicId;
 }
 
 bool 
 nsHtml5Tokenizer::isViewingXmlSource()
 {
@@ -217,20 +218,21 @@ nsHtml5Tokenizer::emitOrAppendCharRefBuf
   } else {
     if (charRefBufLen > 0) {
       tokenHandler->characters(charRefBuf, 0, charRefBufLen);
       charRefBufLen = 0;
     }
   }
 }
 
-nsString* 
+nsHtml5String
 nsHtml5Tokenizer::strBufToString()
 {
-  nsString* str = nsHtml5Portability::newStringFromBuffer(strBuf, 0, strBufLen, tokenHandler);
+  nsHtml5String str =
+    nsHtml5Portability::newStringFromBuffer(strBuf, 0, strBufLen, tokenHandler);
   clearStrBufAfterUse();
   return str;
 }
 
 void 
 nsHtml5Tokenizer::strBufToDoctypeName()
 {
   doctypeName = nsHtml5Portability::newLocalNameFromBuffer(strBuf, 0, strBufLen, interner);
@@ -345,17 +347,17 @@ nsHtml5Tokenizer::addAttributeWithoutVal
     clearStrBufAfterUse();
   }
 }
 
 void 
 nsHtml5Tokenizer::addAttributeWithValue()
 {
   if (attributeName) {
-    nsString* val = strBufToString();
+    nsHtml5String val = strBufToString();
     if (mViewSource) {
       mViewSource->MaybeLinkifyAttributeValue(attributeName, val);
     }
     attributes->addAttribute(attributeName, val, attributeLine);
     attributeName = nullptr;
   } else {
     clearStrBufAfterUse();
   }
@@ -3491,21 +3493,21 @@ nsHtml5Tokenizer::stateLoop(int32_t stat
 }
 
 void 
 nsHtml5Tokenizer::initDoctypeFields()
 {
   clearStrBufAfterUse();
   doctypeName = nsHtml5Atoms::emptystring;
   if (systemIdentifier) {
-    nsHtml5Portability::releaseString(systemIdentifier);
+    systemIdentifier.Release();
     systemIdentifier = nullptr;
   }
   if (publicIdentifier) {
-    nsHtml5Portability::releaseString(publicIdentifier);
+    publicIdentifier.Release();
     publicIdentifier = nullptr;
   }
   forceQuirks = false;
 }
 
 void 
 nsHtml5Tokenizer::emitCarriageReturn(char16_t* buf, int32_t pos)
 {
@@ -3657,21 +3659,21 @@ nsHtml5Tokenizer::eof()
       case NS_HTML5TOKENIZER_MARKUP_DECLARATION_OCTYPE: {
         if (index < 6) {
           errBogusComment();
           emitComment(0, 0);
         } else {
           errEofInDoctype();
           doctypeName = nsHtml5Atoms::emptystring;
           if (systemIdentifier) {
-            nsHtml5Portability::releaseString(systemIdentifier);
+            systemIdentifier.Release();
             systemIdentifier = nullptr;
           }
           if (publicIdentifier) {
-            nsHtml5Portability::releaseString(publicIdentifier);
+            publicIdentifier.Release();
             publicIdentifier = nullptr;
           }
           forceQuirks = true;
           emitDoctypeToken(0);
           NS_HTML5_BREAK(eofloop);
         }
         NS_HTML5_BREAK(eofloop);
       }
@@ -3891,24 +3893,24 @@ nsHtml5Tokenizer::eof()
 }
 
 void 
 nsHtml5Tokenizer::emitDoctypeToken(int32_t pos)
 {
   cstart = pos + 1;
   tokenHandler->doctype(doctypeName, publicIdentifier, systemIdentifier, forceQuirks);
   doctypeName = nullptr;
-  nsHtml5Portability::releaseString(publicIdentifier);
+  publicIdentifier.Release();
   publicIdentifier = nullptr;
-  nsHtml5Portability::releaseString(systemIdentifier);
+  systemIdentifier.Release();
   systemIdentifier = nullptr;
 }
 
-bool 
-nsHtml5Tokenizer::internalEncodingDeclaration(nsString* internalCharset)
+bool
+nsHtml5Tokenizer::internalEncodingDeclaration(nsHtml5String internalCharset)
 {
   if (encodingDeclarationHandler) {
     return encodingDeclarationHandler->internalEncodingDeclaration(internalCharset);
   }
   return false;
 }
 
 void 
@@ -3933,21 +3935,21 @@ nsHtml5Tokenizer::emitOrAppendOne(const 
 }
 
 void 
 nsHtml5Tokenizer::end()
 {
   strBuf = nullptr;
   doctypeName = nullptr;
   if (systemIdentifier) {
-    nsHtml5Portability::releaseString(systemIdentifier);
+    systemIdentifier.Release();
     systemIdentifier = nullptr;
   }
   if (publicIdentifier) {
-    nsHtml5Portability::releaseString(publicIdentifier);
+    publicIdentifier.Release();
     publicIdentifier = nullptr;
   }
   if (tagName) {
     tagName->release();
     tagName = nullptr;
   }
   if (attributeName) {
     attributeName->release();
@@ -4036,23 +4038,23 @@ nsHtml5Tokenizer::loadState(nsHtml5Token
   seenDigits = other->seenDigits;
   endTag = other->endTag;
   shouldSuspend = false;
   if (!other->doctypeName) {
     doctypeName = nullptr;
   } else {
     doctypeName = nsHtml5Portability::newLocalFromLocal(other->doctypeName, interner);
   }
-  nsHtml5Portability::releaseString(systemIdentifier);
+  systemIdentifier.Release();
   if (!other->systemIdentifier) {
     systemIdentifier = nullptr;
   } else {
     systemIdentifier = nsHtml5Portability::newStringFromString(other->systemIdentifier);
   }
-  nsHtml5Portability::releaseString(publicIdentifier);
+  publicIdentifier.Release();
   if (!other->publicIdentifier) {
     publicIdentifier = nullptr;
   } else {
     publicIdentifier = nsHtml5Portability::newStringFromString(other->publicIdentifier);
   }
   if (tagName) {
     tagName->release();
   }
--- a/parser/html/nsHtml5Tokenizer.h
+++ b/parser/html/nsHtml5Tokenizer.h
@@ -28,17 +28,17 @@
  * Please edit Tokenizer.java instead and regenerate.
  */
 
 #ifndef nsHtml5Tokenizer_h
 #define nsHtml5Tokenizer_h
 
 #include "nsIAtom.h"
 #include "nsHtml5AtomTable.h"
-#include "nsString.h"
+#include "nsHtml5String.h"
 #include "nsIContent.h"
 #include "nsTraceRefcnt.h"
 #include "jArray.h"
 #include "nsHtml5DocumentMode.h"
 #include "nsHtml5ArrayCopy.h"
 #include "nsHtml5NamedCharacters.h"
 #include "nsHtml5NamedCharactersAccel.h"
 #include "nsHtml5Atoms.h"
@@ -101,18 +101,18 @@ class nsHtml5Tokenizer
     int32_t charRefBufMark;
   protected:
     int32_t value;
   private:
     bool seenDigits;
   protected:
     int32_t cstart;
   private:
-    nsString* publicId;
-    nsString* systemId;
+    nsHtml5String publicId;
+    nsHtml5String systemId;
     autoJArray<char16_t,int32_t> strBuf;
     int32_t strBufLen;
     autoJArray<char16_t,int32_t> charRefBuf;
     int32_t charRefBufLen;
     autoJArray<char16_t,int32_t> bmpChar;
     autoJArray<char16_t,int32_t> astralChar;
   protected:
     nsHtml5ElementName* endTagExpectation;
@@ -121,32 +121,32 @@ class nsHtml5Tokenizer
   protected:
     bool endTag;
   private:
     nsHtml5ElementName* tagName;
   protected:
     nsHtml5AttributeName* attributeName;
   private:
     nsIAtom* doctypeName;
-    nsString* publicIdentifier;
-    nsString* systemIdentifier;
+    nsHtml5String publicIdentifier;
+    nsHtml5String systemIdentifier;
     nsHtml5HtmlAttributes* attributes;
     bool newAttributesEachTime;
     bool shouldSuspend;
   protected:
     bool confident;
   private:
     int32_t line;
     int32_t attributeLine;
     nsHtml5AtomTable* interner;
     bool viewingXmlSource;
   public:
     nsHtml5Tokenizer(nsHtml5TreeBuilder* tokenHandler, bool viewingXmlSource);
     void setInterner(nsHtml5AtomTable* interner);
-    void initLocation(nsString* newPublicId, nsString* newSystemId);
+    void initLocation(nsHtml5String newPublicId, nsHtml5String newSystemId);
     bool isViewingXmlSource();
     void setStateAndEndTagExpectation(int32_t specialTokenizerState, nsIAtom* endTagExpectation);
     void setStateAndEndTagExpectation(int32_t specialTokenizerState, nsHtml5ElementName* endTagExpectation);
   private:
     void endTagExpectationToArray();
   public:
     void setLineNumber(int32_t line);
     inline int32_t getLineNumber()
@@ -188,17 +188,18 @@ class nsHtml5Tokenizer
         if (MOZ_UNLIKELY(!EnsureBufferSpace(1))) {
           MOZ_CRASH("Unable to recover from buffer reallocation failure");
         }
       }
       strBuf[strBufLen++] = c;
     }
 
   protected:
-    nsString* strBufToString();
+    nsHtml5String strBufToString();
+
   private:
     void strBufToDoctypeName();
     void emitStrBuf();
     inline void appendSecondHyphenToBogusComment()
     {
       appendStrBuf('-');
     }
 
@@ -280,17 +281,18 @@ class nsHtml5Tokenizer
     void emitDoctypeToken(int32_t pos);
   protected:
     inline char16_t checkChar(char16_t* buf, int32_t pos)
     {
       return buf[pos];
     }
 
   public:
-    bool internalEncodingDeclaration(nsString* internalCharset);
+    bool internalEncodingDeclaration(nsHtml5String internalCharset);
+
   private:
     void emitOrAppendTwo(const char16_t* val, int32_t returnState);
     void emitOrAppendOne(const char16_t* val, int32_t returnState);
   public:
     void end();
     void requestSuspension();
     bool isInDataState();
     void resetToDataState();
--- a/parser/html/nsHtml5TreeBuilder.cpp
+++ b/parser/html/nsHtml5TreeBuilder.cpp
@@ -29,17 +29,17 @@
  */
 
 #define nsHtml5TreeBuilder_cpp__
 
 #include "nsContentUtils.h"
 #include "nsIAtom.h"
 #include "nsHtml5AtomTable.h"
 #include "nsITimer.h"
-#include "nsString.h"
+#include "nsHtml5String.h"
 #include "nsNameSpaceManager.h"
 #include "nsIContent.h"
 #include "nsTraceRefcnt.h"
 #include "jArray.h"
 #include "nsHtml5DocumentMode.h"
 #include "nsHtml5ArrayCopy.h"
 #include "nsHtml5Parser.h"
 #include "nsHtml5Atoms.h"
@@ -148,24 +148,27 @@ nsHtml5TreeBuilder::startTokenization(ns
       nsIContentHandle* elt = createElement(kNameSpaceID_SVG, nsHtml5Atoms::svg, tokenizer->emptyAttributes(), nullptr);
       nsHtml5StackNode* node = new nsHtml5StackNode(nsHtml5ElementName::ELT_SVG, nsHtml5Atoms::svg, elt);
       currentPtr++;
       stack[currentPtr] = node;
     }
   }
 }
 
-void 
-nsHtml5TreeBuilder::doctype(nsIAtom* name, nsString* publicIdentifier, nsString* systemIdentifier, bool forceQuirks)
+void
+nsHtml5TreeBuilder::doctype(nsIAtom* name,
+                            nsHtml5String publicIdentifier,
+                            nsHtml5String systemIdentifier,
+                            bool forceQuirks)
 {
   needToDropLF = false;
   if (!isInForeign() && mode == NS_HTML5TREE_BUILDER_INITIAL) {
-    nsString* emptyString = nsHtml5Portability::newEmptyString();
+    nsHtml5String emptyString = nsHtml5Portability::newEmptyString();
     appendDoctypeToDocument(!name ? nsHtml5Atoms::emptystring : name, !publicIdentifier ? emptyString : publicIdentifier, !systemIdentifier ? emptyString : systemIdentifier);
-    nsHtml5Portability::releaseString(emptyString);
+    emptyString.Release();
     if (isQuirky(name, publicIdentifier, systemIdentifier, forceQuirks)) {
       errQuirkyDoctype();
       documentModeInternal(QUIRKS_MODE, publicIdentifier, systemIdentifier, false);
     } else if (isAlmostStandards(publicIdentifier, systemIdentifier)) {
       errAlmostStandardsDoctype();
       documentModeInternal(ALMOST_STANDARDS_MODE, publicIdentifier, systemIdentifier, false);
     } else {
       documentModeInternal(STANDARDS_MODE, publicIdentifier, systemIdentifier, false);
@@ -1985,18 +1988,19 @@ nsHtml5TreeBuilder::isTemplateModeStackE
 
 bool 
 nsHtml5TreeBuilder::isSpecialParentInForeign(nsHtml5StackNode* stackNode)
 {
   int32_t ns = stackNode->ns;
   return (kNameSpaceID_XHTML == ns) || (stackNode->isHtmlIntegrationPoint()) || ((kNameSpaceID_MathML == ns) && (stackNode->getGroup() == NS_HTML5TREE_BUILDER_MI_MO_MN_MS_MTEXT));
 }
 
-nsString* 
-nsHtml5TreeBuilder::extractCharsetFromContent(nsString* attributeValue, nsHtml5TreeBuilder* tb)
+nsHtml5String
+nsHtml5TreeBuilder::extractCharsetFromContent(nsHtml5String attributeValue,
+                                              nsHtml5TreeBuilder* tb)
 {
   int32_t charsetState = NS_HTML5TREE_BUILDER_CHARSET_INITIAL;
   int32_t start = -1;
   int32_t end = -1;
   autoJArray<char16_t,int32_t> buffer = nsHtml5Portability::newCharArrayFromString(attributeValue);
   for (int32_t i = 0; i < buffer.length; i++) {
     char16_t c = buffer[i];
     switch(charsetState) {
@@ -2170,49 +2174,53 @@ nsHtml5TreeBuilder::extractCharsetFromCo
           default: {
             continue;
           }
         }
       }
     }
   }
   charsetloop_end: ;
-  nsString* charset = nullptr;
-  if (start != -1) {
-    if (end == -1) {
-      end = buffer.length;
-    }
-    charset = nsHtml5Portability::newStringFromBuffer(buffer, start, end - start, tb);
+    nsHtml5String charset = nullptr;
+    if (start != -1) {
+      if (end == -1) {
+        end = buffer.length;
+      }
+      charset =
+        nsHtml5Portability::newStringFromBuffer(buffer, start, end - start, tb);
   }
   return charset;
 }
 
 void 
 nsHtml5TreeBuilder::checkMetaCharset(nsHtml5HtmlAttributes* attributes)
 {
-  nsString* charset = attributes->getValue(nsHtml5AttributeName::ATTR_CHARSET);
+  nsHtml5String charset =
+    attributes->getValue(nsHtml5AttributeName::ATTR_CHARSET);
   if (charset) {
     if (tokenizer->internalEncodingDeclaration(charset)) {
       requestSuspension();
       return;
     }
     return;
   }
   if (!nsHtml5Portability::lowerCaseLiteralEqualsIgnoreAsciiCaseString("content-type", attributes->getValue(nsHtml5AttributeName::ATTR_HTTP_EQUIV))) {
     return;
   }
-  nsString* content = attributes->getValue(nsHtml5AttributeName::ATTR_CONTENT);
+  nsHtml5String content =
+    attributes->getValue(nsHtml5AttributeName::ATTR_CONTENT);
   if (content) {
-    nsString* extract = nsHtml5TreeBuilder::extractCharsetFromContent(content, this);
+    nsHtml5String extract =
+      nsHtml5TreeBuilder::extractCharsetFromContent(content, this);
     if (extract) {
       if (tokenizer->internalEncodingDeclaration(extract)) {
         requestSuspension();
       }
     }
-    nsHtml5Portability::releaseString(extract);
+    extract.Release();
   }
 }
 
 void 
 nsHtml5TreeBuilder::endTag(nsHtml5ElementName* elementName)
 {
   flushCharacters();
   needToDropLF = false;
@@ -3202,30 +3210,35 @@ nsHtml5TreeBuilder::generateImpliedEndTa
 }
 
 bool 
 nsHtml5TreeBuilder::isSecondOnStackBody()
 {
   return currentPtr >= 1 && stack[1]->getGroup() == NS_HTML5TREE_BUILDER_BODY;
 }
 
-void 
-nsHtml5TreeBuilder::documentModeInternal(nsHtml5DocumentMode m, nsString* publicIdentifier, nsString* systemIdentifier, bool html4SpecificAdditionalErrorChecks)
+void
+nsHtml5TreeBuilder::documentModeInternal(
+  nsHtml5DocumentMode m,
+  nsHtml5String publicIdentifier,
+  nsHtml5String systemIdentifier,
+  bool html4SpecificAdditionalErrorChecks)
 {
   if (isSrcdocDocument) {
     quirks = false;
     this->documentMode(STANDARDS_MODE);
     return;
   }
   quirks = (m == QUIRKS_MODE);
   this->documentMode(m);
 }
 
-bool 
-nsHtml5TreeBuilder::isAlmostStandards(nsString* publicIdentifier, nsString* systemIdentifier)
+bool
+nsHtml5TreeBuilder::isAlmostStandards(nsHtml5String publicIdentifier,
+                                      nsHtml5String systemIdentifier)
 {
   if (nsHtml5Portability::lowerCaseLiteralEqualsIgnoreAsciiCaseString("-//w3c//dtd xhtml 1.0 transitional//en", publicIdentifier)) {
     return true;
   }
   if (nsHtml5Portability::lowerCaseLiteralEqualsIgnoreAsciiCaseString("-//w3c//dtd xhtml 1.0 frameset//en", publicIdentifier)) {
     return true;
   }
   if (systemIdentifier) {
@@ -3234,18 +3247,21 @@ nsHtml5TreeBuilder::isAlmostStandards(ns
     }
     if (nsHtml5Portability::lowerCaseLiteralEqualsIgnoreAsciiCaseString("-//w3c//dtd html 4.01 frameset//en", publicIdentifier)) {
       return true;
     }
   }
   return false;
 }
 
-bool 
-nsHtml5TreeBuilder::isQuirky(nsIAtom* name, nsString* publicIdentifier, nsString* systemIdentifier, bool forceQuirks)
+bool
+nsHtml5TreeBuilder::isQuirky(nsIAtom* name,
+                             nsHtml5String publicIdentifier,
+                             nsHtml5String systemIdentifier,
+                             bool forceQuirks)
 {
   if (forceQuirks) {
     return true;
   }
   if (name != nsHtml5Atoms::html) {
     return true;
   }
   if (publicIdentifier) {
@@ -4046,17 +4062,18 @@ nsHtml5TreeBuilder::appendToCurrentNodeA
   }
   nsHtml5StackNode* node = new nsHtml5StackNode(elementName, elt, popName, markAsHtmlIntegrationPoint);
   push(node);
 }
 
 bool 
 nsHtml5TreeBuilder::annotationXmlEncodingPermitsHtml(nsHtml5HtmlAttributes* attributes)
 {
-  nsString* encoding = attributes->getValue(nsHtml5AttributeName::ATTR_ENCODING);
+  nsHtml5String encoding =
+    attributes->getValue(nsHtml5AttributeName::ATTR_ENCODING);
   if (!encoding) {
     return false;
   }
   return nsHtml5Portability::lowerCaseLiteralEqualsIgnoreAsciiCaseString("application/xhtml+xml", encoding) || nsHtml5Portability::lowerCaseLiteralEqualsIgnoreAsciiCaseString("text/html", encoding);
 }
 
 void 
 nsHtml5TreeBuilder::appendToCurrentNodeAndPushElementMayFosterSVG(nsHtml5ElementName* elementName, nsHtml5HtmlAttributes* attributes)
--- a/parser/html/nsHtml5TreeBuilder.h
+++ b/parser/html/nsHtml5TreeBuilder.h
@@ -30,17 +30,17 @@
 
 #ifndef nsHtml5TreeBuilder_h
 #define nsHtml5TreeBuilder_h
 
 #include "nsContentUtils.h"
 #include "nsIAtom.h"
 #include "nsHtml5AtomTable.h"
 #include "nsITimer.h"
-#include "nsString.h"
+#include "nsHtml5String.h"
 #include "nsNameSpaceManager.h"
 #include "nsIContent.h"
 #include "nsTraceRefcnt.h"
 #include "jArray.h"
 #include "nsHtml5DocumentMode.h"
 #include "nsHtml5ArrayCopy.h"
 #include "nsHtml5Parser.h"
 #include "nsHtml5Atoms.h"
@@ -98,52 +98,64 @@ class nsHtml5TreeBuilder : public nsAHtm
   protected:
     autoJArray<char16_t,int32_t> charBuffer;
     int32_t charBufferLen;
   private:
     bool quirks;
     bool isSrcdocDocument;
   public:
     void startTokenization(nsHtml5Tokenizer* self);
-    void doctype(nsIAtom* name, nsString* publicIdentifier, nsString* systemIdentifier, bool forceQuirks);
+    void doctype(nsIAtom* name,
+                 nsHtml5String publicIdentifier,
+                 nsHtml5String systemIdentifier,
+                 bool forceQuirks);
     void comment(char16_t* buf, int32_t start, int32_t length);
     void characters(const char16_t* buf, int32_t start, int32_t length);
     void zeroOriginatingReplacementCharacter();
     void eof();
     void endTokenization();
     void startTag(nsHtml5ElementName* elementName, nsHtml5HtmlAttributes* attributes, bool selfClosing);
   private:
     void startTagTitleInHead(nsHtml5ElementName* elementName, nsHtml5HtmlAttributes* attributes);
     void startTagGenericRawText(nsHtml5ElementName* elementName, nsHtml5HtmlAttributes* attributes);
     void startTagScriptInHead(nsHtml5ElementName* elementName, nsHtml5HtmlAttributes* attributes);
     void startTagTemplateInHead(nsHtml5ElementName* elementName, nsHtml5HtmlAttributes* attributes);
     bool isTemplateContents();
     bool isTemplateModeStackEmpty();
     bool isSpecialParentInForeign(nsHtml5StackNode* stackNode);
   public:
-    static nsString* extractCharsetFromContent(nsString* attributeValue, nsHtml5TreeBuilder* tb);
+    static nsHtml5String extractCharsetFromContent(nsHtml5String attributeValue,
+                                                   nsHtml5TreeBuilder* tb);
+
   private:
     void checkMetaCharset(nsHtml5HtmlAttributes* attributes);
   public:
     void endTag(nsHtml5ElementName* elementName);
   private:
     void endTagTemplateInHead();
     int32_t findLastInTableScopeOrRootTemplateTbodyTheadTfoot();
     int32_t findLast(nsIAtom* name);
     int32_t findLastInTableScope(nsIAtom* name);
     int32_t findLastInButtonScope(nsIAtom* name);
     int32_t findLastInScope(nsIAtom* name);
     int32_t findLastInListScope(nsIAtom* name);
     int32_t findLastInScopeHn();
     void generateImpliedEndTagsExceptFor(nsIAtom* name);
     void generateImpliedEndTags();
     bool isSecondOnStackBody();
-    void documentModeInternal(nsHtml5DocumentMode m, nsString* publicIdentifier, nsString* systemIdentifier, bool html4SpecificAdditionalErrorChecks);
-    bool isAlmostStandards(nsString* publicIdentifier, nsString* systemIdentifier);
-    bool isQuirky(nsIAtom* name, nsString* publicIdentifier, nsString* systemIdentifier, bool forceQuirks);
+    void documentModeInternal(nsHtml5DocumentMode m,
+                              nsHtml5String publicIdentifier,
+                              nsHtml5String systemIdentifier,
+                              bool html4SpecificAdditionalErrorChecks);
+    bool isAlmostStandards(nsHtml5String publicIdentifier,
+                           nsHtml5String systemIdentifier);
+    bool isQuirky(nsIAtom* name,
+                  nsHtml5String publicIdentifier,
+                  nsHtml5String systemIdentifier,
+                  bool forceQuirks);
     void closeTheCell(int32_t eltPos);
     int32_t findLastInTableScopeTdTh();
     void clearStackBackTo(int32_t eltPos);
     void resetTheInsertionMode();
     void implicitlyCloseP();
     bool debugOnlyClearLastStackSlot();
     bool debugOnlyClearLastListSlot();
     void pushTemplateMode(int32_t mode);
@@ -219,17 +231,19 @@ class nsHtml5TreeBuilder : public nsAHtm
     void appendCharacters(nsIContentHandle* parent, char16_t* buf, int32_t start, int32_t length);
     void appendIsindexPrompt(nsIContentHandle* parent);
     void appendComment(nsIContentHandle* parent, char16_t* buf, int32_t start, int32_t length);
     void appendCommentToDocument(char16_t* buf, int32_t start, int32_t length);
     void addAttributesToElement(nsIContentHandle* element, nsHtml5HtmlAttributes* attributes);
     void markMalformedIfScript(nsIContentHandle* elt);
     void start(bool fragmentMode);
     void end();
-    void appendDoctypeToDocument(nsIAtom* name, nsString* publicIdentifier, nsString* systemIdentifier);
+    void appendDoctypeToDocument(nsIAtom* name,
+                                 nsHtml5String publicIdentifier,
+                                 nsHtml5String systemIdentifier);
     void elementPushed(int32_t ns, nsIAtom* name, nsIContentHandle* node);
     void elementPopped(int32_t ns, nsIAtom* name, nsIContentHandle* node);
   public:
     inline bool cdataSectionAllowed()
     {
       return isInForeign();
     }
 
--- a/parser/html/nsHtml5TreeBuilderCppSupplement.h
+++ b/parser/html/nsHtml5TreeBuilderCppSupplement.h
@@ -118,191 +118,188 @@ nsHtml5TreeBuilder::createElement(int32_
   // tree builder, which handles the network stream
 
   // Start wall of code for speculative loading and line numbers
 
   if (mSpeculativeLoadStage) {
     switch (aNamespace) {
       case kNameSpaceID_XHTML:
         if (nsHtml5Atoms::img == aName) {
-          nsString* url = aAttributes->getValue(nsHtml5AttributeName::ATTR_SRC);
-          nsString* srcset =
+          nsHtml5String url =
+            aAttributes->getValue(nsHtml5AttributeName::ATTR_SRC);
+          nsHtml5String srcset =
             aAttributes->getValue(nsHtml5AttributeName::ATTR_SRCSET);
-          nsString* crossOrigin =
+          nsHtml5String crossOrigin =
             aAttributes->getValue(nsHtml5AttributeName::ATTR_CROSSORIGIN);
-          nsString* referrerPolicy =
+          nsHtml5String referrerPolicy =
             aAttributes->getValue(nsHtml5AttributeName::ATTR_REFERRERPOLICY);
-          nsString* sizes =
+          nsHtml5String sizes =
             aAttributes->getValue(nsHtml5AttributeName::ATTR_SIZES);
-          mSpeculativeLoadQueue.AppendElement()->
-            InitImage(url ? *url : NullString(),
-                      crossOrigin ? *crossOrigin : NullString(),
-                      referrerPolicy ? *referrerPolicy : NullString(),
-                      srcset ? *srcset : NullString(),
-                      sizes ? *sizes : NullString());
+          mSpeculativeLoadQueue.AppendElement()->InitImage(
+            url, crossOrigin, referrerPolicy, srcset, sizes);
         } else if (nsHtml5Atoms::source == aName) {
-          nsString* srcset =
+          nsHtml5String srcset =
             aAttributes->getValue(nsHtml5AttributeName::ATTR_SRCSET);
           // Sources without srcset cannot be selected. The source could also be
           // for a media element, but in that context doesn't use srcset.  See
           // comments in nsHtml5SpeculativeLoad.h about <picture> preloading
           if (srcset) {
-            nsString* sizes =
+            nsHtml5String sizes =
               aAttributes->getValue(nsHtml5AttributeName::ATTR_SIZES);
-            nsString* type =
+            nsHtml5String type =
               aAttributes->getValue(nsHtml5AttributeName::ATTR_TYPE);
-            nsString* media =
+            nsHtml5String media =
               aAttributes->getValue(nsHtml5AttributeName::ATTR_MEDIA);
-            mSpeculativeLoadQueue.AppendElement()->
-              InitPictureSource(*srcset,
-                                sizes ? *sizes : NullString(),
-                                type ? *type : NullString(),
-                                media ? *media : NullString());
+            mSpeculativeLoadQueue.AppendElement()->InitPictureSource(
+              srcset, sizes, type, media);
           }
         } else if (nsHtml5Atoms::script == aName) {
           nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
           NS_ASSERTION(treeOp, "Tree op allocation failed.");
           treeOp->Init(eTreeOpSetScriptLineNumberAndFreeze, content, tokenizer->getLineNumber());
 
-          nsString* url = aAttributes->getValue(nsHtml5AttributeName::ATTR_SRC);
+          nsHtml5String url =
+            aAttributes->getValue(nsHtml5AttributeName::ATTR_SRC);
           if (url) {
-            nsString* charset = aAttributes->getValue(nsHtml5AttributeName::ATTR_CHARSET);
-            nsString* type = aAttributes->getValue(nsHtml5AttributeName::ATTR_TYPE);
-            nsString* crossOrigin =
+            nsHtml5String charset =
+              aAttributes->getValue(nsHtml5AttributeName::ATTR_CHARSET);
+            nsHtml5String type =
+              aAttributes->getValue(nsHtml5AttributeName::ATTR_TYPE);
+            nsHtml5String crossOrigin =
               aAttributes->getValue(nsHtml5AttributeName::ATTR_CROSSORIGIN);
-            nsString* integrity =
+            nsHtml5String integrity =
               aAttributes->getValue(nsHtml5AttributeName::ATTR_INTEGRITY);
-            mSpeculativeLoadQueue.AppendElement()->
-              InitScript(*url,
-                         (charset) ? *charset : EmptyString(),
-                         (type) ? *type : EmptyString(),
-                         (crossOrigin) ? *crossOrigin : NullString(),
-                         (integrity) ? *integrity : NullString(),
-                         mode == NS_HTML5TREE_BUILDER_IN_HEAD);
+            mSpeculativeLoadQueue.AppendElement()->InitScript(
+              url,
+              charset,
+              type,
+              crossOrigin,
+              integrity,
+              mode == NS_HTML5TREE_BUILDER_IN_HEAD);
             mCurrentHtmlScriptIsAsyncOrDefer =
               aAttributes->contains(nsHtml5AttributeName::ATTR_ASYNC) ||
               aAttributes->contains(nsHtml5AttributeName::ATTR_DEFER);
           }
         } else if (nsHtml5Atoms::link == aName) {
-          nsString* rel = aAttributes->getValue(nsHtml5AttributeName::ATTR_REL);
+          nsHtml5String rel =
+            aAttributes->getValue(nsHtml5AttributeName::ATTR_REL);
           // Not splitting on space here is bogus but the old parser didn't even
           // do a case-insensitive check.
           if (rel) {
-            if (rel->LowerCaseEqualsASCII("stylesheet")) {
-              nsString* url = aAttributes->getValue(nsHtml5AttributeName::ATTR_HREF);
+            if (rel.LowerCaseEqualsASCII("stylesheet")) {
+              nsHtml5String url =
+                aAttributes->getValue(nsHtml5AttributeName::ATTR_HREF);
               if (url) {
-                nsString* charset = aAttributes->getValue(nsHtml5AttributeName::ATTR_CHARSET);
-                nsString* crossOrigin =
+                nsHtml5String charset =
+                  aAttributes->getValue(nsHtml5AttributeName::ATTR_CHARSET);
+                nsHtml5String crossOrigin =
                   aAttributes->getValue(nsHtml5AttributeName::ATTR_CROSSORIGIN);
-                nsString* integrity =
+                nsHtml5String integrity =
                   aAttributes->getValue(nsHtml5AttributeName::ATTR_INTEGRITY);
-                mSpeculativeLoadQueue.AppendElement()->
-                  InitStyle(*url,
-                            (charset) ? *charset : EmptyString(),
-                            (crossOrigin) ? *crossOrigin : NullString(),
-                            (integrity) ? *integrity : NullString());
+                mSpeculativeLoadQueue.AppendElement()->InitStyle(
+                  url, charset, crossOrigin, integrity);
               }
-            } else if (rel->LowerCaseEqualsASCII("preconnect")) {
-              nsString* url = aAttributes->getValue(nsHtml5AttributeName::ATTR_HREF);
+            } else if (rel.LowerCaseEqualsASCII("preconnect")) {
+              nsHtml5String url =
+                aAttributes->getValue(nsHtml5AttributeName::ATTR_HREF);
               if (url) {
-                nsString* crossOrigin =
+                nsHtml5String crossOrigin =
                   aAttributes->getValue(nsHtml5AttributeName::ATTR_CROSSORIGIN);
-                mSpeculativeLoadQueue.AppendElement()->
-                  InitPreconnect(*url, (crossOrigin) ? *crossOrigin : NullString());
+                mSpeculativeLoadQueue.AppendElement()->InitPreconnect(
+                  url, crossOrigin);
               }
             }
           }
         } else if (nsHtml5Atoms::video == aName) {
-          nsString* url = aAttributes->getValue(nsHtml5AttributeName::ATTR_POSTER);
+          nsHtml5String url =
+            aAttributes->getValue(nsHtml5AttributeName::ATTR_POSTER);
           if (url) {
-            mSpeculativeLoadQueue.AppendElement()->InitImage(*url, NullString(),
-                                                             NullString(),
-                                                             NullString(),
-                                                             NullString());
+            mSpeculativeLoadQueue.AppendElement()->InitImage(
+              url, nullptr, nullptr, nullptr, nullptr);
           }
         } else if (nsHtml5Atoms::style == aName) {
           nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
           NS_ASSERTION(treeOp, "Tree op allocation failed.");
           treeOp->Init(eTreeOpSetStyleLineNumber, content, tokenizer->getLineNumber());
         } else if (nsHtml5Atoms::html == aName) {
-          nsString* url = aAttributes->getValue(nsHtml5AttributeName::ATTR_MANIFEST);
+          nsHtml5String url =
+            aAttributes->getValue(nsHtml5AttributeName::ATTR_MANIFEST);
+          mSpeculativeLoadQueue.AppendElement()->InitManifest(url);
+        } else if (nsHtml5Atoms::base == aName) {
+          nsHtml5String url =
+            aAttributes->getValue(nsHtml5AttributeName::ATTR_HREF);
           if (url) {
-            mSpeculativeLoadQueue.AppendElement()->InitManifest(*url);
-          } else {
-            mSpeculativeLoadQueue.AppendElement()->InitManifest(EmptyString());
-          }
-        } else if (nsHtml5Atoms::base == aName) {
-          nsString* url =
-              aAttributes->getValue(nsHtml5AttributeName::ATTR_HREF);
-          if (url) {
-            mSpeculativeLoadQueue.AppendElement()->InitBase(*url);
+            mSpeculativeLoadQueue.AppendElement()->InitBase(url);
           }
         } else if (nsHtml5Atoms::meta == aName) {
           if (nsHtml5Portability::lowerCaseLiteralEqualsIgnoreAsciiCaseString(
                       "content-security-policy",
                       aAttributes->getValue(nsHtml5AttributeName::ATTR_HTTP_EQUIV))) {
-            nsString* csp = aAttributes->getValue(nsHtml5AttributeName::ATTR_CONTENT);
+            nsHtml5String csp =
+              aAttributes->getValue(nsHtml5AttributeName::ATTR_CONTENT);
             if (csp) {
-              mSpeculativeLoadQueue.AppendElement()->InitMetaCSP(*csp);
+              mSpeculativeLoadQueue.AppendElement()->InitMetaCSP(csp);
             }
           }
           else if (nsHtml5Portability::lowerCaseLiteralEqualsIgnoreAsciiCaseString(
                       "referrer",
                       aAttributes->getValue(nsHtml5AttributeName::ATTR_NAME))) {
-            nsString* referrerPolicy = aAttributes->getValue(nsHtml5AttributeName::ATTR_CONTENT);
+            nsHtml5String referrerPolicy =
+              aAttributes->getValue(nsHtml5AttributeName::ATTR_CONTENT);
             if (referrerPolicy) {
-              mSpeculativeLoadQueue.AppendElement()->InitMetaReferrerPolicy(*referrerPolicy);
+              mSpeculativeLoadQueue.AppendElement()->InitMetaReferrerPolicy(
+                referrerPolicy);
             }
           }
         }
         break;
       case kNameSpaceID_SVG:
         if (nsHtml5Atoms::image == aName) {
-          nsString* url = aAttributes->getValue(nsHtml5AttributeName::ATTR_XLINK_HREF);
+          nsHtml5String url =
+            aAttributes->getValue(nsHtml5AttributeName::ATTR_XLINK_HREF);
           if (url) {
-            mSpeculativeLoadQueue.AppendElement()->InitImage(*url, NullString(),
-                                                             NullString(),
-                                                             NullString(),
-                                                             NullString());
+            mSpeculativeLoadQueue.AppendElement()->InitImage(
+              url, nullptr, nullptr, nullptr, nullptr);
           }
         } else if (nsHtml5Atoms::script == aName) {
           nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
           NS_ASSERTION(treeOp, "Tree op allocation failed.");
           treeOp->Init(eTreeOpSetScriptLineNumberAndFreeze, content, tokenizer->getLineNumber());
 
-          nsString* url = aAttributes->getValue(nsHtml5AttributeName::ATTR_XLINK_HREF);
+          nsHtml5String url =
+            aAttributes->getValue(nsHtml5AttributeName::ATTR_XLINK_HREF);
           if (url) {
-            nsString* type = aAttributes->getValue(nsHtml5AttributeName::ATTR_TYPE);
-            nsString* crossOrigin =
+            nsHtml5String type =
+              aAttributes->getValue(nsHtml5AttributeName::ATTR_TYPE);
+            nsHtml5String crossOrigin =
               aAttributes->getValue(nsHtml5AttributeName::ATTR_CROSSORIGIN);
-            nsString* integrity =
+            nsHtml5String integrity =
               aAttributes->getValue(nsHtml5AttributeName::ATTR_INTEGRITY);
-            mSpeculativeLoadQueue.AppendElement()->
-              InitScript(*url,
-                         EmptyString(),
-                         (type) ? *type : EmptyString(),
-                         (crossOrigin) ? *crossOrigin : NullString(),
-                         (integrity) ? *integrity : NullString(),
-                         mode == NS_HTML5TREE_BUILDER_IN_HEAD);
+            mSpeculativeLoadQueue.AppendElement()->InitScript(
+              url,
+              nullptr,
+              type,
+              crossOrigin,
+              integrity,
+              mode == NS_HTML5TREE_BUILDER_IN_HEAD);
           }
         } else if (nsHtml5Atoms::style == aName) {
           nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
           NS_ASSERTION(treeOp, "Tree op allocation failed.");
           treeOp->Init(eTreeOpSetStyleLineNumber, content, tokenizer->getLineNumber());
 
-          nsString* url = aAttributes->getValue(nsHtml5AttributeName::ATTR_XLINK_HREF);
+          nsHtml5String url =
+            aAttributes->getValue(nsHtml5AttributeName::ATTR_XLINK_HREF);
           if (url) {
-            nsString* crossOrigin =
+            nsHtml5String crossOrigin =
               aAttributes->getValue(nsHtml5AttributeName::ATTR_CROSSORIGIN);
-            nsString* integrity =
+            nsHtml5String integrity =
               aAttributes->getValue(nsHtml5AttributeName::ATTR_INTEGRITY);
-            mSpeculativeLoadQueue.AppendElement()->
-              InitStyle(*url, EmptyString(),
-                        (crossOrigin) ? *crossOrigin : NullString(),
-                        (integrity) ? *integrity : NullString());
+            mSpeculativeLoadQueue.AppendElement()->InitStyle(
+              url, nullptr, crossOrigin, integrity);
           }
         }
         break;
     }
   } else if (aNamespace != kNameSpaceID_MathML) {
     // No speculative loader--just line numbers and defer/async check
     if (nsHtml5Atoms::style == aName) {
       nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
@@ -315,28 +312,33 @@ nsHtml5TreeBuilder::createElement(int32_
       if (aNamespace == kNameSpaceID_XHTML) {
         mCurrentHtmlScriptIsAsyncOrDefer = 
           aAttributes->contains(nsHtml5AttributeName::ATTR_SRC) &&
           (aAttributes->contains(nsHtml5AttributeName::ATTR_ASYNC) ||
            aAttributes->contains(nsHtml5AttributeName::ATTR_DEFER));
       }
     } else if (aNamespace == kNameSpaceID_XHTML) {
       if (nsHtml5Atoms::html == aName) {
-        nsString* url = aAttributes->getValue(nsHtml5AttributeName::ATTR_MANIFEST);
+        nsHtml5String url =
+          aAttributes->getValue(nsHtml5AttributeName::ATTR_MANIFEST);
         nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
         NS_ASSERTION(treeOp, "Tree op allocation failed.");
         if (url) {
-          treeOp->Init(eTreeOpProcessOfflineManifest, *url);
+          nsString
+            urlString; // Not Auto, because using it to hold nsStringBuffer*
+          url.ToString(urlString);
+          treeOp->Init(eTreeOpProcessOfflineManifest, urlString);
         } else {
           treeOp->Init(eTreeOpProcessOfflineManifest, EmptyString());
         }
       } else if (nsHtml5Atoms::base == aName && mViewSource) {
-        nsString* url = aAttributes->getValue(nsHtml5AttributeName::ATTR_HREF);
+        nsHtml5String url =
+          aAttributes->getValue(nsHtml5AttributeName::ATTR_HREF);
         if (url) {
-          mViewSource->AddBase(*url);
+          mViewSource->AddBase(url);
         } 
       }
     }
   }
 
   // End wall of code for speculative loading
   
   return content;
@@ -738,36 +740,38 @@ nsHtml5TreeBuilder::end()
 {
   mOpQueue.Clear();
 #ifdef DEBUG
   mActive = false;
 #endif
 }
 
 void
-nsHtml5TreeBuilder::appendDoctypeToDocument(nsIAtom* aName, nsString* aPublicId, nsString* aSystemId)
+nsHtml5TreeBuilder::appendDoctypeToDocument(nsIAtom* aName,
+                                            nsHtml5String aPublicId,
+                                            nsHtml5String aSystemId)
 {
   NS_PRECONDITION(aName, "Null name");
-
+  nsString publicId; // Not Auto, because using it to hold nsStringBuffer*
+  nsString systemId; // Not Auto, because using it to hold nsStringBuffer*
+  aPublicId.ToString(publicId);
+  aSystemId.ToString(systemId);
   if (mBuilder) {
     nsCOMPtr<nsIAtom> name = nsHtml5TreeOperation::Reget(aName);
-    nsresult rv =
-      nsHtml5TreeOperation::AppendDoctypeToDocument(name,
-                                                    *aPublicId,
-                                                    *aSystemId,
-                                                    mBuilder);
+    nsresult rv = nsHtml5TreeOperation::AppendDoctypeToDocument(
+      name, publicId, systemId, mBuilder);
     if (NS_FAILED(rv)) {
       MarkAsBrokenAndRequestSuspension(rv);
     }
     return;
   }
 
   nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
   NS_ASSERTION(treeOp, "Tree op allocation failed.");
-  treeOp->Init(aName, *aPublicId, *aSystemId);
+  treeOp->Init(aName, publicId, systemId);
   // nsXMLContentSink can flush here, but what's the point?
   // It can also interrupt here, but we can't.
 }
 
 void
 nsHtml5TreeBuilder::elementPushed(int32_t aNamespace, nsIAtom* aName, nsIContentHandle* aElement)
 {
   NS_ASSERTION(aNamespace == kNameSpaceID_XHTML || aNamespace == kNameSpaceID_SVG || aNamespace == kNameSpaceID_MathML, "Element isn't HTML, SVG or MathML!");
--- a/parser/html/nsHtml5TreeOperation.cpp
+++ b/parser/html/nsHtml5TreeOperation.cpp
@@ -314,21 +314,20 @@ nsHtml5TreeOperation::AddAttributes(nsIC
     // prefix doesn't need regetting. it is always null or a static atom
     // local name is never null
     nsCOMPtr<nsIAtom> localName =
       Reget(aAttributes->getLocalNameNoBoundsCheck(i));
     int32_t nsuri = aAttributes->getURINoBoundsCheck(i);
     if (!node->HasAttr(nsuri, localName)) {
       // prefix doesn't need regetting. it is always null or a static atom
       // local name is never null
-      node->SetAttr(nsuri,
-                    localName,
-                    aAttributes->getPrefixNoBoundsCheck(i),
-                    *(aAttributes->getValueNoBoundsCheck(i)),
-                    true);
+      nsString value; // Not Auto, because using it to hold nsStringBuffer*
+      aAttributes->getValueNoBoundsCheck(i).ToString(value);
+      node->SetAttr(
+        nsuri, localName, aAttributes->getPrefixNoBoundsCheck(i), value, true);
       // XXX what to do with nsresult?
     }
   }
   return NS_OK;
 }
 
 
 nsIContent*
@@ -413,30 +412,31 @@ nsHtml5TreeOperation::CreateElement(int3
   for (int32_t i = 0; i < len; i++) {
     // prefix doesn't need regetting. it is always null or a static atom
     // local name is never null
     nsCOMPtr<nsIAtom> localName =
       Reget(aAttributes->getLocalNameNoBoundsCheck(i));
     nsCOMPtr<nsIAtom> prefix = aAttributes->getPrefixNoBoundsCheck(i);
     int32_t nsuri = aAttributes->getURINoBoundsCheck(i);
 
+    nsString value; // Not Auto, because using it to hold nsStringBuffer*
+    aAttributes->getValueNoBoundsCheck(i).ToString(value);
     if (aNs == kNameSpaceID_XHTML &&
         nsHtml5Atoms::a == aName &&
         nsHtml5Atoms::name == localName) {
       // This is an HTML5-incompliant Geckoism.
       // Remove when fixing bug 582361
-      NS_ConvertUTF16toUTF8 cname(*(aAttributes->getValueNoBoundsCheck(i)));
+      NS_ConvertUTF16toUTF8 cname(value);
       NS_ConvertUTF8toUTF16 uv(nsUnescape(cname.BeginWriting()));
       newContent->SetAttr(nsuri,
                           localName,
                           prefix,
                           uv,
                           false);
     } else {
-      nsString& value = *(aAttributes->getValueNoBoundsCheck(i));
       newContent->SetAttr(nsuri,
                           localName,
                           prefix,
                           value,
                           false);
 
       // Custom element setup may be needed if there is an "is" attribute.
       if (kNameSpaceID_None == nsuri && !prefix && nsGkAtoms::is == localName) {
--- a/parser/html/nsHtml5UTF16Buffer.cpp
+++ b/parser/html/nsHtml5UTF16Buffer.cpp
@@ -24,17 +24,17 @@
  * THIS IS A GENERATED FILE. PLEASE DO NOT EDIT.
  * Please edit UTF16Buffer.java instead and regenerate.
  */
 
 #define nsHtml5UTF16Buffer_cpp__
 
 #include "nsIAtom.h"
 #include "nsHtml5AtomTable.h"
-#include "nsString.h"
+#include "nsHtml5String.h"
 #include "nsNameSpaceManager.h"
 #include "nsIContent.h"
 #include "nsTraceRefcnt.h"
 #include "jArray.h"
 #include "nsHtml5ArrayCopy.h"
 #include "nsAHtml5TreeBuilderState.h"
 #include "nsHtml5Atoms.h"
 #include "nsHtml5ByteReadable.h"
--- a/parser/html/nsHtml5UTF16Buffer.h
+++ b/parser/html/nsHtml5UTF16Buffer.h
@@ -25,17 +25,17 @@
  * Please edit UTF16Buffer.java instead and regenerate.
  */
 
 #ifndef nsHtml5UTF16Buffer_h
 #define nsHtml5UTF16Buffer_h
 
 #include "nsIAtom.h"
 #include "nsHtml5AtomTable.h"
-#include "nsString.h"
+#include "nsHtml5String.h"
 #include "nsNameSpaceManager.h"
 #include "nsIContent.h"
 #include "nsTraceRefcnt.h"
 #include "jArray.h"
 #include "nsHtml5ArrayCopy.h"
 #include "nsAHtml5TreeBuilderState.h"
 #include "nsHtml5Atoms.h"
 #include "nsHtml5ByteReadable.h"
--- a/parser/html/nsHtml5ViewSourceUtils.cpp
+++ b/parser/html/nsHtml5ViewSourceUtils.cpp
@@ -1,53 +1,56 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 
 #include "nsHtml5ViewSourceUtils.h"
 #include "nsHtml5AttributeName.h"
 #include "mozilla/Preferences.h"
-#include "mozilla/UniquePtr.h"
+#include "nsHtml5String.h"
 
 // static
 nsHtml5HtmlAttributes*
 nsHtml5ViewSourceUtils::NewBodyAttributes()
 {
   nsHtml5HtmlAttributes* bodyAttrs = new nsHtml5HtmlAttributes(0);
-  auto id = MakeUnique<nsString>(NS_LITERAL_STRING("viewsource"));
-  bodyAttrs->addAttribute(nsHtml5AttributeName::ATTR_ID, id.release(), -1);
+  nsHtml5String id = nsHtml5Portability::newStringFromLiteral("viewsource");
+  bodyAttrs->addAttribute(nsHtml5AttributeName::ATTR_ID, id, -1);
 
-  auto klass = MakeUnique<nsString>();
+  nsString klass;
   if (mozilla::Preferences::GetBool("view_source.wrap_long_lines", true)) {
-    klass->Append(NS_LITERAL_STRING("wrap "));
+    klass.Append(NS_LITERAL_STRING("wrap "));
   }
   if (mozilla::Preferences::GetBool("view_source.syntax_highlight", true)) {
-    klass->Append(NS_LITERAL_STRING("highlight"));
+    klass.Append(NS_LITERAL_STRING("highlight"));
   }
-  if (!klass->IsEmpty()) {
-    bodyAttrs->addAttribute(nsHtml5AttributeName::ATTR_CLASS, klass.release(), -1);
+  if (!klass.IsEmpty()) {
+    bodyAttrs->addAttribute(
+      nsHtml5AttributeName::ATTR_CLASS, nsHtml5String::FromString(klass), -1);
   }
 
   int32_t tabSize = mozilla::Preferences::GetInt("view_source.tab_size", 4);
   if (tabSize > 0) {
-    auto style = MakeUnique<nsString>(NS_LITERAL_STRING("-moz-tab-size: "));
-    style->AppendInt(tabSize);
-    bodyAttrs->addAttribute(nsHtml5AttributeName::ATTR_STYLE, style.release(), -1);
+    nsString style;
+    style.AssignASCII("-moz-tab-size: ");
+    style.AppendInt(tabSize);
+    bodyAttrs->addAttribute(
+      nsHtml5AttributeName::ATTR_STYLE, nsHtml5String::FromString(style), -1);
   }
 
   return bodyAttrs;
 }
 
 // static
 nsHtml5HtmlAttributes*
 nsHtml5ViewSourceUtils::NewLinkAttributes()
 {
   nsHtml5HtmlAttributes* linkAttrs = new nsHtml5HtmlAttributes(0);
-  nsString* rel = new nsString(NS_LITERAL_STRING("stylesheet"));
+  nsHtml5String rel = nsHtml5Portability::newStringFromLiteral("stylesheet");
   linkAttrs->addAttribute(nsHtml5AttributeName::ATTR_REL, rel, -1);
-  nsString* type = new nsString(NS_LITERAL_STRING("text/css"));
+  nsHtml5String type = nsHtml5Portability::newStringFromLiteral("text/css");
   linkAttrs->addAttribute(nsHtml5AttributeName::ATTR_TYPE, type, -1);
-  nsString* href = new nsString(
-      NS_LITERAL_STRING("resource://gre-resources/viewsource.css"));
+  nsHtml5String href = nsHtml5Portability::newStringFromLiteral(
+    "resource://gre-resources/viewsource.css");
   linkAttrs->addAttribute(nsHtml5AttributeName::ATTR_HREF, href, -1);
   return linkAttrs;
 }