Bug 1442760 - Switch nsHTMLTags hashtables to nsDataHashtable. r=hsivonen
authorEric Rahm <erahm@mozilla.com>
Tue, 06 Mar 2018 17:27:17 -0800
changeset 407117 8bbb6c0d3214e84541e26b690bf1ecb93d0bdcb9
parent 407116 5705bfa39d3a4390864db1a3fe941b093cb65884
child 407118 2cb86c6e003ddad85e7600bd84e03252b5269cd3
push id100580
push usererahm@mozilla.com
push dateThu, 08 Mar 2018 04:20:49 +0000
treeherdermozilla-inbound@8bbb6c0d3214 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewershsivonen
bugs1442760
milestone60.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 1442760 - Switch nsHTMLTags hashtables to nsDataHashtable. r=hsivonen This converts nsHTMLTags hashtables from PLHash to nsDataHashtable which gives us both type safety and simpler code. Addtionally `gTagTable` now holds a nsString instead of a raw char16_t pointer, this has the benefit of the strings knowing their sizes allowing for more efficient comparisons. We avoid heap allocations in the nsString by using `AssignLiteral` with the string from the static string array.
parser/htmlparser/nsHTMLTags.cpp
parser/htmlparser/nsHTMLTags.h
--- a/parser/htmlparser/nsHTMLTags.cpp
+++ b/parser/htmlparser/nsHTMLTags.cpp
@@ -1,15 +1,16 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsHTMLTags.h"
 #include "nsCRT.h"
+#include "nsDataHashtable.h"
 #include "nsReadableUtils.h"
 #include "nsString.h"
 #include "nsStaticAtom.h"
 #include "nsUnicharUtils.h"
 #include "mozilla/HashFunctions.h"
 #include <algorithm>
 
 using namespace mozilla;
@@ -19,41 +20,18 @@ using namespace mozilla;
 #define HTML_OTHER(_tag)
 const char16_t* const nsHTMLTags::sTagUnicodeTable[] = {
 #include "nsHTMLTagList.h"
 };
 #undef HTML_TAG
 #undef HTML_OTHER
 
 int32_t nsHTMLTags::gTableRefCount;
