-
Notifications
You must be signed in to change notification settings - Fork 205
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Two-level hashing of
std::type_info *
via pointer & string hash (f…
…ixes #283) Exchange of RTTI type information between separately compiled extension libraries tends to be fragile: depending on the compiler and platform, the C++ standard library may use one of two strategies to decide whether two ``std::type_info`` instances are equal. The first is to perform a string comparison of the mangled type name. When types are organized in hash tables, a string hash is then also needed. This strategy yields the expected result but can be rather inefficient. Other platforms simply compare the pointer value and rely on a poiner-based hashing scheme. This is far more efficient but requires that the linker merges duplicate RTTI information from separate shared libraries. Unfortunately, this does not always work for the following reasons: 1. Python passes the ``RTLD_LOCAL`` flag to ``dlopen()`` when it loads shared libraries. If RTTI symbols are exported by a separate shared library, then things may still be fine. But if the Python extension is in charge of exporting RTTI symbols, there is problem. 2. It can generally be tricky to get the compiler to export RTTI symbols for non-polymorphic types. 3. Setting the right ``__attribute__ ((visibility("default")))`` flags in extension libraries is error-prone and a source of confusion for new users. This commit changes nanobind to adopt both strategies at the same time. Type queries first go through a fast pointer-based hash table followed by a secondary string-based hash table. In the latter case, nanobind also populates the faster pointer-based table with the missing information so that the fast path eventually resolves all of the queries. This commit changes the internal representation of nanobind data structures, hence the ABI version had to be incremented.
- Loading branch information
Showing
10 changed files
with
279 additions
and
153 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
#include "hash.h" | ||
#include <stdlib.h> | ||
|
||
#if defined(_MSC_VER) | ||
# define ROTL32(x,y) _rotl(x,y) | ||
# define ROTL64(x,y) _rotl64(x,y) | ||
|
||
#else | ||
inline uint32_t rotl32(uint32_t x, int8_t r) { | ||
return (x << r) | (x >> (32 - r)); | ||
} | ||
|
||
inline uint64_t rotl64(uint64_t x, int8_t r) { | ||
return (x << r) | (x >> (64 - r)); | ||
} | ||
|
||
# define ROTL32(x,y) rotl32(x,y) | ||
# define ROTL64(x,y) rotl64(x,y) | ||
#endif | ||
|
||
//----------------------------------------------------------------------------- | ||
|
||
uint64_t MurmurHash3_x64_64(const void *key, const int len, | ||
const uint32_t seed) { | ||
const uint8_t *data = (const uint8_t *) key; | ||
const int nblocks = len / 16; | ||
|
||
uint64_t h1 = seed; | ||
uint64_t h2 = seed; | ||
|
||
const uint64_t c1 = (uint64_t) 0x87c37b91114253d5ull; | ||
const uint64_t c2 = (uint64_t) 0x4cf5ad432745937full; | ||
|
||
//---------- | ||
// body | ||
|
||
const uint64_t * blocks = (const uint64_t *)(data); | ||
|
||
for(int i = 0; i < nblocks; i++) { | ||
uint64_t k1 = blocks[i*2+0]; | ||
uint64_t k2 = blocks[i*2+1]; | ||
|
||
k1 *= c1; k1 = ROTL64(k1,31); k1 *= c2; h1 ^= k1; | ||
|
||
h1 = ROTL64(h1,27); h1 += h2; h1 = h1*5+0x52dce729; | ||
|
||
k2 *= c2; k2 = ROTL64(k2,33); k2 *= c1; h2 ^= k2; | ||
|
||
h2 = ROTL64(h2,31); h2 += h1; h2 = h2*5+0x38495ab5; | ||
} | ||
|
||
//---------- | ||
// tail | ||
|
||
const uint8_t *tail = (const uint8_t *) (data + nblocks * 16); | ||
|
||
uint64_t k1 = 0; | ||
uint64_t k2 = 0; | ||
|
||
switch(len & 15) { | ||
case 15: k2 ^= ((uint64_t)tail[14]) << 48; | ||
case 14: k2 ^= ((uint64_t)tail[13]) << 40; | ||
case 13: k2 ^= ((uint64_t)tail[12]) << 32; | ||
case 12: k2 ^= ((uint64_t)tail[11]) << 24; | ||
case 11: k2 ^= ((uint64_t)tail[10]) << 16; | ||
case 10: k2 ^= ((uint64_t)tail[ 9]) << 8; | ||
case 9: k2 ^= ((uint64_t)tail[ 8]) << 0; | ||
k2 *= c2; k2 = ROTL64(k2,33); k2 *= c1; h2 ^= k2; | ||
|
||
case 8: k1 ^= ((uint64_t)tail[ 7]) << 56; | ||
case 7: k1 ^= ((uint64_t)tail[ 6]) << 48; | ||
case 6: k1 ^= ((uint64_t)tail[ 5]) << 40; | ||
case 5: k1 ^= ((uint64_t)tail[ 4]) << 32; | ||
case 4: k1 ^= ((uint64_t)tail[ 3]) << 24; | ||
case 3: k1 ^= ((uint64_t)tail[ 2]) << 16; | ||
case 2: k1 ^= ((uint64_t)tail[ 1]) << 8; | ||
case 1: k1 ^= ((uint64_t)tail[ 0]) << 0; | ||
k1 *= c1; k1 = ROTL64(k1,31); k1 *= c2; h1 ^= k1; | ||
}; | ||
|
||
//---------- | ||
// finalization | ||
|
||
h1 ^= len; h2 ^= len; | ||
|
||
h1 += h2; | ||
h2 += h1; | ||
|
||
h1 = fmix64(h1); | ||
h2 = fmix64(h2); | ||
|
||
h1 += h2; | ||
|
||
return h1; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
//----------------------------------------------------------------------------- | ||
// Slightly adapted version of the MurmurHash3 codebase (originally by Austin | ||
// Appleby, in the public domain) | ||
// | ||
// The changes are as follows: | ||
// | ||
// - fmix32 and fmix64 are exported to other compilation units, since they | ||
// are useful has a hash function for 32/64 bit integers and pointers | ||
// | ||
// - The MurmurHash3_x64_64() function is a variant of the original | ||
// MurmurHash3_x64_128() that only returns the low 64 bit of the hash | ||
// value. | ||
//----------------------------------------------------------------------------- | ||
|
||
#pragma once | ||
|
||
#include <cstdint> | ||
|
||
inline uint32_t fmix32(uint32_t h) { | ||
h ^= h >> 16; | ||
h *= 0x85ebca6b; | ||
h ^= h >> 13; | ||
h *= 0xc2b2ae35; | ||
h ^= h >> 16; | ||
|
||
return h; | ||
} | ||
|
||
inline uint64_t fmix64(uint64_t k) { | ||
k ^= k >> 33; | ||
k *= (uint64_t) 0xff51afd7ed558ccdull; | ||
k ^= k >> 33; | ||
k *= (uint64_t) 0xc4ceb9fe1a85ec53ull; | ||
k ^= k >> 33; | ||
return k; | ||
} | ||
|
||
extern uint64_t MurmurHash3_x64_64(const void *key, int len, uint32_t seed); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.