rts: Specialize hashing at call site rather than in struct.
authorCrazycolorz5 <Crazycolorz5@gmail.com>
Mon, 21 Jan 2019 00:26:58 +0000 (19:26 -0500)
committerMarge Bot <ben+marge-bot@smart-cactus.org>
Wed, 11 Dec 2019 19:12:17 +0000 (14:12 -0500)
Separate word and string hash tables on the type level, and do not store
the hashing function.  Thus when a different hash function is desire it
is provided upon accessing the table. This is worst case the same as
before the change, and in the majority of cases is better. Also mark the
functions for aggressive inlining to improve performance.  {F1686506}

Reviewers: bgamari, erikd, simonmar

Subscribers: rwbarton, thomie, carter

GHC Trac Issues: #13165

Differential Revision: https://phabricator.haskell.org/D4889

includes/HsFFI.h
libraries/base/GHC/StaticPtr.hs
rts/FileLock.c
rts/Hash.c
rts/Hash.h
rts/Hpc.c
rts/Linker.c
rts/LinkerInternals.h
rts/RtsSymbolInfo.c
rts/StaticPtrTable.c

index 32523b2..d021e6f 100644 (file)
@@ -126,7 +126,7 @@ extern void hs_free_stable_ptr_unsafe (HsStablePtr sp);
 extern void hs_free_stable_ptr (HsStablePtr sp);
 extern void hs_free_fun_ptr    (HsFunPtr fp);
 
-extern StgPtr hs_spt_lookup(StgWord64 key1, StgWord64 key2);
+extern StgPtr hs_spt_lookup(StgWord64 key[2]);
 extern int hs_spt_keys(StgPtr keys[], int szKeys);
 extern int hs_spt_key_count (void);
 
index ee5ba78..b8d5c11 100644 (file)
@@ -48,7 +48,7 @@ module GHC.StaticPtr
   ) where
 
 import Foreign.C.Types     (CInt(..))
-import Foreign.Marshal     (allocaArray, peekArray)
+import Foreign.Marshal     (allocaArray, peekArray, withArray)
 import GHC.Ptr             (Ptr(..), nullPtr)
 import GHC.Fingerprint     (Fingerprint(..))
 import GHC.Prim
