xpcom/ds/nsAtomTable.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 // vim:cindent:ts=2:et:sw=2:
     3 /* This Source Code Form is subject to the terms of the Mozilla Public
     4  * License, v. 2.0. If a copy of the MPL was not distributed with this
     5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     7 #include "mozilla/Assertions.h"
     8 #include "mozilla/Attributes.h"
     9 #include "mozilla/Compiler.h"
    10 #include "mozilla/HashFunctions.h"
    11 #include "mozilla/MemoryReporting.h"
    12 #include "mozilla/DebugOnly.h"
    13 #include "mozilla/unused.h"
    15 #include "nsAtomTable.h"
    16 #include "nsStaticAtom.h"
    17 #include "nsString.h"
    18 #include "nsCRT.h"
    19 #include "pldhash.h"
    20 #include "prenv.h"
    21 #include "nsThreadUtils.h"
    22 #include "nsDataHashtable.h"
    23 #include "nsHashKeys.h"
    24 #include "nsAutoPtr.h"
    25 #include "nsUnicharUtils.h"
    27 using namespace mozilla;
    29 #if defined(__clang__)
    30 #  pragma GCC diagnostic ignored "-Wdelete-non-virtual-dtor"
    31 #elif MOZ_IS_GCC
    32 #  if MOZ_GCC_VERSION_AT_LEAST(4, 7, 0)
    33 #    pragma GCC diagnostic ignored "-Wdelete-non-virtual-dtor"
    34 #  endif
    35 #endif
    37 /**
    38  * The shared hash table for atom lookups.
    39  *
    40  * XXX This should be manipulated in a threadsafe way or we should make
    41  * sure it's only manipulated from the main thread.  Probably the latter
    42  * is better, since the former would hurt performance.
    43  *
    44  * If |gAtomTable.ops| is 0, then the table is uninitialized.
    45  */
    46 static PLDHashTable gAtomTable;
    48 /**
    49  * A hashtable of static atoms that existed at app startup. This hashtable helps 
    50  * nsHtml5AtomTable.
    51  */
    52 static nsDataHashtable<nsStringHashKey, nsIAtom*>* gStaticAtomTable = 0;
    54 /**
    55  * Whether it is still OK to add atoms to gStaticAtomTable.
    56  */
    57 static bool gStaticAtomTableSealed = false;
    59 //----------------------------------------------------------------------
    61 /**
    62  * Note that AtomImpl objects are sometimes converted into PermanentAtomImpl
    63  * objects using placement new and just overwriting the vtable pointer.
    64  */
    66 class AtomImpl : public nsIAtom {
    67 public:
    68   AtomImpl(const nsAString& aString, uint32_t aHash);
    70   // This is currently only used during startup when creating a permanent atom
    71   // from NS_RegisterStaticAtoms
    72   AtomImpl(nsStringBuffer* aData, uint32_t aLength, uint32_t aHash);
    74 protected:
    75   // This is only intended to be used when a normal atom is turned into a
    76   // permanent one.
    77   AtomImpl() {
    78     // We can't really assert that mString is a valid nsStringBuffer string,
    79     // so do the best we can do and check for some consistencies.
    80     NS_ASSERTION((mLength + 1) * sizeof(char16_t) <=
    81                  nsStringBuffer::FromData(mString)->StorageSize() &&
    82                  mString[mLength] == 0,
    83                  "Not initialized atom");
    84   }
    86   // We don't need a virtual destructor here because PermanentAtomImpl
    87   // deletions aren't handled through Release().
    88   ~AtomImpl();
    90 public:
    91   NS_DECL_ISUPPORTS
    92   NS_DECL_NSIATOM
    94   enum { REFCNT_PERMANENT_SENTINEL = UINT32_MAX };
    96   virtual bool IsPermanent();
    98   // We can't use the virtual function in the base class destructor.
    99   bool IsPermanentInDestructor() {
   100     return mRefCnt == REFCNT_PERMANENT_SENTINEL;
   101   }
   103   // for |#ifdef NS_BUILD_REFCNT_LOGGING| access to reference count
   104   nsrefcnt GetRefCount() { return mRefCnt; }
   106   size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const;
   107 };
   109 /**
   110  * A non-refcounted implementation of nsIAtom.
   111  */
   113 class PermanentAtomImpl MOZ_FINAL : public AtomImpl {
   114 public:
   115   PermanentAtomImpl(const nsAString& aString, PLDHashNumber aKeyHash)
   116     : AtomImpl(aString, aKeyHash)
   117   {}
   118   PermanentAtomImpl(nsStringBuffer* aData, uint32_t aLength,
   119                     PLDHashNumber aKeyHash)
   120     : AtomImpl(aData, aLength, aKeyHash)
   121   {}
   122   PermanentAtomImpl()
   123   {}
   125   ~PermanentAtomImpl();
   126   NS_IMETHOD_(MozExternalRefCountType) AddRef();
   127   NS_IMETHOD_(MozExternalRefCountType) Release();
   129   virtual bool IsPermanent();
   131   // SizeOfIncludingThis() isn't needed -- the one inherited from AtomImpl is
   132   // good enough, because PermanentAtomImpl doesn't add any new data members.
   134   void* operator new(size_t size, AtomImpl* aAtom) CPP_THROW_NEW;
   135   void* operator new(size_t size) CPP_THROW_NEW
   136   {
   137     return ::operator new(size);
   138   }
   139 };
   141 //----------------------------------------------------------------------
   143 struct AtomTableEntry : public PLDHashEntryHdr {
   144   AtomImpl* mAtom;
   145 };
   147 struct AtomTableKey
   148 {
   149   AtomTableKey(const char16_t* aUTF16String, uint32_t aLength,
   150                /*inout*/ uint32_t& aHash)
   151     : mUTF16String(aUTF16String),
   152       mUTF8String(nullptr),
   153       mLength(aLength)
   154   {
   155     if (aHash) {
   156       MOZ_ASSERT(aHash == HashString(mUTF16String, mLength));
   157       mHash = aHash;
   158     } else {
   159       UpdateHashKey();
   160       aHash = mHash;
   161     }
   162   }
   164   AtomTableKey(const char* aUTF8String, uint32_t aLength,
   165                /*inout*/ uint32_t& aHash)
   166     : mUTF16String(nullptr),
   167       mUTF8String(aUTF8String),
   168       mLength(aLength)
   169   {
   170     if (aHash) {
   171       mozilla::DebugOnly<bool> err;
   172       MOZ_ASSERT(aHash == HashUTF8AsUTF16(mUTF8String, mLength, &err));
   173       mHash = aHash;
   174     } else {
   175       UpdateHashKey();
   176       aHash = mHash;
   177     }
   178   }
   180   const char16_t* mUTF16String;
   181   const char* mUTF8String;
   182   uint32_t mLength;
   183   uint32_t mHash;
   185   void UpdateHashKey()
   186   {
   187     if (mUTF8String) {
   188       bool err;
   189       mHash = HashUTF8AsUTF16(mUTF8String, mLength, &err);
   190       if (err) {
   191         mUTF8String = nullptr;
   192         mLength = 0;
   193         mHash = 0;
   194       }
   195     } else {
   196       mHash = HashString(mUTF16String, mLength);
   197     }
   198   }
   199 };
   201 static PLDHashNumber
   202 AtomTableGetHash(PLDHashTable *table, const void *key)
   203 {
   204   const AtomTableKey *k = static_cast<const AtomTableKey*>(key);
   205   return k->mHash;
   206 }
   208 static bool
   209 AtomTableMatchKey(PLDHashTable *table, const PLDHashEntryHdr *entry,
   210                   const void *key)
   211 {
   212   const AtomTableEntry *he = static_cast<const AtomTableEntry*>(entry);
   213   const AtomTableKey *k = static_cast<const AtomTableKey*>(key);
   215   if (k->mUTF8String) {
   216     return
   217       CompareUTF8toUTF16(nsDependentCSubstring(k->mUTF8String,
   218                                                k->mUTF8String + k->mLength),
   219                          nsDependentAtomString(he->mAtom)) == 0;
   220   }
   222   uint32_t length = he->mAtom->GetLength();
   223   if (length != k->mLength) {
   224     return false;
   225   }
   227   return memcmp(he->mAtom->GetUTF16String(),
   228                 k->mUTF16String, length * sizeof(char16_t)) == 0;
   229 }
   231 static void
   232 AtomTableClearEntry(PLDHashTable *table, PLDHashEntryHdr *entry)
   233 {
   234   // Normal |AtomImpl| atoms are deleted when their refcount hits 0, and
   235   // they then remove themselves from the table.  In other words, they
   236   // are owned by the callers who own references to them.
   237   // |PermanentAtomImpl| permanent atoms ignore their refcount and are
   238   // deleted when they are removed from the table at table destruction.
   239   // In other words, they are owned by the atom table.
   241   AtomImpl *atom = static_cast<AtomTableEntry*>(entry)->mAtom;
   242   if (atom->IsPermanent()) {
   243     // Note that the cast here is important since AtomImpls doesn't have a
   244     // virtual dtor.
   245     delete static_cast<PermanentAtomImpl*>(atom);
   246   }
   247 }
   249 static bool
   250 AtomTableInitEntry(PLDHashTable *table, PLDHashEntryHdr *entry,
   251                    const void *key)
   252 {
   253   static_cast<AtomTableEntry*>(entry)->mAtom = nullptr;
   255   return true;
   256 }
   259 static const PLDHashTableOps AtomTableOps = {
   260   PL_DHashAllocTable,
   261   PL_DHashFreeTable,
   262   AtomTableGetHash,
   263   AtomTableMatchKey,
   264   PL_DHashMoveEntryStub,
   265   AtomTableClearEntry,
   266   PL_DHashFinalizeStub,
   267   AtomTableInitEntry
   268 };
   271 #ifdef DEBUG
   272 static PLDHashOperator
   273 DumpAtomLeaks(PLDHashTable *table, PLDHashEntryHdr *he,
   274               uint32_t index, void *arg)
   275 {
   276   AtomTableEntry *entry = static_cast<AtomTableEntry*>(he);
   278   AtomImpl* atom = entry->mAtom;
   279   if (!atom->IsPermanent()) {
   280     ++*static_cast<uint32_t*>(arg);
   281     nsAutoCString str;
   282     atom->ToUTF8String(str);
   283     fputs(str.get(), stdout);
   284     fputs("\n", stdout);
   285   }
   286   return PL_DHASH_NEXT;
   287 }
   288 #endif
   290 static inline
   291 void PromoteToPermanent(AtomImpl* aAtom)
   292 {
   293 #ifdef NS_BUILD_REFCNT_LOGGING
   294   {
   295     nsrefcnt refcount = aAtom->GetRefCount();
   296     do {
   297       NS_LOG_RELEASE(aAtom, --refcount, "AtomImpl");
   298     } while (refcount);
   299   }
   300 #endif
   301   aAtom = new (aAtom) PermanentAtomImpl();
   302 }
   304 void
   305 NS_PurgeAtomTable()
   306 {
   307   delete gStaticAtomTable;
   309   if (gAtomTable.ops) {
   310 #ifdef DEBUG
   311     const char *dumpAtomLeaks = PR_GetEnv("MOZ_DUMP_ATOM_LEAKS");
   312     if (dumpAtomLeaks && *dumpAtomLeaks) {
   313       uint32_t leaked = 0;
   314       printf("*** %d atoms still exist (including permanent):\n",
   315              gAtomTable.entryCount);
   316       PL_DHashTableEnumerate(&gAtomTable, DumpAtomLeaks, &leaked);
   317       printf("*** %u non-permanent atoms leaked\n", leaked);
   318     }
   319 #endif
   320     PL_DHashTableFinish(&gAtomTable);
   321     gAtomTable.entryCount = 0;
   322     gAtomTable.ops = nullptr;
   323   }
   324 }
   326 AtomImpl::AtomImpl(const nsAString& aString, uint32_t aHash)
   327 {
   328   mLength = aString.Length();
   329   nsRefPtr<nsStringBuffer> buf = nsStringBuffer::FromString(aString);
   330   if (buf) {
   331     mString = static_cast<char16_t*>(buf->Data());
   332   } else {
   333     buf = nsStringBuffer::Alloc((mLength + 1) * sizeof(char16_t));
   334     mString = static_cast<char16_t*>(buf->Data());
   335     CopyUnicodeTo(aString, 0, mString, mLength);
   336     mString[mLength] = char16_t(0);
   337   }
   339   mHash = aHash;
   340   MOZ_ASSERT(mHash == HashString(mString, mLength));
   342   NS_ASSERTION(mString[mLength] == char16_t(0), "null terminated");
   343   NS_ASSERTION(buf && buf->StorageSize() >= (mLength+1) * sizeof(char16_t),
   344                "enough storage");
   345   NS_ASSERTION(Equals(aString), "correct data");
   347   // Take ownership of buffer
   348   mozilla::unused << buf.forget();
   349 }
   351 AtomImpl::AtomImpl(nsStringBuffer* aStringBuffer, uint32_t aLength,
   352                    uint32_t aHash)
   353 {
   354   mLength = aLength;
   355   mString = static_cast<char16_t*>(aStringBuffer->Data());
   356   // Technically we could currently avoid doing this addref by instead making
   357   // the static atom buffers have an initial refcount of 2.
   358   aStringBuffer->AddRef();
   360   mHash = aHash;
   361   MOZ_ASSERT(mHash == HashString(mString, mLength));
   363   NS_ASSERTION(mString[mLength] == char16_t(0), "null terminated");
   364   NS_ASSERTION(aStringBuffer &&
   365                aStringBuffer->StorageSize() == (mLength+1) * sizeof(char16_t),
   366                "correct storage");
   367 }
   369 AtomImpl::~AtomImpl()
   370 {
   371   NS_PRECONDITION(gAtomTable.ops, "uninitialized atom hashtable");
   372   // Permanent atoms are removed from the hashtable at shutdown, and we
   373   // don't want to remove them twice.  See comment above in
   374   // |AtomTableClearEntry|.
   375   if (!IsPermanentInDestructor()) {
   376     AtomTableKey key(mString, mLength, mHash);
   377     PL_DHashTableOperate(&gAtomTable, &key, PL_DHASH_REMOVE);
   378     if (gAtomTable.entryCount == 0) {
   379       PL_DHashTableFinish(&gAtomTable);
   380       NS_ASSERTION(gAtomTable.entryCount == 0,
   381                    "PL_DHashTableFinish changed the entry count");
   382     }
   383   }
   385   nsStringBuffer::FromData(mString)->Release();
   386 }
   388 NS_IMPL_ISUPPORTS(AtomImpl, nsIAtom)
   390 PermanentAtomImpl::~PermanentAtomImpl()
   391 {
   392   // So we can tell if we were permanent while running the base class dtor.
   393   mRefCnt = REFCNT_PERMANENT_SENTINEL;
   394 }
   396 NS_IMETHODIMP_(MozExternalRefCountType) PermanentAtomImpl::AddRef()
   397 {
   398   MOZ_ASSERT(NS_IsMainThread(), "wrong thread");
   399   return 2;
   400 }
   402 NS_IMETHODIMP_(MozExternalRefCountType) PermanentAtomImpl::Release()
   403 {
   404   MOZ_ASSERT(NS_IsMainThread(), "wrong thread");
   405   return 1;
   406 }
   408 /* virtual */ bool
   409 AtomImpl::IsPermanent()
   410 {
   411   return false;
   412 }
   414 /* virtual */ bool
   415 PermanentAtomImpl::IsPermanent()
   416 {
   417   return true;
   418 }
   420 void* PermanentAtomImpl::operator new ( size_t size, AtomImpl* aAtom ) CPP_THROW_NEW {
   421   MOZ_ASSERT(!aAtom->IsPermanent(),
   422              "converting atom that's already permanent");
   424   // Just let the constructor overwrite the vtable pointer.
   425   return aAtom;
   426 }
   428 NS_IMETHODIMP 
   429 AtomImpl::ScriptableToString(nsAString& aBuf)
   430 {
   431   nsStringBuffer::FromData(mString)->ToString(mLength, aBuf);
   432   return NS_OK;
   433 }
   435 NS_IMETHODIMP
   436 AtomImpl::ToUTF8String(nsACString& aBuf)
   437 {
   438   CopyUTF16toUTF8(nsDependentString(mString, mLength), aBuf);
   439   return NS_OK;
   440 }
   442 NS_IMETHODIMP_(bool)
   443 AtomImpl::EqualsUTF8(const nsACString& aString)
   444 {
   445   return CompareUTF8toUTF16(aString,
   446                             nsDependentString(mString, mLength)) == 0;
   447 }
   449 NS_IMETHODIMP
   450 AtomImpl::ScriptableEquals(const nsAString& aString, bool* aResult)
   451 {
   452   *aResult = aString.Equals(nsDependentString(mString, mLength));
   453   return NS_OK;
   454 }
   456 NS_IMETHODIMP_(bool)
   457 AtomImpl::IsStaticAtom()
   458 {
   459   return IsPermanent();
   460 }
   462 size_t
   463 AtomImpl::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
   464 {
   465   return aMallocSizeOf(this) +
   466          nsStringBuffer::FromData(mString)->
   467            SizeOfIncludingThisIfUnshared(aMallocSizeOf);
   468 }
   470 //----------------------------------------------------------------------
   472 static size_t
   473 SizeOfAtomTableEntryExcludingThis(PLDHashEntryHdr *aHdr,
   474                                   MallocSizeOf aMallocSizeOf,
   475                                   void *aArg)
   476 {
   477   AtomTableEntry* entry = static_cast<AtomTableEntry*>(aHdr);
   478   return entry->mAtom->SizeOfIncludingThis(aMallocSizeOf);
   479 }
   481 static size_t
   482 SizeOfStaticAtomTableEntryExcludingThis(const nsAString& aKey,
   483                                         nsIAtom* const& aData,
   484                                         MallocSizeOf aMallocSizeOf,
   485                                         void* aArg)
   486 {
   487   return aKey.SizeOfExcludingThisIfUnshared(aMallocSizeOf);
   488 }
   490 size_t
   491 NS_SizeOfAtomTablesIncludingThis(MallocSizeOf aMallocSizeOf) {
   492   size_t n = 0;
   493   if (gAtomTable.ops) {
   494       n += PL_DHashTableSizeOfExcludingThis(&gAtomTable,
   495                                             SizeOfAtomTableEntryExcludingThis,
   496                                             aMallocSizeOf);
   497   }
   498   if (gStaticAtomTable) {
   499     n += gStaticAtomTable->SizeOfIncludingThis(SizeOfStaticAtomTableEntryExcludingThis,
   500                                                aMallocSizeOf);
   501   }
   502   return n;
   503 }
   505 #define ATOM_HASHTABLE_INITIAL_SIZE  4096
   507 static inline void
   508 EnsureTableExists()
   509 {
   510   if (!gAtomTable.ops) {
   511     PL_DHashTableInit(&gAtomTable, &AtomTableOps, 0,
   512                       sizeof(AtomTableEntry), ATOM_HASHTABLE_INITIAL_SIZE);
   513   }
   514 }
   516 static inline AtomTableEntry*
   517 GetAtomHashEntry(const char* aString, uint32_t aLength, uint32_t& aHash)
   518 {
   519   MOZ_ASSERT(NS_IsMainThread(), "wrong thread");
   520   EnsureTableExists();
   521   AtomTableKey key(aString, aLength, aHash);
   522   AtomTableEntry* e =
   523     static_cast<AtomTableEntry*>
   524                (PL_DHashTableOperate(&gAtomTable, &key, PL_DHASH_ADD));
   525   if (!e) {
   526     NS_ABORT_OOM(gAtomTable.entryCount * gAtomTable.entrySize);
   527   }
   528   return e;
   529 }
   531 static inline AtomTableEntry*
   532 GetAtomHashEntry(const char16_t* aString, uint32_t aLength, uint32_t& aHash)
   533 {
   534   MOZ_ASSERT(NS_IsMainThread(), "wrong thread");
   535   EnsureTableExists();
   536   AtomTableKey key(aString, aLength, aHash);
   537   AtomTableEntry* e =
   538     static_cast<AtomTableEntry*>
   539                (PL_DHashTableOperate(&gAtomTable, &key, PL_DHASH_ADD));
   540   if (!e) {
   541     NS_ABORT_OOM(gAtomTable.entryCount * gAtomTable.entrySize);
   542   }
   543   return e;
   544 }
   546 class CheckStaticAtomSizes
   547 {
   548   CheckStaticAtomSizes() {
   549     static_assert((sizeof(nsFakeStringBuffer<1>().mRefCnt) ==
   550                    sizeof(nsStringBuffer().mRefCount)) &&
   551                   (sizeof(nsFakeStringBuffer<1>().mSize) ==
   552                    sizeof(nsStringBuffer().mStorageSize)) &&
   553                   (offsetof(nsFakeStringBuffer<1>, mRefCnt) ==
   554                    offsetof(nsStringBuffer, mRefCount)) &&
   555                   (offsetof(nsFakeStringBuffer<1>, mSize) ==
   556                    offsetof(nsStringBuffer, mStorageSize)) &&
   557                   (offsetof(nsFakeStringBuffer<1>, mStringData) ==
   558                    sizeof(nsStringBuffer)),
   559                   "mocked-up strings' representations should be compatible");
   560   }
   561 };
   563 nsresult
   564 RegisterStaticAtoms(const nsStaticAtom* aAtoms, uint32_t aAtomCount)
   565 {
   566   // this does three things:
   567   // 1) wraps each static atom in a wrapper, if necessary
   568   // 2) initializes the address pointed to by each mBits slot
   569   // 3) puts the atom into the static atom table as well
   571   if (!gStaticAtomTable && !gStaticAtomTableSealed) {
   572     gStaticAtomTable = new nsDataHashtable<nsStringHashKey, nsIAtom*>();
   573   }
   575   for (uint32_t i=0; i<aAtomCount; i++) {
   576     NS_ASSERTION(nsCRT::IsAscii((char16_t*)aAtoms[i].mStringBuffer->Data()),
   577                  "Static atoms must be ASCII!");
   579     uint32_t stringLen =
   580       aAtoms[i].mStringBuffer->StorageSize() / sizeof(char16_t) - 1;
   582     uint32_t hash = 0;
   583     AtomTableEntry *he =
   584       GetAtomHashEntry((char16_t*)aAtoms[i].mStringBuffer->Data(),
   585                        stringLen, hash);
   587     if (he->mAtom) {
   588       // there already is an atom with this name in the table.. but we
   589       // still have to update mBits
   590       if (!he->mAtom->IsPermanent()) {
   591         // since we wanted to create a static atom but there is
   592         // already one there, we convert it to a non-refcounting
   593         // permanent atom
   594         PromoteToPermanent(he->mAtom);
   595       }
   597       *aAtoms[i].mAtom = he->mAtom;
   598     }
   599     else {
   600       AtomImpl* atom = new PermanentAtomImpl(aAtoms[i].mStringBuffer,
   601                                              stringLen,
   602                                              hash);
   603       he->mAtom = atom;
   604       *aAtoms[i].mAtom = atom;
   606       if (!gStaticAtomTableSealed) {
   607         gStaticAtomTable->Put(nsAtomString(atom), atom);
   608       }
   609     }
   610   }
   611   return NS_OK;
   612 }
   614 already_AddRefed<nsIAtom>
   615 NS_NewAtom(const char* aUTF8String)
   616 {
   617   return NS_NewAtom(nsDependentCString(aUTF8String));
   618 }
   620 already_AddRefed<nsIAtom>
   621 NS_NewAtom(const nsACString& aUTF8String)
   622 {
   623   uint32_t hash = 0;
   624   AtomTableEntry *he = GetAtomHashEntry(aUTF8String.Data(),
   625                                         aUTF8String.Length(),
   626                                         hash);
   628   if (he->mAtom) {
   629     nsCOMPtr<nsIAtom> atom = he->mAtom;
   631     return atom.forget();
   632   }
   634   // This results in an extra addref/release of the nsStringBuffer.
   635   // Unfortunately there doesn't seem to be any APIs to avoid that.
   636   // Actually, now there is, sort of: ForgetSharedBuffer.
   637   nsString str;
   638   CopyUTF8toUTF16(aUTF8String, str);
   639   nsRefPtr<AtomImpl> atom = new AtomImpl(str, hash);
   641   he->mAtom = atom;
   643   return atom.forget();
   644 }
   646 already_AddRefed<nsIAtom>
   647 NS_NewAtom(const char16_t* aUTF16String)
   648 {
   649   return NS_NewAtom(nsDependentString(aUTF16String));
   650 }
   652 already_AddRefed<nsIAtom>
   653 NS_NewAtom(const nsAString& aUTF16String)
   654 {
   655   uint32_t hash = 0;
   656   AtomTableEntry *he = GetAtomHashEntry(aUTF16String.Data(),
   657                                         aUTF16String.Length(),
   658                                         hash);
   660   if (he->mAtom) {
   661     nsCOMPtr<nsIAtom> atom = he->mAtom;
   663     return atom.forget();
   664   }
   666   nsRefPtr<AtomImpl> atom = new AtomImpl(aUTF16String, hash);
   667   he->mAtom = atom;
   669   return atom.forget();
   670 }
   672 nsIAtom*
   673 NS_NewPermanentAtom(const nsAString& aUTF16String)
   674 {
   675   uint32_t hash = 0;
   676   AtomTableEntry *he = GetAtomHashEntry(aUTF16String.Data(),
   677                                         aUTF16String.Length(),
   678                                         hash);
   680   AtomImpl* atom = he->mAtom;
   681   if (atom) {
   682     if (!atom->IsPermanent()) {
   683       PromoteToPermanent(atom);
   684     }
   685   }
   686   else {
   687     atom = new PermanentAtomImpl(aUTF16String, hash);
   688     he->mAtom = atom;
   689   }
   691   // No need to addref since permanent atoms aren't refcounted anyway
   692   return atom;
   693 }
   695 nsrefcnt
   696 NS_GetNumberOfAtoms(void)
   697 {
   698   return gAtomTable.entryCount;
   699 }
   701 nsIAtom*
   702 NS_GetStaticAtom(const nsAString& aUTF16String)
   703 {
   704   NS_PRECONDITION(gStaticAtomTable, "Static atom table not created yet.");
   705   NS_PRECONDITION(gStaticAtomTableSealed, "Static atom table not sealed yet.");
   706   nsIAtom* atom;
   707   if (!gStaticAtomTable->Get(aUTF16String, &atom)) {
   708     atom = nullptr;
   709   }
   710   return atom;
   711 }
   713 void
   714 NS_SealStaticAtomTable()
   715 {
   716   gStaticAtomTableSealed = true;
   717 }

mercurial