+2007-10-31 Maciej Stachowiak <mjs@apple.com>
+
+ Reviewed by ChangeLog.
+
+ - get rid of integer divide in PropertyMap and HashTable for 1% SunSpider speedup
+
+ Integer divide sucks. Fortunately, a bunch of shifts and XORs
+ biased towards the high bits is sufficient to provide a good
+ double hash. Besides the SunSpider win, I used the dump statistics
+ mode for both to verify that collisions did not increase and that
+ the longest collision chain is not any longer.
+
+ * kjs/property_map.cpp:
+ (KJS::doubleHash):
+ (KJS::PropertyMap::get):
+ (KJS::PropertyMap::getLocation):
+ (KJS::PropertyMap::put):
+ (KJS::PropertyMap::insert):
+ (KJS::PropertyMap::remove):
+ (KJS::PropertyMap::checkConsistency):
+ * wtf/HashTable.h:
+ (WTF::doubleHash):
+ (WTF::::lookup):
+ (WTF::::lookupForWriting):
+ (WTF::::fullLookupForWriting):
+ (WTF::::add):
+
2007-10-30 Adam Roben <aroben@apple.com>
Build fix
#include "object.h"
#include "protect.h"
#include "PropertyNameArray.h"
+#include "HashTable.h"
#include <algorithm>
#include <wtf/Assertions.h>
#include <wtf/FastMalloc.h>
#define DEBUG_PROPERTIES 0
#define DO_CONSISTENCY_CHECK 0
-#define DUMP_STATISTICS 0
+#define DUMP_PROPERTYMAP_STATS 0
#define USE_SINGLE_ENTRY 1
// 2/28/2006 ggaren: command-line JS iBench says that USE_SINGLE_ENTRY is a
// but it's not going to blow out the stack to allocate this number of pointers.
const int smallMapThreshold = 1024;
-#if DUMP_STATISTICS
+#if DUMP_PROPERTYMAP_STATS
static int numProbes;
static int numCollisions;
Entry *entries = m_u.table->entries;
int i = h & sizeMask;
int k = 0;
-#if DUMP_STATISTICS
+#if DUMP_PROPERTYMAP_STATS
++numProbes;
numCollisions += entries[i].key && entries[i].key != rep;
#endif
}
if (k == 0)
- k = 1 | (h % sizeMask);
+ k = 1 | doubleHash(h);
i = (i + k) & sizeMask;
-#if DUMP_STATISTICS
+#if DUMP_PROPERTYMAP_STATS
++numRehashes;
#endif
}
Entry *entries = m_u.table->entries;
int i = h & sizeMask;
int k = 0;
-#if DUMP_STATISTICS
+#if DUMP_PROPERTYMAP_STATS
++numProbes;
numCollisions += entries[i].key && entries[i].key != rep;
#endif
return entries[i].value;
if (k == 0)
- k = 1 | (h % sizeMask);
+ k = 1 | doubleHash(h);
i = (i + k) & sizeMask;
-#if DUMP_STATISTICS
+#if DUMP_PROPERTYMAP_STATS
++numRehashes;
#endif
}
Entry *entries = m_u.table->entries;
int i = h & sizeMask;
int k = 0;
-#if DUMP_STATISTICS
+#if DUMP_PROPERTYMAP_STATS
++numProbes;
numCollisions += entries[i].key && entries[i].key != rep;
#endif
return &entries[i].value;
if (k == 0)
- k = 1 | (h % sizeMask);
+ k = 1 | doubleHash(h);
i = (i + k) & sizeMask;
-#if DUMP_STATISTICS
+#if DUMP_PROPERTYMAP_STATS
++numRehashes;
#endif
}
int k = 0;
bool foundDeletedElement = false;
int deletedElementIndex = 0; /* initialize to make the compiler happy */
-#if DUMP_STATISTICS
+#if DUMP_PROPERTYMAP_STATS
++numProbes;
numCollisions += entries[i].key && entries[i].key != rep;
#endif
deletedElementIndex = i;
}
if (k == 0)
- k = 1 | (h % sizeMask);
+ k = 1 | doubleHash(h);
i = (i + k) & sizeMask;
-#if DUMP_STATISTICS
+#if DUMP_PROPERTYMAP_STATS
++numRehashes;
#endif
}
Entry *entries = m_u.table->entries;
int i = h & sizeMask;
int k = 0;
-#if DUMP_STATISTICS
+#if DUMP_PROPERTYMAP_STATS
++numProbes;
numCollisions += entries[i].key && entries[i].key != key;
#endif
while (entries[i].key) {
ASSERT(entries[i].key != deletedSentinel());
if (k == 0)
- k = 1 | (h % sizeMask);
+ k = 1 | doubleHash(h);
i = (i + k) & sizeMask;
-#if DUMP_STATISTICS
+#if DUMP_PROPERTYMAP_STATS
++numRehashes;
#endif
}
Entry *entries = m_u.table->entries;
int i = h & sizeMask;
int k = 0;
-#if DUMP_STATISTICS
+#if DUMP_PROPERTYMAP_STATS
++numProbes;
++numRemoves;
numCollisions += entries[i].key && entries[i].key != rep;
if (rep == key)
break;
if (k == 0)
- k = 1 | (h % sizeMask);
+ k = 1 | doubleHash(h);
i = (i + k) & sizeMask;
-#if DUMP_STATISTICS
+#if DUMP_PROPERTYMAP_STATS
++numRehashes;
#endif
}
if (rep == key)
break;
if (k == 0)
- k = 1 | (h % m_u.table->sizeMask);
+ k = 1 | doubleHash(h);
i = (i + k) & m_u.table->sizeMask;
}
ASSERT(i == j);
{
}
+ static inline unsigned doubleHash(unsigned key)
+ {
+ key = ~key + (key >> 23);
+ key ^= (key << 12);
+ key ^= (key >> 7);
+ key ^= (key << 2);
+ key ^= (key >> 20);
+ return key;
+ }
+
template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits>
template<typename T, typename HashTranslator>
inline Value* HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>::lookup(const T& key)
HashTableStats::recordCollisionAtCount(probeCount);
#endif
if (k == 0)
- k = 1 | (h % sizeMask);
+ k = 1 | doubleHash(h);
i = (i + k) & sizeMask;
}
}
HashTableStats::recordCollisionAtCount(probeCount);
#endif
if (k == 0)
- k = 1 | (h % sizeMask);
+ k = 1 | doubleHash(h);
i = (i + k) & sizeMask;
}
}
HashTableStats::recordCollisionAtCount(probeCount);
#endif
if (k == 0)
- k = 1 | (h % sizeMask);
+ k = 1 | doubleHash(h);
i = (i + k) & sizeMask;
}
}
HashTableStats::recordCollisionAtCount(probeCount);
#endif
if (k == 0)
- k = 1 | (h % sizeMask);
+ k = 1 | doubleHash(h);
i = (i + k) & sizeMask;
}