mirror of
https://github.com/python/cpython.git
synced 2026-06-28 11:50:50 +00:00
gh-150490: Raise PyType_Modified for insertion into split dictionary (#150489)
Raise PyType_Modified for insertion into split dictionary
This commit is contained in:
parent
6112d70abe
commit
efb2fffae1
12 changed files with 1300 additions and 1412 deletions
|
|
@ -90,6 +90,8 @@ typedef struct {
|
|||
} PyDictUnicodeEntry;
|
||||
|
||||
extern PyDictKeysObject *_PyDict_NewKeysForClass(PyHeapTypeObject *);
|
||||
extern void _PyDict_RemoveKeysForClass(PyHeapTypeObject *);
|
||||
extern void _PyDict_SplitKeysInvalidated(PyDictKeysObject* keys);
|
||||
extern PyObject *_PyDict_FromKeys(PyObject *, PyObject *, PyObject *);
|
||||
|
||||
/* Implementations of the `|` and `|=` operators for dict, used by the
|
||||
|
|
@ -239,6 +241,17 @@ struct _dictkeysobject {
|
|||
see the DK_ENTRIES() / DK_UNICODE_ENTRIES() functions below */
|
||||
};
|
||||
|
||||
struct _instancekeysobject {
|
||||
PyTypeObject* dsk_owning_type;
|
||||
struct _dictkeysobject dsk_keys;
|
||||
};
|
||||
|
||||
static inline struct _instancekeysobject *_PyDictKeys_AsSharedKeys(struct _dictkeysobject *keys)
|
||||
{
|
||||
assert(keys->dk_kind == DICT_KEYS_SPLIT);
|
||||
return _Py_CONTAINER_OF(keys, struct _instancekeysobject, dsk_keys);
|
||||
}
|
||||
|
||||
/* This must be no more than 250, for the prefix size to fit in one byte. */
|
||||
#define SHARED_KEYS_MAX_SIZE 30
|
||||
#define NEXT_LOG2_SHARED_KEYS_MAX_SIZE 6
|
||||
|
|
|
|||
4
Include/internal/pycore_opcode_metadata.h
generated
4
Include/internal/pycore_opcode_metadata.h
generated
|
|
@ -1476,10 +1476,10 @@ _PyOpcode_macro_expansion[256] = {
|
|||
[LOAD_ATTR_INSTANCE_VALUE] = { .nuops = 6, .uops = { { _RECORD_TOS_TYPE, OPARG_SIMPLE, 1 }, { _GUARD_TYPE_VERSION, 2, 1 }, { _CHECK_MANAGED_OBJECT_HAS_VALUES, OPARG_SIMPLE, 3 }, { _LOAD_ATTR_INSTANCE_VALUE, 1, 3 }, { _POP_TOP, OPARG_SIMPLE, 4 }, { _PUSH_NULL_CONDITIONAL, OPARG_SIMPLE, 9 } } },
|
||||
[LOAD_ATTR_METHOD_LAZY_DICT] = { .nuops = 4, .uops = { { _RECORD_TOS_TYPE, OPARG_SIMPLE, 1 }, { _GUARD_TYPE_VERSION, 2, 1 }, { _CHECK_ATTR_METHOD_LAZY_DICT, 1, 3 }, { _LOAD_ATTR_METHOD_LAZY_DICT, 4, 5 } } },
|
||||
[LOAD_ATTR_METHOD_NO_DICT] = { .nuops = 3, .uops = { { _RECORD_TOS_TYPE, OPARG_SIMPLE, 1 }, { _GUARD_TYPE_VERSION, 2, 1 }, { _LOAD_ATTR_METHOD_NO_DICT, 4, 5 } } },
|
||||
[LOAD_ATTR_METHOD_WITH_VALUES] = { .nuops = 5, .uops = { { _RECORD_TOS_TYPE, OPARG_SIMPLE, 1 }, { _GUARD_TYPE_VERSION, 2, 1 }, { _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT, OPARG_SIMPLE, 3 }, { _GUARD_KEYS_VERSION, 2, 3 }, { _LOAD_ATTR_METHOD_WITH_VALUES, 4, 5 } } },
|
||||
[LOAD_ATTR_METHOD_WITH_VALUES] = { .nuops = 4, .uops = { { _RECORD_TOS_TYPE, OPARG_SIMPLE, 1 }, { _GUARD_TYPE_VERSION, 2, 1 }, { _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT, OPARG_SIMPLE, 3 }, { _LOAD_ATTR_METHOD_WITH_VALUES, 4, 5 } } },
|
||||
[LOAD_ATTR_MODULE] = { .nuops = 4, .uops = { { _LOAD_ATTR_MODULE, 2, 1 }, { _LOAD_ATTR_MODULE, OPERAND1_1, 3 }, { _POP_TOP, OPARG_SIMPLE, 4 }, { _PUSH_NULL_CONDITIONAL, OPARG_SIMPLE, 9 } } },
|
||||
[LOAD_ATTR_NONDESCRIPTOR_NO_DICT] = { .nuops = 3, .uops = { { _RECORD_TOS_TYPE, OPARG_SIMPLE, 1 }, { _GUARD_TYPE_VERSION, 2, 1 }, { _LOAD_ATTR_NONDESCRIPTOR_NO_DICT, 4, 5 } } },
|
||||
[LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES] = { .nuops = 5, .uops = { { _RECORD_TOS_TYPE, OPARG_SIMPLE, 1 }, { _GUARD_TYPE_VERSION, 2, 1 }, { _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT, OPARG_SIMPLE, 3 }, { _GUARD_KEYS_VERSION, 2, 3 }, { _LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES, 4, 5 } } },
|
||||
[LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES] = { .nuops = 4, .uops = { { _RECORD_TOS_TYPE, OPARG_SIMPLE, 1 }, { _GUARD_TYPE_VERSION, 2, 1 }, { _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT, OPARG_SIMPLE, 3 }, { _LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES, 4, 5 } } },
|
||||
[LOAD_ATTR_PROPERTY] = { .nuops = 7, .uops = { { _RECORD_TOS_TYPE, OPARG_SIMPLE, 1 }, { _GUARD_TYPE_VERSION, 2, 1 }, { _CHECK_PEP_523, OPARG_SIMPLE, 3 }, { _LOAD_ATTR_PROPERTY_FRAME, 2, 3 }, { _LOAD_ATTR_PROPERTY_FRAME, OPERAND1_4, 5 }, { _SAVE_RETURN_OFFSET, OPARG_SAVE_RETURN_OFFSET, 9 }, { _PUSH_FRAME, OPARG_SIMPLE, 9 } } },
|
||||
[LOAD_ATTR_SLOT] = { .nuops = 5, .uops = { { _RECORD_TOS_TYPE, OPARG_SIMPLE, 1 }, { _GUARD_TYPE_VERSION, 2, 1 }, { _LOAD_ATTR_SLOT, 1, 3 }, { _POP_TOP, OPARG_SIMPLE, 4 }, { _PUSH_NULL_CONDITIONAL, OPARG_SIMPLE, 9 } } },
|
||||
[LOAD_ATTR_WITH_HINT] = { .nuops = 5, .uops = { { _RECORD_TOS_TYPE, OPARG_SIMPLE, 1 }, { _GUARD_TYPE_VERSION, 2, 1 }, { _LOAD_ATTR_WITH_HINT, 1, 3 }, { _POP_TOP, OPARG_SIMPLE, 4 }, { _PUSH_NULL_CONDITIONAL, OPARG_SIMPLE, 9 } } },
|
||||
|
|
|
|||
2391
Include/internal/pycore_uop_ids.h
generated
2391
Include/internal/pycore_uop_ids.h
generated
File diff suppressed because it is too large
Load diff
21
Include/internal/pycore_uop_metadata.h
generated
21
Include/internal/pycore_uop_metadata.h
generated
|
|
@ -287,7 +287,6 @@ const uint32_t _PyUop_Flags[MAX_UOP_ID+1] = {
|
|||
[_WITH_EXCEPT_START] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG,
|
||||
[_PUSH_EXC_INFO] = 0,
|
||||
[_GUARD_DORV_VALUES_INST_ATTR_FROM_DICT] = HAS_EXIT_FLAG,
|
||||
[_GUARD_KEYS_VERSION] = HAS_EXIT_FLAG,
|
||||
[_LOAD_ATTR_METHOD_WITH_VALUES] = HAS_ARG_FLAG,
|
||||
[_LOAD_ATTR_METHOD_NO_DICT] = HAS_ARG_FLAG,
|
||||
[_LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES] = HAS_ARG_FLAG | HAS_ESCAPES_FLAG,
|
||||
|
|
@ -2717,15 +2716,6 @@ const _PyUopCachingInfo _PyUop_Caching[MAX_UOP_ID+1] = {
|
|||
{ 3, 3, _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT_r33 },
|
||||
},
|
||||
},
|
||||
[_GUARD_KEYS_VERSION] = {
|
||||
.best = { 0, 1, 2, 3 },
|
||||
.entries = {
|
||||
{ 1, 0, _GUARD_KEYS_VERSION_r01 },
|
||||
{ 1, 1, _GUARD_KEYS_VERSION_r11 },
|
||||
{ 2, 2, _GUARD_KEYS_VERSION_r22 },
|
||||
{ 3, 3, _GUARD_KEYS_VERSION_r33 },
|
||||
},
|
||||
},
|
||||
[_LOAD_ATTR_METHOD_WITH_VALUES] = {
|
||||
.best = { 0, 1, 2, 2 },
|
||||
.entries = {
|
||||
|
|
@ -4543,10 +4533,6 @@ const uint16_t _PyUop_Uncached[MAX_UOP_REGS_ID+1] = {
|
|||
[_GUARD_DORV_VALUES_INST_ATTR_FROM_DICT_r11] = _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT,
|
||||
[_GUARD_DORV_VALUES_INST_ATTR_FROM_DICT_r22] = _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT,
|
||||
[_GUARD_DORV_VALUES_INST_ATTR_FROM_DICT_r33] = _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT,
|
||||
[_GUARD_KEYS_VERSION_r01] = _GUARD_KEYS_VERSION,
|
||||
[_GUARD_KEYS_VERSION_r11] = _GUARD_KEYS_VERSION,
|
||||
[_GUARD_KEYS_VERSION_r22] = _GUARD_KEYS_VERSION,
|
||||
[_GUARD_KEYS_VERSION_r33] = _GUARD_KEYS_VERSION,
|
||||
[_LOAD_ATTR_METHOD_WITH_VALUES_r02] = _LOAD_ATTR_METHOD_WITH_VALUES,
|
||||
[_LOAD_ATTR_METHOD_WITH_VALUES_r12] = _LOAD_ATTR_METHOD_WITH_VALUES,
|
||||
[_LOAD_ATTR_METHOD_WITH_VALUES_r23] = _LOAD_ATTR_METHOD_WITH_VALUES,
|
||||
|
|
@ -5473,11 +5459,6 @@ const char *const _PyOpcode_uop_name[MAX_UOP_REGS_ID+1] = {
|
|||
[_GUARD_ITER_VIRTUAL_r11] = "_GUARD_ITER_VIRTUAL_r11",
|
||||
[_GUARD_ITER_VIRTUAL_r22] = "_GUARD_ITER_VIRTUAL_r22",
|
||||
[_GUARD_ITER_VIRTUAL_r33] = "_GUARD_ITER_VIRTUAL_r33",
|
||||
[_GUARD_KEYS_VERSION] = "_GUARD_KEYS_VERSION",
|
||||
[_GUARD_KEYS_VERSION_r01] = "_GUARD_KEYS_VERSION_r01",
|
||||
[_GUARD_KEYS_VERSION_r11] = "_GUARD_KEYS_VERSION_r11",
|
||||
[_GUARD_KEYS_VERSION_r22] = "_GUARD_KEYS_VERSION_r22",
|
||||
[_GUARD_KEYS_VERSION_r33] = "_GUARD_KEYS_VERSION_r33",
|
||||
[_GUARD_LOAD_SUPER_ATTR_METHOD] = "_GUARD_LOAD_SUPER_ATTR_METHOD",
|
||||
[_GUARD_LOAD_SUPER_ATTR_METHOD_r03] = "_GUARD_LOAD_SUPER_ATTR_METHOD_r03",
|
||||
[_GUARD_LOAD_SUPER_ATTR_METHOD_r13] = "_GUARD_LOAD_SUPER_ATTR_METHOD_r13",
|
||||
|
|
@ -6728,8 +6709,6 @@ int _PyUop_num_popped(int opcode, int oparg)
|
|||
return 1;
|
||||
case _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT:
|
||||
return 0;
|
||||
case _GUARD_KEYS_VERSION:
|
||||
return 0;
|
||||
case _LOAD_ATTR_METHOD_WITH_VALUES:
|
||||
return 1;
|
||||
case _LOAD_ATTR_METHOD_NO_DICT:
|
||||
|
|
|
|||
26
Modules/_testinternalcapi/test_cases.c.h
generated
26
Modules/_testinternalcapi/test_cases.c.h
generated
|
|
@ -8773,18 +8773,7 @@
|
|||
JUMP_TO_PREDICTED(LOAD_ATTR);
|
||||
}
|
||||
}
|
||||
// _GUARD_KEYS_VERSION
|
||||
{
|
||||
uint32_t keys_version = read_u32(&this_instr[4].cache);
|
||||
PyTypeObject *owner_cls = Py_TYPE(PyStackRef_AsPyObjectBorrow(owner));
|
||||
PyHeapTypeObject *owner_heap_type = (PyHeapTypeObject *)owner_cls;
|
||||
PyDictKeysObject *keys = owner_heap_type->ht_cached_keys;
|
||||
if (FT_ATOMIC_LOAD_UINT32_RELAXED(keys->dk_version) != keys_version) {
|
||||
UPDATE_MISS_STATS(LOAD_ATTR);
|
||||
assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR));
|
||||
JUMP_TO_PREDICTED(LOAD_ATTR);
|
||||
}
|
||||
}
|
||||
/* Skip 2 cache entries */
|
||||
// _LOAD_ATTR_METHOD_WITH_VALUES
|
||||
{
|
||||
PyObject *descr = read_obj(&this_instr[6].cache);
|
||||
|
|
@ -8967,18 +8956,7 @@
|
|||
JUMP_TO_PREDICTED(LOAD_ATTR);
|
||||
}
|
||||
}
|
||||
// _GUARD_KEYS_VERSION
|
||||
{
|
||||
uint32_t keys_version = read_u32(&this_instr[4].cache);
|
||||
PyTypeObject *owner_cls = Py_TYPE(PyStackRef_AsPyObjectBorrow(owner));
|
||||
PyHeapTypeObject *owner_heap_type = (PyHeapTypeObject *)owner_cls;
|
||||
PyDictKeysObject *keys = owner_heap_type->ht_cached_keys;
|
||||
if (FT_ATOMIC_LOAD_UINT32_RELAXED(keys->dk_version) != keys_version) {
|
||||
UPDATE_MISS_STATS(LOAD_ATTR);
|
||||
assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR));
|
||||
JUMP_TO_PREDICTED(LOAD_ATTR);
|
||||
}
|
||||
}
|
||||
/* Skip 2 cache entries */
|
||||
// _LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES
|
||||
{
|
||||
PyObject *descr = read_obj(&this_instr[6].cache);
|
||||
|
|
|
|||
|
|
@ -784,16 +784,12 @@ _PyDict_CheckConsistency(PyObject *op, int check_content)
|
|||
}
|
||||
|
||||
|
||||
static PyDictKeysObject*
|
||||
new_keys_object(uint8_t log2_size, bool unicode)
|
||||
static inline int
|
||||
get_log2_bytes(uint8_t log2_size)
|
||||
{
|
||||
Py_ssize_t usable;
|
||||
int log2_bytes;
|
||||
size_t entry_size = unicode ? sizeof(PyDictUnicodeEntry) : sizeof(PyDictKeyEntry);
|
||||
|
||||
assert(log2_size >= PyDict_LOG_MINSIZE);
|
||||
|
||||
usable = USABLE_FRACTION((size_t)1<<log2_size);
|
||||
if (log2_size < 8) {
|
||||
log2_bytes = log2_size;
|
||||
}
|
||||
|
|
@ -809,6 +805,38 @@ new_keys_object(uint8_t log2_size, bool unicode)
|
|||
log2_bytes = log2_size + 2;
|
||||
}
|
||||
|
||||
return log2_bytes;
|
||||
}
|
||||
|
||||
static inline void
|
||||
init_keys_object(PyDictKeysObject* dk, uint8_t log2_size, int log2_bytes, int kind,
|
||||
Py_ssize_t usable, Py_ssize_t entry_size)
|
||||
{
|
||||
#ifdef Py_REF_DEBUG
|
||||
_Py_IncRefTotal(_PyThreadState_GET());
|
||||
#endif
|
||||
dk->dk_refcnt = 1;
|
||||
dk->dk_log2_size = log2_size;
|
||||
dk->dk_log2_index_bytes = log2_bytes;
|
||||
dk->dk_kind = kind;
|
||||
#ifdef Py_GIL_DISABLED
|
||||
dk->dk_mutex = (PyMutex){0};
|
||||
#endif
|
||||
dk->dk_nentries = 0;
|
||||
dk->dk_usable = usable;
|
||||
dk->dk_version = 0;
|
||||
memset(&dk->dk_indices[0], 0xff, ((size_t)1 << log2_bytes));
|
||||
memset(&dk->dk_indices[(size_t)1 << log2_bytes], 0, entry_size * usable);
|
||||
}
|
||||
|
||||
static PyDictKeysObject*
|
||||
new_keys_object(uint8_t log2_size, bool unicode)
|
||||
{
|
||||
Py_ssize_t usable = USABLE_FRACTION((size_t)1<<log2_size);
|
||||
size_t entry_size = unicode ? sizeof(PyDictUnicodeEntry) : sizeof(PyDictKeyEntry);
|
||||
|
||||
int log2_bytes = get_log2_bytes(log2_size);
|
||||
|
||||
PyDictKeysObject *dk = NULL;
|
||||
if (log2_size == PyDict_LOG_MINSIZE && unicode) {
|
||||
dk = _Py_FREELIST_POP_MEM(dictkeys);
|
||||
|
|
@ -822,30 +850,28 @@ new_keys_object(uint8_t log2_size, bool unicode)
|
|||
return NULL;
|
||||
}
|
||||
}
|
||||
#ifdef Py_REF_DEBUG
|
||||
_Py_IncRefTotal(_PyThreadState_GET());
|
||||
#endif
|
||||
dk->dk_refcnt = 1;
|
||||
dk->dk_log2_size = log2_size;
|
||||
dk->dk_log2_index_bytes = log2_bytes;
|
||||
dk->dk_kind = unicode ? DICT_KEYS_UNICODE : DICT_KEYS_GENERAL;
|
||||
#ifdef Py_GIL_DISABLED
|
||||
dk->dk_mutex = (PyMutex){0};
|
||||
#endif
|
||||
dk->dk_nentries = 0;
|
||||
dk->dk_usable = usable;
|
||||
dk->dk_version = 0;
|
||||
memset(&dk->dk_indices[0], 0xff, ((size_t)1 << log2_bytes));
|
||||
memset(&dk->dk_indices[(size_t)1 << log2_bytes], 0, entry_size * usable);
|
||||
init_keys_object(dk, log2_size, log2_bytes,
|
||||
unicode ? DICT_KEYS_UNICODE : DICT_KEYS_GENERAL,
|
||||
usable, entry_size);
|
||||
return dk;
|
||||
}
|
||||
|
||||
static void
|
||||
free_keys_object(PyDictKeysObject *keys, bool use_qsbr)
|
||||
{
|
||||
void *ptr = keys;
|
||||
#ifdef Py_GIL_DISABLED
|
||||
size_t size = _PyDict_KeysSize(keys);
|
||||
#endif
|
||||
if (keys->dk_kind == DICT_KEYS_SPLIT) {
|
||||
ptr = _PyDictKeys_AsSharedKeys(keys);
|
||||
#ifdef Py_GIL_DISABLED
|
||||
size += offsetof(struct _instancekeysobject, dsk_keys);
|
||||
#endif
|
||||
}
|
||||
#ifdef Py_GIL_DISABLED
|
||||
if (use_qsbr) {
|
||||
_PyMem_FreeDelayed(keys, _PyDict_KeysSize(keys));
|
||||
_PyMem_FreeDelayed(ptr, size);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
|
@ -853,7 +879,7 @@ free_keys_object(PyDictKeysObject *keys, bool use_qsbr)
|
|||
_Py_FREELIST_FREE(dictkeys, keys, PyMem_Free);
|
||||
}
|
||||
else {
|
||||
PyMem_Free(keys);
|
||||
PyMem_Free(ptr);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1901,6 +1927,7 @@ insert_split_key(PyDictKeysObject *keys, PyObject *key, Py_hash_t hash)
|
|||
if (ix == DKIX_EMPTY && keys->dk_usable > 0) {
|
||||
// Insert into new slot
|
||||
FT_ATOMIC_STORE_UINT32_RELAXED(keys->dk_version, 0);
|
||||
_PyDict_SplitKeysInvalidated(keys);
|
||||
Py_ssize_t hashpos = find_empty_slot(keys, hash);
|
||||
ix = keys->dk_nentries;
|
||||
dictkeys_set_index(keys, hashpos, ix);
|
||||
|
|
@ -7099,16 +7126,24 @@ dictvalues_reversed(PyObject *self, PyObject *Py_UNUSED(ignored))
|
|||
PyDictKeysObject *
|
||||
_PyDict_NewKeysForClass(PyHeapTypeObject *cls)
|
||||
{
|
||||
PyDictKeysObject *keys = new_keys_object(NEXT_LOG2_SHARED_KEYS_MAX_SIZE, 1);
|
||||
if (keys == NULL) {
|
||||
int log2_bytes = get_log2_bytes(NEXT_LOG2_SHARED_KEYS_MAX_SIZE);
|
||||
Py_ssize_t usable = USABLE_FRACTION((size_t)1<<NEXT_LOG2_SHARED_KEYS_MAX_SIZE);
|
||||
|
||||
struct _instancekeysobject *shared_keys =
|
||||
PyMem_Malloc(sizeof(struct _instancekeysobject)
|
||||
+ ((size_t)1 << log2_bytes)
|
||||
+ sizeof(PyDictUnicodeEntry) * usable);
|
||||
if (shared_keys == NULL) {
|
||||
PyErr_Clear();
|
||||
return NULL;
|
||||
}
|
||||
else {
|
||||
assert(keys->dk_nentries == 0);
|
||||
/* Set to max size+1 as it will shrink by one before each new object */
|
||||
keys->dk_usable = SHARED_KEYS_MAX_SIZE;
|
||||
keys->dk_kind = DICT_KEYS_SPLIT;
|
||||
}
|
||||
|
||||
shared_keys->dsk_owning_type = (PyTypeObject *)cls;
|
||||
PyDictKeysObject* keys = &shared_keys->dsk_keys;
|
||||
init_keys_object(keys, NEXT_LOG2_SHARED_KEYS_MAX_SIZE, log2_bytes, DICT_KEYS_SPLIT,
|
||||
SHARED_KEYS_MAX_SIZE, sizeof(PyDictUnicodeEntry));
|
||||
assert(keys->dk_nentries == 0);
|
||||
/* Set to max size+1 as it will shrink by one before each new object */
|
||||
if (cls->ht_type.tp_dict) {
|
||||
PyObject *attrs = PyDict_GetItem(cls->ht_type.tp_dict, &_Py_ID(__static_attributes__));
|
||||
if (attrs != NULL && PyTuple_Check(attrs)) {
|
||||
|
|
@ -7126,6 +7161,25 @@ _PyDict_NewKeysForClass(PyHeapTypeObject *cls)
|
|||
return keys;
|
||||
}
|
||||
|
||||
void
|
||||
_PyDict_RemoveKeysForClass(PyHeapTypeObject *cls)
|
||||
{
|
||||
struct _instancekeysobject *shared_keys = _PyDictKeys_AsSharedKeys(cls->ht_cached_keys);
|
||||
FT_ATOMIC_STORE_PTR_RELEASE(shared_keys->dsk_owning_type, NULL);
|
||||
|
||||
_PyDictKeys_DecRef(cls->ht_cached_keys);
|
||||
}
|
||||
|
||||
void
|
||||
_PyDict_SplitKeysInvalidated(PyDictKeysObject* keys)
|
||||
{
|
||||
struct _instancekeysobject *shared_keys = _PyDictKeys_AsSharedKeys(keys);
|
||||
PyTypeObject *type = FT_ATOMIC_LOAD_PTR_ACQUIRE(shared_keys->dsk_owning_type);
|
||||
if (type) {
|
||||
PyType_Modified(type);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
_PyObject_InitInlineValues(PyObject *obj, PyTypeObject *tp)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -7023,7 +7023,7 @@ type_dealloc(PyObject *self)
|
|||
Py_XDECREF(et->ht_qualname);
|
||||
Py_XDECREF(et->ht_slots);
|
||||
if (et->ht_cached_keys) {
|
||||
_PyDictKeys_DecRef(et->ht_cached_keys);
|
||||
_PyDict_RemoveKeysForClass(et);
|
||||
}
|
||||
Py_XDECREF(et->ht_module);
|
||||
PyMem_Free(et->_ht_tpname);
|
||||
|
|
|
|||
|
|
@ -4265,13 +4265,6 @@ dummy_func(
|
|||
EXIT_IF(!FT_ATOMIC_LOAD_UINT8(ivs->valid));
|
||||
}
|
||||
|
||||
op(_GUARD_KEYS_VERSION, (keys_version/2, owner -- owner)) {
|
||||
PyTypeObject *owner_cls = Py_TYPE(PyStackRef_AsPyObjectBorrow(owner));
|
||||
PyHeapTypeObject *owner_heap_type = (PyHeapTypeObject *)owner_cls;
|
||||
PyDictKeysObject *keys = owner_heap_type->ht_cached_keys;
|
||||
EXIT_IF(FT_ATOMIC_LOAD_UINT32_RELAXED(keys->dk_version) != keys_version);
|
||||
}
|
||||
|
||||
op(_LOAD_ATTR_METHOD_WITH_VALUES, (descr/4, owner -- attr, self)) {
|
||||
assert(oparg & 1);
|
||||
/* Cached method object */
|
||||
|
|
@ -4288,7 +4281,7 @@ dummy_func(
|
|||
_RECORD_TOS_TYPE +
|
||||
_GUARD_TYPE_VERSION +
|
||||
_GUARD_DORV_VALUES_INST_ATTR_FROM_DICT +
|
||||
_GUARD_KEYS_VERSION +
|
||||
unused/2 +
|
||||
_LOAD_ATTR_METHOD_WITH_VALUES;
|
||||
|
||||
op(_LOAD_ATTR_METHOD_NO_DICT, (descr/4, owner -- attr, self)) {
|
||||
|
|
@ -4322,7 +4315,7 @@ dummy_func(
|
|||
_RECORD_TOS_TYPE +
|
||||
_GUARD_TYPE_VERSION +
|
||||
_GUARD_DORV_VALUES_INST_ATTR_FROM_DICT +
|
||||
_GUARD_KEYS_VERSION +
|
||||
unused/2 +
|
||||
_LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES;
|
||||
|
||||
op(_LOAD_ATTR_NONDESCRIPTOR_NO_DICT, (descr/4, owner -- attr)) {
|
||||
|
|
|
|||
97
Python/executor_cases.c.h
generated
97
Python/executor_cases.c.h
generated
|
|
@ -16231,103 +16231,6 @@
|
|||
break;
|
||||
}
|
||||
|
||||
case _GUARD_KEYS_VERSION_r01: {
|
||||
CHECK_CURRENT_CACHED_VALUES(0);
|
||||
ASSERT_WITHIN_STACK_BOUNDS_IGNORING_CACHE(__FILE__, __LINE__);
|
||||
_PyStackRef owner;
|
||||
owner = stack_pointer[-1];
|
||||
uint32_t keys_version = (uint32_t)CURRENT_OPERAND0_32();
|
||||
PyTypeObject *owner_cls = Py_TYPE(PyStackRef_AsPyObjectBorrow(owner));
|
||||
PyHeapTypeObject *owner_heap_type = (PyHeapTypeObject *)owner_cls;
|
||||
PyDictKeysObject *keys = owner_heap_type->ht_cached_keys;
|
||||
if (FT_ATOMIC_LOAD_UINT32_RELAXED(keys->dk_version) != keys_version) {
|
||||
UOP_STAT_INC(uopcode, miss);
|
||||
SET_CURRENT_CACHED_VALUES(0);
|
||||
JUMP_TO_JUMP_TARGET();
|
||||
}
|
||||
_tos_cache0 = owner;
|
||||
SET_CURRENT_CACHED_VALUES(1);
|
||||
stack_pointer += -1;
|
||||
ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__);
|
||||
ASSERT_WITHIN_STACK_BOUNDS_IGNORING_CACHE(__FILE__, __LINE__);
|
||||
break;
|
||||
}
|
||||
|
||||
case _GUARD_KEYS_VERSION_r11: {
|
||||
CHECK_CURRENT_CACHED_VALUES(1);
|
||||
ASSERT_WITHIN_STACK_BOUNDS_IGNORING_CACHE(__FILE__, __LINE__);
|
||||
_PyStackRef owner;
|
||||
_PyStackRef _stack_item_0 = _tos_cache0;
|
||||
owner = _stack_item_0;
|
||||
uint32_t keys_version = (uint32_t)CURRENT_OPERAND0_32();
|
||||
PyTypeObject *owner_cls = Py_TYPE(PyStackRef_AsPyObjectBorrow(owner));
|
||||
PyHeapTypeObject *owner_heap_type = (PyHeapTypeObject *)owner_cls;
|
||||
PyDictKeysObject *keys = owner_heap_type->ht_cached_keys;
|
||||
if (FT_ATOMIC_LOAD_UINT32_RELAXED(keys->dk_version) != keys_version) {
|
||||
UOP_STAT_INC(uopcode, miss);
|
||||
_tos_cache0 = owner;
|
||||
SET_CURRENT_CACHED_VALUES(1);
|
||||
JUMP_TO_JUMP_TARGET();
|
||||
}
|
||||
_tos_cache0 = owner;
|
||||
SET_CURRENT_CACHED_VALUES(1);
|
||||
ASSERT_WITHIN_STACK_BOUNDS_IGNORING_CACHE(__FILE__, __LINE__);
|
||||
break;
|
||||
}
|
||||
|
||||
case _GUARD_KEYS_VERSION_r22: {
|
||||
CHECK_CURRENT_CACHED_VALUES(2);
|
||||
ASSERT_WITHIN_STACK_BOUNDS_IGNORING_CACHE(__FILE__, __LINE__);
|
||||
_PyStackRef owner;
|
||||
_PyStackRef _stack_item_0 = _tos_cache0;
|
||||
_PyStackRef _stack_item_1 = _tos_cache1;
|
||||
owner = _stack_item_1;
|
||||
uint32_t keys_version = (uint32_t)CURRENT_OPERAND0_32();
|
||||
PyTypeObject *owner_cls = Py_TYPE(PyStackRef_AsPyObjectBorrow(owner));
|
||||
PyHeapTypeObject *owner_heap_type = (PyHeapTypeObject *)owner_cls;
|
||||
PyDictKeysObject *keys = owner_heap_type->ht_cached_keys;
|
||||
if (FT_ATOMIC_LOAD_UINT32_RELAXED(keys->dk_version) != keys_version) {
|
||||
UOP_STAT_INC(uopcode, miss);
|
||||
_tos_cache1 = owner;
|
||||
_tos_cache0 = _stack_item_0;
|
||||
SET_CURRENT_CACHED_VALUES(2);
|
||||
JUMP_TO_JUMP_TARGET();
|
||||
}
|
||||
_tos_cache1 = owner;
|
||||
_tos_cache0 = _stack_item_0;
|
||||
SET_CURRENT_CACHED_VALUES(2);
|
||||
ASSERT_WITHIN_STACK_BOUNDS_IGNORING_CACHE(__FILE__, __LINE__);
|
||||
break;
|
||||
}
|
||||
|
||||
case _GUARD_KEYS_VERSION_r33: {
|
||||
CHECK_CURRENT_CACHED_VALUES(3);
|
||||
ASSERT_WITHIN_STACK_BOUNDS_IGNORING_CACHE(__FILE__, __LINE__);
|
||||
_PyStackRef owner;
|
||||
_PyStackRef _stack_item_0 = _tos_cache0;
|
||||
_PyStackRef _stack_item_1 = _tos_cache1;
|
||||
_PyStackRef _stack_item_2 = _tos_cache2;
|
||||
owner = _stack_item_2;
|
||||
uint32_t keys_version = (uint32_t)CURRENT_OPERAND0_32();
|
||||
PyTypeObject *owner_cls = Py_TYPE(PyStackRef_AsPyObjectBorrow(owner));
|
||||
PyHeapTypeObject *owner_heap_type = (PyHeapTypeObject *)owner_cls;
|
||||
PyDictKeysObject *keys = owner_heap_type->ht_cached_keys;
|
||||
if (FT_ATOMIC_LOAD_UINT32_RELAXED(keys->dk_version) != keys_version) {
|
||||
UOP_STAT_INC(uopcode, miss);
|
||||
_tos_cache2 = owner;
|
||||
_tos_cache1 = _stack_item_1;
|
||||
_tos_cache0 = _stack_item_0;
|
||||
SET_CURRENT_CACHED_VALUES(3);
|
||||
JUMP_TO_JUMP_TARGET();
|
||||
}
|
||||
_tos_cache2 = owner;
|
||||
_tos_cache1 = _stack_item_1;
|
||||
_tos_cache0 = _stack_item_0;
|
||||
SET_CURRENT_CACHED_VALUES(3);
|
||||
ASSERT_WITHIN_STACK_BOUNDS_IGNORING_CACHE(__FILE__, __LINE__);
|
||||
break;
|
||||
}
|
||||
|
||||
case _LOAD_ATTR_METHOD_WITH_VALUES_r02: {
|
||||
CHECK_CURRENT_CACHED_VALUES(0);
|
||||
ASSERT_WITHIN_STACK_BOUNDS_IGNORING_CACHE(__FILE__, __LINE__);
|
||||
|
|
|
|||
26
Python/generated_cases.c.h
generated
26
Python/generated_cases.c.h
generated
|
|
@ -8772,18 +8772,7 @@
|
|||
JUMP_TO_PREDICTED(LOAD_ATTR);
|
||||
}
|
||||
}
|
||||
// _GUARD_KEYS_VERSION
|
||||
{
|
||||
uint32_t keys_version = read_u32(&this_instr[4].cache);
|
||||
PyTypeObject *owner_cls = Py_TYPE(PyStackRef_AsPyObjectBorrow(owner));
|
||||
PyHeapTypeObject *owner_heap_type = (PyHeapTypeObject *)owner_cls;
|
||||
PyDictKeysObject *keys = owner_heap_type->ht_cached_keys;
|
||||
if (FT_ATOMIC_LOAD_UINT32_RELAXED(keys->dk_version) != keys_version) {
|
||||
UPDATE_MISS_STATS(LOAD_ATTR);
|
||||
assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR));
|
||||
JUMP_TO_PREDICTED(LOAD_ATTR);
|
||||
}
|
||||
}
|
||||
/* Skip 2 cache entries */
|
||||
// _LOAD_ATTR_METHOD_WITH_VALUES
|
||||
{
|
||||
PyObject *descr = read_obj(&this_instr[6].cache);
|
||||
|
|
@ -8966,18 +8955,7 @@
|
|||
JUMP_TO_PREDICTED(LOAD_ATTR);
|
||||
}
|
||||
}
|
||||
// _GUARD_KEYS_VERSION
|
||||
{
|
||||
uint32_t keys_version = read_u32(&this_instr[4].cache);
|
||||
PyTypeObject *owner_cls = Py_TYPE(PyStackRef_AsPyObjectBorrow(owner));
|
||||
PyHeapTypeObject *owner_heap_type = (PyHeapTypeObject *)owner_cls;
|
||||
PyDictKeysObject *keys = owner_heap_type->ht_cached_keys;
|
||||
if (FT_ATOMIC_LOAD_UINT32_RELAXED(keys->dk_version) != keys_version) {
|
||||
UPDATE_MISS_STATS(LOAD_ATTR);
|
||||
assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR));
|
||||
JUMP_TO_PREDICTED(LOAD_ATTR);
|
||||
}
|
||||
}
|
||||
/* Skip 2 cache entries */
|
||||
// _LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES
|
||||
{
|
||||
PyObject *descr = read_obj(&this_instr[6].cache);
|
||||
|
|
|
|||
4
Python/optimizer_cases.c.h
generated
4
Python/optimizer_cases.c.h
generated
|
|
@ -3941,10 +3941,6 @@
|
|||
break;
|
||||
}
|
||||
|
||||
case _GUARD_KEYS_VERSION: {
|
||||
break;
|
||||
}
|
||||
|
||||
case _LOAD_ATTR_METHOD_WITH_VALUES: {
|
||||
JitOptRef owner;
|
||||
JitOptRef attr;
|
||||
|
|
|
|||
|
|
@ -1285,7 +1285,6 @@ specialize_attr_loadclassattr(PyObject *owner, _Py_CODEUNIT *instr,
|
|||
SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_OUT_OF_VERSIONS);
|
||||
return 0;
|
||||
}
|
||||
write_u32(cache->keys_version, shared_keys_version);
|
||||
specialize(instr, is_method ? LOAD_ATTR_METHOD_WITH_VALUES : LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES);
|
||||
}
|
||||
else {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue