xpcom/glue/nsTHashtable.h

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

     1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 #ifndef nsTHashtable_h__
     7 #define nsTHashtable_h__
     9 #include "nscore.h"
    10 #include "pldhash.h"
    11 #include "nsDebug.h"
    12 #include "mozilla/MemoryChecking.h"
    13 #include "mozilla/MemoryReporting.h"
    14 #include "mozilla/Move.h"
    15 #include "mozilla/fallible.h"
    16 #include "mozilla/PodOperations.h"
    18 #include <new>
    20 // helper function for nsTHashtable::Clear()
    21 NS_COM_GLUE PLDHashOperator
    22 PL_DHashStubEnumRemove(PLDHashTable    *table,
    23                        PLDHashEntryHdr *entry,
    24                        uint32_t         ordinal,
    25                        void            *userArg);
    28 /**
    29  * a base class for templated hashtables.
    30  *
    31  * Clients will rarely need to use this class directly. Check the derived
    32  * classes first, to see if they will meet your needs.
    33  *
    34  * @param EntryType  the templated entry-type class that is managed by the
    35  *   hashtable. <code>EntryType</code> must extend the following declaration,
    36  *   and <strong>must not declare any virtual functions or derive from classes
    37  *   with virtual functions.</strong>  Any vtable pointer would break the
    38  *   PLDHashTable code.
    39  *<pre>   class EntryType : public PLDHashEntryHdr
    40  *   {
    41  *   public: or friend nsTHashtable<EntryType>;
    42  *     // KeyType is what we use when Get()ing or Put()ing this entry
    43  *     // this should either be a simple datatype (uint32_t, nsISupports*) or
    44  *     // a const reference (const nsAString&)
    45  *     typedef something KeyType;
    46  *     // KeyTypePointer is the pointer-version of KeyType, because pldhash.h
    47  *     // requires keys to cast to <code>const void*</code>
    48  *     typedef const something* KeyTypePointer;
    49  *
    50  *     EntryType(KeyTypePointer aKey);
    51  *
    52  *     // A copy or C++11 Move constructor must be defined, even if
    53  *     // AllowMemMove() == true, otherwise you will cause link errors.
    54  *     EntryType(const EntryType& aEnt);  // Either this...
    55  *     EntryType(EntryType&& aEnt);       // ...or this
    56  *
    57  *     // the destructor must be defined... or you will cause link errors!
    58  *     ~EntryType();
    59  *
    60  *     // KeyEquals(): does this entry match this key?
    61  *     bool KeyEquals(KeyTypePointer aKey) const;
    62  *
    63  *     // KeyToPointer(): Convert KeyType to KeyTypePointer
    64  *     static KeyTypePointer KeyToPointer(KeyType aKey);
    65  *
    66  *     // HashKey(): calculate the hash number
    67  *     static PLDHashNumber HashKey(KeyTypePointer aKey);
    68  *
    69  *     // ALLOW_MEMMOVE can we move this class with memmove(), or do we have
    70  *     // to use the copy constructor?
    71  *     enum { ALLOW_MEMMOVE = true/false };
    72  *   }</pre>
    73  *
    74  * @see nsInterfaceHashtable
    75  * @see nsDataHashtable
    76  * @see nsClassHashtable
    77  * @author "Benjamin Smedberg <bsmedberg@covad.net>"
    78  */
    80 template<class EntryType>
    81 class nsTHashtable
    82 {
    83   typedef mozilla::fallible_t fallible_t;
    85 public:
    86   // Separate constructors instead of default aInitSize parameter since
    87   // otherwise the default no-arg constructor isn't found.
    88   nsTHashtable()
    89   {
    90     Init(PL_DHASH_MIN_SIZE);
    91   }
    92   explicit nsTHashtable(uint32_t aInitSize)
    93   {
    94     Init(aInitSize);
    95   }
    97   /**
    98    * destructor, cleans up and deallocates
    99    */
   100   ~nsTHashtable();
   102   nsTHashtable(nsTHashtable<EntryType>&& aOther);
   104   /**
   105    * Return the generation number for the table. This increments whenever
   106    * the table data items are moved.
   107    */
   108   uint32_t GetGeneration() const { return mTable.generation; }
   110   /**
   111    * KeyType is typedef'ed for ease of use.
   112    */
   113   typedef typename EntryType::KeyType KeyType;
   115   /**
   116    * KeyTypePointer is typedef'ed for ease of use.
   117    */
   118   typedef typename EntryType::KeyTypePointer KeyTypePointer;
   120   /**
   121    * Return the number of entries in the table.
   122    * @return    number of entries
   123    */
   124   uint32_t Count() const { return mTable.entryCount; }
   126   /**
   127    * Get the entry associated with a key.
   128    * @param     aKey the key to retrieve
   129    * @return    pointer to the entry class, if the key exists; nullptr if the
   130    *            key doesn't exist
   131    */
   132   EntryType* GetEntry(KeyType aKey) const
   133   {
   134     NS_ASSERTION(mTable.entrySize, "nsTHashtable was not initialized properly.");
   136     EntryType* entry =
   137       reinterpret_cast<EntryType*>
   138                       (PL_DHashTableOperate(
   139                             const_cast<PLDHashTable*>(&mTable),
   140                             EntryType::KeyToPointer(aKey),
   141                             PL_DHASH_LOOKUP));
   142     return PL_DHASH_ENTRY_IS_BUSY(entry) ? entry : nullptr;
   143   }
   145   /**
   146    * Return true if an entry for the given key exists, false otherwise.
   147    * @param     aKey the key to retrieve
   148    * @return    true if the key exists, false if the key doesn't exist
   149    */
   150   bool Contains(KeyType aKey) const
   151   {
   152     return !!GetEntry(aKey);
   153   }
   155   /**
   156    * Get the entry associated with a key, or create a new entry,
   157    * @param     aKey the key to retrieve
   158    * @return    pointer to the entry class retreived; nullptr only if memory
   159                 can't be allocated
   160    */
   161   EntryType* PutEntry(KeyType aKey)
   162   {
   163     EntryType* e = PutEntry(aKey, fallible_t());
   164     if (!e)
   165       NS_ABORT_OOM(mTable.entrySize * mTable.entryCount);
   166     return e;
   167   }
   169   EntryType* PutEntry(KeyType aKey, const fallible_t&) NS_WARN_UNUSED_RESULT
   170   {
   171     NS_ASSERTION(mTable.entrySize, "nsTHashtable was not initialized properly.");
   173     return static_cast<EntryType*>
   174                       (PL_DHashTableOperate(
   175                             &mTable,
   176                             EntryType::KeyToPointer(aKey),
   177                             PL_DHASH_ADD));
   178   }
   180   /**
   181    * Remove the entry associated with a key.
   182    * @param     aKey of the entry to remove
   183    */
   184   void RemoveEntry(KeyType aKey)
   185   {
   186     NS_ASSERTION(mTable.entrySize, "nsTHashtable was not initialized properly.");
   188     PL_DHashTableOperate(&mTable,
   189                          EntryType::KeyToPointer(aKey),
   190                          PL_DHASH_REMOVE);
   191   }
   193   /**
   194    * Remove the entry associated with a key, but don't resize the hashtable.
   195    * This is a low-level method, and is not recommended unless you know what
   196    * you're doing and you need the extra performance. This method can be used
   197    * during enumeration, while RemoveEntry() cannot.
   198    * @param aEntry   the entry-pointer to remove (obtained from GetEntry or
   199    *                 the enumerator
   200    */
   201   void RawRemoveEntry(EntryType* aEntry)
   202   {
   203     PL_DHashTableRawRemove(&mTable, aEntry);
   204   }
   206   /**
   207    * client must provide an <code>Enumerator</code> function for
   208    *   EnumerateEntries
   209    * @param     aEntry the entry being enumerated
   210    * @param     userArg passed unchanged from <code>EnumerateEntries</code>
   211    * @return    combination of flags
   212    *            @link PLDHashOperator::PL_DHASH_NEXT PL_DHASH_NEXT @endlink ,
   213    *            @link PLDHashOperator::PL_DHASH_STOP PL_DHASH_STOP @endlink ,
   214    *            @link PLDHashOperator::PL_DHASH_REMOVE PL_DHASH_REMOVE @endlink
   215    */
   216   typedef PLDHashOperator (* Enumerator)(EntryType* aEntry, void* userArg);
   218   /**
   219    * Enumerate all the entries of the function.
   220    * @param     enumFunc the <code>Enumerator</code> function to call
   221    * @param     userArg a pointer to pass to the
   222    *            <code>Enumerator</code> function
   223    * @return    the number of entries actually enumerated
   224    */
   225   uint32_t EnumerateEntries(Enumerator enumFunc, void* userArg)
   226   {
   227     NS_ASSERTION(mTable.entrySize, "nsTHashtable was not initialized properly.");
   229     s_EnumArgs args = { enumFunc, userArg };
   230     return PL_DHashTableEnumerate(&mTable, s_EnumStub, &args);
   231   }
   233   /**
   234    * remove all entries, return hashtable to "pristine" state ;)
   235    */
   236   void Clear()
   237   {
   238     NS_ASSERTION(mTable.entrySize, "nsTHashtable was not initialized properly.");
   240     PL_DHashTableEnumerate(&mTable, PL_DHashStubEnumRemove, nullptr);
   241   }
   243   /**
   244    * client must provide a <code>SizeOfEntryExcludingThisFun</code> function for
   245    *   SizeOfExcludingThis.
   246    * @param     aEntry the entry being enumerated
   247    * @param     mallocSizeOf the function used to measure heap-allocated blocks
   248    * @param     arg passed unchanged from <code>SizeOf{In,Ex}cludingThis</code>
   249    * @return    summed size of the things pointed to by the entries
   250    */
   251   typedef size_t (* SizeOfEntryExcludingThisFun)(EntryType* aEntry,
   252                                                  mozilla::MallocSizeOf mallocSizeOf,
   253                                                  void *arg);
   255   /**
   256    * Measure the size of the table's entry storage, and if
   257    * |sizeOfEntryExcludingThis| is non-nullptr, measure the size of things
   258    * pointed to by entries.
   259    * 
   260    * @param     sizeOfEntryExcludingThis the
   261    *            <code>SizeOfEntryExcludingThisFun</code> function to call
   262    * @param     mallocSizeOf the function used to measure heap-allocated blocks
   263    * @param     userArg a pointer to pass to the
   264    *            <code>SizeOfEntryExcludingThisFun</code> function
   265    * @return    the summed size of all the entries
   266    */
   267   size_t SizeOfExcludingThis(SizeOfEntryExcludingThisFun sizeOfEntryExcludingThis,
   268                              mozilla::MallocSizeOf mallocSizeOf,
   269                              void *userArg = nullptr) const
   270   {
   271     if (sizeOfEntryExcludingThis) {
   272       s_SizeOfArgs args = { sizeOfEntryExcludingThis, userArg };
   273       return PL_DHashTableSizeOfExcludingThis(&mTable, s_SizeOfStub, mallocSizeOf, &args);
   274     }
   275     return PL_DHashTableSizeOfExcludingThis(&mTable, nullptr, mallocSizeOf);
   276   }
   278 #ifdef DEBUG
   279   /**
   280    * Mark the table as constant after initialization.
   281    *
   282    * This will prevent assertions when a read-only hash is accessed on multiple
   283    * threads without synchronization.
   284    */
   285   void MarkImmutable()
   286   {
   287     NS_ASSERTION(mTable.entrySize, "nsTHashtable was not initialized properly.");
   289     PL_DHashMarkTableImmutable(&mTable);
   290   }
   291 #endif
   293 protected:
   294   PLDHashTable mTable;
   296   static const void* s_GetKey(PLDHashTable    *table,
   297                               PLDHashEntryHdr *entry);
   299   static PLDHashNumber s_HashKey(PLDHashTable *table,
   300                                  const void   *key);
   302   static bool s_MatchEntry(PLDHashTable           *table,
   303                              const PLDHashEntryHdr  *entry,
   304                              const void             *key);
   306   static void s_CopyEntry(PLDHashTable          *table,
   307                           const PLDHashEntryHdr *from,
   308                           PLDHashEntryHdr       *to);
   310   static void s_ClearEntry(PLDHashTable *table,
   311                            PLDHashEntryHdr *entry);
   313   static bool s_InitEntry(PLDHashTable     *table,
   314                             PLDHashEntryHdr  *entry,
   315                             const void       *key);
   317   /**
   318    * passed internally during enumeration.  Allocated on the stack.
   319    *
   320    * @param userFunc the Enumerator function passed to
   321    *   EnumerateEntries by the client
   322    * @param userArg the userArg passed unaltered
   323    */
   324   struct s_EnumArgs
   325   {
   326     Enumerator userFunc;
   327     void* userArg;
   328   };
   330   static PLDHashOperator s_EnumStub(PLDHashTable    *table,
   331                                     PLDHashEntryHdr *entry,
   332                                     uint32_t         number,
   333                                     void            *arg);
   335   /**
   336    * passed internally during sizeOf counting.  Allocated on the stack.
   337    *
   338    * @param userFunc the SizeOfEntryExcludingThisFun passed to
   339    *                 SizeOf{In,Ex}cludingThis by the client
   340    * @param userArg the userArg passed unaltered
   341    */
   342   struct s_SizeOfArgs
   343   {
   344     SizeOfEntryExcludingThisFun userFunc;
   345     void* userArg;
   346   };
   348   static size_t s_SizeOfStub(PLDHashEntryHdr *entry,
   349                              mozilla::MallocSizeOf mallocSizeOf,
   350                              void *arg);
   352 private:
   353   // copy constructor, not implemented
   354   nsTHashtable(nsTHashtable<EntryType>& toCopy) MOZ_DELETE;
   356   /**
   357    * Initialize the table.
   358    * @param initSize the initial number of buckets in the hashtable
   359    */
   360   void Init(uint32_t aInitSize);
   362   // assignment operator, not implemented
   363   nsTHashtable<EntryType>& operator= (nsTHashtable<EntryType>& toEqual) MOZ_DELETE;
   364 };
   366 //
   367 // template definitions
   368 //
   370 template<class EntryType>
   371 nsTHashtable<EntryType>::nsTHashtable(
   372   nsTHashtable<EntryType>&& aOther)
   373   : mTable(mozilla::Move(aOther.mTable))
   374 {
   375   // aOther shouldn't touch mTable after this, because we've stolen the table's
   376   // pointers but not overwitten them.
   377   MOZ_MAKE_MEM_UNDEFINED(&aOther.mTable, sizeof(aOther.mTable));
   379   // Indicate that aOther is not initialized.  This will make its destructor a
   380   // nop, which is what we want.
   381   aOther.mTable.entrySize = 0;
   382 }
   384 template<class EntryType>
   385 nsTHashtable<EntryType>::~nsTHashtable()
   386 {
   387   if (mTable.entrySize)
   388     PL_DHashTableFinish(&mTable);
   389 }
   391 template<class EntryType>
   392 void
   393 nsTHashtable<EntryType>::Init(uint32_t aInitSize)
   394 {
   395   static const PLDHashTableOps sOps =
   396   {
   397     ::PL_DHashAllocTable,
   398     ::PL_DHashFreeTable,
   399     s_HashKey,
   400     s_MatchEntry,
   401     EntryType::ALLOW_MEMMOVE ? ::PL_DHashMoveEntryStub : s_CopyEntry,
   402     s_ClearEntry,
   403     ::PL_DHashFinalizeStub,
   404     s_InitEntry
   405   };
   407   PL_DHashTableInit(&mTable, &sOps, nullptr, sizeof(EntryType), aInitSize);
   408 }
   410 // static definitions
   412 template<class EntryType>
   413 PLDHashNumber
   414 nsTHashtable<EntryType>::s_HashKey(PLDHashTable  *table,
   415                                    const void    *key)
   416 {
   417   return EntryType::HashKey(reinterpret_cast<const KeyTypePointer>(key));
   418 }
   420 template<class EntryType>
   421 bool
   422 nsTHashtable<EntryType>::s_MatchEntry(PLDHashTable          *table,
   423                                       const PLDHashEntryHdr *entry,
   424                                       const void            *key)
   425 {
   426   return ((const EntryType*) entry)->KeyEquals(
   427     reinterpret_cast<const KeyTypePointer>(key));
   428 }
   430 template<class EntryType>
   431 void
   432 nsTHashtable<EntryType>::s_CopyEntry(PLDHashTable          *table,
   433                                      const PLDHashEntryHdr *from,
   434                                      PLDHashEntryHdr       *to)
   435 {
   436   EntryType* fromEntry =
   437     const_cast<EntryType*>(reinterpret_cast<const EntryType*>(from));
   439   new(to) EntryType(mozilla::Move(*fromEntry));
   441   fromEntry->~EntryType();
   442 }
   444 template<class EntryType>
   445 void
   446 nsTHashtable<EntryType>::s_ClearEntry(PLDHashTable    *table,
   447                                       PLDHashEntryHdr *entry)
   448 {
   449   reinterpret_cast<EntryType*>(entry)->~EntryType();
   450 }
   452 template<class EntryType>
   453 bool
   454 nsTHashtable<EntryType>::s_InitEntry(PLDHashTable    *table,
   455                                      PLDHashEntryHdr *entry,
   456                                      const void      *key)
   457 {
   458   new(entry) EntryType(reinterpret_cast<KeyTypePointer>(key));
   459   return true;
   460 }
   462 template<class EntryType>
   463 PLDHashOperator
   464 nsTHashtable<EntryType>::s_EnumStub(PLDHashTable    *table,
   465                                     PLDHashEntryHdr *entry,
   466                                     uint32_t         number,
   467                                     void            *arg)
   468 {
   469   // dereferences the function-pointer to the user's enumeration function
   470   return (* reinterpret_cast<s_EnumArgs*>(arg)->userFunc)(
   471     reinterpret_cast<EntryType*>(entry),
   472     reinterpret_cast<s_EnumArgs*>(arg)->userArg);
   473 }
   475 template<class EntryType>
   476 size_t
   477 nsTHashtable<EntryType>::s_SizeOfStub(PLDHashEntryHdr *entry,
   478                                       mozilla::MallocSizeOf mallocSizeOf,
   479                                       void *arg)
   480 {
   481   // dereferences the function-pointer to the user's enumeration function
   482   return (* reinterpret_cast<s_SizeOfArgs*>(arg)->userFunc)(
   483     reinterpret_cast<EntryType*>(entry),
   484     mallocSizeOf,
   485     reinterpret_cast<s_SizeOfArgs*>(arg)->userArg);
   486 }
   488 class nsCycleCollectionTraversalCallback;
   490 struct MOZ_STACK_CLASS nsTHashtableCCTraversalData
   491 {
   492   nsTHashtableCCTraversalData(nsCycleCollectionTraversalCallback& aCallback,
   493                               const char* aName,
   494                               uint32_t aFlags)
   495   : mCallback(aCallback),
   496     mName(aName),
   497     mFlags(aFlags)
   498   {
   499   }
   501   nsCycleCollectionTraversalCallback& mCallback;
   502   const char* mName;
   503   uint32_t mFlags;
   504 };
   506 template <class EntryType>
   507 PLDHashOperator
   508 ImplCycleCollectionTraverse_EnumFunc(EntryType *aEntry,
   509                                      void* aUserData)
   510 {
   511   auto userData = static_cast<nsTHashtableCCTraversalData*>(aUserData);
   513   ImplCycleCollectionTraverse(userData->mCallback,
   514                               *aEntry,
   515                               userData->mName,
   516                               userData->mFlags);
   517   return PL_DHASH_NEXT;
   518 }
   520 template <class EntryType>
   521 inline void
   522 ImplCycleCollectionUnlink(nsTHashtable<EntryType>& aField)
   523 {
   524   aField.Clear();
   525 }
   527 template <class EntryType>
   528 inline void
   529 ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback,
   530                             nsTHashtable<EntryType>& aField,
   531                             const char* aName,
   532                             uint32_t aFlags = 0)
   533 {
   534   nsTHashtableCCTraversalData userData(aCallback, aName, aFlags);
   536   aField.EnumerateEntries(ImplCycleCollectionTraverse_EnumFunc<EntryType>,
   537                           &userData);
   538 }
   540 #endif // nsTHashtable_h__

mercurial