diff --git a/Zend/zend_string.h b/Zend/zend_string.h index 1513a19c36070..ee53dbafc2b0c 100644 --- a/Zend/zend_string.h +++ b/Zend/zend_string.h @@ -457,12 +457,21 @@ static zend_always_inline bool zend_string_starts_with_ci(const zend_string *str * -- Ralf S. Engelschall */ + static zend_always_inline zend_ulong zend_inline_hash_func(const char *str, size_t len) { - zend_ulong hash = Z_UL(5381); +#if SIZEOF_ZEND_LONG == 8 + zend_ulong hash = Z_UL(14695981039346656037); + const zend_ulong prime = Z_UL(1099511628211); +#else + zend_ulong hash = Z_UL(2166136261); + const zend_ulong prime = Z_UL(16777619); +#endif + +#define ROUND(character) \ + hash *= prime; \ + hash ^= character; -#if defined(_WIN32) || defined(__i386__) || defined(__x86_64__) || defined(__aarch64__) - /* Version with multiplication works better on modern CPU */ for (; len >= 8; len -= 8, str += 8) { # if defined(__aarch64__) && !defined(WORDS_BIGENDIAN) /* On some architectures it is beneficial to load 8 bytes at a @@ -470,83 +479,45 @@ static zend_always_inline zend_ulong zend_inline_hash_func(const char *str, size uint64_t chunk; memcpy(&chunk, str, sizeof(chunk)); - hash = - hash * 33 * 33 * 33 * 33 + - ((chunk >> (8 * 0)) & 0xff) * 33 * 33 * 33 + - ((chunk >> (8 * 1)) & 0xff) * 33 * 33 + - ((chunk >> (8 * 2)) & 0xff) * 33 + - ((chunk >> (8 * 3)) & 0xff); - hash = - hash * 33 * 33 * 33 * 33 + - ((chunk >> (8 * 4)) & 0xff) * 33 * 33 * 33 + - ((chunk >> (8 * 5)) & 0xff) * 33 * 33 + - ((chunk >> (8 * 6)) & 0xff) * 33 + - ((chunk >> (8 * 7)) & 0xff); + ROUND((chunk >> (8 * 0)) & 0xff); + ROUND((chunk >> (8 * 1)) & 0xff); + ROUND((chunk >> (8 * 2)) & 0xff); + ROUND((chunk >> (8 * 3)) & 0xff); + ROUND((chunk >> (8 * 4)) & 0xff); + ROUND((chunk >> (8 * 5)) & 0xff); + ROUND((chunk >> (8 * 6)) & 0xff); + ROUND((chunk >> (8 * 7)) & 0xff); # else - hash = - hash * Z_L(33 * 33 * 33 * 33) + - str[0] * Z_L(33 * 33 * 33) + - str[1] * Z_L(33 * 33) + - str[2] * Z_L(33) + - str[3]; - hash = - hash * Z_L(33 * 33 * 33 * 33) + - str[4] * Z_L(33 * 33 * 33) + - str[5] * Z_L(33 * 33) + - str[6] * Z_L(33) + - str[7]; + ROUND(str[0]); + ROUND(str[1]); + ROUND(str[2]); + ROUND(str[3]); + ROUND(str[4]); + ROUND(str[5]); + ROUND(str[6]); + ROUND(str[7]); # endif } if (len >= 4) { - hash = - hash * Z_L(33 * 33 * 33 * 33) + - str[0] * Z_L(33 * 33 * 33) + - str[1] * Z_L(33 * 33) + - str[2] * Z_L(33) + - str[3]; + ROUND(str[0]); + ROUND(str[1]); + ROUND(str[2]); + ROUND(str[3]); len -= 4; str += 4; } if (len >= 2) { if (len > 2) { - hash = - hash * Z_L(33 * 33 * 33) + - str[0] * Z_L(33 * 33) + - str[1] * Z_L(33) + - str[2]; + ROUND(str[0]); + ROUND(str[1]); + ROUND(str[2]); } else { - hash = - hash * Z_L(33 * 33) + - str[0] * Z_L(33) + - str[1]; + ROUND(str[0]); + ROUND(str[1]); } } else if (len != 0) { - hash = hash * Z_L(33) + *str; + ROUND(*str); } -#else - /* variant with the hash unrolled eight times */ - for (; len >= 8; len -= 8) { - hash = ((hash << 5) + hash) + *str++; - hash = ((hash << 5) + hash) + *str++; - hash = ((hash << 5) + hash) + *str++; - hash = ((hash << 5) + hash) + *str++; - hash = ((hash << 5) + hash) + *str++; - hash = ((hash << 5) + hash) + *str++; - hash = ((hash << 5) + hash) + *str++; - hash = ((hash << 5) + hash) + *str++; - } - switch (len) { - case 7: hash = ((hash << 5) + hash) + *str++; /* fallthrough... */ - case 6: hash = ((hash << 5) + hash) + *str++; /* fallthrough... */ - case 5: hash = ((hash << 5) + hash) + *str++; /* fallthrough... */ - case 4: hash = ((hash << 5) + hash) + *str++; /* fallthrough... */ - case 3: hash = ((hash << 5) + hash) + *str++; /* fallthrough... */ - case 2: hash = ((hash << 5) + hash) + *str++; /* fallthrough... */ - case 1: hash = ((hash << 5) + hash) + *str++; break; - case 0: break; -EMPTY_SWITCH_DEFAULT_CASE() - } -#endif /* Hash value can't be zero, so we always set the high bit */ #if SIZEOF_ZEND_LONG == 8