gh-115999: Specialize LOAD_ATTR for instance and class receivers in free-threaded builds (#128164)

Finish specialization for LOAD_ATTR in the free-threaded build by adding support for class and instance receivers.
This commit is contained in:
mpage 2025-01-14 11:56:11 -08:00 committed by GitHub
parent 1c13c56a34
commit b5ee0258bf
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
18 changed files with 619 additions and 271 deletions

View file

@ -1129,6 +1129,24 @@ dictkeys_generic_lookup(PyDictObject *mp, PyDictKeysObject* dk, PyObject *key, P
return do_lookup(mp, dk, key, hash, compare_generic);
}
static bool
check_keys_unicode(PyDictKeysObject *dk, PyObject *key)
{
return PyUnicode_CheckExact(key) && (dk->dk_kind != DICT_KEYS_GENERAL);
}
static Py_ssize_t
hash_unicode_key(PyObject *key)
{
assert(PyUnicode_CheckExact(key));
Py_hash_t hash = unicode_get_hash(key);
if (hash == -1) {
hash = PyUnicode_Type.tp_hash(key);
assert(hash != -1);
}
return hash;
}
#ifdef Py_GIL_DISABLED
static Py_ssize_t
unicodekeys_lookup_unicode_threadsafe(PyDictKeysObject* dk, PyObject *key,
@ -1167,21 +1185,28 @@ unicodekeys_lookup_split(PyDictKeysObject* dk, PyObject *key, Py_hash_t hash)
Py_ssize_t
_PyDictKeys_StringLookup(PyDictKeysObject* dk, PyObject *key)
{
DictKeysKind kind = dk->dk_kind;
if (!PyUnicode_CheckExact(key) || kind == DICT_KEYS_GENERAL) {
if (!check_keys_unicode(dk, key)) {
return DKIX_ERROR;
}
Py_hash_t hash = unicode_get_hash(key);
if (hash == -1) {
hash = PyUnicode_Type.tp_hash(key);
if (hash == -1) {
PyErr_Clear();
return DKIX_ERROR;
}
}
Py_hash_t hash = hash_unicode_key(key);
return unicodekeys_lookup_unicode(dk, key, hash);
}
Py_ssize_t
_PyDictKeys_StringLookupAndVersion(PyDictKeysObject *dk, PyObject *key, uint32_t *version)
{
if (!check_keys_unicode(dk, key)) {
return DKIX_ERROR;
}
Py_ssize_t ix;
Py_hash_t hash = hash_unicode_key(key);
LOCK_KEYS(dk);
ix = unicodekeys_lookup_unicode(dk, key, hash);
*version = _PyDictKeys_GetVersionForCurrentState(_PyInterpreterState_GET(), dk);
UNLOCK_KEYS(dk);
return ix;
}
/* Like _PyDictKeys_StringLookup() but only works on split keys. Note
* that in free-threaded builds this locks the keys object as required.
*/
@ -1926,6 +1951,16 @@ build_indices_unicode(PyDictKeysObject *keys, PyDictUnicodeEntry *ep, Py_ssize_t
}
}
static void
invalidate_and_clear_inline_values(PyDictValues *values)
{
assert(values->embedded);
FT_ATOMIC_STORE_UINT8(values->valid, 0);
for (int i = 0; i < values->capacity; i++) {
FT_ATOMIC_STORE_PTR_RELEASE(values->values[i], NULL);
}
}
/*
Restructure the table by allocating a new table and reinserting all
items again. When entries have been deleted, the new table may
@ -2017,7 +2052,7 @@ dictresize(PyInterpreterState *interp, PyDictObject *mp,
if (oldvalues->embedded) {
assert(oldvalues->embedded == 1);
assert(oldvalues->valid == 1);
FT_ATOMIC_STORE_UINT8(oldvalues->valid, 0);
invalidate_and_clear_inline_values(oldvalues);
}
else {
free_values(oldvalues, IS_DICT_SHARED(mp));
@ -7007,7 +7042,13 @@ _PyObject_TryGetInstanceAttribute(PyObject *obj, PyObject *name, PyObject **attr
#ifdef Py_GIL_DISABLED
PyObject *value = _Py_atomic_load_ptr_acquire(&values->values[ix]);
if (value == NULL || _Py_TryIncrefCompare(&values->values[ix], value)) {
if (value == NULL) {
if (FT_ATOMIC_LOAD_UINT8(values->valid)) {
*attr = NULL;
return true;
}
}
else if (_Py_TryIncrefCompare(&values->values[ix], value)) {
*attr = value;
return true;
}
@ -7345,7 +7386,7 @@ _PyDict_DetachFromObject(PyDictObject *mp, PyObject *obj)
}
mp->ma_values = values;
FT_ATOMIC_STORE_UINT8(_PyObject_InlineValues(obj)->valid, 0);
invalidate_and_clear_inline_values(_PyObject_InlineValues(obj));
assert(_PyObject_InlineValuesConsistencyCheck(obj));
ASSERT_CONSISTENT(mp);