mirror of
https://github.com/python/cpython.git
synced 2025-10-09 16:34:44 +00:00
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:
parent
4575c01b75
commit
036fead695
10 changed files with 241 additions and 71 deletions
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue