Merge remote-tracking branch 'origin/main' into HEAD

This commit is contained in:
Dino Viehland 2025-11-03 10:10:28 -08:00
commit 8d57aca95a
1284 changed files with 27792 additions and 11927 deletions

View file

@ -1775,6 +1775,14 @@ static inline int
insert_combined_dict(PyInterpreterState *interp, PyDictObject *mp,
Py_hash_t hash, PyObject *key, PyObject *value)
{
// gh-140551: If dict was cleared in _Py_dict_lookup,
// we have to resize one more time to force general key kind.
if (DK_IS_UNICODE(mp->ma_keys) && !PyUnicode_CheckExact(key)) {
if (insertion_resize(mp, 0) < 0)
return -1;
assert(mp->ma_keys->dk_kind == DICT_KEYS_GENERAL);
}
if (mp->ma_keys->dk_usable <= 0) {
/* Need to resize. */
if (insertion_resize(mp, 1) < 0) {
@ -1871,38 +1879,31 @@ insertdict(PyInterpreterState *interp, PyDictObject *mp,
PyObject *key, Py_hash_t hash, PyObject *value)
{
PyObject *old_value;
Py_ssize_t ix;
ASSERT_DICT_LOCKED(mp);
if (DK_IS_UNICODE(mp->ma_keys) && !PyUnicode_CheckExact(key)) {
if (insertion_resize(mp, 0) < 0)
goto Fail;
assert(mp->ma_keys->dk_kind == DICT_KEYS_GENERAL);
}
if (_PyDict_HasSplitTable(mp)) {
Py_ssize_t ix = insert_split_key(mp->ma_keys, key, hash);
if (_PyDict_HasSplitTable(mp) && PyUnicode_CheckExact(key)) {
ix = insert_split_key(mp->ma_keys, key, hash);
if (ix != DKIX_EMPTY) {
insert_split_value(interp, mp, key, value, ix);
Py_DECREF(key);
Py_DECREF(value);
return 0;
}
/* No space in shared keys. Resize and continue below. */
if (insertion_resize(mp, 1) < 0) {
// No space in shared keys. Go to insert_combined_dict() below.
}
else {
ix = _Py_dict_lookup(mp, key, hash, &old_value);
if (ix == DKIX_ERROR)
goto Fail;
}
}
Py_ssize_t ix = _Py_dict_lookup(mp, key, hash, &old_value);
if (ix == DKIX_ERROR)
goto Fail;
if (ix == DKIX_EMPTY) {
assert(!_PyDict_HasSplitTable(mp));
/* Insert into new slot. */
assert(old_value == NULL);
// insert_combined_dict() will convert from non DICT_KEYS_GENERAL table
// into DICT_KEYS_GENERAL table if key is not Unicode.
// We don't convert it before _Py_dict_lookup because non-Unicode key
// may change generic table into Unicode table.
if (insert_combined_dict(interp, mp, hash, key, value) < 0) {
goto Fail;
}
@ -2819,8 +2820,8 @@ PyDict_DelItem(PyObject *op, PyObject *key)
return _PyDict_DelItem_KnownHash(op, key, hash);
}
static int
delitem_knownhash_lock_held(PyObject *op, PyObject *key, Py_hash_t hash)
int
_PyDict_DelItem_KnownHash_LockHeld(PyObject *op, PyObject *key, Py_hash_t hash)
{
Py_ssize_t ix;
PyDictObject *mp;
@ -2855,7 +2856,7 @@ _PyDict_DelItem_KnownHash(PyObject *op, PyObject *key, Py_hash_t hash)
{
int res;
Py_BEGIN_CRITICAL_SECTION(op);
res = delitem_knownhash_lock_held(op, key, hash);
res = _PyDict_DelItem_KnownHash_LockHeld(op, key, hash);
Py_END_CRITICAL_SECTION();
return res;
}
@ -4374,6 +4375,7 @@ dict_setdefault_ref_lock_held(PyObject *d, PyObject *key, PyObject *default_valu
PyDictObject *mp = (PyDictObject *)d;
PyObject *value;
Py_hash_t hash;
Py_ssize_t ix;
PyInterpreterState *interp = _PyInterpreterState_GET();
ASSERT_DICT_LOCKED(d);
@ -4409,17 +4411,8 @@ dict_setdefault_ref_lock_held(PyObject *d, PyObject *key, PyObject *default_valu
return 0;
}
if (!PyUnicode_CheckExact(key) && DK_IS_UNICODE(mp->ma_keys)) {
if (insertion_resize(mp, 0) < 0) {
if (result) {
*result = NULL;
}
return -1;
}
}
if (_PyDict_HasSplitTable(mp)) {
Py_ssize_t ix = insert_split_key(mp->ma_keys, key, hash);
if (_PyDict_HasSplitTable(mp) && PyUnicode_CheckExact(key)) {
ix = insert_split_key(mp->ma_keys, key, hash);
if (ix != DKIX_EMPTY) {
PyObject *value = mp->ma_values->values[ix];
int already_present = value != NULL;
@ -4432,27 +4425,22 @@ dict_setdefault_ref_lock_held(PyObject *d, PyObject *key, PyObject *default_valu
}
return already_present;
}
/* No space in shared keys. Resize and continue below. */
if (insertion_resize(mp, 1) < 0) {
goto error;
}
// No space in shared keys. Go to insert_combined_dict() below.
}
assert(!_PyDict_HasSplitTable(mp));
Py_ssize_t ix = _Py_dict_lookup(mp, key, hash, &value);
if (ix == DKIX_ERROR) {
if (result) {
*result = NULL;
else {
ix = _Py_dict_lookup(mp, key, hash, &value);
if (ix == DKIX_ERROR) {
if (result) {
*result = NULL;
}
return -1;
}
return -1;
}
if (ix == DKIX_EMPTY) {
assert(!_PyDict_HasSplitTable(mp));
value = default_value;
// See comment to this function in insertdict.
if (insert_combined_dict(interp, mp, hash, Py_NewRef(key), Py_NewRef(value)) < 0) {
Py_DECREF(key);
Py_DECREF(value);
@ -4477,12 +4465,6 @@ dict_setdefault_ref_lock_held(PyObject *d, PyObject *key, PyObject *default_valu
*result = incref_result ? Py_NewRef(value) : value;
}
return 1;
error:
if (result) {
*result = NULL;
}
return -1;
}
int
@ -4703,9 +4685,11 @@ dict_tp_clear(PyObject *op)
static PyObject *dictiter_new(PyDictObject *, PyTypeObject *);
static Py_ssize_t
sizeof_lock_held(PyDictObject *mp)
Py_ssize_t
_PyDict_SizeOf_LockHeld(PyDictObject *mp)
{
_Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(mp);
size_t res = _PyObject_SIZE(Py_TYPE(mp));
if (_PyDict_HasSplitTable(mp)) {
res += shared_keys_usable_size(mp->ma_keys) * sizeof(PyObject*);
@ -4732,7 +4716,7 @@ _PyDict_SizeOf(PyDictObject *mp)
{
Py_ssize_t res;
Py_BEGIN_CRITICAL_SECTION(mp);
res = sizeof_lock_held(mp);
res = _PyDict_SizeOf_LockHeld(mp);
Py_END_CRITICAL_SECTION();
return res;
@ -5673,22 +5657,10 @@ dictiter_iternext_threadsafe(PyDictObject *d, PyObject *self,
#endif
static bool
has_unique_reference(PyObject *op)
{
#ifdef Py_GIL_DISABLED
return (_Py_IsOwnedByCurrentThread(op) &&
op->ob_ref_local == 1 &&
_Py_atomic_load_ssize_relaxed(&op->ob_ref_shared) == 0);
#else
return Py_REFCNT(op) == 1;
#endif
}
static bool
acquire_iter_result(PyObject *result)
{
if (has_unique_reference(result)) {
if (_PyObject_IsUniquelyReferenced(result)) {
Py_INCREF(result);
return true;
}
@ -5725,8 +5697,11 @@ dictiter_iternextitem(PyObject *self)
}
else {
result = PyTuple_New(2);
if (result == NULL)
if (result == NULL) {
Py_DECREF(key);
Py_DECREF(value);
return NULL;
}
PyTuple_SET_ITEM(result, 0, key);
PyTuple_SET_ITEM(result, 1, value);
}
@ -5834,7 +5809,7 @@ dictreviter_iter_lock_held(PyDictObject *d, PyObject *self)
}
else if (Py_IS_TYPE(di, &PyDictRevIterItem_Type)) {
result = di->di_result;
if (Py_REFCNT(result) == 1) {
if (_PyObject_IsUniquelyReferenced(result)) {
PyObject *oldkey = PyTuple_GET_ITEM(result, 0);
PyObject *oldvalue = PyTuple_GET_ITEM(result, 1);
PyTuple_SET_ITEM(result, 0, Py_NewRef(key));
@ -6917,7 +6892,7 @@ _PyDict_SetItem_LockHeld(PyDictObject *dict, PyObject *name, PyObject *value)
dict_unhashable_type(name);
return -1;
}
return delitem_knownhash_lock_held((PyObject *)dict, name, hash);
return _PyDict_DelItem_KnownHash_LockHeld((PyObject *)dict, name, hash);
} else {
return setitem_lock_held(dict, name, value);
}