bpo-45609: Specialize STORE_SUBSCR (GH-29242)

* Specialize STORE_SUBSCR for list[int], and dict[object]

* Adds _PyDict_SetItem_Take2 which consumes references to the key and values.
This commit is contained in:
Dennis Sweeney 2021-11-19 05:30:37 -05:00 committed by GitHub
parent 4575c01b75
commit 036fead695
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 241 additions and 71 deletions

View file

@ -1055,6 +1055,7 @@ insert_into_dictkeys(PyDictKeysObject *keys, PyObject *name)
Internal routine to insert a new item into the table.
Used both by the internal resize routine and by the public insert routine.
Returns -1 if an error occurred, or 0 on success.
Consumes key and value references.
*/
static int
insertdict(PyDictObject *mp, PyObject *key, Py_hash_t hash, PyObject *value)
@ -1062,8 +1063,6 @@ insertdict(PyDictObject *mp, PyObject *key, Py_hash_t hash, PyObject *value)
PyObject *old_value;
PyDictKeyEntry *ep;
Py_INCREF(key);
Py_INCREF(value);
if (mp->ma_values != NULL && !PyUnicode_CheckExact(key)) {
if (insertion_resize(mp) < 0)
goto Fail;
@ -1138,6 +1137,7 @@ Fail:
}
// Same to insertdict but specialized for ma_keys = Py_EMPTY_KEYS.
// Consumes key and value references.
static int
insert_to_emptydict(PyDictObject *mp, PyObject *key, Py_hash_t hash,
PyObject *value)
@ -1146,6 +1146,8 @@ insert_to_emptydict(PyDictObject *mp, PyObject *key, Py_hash_t hash,
PyDictKeysObject *newkeys = new_keys_object(PyDict_LOG_MINSIZE);
if (newkeys == NULL) {
Py_DECREF(key);
Py_DECREF(value);
return -1;
}
if (!PyUnicode_CheckExact(key)) {
@ -1155,8 +1157,6 @@ insert_to_emptydict(PyDictObject *mp, PyObject *key, Py_hash_t hash,
mp->ma_keys = newkeys;
mp->ma_values = NULL;
Py_INCREF(key);
Py_INCREF(value);
MAINTAIN_TRACKING(mp, key, value);
size_t hashpos = (size_t)hash & (PyDict_MINSIZE-1);
@ -1529,6 +1529,31 @@ _PyDict_LoadGlobal(PyDictObject *globals, PyDictObject *builtins, PyObject *key)
return value;
}
/* Consumes references to key and value */
int
_PyDict_SetItem_Take2(PyDictObject *mp, PyObject *key, PyObject *value)
{
assert(key);
assert(value);
assert(PyDict_Check(mp));
Py_hash_t hash;
if (!PyUnicode_CheckExact(key) ||
(hash = ((PyASCIIObject *) key)->hash) == -1)
{
hash = PyObject_Hash(key);
if (hash == -1) {
Py_DECREF(key);
Py_DECREF(value);
return -1;
}
}
if (mp->ma_keys == Py_EMPTY_KEYS) {
return insert_to_emptydict(mp, key, hash, value);
}
/* insertdict() handles any resizing that might be necessary */
return insertdict(mp, key, hash, value);
}
/* CAUTION: PyDict_SetItem() must guarantee that it won't resize the
* dictionary if it's merely replacing the value for an existing key.
* This means that it's safe to loop over a dictionary with PyDict_Next()
@ -1538,28 +1563,15 @@ _PyDict_LoadGlobal(PyDictObject *globals, PyDictObject *builtins, PyObject *key)
int
PyDict_SetItem(PyObject *op, PyObject *key, PyObject *value)
{
PyDictObject *mp;
Py_hash_t hash;
if (!PyDict_Check(op)) {
PyErr_BadInternalCall();
return -1;
}
assert(key);
assert(value);
mp = (PyDictObject *)op;
if (!PyUnicode_CheckExact(key) ||
(hash = ((PyASCIIObject *) key)->hash) == -1)
{
hash = PyObject_Hash(key);
if (hash == -1)
return -1;
}
if (mp->ma_keys == Py_EMPTY_KEYS) {
return insert_to_emptydict(mp, key, hash, value);
}
/* insertdict() handles any resizing that might be necessary */
return insertdict(mp, key, hash, value);
Py_INCREF(key);
Py_INCREF(value);
return _PyDict_SetItem_Take2((PyDictObject *)op, key, value);
}
int
@ -1577,6 +1589,8 @@ _PyDict_SetItem_KnownHash(PyObject *op, PyObject *key, PyObject *value,
assert(hash != -1);
mp = (PyDictObject *)op;
Py_INCREF(key);
Py_INCREF(value);
if (mp->ma_keys == Py_EMPTY_KEYS) {
return insert_to_emptydict(mp, key, hash, value);
}
@ -1917,6 +1931,8 @@ _PyDict_FromKeys(PyObject *cls, PyObject *iterable, PyObject *value)
}
while (_PyDict_Next(iterable, &pos, &key, &oldvalue, &hash)) {
Py_INCREF(key);
Py_INCREF(value);
if (insertdict(mp, key, hash, value)) {
Py_DECREF(d);
return NULL;
@ -1936,6 +1952,8 @@ _PyDict_FromKeys(PyObject *cls, PyObject *iterable, PyObject *value)
}
while (_PySet_NextEntry(iterable, &pos, &key, &hash)) {
Py_INCREF(key);
Py_INCREF(value);
if (insertdict(mp, key, hash, value)) {
Py_DECREF(d);
return NULL;
@ -2562,11 +2580,16 @@ dict_merge(PyObject *a, PyObject *b, int override)
int err = 0;
Py_INCREF(key);
Py_INCREF(value);
if (override == 1)
if (override == 1) {
Py_INCREF(key);
Py_INCREF(value);
err = insertdict(mp, key, hash, value);
}
else {
err = _PyDict_Contains_KnownHash(a, key, hash);
if (err == 0) {
Py_INCREF(key);
Py_INCREF(value);
err = insertdict(mp, key, hash, value);
}
else if (err > 0) {
@ -2967,7 +2990,10 @@ PyDict_SetDefault(PyObject *d, PyObject *key, PyObject *defaultobj)
if (hash == -1)
return NULL;
}
if (mp->ma_keys == Py_EMPTY_KEYS) {
Py_INCREF(key);
Py_INCREF(defaultobj);
if (insert_to_emptydict(mp, key, hash, defaultobj) < 0) {
return NULL;
}