Skip to content

Commit 64a76c9

Browse files
committed
Refactor dict lookup functions to use force inline helpers
1 parent 8612230 commit 64a76c9

File tree

1 file changed

+94
-93
lines changed

1 file changed

+94
-93
lines changed

Objects/dictobject.c

Lines changed: 94 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -874,69 +874,37 @@ lookdict_index(PyDictKeysObject *k, Py_hash_t hash, Py_ssize_t index)
874874
Py_UNREACHABLE();
875875
}
876876

877-
// Search non-Unicode key from Unicode table
878-
static Py_ssize_t
879-
unicodekeys_lookup_generic(PyDictObject *mp, PyDictKeysObject* dk, PyObject *key, Py_hash_t hash)
877+
typedef void *(*generic_entries_func)(PyDictKeysObject *dk);
878+
879+
static inline Py_ALWAYS_INLINE Py_ssize_t
880+
do_lookup(PyDictObject *mp, PyDictKeysObject *dk, PyObject *key, Py_hash_t hash,
881+
generic_entries_func entries,
882+
Py_ssize_t (*check_lookup)(PyDictObject *, PyDictKeysObject *, void *, Py_ssize_t ix, PyObject *key, Py_hash_t))
880883
{
881-
PyDictUnicodeEntry *ep0 = DK_UNICODE_ENTRIES(dk);
884+
void *ep0 = entries(dk);
882885
size_t mask = DK_MASK(dk);
883886
size_t perturb = hash;
884887
size_t i = (size_t)hash & mask;
885888
Py_ssize_t ix;
886889
for (;;) {
887890
ix = dictkeys_get_index(dk, i);
888891
if (ix >= 0) {
889-
PyDictUnicodeEntry *ep = &ep0[ix];
890-
assert(ep->me_key != NULL);
891-
assert(PyUnicode_CheckExact(ep->me_key));
892-
if (ep->me_key == key) {
892+
ix = check_lookup(mp, dk, ep0, ix, key, hash);
893+
if (ix != DKIX_DUMMY) {
893894
return ix;
894895
}
895-
if (unicode_get_hash(ep->me_key) == hash) {
896-
PyObject *startkey = ep->me_key;
897-
Py_INCREF(startkey);
898-
int cmp = PyObject_RichCompareBool(startkey, key, Py_EQ);
899-
Py_DECREF(startkey);
900-
if (cmp < 0) {
901-
return DKIX_ERROR;
902-
}
903-
if (dk == mp->ma_keys && ep->me_key == startkey) {
904-
if (cmp > 0) {
905-
return ix;
906-
}
907-
}
908-
else {
909-
/* The dict was mutated, restart */
910-
return DKIX_KEY_CHANGED;
911-
}
912-
}
913896
}
914897
else if (ix == DKIX_EMPTY) {
915898
return DKIX_EMPTY;
916899
}
917900
perturb >>= PERTURB_SHIFT;
918901
i = mask & (i*5 + perturb + 1);
919-
}
920-
Py_UNREACHABLE();
921-
}
922902

923-
// Search Unicode key from Unicode table.
924-
static Py_ssize_t _Py_HOT_FUNCTION
925-
unicodekeys_lookup_unicode(PyDictKeysObject* dk, PyObject *key, Py_hash_t hash)
926-
{
927-
PyDictUnicodeEntry *ep0 = DK_UNICODE_ENTRIES(dk);
928-
size_t mask = DK_MASK(dk);
929-
size_t perturb = hash;
930-
size_t i = (size_t)hash & mask;
931-
Py_ssize_t ix;
932-
for (;;) {
903+
// Manual loop unrolling
933904
ix = dictkeys_get_index(dk, i);
934905
if (ix >= 0) {
935-
PyDictUnicodeEntry *ep = &ep0[ix];
936-
assert(ep->me_key != NULL);
937-
assert(PyUnicode_CheckExact(ep->me_key));
938-
if (ep->me_key == key ||
939-
(unicode_get_hash(ep->me_key) == hash && unicode_eq(ep->me_key, key))) {
906+
ix = check_lookup(mp, dk, ep0, ix, key, hash);
907+
if (ix != DKIX_DUMMY) {
940908
return ix;
941909
}
942910
}
@@ -945,69 +913,102 @@ unicodekeys_lookup_unicode(PyDictKeysObject* dk, PyObject *key, Py_hash_t hash)
945913
}
946914
perturb >>= PERTURB_SHIFT;
947915
i = mask & (i*5 + perturb + 1);
948-
// Manual loop unrolling
949-
ix = dictkeys_get_index(dk, i);
950-
if (ix >= 0) {
951-
PyDictUnicodeEntry *ep = &ep0[ix];
952-
assert(ep->me_key != NULL);
953-
assert(PyUnicode_CheckExact(ep->me_key));
954-
if (ep->me_key == key ||
955-
(unicode_get_hash(ep->me_key) == hash && unicode_eq(ep->me_key, key))) {
916+
}
917+
Py_UNREACHABLE();
918+
}
919+
920+
static inline Py_ALWAYS_INLINE
921+
Py_ssize_t compare_unicode_generic(PyDictObject *mp, PyDictKeysObject *dk,
922+
void *ep0, Py_ssize_t ix, PyObject *key, Py_hash_t hash)
923+
{
924+
PyDictUnicodeEntry *ep = &((PyDictUnicodeEntry *)ep0)[ix];
925+
assert(ep->me_key != NULL);
926+
assert(PyUnicode_CheckExact(ep->me_key));
927+
assert(!PyUnicode_CheckExact(key));
928+
// TODO: Thread safety
929+
930+
if (unicode_get_hash(ep->me_key) == hash) {
931+
PyObject *startkey = ep->me_key;
932+
Py_INCREF(startkey);
933+
int cmp = PyObject_RichCompareBool(startkey, key, Py_EQ);
934+
Py_DECREF(startkey);
935+
if (cmp < 0) {
936+
return DKIX_ERROR;
937+
}
938+
if (dk == mp->ma_keys && ep->me_key == startkey) {
939+
if (cmp > 0) {
956940
return ix;
957941
}
958942
}
959-
else if (ix == DKIX_EMPTY) {
960-
return DKIX_EMPTY;
943+
else {
944+
/* The dict was mutated, restart */
945+
return DKIX_KEY_CHANGED;
961946
}
962-
perturb >>= PERTURB_SHIFT;
963-
i = mask & (i*5 + perturb + 1);
964947
}
965-
Py_UNREACHABLE();
948+
return DKIX_DUMMY;
966949
}
967950

968-
// Search key from Generic table.
951+
// Search non-Unicode key from Unicode table
969952
static Py_ssize_t
970-
dictkeys_generic_lookup(PyDictObject *mp, PyDictKeysObject* dk, PyObject *key, Py_hash_t hash)
953+
unicodekeys_lookup_generic(PyDictObject *mp, PyDictKeysObject* dk, PyObject *key, Py_hash_t hash)
971954
{
972-
PyDictKeyEntry *ep0 = DK_ENTRIES(dk);
973-
size_t mask = DK_MASK(dk);
974-
size_t perturb = hash;
975-
size_t i = (size_t)hash & mask;
976-
Py_ssize_t ix;
977-
for (;;) {
978-
ix = dictkeys_get_index(dk, i);
979-
if (ix >= 0) {
980-
PyDictKeyEntry *ep = &ep0[ix];
981-
assert(ep->me_key != NULL);
982-
if (ep->me_key == key) {
955+
return do_lookup(mp, dk, key, hash, (generic_entries_func)DK_UNICODE_ENTRIES, compare_unicode_generic);
956+
}
957+
958+
static inline Py_ALWAYS_INLINE
959+
Py_ssize_t compare_unicode_unicode(PyDictObject *mp, PyDictKeysObject *dk,
960+
void *ep0, Py_ssize_t ix, PyObject *key, Py_hash_t hash)
961+
{
962+
PyDictUnicodeEntry *ep = &((PyDictUnicodeEntry *)ep0)[ix];
963+
assert(ep->me_key != NULL);
964+
assert(PyUnicode_CheckExact(ep->me_key));
965+
if (ep->me_key == key ||
966+
(unicode_get_hash(ep->me_key) == hash && unicode_eq(ep->me_key, key))) {
967+
return ix;
968+
}
969+
return DKIX_DUMMY;
970+
}
971+
972+
static Py_ssize_t _Py_HOT_FUNCTION
973+
unicodekeys_lookup_unicode(PyDictKeysObject* dk, PyObject *key, Py_hash_t hash)
974+
{
975+
return do_lookup(NULL, dk, key, hash, (generic_entries_func)DK_UNICODE_ENTRIES, compare_unicode_unicode);
976+
}
977+
978+
static inline Py_ALWAYS_INLINE
979+
Py_ssize_t compare_generic(PyDictObject *mp, PyDictKeysObject *dk,
980+
void *ep0, Py_ssize_t ix, PyObject *key, Py_hash_t hash)
981+
{
982+
PyDictKeyEntry *ep = &((PyDictKeyEntry *)ep0)[ix];
983+
assert(ep->me_key != NULL);
984+
if (ep->me_key == key) {
985+
return ix;
986+
}
987+
if (ep->me_hash == hash) {
988+
PyObject *startkey = ep->me_key;
989+
Py_INCREF(startkey);
990+
int cmp = PyObject_RichCompareBool(startkey, key, Py_EQ);
991+
Py_DECREF(startkey);
992+
if (cmp < 0) {
993+
return DKIX_ERROR;
994+
}
995+
if (dk == mp->ma_keys && ep->me_key == startkey) {
996+
if (cmp > 0) {
983997
return ix;
984998
}
985-
if (ep->me_hash == hash) {
986-
PyObject *startkey = ep->me_key;
987-
Py_INCREF(startkey);
988-
int cmp = PyObject_RichCompareBool(startkey, key, Py_EQ);
989-
Py_DECREF(startkey);
990-
if (cmp < 0) {
991-
return DKIX_ERROR;
992-
}
993-
if (dk == mp->ma_keys && ep->me_key == startkey) {
994-
if (cmp > 0) {
995-
return ix;
996-
}
997-
}
998-
else {
999-
/* The dict was mutated, restart */
1000-
return DKIX_KEY_CHANGED;
1001-
}
1002-
}
1003999
}
1004-
else if (ix == DKIX_EMPTY) {
1005-
return DKIX_EMPTY;
1000+
else {
1001+
/* The dict was mutated, restart */
1002+
return DKIX_KEY_CHANGED;
10061003
}
1007-
perturb >>= PERTURB_SHIFT;
1008-
i = mask & (i*5 + perturb + 1);
10091004
}
1010-
Py_UNREACHABLE();
1005+
return DKIX_DUMMY;
1006+
}
1007+
1008+
static Py_ssize_t
1009+
dictkeys_generic_lookup(PyDictObject *mp, PyDictKeysObject* dk, PyObject *key, Py_hash_t hash)
1010+
{
1011+
return do_lookup(mp, dk, key, hash, (generic_entries_func)DK_ENTRIES, compare_generic);
10111012
}
10121013

10131014
/* Lookup a string in a (all unicode) dict keys.

0 commit comments

Comments
 (0)