LCOV - code coverage report
Current view: directory - xpcom/ds - nsAtomTable.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 241 175 72.6 %
Date: 2012-06-02 Functions: 48 37 77.1 %

       1                 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2                 : // vim:cindent:ts=2:et:sw=2:
       3                 : /* ***** BEGIN LICENSE BLOCK *****
       4                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       5                 :  *
       6                 :  * The contents of this file are subject to the Mozilla Public License Version
       7                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       8                 :  * the License. You may obtain a copy of the License at
       9                 :  * http://www.mozilla.org/MPL/
      10                 :  *
      11                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      12                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      13                 :  * for the specific language governing rights and limitations under the
      14                 :  * License.
      15                 :  *
      16                 :  * The Original Code is mozilla.org code.
      17                 :  *
      18                 :  * The Initial Developer of the Original Code is
      19                 :  * Netscape Communications Corporation.
      20                 :  * Portions created by the Initial Developer are Copyright (C) 1998
      21                 :  * the Initial Developer. All Rights Reserved.
      22                 :  *
      23                 :  * Contributor(s):
      24                 :  *
      25                 :  * Alternatively, the contents of this file may be used under the terms of
      26                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
      27                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      28                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      29                 :  * of those above. If you wish to allow use of your version of this file only
      30                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      31                 :  * use your version of this file under the terms of the MPL, indicate your
      32                 :  * decision by deleting the provisions above and replace them with the notice
      33                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      34                 :  * the provisions above, a recipient may use your version of this file under
      35                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      36                 :  *
      37                 :  * ***** END LICENSE BLOCK ***** */
      38                 : 
      39                 : #include "mozilla/Assertions.h"
      40                 : #include "mozilla/HashFunctions.h"
      41                 : 
      42                 : #include "nsAtomTable.h"
      43                 : #include "nsStaticAtom.h"
      44                 : #include "nsString.h"
      45                 : #include "nsReadableUtils.h"
      46                 : #include "nsUTF8Utils.h"
      47                 : #include "nsCRT.h"
      48                 : #include "pldhash.h"
      49                 : #include "prenv.h"
      50                 : #include "nsThreadUtils.h"
      51                 : #include "nsDataHashtable.h"
      52                 : #include "nsHashKeys.h"
      53                 : #include "nsAutoPtr.h"
      54                 : #include "nsUnicharUtils.h"
      55                 : 
      56                 : #define PL_ARENA_CONST_ALIGN_MASK 3
      57                 : #include "plarena.h"
      58                 : 
      59                 : using namespace mozilla;
      60                 : 
      61                 : /**
      62                 :  * The shared hash table for atom lookups.
      63                 :  *
      64                 :  * XXX This should be manipulated in a threadsafe way or we should make
      65                 :  * sure it's only manipulated from the main thread.  Probably the latter
      66                 :  * is better, since the former would hurt performance.
      67                 :  *
      68                 :  * If |gAtomTable.ops| is 0, then the table is uninitialized.
      69                 :  */
      70                 : static PLDHashTable gAtomTable;
      71                 : 
      72                 : /**
      73                 :  * A hashtable of static atoms that existed at app startup. This hashtable helps 
      74                 :  * nsHtml5AtomTable.
      75                 :  */
      76                 : static nsDataHashtable<nsStringHashKey, nsIAtom*>* gStaticAtomTable = 0;
      77                 : 
      78                 : /**
      79                 :  * Whether it is still OK to add atoms to gStaticAtomTable.
      80                 :  */
      81                 : static bool gStaticAtomTableSealed = false;
      82                 : 
      83                 : //----------------------------------------------------------------------
      84                 : 
      85                 : /**
      86                 :  * Note that AtomImpl objects are sometimes converted into PermanentAtomImpl
      87                 :  * objects using placement new and just overwriting the vtable pointer.
      88                 :  */
      89                 : 
      90                 : class AtomImpl : public nsIAtom {
      91                 : public:
      92                 :   AtomImpl(const nsAString& aString, PLDHashNumber aKeyHash);
      93                 : 
      94                 :   // This is currently only used during startup when creating a permanent atom
      95                 :   // from NS_RegisterStaticAtoms
      96                 :   AtomImpl(nsStringBuffer* aData, PRUint32 aLength, PLDHashNumber aKeyHash);
      97                 : 
      98                 : protected:
      99                 :   // This is only intended to be used when a normal atom is turned into a
     100                 :   // permanent one.
     101              24 :   AtomImpl() {
     102                 :     // We can't really assert that mString is a valid nsStringBuffer string,
     103                 :     // so do the best we can do and check for some consistencies.
     104              24 :     NS_ASSERTION((mLength + 1) * sizeof(PRUnichar) <=
     105                 :                  nsStringBuffer::FromData(mString)->StorageSize() &&
     106                 :                  mString[mLength] == 0,
     107                 :                  "Not initialized atom");
     108              24 :   }
     109                 : 
     110                 :   // We don't need a virtual destructor here because PermanentAtomImpl
     111                 :   // deletions aren't handled through Release().
     112                 :   ~AtomImpl();
     113                 : 
     114                 : public:
     115                 :   NS_DECL_ISUPPORTS
     116                 :   NS_DECL_NSIATOM
     117                 : 
     118                 :   enum { REFCNT_PERMANENT_SENTINEL = PR_UINT32_MAX };
     119                 : 
     120                 :   virtual bool IsPermanent();
     121                 : 
     122                 :   // We can't use the virtual function in the base class destructor.
     123         3244492 :   bool IsPermanentInDestructor() {
     124         3244492 :     return mRefCnt == REFCNT_PERMANENT_SENTINEL;
     125                 :   }
     126                 : 
     127                 :   // for |#ifdef NS_BUILD_REFCNT_LOGGING| access to reference count
     128              24 :   nsrefcnt GetRefCount() { return mRefCnt; }
     129                 : 
     130                 :   size_t SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const;
     131                 : };
     132                 : 
     133                 : /**
     134                 :  * A non-refcounted implementation of nsIAtom.
     135                 :  */
     136                 : 
     137                 : class PermanentAtomImpl : public AtomImpl {
     138                 : public:
     139               0 :   PermanentAtomImpl(const nsAString& aString, PLDHashNumber aKeyHash)
     140               0 :     : AtomImpl(aString, aKeyHash)
     141               0 :   {}
     142         3227071 :   PermanentAtomImpl(nsStringBuffer* aData, PRUint32 aLength,
     143                 :                     PLDHashNumber aKeyHash)
     144         3227071 :     : AtomImpl(aData, aLength, aKeyHash)
     145         3227071 :   {}
     146              24 :   PermanentAtomImpl()
     147              24 :   {}
     148                 : 
     149                 :   ~PermanentAtomImpl();
     150                 :   NS_IMETHOD_(nsrefcnt) AddRef();
     151                 :   NS_IMETHOD_(nsrefcnt) Release();
     152                 : 
     153                 :   virtual bool IsPermanent();
     154                 : 
     155                 :   // SizeOfIncludingThis() isn't needed -- the one inherited from AtomImpl is
     156                 :   // good enough, because PermanentAtomImpl doesn't add any new data members.
     157                 : 
     158                 :   void* operator new(size_t size, AtomImpl* aAtom) CPP_THROW_NEW;
     159         3227071 :   void* operator new(size_t size) CPP_THROW_NEW
     160                 :   {
     161         3227071 :     return ::operator new(size);
     162                 :   }
     163                 : };
     164                 : 
     165                 : //----------------------------------------------------------------------
     166                 : 
     167                 : struct AtomTableEntry : public PLDHashEntryHdr {
     168                 :   AtomImpl* mAtom;
     169                 : };
     170                 : 
     171                 : struct AtomTableKey
     172                 : {
     173         4860607 :   AtomTableKey(const PRUnichar* aUTF16String, PRUint32 aLength)
     174                 :     : mUTF16String(aUTF16String),
     175                 :       mUTF8String(nsnull),
     176         4860607 :       mLength(aLength)
     177                 :   {
     178         4860607 :   }
     179                 : 
     180           69442 :   AtomTableKey(const char* aUTF8String, PRUint32 aLength)
     181                 :     : mUTF16String(nsnull),
     182                 :       mUTF8String(aUTF8String),
     183           69442 :       mLength(aLength)
     184                 :   {
     185           69442 :   }
     186                 : 
     187                 :   const PRUnichar* mUTF16String;
     188                 :   const char* mUTF8String;
     189                 :   PRUint32 mLength;
     190                 : };
     191                 : 
     192                 : static PLDHashNumber
     193         4930049 : AtomTableGetHash(PLDHashTable *table, const void *key)
     194                 : {
     195         4930049 :   const AtomTableKey *k = static_cast<const AtomTableKey*>(key);
     196                 : 
     197         4930049 :   if (k->mUTF8String) {
     198                 :     bool err;
     199           69442 :     PRUint32 hash = HashUTF8AsUTF16(k->mUTF8String, k->mLength, &err);
     200           69442 :     if (err) {
     201               0 :       AtomTableKey* mutableKey = const_cast<AtomTableKey*>(k);
     202               0 :       mutableKey->mUTF8String = nsnull;
     203               0 :       mutableKey->mLength = 0;
     204               0 :       hash = 0;
     205                 :     }
     206           69442 :     return hash;
     207                 :   }
     208                 : 
     209         4860607 :   return HashString(k->mUTF16String, k->mLength);
     210                 : }
     211                 : 
     212                 : static bool
     213         1685553 : AtomTableMatchKey(PLDHashTable *table, const PLDHashEntryHdr *entry,
     214                 :                   const void *key)
     215                 : {
     216         1685553 :   const AtomTableEntry *he = static_cast<const AtomTableEntry*>(entry);
     217         1685553 :   const AtomTableKey *k = static_cast<const AtomTableKey*>(key);
     218                 : 
     219         1685553 :   if (k->mUTF8String) {
     220                 :     return
     221                 :       CompareUTF8toUTF16(nsDependentCSubstring(k->mUTF8String,
     222           61504 :                                                k->mUTF8String + k->mLength),
     223          123008 :                          nsDependentAtomString(he->mAtom)) == 0;
     224                 :   }
     225                 : 
     226         1624049 :   PRUint32 length = he->mAtom->GetLength();
     227         1624049 :   if (length != k->mLength) {
     228               0 :     return false;
     229                 :   }
     230                 : 
     231         1624049 :   return memcmp(he->mAtom->GetUTF16String(),
     232         3248098 :                 k->mUTF16String, length * sizeof(PRUnichar)) == 0;
     233                 : }
     234                 : 
     235                 : static void
     236         3244496 : AtomTableClearEntry(PLDHashTable *table, PLDHashEntryHdr *entry)
     237                 : {
     238                 :   // Normal |AtomImpl| atoms are deleted when their refcount hits 0, and
     239                 :   // they then remove themselves from the table.  In other words, they
     240                 :   // are owned by the callers who own references to them.
     241                 :   // |PermanentAtomImpl| permanent atoms ignore their refcount and are
     242                 :   // deleted when they are removed from the table at table destruction.
     243                 :   // In other words, they are owned by the atom table.
     244                 : 
     245         3244496 :   AtomImpl *atom = static_cast<AtomTableEntry*>(entry)->mAtom;
     246         3244496 :   if (atom->IsPermanent()) {
     247                 :     // Note that the cast here is important since AtomImpls doesn't have a
     248                 :     // virtual dtor.
     249         3227095 :     delete static_cast<PermanentAtomImpl*>(atom);
     250                 :   }
     251         3244496 : }
     252                 : 
     253                 : static bool
     254         3244496 : AtomTableInitEntry(PLDHashTable *table, PLDHashEntryHdr *entry,
     255                 :                    const void *key)
     256                 : {
     257         3244496 :   static_cast<AtomTableEntry*>(entry)->mAtom = nsnull;
     258                 : 
     259         3244496 :   return true;
     260                 : }
     261                 : 
     262                 : 
     263                 : static const PLDHashTableOps AtomTableOps = {
     264                 :   PL_DHashAllocTable,
     265                 :   PL_DHashFreeTable,
     266                 :   AtomTableGetHash,
     267                 :   AtomTableMatchKey,
     268                 :   PL_DHashMoveEntryStub,
     269                 :   AtomTableClearEntry,
     270                 :   PL_DHashFinalizeStub,
     271                 :   AtomTableInitEntry
     272                 : };
     273                 : 
     274                 : 
     275                 : #ifdef DEBUG
     276                 : static PLDHashOperator
     277               0 : DumpAtomLeaks(PLDHashTable *table, PLDHashEntryHdr *he,
     278                 :               PRUint32 index, void *arg)
     279                 : {
     280               0 :   AtomTableEntry *entry = static_cast<AtomTableEntry*>(he);
     281                 :   
     282               0 :   AtomImpl* atom = entry->mAtom;
     283               0 :   if (!atom->IsPermanent()) {
     284               0 :     ++*static_cast<PRUint32*>(arg);
     285               0 :     nsCAutoString str;
     286               0 :     atom->ToUTF8String(str);
     287               0 :     fputs(str.get(), stdout);
     288               0 :     fputs("\n", stdout);
     289                 :   }
     290               0 :   return PL_DHASH_NEXT;
     291                 : }
     292                 : #endif
     293                 : 
     294                 : static inline
     295              24 : void PromoteToPermanent(AtomImpl* aAtom)
     296                 : {
     297                 : #ifdef NS_BUILD_REFCNT_LOGGING
     298                 :   {
     299              24 :     nsrefcnt refcount = aAtom->GetRefCount();
     300              98 :     do {
     301              98 :       NS_LOG_RELEASE(aAtom, --refcount, "AtomImpl");
     302                 :     } while (refcount);
     303                 :   }
     304                 : #endif
     305              24 :   aAtom = new (aAtom) PermanentAtomImpl();
     306              24 : }
     307                 : 
     308                 : void
     309            1419 : NS_PurgeAtomTable()
     310                 : {
     311            1419 :   delete gStaticAtomTable;
     312                 : 
     313            1419 :   if (gAtomTable.ops) {
     314                 : #ifdef DEBUG
     315            1419 :     const char *dumpAtomLeaks = PR_GetEnv("MOZ_DUMP_ATOM_LEAKS");
     316            1419 :     if (dumpAtomLeaks && *dumpAtomLeaks) {
     317               0 :       PRUint32 leaked = 0;
     318                 :       printf("*** %d atoms still exist (including permanent):\n",
     319               0 :              gAtomTable.entryCount);
     320               0 :       PL_DHashTableEnumerate(&gAtomTable, DumpAtomLeaks, &leaked);
     321               0 :       printf("*** %u non-permanent atoms leaked\n", leaked);
     322                 :     }
     323                 : #endif
     324            1419 :     PL_DHashTableFinish(&gAtomTable);
     325            1419 :     gAtomTable.entryCount = 0;
     326            1419 :     gAtomTable.ops = nsnull;
     327                 :   }
     328            1419 : }
     329                 : 
     330           17425 : AtomImpl::AtomImpl(const nsAString& aString, PLDHashNumber aKeyHash)
     331                 : {
     332           17425 :   mLength = aString.Length();
     333           17425 :   nsStringBuffer* buf = nsStringBuffer::FromString(aString);
     334           17425 :   if (buf) {
     335            9199 :     buf->AddRef();
     336            9199 :     mString = static_cast<PRUnichar*>(buf->Data());
     337                 :   }
     338                 :   else {
     339            8226 :     buf = nsStringBuffer::Alloc((mLength + 1) * sizeof(PRUnichar));
     340            8226 :     mString = static_cast<PRUnichar*>(buf->Data());
     341            8226 :     CopyUnicodeTo(aString, 0, mString, mLength);
     342            8226 :     mString[mLength] = PRUnichar(0);
     343                 :   }
     344                 : 
     345                 :   // The low bit of aKeyHash is generally useless, so shift it out
     346                 :   MOZ_ASSERT(sizeof(mHash) == sizeof(PLDHashNumber));
     347           17425 :   mHash = aKeyHash >> 1;
     348                 : 
     349           17425 :   NS_ASSERTION(mString[mLength] == PRUnichar(0), "null terminated");
     350           17425 :   NS_ASSERTION(buf && buf->StorageSize() >= (mLength+1) * sizeof(PRUnichar),
     351                 :                "enough storage");
     352           17425 :   NS_ASSERTION(Equals(aString), "correct data");
     353           17425 : }
     354                 : 
     355         3227071 : AtomImpl::AtomImpl(nsStringBuffer* aStringBuffer, PRUint32 aLength,
     356         3227071 :                    PLDHashNumber aKeyHash)
     357                 : {
     358         3227071 :   mLength = aLength;
     359         3227071 :   mString = static_cast<PRUnichar*>(aStringBuffer->Data());
     360                 :   // Technically we could currently avoid doing this addref by instead making
     361                 :   // the static atom buffers have an initial refcount of 2.
     362         3227071 :   aStringBuffer->AddRef();
     363                 : 
     364                 :   // The low bit of aKeyHash is generally useless, so shift it out
     365                 :   MOZ_ASSERT(sizeof(mHash) == sizeof(PLDHashNumber));
     366         3227071 :   mHash = aKeyHash >> 1;
     367                 : 
     368         3227071 :   NS_ASSERTION(mString[mLength] == PRUnichar(0), "null terminated");
     369         3227071 :   NS_ASSERTION(aStringBuffer &&
     370                 :                aStringBuffer->StorageSize() == (mLength+1) * sizeof(PRUnichar),
     371                 :                "correct storage");
     372         3227071 : }
     373                 : 
     374         3244492 : AtomImpl::~AtomImpl()
     375                 : {
     376         3244492 :   NS_PRECONDITION(gAtomTable.ops, "uninitialized atom hashtable");
     377                 :   // Permanent atoms are removed from the hashtable at shutdown, and we
     378                 :   // don't want to remove them twice.  See comment above in
     379                 :   // |AtomTableClearEntry|.
     380         3244492 :   if (!IsPermanentInDestructor()) {
     381           17397 :     AtomTableKey key(mString, mLength);
     382           17397 :     PL_DHashTableOperate(&gAtomTable, &key, PL_DHASH_REMOVE);
     383           17397 :     if (gAtomTable.entryCount == 0) {
     384               0 :       PL_DHashTableFinish(&gAtomTable);
     385               0 :       NS_ASSERTION(gAtomTable.entryCount == 0,
     386                 :                    "PL_DHashTableFinish changed the entry count");
     387                 :     }
     388                 :   }
     389                 : 
     390         3244492 :   nsStringBuffer::FromData(mString)->Release();
     391         3244492 : }
     392                 : 
     393          821091 : NS_IMPL_ISUPPORTS1(AtomImpl, nsIAtom)
     394                 : 
     395         6454190 : PermanentAtomImpl::~PermanentAtomImpl()
     396                 : {
     397                 :   // So we can tell if we were permanent while running the base class dtor.
     398         3227095 :   mRefCnt = REFCNT_PERMANENT_SENTINEL;
     399         3227095 : }
     400                 : 
     401          832859 : NS_IMETHODIMP_(nsrefcnt) PermanentAtomImpl::AddRef()
     402                 : {
     403          832859 :   NS_ASSERTION(NS_IsMainThread(), "wrong thread");
     404          832859 :   return 2;
     405                 : }
     406                 : 
     407          833546 : NS_IMETHODIMP_(nsrefcnt) PermanentAtomImpl::Release()
     408                 : {
     409          833546 :   NS_ASSERTION(NS_IsMainThread(), "wrong thread");
     410          833546 :   return 1;
     411                 : }
     412                 : 
     413                 : /* virtual */ bool
     414           17449 : AtomImpl::IsPermanent()
     415                 : {
     416           17449 :   return false;
     417                 : }
     418                 : 
     419                 : /* virtual */ bool
     420         4626987 : PermanentAtomImpl::IsPermanent()
     421                 : {
     422         4626987 :   return true;
     423                 : }
     424                 : 
     425              24 : void* PermanentAtomImpl::operator new ( size_t size, AtomImpl* aAtom ) CPP_THROW_NEW {
     426              24 :   NS_ASSERTION(!aAtom->IsPermanent(),
     427                 :                "converting atom that's already permanent");
     428                 : 
     429                 :   // Just let the constructor overwrite the vtable pointer.
     430              24 :   return aAtom;
     431                 : }
     432                 : 
     433                 : NS_IMETHODIMP 
     434               0 : AtomImpl::ScriptableToString(nsAString& aBuf)
     435                 : {
     436               0 :   nsStringBuffer::FromData(mString)->ToString(mLength, aBuf);
     437               0 :   return NS_OK;
     438                 : }
     439                 : 
     440                 : NS_IMETHODIMP
     441           29588 : AtomImpl::ToUTF8String(nsACString& aBuf)
     442                 : {
     443           29588 :   CopyUTF16toUTF8(nsDependentString(mString, mLength), aBuf);
     444           29588 :   return NS_OK;
     445                 : }
     446                 : 
     447                 : NS_IMETHODIMP_(bool)
     448               0 : AtomImpl::EqualsUTF8(const nsACString& aString)
     449                 : {
     450                 :   return CompareUTF8toUTF16(aString,
     451               0 :                             nsDependentString(mString, mLength)) == 0;
     452                 : }
     453                 : 
     454                 : NS_IMETHODIMP
     455               0 : AtomImpl::ScriptableEquals(const nsAString& aString, bool* aResult)
     456                 : {
     457               0 :   *aResult = aString.Equals(nsDependentString(mString, mLength));
     458               0 :   return NS_OK;
     459                 : }
     460                 : 
     461                 : NS_IMETHODIMP_(bool)
     462            2340 : AtomImpl::IsStaticAtom()
     463                 : {
     464            2340 :   return IsPermanent();
     465                 : }
     466                 : 
     467                 : size_t
     468               0 : AtomImpl::SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const
     469                 : {
     470               0 :   return aMallocSizeOf(this) +
     471                 :          nsStringBuffer::FromData(mString)->
     472               0 :            SizeOfIncludingThisIfUnshared(aMallocSizeOf);
     473                 : }
     474                 : 
     475                 : //----------------------------------------------------------------------
     476                 : 
     477                 : static size_t
     478               0 : SizeOfAtomTableEntryExcludingThis(PLDHashEntryHdr *aHdr,
     479                 :                                   nsMallocSizeOfFun aMallocSizeOf,
     480                 :                                   void *aArg)
     481                 : {
     482               0 :   AtomTableEntry* entry = static_cast<AtomTableEntry*>(aHdr);
     483               0 :   return entry->mAtom->SizeOfIncludingThis(aMallocSizeOf);
     484                 : }
     485                 : 
     486               0 : size_t NS_SizeOfAtomTableIncludingThis(nsMallocSizeOfFun aMallocSizeOf) {
     487               0 :   if (gAtomTable.ops) {
     488                 :       return PL_DHashTableSizeOfExcludingThis(&gAtomTable,
     489                 :                                               SizeOfAtomTableEntryExcludingThis,
     490               0 :                                               aMallocSizeOf);
     491                 :   }
     492               0 :   return 0;
     493                 : }
     494                 : 
     495                 : #define ATOM_HASHTABLE_INITIAL_SIZE  4096
     496                 : 
     497                 : static inline bool
     498         4912652 : EnsureTableExists()
     499                 : {
     500         4912652 :   if (gAtomTable.ops) {
     501         4911233 :     return true;
     502                 :   }
     503            1419 :   if (PL_DHashTableInit(&gAtomTable, &AtomTableOps, 0,
     504                 :                         sizeof(AtomTableEntry), ATOM_HASHTABLE_INITIAL_SIZE)) {
     505            1419 :     return true;
     506                 :   }
     507                 :   // Initialization failed.
     508               0 :   gAtomTable.ops = nsnull;
     509               0 :   return false;
     510                 : }
     511                 : 
     512                 : static inline AtomTableEntry*
     513           69442 : GetAtomHashEntry(const char* aString, PRUint32 aLength)
     514                 : {
     515           69442 :   NS_ASSERTION(NS_IsMainThread(), "wrong thread");
     516           69442 :   if (!EnsureTableExists()) {
     517               0 :     return nsnull;
     518                 :   }
     519           69442 :   AtomTableKey key(aString, aLength);
     520                 :   return static_cast<AtomTableEntry*>
     521           69442 :                     (PL_DHashTableOperate(&gAtomTable, &key, PL_DHASH_ADD));
     522                 : }
     523                 : 
     524                 : static inline AtomTableEntry*
     525         4843210 : GetAtomHashEntry(const PRUnichar* aString, PRUint32 aLength)
     526                 : {
     527         4843210 :   NS_ASSERTION(NS_IsMainThread(), "wrong thread");
     528         4843210 :   if (!EnsureTableExists()) {
     529               0 :     return nsnull;
     530                 :   }
     531         4843210 :   AtomTableKey key(aString, aLength);
     532                 :   return static_cast<AtomTableEntry*>
     533         4843210 :                     (PL_DHashTableOperate(&gAtomTable, &key, PL_DHASH_ADD));
     534                 : }
     535                 : 
     536                 : class CheckStaticAtomSizes
     537                 : {
     538                 :   CheckStaticAtomSizes() {
     539                 :     MOZ_STATIC_ASSERT((sizeof(nsFakeStringBuffer<1>().mRefCnt) ==
     540                 :                        sizeof(nsStringBuffer().mRefCount)) &&
     541                 :                       (sizeof(nsFakeStringBuffer<1>().mSize) ==
     542                 :                        sizeof(nsStringBuffer().mStorageSize)) &&
     543                 :                       (offsetof(nsFakeStringBuffer<1>, mRefCnt) ==
     544                 :                        offsetof(nsStringBuffer, mRefCount)) &&
     545                 :                       (offsetof(nsFakeStringBuffer<1>, mSize) ==
     546                 :                        offsetof(nsStringBuffer, mStorageSize)) &&
     547                 :                       (offsetof(nsFakeStringBuffer<1>, mStringData) ==
     548                 :                        sizeof(nsStringBuffer)),
     549                 :                       "mocked-up strings' representations should be compatible");
     550                 :   }
     551                 : };
     552                 : 
     553                 : nsresult
     554           13452 : RegisterStaticAtoms(const nsStaticAtom* aAtoms, PRUint32 aAtomCount)
     555                 : {
     556                 :   // this does three things:
     557                 :   // 1) wraps each static atom in a wrapper, if necessary
     558                 :   // 2) initializes the address pointed to by each mBits slot
     559                 :   // 3) puts the atom into the static atom table as well
     560                 :   
     561           13452 :   if (!gStaticAtomTable && !gStaticAtomTableSealed) {
     562            1419 :     gStaticAtomTable = new nsDataHashtable<nsStringHashKey, nsIAtom*>();
     563            1419 :     if (!gStaticAtomTable || !gStaticAtomTable->Init()) {
     564               0 :       delete gStaticAtomTable;
     565               0 :       gStaticAtomTable = nsnull;
     566               0 :       return NS_ERROR_OUT_OF_MEMORY;
     567                 :     }
     568                 :   }
     569                 :   
     570         4638099 :   for (PRUint32 i=0; i<aAtomCount; i++) {
     571                 : #ifdef NS_STATIC_ATOM_USE_WIDE_STRINGS
     572         4624647 :     NS_ASSERTION(nsCRT::IsAscii((PRUnichar*)aAtoms[i].mStringBuffer->Data()),
     573                 :                  "Static atoms must be ASCII!");
     574                 : 
     575                 :     PRUint32 stringLen =
     576         4624647 :       aAtoms[i].mStringBuffer->StorageSize() / sizeof(PRUnichar) - 1;
     577                 : 
     578                 :     AtomTableEntry *he =
     579         4624647 :       GetAtomHashEntry((PRUnichar*)aAtoms[i].mStringBuffer->Data(),
     580         4624647 :                        stringLen);
     581                 : 
     582         4624647 :     if (he->mAtom) {
     583                 :       // there already is an atom with this name in the table.. but we
     584                 :       // still have to update mBits
     585         1397576 :       if (!he->mAtom->IsPermanent()) {
     586                 :         // since we wanted to create a static atom but there is
     587                 :         // already one there, we convert it to a non-refcounting
     588                 :         // permanent atom
     589              24 :         PromoteToPermanent(he->mAtom);
     590                 :       }
     591                 :       
     592         1397576 :       *aAtoms[i].mAtom = he->mAtom;
     593                 :     }
     594                 :     else {
     595         3227071 :       AtomImpl* atom = new PermanentAtomImpl(aAtoms[i].mStringBuffer,
     596                 :                                              stringLen,
     597         6454142 :                                              he->keyHash);
     598         3227071 :       he->mAtom = atom;
     599         3227071 :       *aAtoms[i].mAtom = atom;
     600                 : 
     601         3227071 :       if (!gStaticAtomTableSealed) {
     602         3225288 :         gStaticAtomTable->Put(nsAtomString(atom), atom);
     603                 :       }
     604                 :     }
     605                 : #else // NS_STATIC_ATOM_USE_WIDE_STRINGS
     606                 :     NS_ASSERTION(nsCRT::IsAscii((char*)aAtoms[i].mStringBuffer->Data()),
     607                 :                  "Static atoms must be ASCII!");
     608                 : 
     609                 :     PRUint32 stringLen = aAtoms[i].mStringBuffer->StorageSize() - 1;
     610                 : 
     611                 :     NS_ConvertASCIItoUTF16 str((char*)aAtoms[i].mStringBuffer->Data(),
     612                 :                                stringLen);
     613                 :     nsIAtom* atom = NS_NewPermanentAtom(str);
     614                 :     *aAtoms[i].mAtom = atom;
     615                 : 
     616                 :     if (!gStaticAtomTableSealed) {
     617                 :       gStaticAtomTable->Put(str, atom);
     618                 :     }
     619                 : #endif
     620                 : 
     621                 :   }
     622           13452 :   return NS_OK;
     623                 : }
     624                 : 
     625                 : nsIAtom*
     626           69366 : NS_NewAtom(const char* aUTF8String)
     627                 : {
     628           69366 :   return NS_NewAtom(nsDependentCString(aUTF8String));
     629                 : }
     630                 : 
     631                 : nsIAtom*
     632           69442 : NS_NewAtom(const nsACString& aUTF8String)
     633                 : {
     634                 :   AtomTableEntry *he = GetAtomHashEntry(aUTF8String.Data(),
     635           69442 :                                         aUTF8String.Length());
     636                 : 
     637           69442 :   if (he->mAtom) {
     638                 :     nsIAtom* atom;
     639           61504 :     NS_ADDREF(atom = he->mAtom);
     640                 : 
     641           61504 :     return atom;
     642                 :   }
     643                 : 
     644                 :   // This results in an extra addref/release of the nsStringBuffer.
     645                 :   // Unfortunately there doesn't seem to be any APIs to avoid that.
     646                 :   // Actually, now there is, sort of: ForgetSharedBuffer.
     647           15876 :   nsString str;
     648            7938 :   CopyUTF8toUTF16(aUTF8String, str);
     649            7938 :   AtomImpl* atom = new AtomImpl(str, he->keyHash);
     650                 : 
     651            7938 :   he->mAtom = atom;
     652            7938 :   NS_ADDREF(atom);
     653                 : 
     654            7938 :   return atom;
     655                 : }
     656                 : 
     657                 : nsIAtom*
     658           31935 : NS_NewAtom(const PRUnichar* aUTF16String)
     659                 : {
     660           31935 :   return NS_NewAtom(nsDependentString(aUTF16String));
     661                 : }
     662                 : 
     663                 : nsIAtom*
     664          218563 : NS_NewAtom(const nsAString& aUTF16String)
     665                 : {
     666                 :   AtomTableEntry *he = GetAtomHashEntry(aUTF16String.Data(),
     667          218563 :                                         aUTF16String.Length());
     668                 : 
     669          218563 :   if (he->mAtom) {
     670                 :     nsIAtom* atom;
     671          209076 :     NS_ADDREF(atom = he->mAtom);
     672                 : 
     673          209076 :     return atom;
     674                 :   }
     675                 : 
     676            9487 :   AtomImpl* atom = new AtomImpl(aUTF16String, he->keyHash);
     677            9487 :   he->mAtom = atom;
     678            9487 :   NS_ADDREF(atom);
     679                 : 
     680            9487 :   return atom;
     681                 : }
     682                 : 
     683                 : nsIAtom*
     684               0 : NS_NewPermanentAtom(const nsAString& aUTF16String)
     685                 : {
     686                 :   AtomTableEntry *he = GetAtomHashEntry(aUTF16String.Data(),
     687               0 :                                         aUTF16String.Length());
     688                 : 
     689               0 :   AtomImpl* atom = he->mAtom;
     690               0 :   if (atom) {
     691               0 :     if (!atom->IsPermanent()) {
     692               0 :       PromoteToPermanent(atom);
     693                 :     }
     694                 :   }
     695                 :   else {
     696               0 :     atom = new PermanentAtomImpl(aUTF16String, he->keyHash);
     697               0 :     he->mAtom = atom;
     698                 :   }
     699                 : 
     700                 :   // No need to addref since permanent atoms aren't refcounted anyway
     701               0 :   return atom;
     702                 : }
     703                 : 
     704                 : nsrefcnt
     705               0 : NS_GetNumberOfAtoms(void)
     706                 : {
     707               0 :   return gAtomTable.entryCount;
     708                 : }
     709                 : 
     710                 : nsIAtom*
     711               0 : NS_GetStaticAtom(const nsAString& aUTF16String)
     712                 : {
     713               0 :   NS_PRECONDITION(gStaticAtomTable, "Static atom table not created yet.");
     714               0 :   NS_PRECONDITION(gStaticAtomTableSealed, "Static atom table not sealed yet.");
     715                 :   nsIAtom* atom;
     716               0 :   if (!gStaticAtomTable->Get(aUTF16String, &atom)) {
     717               0 :     atom = nsnull;
     718                 :   }
     719               0 :   return atom;
     720                 : }
     721                 : 
     722                 : void
     723            1404 : NS_SealStaticAtomTable()
     724                 : {
     725            1404 :   gStaticAtomTableSealed = true;
     726            1404 : }

Generated by: LCOV version 1.7