@@ -87,13 +87,13 @@ staticKey (StaticPtr w0 w1 _ _) = Fingerprint (W64# w0) (W64# w1)
 --
 unsafeLookupStaticPtr :: StaticKey -> IO (Maybe (StaticPtr a))
 unsafeLookupStaticPtr (Fingerprint w1 w2) = do
-    ptr@(Ptr addr) <- hs_spt_lookup w1 w2
+    ptr@(Ptr addr) <- withArray [w1, w2] hs_spt_lookup
     if (ptr == nullPtr)
     then return Nothing
     else case addrToAny# addr of
            (# spe #) -> return (Just spe)
 
-foreign import ccall unsafe hs_spt_lookup :: Word64 -> Word64 -> IO (Ptr a)
+foreign import ccall unsafe hs_spt_lookup :: Ptr Word64 -> IO (Ptr a)
 
 -- | A class for things buildable from static pointers.
 class IsStatic p where
index ac21bea..351d2a5 100644 (file)
@@ -34,14 +34,14 @@ static HashTable *fd_hash;
 static Mutex file_lock_mutex;
 #endif
 
-static int cmpLocks(StgWord w1, StgWord w2)
+STATIC_INLINE int cmpLocks(StgWord w1, StgWord w2)
 {
     Lock *l1 = (Lock *)w1;
     Lock *l2 = (Lock *)w2;
     return (l1->device == l2->device && l1->inode == l2->inode);
 }
 
-static int hashLock(const HashTable *table, StgWord w)
+STATIC_INLINE int hashLock(const HashTable *table, StgWord w)
 {
     Lock *l = (Lock *)w;
     StgWord key = l->inode ^ (l->inode >> 32) ^ l->device ^ (l->device >> 32);
@@ -52,7 +52,7 @@ static int hashLock(const HashTable *table, StgWord w)
 void
 initFileLocking(void)
 {
-    obj_hash = allocHashTable_(hashLock, cmpLocks);
+    obj_hash = allocHashTable();
     fd_hash  = allocHashTable(); /* ordinary word-based table */
 #if defined(THREADED_RTS)
     initMutex(&file_lock_mutex);
@@ -85,7 +85,7 @@ lockFile(int fd, StgWord64 dev, StgWord64 ino, int for_writing)
     key.device = dev;
     key.inode  = ino;
 
-    lock = lookupHashTable(obj_hash, (StgWord)&key);
+    lock = lookupHashTable_(obj_hash, (StgWord)&key, hashLock, cmpLocks);
 
     if (lock == NULL)
     {
@@ -93,7 +93,7 @@ lockFile(int fd, StgWord64 dev, StgWord64 ino, int for_writing)
         lock->device = dev;
         lock->inode  = ino;
         lock->readers = for_writing ? -1 : 1;
-        insertHashTable(obj_hash, (StgWord)lock, (void *)lock);
+        insertHashTable_(obj_hash, (StgWord)lock, (void *)lock, hashLock);
         insertHashTable(fd_hash, fd, lock);
         RELEASE_LOCK(&file_lock_mutex);
         return 0;
@@ -135,7 +135,7 @@ unlockFile(int fd)
     }
 
     if (lock->readers == 0) {
-        removeHashTable(obj_hash, (StgWord)lock, NULL);
+        removeHashTable_(obj_hash, (StgWord)lock, NULL, hashLock, cmpLocks);
         stgFree(lock);
     }
     removeHashTable(fd_hash, fd, NULL);
index 2f611c9..4e11228 100644 (file)
@@ -49,22 +49,25 @@ struct hashtable {
     HashList **dir[HDIRSIZE];   /* Directory of segments */
     HashList *freeList;         /* free list of HashLists */
     HashListChunk *chunks;
-    HashFunction *hash;         /* hash function */
-    CompareFunction *compare;   /* key comparison function */
 };
 
+/* Create an identical structure, but is distinct on a type level,
+ * for string hash table. Since it's a direct embedding of
+ * a hashtable and not a reference, there shouldn't be
+ * any overhead post-compilation.  */
+struct strhashtable { struct hashtable table; };
+
 /* -----------------------------------------------------------------------------
  * Hash first using the smaller table.  If the bucket is less than the
  * next bucket to be split, re-hash using the larger table.
  * -------------------------------------------------------------------------- */
-
 int
 hashWord(const HashTable *table, StgWord key)
 {
     int bucket;
 
     /* Strip the boring zero bits */
-    key /= sizeof(StgWord);
+    key >>= sizeof(StgWord);
 
     /* Mod the size of the hash table (a power of 2) */
     bucket = key & table->mask1;
@@ -97,13 +100,13 @@ hashStr(const HashTable *table, StgWord w)
     return bucket;
 }
 
-static int
+STATIC_INLINE int
 compareWord(StgWord key1, StgWord key2)
 {
     return (key1 == key2);
 }
 
-static int
+STATIC_INLINE int
 compareStr(StgWord key1, StgWord key2)
 {
     return (strcmp((char *)key1, (char *)key2) == 0);
@@ -114,7 +117,7 @@ compareStr(StgWord key1, StgWord key2)
  * Allocate a new segment of the dynamically growing hash table.
  * -------------------------------------------------------------------------- */
 
-static void
+STATIC_INLINE void
 allocSegment(HashTable *table, int segment)
 {
     table->dir[segment] = stgMallocBytes(HSEGSIZE * sizeof(HashList *),
@@ -128,8 +131,8 @@ allocSegment(HashTable *table, int segment)
  * by @table->split@ is affected by the expansion.
  * -------------------------------------------------------------------------- */
 
-static void
-expand(HashTable *table)
+STATIC_INLINE void
+expand(HashTable *table, HashFunction f)
 {
     int oldsegment;
     int oldindex;
@@ -170,7 +173,7 @@ expand(HashTable *table)
     old = new = NULL;
     for (hl = table->dir[oldsegment][oldindex]; hl != NULL; hl = next) {
         next = hl->next;
-        if (table->hash(table, hl->key) == newbucket) {
+        if (f(table, hl->key) == newbucket) {
             hl->next = new;
             new = hl;
         } else {
@@ -184,19 +187,20 @@ expand(HashTable *table)
     return;
 }
 
-void *
-lookupHashTable(const HashTable *table, StgWord key)
+STATIC_INLINE void*
+lookupHashTable_inlined(const HashTable *table, StgWord key,
+                        HashFunction f, CompareFunction cmp)
 {
     int bucket;
     int segment;
     int index;
+
     HashList *hl;
 
-    bucket = table->hash(table, key);
+    bucket = f(table, key);
     segment = bucket / HSEGSIZE;
     index = bucket % HSEGSIZE;
 
-    CompareFunction *cmp = table->compare;
     for (hl = table->dir[segment][index]; hl != NULL; hl = hl->next) {
         if (cmp(hl->key, key))
             return (void *) hl->data;
@@ -206,6 +210,26 @@ lookupHashTable(const HashTable *table, StgWord key)
     return NULL;
 }
 
+void *
+lookupHashTable_(const HashTable *table, StgWord key,
+                 HashFunction f, CompareFunction cmp)
+{
+    return lookupHashTable_inlined(table, key, f, cmp);
+}
+
+void *
+lookupHashTable(const HashTable *table, StgWord key)
+{
+    return lookupHashTable_inlined(table, key, hashWord, compareWord);
+}
+
+void *
+lookupStrHashTable(const StrHashTable* table, const char* key)
+{
+    return lookupHashTable_inlined(&table->table, (StgWord) key,
+                                   hashStr, compareStr);
+}
+
 // Puts up to szKeys keys of the hash table into the given array. Returns the
 // actual amount of keys that have been retrieved.
 //
@@ -273,8 +297,9 @@ freeHashList (HashTable *table, HashList *hl)
     table->freeList = hl;
 }
 
-void
-insertHashTable(HashTable *table, StgWord key, const void *data)
+STATIC_INLINE void
+insertHashTable_inlined(HashTable *table, StgWord key,
+                        const void *data, HashFunction f)
 {
     int bucket;
     int segment;
@@ -287,9 +312,9 @@ insertHashTable(HashTable *table, StgWord key, const void *data)
 
     /* When the average load gets too high, we expand the table */
     if (++table->kcount >= HLOAD * table->bcount)
-        expand(table);
+        expand(table, f);
 
-    bucket = table->hash(table, key);
+    bucket = f(table, key);
     segment = bucket / HSEGSIZE;
     index = bucket % HSEGSIZE;
 
@@ -299,11 +324,30 @@ insertHashTable(HashTable *table, StgWord key, const void *data)
     hl->data = data;
     hl->next = table->dir[segment][index];
     table->dir[segment][index] = hl;
+}
 
+void
+insertHashTable_(HashTable *table, StgWord key,
+                 const void *data, HashFunction f)
+{
+    return insertHashTable_inlined(table, key, data, f);
 }
 
-void *
-removeHashTable(HashTable *table, StgWord key, const void *data)
+void
+insertHashTable(HashTable *table, StgWord key, const void *data)
+{
+    insertHashTable_inlined(table, key, data, hashWord);
+}
+
+void
+insertStrHashTable(StrHashTable *table, const char * key, const void *data)
+{
+    insertHashTable_inlined(&table->table, (StgWord) key, data, hashStr);
+}
+
+STATIC_INLINE void*
+removeHashTable_inlined(HashTable *table, StgWord key, const void *data,
+                        HashFunction f, CompareFunction cmp)
 {
     int bucket;
     int segment;
@@ -311,12 +355,12 @@ removeHashTable(HashTable *table, StgWord key, const void *data)
     HashList *hl;
     HashList *prev = NULL;
 
-    bucket = table->hash(table, key);
+    bucket = f(table, key);
     segment = bucket / HSEGSIZE;
     index = bucket % HSEGSIZE;
 
     for (hl = table->dir[segment][index]; hl != NULL; hl = hl->next) {
-        if (table->compare(hl->key,key) && (data == NULL || hl->data == data)) {
+        if (cmp(hl->key, key) && (data == NULL || hl->data == data)) {
             if (prev == NULL)
                 table->dir[segment][index] = hl->next;
             else
@@ -333,6 +377,26 @@ removeHashTable(HashTable *table, StgWord key, const void *data)
     return NULL;
 }
 
+void*
+removeHashTable_(HashTable *table, StgWord key, const void *data,
+                 HashFunction f, CompareFunction cmp)
+{
+    return removeHashTable_inlined(table, key, data, f, cmp);
+}
+
+void *
+removeHashTable(HashTable *table, StgWord key, const void *data)
+{
+    return removeHashTable_inlined(table, key, data, hashWord, compareWord);
+}
+
+void *
+removeStrHashTable(StrHashTable *table, const char * key, const void *data)
+{
+    return removeHashTable_inlined(&table->table, (StgWord) key,
+                                   data, hashStr, compareStr);
+}
+
 /* -----------------------------------------------------------------------------
  * When we free a hash table, we are also good enough to free the
  * data part of each (key, data) pair, as long as our caller can tell
@@ -406,7 +470,7 @@ mapHashTable(HashTable *table, void *data, MapHashFn fn)
  * -------------------------------------------------------------------------- */
 
 HashTable *
-allocHashTable_(HashFunction *hash, CompareFunction *compare)
+allocHashTable(void)
 {
     HashTable *table;
     HashList **hb;
@@ -426,24 +490,10 @@ allocHashTable_(HashFunction *hash, CompareFunction *compare)
     table->bcount = HSEGSIZE;
     table->freeList = NULL;
     table->chunks = NULL;
-    table->hash = hash;
-    table->compare = compare;
 
     return table;
 }
 
-HashTable *
-allocHashTable(void)
-{
-    return allocHashTable_(hashWord, compareWord);
-}
-
-HashTable *
-allocStrHashTable(void)
-{
-    return allocHashTable_(hashStr, compareStr);
-}
-
 void
 exitHashTable(void)
 {
index be388fb..59e2e22 100644 (file)
@@ -11,6 +11,7 @@
 #include "BeginPrivate.h"
 
 typedef struct hashtable HashTable; /* abstract */
+typedef struct strhashtable StrHashTable;
 
 /* Hash table access where the keys are StgWords.
  * Values are passed into the hash table and stored as `const void *` values,
@@ -40,27 +41,44 @@ void mapHashTable(HashTable *table, void *data, MapHashFn fn);
  * assumed to be allocated by the caller, and mustn't be deallocated
  * until the corresponding hash table entry has been removed).
  */
-HashTable * allocStrHashTable ( void );
-
-#define lookupStrHashTable(table, key)  \
-   (lookupHashTable(table, (StgWord)key))
-
-#define insertStrHashTable(table, key, data)  \
-   (insertHashTable(table, (StgWord)key, data))
-
-#define removeStrHashTable(table, key, data) \
-   (removeHashTable(table, (StgWord)key, data))
-
-/* Hash tables for arbitrary keys */
+INLINE_HEADER StrHashTable * allocStrHashTable ( void )
+{
+    return (StrHashTable*) allocHashTable();
+}
+
+void        insertStrHashTable ( StrHashTable *table, const char * key,
+                                 const void *data );
+void *      lookupStrHashTable ( const StrHashTable *table, const char * key);
+void *      removeStrHashTable ( StrHashTable *table, const char * key,
+                                 const void *data );
+
+/*
+ * Hash tables for arbitrary key types.
+ * Generally, these functions allow for the specification of the
+ * HashFunction and CompareFunction. It's recommended that those
+ * are inlinable so there's a chance the compiler can discard
+ * some parameter-passing, as well as function calls, though note
+ * it's not guaranteed. Either way, the functions are parameters
+ * as the types should be statically known and thus
+ * storing them is unnecessary.
+ */
 typedef int HashFunction(const HashTable *table, StgWord key);
 typedef int CompareFunction(StgWord key1, StgWord key2);
-HashTable * allocHashTable_(HashFunction *hash, CompareFunction *compare);
 int hashWord(const HashTable *table, StgWord key);
-int hashStr(const HashTable *table, StgWord key);
+int hashStr(const HashTable *table, StgWord w);
+void        insertHashTable_ ( HashTable *table, StgWord key,
+                               const void *data, HashFunction f );
+void *      lookupHashTable_ ( const HashTable *table, StgWord key,
+                               HashFunction f, CompareFunction cmp );
+void *      removeHashTable_ ( HashTable *table, StgWord key,
+                               const void *data, HashFunction f,
+                               CompareFunction cmp );
 
 /* Freeing hash tables
  */
 void freeHashTable ( HashTable *table, void (*freeDataFun)(void *) );
+#define freeStrHashTable(table, f) \
+    (freeHashTable((HashTable*) table, f))
 
 void exitHashTable ( void );
 
index 52a8333..37df56b 100644 (file)
--- a/rts/Hpc.c
+++ b/rts/Hpc.c
@@ -39,7 +39,7 @@ static pid_t hpc_pid = 0;               // pid of this process at hpc-boot time.
 static FILE *tixFile;                   // file being read/written
 static int tix_ch;                      // current char
 
-static HashTable * moduleHash = NULL;   // module name -> HpcModuleInfo
+static StrHashTable * moduleHash = NULL;   // module name -> HpcModuleInfo
 
 HpcModuleInfo *modules = 0;
 
@@ -152,11 +152,11 @@ readTix(void) {
     expect(']');
     ws();
 
-    lookup = lookupHashTable(moduleHash, (StgWord)tmpModule->modName);
+    lookup = lookupStrHashTable(moduleHash, tmpModule->modName);
     if (lookup == NULL) {
         debugTrace(DEBUG_hpc,"readTix: new HpcModuleInfo for %s",
                    tmpModule->modName);
-        insertHashTable(moduleHash, (StgWord)tmpModule->modName, tmpModule);
+        insertStrHashTable(moduleHash, tmpModule->modName, tmpModule);
     } else {
         ASSERT(lookup->tixArr != 0);
         ASSERT(!strcmp(tmpModule->modName, lookup->modName));
@@ -265,7 +265,7 @@ hs_hpc_module(char *modName,
       moduleHash = allocStrHashTable();
   }
 
-  tmpModule = lookupHashTable(moduleHash, (StgWord)modName);
+  tmpModule = lookupStrHashTable(moduleHash, modName);
   if (tmpModule == NULL)
   {
       // Did not find entry so add one on.
@@ -282,7 +282,7 @@ hs_hpc_module(char *modName,
       tmpModule->next = modules;
       tmpModule->from_file = false;
       modules = tmpModule;
-      insertHashTable(moduleHash, (StgWord)modName, tmpModule);
+      insertStrHashTable(moduleHash, modName, tmpModule);
   }
   else
   {
@@ -392,7 +392,7 @@ exitHpc(void) {
     writeTix(f);
   }
 
-  freeHashTable(moduleHash, (void (*)(void *))freeHpcModuleInfo);
+  freeStrHashTable(moduleHash, (void (*)(void *))freeHpcModuleInfo);
   moduleHash = NULL;
 
   stgFree(tixFilename);
index 7bd2e67..3539f90 100644 (file)
    2) The number of duplicate symbols, since now only symbols that are
       true duplicates will display the error.
  */
-/*Str*/HashTable *symhash;
+StrHashTable *symhash;
 
 /* List of currently loaded objects */
 ObjectCode *objects = NULL;     /* initially empty */
@@ -227,7 +227,7 @@ int ocTryLoad( ObjectCode* oc );
 
 static void *mmap_32bit_base = (void *)MMAP_32BIT_BASE_DEFAULT;
 
-static void ghciRemoveSymbolTable(HashTable *table, const SymbolName* key,
+static void ghciRemoveSymbolTable(StrHashTable *table, const SymbolName* key,
     ObjectCode *owner)
 {
     RtsSymbolInfo *pinfo = lookupStrHashTable(table, key);
@@ -262,7 +262,7 @@ static void ghciRemoveSymbolTable(HashTable *table, const SymbolName* key,
  */
 int ghciInsertSymbolTable(
    pathchar* obj_name,
-   HashTable *table,
+   StrHashTable *table,
    const SymbolName* key,
    SymbolAddr* data,
    HsBool weak,
@@ -373,7 +373,7 @@ int ghciInsertSymbolTable(
 * Returns: 0 on failure and result is not set,
 *          nonzero on success and result set to nonzero pointer
 */
-HsBool ghciLookupSymbolInfo(HashTable *table,
+HsBool ghciLookupSymbolInfo(StrHashTable *table,
     const SymbolName* key, RtsSymbolInfo **result)
 {
     RtsSymbolInfo *pinfo = lookupStrHashTable(table, key);
@@ -524,7 +524,7 @@ exitLinker( void ) {
    }
 #endif
    if (linker_init_done == 1) {
-       freeHashTable(symhash, free);
+       freeStrHashTable(symhash, free);
    }
 #if defined(THREADED_RTS)
    closeMutex(&linker_mutex);
@@ -1200,7 +1200,7 @@ void freeObjectCode (ObjectCode *oc)
     }
 
     if (oc->extraInfos != NULL) {
-        freeHashTable(oc->extraInfos, NULL);
+        freeStrHashTable(oc->extraInfos, NULL);
         oc->extraInfos = NULL;
     }
 
index 0f47b82..8a8df50 100644 (file)
@@ -243,7 +243,7 @@ typedef struct _ObjectCode {
 
     /* Holds the list of symbols in the .o file which
        require extra information.*/
-    HashTable *extraInfos;
+    StrHashTable *extraInfos;
 
 #if RTS_LINKER_USE_MMAP == 1
     /* The m32 allocators used for allocating small sections and symbol extras
@@ -304,12 +304,12 @@ void addSection (Section *s, SectionKind kind, SectionAlloc alloc,
                  void* start, StgWord size, StgWord mapped_offset,
                  void* mapped_start, StgWord mapped_size);
 
-HsBool ghciLookupSymbolInfo(HashTable *table,
+HsBool ghciLookupSymbolInfo(StrHashTable *table,
                             const SymbolName* key, RtsSymbolInfo **result);
 
 int ghciInsertSymbolTable(
     pathchar* obj_name,
-    HashTable *table,
+    StrHashTable *table,
     const SymbolName* key,
     SymbolAddr* data,
     HsBool weak,
@@ -318,7 +318,7 @@ int ghciInsertSymbolTable(
 /* lock-free version of lookupSymbol */
 SymbolAddr* lookupSymbol_ (SymbolName* lbl);
 
-extern /*Str*/HashTable *symhash;
+extern StrHashTable *symhash;
 
 pathchar*
 resolveSymbolAddr (pathchar* buffer, int size,
index 0553308..1110d58 100644 (file)
@@ -93,7 +93,7 @@ static void unmarkImport(SymbolInfo* info)
 /* -----------------------------------------------------------------------------
 * Marks the symbol at the given address as weak or not.
 * If the extra symbol infos table has not been initialized
-* yet this will create and allocate a new Hashtable
+* yet this will create and allocate a new StrHashtable
 */
 void setWeakSymbol(ObjectCode *owner, const void *label)
 {
@@ -103,7 +103,7 @@ void setWeakSymbol(ObjectCode *owner, const void *label)
 /* -----------------------------------------------------------------------------
 * Marks the symbol at the given address as import or not.
 * If the extra symbol infos table has not been initialized
-* yet this will create and allocate a new Hashtable
+* yet this will create and allocate a new StrHashtable
 */
 void setImportSymbol(ObjectCode *owner, const void *label)
 {
@@ -113,7 +113,7 @@ void setImportSymbol(ObjectCode *owner, const void *label)
 /* -----------------------------------------------------------------------------
 * Clear the import symbol flag.
 * If the extra symbol infos table has not been initialized
-* yet this will create and allocate a new Hashtable
+* yet this will create and allocate a new StrHashtable
 */
 void clearImportSymbol(ObjectCode *owner, const void *label)
 {
index f5e6239..9754cfa 100644 (file)
@@ -21,14 +21,14 @@ static Mutex spt_lock;
 #endif
 
 /// Hash function for the SPT.
-static int hashFingerprint(const HashTable *table, StgWord key) {
+STATIC_INLINE int hashFingerprint(const HashTable *table, StgWord key) {
   const StgWord64* ptr = (StgWord64*) key;
   // Take half of the key to compute the hash.
   return hashWord(table, *(ptr + 1));
 }
 
 /// Comparison function for the SPT.
-static int compareFingerprint(StgWord a, StgWord b) {
+STATIC_INLINE int compareFingerprint(StgWord a, StgWord b) {
   const StgWord64* ptra = (StgWord64*) a;
   const StgWord64* ptrb = (StgWord64*) b;
   return *ptra == *ptrb && *(ptra + 1) == *(ptrb + 1);
@@ -38,14 +38,14 @@ void hs_spt_insert_stableptr(StgWord64 key[2], StgStablePtr *entry) {
   // hs_spt_insert is called from constructor functions, so
   // the SPT needs to be initialized here.
   if (spt == NULL) {
-    spt = allocHashTable_(hashFingerprint, compareFingerprint);
+    spt = allocHashTable();
 #if defined(THREADED_RTS)
     initMutex(&spt_lock);
 #endif
   }
 
   ACQUIRE_LOCK(&spt_lock);
-  insertHashTable(spt, (StgWord)key, entry);
+  insertHashTable_(spt, (StgWord)key, entry, hashFingerprint);
   RELEASE_LOCK(&spt_lock);
 }
 
@@ -68,7 +68,8 @@ static void freeSptEntry(void* entry) {
 void hs_spt_remove(StgWord64 key[2]) {
    if (spt) {
      ACQUIRE_LOCK(&spt_lock);
-     StgStablePtr* entry = removeHashTable(spt, (StgWord)key, NULL);
+     StgStablePtr* entry = removeHashTable_(spt, (StgWord)key, NULL,
+        hashFingerprint, compareFingerprint);
      RELEASE_LOCK(&spt_lock);
 
      if (entry)
@@ -76,11 +77,11 @@ void hs_spt_remove(StgWord64 key[2]) {
    }
 }
 
-StgPtr hs_spt_lookup(StgWord64 key1, StgWord64 key2) {
+StgPtr hs_spt_lookup(StgWord64 key[2]) {
   if (spt) {
     ACQUIRE_LOCK(&spt_lock);
-    StgWord64 key[2] = { key1, key2 };
-    const StgStablePtr * entry = lookupHashTable(spt, (StgWord)key);
+    const StgStablePtr * entry = lookupHashTable_(spt, (StgWord)key,
+        hashFingerprint, compareFingerprint);
     const StgPtr ret = entry ? deRefStablePtr(*entry) : NULL;
     RELEASE_LOCK(&spt_lock);
     return ret;