-PLHashTable* nsHTMLTags::gTagTable;
-PLHashTable* nsHTMLTags::gTagAtomTable;
-
-// char16_t* -> id hash
-static PLHashNumber
-HTMLTagsHashCodeUCPtr(const void *key)
-{
-  return HashString(static_cast<const char16_t*>(key));
-}
-
-static int
-HTMLTagsKeyCompareUCPtr(const void *key1, const void *key2)
-{
-  const char16_t *str1 = (const char16_t *)key1;
-  const char16_t *str2 = (const char16_t *)key2;
-
-  return nsCRT::strcmp(str1, str2) == 0;
-}
-
-// nsAtom* -> id hash
-static PLHashNumber
-HTMLTagsHashCodeAtom(const void *key)
-{
-  return NS_PTR_TO_INT32(key) >> 2;
-}
+nsHTMLTags::TagStringHash* nsHTMLTags::gTagTable;
+nsHTMLTags::TagAtomHash* nsHTMLTags::gTagAtomTable;
 
 #define NS_HTMLTAG_NAME_MAX_LENGTH 10
 
 // This would use NS_STATIC_ATOM_DEFN if it wasn't an array.
 nsStaticAtom* nsHTMLTags::sTagAtomTable[eHTMLTag_userdefined - 1];
 
 #define HTML_TAG(_tag, _classname, _interfacename) \
   NS_STATIC_ATOM_BUFFER(_tag, #_tag)
@@ -109,118 +87,106 @@ nsHTMLTags::RegisterAtoms(void)
 
 // static
 nsresult
 nsHTMLTags::AddRefTable(void)
 {
   if (gTableRefCount++ == 0) {
     NS_ASSERTION(!gTagTable && !gTagAtomTable, "pre existing hash!");
 
-    gTagTable = PL_NewHashTable(64, HTMLTagsHashCodeUCPtr,
-                                HTMLTagsKeyCompareUCPtr, PL_CompareValues,
-                                nullptr, nullptr);
-    NS_ENSURE_TRUE(gTagTable, NS_ERROR_OUT_OF_MEMORY);
-
-    gTagAtomTable = PL_NewHashTable(64, HTMLTagsHashCodeAtom,
-                                    PL_CompareValues, PL_CompareValues,
-                                    nullptr, nullptr);
-    NS_ENSURE_TRUE(gTagAtomTable, NS_ERROR_OUT_OF_MEMORY);
+    gTagTable = new TagStringHash(64);
+    gTagAtomTable = new TagAtomHash(64);
 
     // Fill in gTagTable with the above static char16_t strings as
     // keys and the value of the corresponding enum as the value in
     // the table.
 
     int32_t i;
     for (i = 0; i < NS_HTML_TAG_MAX; ++i) {
-      PL_HashTableAdd(gTagTable, sTagUnicodeTable[i],
-                      NS_INT32_TO_PTR(i + 1));
-
-      PL_HashTableAdd(gTagAtomTable, sTagAtomTable[i],
-                      NS_INT32_TO_PTR(i + 1));
+      const char16_t* tagName = sTagUnicodeTable[i];
+      const nsHTMLTag tagValue = static_cast<nsHTMLTag>(i + 1);
+      // We use AssignLiteral here to avoid a string copy. This is okay
+      // because this is truly static data.
+      nsString tmp;
+      tmp.AssignLiteral(tagName, nsString::char_traits::length(tagName));
+      gTagTable->Put(tmp, tagValue);
+      gTagAtomTable->Put(sTagAtomTable[i], tagValue);
     }
   }
 
   return NS_OK;
 }
 
 // static
 void
 nsHTMLTags::ReleaseTable(void)
 {
   if (0 == --gTableRefCount) {
-    if (gTagTable) {
-      // Nothing to delete/free in this table, just destroy the table.
-
-      PL_HashTableDestroy(gTagTable);
-      PL_HashTableDestroy(gTagAtomTable);
-      gTagTable = nullptr;
-      gTagAtomTable = nullptr;
-    }
+    delete gTagTable;
+    delete gTagAtomTable;
+    gTagTable = nullptr;
+    gTagAtomTable = nullptr;
   }
 }
 
 // static
 nsHTMLTag
 nsHTMLTags::StringTagToId(const nsAString& aTagName)
 {
   uint32_t length = aTagName.Length();
 
   if (length > NS_HTMLTAG_NAME_MAX_LENGTH) {
     return eHTMLTag_userdefined;
   }
 
-  char16_t buf[NS_HTMLTAG_NAME_MAX_LENGTH + 1];
+  // Setup a stack allocated string buffer with the appropriate length.
+  nsAutoString lowerCase;
+  lowerCase.SetLength(length);
 
-  nsAString::const_iterator iter;
-  uint32_t i = 0;
-  char16_t c;
-
-  aTagName.BeginReading(iter);
+  // Operate on the raw buffers to avoid bounds checks.
+  auto src = aTagName.BeginReading();
+  auto dst = lowerCase.BeginWriting();
 
   // Fast lowercasing-while-copying of ASCII characters into a
-  // char16_t buffer
+  // nsString buffer.
 
-  while (i < length) {
-    c = *iter;
+  for (uint32_t i = 0; i < length; i++) {
+    char16_t c = src[i];
 
     if (c <= 'Z' && c >= 'A') {
       c |= 0x20; // Lowercase the ASCII character.
     }
 
-    buf[i] = c; // Copy ASCII character.
-
-    ++i;
-    ++iter;
+    dst[i] = c; // Copy ASCII character.
   }
 
-  buf[i] = 0;
-
-  return CaseSensitiveStringTagToId(buf);
+  return CaseSensitiveStringTagToId(lowerCase);
 }
 
 #ifdef DEBUG
 void
 nsHTMLTags::TestTagTable()
 {
      const char16_t *tag;
      nsHTMLTag id;
      RefPtr<nsAtom> atom;
 
      nsHTMLTags::AddRefTable();
      // Make sure we can find everything we are supposed to
      for (int i = 0; i < NS_HTML_TAG_MAX; ++i) {
        tag = sTagUnicodeTable[i];
-       id = StringTagToId(nsDependentString(tag));
+       const nsAString& tagString = nsDependentString(tag);
+       id = StringTagToId(tagString);
        NS_ASSERTION(id != eHTMLTag_userdefined, "can't find tag id");
 
-       nsAutoString uname(tag);
+       nsAutoString uname(tagString);
        ToUpperCase(uname);
        NS_ASSERTION(id == StringTagToId(uname), "wrong id");
 
-       NS_ASSERTION(id == CaseSensitiveStringTagToId(tag), "wrong id");
+       NS_ASSERTION(id == CaseSensitiveStringTagToId(tagString), "wrong id");
 
        atom = NS_Atomize(tag);
        NS_ASSERTION(id == CaseSensitiveAtomTagToId(atom), "wrong id");
      }
 
      // Make sure we don't find things that aren't there
      id = StringTagToId(NS_LITERAL_STRING("@"));
      NS_ASSERTION(id == eHTMLTag_userdefined, "found @");
--- a/parser/htmlparser/nsHTMLTags.h
+++ b/parser/htmlparser/nsHTMLTags.h
@@ -3,17 +3,18 @@
  * 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 nsHTMLTags_h___
 #define nsHTMLTags_h___
 
 #include "nsStaticAtom.h"
 #include "nsString.h"
-#include "plhash.h"
+#include "nsDataHashtable.h"
+#include "nsHashKeys.h"
 
 /*
    Declare the enum list using the magic of preprocessing
    enum values are "eHTMLTag_foo" (where foo is the tag)
 
    To change the list of tags, see nsHTMLTagList.h
 
    These enum values are used as the index of array in various places.
@@ -35,53 +36,53 @@ enum nsHTMLTag {
 #undef HTML_TAG
 #undef HTML_OTHER
 
 // All tags before eHTMLTag_text are HTML tags
 #define NS_HTML_TAG_MAX int32_t(eHTMLTag_text - 1)
 
 class nsHTMLTags {
 public:
+  using TagStringHash = nsDataHashtable<nsStringHashKey, nsHTMLTag>;
+  using TagAtomHash = nsDataHashtable<nsPtrHashKey<nsAtom>, nsHTMLTag>;
+
   static void RegisterAtoms(void);
   static nsresult AddRefTable(void);
   static void ReleaseTable(void);
 
   // Functions for converting string or atom to id
   static nsHTMLTag StringTagToId(const nsAString& aTagName);
   static nsHTMLTag AtomTagToId(nsAtom* aTagName)
   {
     return StringTagToId(nsDependentAtomString(aTagName));
   }
 
-  static nsHTMLTag CaseSensitiveStringTagToId(const char16_t* aTagName)
+  static nsHTMLTag CaseSensitiveStringTagToId(const nsAString& aTagName)
   {
     NS_ASSERTION(gTagTable, "no lookup table, needs addref");
-    NS_ASSERTION(aTagName, "null tagname!");
 
-    void* tag = PL_HashTableLookupConst(gTagTable, aTagName);
-
-    return tag ? (nsHTMLTag)NS_PTR_TO_INT32(tag) : eHTMLTag_userdefined;
+    nsHTMLTag* tag = gTagTable->GetValue(aTagName);
+    return tag ? *tag : eHTMLTag_userdefined;
   }
   static nsHTMLTag CaseSensitiveAtomTagToId(nsAtom* aTagName)
   {
     NS_ASSERTION(gTagAtomTable, "no lookup table, needs addref");
     NS_ASSERTION(aTagName, "null tagname!");
 
-    void* tag = PL_HashTableLookupConst(gTagAtomTable, aTagName);
-
-    return tag ? (nsHTMLTag)NS_PTR_TO_INT32(tag) : eHTMLTag_userdefined;
+    nsHTMLTag* tag = gTagAtomTable->GetValue(aTagName);
+    return tag ? *tag : eHTMLTag_userdefined;
   }
 
 #ifdef DEBUG
   static void TestTagTable();
 #endif
 
 private:
   // This would use NS_STATIC_ATOM_DECL if it wasn't an array.
   static nsStaticAtom* sTagAtomTable[eHTMLTag_userdefined - 1];
   static const char16_t* const sTagUnicodeTable[];
 
   static int32_t gTableRefCount;
-  static PLHashTable* gTagTable;
-  static PLHashTable* gTagAtomTable;
+  static TagStringHash* gTagTable;
+  static TagAtomHash* gTagAtomTable;
 };
 
 #endif /* nsHTMLTags_h___ */