diff --git a/Include/internal/pycore_opcode_metadata.h b/Include/internal/pycore_opcode_metadata.h index 9bd78f67c6e2d4..918882b921b639 100644 --- a/Include/internal/pycore_opcode_metadata.h +++ b/Include/internal/pycore_opcode_metadata.h @@ -1221,7 +1221,7 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[267] = { [LIST_APPEND] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG }, [LIST_EXTEND] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, [LOAD_ATTR] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, - [LOAD_ATTR_CLASS] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_EXIT_FLAG | HAS_ESCAPES_FLAG }, + [LOAD_ATTR_CLASS] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_EXIT_FLAG | HAS_ESCAPES_FLAG | HAS_RECORDS_VALUE_FLAG }, [LOAD_ATTR_CLASS_WITH_METACLASS_CHECK] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_EXIT_FLAG | HAS_ESCAPES_FLAG | HAS_RECORDS_VALUE_FLAG }, [LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_DEOPT_FLAG | HAS_SYNC_SP_FLAG | HAS_NEEDS_GUARD_IP_FLAG }, [LOAD_ATTR_INSTANCE_VALUE] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ESCAPES_FLAG | HAS_RECORDS_VALUE_FLAG }, @@ -1442,7 +1442,7 @@ _PyOpcode_macro_expansion[256] = { [LIST_APPEND] = { .nuops = 1, .uops = { { _LIST_APPEND, OPARG_SIMPLE, 0 } } }, [LIST_EXTEND] = { .nuops = 2, .uops = { { _LIST_EXTEND, OPARG_SIMPLE, 0 }, { _POP_TOP, OPARG_SIMPLE, 0 } } }, [LOAD_ATTR] = { .nuops = 1, .uops = { { _LOAD_ATTR, OPARG_SIMPLE, 8 } } }, - [LOAD_ATTR_CLASS] = { .nuops = 3, .uops = { { _CHECK_ATTR_CLASS, 2, 1 }, { _LOAD_ATTR_CLASS, 4, 5 }, { _PUSH_NULL_CONDITIONAL, OPARG_SIMPLE, 9 } } }, + [LOAD_ATTR_CLASS] = { .nuops = 4, .uops = { { _RECORD_TOS, OPARG_SIMPLE, 1 }, { _CHECK_ATTR_CLASS, 2, 1 }, { _LOAD_ATTR_CLASS, 4, 5 }, { _PUSH_NULL_CONDITIONAL, OPARG_SIMPLE, 9 } } }, [LOAD_ATTR_CLASS_WITH_METACLASS_CHECK] = { .nuops = 5, .uops = { { _RECORD_TOS_TYPE, OPARG_SIMPLE, 1 }, { _GUARD_TYPE_VERSION, 2, 1 }, { _CHECK_ATTR_CLASS, 2, 3 }, { _LOAD_ATTR_CLASS, 4, 5 }, { _PUSH_NULL_CONDITIONAL, OPARG_SIMPLE, 9 } } }, [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 } } }, diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 34e3885a93c8bd..3f86dc9e6ca0d6 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -2906,6 +2906,7 @@ dummy_func( macro(LOAD_ATTR_CLASS) = unused/1 + + _RECORD_TOS + _CHECK_ATTR_CLASS + unused/2 + _LOAD_ATTR_CLASS + diff --git a/Python/optimizer_bytecodes.c b/Python/optimizer_bytecodes.c index c12a4f4131bc7e..bbea807fbf3ecb 100644 --- a/Python/optimizer_bytecodes.c +++ b/Python/optimizer_bytecodes.c @@ -219,8 +219,8 @@ dummy_func(void) { } op(_CHECK_ATTR_CLASS, (type_version/2, owner -- owner)) { - PyObject *type = (PyObject *)_PyType_LookupByVersion(type_version); - if (type) { + PyObject *type = sym_get_probable_value(owner); + if (type != NULL && ((PyTypeObject *)type)->tp_version_tag == type_version) { if (type == sym_get_const(ctx, owner)) { ADD_OP(_NOP, 0, 0); } @@ -236,19 +236,10 @@ dummy_func(void) { if (sym_matches_type_version(owner, type_version)) { ADD_OP(_NOP, 0, 0); } else { - // add watcher so that whenever the type changes we invalidate this - PyTypeObject *type = _PyType_LookupByVersion(type_version); - // if the type is null, it was not found in the cache (there was a conflict) - // with the key, in which case we can't trust the version - if (type) { - // if the type version was set properly, then add a watcher - // if it wasn't this means that the type version was previously set to something else - // and we set the owner to bottom, so we don't need to add a watcher because we must have - // already added one earlier. - if (sym_set_type_version(owner, type_version)) { - PyType_Watch(TYPE_WATCHER_ID, (PyObject *)type); - _Py_BloomFilter_Add(dependencies, type); - } + PyTypeObject *probable_type = sym_get_probable_type(owner); + if (probable_type->tp_version_tag == type_version && sym_set_type_version(owner, type_version)) { + PyType_Watch(TYPE_WATCHER_ID, (PyObject *)probable_type); + _Py_BloomFilter_Add(dependencies, probable_type); } } } diff --git a/Python/optimizer_cases.c.h b/Python/optimizer_cases.c.h index 2db2c87cb3610b..cf5ffae07bdb7a 100644 --- a/Python/optimizer_cases.c.h +++ b/Python/optimizer_cases.c.h @@ -2430,12 +2430,10 @@ if (sym_matches_type_version(owner, type_version)) { ADD_OP(_NOP, 0, 0); } else { - PyTypeObject *type = _PyType_LookupByVersion(type_version); - if (type) { - if (sym_set_type_version(owner, type_version)) { - PyType_Watch(TYPE_WATCHER_ID, (PyObject *)type); - _Py_BloomFilter_Add(dependencies, type); - } + PyTypeObject *probable_type = sym_get_probable_type(owner); + if (probable_type->tp_version_tag == type_version && sym_set_type_version(owner, type_version)) { + PyType_Watch(TYPE_WATCHER_ID, (PyObject *)probable_type); + _Py_BloomFilter_Add(dependencies, probable_type); } } break; @@ -2564,8 +2562,8 @@ JitOptRef owner; owner = stack_pointer[-1]; uint32_t type_version = (uint32_t)this_instr->operand0; - PyObject *type = (PyObject *)_PyType_LookupByVersion(type_version); - if (type) { + PyObject *type = sym_get_probable_value(owner); + if (type != NULL && ((PyTypeObject *)type)->tp_version_tag == type_version) { if (type == sym_get_const(ctx, owner)) { ADD_OP(_NOP, 0, 0); } diff --git a/Python/record_functions.c.h b/Python/record_functions.c.h index 02b8538bc902b5..3c0eb9a507cbc6 100644 --- a/Python/record_functions.c.h +++ b/Python/record_functions.c.h @@ -88,10 +88,11 @@ void _PyOpcode_RecordFunction_CODE(_PyInterpreterFrame *frame, _PyStackRef *stac #define _RECORD_TOS_TYPE_INDEX 1 #define _RECORD_NOS_INDEX 2 #define _RECORD_3OS_GEN_FUNC_INDEX 3 -#define _RECORD_NOS_GEN_FUNC_INDEX 4 -#define _RECORD_CALLABLE_INDEX 5 -#define _RECORD_BOUND_METHOD_INDEX 6 -#define _RECORD_4OS_INDEX 7 +#define _RECORD_TOS_INDEX 4 +#define _RECORD_NOS_GEN_FUNC_INDEX 5 +#define _RECORD_CALLABLE_INDEX 6 +#define _RECORD_BOUND_METHOD_INDEX 7 +#define _RECORD_4OS_INDEX 8 const uint8_t _PyOpcode_RecordFunctionIndices[256] = { [TO_BOOL_ALWAYS_TRUE] = _RECORD_TOS_TYPE_INDEX, [BINARY_OP_SUBSCR_GETITEM] = _RECORD_NOS_INDEX, @@ -100,6 +101,7 @@ const uint8_t _PyOpcode_RecordFunctionIndices[256] = { [LOAD_ATTR_INSTANCE_VALUE] = _RECORD_TOS_TYPE_INDEX, [LOAD_ATTR_WITH_HINT] = _RECORD_TOS_TYPE_INDEX, [LOAD_ATTR_SLOT] = _RECORD_TOS_TYPE_INDEX, + [LOAD_ATTR_CLASS] = _RECORD_TOS_INDEX, [LOAD_ATTR_CLASS_WITH_METACLASS_CHECK] = _RECORD_TOS_TYPE_INDEX, [LOAD_ATTR_PROPERTY] = _RECORD_TOS_TYPE_INDEX, [STORE_ATTR_INSTANCE_VALUE] = _RECORD_TOS_TYPE_INDEX, @@ -127,11 +129,12 @@ const uint8_t _PyOpcode_RecordFunctionIndices[256] = { [CALL_EX_PY] = _RECORD_4OS_INDEX, }; -const _Py_RecordFuncPtr _PyOpcode_RecordFunctions[8] = { +const _Py_RecordFuncPtr _PyOpcode_RecordFunctions[9] = { [0] = NULL, [_RECORD_TOS_TYPE_INDEX] = _PyOpcode_RecordFunction_TOS_TYPE, [_RECORD_NOS_INDEX] = _PyOpcode_RecordFunction_NOS, [_RECORD_3OS_GEN_FUNC_INDEX] = _PyOpcode_RecordFunction_3OS_GEN_FUNC, + [_RECORD_TOS_INDEX] = _PyOpcode_RecordFunction_TOS, [_RECORD_NOS_GEN_FUNC_INDEX] = _PyOpcode_RecordFunction_NOS_GEN_FUNC, [_RECORD_CALLABLE_INDEX] = _PyOpcode_RecordFunction_CALLABLE, [_RECORD_BOUND_METHOD_INDEX] = _PyOpcode_RecordFunction_BOUND_METHOD,