Issue #28818: Simplify lookdict functions

This commit is contained in:
INADA Naoki 2016-12-07 20:41:42 +09:00
parent d7d266c113
commit ba6097734d
3 changed files with 97 additions and 125 deletions

View File

@ -12,7 +12,7 @@ typedef struct {
* -1 when no entry found, -3 when compare raises error. * -1 when no entry found, -3 when compare raises error.
*/ */
typedef Py_ssize_t (*dict_lookup_func) typedef Py_ssize_t (*dict_lookup_func)
(PyDictObject *mp, PyObject *key, Py_hash_t hash, PyObject ***value_addr, (PyDictObject *mp, PyObject *key, Py_hash_t hash, PyObject **value_addr,
Py_ssize_t *hashpos); Py_ssize_t *hashpos);
#define DKIX_EMPTY (-1) #define DKIX_EMPTY (-1)

View File

@ -223,17 +223,17 @@ equally good collision statistics, needed less code & used less memory.
/* forward declarations */ /* forward declarations */
static Py_ssize_t lookdict(PyDictObject *mp, PyObject *key, static Py_ssize_t lookdict(PyDictObject *mp, PyObject *key,
Py_hash_t hash, PyObject ***value_addr, Py_hash_t hash, PyObject **value_addr,
Py_ssize_t *hashpos); Py_ssize_t *hashpos);
static Py_ssize_t lookdict_unicode(PyDictObject *mp, PyObject *key, static Py_ssize_t lookdict_unicode(PyDictObject *mp, PyObject *key,
Py_hash_t hash, PyObject ***value_addr, Py_hash_t hash, PyObject **value_addr,
Py_ssize_t *hashpos); Py_ssize_t *hashpos);
static Py_ssize_t static Py_ssize_t
lookdict_unicode_nodummy(PyDictObject *mp, PyObject *key, lookdict_unicode_nodummy(PyDictObject *mp, PyObject *key,
Py_hash_t hash, PyObject ***value_addr, Py_hash_t hash, PyObject **value_addr,
Py_ssize_t *hashpos); Py_ssize_t *hashpos);
static Py_ssize_t lookdict_split(PyDictObject *mp, PyObject *key, static Py_ssize_t lookdict_split(PyDictObject *mp, PyObject *key,
Py_hash_t hash, PyObject ***value_addr, Py_hash_t hash, PyObject **value_addr,
Py_ssize_t *hashpos); Py_ssize_t *hashpos);
static int dictresize(PyDictObject *mp, Py_ssize_t minused); static int dictresize(PyDictObject *mp, Py_ssize_t minused);
@ -685,7 +685,7 @@ where the key index should be inserted.
*/ */
static Py_ssize_t _Py_HOT_FUNCTION static Py_ssize_t _Py_HOT_FUNCTION
lookdict(PyDictObject *mp, PyObject *key, lookdict(PyDictObject *mp, PyObject *key,
Py_hash_t hash, PyObject ***value_addr, Py_ssize_t *hashpos) Py_hash_t hash, PyObject **value_addr, Py_ssize_t *hashpos)
{ {
size_t i, mask; size_t i, mask;
Py_ssize_t ix, freeslot; Py_ssize_t ix, freeslot;
@ -714,7 +714,7 @@ top:
ep = &ep0[ix]; ep = &ep0[ix];
assert(ep->me_key != NULL); assert(ep->me_key != NULL);
if (ep->me_key == key) { if (ep->me_key == key) {
*value_addr = &ep->me_value; *value_addr = ep->me_value;
if (hashpos != NULL) if (hashpos != NULL)
*hashpos = i; *hashpos = i;
return ix; return ix;
@ -730,7 +730,7 @@ top:
} }
if (dk == mp->ma_keys && ep->me_key == startkey) { if (dk == mp->ma_keys && ep->me_key == startkey) {
if (cmp > 0) { if (cmp > 0) {
*value_addr = &ep->me_value; *value_addr = ep->me_value;
if (hashpos != NULL) if (hashpos != NULL)
*hashpos = i; *hashpos = i;
return ix; return ix;
@ -766,7 +766,7 @@ top:
if (hashpos != NULL) { if (hashpos != NULL) {
*hashpos = i; *hashpos = i;
} }
*value_addr = &ep->me_value; *value_addr = ep->me_value;
return ix; return ix;
} }
if (ep->me_hash == hash) { if (ep->me_hash == hash) {
@ -783,7 +783,7 @@ top:
if (hashpos != NULL) { if (hashpos != NULL) {
*hashpos = i; *hashpos = i;
} }
*value_addr = &ep->me_value; *value_addr = ep->me_value;
return ix; return ix;
} }
} }
@ -800,7 +800,7 @@ top:
/* Specialized version for string-only keys */ /* Specialized version for string-only keys */
static Py_ssize_t _Py_HOT_FUNCTION static Py_ssize_t _Py_HOT_FUNCTION
lookdict_unicode(PyDictObject *mp, PyObject *key, lookdict_unicode(PyDictObject *mp, PyObject *key,
Py_hash_t hash, PyObject ***value_addr, Py_ssize_t *hashpos) Py_hash_t hash, PyObject **value_addr, Py_ssize_t *hashpos)
{ {
size_t i; size_t i;
size_t mask = DK_MASK(mp->ma_keys); size_t mask = DK_MASK(mp->ma_keys);
@ -834,7 +834,7 @@ lookdict_unicode(PyDictObject *mp, PyObject *key,
|| (ep->me_hash == hash && unicode_eq(ep->me_key, key))) { || (ep->me_hash == hash && unicode_eq(ep->me_key, key))) {
if (hashpos != NULL) if (hashpos != NULL)
*hashpos = i; *hashpos = i;
*value_addr = &ep->me_value; *value_addr = ep->me_value;
return ix; return ix;
} }
freeslot = -1; freeslot = -1;
@ -860,7 +860,7 @@ lookdict_unicode(PyDictObject *mp, PyObject *key,
assert(ep->me_key != NULL); assert(ep->me_key != NULL);
if (ep->me_key == key if (ep->me_key == key
|| (ep->me_hash == hash && unicode_eq(ep->me_key, key))) { || (ep->me_hash == hash && unicode_eq(ep->me_key, key))) {
*value_addr = &ep->me_value; *value_addr = ep->me_value;
if (hashpos != NULL) { if (hashpos != NULL) {
*hashpos = i; *hashpos = i;
} }
@ -875,7 +875,7 @@ lookdict_unicode(PyDictObject *mp, PyObject *key,
* will be present. */ * will be present. */
static Py_ssize_t _Py_HOT_FUNCTION static Py_ssize_t _Py_HOT_FUNCTION
lookdict_unicode_nodummy(PyDictObject *mp, PyObject *key, lookdict_unicode_nodummy(PyDictObject *mp, PyObject *key,
Py_hash_t hash, PyObject ***value_addr, Py_hash_t hash, PyObject **value_addr,
Py_ssize_t *hashpos) Py_ssize_t *hashpos)
{ {
size_t i; size_t i;
@ -908,7 +908,7 @@ lookdict_unicode_nodummy(PyDictObject *mp, PyObject *key,
(ep->me_hash == hash && unicode_eq(ep->me_key, key))) { (ep->me_hash == hash && unicode_eq(ep->me_key, key))) {
if (hashpos != NULL) if (hashpos != NULL)
*hashpos = i; *hashpos = i;
*value_addr = &ep->me_value; *value_addr = ep->me_value;
return ix; return ix;
} }
for (size_t perturb = hash;;) { for (size_t perturb = hash;;) {
@ -928,7 +928,7 @@ lookdict_unicode_nodummy(PyDictObject *mp, PyObject *key,
(ep->me_hash == hash && unicode_eq(ep->me_key, key))) { (ep->me_hash == hash && unicode_eq(ep->me_key, key))) {
if (hashpos != NULL) if (hashpos != NULL)
*hashpos = i; *hashpos = i;
*value_addr = &ep->me_value; *value_addr = ep->me_value;
return ix; return ix;
} }
} }
@ -943,7 +943,7 @@ lookdict_unicode_nodummy(PyDictObject *mp, PyObject *key,
*/ */
static Py_ssize_t _Py_HOT_FUNCTION static Py_ssize_t _Py_HOT_FUNCTION
lookdict_split(PyDictObject *mp, PyObject *key, lookdict_split(PyDictObject *mp, PyObject *key,
Py_hash_t hash, PyObject ***value_addr, Py_ssize_t *hashpos) Py_hash_t hash, PyObject **value_addr, Py_ssize_t *hashpos)
{ {
size_t i; size_t i;
size_t mask = DK_MASK(mp->ma_keys); size_t mask = DK_MASK(mp->ma_keys);
@ -955,7 +955,7 @@ lookdict_split(PyDictObject *mp, PyObject *key,
if (!PyUnicode_CheckExact(key)) { if (!PyUnicode_CheckExact(key)) {
ix = lookdict(mp, key, hash, value_addr, hashpos); ix = lookdict(mp, key, hash, value_addr, hashpos);
if (ix >= 0) { if (ix >= 0) {
*value_addr = &mp->ma_values[ix]; *value_addr = mp->ma_values[ix];
} }
return ix; return ix;
} }
@ -975,7 +975,7 @@ lookdict_split(PyDictObject *mp, PyObject *key,
(ep->me_hash == hash && unicode_eq(ep->me_key, key))) { (ep->me_hash == hash && unicode_eq(ep->me_key, key))) {
if (hashpos != NULL) if (hashpos != NULL)
*hashpos = i; *hashpos = i;
*value_addr = &mp->ma_values[ix]; *value_addr = mp->ma_values[ix];
return ix; return ix;
} }
for (size_t perturb = hash;;) { for (size_t perturb = hash;;) {
@ -995,7 +995,7 @@ lookdict_split(PyDictObject *mp, PyObject *key,
(ep->me_hash == hash && unicode_eq(ep->me_key, key))) { (ep->me_hash == hash && unicode_eq(ep->me_key, key))) {
if (hashpos != NULL) if (hashpos != NULL)
*hashpos = i; *hashpos = i;
*value_addr = &mp->ma_values[ix]; *value_addr = mp->ma_values[ix];
return ix; return ix;
} }
} }
@ -1068,32 +1068,24 @@ _PyDict_MaybeUntrack(PyObject *op)
when it is known that the key is not present in the dict. when it is known that the key is not present in the dict.
The dict must be combined. */ The dict must be combined. */
static void static Py_ssize_t
find_empty_slot(PyDictObject *mp, PyObject *key, Py_hash_t hash, find_empty_slot(PyDictKeysObject *keys, PyObject *key, Py_hash_t hash)
PyObject ***value_addr, Py_ssize_t *hashpos)
{ {
size_t i; size_t i;
size_t mask = DK_MASK(mp->ma_keys); size_t mask = DK_MASK(keys);
Py_ssize_t ix; Py_ssize_t ix;
PyDictKeyEntry *ep, *ep0 = DK_ENTRIES(mp->ma_keys);
assert(!_PyDict_HasSplitTable(mp));
assert(hashpos != NULL);
assert(key != NULL); assert(key != NULL);
if (!PyUnicode_CheckExact(key))
mp->ma_keys->dk_lookup = lookdict;
i = hash & mask; i = hash & mask;
ix = dk_get_index(mp->ma_keys, i); ix = dk_get_index(keys, i);
for (size_t perturb = hash; ix != DKIX_EMPTY;) { for (size_t perturb = hash; ix != DKIX_EMPTY;) {
perturb >>= PERTURB_SHIFT; perturb >>= PERTURB_SHIFT;
i = (i << 2) + i + perturb + 1; i = (i << 2) + i + perturb + 1;
ix = dk_get_index(mp->ma_keys, i & mask); ix = dk_get_index(keys, i & mask);
} }
ep = &ep0[mp->ma_keys->dk_nentries]; assert(DK_ENTRIES(keys)[keys->dk_nentries].me_value == NULL);
*hashpos = i & mask; return i & mask;
assert(ep->me_value == NULL);
*value_addr = &ep->me_value;
} }
static int static int
@ -1111,8 +1103,7 @@ static int
insertdict(PyDictObject *mp, PyObject *key, Py_hash_t hash, PyObject *value) insertdict(PyDictObject *mp, PyObject *key, Py_hash_t hash, PyObject *value)
{ {
PyObject *old_value; PyObject *old_value;
PyObject **value_addr; PyDictKeyEntry *ep;
PyDictKeyEntry *ep, *ep0;
Py_ssize_t hashpos, ix; Py_ssize_t hashpos, ix;
if (mp->ma_values != NULL && !PyUnicode_CheckExact(key)) { if (mp->ma_values != NULL && !PyUnicode_CheckExact(key)) {
@ -1120,7 +1111,7 @@ insertdict(PyDictObject *mp, PyObject *key, Py_hash_t hash, PyObject *value)
return -1; return -1;
} }
ix = mp->ma_keys->dk_lookup(mp, key, hash, &value_addr, &hashpos); ix = mp->ma_keys->dk_lookup(mp, key, hash, &old_value, &hashpos);
if (ix == DKIX_ERROR) { if (ix == DKIX_ERROR) {
return -1; return -1;
} }
@ -1133,28 +1124,28 @@ insertdict(PyDictObject *mp, PyObject *key, Py_hash_t hash, PyObject *value)
* the key anymore. Convert this instance to combine table. * the key anymore. Convert this instance to combine table.
*/ */
if (_PyDict_HasSplitTable(mp) && if (_PyDict_HasSplitTable(mp) &&
((ix >= 0 && *value_addr == NULL && mp->ma_used != ix) || ((ix >= 0 && old_value == NULL && mp->ma_used != ix) ||
(ix == DKIX_EMPTY && mp->ma_used != mp->ma_keys->dk_nentries))) { (ix == DKIX_EMPTY && mp->ma_used != mp->ma_keys->dk_nentries))) {
if (insertion_resize(mp) < 0) { if (insertion_resize(mp) < 0) {
Py_DECREF(value); Py_DECREF(value);
return -1; return -1;
} }
find_empty_slot(mp, key, hash, &value_addr, &hashpos); hashpos = find_empty_slot(mp->ma_keys, key, hash);
ix = DKIX_EMPTY; ix = DKIX_EMPTY;
} }
if (ix == DKIX_EMPTY) { if (ix == DKIX_EMPTY) {
/* Insert into new slot. */ /* Insert into new slot. */
assert(old_value == NULL);
if (mp->ma_keys->dk_usable <= 0) { if (mp->ma_keys->dk_usable <= 0) {
/* Need to resize. */ /* Need to resize. */
if (insertion_resize(mp) < 0) { if (insertion_resize(mp) < 0) {
Py_DECREF(value); Py_DECREF(value);
return -1; return -1;
} }
find_empty_slot(mp, key, hash, &value_addr, &hashpos); hashpos = find_empty_slot(mp->ma_keys, key, hash);
} }
ep0 = DK_ENTRIES(mp->ma_keys); ep = &DK_ENTRIES(mp->ma_keys)[mp->ma_keys->dk_nentries];
ep = &ep0[mp->ma_keys->dk_nentries];
dk_set_index(mp->ma_keys, hashpos, mp->ma_keys->dk_nentries); dk_set_index(mp->ma_keys, hashpos, mp->ma_keys->dk_nentries);
Py_INCREF(key); Py_INCREF(key);
ep->me_key = key; ep->me_key = key;
@ -1175,24 +1166,21 @@ insertdict(PyDictObject *mp, PyObject *key, Py_hash_t hash, PyObject *value)
return 0; return 0;
} }
assert(value_addr != NULL); if (_PyDict_HasSplitTable(mp)) {
mp->ma_values[ix] = value;
old_value = *value_addr; if (old_value == NULL) {
if (old_value != NULL) { /* pending state */
*value_addr = value; assert(ix == mp->ma_used);
mp->ma_version_tag = DICT_NEXT_VERSION(); mp->ma_used++;
assert(_PyDict_CheckConsistency(mp)); }
}
Py_DECREF(old_value); /* which **CAN** re-enter (see issue #22653) */ else {
return 0; assert(old_value != NULL);
DK_ENTRIES(mp->ma_keys)[ix].me_value = value;
} }
/* pending state */
assert(_PyDict_HasSplitTable(mp));
assert(ix == mp->ma_used);
*value_addr = value;
mp->ma_used++;
mp->ma_version_tag = DICT_NEXT_VERSION(); mp->ma_version_tag = DICT_NEXT_VERSION();
Py_XDECREF(old_value); /* which **CAN** re-enter (see issue #22653) */
assert(_PyDict_CheckConsistency(mp)); assert(_PyDict_CheckConsistency(mp));
return 0; return 0;
} }
@ -1404,7 +1392,7 @@ PyDict_GetItem(PyObject *op, PyObject *key)
Py_ssize_t ix; Py_ssize_t ix;
PyDictObject *mp = (PyDictObject *)op; PyDictObject *mp = (PyDictObject *)op;
PyThreadState *tstate; PyThreadState *tstate;
PyObject **value_addr; PyObject *value;
if (!PyDict_Check(op)) if (!PyDict_Check(op))
return NULL; return NULL;
@ -1428,20 +1416,20 @@ PyDict_GetItem(PyObject *op, PyObject *key)
/* preserve the existing exception */ /* preserve the existing exception */
PyObject *err_type, *err_value, *err_tb; PyObject *err_type, *err_value, *err_tb;
PyErr_Fetch(&err_type, &err_value, &err_tb); PyErr_Fetch(&err_type, &err_value, &err_tb);
ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &value_addr, NULL); ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &value, NULL);
/* ignore errors */ /* ignore errors */
PyErr_Restore(err_type, err_value, err_tb); PyErr_Restore(err_type, err_value, err_tb);
if (ix < 0) if (ix < 0)
return NULL; return NULL;
} }
else { else {
ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &value_addr, NULL); ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &value, NULL);
if (ix < 0) { if (ix < 0) {
PyErr_Clear(); PyErr_Clear();
return NULL; return NULL;
} }
} }
return *value_addr; return value;
} }
/* Same as PyDict_GetItemWithError() but with hash supplied by caller. /* Same as PyDict_GetItemWithError() but with hash supplied by caller.
@ -1453,18 +1441,18 @@ _PyDict_GetItem_KnownHash(PyObject *op, PyObject *key, Py_hash_t hash)
{ {
Py_ssize_t ix; Py_ssize_t ix;
PyDictObject *mp = (PyDictObject *)op; PyDictObject *mp = (PyDictObject *)op;
PyObject **value_addr; PyObject *value;
if (!PyDict_Check(op)) { if (!PyDict_Check(op)) {
PyErr_BadInternalCall(); PyErr_BadInternalCall();
return NULL; return NULL;
} }
ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &value_addr, NULL); ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &value, NULL);
if (ix < 0) { if (ix < 0) {
return NULL; return NULL;
} }
return *value_addr; return value;
} }
/* Variant of PyDict_GetItem() that doesn't suppress exceptions. /* Variant of PyDict_GetItem() that doesn't suppress exceptions.
@ -1477,7 +1465,7 @@ PyDict_GetItemWithError(PyObject *op, PyObject *key)
Py_ssize_t ix; Py_ssize_t ix;
Py_hash_t hash; Py_hash_t hash;
PyDictObject*mp = (PyDictObject *)op; PyDictObject*mp = (PyDictObject *)op;
PyObject **value_addr; PyObject *value;
if (!PyDict_Check(op)) { if (!PyDict_Check(op)) {
PyErr_BadInternalCall(); PyErr_BadInternalCall();
@ -1492,10 +1480,10 @@ PyDict_GetItemWithError(PyObject *op, PyObject *key)
} }
} }
ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &value_addr, NULL); ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &value, NULL);
if (ix < 0) if (ix < 0)
return NULL; return NULL;
return *value_addr; return value;
} }
PyObject * PyObject *
@ -1520,7 +1508,7 @@ _PyDict_LoadGlobal(PyDictObject *globals, PyDictObject *builtins, PyObject *key)
{ {
Py_ssize_t ix; Py_ssize_t ix;
Py_hash_t hash; Py_hash_t hash;
PyObject **value_addr; PyObject *value;
if (!PyUnicode_CheckExact(key) || if (!PyUnicode_CheckExact(key) ||
(hash = ((PyASCIIObject *) key)->hash) == -1) (hash = ((PyASCIIObject *) key)->hash) == -1)
@ -1531,17 +1519,17 @@ _PyDict_LoadGlobal(PyDictObject *globals, PyDictObject *builtins, PyObject *key)
} }
/* namespace 1: globals */ /* namespace 1: globals */
ix = globals->ma_keys->dk_lookup(globals, key, hash, &value_addr, NULL); ix = globals->ma_keys->dk_lookup(globals, key, hash, &value, NULL);
if (ix == DKIX_ERROR) if (ix == DKIX_ERROR)
return NULL; return NULL;
if (ix != DKIX_EMPTY && *value_addr != NULL) if (ix != DKIX_EMPTY && value != NULL)
return *value_addr; return value;
/* namespace 2: builtins */ /* namespace 2: builtins */
ix = builtins->ma_keys->dk_lookup(builtins, key, hash, &value_addr, NULL); ix = builtins->ma_keys->dk_lookup(builtins, key, hash, &value, NULL);
if (ix < 0) if (ix < 0)
return NULL; return NULL;
return *value_addr; return value;
} }
/* CAUTION: PyDict_SetItem() must guarantee that it won't resize the /* CAUTION: PyDict_SetItem() must guarantee that it won't resize the
@ -1616,7 +1604,6 @@ _PyDict_DelItem_KnownHash(PyObject *op, PyObject *key, Py_hash_t hash)
PyDictObject *mp; PyDictObject *mp;
PyDictKeyEntry *ep; PyDictKeyEntry *ep;
PyObject *old_key, *old_value; PyObject *old_key, *old_value;
PyObject **value_addr;
if (!PyDict_Check(op)) { if (!PyDict_Check(op)) {
PyErr_BadInternalCall(); PyErr_BadInternalCall();
@ -1625,10 +1612,10 @@ _PyDict_DelItem_KnownHash(PyObject *op, PyObject *key, Py_hash_t hash)
assert(key); assert(key);
assert(hash != -1); assert(hash != -1);
mp = (PyDictObject *)op; mp = (PyDictObject *)op;
ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &value_addr, &hashpos); ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &old_value, &hashpos);
if (ix == DKIX_ERROR) if (ix == DKIX_ERROR)
return -1; return -1;
if (ix == DKIX_EMPTY || *value_addr == NULL) { if (ix == DKIX_EMPTY || old_value == NULL) {
_PyErr_SetKeyError(key); _PyErr_SetKeyError(key);
return -1; return -1;
} }
@ -1639,13 +1626,11 @@ _PyDict_DelItem_KnownHash(PyObject *op, PyObject *key, Py_hash_t hash)
if (dictresize(mp, DK_SIZE(mp->ma_keys))) { if (dictresize(mp, DK_SIZE(mp->ma_keys))) {
return -1; return -1;
} }
ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &value_addr, &hashpos); ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &old_value, &hashpos);
assert(ix >= 0); assert(ix >= 0);
} }
old_value = *value_addr;
assert(old_value != NULL); assert(old_value != NULL);
*value_addr = NULL;
mp->ma_used--; mp->ma_used--;
mp->ma_version_tag = DICT_NEXT_VERSION(); mp->ma_version_tag = DICT_NEXT_VERSION();
ep = &DK_ENTRIES(mp->ma_keys)[ix]; ep = &DK_ENTRIES(mp->ma_keys)[ix];
@ -1653,6 +1638,7 @@ _PyDict_DelItem_KnownHash(PyObject *op, PyObject *key, Py_hash_t hash)
ENSURE_ALLOWS_DELETIONS(mp); ENSURE_ALLOWS_DELETIONS(mp);
old_key = ep->me_key; old_key = ep->me_key;
ep->me_key = NULL; ep->me_key = NULL;
ep->me_value = NULL;
Py_DECREF(old_key); Py_DECREF(old_key);
Py_DECREF(old_value); Py_DECREF(old_value);
@ -1777,7 +1763,6 @@ _PyDict_Pop(PyObject *dict, PyObject *key, PyObject *deflt)
Py_ssize_t ix, hashpos; Py_ssize_t ix, hashpos;
PyObject *old_value, *old_key; PyObject *old_value, *old_key;
PyDictKeyEntry *ep; PyDictKeyEntry *ep;
PyObject **value_addr;
PyDictObject *mp; PyDictObject *mp;
assert(PyDict_Check(dict)); assert(PyDict_Check(dict));
@ -1797,10 +1782,10 @@ _PyDict_Pop(PyObject *dict, PyObject *key, PyObject *deflt)
if (hash == -1) if (hash == -1)
return NULL; return NULL;
} }
ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &value_addr, &hashpos); ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &old_value, &hashpos);
if (ix == DKIX_ERROR) if (ix == DKIX_ERROR)
return NULL; return NULL;
if (ix == DKIX_EMPTY || *value_addr == NULL) { if (ix == DKIX_EMPTY || old_value == NULL) {
if (deflt) { if (deflt) {
Py_INCREF(deflt); Py_INCREF(deflt);
return deflt; return deflt;
@ -1814,13 +1799,11 @@ _PyDict_Pop(PyObject *dict, PyObject *key, PyObject *deflt)
if (dictresize(mp, DK_SIZE(mp->ma_keys))) { if (dictresize(mp, DK_SIZE(mp->ma_keys))) {
return NULL; return NULL;
} }
ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &value_addr, &hashpos); ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &old_value, &hashpos);
assert(ix >= 0); assert(ix >= 0);
} }
old_value = *value_addr;
assert(old_value != NULL); assert(old_value != NULL);
*value_addr = NULL;
mp->ma_used--; mp->ma_used--;
mp->ma_version_tag = DICT_NEXT_VERSION(); mp->ma_version_tag = DICT_NEXT_VERSION();
dk_set_index(mp->ma_keys, hashpos, DKIX_DUMMY); dk_set_index(mp->ma_keys, hashpos, DKIX_DUMMY);
@ -1828,6 +1811,7 @@ _PyDict_Pop(PyObject *dict, PyObject *key, PyObject *deflt)
ENSURE_ALLOWS_DELETIONS(mp); ENSURE_ALLOWS_DELETIONS(mp);
old_key = ep->me_key; old_key = ep->me_key;
ep->me_key = NULL; ep->me_key = NULL;
ep->me_value = NULL;
Py_DECREF(old_key); Py_DECREF(old_key);
assert(_PyDict_CheckConsistency(mp)); assert(_PyDict_CheckConsistency(mp));
@ -2045,10 +2029,9 @@ dict_length(PyDictObject *mp)
static PyObject * static PyObject *
dict_subscript(PyDictObject *mp, PyObject *key) dict_subscript(PyDictObject *mp, PyObject *key)
{ {
PyObject *v;
Py_ssize_t ix; Py_ssize_t ix;
Py_hash_t hash; Py_hash_t hash;
PyObject **value_addr; PyObject *value;
if (!PyUnicode_CheckExact(key) || if (!PyUnicode_CheckExact(key) ||
(hash = ((PyASCIIObject *) key)->hash) == -1) { (hash = ((PyASCIIObject *) key)->hash) == -1) {
@ -2056,10 +2039,10 @@ dict_subscript(PyDictObject *mp, PyObject *key)
if (hash == -1) if (hash == -1)
return NULL; return NULL;
} }
ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &value_addr, NULL); ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &value, NULL);
if (ix == DKIX_ERROR) if (ix == DKIX_ERROR)
return NULL; return NULL;
if (ix == DKIX_EMPTY || *value_addr == NULL) { if (ix == DKIX_EMPTY || value == NULL) {
if (!PyDict_CheckExact(mp)) { if (!PyDict_CheckExact(mp)) {
/* Look up __missing__ method if we're a subclass. */ /* Look up __missing__ method if we're a subclass. */
PyObject *missing, *res; PyObject *missing, *res;
@ -2077,9 +2060,8 @@ dict_subscript(PyDictObject *mp, PyObject *key)
_PyErr_SetKeyError(key); _PyErr_SetKeyError(key);
return NULL; return NULL;
} }
v = *value_addr; Py_INCREF(value);
Py_INCREF(v); return value;
return v;
} }
static int static int
@ -2651,7 +2633,6 @@ dict_equal(PyDictObject *a, PyDictObject *b)
if (aval != NULL) { if (aval != NULL) {
int cmp; int cmp;
PyObject *bval; PyObject *bval;
PyObject **vaddr;
PyObject *key = ep->me_key; PyObject *key = ep->me_key;
/* temporarily bump aval's refcount to ensure it stays /* temporarily bump aval's refcount to ensure it stays
alive until we're done with it */ alive until we're done with it */
@ -2659,10 +2640,7 @@ dict_equal(PyDictObject *a, PyDictObject *b)
/* ditto for key */ /* ditto for key */
Py_INCREF(key); Py_INCREF(key);
/* reuse the known hash value */ /* reuse the known hash value */
if ((b->ma_keys->dk_lookup)(b, key, ep->me_hash, &vaddr, NULL) < 0) b->ma_keys->dk_lookup(b, key, ep->me_hash, &bval, NULL);
bval = NULL;
else
bval = *vaddr;
Py_DECREF(key); Py_DECREF(key);
if (bval == NULL) { if (bval == NULL) {
Py_DECREF(aval); Py_DECREF(aval);
@ -2718,7 +2696,7 @@ dict___contains__(PyDictObject *self, PyObject *key)
register PyDictObject *mp = self; register PyDictObject *mp = self;
Py_hash_t hash; Py_hash_t hash;
Py_ssize_t ix; Py_ssize_t ix;
PyObject **value_addr; PyObject *value;
if (!PyUnicode_CheckExact(key) || if (!PyUnicode_CheckExact(key) ||
(hash = ((PyASCIIObject *) key)->hash) == -1) { (hash = ((PyASCIIObject *) key)->hash) == -1) {
@ -2726,10 +2704,10 @@ dict___contains__(PyDictObject *self, PyObject *key)
if (hash == -1) if (hash == -1)
return NULL; return NULL;
} }
ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &value_addr, NULL); ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &value, NULL);
if (ix == DKIX_ERROR) if (ix == DKIX_ERROR)
return NULL; return NULL;
if (ix == DKIX_EMPTY || *value_addr == NULL) if (ix == DKIX_EMPTY || value == NULL)
Py_RETURN_FALSE; Py_RETURN_FALSE;
Py_RETURN_TRUE; Py_RETURN_TRUE;
} }
@ -2742,7 +2720,6 @@ dict_get(PyDictObject *mp, PyObject *args)
PyObject *val = NULL; PyObject *val = NULL;
Py_hash_t hash; Py_hash_t hash;
Py_ssize_t ix; Py_ssize_t ix;
PyObject **value_addr;
if (!PyArg_UnpackTuple(args, "get", 1, 2, &key, &failobj)) if (!PyArg_UnpackTuple(args, "get", 1, 2, &key, &failobj))
return NULL; return NULL;
@ -2753,13 +2730,12 @@ dict_get(PyDictObject *mp, PyObject *args)
if (hash == -1) if (hash == -1)
return NULL; return NULL;
} }
ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &value_addr, NULL); ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &val, NULL);
if (ix == DKIX_ERROR) if (ix == DKIX_ERROR)
return NULL; return NULL;
if (ix == DKIX_EMPTY || *value_addr == NULL) if (ix == DKIX_EMPTY || val == NULL) {
val = failobj; val = failobj;
else }
val = *value_addr;
Py_INCREF(val); Py_INCREF(val);
return val; return val;
} }
@ -2771,7 +2747,6 @@ PyDict_SetDefault(PyObject *d, PyObject *key, PyObject *defaultobj)
PyObject *value; PyObject *value;
Py_hash_t hash; Py_hash_t hash;
Py_ssize_t hashpos, ix; Py_ssize_t hashpos, ix;
PyObject **value_addr;
if (!PyDict_Check(d)) { if (!PyDict_Check(d)) {
PyErr_BadInternalCall(); PyErr_BadInternalCall();
@ -2790,17 +2765,17 @@ PyDict_SetDefault(PyObject *d, PyObject *key, PyObject *defaultobj)
return NULL; return NULL;
} }
ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &value_addr, &hashpos); ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &value, &hashpos);
if (ix == DKIX_ERROR) if (ix == DKIX_ERROR)
return NULL; return NULL;
if (_PyDict_HasSplitTable(mp) && if (_PyDict_HasSplitTable(mp) &&
((ix >= 0 && *value_addr == NULL && mp->ma_used != ix) || ((ix >= 0 && value == NULL && mp->ma_used != ix) ||
(ix == DKIX_EMPTY && mp->ma_used != mp->ma_keys->dk_nentries))) { (ix == DKIX_EMPTY && mp->ma_used != mp->ma_keys->dk_nentries))) {
if (insertion_resize(mp) < 0) { if (insertion_resize(mp) < 0) {
return NULL; return NULL;
} }
find_empty_slot(mp, key, hash, &value_addr, &hashpos); hashpos = find_empty_slot(mp->ma_keys, key, hash);
ix = DKIX_EMPTY; ix = DKIX_EMPTY;
} }
@ -2811,7 +2786,7 @@ PyDict_SetDefault(PyObject *d, PyObject *key, PyObject *defaultobj)
if (insertion_resize(mp) < 0) { if (insertion_resize(mp) < 0) {
return NULL; return NULL;
} }
find_empty_slot(mp, key, hash, &value_addr, &hashpos); hashpos = find_empty_slot(mp->ma_keys, key, hash);
} }
ep0 = DK_ENTRIES(mp->ma_keys); ep0 = DK_ENTRIES(mp->ma_keys);
ep = &ep0[mp->ma_keys->dk_nentries]; ep = &ep0[mp->ma_keys->dk_nentries];
@ -2821,7 +2796,7 @@ PyDict_SetDefault(PyObject *d, PyObject *key, PyObject *defaultobj)
MAINTAIN_TRACKING(mp, key, value); MAINTAIN_TRACKING(mp, key, value);
ep->me_key = key; ep->me_key = key;
ep->me_hash = hash; ep->me_hash = hash;
if (mp->ma_values) { if (_PyDict_HasSplitTable(mp)) {
assert(mp->ma_values[mp->ma_keys->dk_nentries] == NULL); assert(mp->ma_values[mp->ma_keys->dk_nentries] == NULL);
mp->ma_values[mp->ma_keys->dk_nentries] = value; mp->ma_values[mp->ma_keys->dk_nentries] = value;
} }
@ -2834,19 +2809,16 @@ PyDict_SetDefault(PyObject *d, PyObject *key, PyObject *defaultobj)
mp->ma_keys->dk_nentries++; mp->ma_keys->dk_nentries++;
assert(mp->ma_keys->dk_usable >= 0); assert(mp->ma_keys->dk_usable >= 0);
} }
else if (*value_addr == NULL) { else if (value == NULL) {
value = defaultobj; value = defaultobj;
assert(_PyDict_HasSplitTable(mp)); assert(_PyDict_HasSplitTable(mp));
assert(ix == mp->ma_used); assert(ix == mp->ma_used);
Py_INCREF(value); Py_INCREF(value);
MAINTAIN_TRACKING(mp, key, value); MAINTAIN_TRACKING(mp, key, value);
*value_addr = value; mp->ma_values[ix] = value;
mp->ma_used++; mp->ma_used++;
mp->ma_version_tag = DICT_NEXT_VERSION(); mp->ma_version_tag = DICT_NEXT_VERSION();
} }
else {
value = *value_addr;
}
assert(_PyDict_CheckConsistency(mp)); assert(_PyDict_CheckConsistency(mp));
return value; return value;
@ -3100,7 +3072,7 @@ PyDict_Contains(PyObject *op, PyObject *key)
Py_hash_t hash; Py_hash_t hash;
Py_ssize_t ix; Py_ssize_t ix;
PyDictObject *mp = (PyDictObject *)op; PyDictObject *mp = (PyDictObject *)op;
PyObject **value_addr; PyObject *value;
if (!PyUnicode_CheckExact(key) || if (!PyUnicode_CheckExact(key) ||
(hash = ((PyASCIIObject *) key)->hash) == -1) { (hash = ((PyASCIIObject *) key)->hash) == -1) {
@ -3108,10 +3080,10 @@ PyDict_Contains(PyObject *op, PyObject *key)
if (hash == -1) if (hash == -1)
return -1; return -1;
} }
ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &value_addr, NULL); ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &value, NULL);
if (ix == DKIX_ERROR) if (ix == DKIX_ERROR)
return -1; return -1;
return (ix != DKIX_EMPTY && *value_addr != NULL); return (ix != DKIX_EMPTY && value != NULL);
} }
/* Internal version of PyDict_Contains used when the hash value is already known */ /* Internal version of PyDict_Contains used when the hash value is already known */
@ -3119,13 +3091,13 @@ int
_PyDict_Contains(PyObject *op, PyObject *key, Py_hash_t hash) _PyDict_Contains(PyObject *op, PyObject *key, Py_hash_t hash)
{ {
PyDictObject *mp = (PyDictObject *)op; PyDictObject *mp = (PyDictObject *)op;
PyObject **value_addr; PyObject *value;
Py_ssize_t ix; Py_ssize_t ix;
ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &value_addr, NULL); ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &value, NULL);
if (ix == DKIX_ERROR) if (ix == DKIX_ERROR)
return -1; return -1;
return (ix != DKIX_EMPTY && *value_addr != NULL); return (ix != DKIX_EMPTY && value != NULL);
} }
/* Hack to implement "key in dict" */ /* Hack to implement "key in dict" */

View File

@ -535,11 +535,11 @@ _odict_free_fast_nodes(PyODictObject *od) {
static Py_ssize_t static Py_ssize_t
_odict_get_index_raw(PyODictObject *od, PyObject *key, Py_hash_t hash) _odict_get_index_raw(PyODictObject *od, PyObject *key, Py_hash_t hash)
{ {
PyObject **value_addr = NULL; PyObject *value = NULL;
PyDictKeysObject *keys = ((PyDictObject *)od)->ma_keys; PyDictKeysObject *keys = ((PyDictObject *)od)->ma_keys;
Py_ssize_t ix; Py_ssize_t ix;
ix = (keys->dk_lookup)((PyDictObject *)od, key, hash, &value_addr, NULL); ix = (keys->dk_lookup)((PyDictObject *)od, key, hash, &value, NULL);
if (ix == DKIX_EMPTY) { if (ix == DKIX_EMPTY) {
return keys->dk_nentries; /* index of new entry */ return keys->dk_nentries; /* index of new entry */
} }