Index: third_party/WebKit/Source/wtf/HashTable.h |
diff --git a/third_party/WebKit/Source/wtf/HashTable.h b/third_party/WebKit/Source/wtf/HashTable.h |
index 9d6449ac4ae99ca3b05bc7daba4d33076335941d..2afcfba70189a2ce23dcbd70bc11168a516c8317 100644 |
--- a/third_party/WebKit/Source/wtf/HashTable.h |
+++ b/third_party/WebKit/Source/wtf/HashTable.h |
@@ -42,26 +42,28 @@ |
#if DUMP_HASHTABLE_STATS_PER_TABLE |
#include "wtf/DataLog.h" |
+#include <type_traits> |
#endif |
#if DUMP_HASHTABLE_STATS |
#if DUMP_HASHTABLE_STATS_PER_TABLE |
-#define UPDATE_PROBE_COUNTS() \ |
- ++probeCount; \ |
- HashTableStats::recordCollisionAtCount(probeCount); \ |
- ++perTableProbeCount; \ |
+ |
+#define UPDATE_PROBE_COUNTS() \ |
+ ++probeCount; \ |
+ HashTableStats::instance().recordCollisionAtCount(probeCount); \ |
+ ++perTableProbeCount; \ |
m_stats->recordCollisionAtCount(perTableProbeCount) |
-#define UPDATE_ACCESS_COUNTS() \ |
- atomicIncrement(&HashTableStats::numAccesses); \ |
- int probeCount = 0; \ |
- ++m_stats->numAccesses; \ |
+#define UPDATE_ACCESS_COUNTS() \ |
+ atomicIncrement(&HashTableStats::instance().numAccesses); \ |
+ int probeCount = 0; \ |
+ ++m_stats->numAccesses; \ |
int perTableProbeCount = 0 |
#else |
#define UPDATE_PROBE_COUNTS() \ |
++probeCount; \ |
- HashTableStats::recordCollisionAtCount(probeCount) |
-#define UPDATE_ACCESS_COUNTS() \ |
- atomicIncrement(&HashTableStats::numAccesses); \ |
+ HashTableStats::instance().recordCollisionAtCount(probeCount) |
+#define UPDATE_ACCESS_COUNTS() \ |
+ atomicIncrement(&HashTableStats::instance().numAccesses); \ |
int probeCount = 0 |
#endif |
#else |
@@ -85,25 +87,92 @@ |
namespace WTF { |
#if DUMP_HASHTABLE_STATS |
- |
struct WTF_EXPORT HashTableStats { |
- STATIC_ONLY(HashTableStats); |
+ HashTableStats() |
+ : numAccesses(0), |
+ numRehashes(0), |
+ numRemoves(0), |
+ numReinserts(0), |
+ maxCollisions(0), |
+ numCollisions(0), |
+ collisionGraph() {} |
+ |
// The following variables are all atomically incremented when modified. |
- static int numAccesses; |
- static int numRehashes; |
- static int numRemoves; |
- static int numReinserts; |
+ int numAccesses; |
+ int numRehashes; |
+ int numRemoves; |
+ int numReinserts; |
// The following variables are only modified in the recordCollisionAtCount |
// method within a mutex. |
- static int maxCollisions; |
- static int numCollisions; |
- static int collisionGraph[4096]; |
+ int maxCollisions; |
+ int numCollisions; |
+ int collisionGraph[4096]; |
+ |
+ void copy(const HashTableStats* other); |
+ void recordCollisionAtCount(int count); |
+ void dumpStats(); |
+ |
+ static HashTableStats& instance(); |
+ |
+ template <typename VisitorDispatcher> |
+ void trace(VisitorDispatcher) {} |
+}; |
+ |
+#if DUMP_HASHTABLE_STATS_PER_TABLE |
+template <typename Allocator, bool isGCType = Allocator::isGarbageCollected> |
+class HashTableStatsPtr; |
- static void recordCollisionAtCount(int count); |
- static void dumpStats(); |
+template <typename Allocator> |
+class HashTableStatsPtr<Allocator, false> final { |
+ STATIC_ONLY(HashTableStatsPtr); |
+ |
+ public: |
+ static std::unique_ptr<HashTableStats> create() { |
+ return wrapUnique(new HashTableStats); |
+ } |
+ |
+ static std::unique_ptr<HashTableStats> copy( |
+ const std::unique_ptr<HashTableStats>& other) { |
+ if (!other) |
+ return nullptr; |
+ return wrapUnique(new HashTableStats(*other)); |
+ } |
+ |
+ static void swap(std::unique_ptr<HashTableStats>& stats, |
+ std::unique_ptr<HashTableStats>& other) { |
+ stats.swap(other); |
+ } |
}; |
+template <typename Allocator> |
+class HashTableStatsPtr<Allocator, true> final { |
+ STATIC_ONLY(HashTableStatsPtr); |
+ |
+ public: |
+ static HashTableStats* create() { |
+ // Resort to manually allocating this POD on the vector |
+ // backing heap, as blink::GarbageCollected<> isn't in scope |
+ // in WTF. |
+ void* storage = reinterpret_cast<void*>( |
+ Allocator::template allocateVectorBacking<unsigned char>( |
+ sizeof(HashTableStats))); |
+ return new (storage) HashTableStats; |
+ } |
+ |
+ static HashTableStats* copy(const HashTableStats* other) { |
+ if (!other) |
+ return nullptr; |
+ HashTableStats* obj = create(); |
+ obj->copy(other); |
+ return obj; |
+ } |
+ |
+ static void swap(HashTableStats*& stats, HashTableStats*& other) { |
+ std::swap(stats, other); |
+ } |
+}; |
+#endif |
#endif |
template <typename Key, |
@@ -596,55 +665,6 @@ class HashTable final |
typedef IdentityHashTranslator<HashFunctions> IdentityTranslatorType; |
typedef HashTableAddResult<HashTable, ValueType> AddResult; |
-#if DUMP_HASHTABLE_STATS_PER_TABLE |
- struct Stats { |
- DISALLOW_NEW(Stats); |
- Stats() |
- : numAccesses(0), |
- numRehashes(0), |
- numRemoves(0), |
- numReinserts(0), |
- maxCollisions(0), |
- numCollisions(0), |
- collisionGraph() {} |
- |
- int numAccesses; |
- int numRehashes; |
- int numRemoves; |
- int numReinserts; |
- |
- int maxCollisions; |
- int numCollisions; |
- int collisionGraph[4096]; |
- |
- void recordCollisionAtCount(int count) { |
- if (count > maxCollisions) |
- maxCollisions = count; |
- numCollisions++; |
- collisionGraph[count]++; |
- } |
- |
- void dumpStats() { |
- dataLogF("\nWTF::HashTable::Stats dump\n\n"); |
- dataLogF("%d accesses\n", numAccesses); |
- dataLogF("%d total collisions, average %.2f probes per access\n", |
- numCollisions, |
- 1.0 * (numAccesses + numCollisions) / numAccesses); |
- dataLogF("longest collision chain: %d\n", maxCollisions); |
- for (int i = 1; i <= maxCollisions; i++) { |
- dataLogF( |
- " %d lookups with exactly %d collisions (%.2f%% , %.2f%% with " |
- "this many or more)\n", |
- collisionGraph[i], i, |
- 100.0 * (collisionGraph[i] - collisionGraph[i + 1]) / numAccesses, |
- 100.0 * collisionGraph[i] / numAccesses); |
- } |
- dataLogF("%d rehashes\n", numRehashes); |
- dataLogF("%d reinserts\n", numReinserts); |
- } |
- }; |
-#endif |
- |
HashTable(); |
void finalize() { |
ASSERT(!Allocator::isGarbageCollected); |
@@ -860,7 +880,10 @@ class HashTable final |
#if DUMP_HASHTABLE_STATS_PER_TABLE |
public: |
- mutable std::unique_ptr<Stats> m_stats; |
+ mutable |
+ typename std::conditional<Allocator::isGarbageCollected, |
+ HashTableStats*, |
+ std::unique_ptr<HashTableStats>>::type m_stats; |
#endif |
template <WeakHandlingFlag x, |
@@ -902,7 +925,7 @@ inline HashTable<Key, |
#endif |
#if DUMP_HASHTABLE_STATS_PER_TABLE |
, |
- m_stats(wrapUnique(new Stats)) |
+ m_stats(nullptr) |
#endif |
{ |
static_assert(Allocator::isGarbageCollected || |
@@ -1330,7 +1353,7 @@ HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, Allocator>:: |
ASSERT( |
!isDeletedBucket(*(lookupForWriting(Extractor::extract(entry)).first))); |
#if DUMP_HASHTABLE_STATS |
- atomicIncrement(&HashTableStats::numReinserts); |
+ atomicIncrement(&HashTableStats::instance().numReinserts); |
#endif |
#if DUMP_HASHTABLE_STATS_PER_TABLE |
++m_stats->numReinserts; |
@@ -1425,7 +1448,7 @@ void HashTable<Key, |
Allocator>::remove(ValueType* pos) { |
registerModification(); |
#if DUMP_HASHTABLE_STATS |
- atomicIncrement(&HashTableStats::numRemoves); |
+ atomicIncrement(&HashTableStats::instance().numRemoves); |
#endif |
#if DUMP_HASHTABLE_STATS_PER_TABLE |
++m_stats->numRemoves; |
@@ -1666,7 +1689,7 @@ HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, Allocator>:: |
#if DUMP_HASHTABLE_STATS |
if (oldTableSize != 0) |
- atomicIncrement(&HashTableStats::numRehashes); |
+ atomicIncrement(&HashTableStats::instance().numRehashes); |
#endif |
#if DUMP_HASHTABLE_STATS_PER_TABLE |
@@ -1692,6 +1715,11 @@ HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, Allocator>:: |
m_deletedCount = 0; |
+#if DUMP_HASHTABLE_STATS_PER_TABLE |
+ if (!m_stats) |
+ m_stats = HashTableStatsPtr<Allocator>::create(); |
+#endif |
+ |
return newEntry; |
} |
@@ -1710,7 +1738,7 @@ HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, Allocator>:: |
#if DUMP_HASHTABLE_STATS |
if (oldTableSize != 0) |
- atomicIncrement(&HashTableStats::numRehashes); |
+ atomicIncrement(&HashTableStats::instance().numRehashes); |
#endif |
#if DUMP_HASHTABLE_STATS_PER_TABLE |
@@ -1795,7 +1823,7 @@ HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, Allocator>:: |
#endif |
#if DUMP_HASHTABLE_STATS_PER_TABLE |
, |
- m_stats(wrapUnique(new Stats(*other.m_stats))) |
+ m_stats(HashTableStatsPtr<Allocator>::copy(other.m_stats)) |
#endif |
{ |
// Copy the hash table the dumb way, by adding each element to the new |
@@ -1827,7 +1855,7 @@ HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, Allocator>:: |
#endif |
#if DUMP_HASHTABLE_STATS_PER_TABLE |
, |
- m_stats(wrapUnique(new Stats(*other.m_stats))) |
+ m_stats(HashTableStatsPtr<Allocator>::copy(other.m_stats)) |
#endif |
{ |
swap(other); |
@@ -1863,7 +1891,7 @@ void HashTable<Key, |
#endif |
#if DUMP_HASHTABLE_STATS_PER_TABLE |
- m_stats.swap(other.m_stats); |
+ HashTableStatsPtr<Allocator>::swap(m_stats, other.m_stats); |
#endif |
} |
@@ -2028,11 +2056,16 @@ void HashTable<Key, |
Traits, |
KeyTraits, |
Allocator>::trace(VisitorDispatcher visitor) { |
+#if DUMP_HASHTABLE_STATS_PER_TABLE |
+ Allocator::markNoTracing(visitor, m_stats); |
+#endif |
+ |
// If someone else already marked the backing and queued up the trace and/or |
// weak callback then we are done. This optimization does not happen for |
// ListHashSet since its iterator does not point at the backing. |
if (!m_table || Allocator::isHeapObjectAlive(m_table)) |
return; |
+ |
// Normally, we mark the backing store without performing trace. This means |
// it is marked live, but the pointers inside it are not marked. Instead we |
// will mark the pointers below. However, for backing stores that contain |