diff --git a/Include/cpython/pystats.h b/Include/cpython/pystats.h index 38480a4f6cd78f..b944d1acac7223 100644 --- a/Include/cpython/pystats.h +++ b/Include/cpython/pystats.h @@ -154,9 +154,9 @@ typedef struct _stats { OptimizationStats optimization_stats; RareEventStats rare_event_stats; GCStats *gc_stats; + uint64_t binary_specialization_failure[1<<15]; } PyStats; - // Export for shared extensions like 'math' PyAPI_DATA(PyStats*) _Py_stats; diff --git a/Include/internal/pycore_code.h b/Include/internal/pycore_code.h index bcbaf60f226c77..aa825fdb3a626d 100644 --- a/Include/internal/pycore_code.h +++ b/Include/internal/pycore_code.h @@ -51,6 +51,7 @@ typedef struct { typedef struct { _Py_BackoffCounter counter; + uint16_t type_versions; } _PyBinaryOpCache; #define INLINE_CACHE_ENTRIES_BINARY_OP CACHE_ENTRIES(_PyBinaryOpCache) @@ -298,6 +299,8 @@ extern void _Py_Specialize_Send(PyObject *receiver, _Py_CODEUNIT *instr); extern void _Py_Specialize_ToBool(PyObject *value, _Py_CODEUNIT *instr); extern void _Py_Specialize_ContainsOp(PyObject *value, _Py_CODEUNIT *instr); + +PyAPI_DATA(const binaryfunc) _Py_BinaryFunctionTable[]; #ifdef Py_STATS #include "pycore_bitutils.h" // _Py_bit_length diff --git a/Include/internal/pycore_list.h b/Include/internal/pycore_list.h index 73695d10e0c372..95716d60591c68 100644 --- a/Include/internal/pycore_list.h +++ b/Include/internal/pycore_list.h @@ -60,6 +60,8 @@ typedef struct { PyAPI_FUNC(PyObject *)_PyList_FromArraySteal(PyObject *const *src, Py_ssize_t n); +extern PyObject *_PyList_Concat(PyListObject *a, PyListObject *b); + #ifdef __cplusplus } #endif diff --git a/Include/internal/pycore_long.h b/Include/internal/pycore_long.h index f04f66d053bab9..41cd2849fcca18 100644 --- a/Include/internal/pycore_long.h +++ b/Include/internal/pycore_long.h @@ -121,9 +121,17 @@ PyAPI_DATA(PyObject*) _PyLong_Rshift(PyObject *, size_t); // Export for 'math' shared extension PyAPI_DATA(PyObject*) _PyLong_Lshift(PyObject *, size_t); +PyAPI_FUNC(PyObject*) _PyLong_Add_1X(PyLongObject *left, PyLongObject *right); +PyAPI_FUNC(PyObject*) _PyLong_Add_X1(PyLongObject *left, PyLongObject *right); PyAPI_FUNC(PyObject*) _PyLong_Add(PyLongObject *left, PyLongObject *right); PyAPI_FUNC(PyObject*) _PyLong_Multiply(PyLongObject *left, PyLongObject *right); PyAPI_FUNC(PyObject*) _PyLong_Subtract(PyLongObject *left, PyLongObject *right); +PyObject* _PyLong_And(PyLongObject *left, PyLongObject *right); +PyObject* _PyLong_Or(PyLongObject *left, PyLongObject *right); +PyObject* _PyLong_Xor(PyLongObject *left, PyLongObject *right); +PyObject* _PyLong_FloorDiv(PyLongObject *left, PyLongObject *right); +PyObject* _PyLong_LShiftObject(PyLongObject *left, PyLongObject *right); +PyObject* _PyLong_RShiftObject(PyLongObject *left, PyLongObject *right); // Export for 'binascii' shared extension. PyAPI_DATA(unsigned char) _PyLong_DigitValue[256]; @@ -311,6 +319,8 @@ _PyLong_FlipSign(PyLongObject *op) { #define _PyLong_FALSE_TAG TAG_FROM_SIGN_AND_SIZE(0, 0) #define _PyLong_TRUE_TAG TAG_FROM_SIGN_AND_SIZE(1, 1) +extern double _PyLong_AsDouble(PyLongObject *l); + #ifdef __cplusplus } #endif diff --git a/Include/internal/pycore_opcode_metadata.h b/Include/internal/pycore_opcode_metadata.h index d3535800139a66..cd92f0d37fa197 100644 --- a/Include/internal/pycore_opcode_metadata.h +++ b/Include/internal/pycore_opcode_metadata.h @@ -39,21 +39,23 @@ int _PyOpcode_num_popped(int opcode, int oparg) { return 1; case BINARY_OP: return 2; - case BINARY_OP_ADD_FLOAT: + case BINARY_OP_1I: return 2; - case BINARY_OP_ADD_INT: + case BINARY_OP_1X: return 2; - case BINARY_OP_ADD_UNICODE: + case BINARY_OP_I1: + return 2; + case BINARY_OP_II: return 2; case BINARY_OP_INPLACE_ADD_UNICODE: return 2; - case BINARY_OP_MULTIPLY_FLOAT: + case BINARY_OP_IX: return 2; - case BINARY_OP_MULTIPLY_INT: + case BINARY_OP_X1: return 2; - case BINARY_OP_SUBTRACT_FLOAT: + case BINARY_OP_XI: return 2; - case BINARY_OP_SUBTRACT_INT: + case BINARY_OP_XX: return 2; case BINARY_SLICE: return 3; @@ -488,21 +490,23 @@ int _PyOpcode_num_pushed(int opcode, int oparg) { return 2; case BINARY_OP: return 1; - case BINARY_OP_ADD_FLOAT: + case BINARY_OP_1I: + return 1; + case BINARY_OP_1X: return 1; - case BINARY_OP_ADD_INT: + case BINARY_OP_I1: return 1; - case BINARY_OP_ADD_UNICODE: + case BINARY_OP_II: return 1; case BINARY_OP_INPLACE_ADD_UNICODE: return 0; - case BINARY_OP_MULTIPLY_FLOAT: + case BINARY_OP_IX: return 1; - case BINARY_OP_MULTIPLY_INT: + case BINARY_OP_X1: return 1; - case BINARY_OP_SUBTRACT_FLOAT: + case BINARY_OP_XI: return 1; - case BINARY_OP_SUBTRACT_INT: + case BINARY_OP_XX: return 1; case BINARY_SLICE: return 1; @@ -930,13 +934,15 @@ int _PyOpcode_num_pushed(int opcode, int oparg) { enum InstructionFormat { INSTR_FMT_IB = 1, INSTR_FMT_IBC = 2, - INSTR_FMT_IBC00 = 3, - INSTR_FMT_IBC000 = 4, - INSTR_FMT_IBC00000000 = 5, - INSTR_FMT_IX = 6, - INSTR_FMT_IXC = 7, - INSTR_FMT_IXC00 = 8, - INSTR_FMT_IXC000 = 9, + INSTR_FMT_IBC0 = 3, + INSTR_FMT_IBC00 = 4, + INSTR_FMT_IBC000 = 5, + INSTR_FMT_IBC00000000 = 6, + INSTR_FMT_IX = 7, + INSTR_FMT_IXC = 8, + INSTR_FMT_IXC0 = 9, + INSTR_FMT_IXC00 = 10, + INSTR_FMT_IXC000 = 11, }; #define IS_VALID_OPCODE(OP) \ @@ -994,15 +1000,16 @@ extern const struct opcode_metadata _PyOpcode_opcode_metadata[264]; const struct opcode_metadata _PyOpcode_opcode_metadata[264] = { [BEFORE_ASYNC_WITH] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, [BEFORE_WITH] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, - [BINARY_OP] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, - [BINARY_OP_ADD_FLOAT] = { true, INSTR_FMT_IXC, HAS_EXIT_FLAG }, - [BINARY_OP_ADD_INT] = { true, INSTR_FMT_IXC, HAS_EXIT_FLAG | HAS_ERROR_FLAG }, - [BINARY_OP_ADD_UNICODE] = { true, INSTR_FMT_IXC, HAS_EXIT_FLAG | HAS_ERROR_FLAG }, - [BINARY_OP_INPLACE_ADD_UNICODE] = { true, INSTR_FMT_IXC, HAS_LOCAL_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, - [BINARY_OP_MULTIPLY_FLOAT] = { true, INSTR_FMT_IXC, HAS_EXIT_FLAG }, - [BINARY_OP_MULTIPLY_INT] = { true, INSTR_FMT_IXC, HAS_EXIT_FLAG | HAS_ERROR_FLAG }, - [BINARY_OP_SUBTRACT_FLOAT] = { true, INSTR_FMT_IXC, HAS_EXIT_FLAG }, - [BINARY_OP_SUBTRACT_INT] = { true, INSTR_FMT_IXC, HAS_EXIT_FLAG | HAS_ERROR_FLAG }, + [BINARY_OP] = { true, INSTR_FMT_IBC0, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, + [BINARY_OP_1I] = { true, INSTR_FMT_IXC0, HAS_EXIT_FLAG | HAS_ERROR_FLAG }, + [BINARY_OP_1X] = { true, INSTR_FMT_IXC0, HAS_EXIT_FLAG | HAS_ERROR_FLAG }, + [BINARY_OP_I1] = { true, INSTR_FMT_IXC0, HAS_EXIT_FLAG | HAS_ERROR_FLAG }, + [BINARY_OP_II] = { true, INSTR_FMT_IXC0, HAS_EXIT_FLAG | HAS_ERROR_FLAG }, + [BINARY_OP_INPLACE_ADD_UNICODE] = { true, INSTR_FMT_IXC0, HAS_LOCAL_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, + [BINARY_OP_IX] = { true, INSTR_FMT_IXC0, HAS_EXIT_FLAG | HAS_ERROR_FLAG }, + [BINARY_OP_X1] = { true, INSTR_FMT_IXC0, HAS_EXIT_FLAG | HAS_ERROR_FLAG }, + [BINARY_OP_XI] = { true, INSTR_FMT_IXC0, HAS_EXIT_FLAG | HAS_ERROR_FLAG }, + [BINARY_OP_XX] = { true, INSTR_FMT_IXC0, HAS_EXIT_FLAG | HAS_ERROR_FLAG }, [BINARY_SLICE] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [BINARY_SUBSCR] = { true, INSTR_FMT_IXC, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [BINARY_SUBSCR_DICT] = { true, INSTR_FMT_IXC, HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, @@ -1225,13 +1232,14 @@ extern const struct opcode_macro_expansion _PyOpcode_macro_expansion[256]; const struct opcode_macro_expansion _PyOpcode_macro_expansion[256] = { [BINARY_OP] = { .nuops = 1, .uops = { { _BINARY_OP, 0, 0 } } }, - [BINARY_OP_ADD_FLOAT] = { .nuops = 2, .uops = { { _GUARD_BOTH_FLOAT, 0, 0 }, { _BINARY_OP_ADD_FLOAT, 0, 0 } } }, - [BINARY_OP_ADD_INT] = { .nuops = 2, .uops = { { _GUARD_BOTH_INT, 0, 0 }, { _BINARY_OP_ADD_INT, 0, 0 } } }, - [BINARY_OP_ADD_UNICODE] = { .nuops = 2, .uops = { { _GUARD_BOTH_UNICODE, 0, 0 }, { _BINARY_OP_ADD_UNICODE, 0, 0 } } }, - [BINARY_OP_MULTIPLY_FLOAT] = { .nuops = 2, .uops = { { _GUARD_BOTH_FLOAT, 0, 0 }, { _BINARY_OP_MULTIPLY_FLOAT, 0, 0 } } }, - [BINARY_OP_MULTIPLY_INT] = { .nuops = 2, .uops = { { _GUARD_BOTH_INT, 0, 0 }, { _BINARY_OP_MULTIPLY_INT, 0, 0 } } }, - [BINARY_OP_SUBTRACT_FLOAT] = { .nuops = 2, .uops = { { _GUARD_BOTH_FLOAT, 0, 0 }, { _BINARY_OP_SUBTRACT_FLOAT, 0, 0 } } }, - [BINARY_OP_SUBTRACT_INT] = { .nuops = 2, .uops = { { _GUARD_BOTH_INT, 0, 0 }, { _BINARY_OP_SUBTRACT_INT, 0, 0 } } }, + [BINARY_OP_1I] = { .nuops = 4, .uops = { { _GUARD_NOS_REFCNT1, 0, 0 }, { _GUARD_TOS_IMMORTAL, 0, 0 }, { _GUARD_VERSION_TYPES, 1, 1 }, { _BINARY_OP_TABLE_NN, 1, 1 } } }, + [BINARY_OP_1X] = { .nuops = 3, .uops = { { _GUARD_NOS_REFCNT1, 0, 0 }, { _GUARD_VERSION_TYPES, 1, 1 }, { _BINARY_OP_TABLE_ND, 1, 1 } } }, + [BINARY_OP_I1] = { .nuops = 4, .uops = { { _GUARD_NOS_IMMORTAL, 0, 0 }, { _GUARD_TOS_REFCNT1, 0, 0 }, { _GUARD_VERSION_TYPES, 1, 1 }, { _BINARY_OP_TABLE_NN, 1, 1 } } }, + [BINARY_OP_II] = { .nuops = 4, .uops = { { _GUARD_NOS_IMMORTAL, 0, 0 }, { _GUARD_TOS_IMMORTAL, 0, 0 }, { _GUARD_VERSION_TYPES, 1, 1 }, { _BINARY_OP_TABLE_NN, 1, 1 } } }, + [BINARY_OP_IX] = { .nuops = 3, .uops = { { _GUARD_NOS_IMMORTAL, 0, 0 }, { _GUARD_VERSION_TYPES, 1, 1 }, { _BINARY_OP_TABLE_ND, 1, 1 } } }, + [BINARY_OP_X1] = { .nuops = 3, .uops = { { _GUARD_TOS_REFCNT1, 0, 0 }, { _GUARD_VERSION_TYPES, 1, 1 }, { _BINARY_OP_TABLE_DN, 1, 1 } } }, + [BINARY_OP_XI] = { .nuops = 3, .uops = { { _GUARD_TOS_IMMORTAL, 0, 0 }, { _GUARD_VERSION_TYPES, 1, 1 }, { _BINARY_OP_TABLE_DN, 1, 1 } } }, + [BINARY_OP_XX] = { .nuops = 2, .uops = { { _GUARD_VERSION_TYPES, 1, 1 }, { _BINARY_OP_TABLE_DD, 1, 1 } } }, [BINARY_SLICE] = { .nuops = 1, .uops = { { _BINARY_SLICE, 0, 0 } } }, [BINARY_SUBSCR] = { .nuops = 1, .uops = { { _BINARY_SUBSCR, 0, 0 } } }, [BINARY_SUBSCR_DICT] = { .nuops = 1, .uops = { { _BINARY_SUBSCR_DICT, 0, 0 } } }, @@ -1395,14 +1403,15 @@ const char *_PyOpcode_OpName[264] = { [BEFORE_ASYNC_WITH] = "BEFORE_ASYNC_WITH", [BEFORE_WITH] = "BEFORE_WITH", [BINARY_OP] = "BINARY_OP", - [BINARY_OP_ADD_FLOAT] = "BINARY_OP_ADD_FLOAT", - [BINARY_OP_ADD_INT] = "BINARY_OP_ADD_INT", - [BINARY_OP_ADD_UNICODE] = "BINARY_OP_ADD_UNICODE", + [BINARY_OP_1I] = "BINARY_OP_1I", + [BINARY_OP_1X] = "BINARY_OP_1X", + [BINARY_OP_I1] = "BINARY_OP_I1", + [BINARY_OP_II] = "BINARY_OP_II", [BINARY_OP_INPLACE_ADD_UNICODE] = "BINARY_OP_INPLACE_ADD_UNICODE", - [BINARY_OP_MULTIPLY_FLOAT] = "BINARY_OP_MULTIPLY_FLOAT", - [BINARY_OP_MULTIPLY_INT] = "BINARY_OP_MULTIPLY_INT", - [BINARY_OP_SUBTRACT_FLOAT] = "BINARY_OP_SUBTRACT_FLOAT", - [BINARY_OP_SUBTRACT_INT] = "BINARY_OP_SUBTRACT_INT", + [BINARY_OP_IX] = "BINARY_OP_IX", + [BINARY_OP_X1] = "BINARY_OP_X1", + [BINARY_OP_XI] = "BINARY_OP_XI", + [BINARY_OP_XX] = "BINARY_OP_XX", [BINARY_SLICE] = "BINARY_SLICE", [BINARY_SUBSCR] = "BINARY_SUBSCR", [BINARY_SUBSCR_DICT] = "BINARY_SUBSCR_DICT", @@ -1636,7 +1645,7 @@ const uint8_t _PyOpcode_Caches[256] = { [POP_JUMP_IF_NOT_NONE] = 1, [FOR_ITER] = 1, [CALL] = 3, - [BINARY_OP] = 1, + [BINARY_OP] = 2, }; #endif @@ -1646,14 +1655,15 @@ const uint8_t _PyOpcode_Deopt[256] = { [BEFORE_ASYNC_WITH] = BEFORE_ASYNC_WITH, [BEFORE_WITH] = BEFORE_WITH, [BINARY_OP] = BINARY_OP, - [BINARY_OP_ADD_FLOAT] = BINARY_OP, - [BINARY_OP_ADD_INT] = BINARY_OP, - [BINARY_OP_ADD_UNICODE] = BINARY_OP, + [BINARY_OP_1I] = BINARY_OP, + [BINARY_OP_1X] = BINARY_OP, + [BINARY_OP_I1] = BINARY_OP, + [BINARY_OP_II] = BINARY_OP, [BINARY_OP_INPLACE_ADD_UNICODE] = BINARY_OP, - [BINARY_OP_MULTIPLY_FLOAT] = BINARY_OP, - [BINARY_OP_MULTIPLY_INT] = BINARY_OP, - [BINARY_OP_SUBTRACT_FLOAT] = BINARY_OP, - [BINARY_OP_SUBTRACT_INT] = BINARY_OP, + [BINARY_OP_IX] = BINARY_OP, + [BINARY_OP_X1] = BINARY_OP, + [BINARY_OP_XI] = BINARY_OP, + [BINARY_OP_XX] = BINARY_OP, [BINARY_SLICE] = BINARY_SLICE, [BINARY_SUBSCR] = BINARY_SUBSCR, [BINARY_SUBSCR_DICT] = BINARY_SUBSCR, @@ -1890,7 +1900,6 @@ const uint8_t _PyOpcode_Deopt[256] = { case 146: \ case 147: \ case 148: \ - case 223: \ case 224: \ case 225: \ case 226: \ diff --git a/Include/internal/pycore_optimizer.h b/Include/internal/pycore_optimizer.h index 76123987ac99f5..9c883b9d83004e 100644 --- a/Include/internal/pycore_optimizer.h +++ b/Include/internal/pycore_optimizer.h @@ -122,6 +122,7 @@ extern _Py_UopsSymbol *_Py_uop_sym_new_type( extern _Py_UopsSymbol *_Py_uop_sym_new_const(_Py_UOpsContext *ctx, PyObject *const_val); extern _Py_UopsSymbol *_Py_uop_sym_new_null(_Py_UOpsContext *ctx); extern bool _Py_uop_sym_has_type(_Py_UopsSymbol *sym); +extern PyTypeObject *_Py_uop_sym_get_type(_Py_UopsSymbol *sym); extern bool _Py_uop_sym_matches_type(_Py_UopsSymbol *sym, PyTypeObject *typ); extern void _Py_uop_sym_set_null(_Py_UOpsContext *ctx, _Py_UopsSymbol *sym); extern void _Py_uop_sym_set_non_null(_Py_UOpsContext *ctx, _Py_UopsSymbol *sym); @@ -131,7 +132,6 @@ extern bool _Py_uop_sym_is_bottom(_Py_UopsSymbol *sym); extern int _Py_uop_sym_truthiness(_Py_UopsSymbol *sym); extern PyTypeObject *_Py_uop_sym_get_type(_Py_UopsSymbol *sym); - extern void _Py_uop_abstractcontext_init(_Py_UOpsContext *ctx); extern void _Py_uop_abstractcontext_fini(_Py_UOpsContext *ctx); diff --git a/Include/internal/pycore_runtime_init.h b/Include/internal/pycore_runtime_init.h index 98920dbb7c7a92..27f3a3e3d592b4 100644 --- a/Include/internal/pycore_runtime_init.h +++ b/Include/internal/pycore_runtime_init.h @@ -140,7 +140,7 @@ extern PyTypeObject _PyExc_MemoryError; .double_format = _py_float_format_unknown, \ }, \ .types = { \ - .next_version_tag = 1, \ + .next_version_tag = _Py_TYPE_VERSIONS_PREALLOCATED, \ }, \ .static_objects = { \ .singletons = { \ diff --git a/Include/internal/pycore_typeobject.h b/Include/internal/pycore_typeobject.h index 7e533bd138469b..aa7f57bfb9e415 100644 --- a/Include/internal/pycore_typeobject.h +++ b/Include/internal/pycore_typeobject.h @@ -14,6 +14,24 @@ extern "C" { /* state */ +#define _Py_TYPE_VERSION_INT 1 +#define _Py_TYPE_VERSION_FLOAT 2 +#define _Py_TYPE_VERSION_LIST 3 +#define _Py_TYPE_VERSION_TUPLE 4 +#define _Py_TYPE_VERSION_STR 5 +#define _Py_TYPE_VERSION_SET 6 +#define _Py_TYPE_VERSION_FROZEN_SET 7 +#define _Py_TYPE_VERSION_ARRAY 8 +#define _Py_TYPE_VERSION_DICT 9 +#define _Py_TYPE_VERSION_BYTES 10 +#define _Py_TYPE_VERSION_COMPLEX 11 +#define _Py_TYPE_VERSION_DICTITEMS 12 +#define _Py_TYPE_VERSION_BYTEARRAY 13 + +#define _Py_TYPE_VERSIONS_PREALLOCATED 16 + +extern PyTypeObject *const _Py_PreAllocatedTypes[_Py_TYPE_VERSIONS_PREALLOCATED]; + #define _Py_TYPE_BASE_VERSION_TAG (2<<16) #define _Py_MAX_GLOBAL_TYPE_VERSION_TAG (_Py_TYPE_BASE_VERSION_TAG - 1) diff --git a/Include/internal/pycore_uop_ids.h b/Include/internal/pycore_uop_ids.h index 19e2b823ed0140..dada5726d3c567 100644 --- a/Include/internal/pycore_uop_ids.h +++ b/Include/internal/pycore_uop_ids.h @@ -14,15 +14,12 @@ extern "C" { #define _BEFORE_ASYNC_WITH BEFORE_ASYNC_WITH #define _BEFORE_WITH BEFORE_WITH #define _BINARY_OP 302 -#define _BINARY_OP_ADD_FLOAT 303 -#define _BINARY_OP_ADD_INT 304 -#define _BINARY_OP_ADD_UNICODE 305 -#define _BINARY_OP_MULTIPLY_FLOAT 306 -#define _BINARY_OP_MULTIPLY_INT 307 -#define _BINARY_OP_SUBTRACT_FLOAT 308 -#define _BINARY_OP_SUBTRACT_INT 309 +#define _BINARY_OP_TABLE_DD 303 +#define _BINARY_OP_TABLE_DN 304 +#define _BINARY_OP_TABLE_ND 305 +#define _BINARY_OP_TABLE_NN 306 #define _BINARY_SLICE BINARY_SLICE -#define _BINARY_SUBSCR 310 +#define _BINARY_SUBSCR 307 #define _BINARY_SUBSCR_DICT BINARY_SUBSCR_DICT #define _BINARY_SUBSCR_GETITEM BINARY_SUBSCR_GETITEM #define _BINARY_SUBSCR_LIST_INT BINARY_SUBSCR_LIST_INT @@ -35,51 +32,51 @@ extern "C" { #define _BUILD_SLICE BUILD_SLICE #define _BUILD_STRING BUILD_STRING #define _BUILD_TUPLE BUILD_TUPLE -#define _CALL 311 +#define _CALL 308 #define _CALL_ALLOC_AND_ENTER_INIT CALL_ALLOC_AND_ENTER_INIT -#define _CALL_BUILTIN_CLASS 312 -#define _CALL_BUILTIN_FAST 313 -#define _CALL_BUILTIN_FAST_WITH_KEYWORDS 314 -#define _CALL_BUILTIN_O 315 +#define _CALL_BUILTIN_CLASS 309 +#define _CALL_BUILTIN_FAST 310 +#define _CALL_BUILTIN_FAST_WITH_KEYWORDS 311 +#define _CALL_BUILTIN_O 312 #define _CALL_FUNCTION_EX CALL_FUNCTION_EX #define _CALL_INTRINSIC_1 CALL_INTRINSIC_1 #define _CALL_INTRINSIC_2 CALL_INTRINSIC_2 #define _CALL_ISINSTANCE CALL_ISINSTANCE #define _CALL_KW CALL_KW #define _CALL_LEN CALL_LEN -#define _CALL_METHOD_DESCRIPTOR_FAST 316 -#define _CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS 317 -#define _CALL_METHOD_DESCRIPTOR_NOARGS 318 -#define _CALL_METHOD_DESCRIPTOR_O 319 -#define _CALL_NON_PY_GENERAL 320 -#define _CALL_STR_1 321 -#define _CALL_TUPLE_1 322 +#define _CALL_METHOD_DESCRIPTOR_FAST 313 +#define _CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS 314 +#define _CALL_METHOD_DESCRIPTOR_NOARGS 315 +#define _CALL_METHOD_DESCRIPTOR_O 316 +#define _CALL_NON_PY_GENERAL 317 +#define _CALL_STR_1 318 +#define _CALL_TUPLE_1 319 #define _CALL_TYPE_1 CALL_TYPE_1 -#define _CHECK_ATTR_CLASS 323 -#define _CHECK_ATTR_METHOD_LAZY_DICT 324 -#define _CHECK_ATTR_MODULE 325 -#define _CHECK_ATTR_WITH_HINT 326 -#define _CHECK_CALL_BOUND_METHOD_EXACT_ARGS 327 +#define _CHECK_ATTR_CLASS 320 +#define _CHECK_ATTR_METHOD_LAZY_DICT 321 +#define _CHECK_ATTR_MODULE 322 +#define _CHECK_ATTR_WITH_HINT 323 +#define _CHECK_CALL_BOUND_METHOD_EXACT_ARGS 324 #define _CHECK_EG_MATCH CHECK_EG_MATCH #define _CHECK_EXC_MATCH CHECK_EXC_MATCH -#define _CHECK_FUNCTION 328 -#define _CHECK_FUNCTION_EXACT_ARGS 329 -#define _CHECK_FUNCTION_VERSION 330 -#define _CHECK_IS_NOT_PY_CALLABLE 331 -#define _CHECK_MANAGED_OBJECT_HAS_VALUES 332 -#define _CHECK_METHOD_VERSION 333 -#define _CHECK_PEP_523 334 -#define _CHECK_PERIODIC 335 -#define _CHECK_STACK_SPACE 336 -#define _CHECK_STACK_SPACE_OPERAND 337 -#define _CHECK_VALIDITY 338 -#define _CHECK_VALIDITY_AND_SET_IP 339 -#define _COLD_EXIT 340 -#define _COMPARE_OP 341 -#define _COMPARE_OP_FLOAT 342 -#define _COMPARE_OP_INT 343 -#define _COMPARE_OP_STR 344 -#define _CONTAINS_OP 345 +#define _CHECK_FUNCTION 325 +#define _CHECK_FUNCTION_EXACT_ARGS 326 +#define _CHECK_FUNCTION_VERSION 327 +#define _CHECK_IS_NOT_PY_CALLABLE 328 +#define _CHECK_MANAGED_OBJECT_HAS_VALUES 329 +#define _CHECK_METHOD_VERSION 330 +#define _CHECK_PEP_523 331 +#define _CHECK_PERIODIC 332 +#define _CHECK_STACK_SPACE 333 +#define _CHECK_STACK_SPACE_OPERAND 334 +#define _CHECK_VALIDITY 335 +#define _CHECK_VALIDITY_AND_SET_IP 336 +#define _COLD_EXIT 337 +#define _COMPARE_OP 338 +#define _COMPARE_OP_FLOAT 339 +#define _COMPARE_OP_INT 340 +#define _COMPARE_OP_STR 341 +#define _CONTAINS_OP 342 #define _CONTAINS_OP_DICT CONTAINS_OP_DICT #define _CONTAINS_OP_SET CONTAINS_OP_SET #define _CONVERT_VALUE CONVERT_VALUE @@ -91,53 +88,60 @@ extern "C" { #define _DELETE_GLOBAL DELETE_GLOBAL #define _DELETE_NAME DELETE_NAME #define _DELETE_SUBSCR DELETE_SUBSCR -#define _DEOPT 346 +#define _DEOPT 343 #define _DICT_MERGE DICT_MERGE #define _DICT_UPDATE DICT_UPDATE -#define _DYNAMIC_EXIT 347 +#define _DYNAMIC_EXIT 344 #define _END_SEND END_SEND -#define _ERROR_POP_N 348 +#define _ERROR_POP_N 345 #define _EXIT_INIT_CHECK EXIT_INIT_CHECK -#define _EXPAND_METHOD 349 -#define _FATAL_ERROR 350 +#define _EXPAND_METHOD 346 +#define _FATAL_ERROR 347 #define _FORMAT_SIMPLE FORMAT_SIMPLE #define _FORMAT_WITH_SPEC FORMAT_WITH_SPEC -#define _FOR_ITER 351 -#define _FOR_ITER_GEN_FRAME 352 -#define _FOR_ITER_TIER_TWO 353 +#define _FOR_ITER 348 +#define _FOR_ITER_GEN_FRAME 349 +#define _FOR_ITER_TIER_TWO 350 #define _GET_AITER GET_AITER #define _GET_ANEXT GET_ANEXT #define _GET_AWAITABLE GET_AWAITABLE #define _GET_ITER GET_ITER #define _GET_LEN GET_LEN #define _GET_YIELD_FROM_ITER GET_YIELD_FROM_ITER -#define _GUARD_BOTH_FLOAT 354 -#define _GUARD_BOTH_INT 355 -#define _GUARD_BOTH_UNICODE 356 -#define _GUARD_BUILTINS_VERSION 357 -#define _GUARD_DORV_NO_DICT 358 -#define _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT 359 -#define _GUARD_GLOBALS_VERSION 360 -#define _GUARD_IS_FALSE_POP 361 -#define _GUARD_IS_NONE_POP 362 -#define _GUARD_IS_NOT_NONE_POP 363 -#define _GUARD_IS_TRUE_POP 364 -#define _GUARD_KEYS_VERSION 365 -#define _GUARD_NOS_FLOAT 366 -#define _GUARD_NOS_INT 367 +#define _GUARD_BOTH_FLOAT 351 +#define _GUARD_BOTH_INT 352 +#define _GUARD_BOTH_UNICODE 353 +#define _GUARD_BUILTINS_VERSION 354 +#define _GUARD_DORV_NO_DICT 355 +#define _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT 356 +#define _GUARD_GLOBALS_VERSION 357 +#define _GUARD_IS_FALSE_POP 358 +#define _GUARD_IS_NONE_POP 359 +#define _GUARD_IS_NOT_NONE_POP 360 +#define _GUARD_IS_TRUE_POP 361 +#define _GUARD_KEYS_VERSION 362 +#define _GUARD_NOS_FLOAT 363 +#define _GUARD_NOS_IMMORTAL 364 +#define _GUARD_NOS_INT 365 +#define _GUARD_NOS_REFCNT1 366 +#define _GUARD_NOS_VERSION 367 #define _GUARD_NOT_EXHAUSTED_LIST 368 #define _GUARD_NOT_EXHAUSTED_RANGE 369 #define _GUARD_NOT_EXHAUSTED_TUPLE 370 #define _GUARD_TOS_FLOAT 371 -#define _GUARD_TOS_INT 372 -#define _GUARD_TYPE_VERSION 373 -#define _INIT_CALL_BOUND_METHOD_EXACT_ARGS 374 -#define _INIT_CALL_PY_EXACT_ARGS 375 -#define _INIT_CALL_PY_EXACT_ARGS_0 376 -#define _INIT_CALL_PY_EXACT_ARGS_1 377 -#define _INIT_CALL_PY_EXACT_ARGS_2 378 -#define _INIT_CALL_PY_EXACT_ARGS_3 379 -#define _INIT_CALL_PY_EXACT_ARGS_4 380 +#define _GUARD_TOS_IMMORTAL 372 +#define _GUARD_TOS_INT 373 +#define _GUARD_TOS_REFCNT1 374 +#define _GUARD_TOS_VERSION 375 +#define _GUARD_TYPE_VERSION 376 +#define _GUARD_VERSION_TYPES 377 +#define _INIT_CALL_BOUND_METHOD_EXACT_ARGS 378 +#define _INIT_CALL_PY_EXACT_ARGS 379 +#define _INIT_CALL_PY_EXACT_ARGS_0 380 +#define _INIT_CALL_PY_EXACT_ARGS_1 381 +#define _INIT_CALL_PY_EXACT_ARGS_2 382 +#define _INIT_CALL_PY_EXACT_ARGS_3 383 +#define _INIT_CALL_PY_EXACT_ARGS_4 384 #define _INSTRUMENTED_CALL INSTRUMENTED_CALL #define _INSTRUMENTED_CALL_FUNCTION_EX INSTRUMENTED_CALL_FUNCTION_EX #define _INSTRUMENTED_CALL_KW INSTRUMENTED_CALL_KW @@ -154,65 +158,65 @@ extern "C" { #define _INSTRUMENTED_RETURN_CONST INSTRUMENTED_RETURN_CONST #define _INSTRUMENTED_RETURN_VALUE INSTRUMENTED_RETURN_VALUE #define _INSTRUMENTED_YIELD_VALUE INSTRUMENTED_YIELD_VALUE -#define _INTERNAL_INCREMENT_OPT_COUNTER 381 -#define _IS_NONE 382 +#define _INTERNAL_INCREMENT_OPT_COUNTER 385 +#define _IS_NONE 386 #define _IS_OP IS_OP -#define _ITER_CHECK_LIST 383 -#define _ITER_CHECK_RANGE 384 -#define _ITER_CHECK_TUPLE 385 -#define _ITER_JUMP_LIST 386 -#define _ITER_JUMP_RANGE 387 -#define _ITER_JUMP_TUPLE 388 -#define _ITER_NEXT_LIST 389 -#define _ITER_NEXT_RANGE 390 -#define _ITER_NEXT_TUPLE 391 -#define _JUMP_TO_TOP 392 +#define _ITER_CHECK_LIST 387 +#define _ITER_CHECK_RANGE 388 +#define _ITER_CHECK_TUPLE 389 +#define _ITER_JUMP_LIST 390 +#define _ITER_JUMP_RANGE 391 +#define _ITER_JUMP_TUPLE 392 +#define _ITER_NEXT_LIST 393 +#define _ITER_NEXT_RANGE 394 +#define _ITER_NEXT_TUPLE 395 +#define _JUMP_TO_TOP 396 #define _LIST_APPEND LIST_APPEND #define _LIST_EXTEND LIST_EXTEND -#define _LOAD_ATTR 393 -#define _LOAD_ATTR_CLASS 394 -#define _LOAD_ATTR_CLASS_0 395 -#define _LOAD_ATTR_CLASS_1 396 +#define _LOAD_ATTR 397 +#define _LOAD_ATTR_CLASS 398 +#define _LOAD_ATTR_CLASS_0 399 +#define _LOAD_ATTR_CLASS_1 400 #define _LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN -#define _LOAD_ATTR_INSTANCE_VALUE 397 -#define _LOAD_ATTR_INSTANCE_VALUE_0 398 -#define _LOAD_ATTR_INSTANCE_VALUE_1 399 -#define _LOAD_ATTR_METHOD_LAZY_DICT 400 -#define _LOAD_ATTR_METHOD_NO_DICT 401 -#define _LOAD_ATTR_METHOD_WITH_VALUES 402 -#define _LOAD_ATTR_MODULE 403 -#define _LOAD_ATTR_NONDESCRIPTOR_NO_DICT 404 -#define _LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES 405 +#define _LOAD_ATTR_INSTANCE_VALUE 401 +#define _LOAD_ATTR_INSTANCE_VALUE_0 402 +#define _LOAD_ATTR_INSTANCE_VALUE_1 403 +#define _LOAD_ATTR_METHOD_LAZY_DICT 404 +#define _LOAD_ATTR_METHOD_NO_DICT 405 +#define _LOAD_ATTR_METHOD_WITH_VALUES 406 +#define _LOAD_ATTR_MODULE 407 +#define _LOAD_ATTR_NONDESCRIPTOR_NO_DICT 408 +#define _LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES 409 #define _LOAD_ATTR_PROPERTY LOAD_ATTR_PROPERTY -#define _LOAD_ATTR_SLOT 406 -#define _LOAD_ATTR_SLOT_0 407 -#define _LOAD_ATTR_SLOT_1 408 -#define _LOAD_ATTR_WITH_HINT 409 +#define _LOAD_ATTR_SLOT 410 +#define _LOAD_ATTR_SLOT_0 411 +#define _LOAD_ATTR_SLOT_1 412 +#define _LOAD_ATTR_WITH_HINT 413 #define _LOAD_BUILD_CLASS LOAD_BUILD_CLASS #define _LOAD_COMMON_CONSTANT LOAD_COMMON_CONSTANT #define _LOAD_CONST LOAD_CONST -#define _LOAD_CONST_INLINE 410 -#define _LOAD_CONST_INLINE_BORROW 411 -#define _LOAD_CONST_INLINE_BORROW_WITH_NULL 412 -#define _LOAD_CONST_INLINE_WITH_NULL 413 +#define _LOAD_CONST_INLINE 414 +#define _LOAD_CONST_INLINE_BORROW 415 +#define _LOAD_CONST_INLINE_BORROW_WITH_NULL 416 +#define _LOAD_CONST_INLINE_WITH_NULL 417 #define _LOAD_DEREF LOAD_DEREF -#define _LOAD_FAST 414 -#define _LOAD_FAST_0 415 -#define _LOAD_FAST_1 416 -#define _LOAD_FAST_2 417 -#define _LOAD_FAST_3 418 -#define _LOAD_FAST_4 419 -#define _LOAD_FAST_5 420 -#define _LOAD_FAST_6 421 -#define _LOAD_FAST_7 422 +#define _LOAD_FAST 418 +#define _LOAD_FAST_0 419 +#define _LOAD_FAST_1 420 +#define _LOAD_FAST_2 421 +#define _LOAD_FAST_3 422 +#define _LOAD_FAST_4 423 +#define _LOAD_FAST_5 424 +#define _LOAD_FAST_6 425 +#define _LOAD_FAST_7 426 #define _LOAD_FAST_AND_CLEAR LOAD_FAST_AND_CLEAR #define _LOAD_FAST_CHECK LOAD_FAST_CHECK #define _LOAD_FAST_LOAD_FAST LOAD_FAST_LOAD_FAST #define _LOAD_FROM_DICT_OR_DEREF LOAD_FROM_DICT_OR_DEREF #define _LOAD_FROM_DICT_OR_GLOBALS LOAD_FROM_DICT_OR_GLOBALS -#define _LOAD_GLOBAL 423 -#define _LOAD_GLOBAL_BUILTINS 424 -#define _LOAD_GLOBAL_MODULE 425 +#define _LOAD_GLOBAL 427 +#define _LOAD_GLOBAL_BUILTINS 428 +#define _LOAD_GLOBAL_MODULE 429 #define _LOAD_LOCALS LOAD_LOCALS #define _LOAD_NAME LOAD_NAME #define _LOAD_SUPER_ATTR_ATTR LOAD_SUPER_ATTR_ATTR @@ -226,51 +230,51 @@ extern "C" { #define _MATCH_SEQUENCE MATCH_SEQUENCE #define _NOP NOP #define _POP_EXCEPT POP_EXCEPT -#define _POP_FRAME 426 -#define _POP_JUMP_IF_FALSE 427 -#define _POP_JUMP_IF_TRUE 428 +#define _POP_FRAME 430 +#define _POP_JUMP_IF_FALSE 431 +#define _POP_JUMP_IF_TRUE 432 #define _POP_TOP POP_TOP -#define _POP_TOP_LOAD_CONST_INLINE_BORROW 429 +#define _POP_TOP_LOAD_CONST_INLINE_BORROW 433 #define _PUSH_EXC_INFO PUSH_EXC_INFO -#define _PUSH_FRAME 430 +#define _PUSH_FRAME 434 #define _PUSH_NULL PUSH_NULL -#define _PY_FRAME_GENERAL 431 -#define _REPLACE_WITH_TRUE 432 +#define _PY_FRAME_GENERAL 435 +#define _REPLACE_WITH_TRUE 436 #define _RESUME_CHECK RESUME_CHECK #define _RETURN_GENERATOR RETURN_GENERATOR -#define _SAVE_RETURN_OFFSET 433 -#define _SEND 434 +#define _SAVE_RETURN_OFFSET 437 +#define _SEND 438 #define _SEND_GEN SEND_GEN #define _SETUP_ANNOTATIONS SETUP_ANNOTATIONS #define _SET_ADD SET_ADD #define _SET_FUNCTION_ATTRIBUTE SET_FUNCTION_ATTRIBUTE #define _SET_UPDATE SET_UPDATE -#define _START_EXECUTOR 435 -#define _STORE_ATTR 436 -#define _STORE_ATTR_INSTANCE_VALUE 437 -#define _STORE_ATTR_SLOT 438 -#define _STORE_ATTR_WITH_HINT 439 +#define _START_EXECUTOR 439 +#define _STORE_ATTR 440 +#define _STORE_ATTR_INSTANCE_VALUE 441 +#define _STORE_ATTR_SLOT 442 +#define _STORE_ATTR_WITH_HINT 443 #define _STORE_DEREF STORE_DEREF -#define _STORE_FAST 440 -#define _STORE_FAST_0 441 -#define _STORE_FAST_1 442 -#define _STORE_FAST_2 443 -#define _STORE_FAST_3 444 -#define _STORE_FAST_4 445 -#define _STORE_FAST_5 446 -#define _STORE_FAST_6 447 -#define _STORE_FAST_7 448 +#define _STORE_FAST 444 +#define _STORE_FAST_0 445 +#define _STORE_FAST_1 446 +#define _STORE_FAST_2 447 +#define _STORE_FAST_3 448 +#define _STORE_FAST_4 449 +#define _STORE_FAST_5 450 +#define _STORE_FAST_6 451 +#define _STORE_FAST_7 452 #define _STORE_FAST_LOAD_FAST STORE_FAST_LOAD_FAST #define _STORE_FAST_STORE_FAST STORE_FAST_STORE_FAST #define _STORE_GLOBAL STORE_GLOBAL #define _STORE_NAME STORE_NAME #define _STORE_SLICE STORE_SLICE -#define _STORE_SUBSCR 449 +#define _STORE_SUBSCR 453 #define _STORE_SUBSCR_DICT STORE_SUBSCR_DICT #define _STORE_SUBSCR_LIST_INT STORE_SUBSCR_LIST_INT #define _SWAP SWAP -#define _TIER2_RESUME_CHECK 450 -#define _TO_BOOL 451 +#define _TIER2_RESUME_CHECK 454 +#define _TO_BOOL 455 #define _TO_BOOL_BOOL TO_BOOL_BOOL #define _TO_BOOL_INT TO_BOOL_INT #define _TO_BOOL_LIST TO_BOOL_LIST @@ -280,13 +284,13 @@ extern "C" { #define _UNARY_NEGATIVE UNARY_NEGATIVE #define _UNARY_NOT UNARY_NOT #define _UNPACK_EX UNPACK_EX -#define _UNPACK_SEQUENCE 452 +#define _UNPACK_SEQUENCE 456 #define _UNPACK_SEQUENCE_LIST UNPACK_SEQUENCE_LIST #define _UNPACK_SEQUENCE_TUPLE UNPACK_SEQUENCE_TUPLE #define _UNPACK_SEQUENCE_TWO_TUPLE UNPACK_SEQUENCE_TWO_TUPLE #define _WITH_EXCEPT_START WITH_EXCEPT_START #define _YIELD_VALUE YIELD_VALUE -#define MAX_UOP_ID 452 +#define MAX_UOP_ID 456 #ifdef __cplusplus } diff --git a/Include/internal/pycore_uop_metadata.h b/Include/internal/pycore_uop_metadata.h index 78f0eafaa32042..b7d51331e905a9 100644 --- a/Include/internal/pycore_uop_metadata.h +++ b/Include/internal/pycore_uop_metadata.h @@ -58,20 +58,24 @@ const uint16_t _PyUop_Flags[MAX_UOP_ID+1] = { [_TO_BOOL_STR] = HAS_EXIT_FLAG, [_REPLACE_WITH_TRUE] = 0, [_UNARY_INVERT] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, - [_GUARD_BOTH_INT] = HAS_EXIT_FLAG, + [_GUARD_NOS_REFCNT1] = HAS_EXIT_FLAG, + [_GUARD_TOS_REFCNT1] = HAS_EXIT_FLAG, [_GUARD_NOS_INT] = HAS_EXIT_FLAG, [_GUARD_TOS_INT] = HAS_EXIT_FLAG, - [_BINARY_OP_MULTIPLY_INT] = HAS_ERROR_FLAG | HAS_PURE_FLAG, - [_BINARY_OP_ADD_INT] = HAS_ERROR_FLAG | HAS_PURE_FLAG, - [_BINARY_OP_SUBTRACT_INT] = HAS_ERROR_FLAG | HAS_PURE_FLAG, - [_GUARD_BOTH_FLOAT] = HAS_EXIT_FLAG, + [_GUARD_NOS_IMMORTAL] = HAS_EXIT_FLAG, + [_GUARD_TOS_IMMORTAL] = HAS_EXIT_FLAG, + [_GUARD_VERSION_TYPES] = HAS_EXIT_FLAG, + [_GUARD_TOS_VERSION] = HAS_EXIT_FLAG, + [_GUARD_NOS_VERSION] = HAS_EXIT_FLAG, [_GUARD_NOS_FLOAT] = HAS_EXIT_FLAG, [_GUARD_TOS_FLOAT] = HAS_EXIT_FLAG, - [_BINARY_OP_MULTIPLY_FLOAT] = HAS_PURE_FLAG, - [_BINARY_OP_ADD_FLOAT] = HAS_PURE_FLAG, - [_BINARY_OP_SUBTRACT_FLOAT] = HAS_PURE_FLAG, + [_BINARY_OP_TABLE_NN] = HAS_ERROR_FLAG, + [_BINARY_OP_TABLE_ND] = HAS_ERROR_FLAG, + [_BINARY_OP_TABLE_DN] = HAS_ERROR_FLAG, + [_BINARY_OP_TABLE_DD] = HAS_ERROR_FLAG, + [_GUARD_BOTH_INT] = HAS_EXIT_FLAG, + [_GUARD_BOTH_FLOAT] = HAS_EXIT_FLAG, [_GUARD_BOTH_UNICODE] = HAS_EXIT_FLAG, - [_BINARY_OP_ADD_UNICODE] = HAS_ERROR_FLAG | HAS_PURE_FLAG, [_BINARY_SUBSCR] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, [_BINARY_SLICE] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, [_STORE_SLICE] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, @@ -271,13 +275,10 @@ const uint8_t _PyUop_Replication[MAX_UOP_ID+1] = { const char *const _PyOpcode_uop_name[MAX_UOP_ID+1] = { [_BINARY_OP] = "_BINARY_OP", - [_BINARY_OP_ADD_FLOAT] = "_BINARY_OP_ADD_FLOAT", - [_BINARY_OP_ADD_INT] = "_BINARY_OP_ADD_INT", - [_BINARY_OP_ADD_UNICODE] = "_BINARY_OP_ADD_UNICODE", - [_BINARY_OP_MULTIPLY_FLOAT] = "_BINARY_OP_MULTIPLY_FLOAT", - [_BINARY_OP_MULTIPLY_INT] = "_BINARY_OP_MULTIPLY_INT", - [_BINARY_OP_SUBTRACT_FLOAT] = "_BINARY_OP_SUBTRACT_FLOAT", - [_BINARY_OP_SUBTRACT_INT] = "_BINARY_OP_SUBTRACT_INT", + [_BINARY_OP_TABLE_DD] = "_BINARY_OP_TABLE_DD", + [_BINARY_OP_TABLE_DN] = "_BINARY_OP_TABLE_DN", + [_BINARY_OP_TABLE_ND] = "_BINARY_OP_TABLE_ND", + [_BINARY_OP_TABLE_NN] = "_BINARY_OP_TABLE_NN", [_BINARY_SLICE] = "_BINARY_SLICE", [_BINARY_SUBSCR] = "_BINARY_SUBSCR", [_BINARY_SUBSCR_DICT] = "_BINARY_SUBSCR_DICT", @@ -375,13 +376,20 @@ const char *const _PyOpcode_uop_name[MAX_UOP_ID+1] = { [_GUARD_IS_TRUE_POP] = "_GUARD_IS_TRUE_POP", [_GUARD_KEYS_VERSION] = "_GUARD_KEYS_VERSION", [_GUARD_NOS_FLOAT] = "_GUARD_NOS_FLOAT", + [_GUARD_NOS_IMMORTAL] = "_GUARD_NOS_IMMORTAL", [_GUARD_NOS_INT] = "_GUARD_NOS_INT", + [_GUARD_NOS_REFCNT1] = "_GUARD_NOS_REFCNT1", + [_GUARD_NOS_VERSION] = "_GUARD_NOS_VERSION", [_GUARD_NOT_EXHAUSTED_LIST] = "_GUARD_NOT_EXHAUSTED_LIST", [_GUARD_NOT_EXHAUSTED_RANGE] = "_GUARD_NOT_EXHAUSTED_RANGE", [_GUARD_NOT_EXHAUSTED_TUPLE] = "_GUARD_NOT_EXHAUSTED_TUPLE", [_GUARD_TOS_FLOAT] = "_GUARD_TOS_FLOAT", + [_GUARD_TOS_IMMORTAL] = "_GUARD_TOS_IMMORTAL", [_GUARD_TOS_INT] = "_GUARD_TOS_INT", + [_GUARD_TOS_REFCNT1] = "_GUARD_TOS_REFCNT1", + [_GUARD_TOS_VERSION] = "_GUARD_TOS_VERSION", [_GUARD_TYPE_VERSION] = "_GUARD_TYPE_VERSION", + [_GUARD_VERSION_TYPES] = "_GUARD_VERSION_TYPES", [_INIT_CALL_BOUND_METHOD_EXACT_ARGS] = "_INIT_CALL_BOUND_METHOD_EXACT_ARGS", [_INIT_CALL_PY_EXACT_ARGS] = "_INIT_CALL_PY_EXACT_ARGS", [_INIT_CALL_PY_EXACT_ARGS_0] = "_INIT_CALL_PY_EXACT_ARGS_0", @@ -594,33 +602,41 @@ int _PyUop_num_popped(int opcode, int oparg) return 1; case _UNARY_INVERT: return 1; - case _GUARD_BOTH_INT: + case _GUARD_NOS_REFCNT1: return 2; + case _GUARD_TOS_REFCNT1: + return 1; case _GUARD_NOS_INT: return 2; case _GUARD_TOS_INT: return 1; - case _BINARY_OP_MULTIPLY_INT: + case _GUARD_NOS_IMMORTAL: return 2; - case _BINARY_OP_ADD_INT: - return 2; - case _BINARY_OP_SUBTRACT_INT: + case _GUARD_TOS_IMMORTAL: + return 1; + case _GUARD_VERSION_TYPES: return 2; - case _GUARD_BOTH_FLOAT: + case _GUARD_TOS_VERSION: + return 1; + case _GUARD_NOS_VERSION: return 2; case _GUARD_NOS_FLOAT: return 2; case _GUARD_TOS_FLOAT: return 1; - case _BINARY_OP_MULTIPLY_FLOAT: + case _BINARY_OP_TABLE_NN: return 2; - case _BINARY_OP_ADD_FLOAT: + case _BINARY_OP_TABLE_ND: return 2; - case _BINARY_OP_SUBTRACT_FLOAT: + case _BINARY_OP_TABLE_DN: return 2; - case _GUARD_BOTH_UNICODE: + case _BINARY_OP_TABLE_DD: + return 2; + case _GUARD_BOTH_INT: + return 2; + case _GUARD_BOTH_FLOAT: return 2; - case _BINARY_OP_ADD_UNICODE: + case _GUARD_BOTH_UNICODE: return 2; case _BINARY_SUBSCR: return 2; diff --git a/Include/opcode_ids.h b/Include/opcode_ids.h index 5b37de25703560..be46a1ad1408f6 100644 --- a/Include/opcode_ids.h +++ b/Include/opcode_ids.h @@ -130,79 +130,80 @@ extern "C" { #define UNPACK_SEQUENCE 117 #define YIELD_VALUE 118 #define RESUME 149 -#define BINARY_OP_ADD_FLOAT 150 -#define BINARY_OP_ADD_INT 151 -#define BINARY_OP_ADD_UNICODE 152 -#define BINARY_OP_MULTIPLY_FLOAT 153 -#define BINARY_OP_MULTIPLY_INT 154 -#define BINARY_OP_SUBTRACT_FLOAT 155 -#define BINARY_OP_SUBTRACT_INT 156 -#define BINARY_SUBSCR_DICT 157 -#define BINARY_SUBSCR_GETITEM 158 -#define BINARY_SUBSCR_LIST_INT 159 -#define BINARY_SUBSCR_STR_INT 160 -#define BINARY_SUBSCR_TUPLE_INT 161 -#define CALL_ALLOC_AND_ENTER_INIT 162 -#define CALL_BOUND_METHOD_EXACT_ARGS 163 -#define CALL_BOUND_METHOD_GENERAL 164 -#define CALL_BUILTIN_CLASS 165 -#define CALL_BUILTIN_FAST 166 -#define CALL_BUILTIN_FAST_WITH_KEYWORDS 167 -#define CALL_BUILTIN_O 168 -#define CALL_ISINSTANCE 169 -#define CALL_LEN 170 -#define CALL_LIST_APPEND 171 -#define CALL_METHOD_DESCRIPTOR_FAST 172 -#define CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS 173 -#define CALL_METHOD_DESCRIPTOR_NOARGS 174 -#define CALL_METHOD_DESCRIPTOR_O 175 -#define CALL_NON_PY_GENERAL 176 -#define CALL_PY_EXACT_ARGS 177 -#define CALL_PY_GENERAL 178 -#define CALL_STR_1 179 -#define CALL_TUPLE_1 180 -#define CALL_TYPE_1 181 -#define COMPARE_OP_FLOAT 182 -#define COMPARE_OP_INT 183 -#define COMPARE_OP_STR 184 -#define CONTAINS_OP_DICT 185 -#define CONTAINS_OP_SET 186 -#define FOR_ITER_GEN 187 -#define FOR_ITER_LIST 188 -#define FOR_ITER_RANGE 189 -#define FOR_ITER_TUPLE 190 -#define LOAD_ATTR_CLASS 191 -#define LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN 192 -#define LOAD_ATTR_INSTANCE_VALUE 193 -#define LOAD_ATTR_METHOD_LAZY_DICT 194 -#define LOAD_ATTR_METHOD_NO_DICT 195 -#define LOAD_ATTR_METHOD_WITH_VALUES 196 -#define LOAD_ATTR_MODULE 197 -#define LOAD_ATTR_NONDESCRIPTOR_NO_DICT 198 -#define LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES 199 -#define LOAD_ATTR_PROPERTY 200 -#define LOAD_ATTR_SLOT 201 -#define LOAD_ATTR_WITH_HINT 202 -#define LOAD_GLOBAL_BUILTIN 203 -#define LOAD_GLOBAL_MODULE 204 -#define LOAD_SUPER_ATTR_ATTR 205 -#define LOAD_SUPER_ATTR_METHOD 206 -#define RESUME_CHECK 207 -#define SEND_GEN 208 -#define STORE_ATTR_INSTANCE_VALUE 209 -#define STORE_ATTR_SLOT 210 -#define STORE_ATTR_WITH_HINT 211 -#define STORE_SUBSCR_DICT 212 -#define STORE_SUBSCR_LIST_INT 213 -#define TO_BOOL_ALWAYS_TRUE 214 -#define TO_BOOL_BOOL 215 -#define TO_BOOL_INT 216 -#define TO_BOOL_LIST 217 -#define TO_BOOL_NONE 218 -#define TO_BOOL_STR 219 -#define UNPACK_SEQUENCE_LIST 220 -#define UNPACK_SEQUENCE_TUPLE 221 -#define UNPACK_SEQUENCE_TWO_TUPLE 222 +#define BINARY_OP_1I 150 +#define BINARY_OP_1X 151 +#define BINARY_OP_I1 152 +#define BINARY_OP_II 153 +#define BINARY_OP_IX 154 +#define BINARY_OP_X1 155 +#define BINARY_OP_XI 156 +#define BINARY_OP_XX 157 +#define BINARY_SUBSCR_DICT 158 +#define BINARY_SUBSCR_GETITEM 159 +#define BINARY_SUBSCR_LIST_INT 160 +#define BINARY_SUBSCR_STR_INT 161 +#define BINARY_SUBSCR_TUPLE_INT 162 +#define CALL_ALLOC_AND_ENTER_INIT 163 +#define CALL_BOUND_METHOD_EXACT_ARGS 164 +#define CALL_BOUND_METHOD_GENERAL 165 +#define CALL_BUILTIN_CLASS 166 +#define CALL_BUILTIN_FAST 167 +#define CALL_BUILTIN_FAST_WITH_KEYWORDS 168 +#define CALL_BUILTIN_O 169 +#define CALL_ISINSTANCE 170 +#define CALL_LEN 171 +#define CALL_LIST_APPEND 172 +#define CALL_METHOD_DESCRIPTOR_FAST 173 +#define CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS 174 +#define CALL_METHOD_DESCRIPTOR_NOARGS 175 +#define CALL_METHOD_DESCRIPTOR_O 176 +#define CALL_NON_PY_GENERAL 177 +#define CALL_PY_EXACT_ARGS 178 +#define CALL_PY_GENERAL 179 +#define CALL_STR_1 180 +#define CALL_TUPLE_1 181 +#define CALL_TYPE_1 182 +#define COMPARE_OP_FLOAT 183 +#define COMPARE_OP_INT 184 +#define COMPARE_OP_STR 185 +#define CONTAINS_OP_DICT 186 +#define CONTAINS_OP_SET 187 +#define FOR_ITER_GEN 188 +#define FOR_ITER_LIST 189 +#define FOR_ITER_RANGE 190 +#define FOR_ITER_TUPLE 191 +#define LOAD_ATTR_CLASS 192 +#define LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN 193 +#define LOAD_ATTR_INSTANCE_VALUE 194 +#define LOAD_ATTR_METHOD_LAZY_DICT 195 +#define LOAD_ATTR_METHOD_NO_DICT 196 +#define LOAD_ATTR_METHOD_WITH_VALUES 197 +#define LOAD_ATTR_MODULE 198 +#define LOAD_ATTR_NONDESCRIPTOR_NO_DICT 199 +#define LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES 200 +#define LOAD_ATTR_PROPERTY 201 +#define LOAD_ATTR_SLOT 202 +#define LOAD_ATTR_WITH_HINT 203 +#define LOAD_GLOBAL_BUILTIN 204 +#define LOAD_GLOBAL_MODULE 205 +#define LOAD_SUPER_ATTR_ATTR 206 +#define LOAD_SUPER_ATTR_METHOD 207 +#define RESUME_CHECK 208 +#define SEND_GEN 209 +#define STORE_ATTR_INSTANCE_VALUE 210 +#define STORE_ATTR_SLOT 211 +#define STORE_ATTR_WITH_HINT 212 +#define STORE_SUBSCR_DICT 213 +#define STORE_SUBSCR_LIST_INT 214 +#define TO_BOOL_ALWAYS_TRUE 215 +#define TO_BOOL_BOOL 216 +#define TO_BOOL_INT 217 +#define TO_BOOL_LIST 218 +#define TO_BOOL_NONE 219 +#define TO_BOOL_STR 220 +#define UNPACK_SEQUENCE_LIST 221 +#define UNPACK_SEQUENCE_TUPLE 222 +#define UNPACK_SEQUENCE_TWO_TUPLE 223 #define INSTRUMENTED_RESUME 236 #define INSTRUMENTED_END_FOR 237 #define INSTRUMENTED_END_SEND 238 diff --git a/Lib/_opcode_metadata.py b/Lib/_opcode_metadata.py index c5d1c79fe6b043..9f4de8b9cf166f 100644 --- a/Lib/_opcode_metadata.py +++ b/Lib/_opcode_metadata.py @@ -15,13 +15,14 @@ "TO_BOOL_STR", ], "BINARY_OP": [ - "BINARY_OP_MULTIPLY_INT", - "BINARY_OP_ADD_INT", - "BINARY_OP_SUBTRACT_INT", - "BINARY_OP_MULTIPLY_FLOAT", - "BINARY_OP_ADD_FLOAT", - "BINARY_OP_SUBTRACT_FLOAT", - "BINARY_OP_ADD_UNICODE", + "BINARY_OP_1X", + "BINARY_OP_1I", + "BINARY_OP_I1", + "BINARY_OP_II", + "BINARY_OP_IX", + "BINARY_OP_X1", + "BINARY_OP_XI", + "BINARY_OP_XX", "BINARY_OP_INPLACE_ADD_UNICODE", ], "BINARY_SUBSCR": [ @@ -110,80 +111,81 @@ } _specialized_opmap = { - 'BINARY_OP_ADD_FLOAT': 150, - 'BINARY_OP_ADD_INT': 151, - 'BINARY_OP_ADD_UNICODE': 152, + 'BINARY_OP_1I': 150, + 'BINARY_OP_1X': 151, + 'BINARY_OP_I1': 152, + 'BINARY_OP_II': 153, 'BINARY_OP_INPLACE_ADD_UNICODE': 3, - 'BINARY_OP_MULTIPLY_FLOAT': 153, - 'BINARY_OP_MULTIPLY_INT': 154, - 'BINARY_OP_SUBTRACT_FLOAT': 155, - 'BINARY_OP_SUBTRACT_INT': 156, - 'BINARY_SUBSCR_DICT': 157, - 'BINARY_SUBSCR_GETITEM': 158, - 'BINARY_SUBSCR_LIST_INT': 159, - 'BINARY_SUBSCR_STR_INT': 160, - 'BINARY_SUBSCR_TUPLE_INT': 161, - 'CALL_ALLOC_AND_ENTER_INIT': 162, - 'CALL_BOUND_METHOD_EXACT_ARGS': 163, - 'CALL_BOUND_METHOD_GENERAL': 164, - 'CALL_BUILTIN_CLASS': 165, - 'CALL_BUILTIN_FAST': 166, - 'CALL_BUILTIN_FAST_WITH_KEYWORDS': 167, - 'CALL_BUILTIN_O': 168, - 'CALL_ISINSTANCE': 169, - 'CALL_LEN': 170, - 'CALL_LIST_APPEND': 171, - 'CALL_METHOD_DESCRIPTOR_FAST': 172, - 'CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS': 173, - 'CALL_METHOD_DESCRIPTOR_NOARGS': 174, - 'CALL_METHOD_DESCRIPTOR_O': 175, - 'CALL_NON_PY_GENERAL': 176, - 'CALL_PY_EXACT_ARGS': 177, - 'CALL_PY_GENERAL': 178, - 'CALL_STR_1': 179, - 'CALL_TUPLE_1': 180, - 'CALL_TYPE_1': 181, - 'COMPARE_OP_FLOAT': 182, - 'COMPARE_OP_INT': 183, - 'COMPARE_OP_STR': 184, - 'CONTAINS_OP_DICT': 185, - 'CONTAINS_OP_SET': 186, - 'FOR_ITER_GEN': 187, - 'FOR_ITER_LIST': 188, - 'FOR_ITER_RANGE': 189, - 'FOR_ITER_TUPLE': 190, - 'LOAD_ATTR_CLASS': 191, - 'LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN': 192, - 'LOAD_ATTR_INSTANCE_VALUE': 193, - 'LOAD_ATTR_METHOD_LAZY_DICT': 194, - 'LOAD_ATTR_METHOD_NO_DICT': 195, - 'LOAD_ATTR_METHOD_WITH_VALUES': 196, - 'LOAD_ATTR_MODULE': 197, - 'LOAD_ATTR_NONDESCRIPTOR_NO_DICT': 198, - 'LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES': 199, - 'LOAD_ATTR_PROPERTY': 200, - 'LOAD_ATTR_SLOT': 201, - 'LOAD_ATTR_WITH_HINT': 202, - 'LOAD_GLOBAL_BUILTIN': 203, - 'LOAD_GLOBAL_MODULE': 204, - 'LOAD_SUPER_ATTR_ATTR': 205, - 'LOAD_SUPER_ATTR_METHOD': 206, - 'RESUME_CHECK': 207, - 'SEND_GEN': 208, - 'STORE_ATTR_INSTANCE_VALUE': 209, - 'STORE_ATTR_SLOT': 210, - 'STORE_ATTR_WITH_HINT': 211, - 'STORE_SUBSCR_DICT': 212, - 'STORE_SUBSCR_LIST_INT': 213, - 'TO_BOOL_ALWAYS_TRUE': 214, - 'TO_BOOL_BOOL': 215, - 'TO_BOOL_INT': 216, - 'TO_BOOL_LIST': 217, - 'TO_BOOL_NONE': 218, - 'TO_BOOL_STR': 219, - 'UNPACK_SEQUENCE_LIST': 220, - 'UNPACK_SEQUENCE_TUPLE': 221, - 'UNPACK_SEQUENCE_TWO_TUPLE': 222, + 'BINARY_OP_IX': 154, + 'BINARY_OP_X1': 155, + 'BINARY_OP_XI': 156, + 'BINARY_OP_XX': 157, + 'BINARY_SUBSCR_DICT': 158, + 'BINARY_SUBSCR_GETITEM': 159, + 'BINARY_SUBSCR_LIST_INT': 160, + 'BINARY_SUBSCR_STR_INT': 161, + 'BINARY_SUBSCR_TUPLE_INT': 162, + 'CALL_ALLOC_AND_ENTER_INIT': 163, + 'CALL_BOUND_METHOD_EXACT_ARGS': 164, + 'CALL_BOUND_METHOD_GENERAL': 165, + 'CALL_BUILTIN_CLASS': 166, + 'CALL_BUILTIN_FAST': 167, + 'CALL_BUILTIN_FAST_WITH_KEYWORDS': 168, + 'CALL_BUILTIN_O': 169, + 'CALL_ISINSTANCE': 170, + 'CALL_LEN': 171, + 'CALL_LIST_APPEND': 172, + 'CALL_METHOD_DESCRIPTOR_FAST': 173, + 'CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS': 174, + 'CALL_METHOD_DESCRIPTOR_NOARGS': 175, + 'CALL_METHOD_DESCRIPTOR_O': 176, + 'CALL_NON_PY_GENERAL': 177, + 'CALL_PY_EXACT_ARGS': 178, + 'CALL_PY_GENERAL': 179, + 'CALL_STR_1': 180, + 'CALL_TUPLE_1': 181, + 'CALL_TYPE_1': 182, + 'COMPARE_OP_FLOAT': 183, + 'COMPARE_OP_INT': 184, + 'COMPARE_OP_STR': 185, + 'CONTAINS_OP_DICT': 186, + 'CONTAINS_OP_SET': 187, + 'FOR_ITER_GEN': 188, + 'FOR_ITER_LIST': 189, + 'FOR_ITER_RANGE': 190, + 'FOR_ITER_TUPLE': 191, + 'LOAD_ATTR_CLASS': 192, + 'LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN': 193, + 'LOAD_ATTR_INSTANCE_VALUE': 194, + 'LOAD_ATTR_METHOD_LAZY_DICT': 195, + 'LOAD_ATTR_METHOD_NO_DICT': 196, + 'LOAD_ATTR_METHOD_WITH_VALUES': 197, + 'LOAD_ATTR_MODULE': 198, + 'LOAD_ATTR_NONDESCRIPTOR_NO_DICT': 199, + 'LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES': 200, + 'LOAD_ATTR_PROPERTY': 201, + 'LOAD_ATTR_SLOT': 202, + 'LOAD_ATTR_WITH_HINT': 203, + 'LOAD_GLOBAL_BUILTIN': 204, + 'LOAD_GLOBAL_MODULE': 205, + 'LOAD_SUPER_ATTR_ATTR': 206, + 'LOAD_SUPER_ATTR_METHOD': 207, + 'RESUME_CHECK': 208, + 'SEND_GEN': 209, + 'STORE_ATTR_INSTANCE_VALUE': 210, + 'STORE_ATTR_SLOT': 211, + 'STORE_ATTR_WITH_HINT': 212, + 'STORE_SUBSCR_DICT': 213, + 'STORE_SUBSCR_LIST_INT': 214, + 'TO_BOOL_ALWAYS_TRUE': 215, + 'TO_BOOL_BOOL': 216, + 'TO_BOOL_INT': 217, + 'TO_BOOL_LIST': 218, + 'TO_BOOL_NONE': 219, + 'TO_BOOL_STR': 220, + 'UNPACK_SEQUENCE_LIST': 221, + 'UNPACK_SEQUENCE_TUPLE': 222, + 'UNPACK_SEQUENCE_TWO_TUPLE': 223, } opmap = { diff --git a/Lib/dis.py b/Lib/dis.py index f5bb7976b5fa62..756eca4171420c 100644 --- a/Lib/dis.py +++ b/Lib/dis.py @@ -752,8 +752,10 @@ def _get_instructions_bytes(code, linestarts=None, line_offset=0, co_positions=N if caches: cache_info = [] + data_offset = offset + 2 for name, size in _cache_format[opname[deop]].items(): - data = code[offset + 2: offset + 2 + 2 * size] + data = code[data_offset: data_offset + 2 * size] + data_offset += 2 * size cache_info.append((name, size, data)) else: cache_info = None diff --git a/Lib/importlib/_bootstrap_external.py b/Lib/importlib/_bootstrap_external.py index 30c91801212374..c29b9e6e926b45 100644 --- a/Lib/importlib/_bootstrap_external.py +++ b/Lib/importlib/_bootstrap_external.py @@ -474,8 +474,9 @@ def _write_atomic(path, data, mode=0o666): # Python 3.13a6 3570 (Add __firstlineno__ class attribute) # Python 3.14a1 3600 (Add LOAD_COMMON_CONSTANT) # Python 3.14a1 3601 (Fix miscompilation of private names in generic classes) +# Python 3.14a1 3602 (Change specialization of BINARY_OP) -# Python 3.15 will start with 3700 +# Python 3.15 will start with 3650 # Please don't copy-paste the same pre-release tag for new entries above!!! # You should always use the *upcoming* tag. For example, if 3.12a6 came out @@ -490,7 +491,7 @@ def _write_atomic(path, data, mode=0o666): # Whenever MAGIC_NUMBER is changed, the ranges in the magic_values array # in PC/launcher.c must also be updated. -MAGIC_NUMBER = (3601).to_bytes(2, 'little') + b'\r\n' +MAGIC_NUMBER = (3602).to_bytes(2, 'little') + b'\r\n' _RAW_MAGIC_NUMBER = int.from_bytes(MAGIC_NUMBER, 'little') # For import.c diff --git a/Lib/opcode.py b/Lib/opcode.py index 85e37ff53e577f..be18e03ebc910f 100644 --- a/Lib/opcode.py +++ b/Lib/opcode.py @@ -50,6 +50,7 @@ }, "BINARY_OP": { "counter": 1, + "type_versions": 1, }, "UNPACK_SEQUENCE": { "counter": 1, diff --git a/Lib/test/test_capi/test_opt.py b/Lib/test/test_capi/test_opt.py index 0491ff9b84d486..04ce949ba9a701 100644 --- a/Lib/test/test_capi/test_opt.py +++ b/Lib/test/test_capi/test_opt.py @@ -117,17 +117,26 @@ def testfunc(x): self.assertEqual(hash(code), hash(replace_code)) -def get_first_executor(func): + +def get_nth_executor(func, n): code = func.__code__ co_code = code.co_code + count = 0 for i in range(0, len(co_code), 2): try: - return _opcode.get_executor(code, i) + ex = _opcode.get_executor(code, i) + if count == n: + return ex + else: + count += 1 except ValueError: pass return None +def get_first_executor(func): + return get_nth_executor(func, 0) + def iter_opnames(ex): for item in ex: yield item[0] @@ -234,7 +243,7 @@ def testfunc(x): with temporary_optimizer(opt): testfunc(1000) - ex = get_first_executor(testfunc) + ex = get_nth_executor(testfunc, 1) self.assertIsNotNone(ex) uops = get_opnames(ex) self.assertIn("_JUMP_TO_TOP", uops) @@ -408,7 +417,7 @@ def testfunc(n): uops = get_opnames(ex) # Since there is no JUMP_FORWARD instruction, # look for indirect evidence: the += operator - self.assertIn("_BINARY_OP_ADD_INT", uops) + self.assertIn("_BINARY_OP_TABLE_NN", uops) def test_for_iter_range(self): def testfunc(n): @@ -504,7 +513,7 @@ def dummy(x): self.assertIsNotNone(ex) uops = get_opnames(ex) self.assertIn("_PUSH_FRAME", uops) - self.assertIn("_BINARY_OP_ADD_INT", uops) + self.assertIn("_BINARY_OP_TABLE_NN", uops) def test_branch_taken(self): def testfunc(n): @@ -539,14 +548,14 @@ def testfunc(n, m): x = 0 for i in range(m): for j in MyIter(n): - x += 1000*i + j + x += 2*i + j return x opt = _testinternalcapi.new_uop_optimizer() with temporary_optimizer(opt): x = testfunc(10, 10) - self.assertEqual(x, sum(range(10)) * 10010) + self.assertEqual(x, sum(range(10)) * 30) ex = get_first_executor(testfunc) self.assertIsNotNone(ex) @@ -612,7 +621,7 @@ def testfunc(loops): res, ex = self._run_with_optimizer(testfunc, 32) self.assertIsNotNone(ex) self.assertEqual(res, 63) - binop_count = [opname for opname in iter_opnames(ex) if opname == "_BINARY_OP_ADD_INT"] + binop_count = [opname for opname in iter_opnames(ex) if opname == "_BINARY_OP_TABLE_NN"] guard_both_int_count = [opname for opname in iter_opnames(ex) if opname == "_GUARD_BOTH_INT"] self.assertGreaterEqual(len(binop_count), 3) self.assertLessEqual(len(guard_both_int_count), 1) @@ -636,7 +645,7 @@ def testfunc(loops): ex = get_first_executor(testfunc) self.assertIsNotNone(ex) self.assertEqual(res, 124) - binop_count = [opname for opname in iter_opnames(ex) if opname == "_BINARY_OP_ADD_INT"] + binop_count = [opname for opname in iter_opnames(ex) if opname == "_BINARY_OP_TABLE_NN"] guard_both_int_count = [opname for opname in iter_opnames(ex) if opname == "_GUARD_BOTH_INT"] self.assertGreaterEqual(len(binop_count), 3) self.assertLessEqual(len(guard_both_int_count), 1) @@ -660,7 +669,7 @@ def testfunc(loops): ex = get_first_executor(testfunc) self.assertIsNotNone(ex) self.assertEqual(res, 124) - binop_count = [opname for opname in iter_opnames(ex) if opname == "_BINARY_OP_ADD_INT"] + binop_count = [opname for opname in iter_opnames(ex) if opname == "_BINARY_OP_TABLE_NN"] guard_both_int_count = [opname for opname in iter_opnames(ex) if opname == "_GUARD_BOTH_INT"] self.assertGreaterEqual(len(binop_count), 3) self.assertLessEqual(len(guard_both_int_count), 1) @@ -678,7 +687,7 @@ def testfunc(loops): res, ex = self._run_with_optimizer(testfunc, 64) self.assertIsNotNone(ex) - binop_count = [opname for opname in iter_opnames(ex) if opname == "_BINARY_OP_ADD_INT"] + binop_count = [opname for opname in iter_opnames(ex) if opname == "_BINARY_OP_TABLE_NN"] self.assertGreaterEqual(len(binop_count), 3) def test_call_py_exact_args(self): @@ -692,7 +701,7 @@ def dummy(x): self.assertIsNotNone(ex) uops = get_opnames(ex) self.assertIn("_PUSH_FRAME", uops) - self.assertIn("_BINARY_OP_ADD_INT", uops) + self.assertIn("_BINARY_OP_TABLE_NN", uops) self.assertNotIn("_CHECK_PEP_523", uops) def test_int_type_propagate_through_range(self): @@ -724,8 +733,8 @@ def testfunc(n): self.assertEqual(res, 4) self.assertIsNotNone(ex) uops = get_opnames(ex) - self.assertIn("_GUARD_BOTH_INT", uops) - guard_count = [opname for opname in iter_opnames(ex) if opname == "_GUARD_BOTH_INT"] + self.assertIn("_GUARD_VERSION_TYPES", uops) + guard_count = [opname for opname in iter_opnames(ex) if opname == "_GUARD_VERSION_TYPES"] self.assertEqual(len(guard_count), 1) def test_comprehension(self): @@ -819,7 +828,7 @@ def testfunc(n): self.assertLessEqual(len(guard_both_float_count), 1) # TODO gh-115506: this assertion may change after propagating constants. # We'll also need to verify that propagation actually occurs. - self.assertIn("_BINARY_OP_ADD_FLOAT", uops) + self.assertIn("_BINARY_OP_TABLE_DD", uops) def test_float_subtract_constant_propagation(self): def testfunc(n): @@ -839,7 +848,7 @@ def testfunc(n): self.assertLessEqual(len(guard_both_float_count), 1) # TODO gh-115506: this assertion may change after propagating constants. # We'll also need to verify that propagation actually occurs. - self.assertIn("_BINARY_OP_SUBTRACT_FLOAT", uops) + self.assertIn("_BINARY_OP_TABLE_DD", uops) def test_float_multiply_constant_propagation(self): def testfunc(n): @@ -859,7 +868,7 @@ def testfunc(n): self.assertLessEqual(len(guard_both_float_count), 1) # TODO gh-115506: this assertion may change after propagating constants. # We'll also need to verify that propagation actually occurs. - self.assertIn("_BINARY_OP_MULTIPLY_FLOAT", uops) + self.assertIn("_BINARY_OP_TABLE_DD", uops) def test_add_unicode_propagation(self): def testfunc(n): @@ -877,7 +886,7 @@ def testfunc(n): uops = get_opnames(ex) guard_both_unicode_count = [opname for opname in iter_opnames(ex) if opname == "_GUARD_BOTH_UNICODE"] self.assertLessEqual(len(guard_both_unicode_count), 1) - self.assertIn("_BINARY_OP_ADD_UNICODE", uops) + self.assertIn("_BINARY_OP_TABLE_NN", uops) def test_compare_op_type_propagation_float(self): def testfunc(n): @@ -990,7 +999,7 @@ def testfunc(n): self.assertIsNotNone(ex) uops = get_opnames(ex) self.assertNotIn("_GUARD_BOTH_INT", uops) - self.assertIn("_BINARY_OP_ADD_INT", uops) + self.assertIn("_BINARY_OP_TABLE_NN", uops) # Try again, but between the runs, set the global to a float. # This should result in no executor the second time. ns = {} @@ -999,7 +1008,7 @@ def testfunc(n): ns['_test_global'] = 0 _, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD) self.assertIsNone(ex) - ns['_test_global'] = 3.14 + ns['_test_global'] = "" _, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD) self.assertIsNone(ex) diff --git a/Lib/test/test_dis.py b/Lib/test/test_dis.py index b1a1b77c53e8cb..6fac5105e49e69 100644 --- a/Lib/test/test_dis.py +++ b/Lib/test/test_dis.py @@ -399,7 +399,7 @@ def wrap_func_w_kwargs(): BINARY_OP 13 (+=) STORE_NAME 0 (x) - 2 JUMP_BACKWARD 7 (to L1) + 2 JUMP_BACKWARD 8 (to L1) """ dis_traceback = """\ @@ -782,7 +782,7 @@ def foo(x): POP_TOP L1: RESUME 0 LOAD_FAST 0 (.0) - L2: FOR_ITER 10 (to L3) + L2: FOR_ITER 11 (to L3) STORE_FAST 1 (z) LOAD_DEREF 2 (x) LOAD_FAST 1 (z) @@ -790,7 +790,7 @@ def foo(x): YIELD_VALUE 0 RESUME 5 POP_TOP - JUMP_BACKWARD 12 (to L2) + JUMP_BACKWARD 13 (to L2) L3: END_FOR POP_TOP RETURN_CONST 0 (None) @@ -1141,12 +1141,12 @@ def test_binary_specialize(self): co_int = compile('a + b', "", "eval") self.code_quicken(lambda: exec(co_int, {}, {'a': 1, 'b': 2})) got = self.get_disassembly(co_int, adaptive=True) - self.do_disassembly_compare(got, binary_op_quicken % "BINARY_OP_ADD_INT 0 (+)") + self.do_disassembly_compare(got, binary_op_quicken % "BINARY_OP_II 0 (+)") co_unicode = compile('a + b', "", "eval") self.code_quicken(lambda: exec(co_unicode, {}, {'a': 'a', 'b': 'b'})) got = self.get_disassembly(co_unicode, adaptive=True) - self.do_disassembly_compare(got, binary_op_quicken % "BINARY_OP_ADD_UNICODE 0 (+)") + self.do_disassembly_compare(got, binary_op_quicken % "BINARY_OP_II 0 (+)") binary_subscr_quicken = """\ 0 RESUME_CHECK 0 @@ -1703,92 +1703,92 @@ def _prepare_test_cases(): Instruction(opname='POP_TOP', opcode=31, arg=None, argval=None, argrepr='', offset=112, start_offset=112, starts_line=False, line_number=10, label=None, positions=None, cache_info=None), Instruction(opname='LOAD_FAST_CHECK', opcode=87, arg=0, argval='i', argrepr='i', offset=114, start_offset=114, starts_line=True, line_number=11, label=5, positions=None, cache_info=None), Instruction(opname='TO_BOOL', opcode=39, arg=None, argval=None, argrepr='', offset=116, start_offset=116, starts_line=False, line_number=11, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('version', 2, b'\x00\x00\x00\x00')]), - Instruction(opname='POP_JUMP_IF_FALSE', opcode=97, arg=40, argval=208, argrepr='to L9', offset=124, start_offset=124, starts_line=False, line_number=11, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00')]), + Instruction(opname='POP_JUMP_IF_FALSE', opcode=97, arg=41, argval=210, argrepr='to L9', offset=124, start_offset=124, starts_line=False, line_number=11, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00')]), Instruction(opname='LOAD_GLOBAL', opcode=91, arg=3, argval='print', argrepr='print + NULL', offset=128, start_offset=128, starts_line=True, line_number=12, label=6, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('index', 1, b'\x00\x00'), ('module_keys_version', 1, b'\x00\x00'), ('builtin_keys_version', 1, b'\x00\x00')]), Instruction(opname='LOAD_FAST', opcode=85, arg=0, argval='i', argrepr='i', offset=138, start_offset=138, starts_line=False, line_number=12, label=None, positions=None, cache_info=None), Instruction(opname='CALL', opcode=52, arg=1, argval=1, argrepr='', offset=140, start_offset=140, starts_line=False, line_number=12, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]), Instruction(opname='POP_TOP', opcode=31, arg=None, argval=None, argrepr='', offset=148, start_offset=148, starts_line=False, line_number=12, label=None, positions=None, cache_info=None), Instruction(opname='LOAD_FAST', opcode=85, arg=0, argval='i', argrepr='i', offset=150, start_offset=150, starts_line=True, line_number=13, label=None, positions=None, cache_info=None), Instruction(opname='LOAD_CONST', opcode=83, arg=5, argval=1, argrepr='1', offset=152, start_offset=152, starts_line=False, line_number=13, label=None, positions=None, cache_info=None), - Instruction(opname='BINARY_OP', opcode=44, arg=23, argval=23, argrepr='-=', offset=154, start_offset=154, starts_line=False, line_number=13, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00')]), - Instruction(opname='STORE_FAST', opcode=110, arg=0, argval='i', argrepr='i', offset=158, start_offset=158, starts_line=False, line_number=13, label=None, positions=None, cache_info=None), - Instruction(opname='LOAD_FAST', opcode=85, arg=0, argval='i', argrepr='i', offset=160, start_offset=160, starts_line=True, line_number=14, label=None, positions=None, cache_info=None), - Instruction(opname='LOAD_CONST', opcode=83, arg=3, argval=6, argrepr='6', offset=162, start_offset=162, starts_line=False, line_number=14, label=None, positions=None, cache_info=None), - Instruction(opname='COMPARE_OP', opcode=57, arg=148, argval='>', argrepr='bool(>)', offset=164, start_offset=164, starts_line=False, line_number=14, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00')]), - Instruction(opname='POP_JUMP_IF_FALSE', opcode=97, arg=2, argval=176, argrepr='to L7', offset=168, start_offset=168, starts_line=False, line_number=14, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00')]), - Instruction(opname='JUMP_BACKWARD', opcode=76, arg=31, argval=114, argrepr='to L5', offset=172, start_offset=172, starts_line=True, line_number=15, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00')]), - Instruction(opname='LOAD_FAST', opcode=85, arg=0, argval='i', argrepr='i', offset=176, start_offset=176, starts_line=True, line_number=16, label=7, positions=None, cache_info=None), - Instruction(opname='LOAD_CONST', opcode=83, arg=2, argval=4, argrepr='4', offset=178, start_offset=178, starts_line=False, line_number=16, label=None, positions=None, cache_info=None), - Instruction(opname='COMPARE_OP', opcode=57, arg=18, argval='<', argrepr='bool(<)', offset=180, start_offset=180, starts_line=False, line_number=16, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00')]), - Instruction(opname='POP_JUMP_IF_FALSE', opcode=97, arg=1, argval=190, argrepr='to L8', offset=184, start_offset=184, starts_line=False, line_number=16, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00')]), - Instruction(opname='JUMP_FORWARD', opcode=78, arg=20, argval=230, argrepr='to L10', offset=188, start_offset=188, starts_line=True, line_number=17, label=None, positions=None, cache_info=None), - Instruction(opname='LOAD_FAST', opcode=85, arg=0, argval='i', argrepr='i', offset=190, start_offset=190, starts_line=True, line_number=11, label=8, positions=None, cache_info=None), - Instruction(opname='TO_BOOL', opcode=39, arg=None, argval=None, argrepr='', offset=192, start_offset=192, starts_line=False, line_number=11, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('version', 2, b'\x00\x00\x00\x00')]), - Instruction(opname='POP_JUMP_IF_FALSE', opcode=97, arg=2, argval=208, argrepr='to L9', offset=200, start_offset=200, starts_line=False, line_number=11, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00')]), - Instruction(opname='JUMP_BACKWARD', opcode=76, arg=40, argval=128, argrepr='to L6', offset=204, start_offset=204, starts_line=False, line_number=11, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00')]), - Instruction(opname='LOAD_GLOBAL', opcode=91, arg=3, argval='print', argrepr='print + NULL', offset=208, start_offset=208, starts_line=True, line_number=19, label=9, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('index', 1, b'\x00\x00'), ('module_keys_version', 1, b'\x00\x00'), ('builtin_keys_version', 1, b'\x00\x00')]), - Instruction(opname='LOAD_CONST', opcode=83, arg=6, argval='Who let lolcatz into this test suite?', argrepr="'Who let lolcatz into this test suite?'", offset=218, start_offset=218, starts_line=False, line_number=19, label=None, positions=None, cache_info=None), - Instruction(opname='CALL', opcode=52, arg=1, argval=1, argrepr='', offset=220, start_offset=220, starts_line=False, line_number=19, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]), - Instruction(opname='POP_TOP', opcode=31, arg=None, argval=None, argrepr='', offset=228, start_offset=228, starts_line=False, line_number=19, label=None, positions=None, cache_info=None), - Instruction(opname='NOP', opcode=29, arg=None, argval=None, argrepr='', offset=230, start_offset=230, starts_line=True, line_number=20, label=10, positions=None, cache_info=None), - Instruction(opname='LOAD_CONST', opcode=83, arg=5, argval=1, argrepr='1', offset=232, start_offset=232, starts_line=True, line_number=21, label=None, positions=None, cache_info=None), - Instruction(opname='LOAD_CONST', opcode=83, arg=7, argval=0, argrepr='0', offset=234, start_offset=234, starts_line=False, line_number=21, label=None, positions=None, cache_info=None), - Instruction(opname='BINARY_OP', opcode=44, arg=11, argval=11, argrepr='/', offset=236, start_offset=236, starts_line=False, line_number=21, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00')]), - Instruction(opname='POP_TOP', opcode=31, arg=None, argval=None, argrepr='', offset=240, start_offset=240, starts_line=False, line_number=21, label=None, positions=None, cache_info=None), - Instruction(opname='LOAD_FAST', opcode=85, arg=0, argval='i', argrepr='i', offset=242, start_offset=242, starts_line=True, line_number=25, label=None, positions=None, cache_info=None), - Instruction(opname='BEFORE_WITH', opcode=2, arg=None, argval=None, argrepr='', offset=244, start_offset=244, starts_line=False, line_number=25, label=None, positions=None, cache_info=None), - Instruction(opname='STORE_FAST', opcode=110, arg=1, argval='dodgy', argrepr='dodgy', offset=246, start_offset=246, starts_line=False, line_number=25, label=None, positions=None, cache_info=None), - Instruction(opname='LOAD_GLOBAL', opcode=91, arg=3, argval='print', argrepr='print + NULL', offset=248, start_offset=248, starts_line=True, line_number=26, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('index', 1, b'\x00\x00'), ('module_keys_version', 1, b'\x00\x00'), ('builtin_keys_version', 1, b'\x00\x00')]), - Instruction(opname='LOAD_CONST', opcode=83, arg=8, argval='Never reach this', argrepr="'Never reach this'", offset=258, start_offset=258, starts_line=False, line_number=26, label=None, positions=None, cache_info=None), - Instruction(opname='CALL', opcode=52, arg=1, argval=1, argrepr='', offset=260, start_offset=260, starts_line=False, line_number=26, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]), - Instruction(opname='POP_TOP', opcode=31, arg=None, argval=None, argrepr='', offset=268, start_offset=268, starts_line=False, line_number=26, label=None, positions=None, cache_info=None), - Instruction(opname='LOAD_CONST', opcode=83, arg=0, argval=None, argrepr='None', offset=270, start_offset=270, starts_line=True, line_number=25, label=None, positions=None, cache_info=None), - Instruction(opname='LOAD_CONST', opcode=83, arg=0, argval=None, argrepr='None', offset=272, start_offset=272, starts_line=False, line_number=25, label=None, positions=None, cache_info=None), - Instruction(opname='LOAD_CONST', opcode=83, arg=0, argval=None, argrepr='None', offset=274, start_offset=274, starts_line=False, line_number=25, label=None, positions=None, cache_info=None), - Instruction(opname='CALL', opcode=52, arg=2, argval=2, argrepr='', offset=276, start_offset=276, starts_line=False, line_number=25, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]), - Instruction(opname='POP_TOP', opcode=31, arg=None, argval=None, argrepr='', offset=284, start_offset=284, starts_line=False, line_number=25, label=None, positions=None, cache_info=None), - Instruction(opname='LOAD_GLOBAL', opcode=91, arg=3, argval='print', argrepr='print + NULL', offset=286, start_offset=286, starts_line=True, line_number=28, label=11, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('index', 1, b'\x00\x00'), ('module_keys_version', 1, b'\x00\x00'), ('builtin_keys_version', 1, b'\x00\x00')]), - Instruction(opname='LOAD_CONST', opcode=83, arg=10, argval="OK, now we're done", argrepr='"OK, now we\'re done"', offset=296, start_offset=296, starts_line=False, line_number=28, label=None, positions=None, cache_info=None), - Instruction(opname='CALL', opcode=52, arg=1, argval=1, argrepr='', offset=298, start_offset=298, starts_line=False, line_number=28, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]), - Instruction(opname='POP_TOP', opcode=31, arg=None, argval=None, argrepr='', offset=306, start_offset=306, starts_line=False, line_number=28, label=None, positions=None, cache_info=None), - Instruction(opname='RETURN_CONST', opcode=103, arg=0, argval=None, argrepr='None', offset=308, start_offset=308, starts_line=False, line_number=28, label=None, positions=None, cache_info=None), - Instruction(opname='PUSH_EXC_INFO', opcode=32, arg=None, argval=None, argrepr='', offset=310, start_offset=310, starts_line=True, line_number=25, label=None, positions=None, cache_info=None), - Instruction(opname='WITH_EXCEPT_START', opcode=43, arg=None, argval=None, argrepr='', offset=312, start_offset=312, starts_line=False, line_number=25, label=None, positions=None, cache_info=None), - Instruction(opname='TO_BOOL', opcode=39, arg=None, argval=None, argrepr='', offset=314, start_offset=314, starts_line=False, line_number=25, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('version', 2, b'\x00\x00\x00\x00')]), - Instruction(opname='POP_JUMP_IF_TRUE', opcode=100, arg=1, argval=328, argrepr='to L12', offset=322, start_offset=322, starts_line=False, line_number=25, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00')]), - Instruction(opname='RERAISE', opcode=102, arg=2, argval=2, argrepr='', offset=326, start_offset=326, starts_line=False, line_number=25, label=None, positions=None, cache_info=None), - Instruction(opname='POP_TOP', opcode=31, arg=None, argval=None, argrepr='', offset=328, start_offset=328, starts_line=False, line_number=25, label=12, positions=None, cache_info=None), - Instruction(opname='POP_EXCEPT', opcode=30, arg=None, argval=None, argrepr='', offset=330, start_offset=330, starts_line=False, line_number=25, label=None, positions=None, cache_info=None), - Instruction(opname='POP_TOP', opcode=31, arg=None, argval=None, argrepr='', offset=332, start_offset=332, starts_line=False, line_number=25, label=None, positions=None, cache_info=None), - Instruction(opname='POP_TOP', opcode=31, arg=None, argval=None, argrepr='', offset=334, start_offset=334, starts_line=False, line_number=25, label=None, positions=None, cache_info=None), - Instruction(opname='JUMP_BACKWARD_NO_INTERRUPT', opcode=77, arg=26, argval=286, argrepr='to L11', offset=336, start_offset=336, starts_line=False, line_number=25, label=None, positions=None, cache_info=None), - Instruction(opname='COPY', opcode=60, arg=3, argval=3, argrepr='', offset=338, start_offset=338, starts_line=True, line_number=None, label=None, positions=None, cache_info=None), - Instruction(opname='POP_EXCEPT', opcode=30, arg=None, argval=None, argrepr='', offset=340, start_offset=340, starts_line=False, line_number=None, label=None, positions=None, cache_info=None), - Instruction(opname='RERAISE', opcode=102, arg=1, argval=1, argrepr='', offset=342, start_offset=342, starts_line=False, line_number=None, label=None, positions=None, cache_info=None), - Instruction(opname='PUSH_EXC_INFO', opcode=32, arg=None, argval=None, argrepr='', offset=344, start_offset=344, starts_line=False, line_number=None, label=None, positions=None, cache_info=None), - Instruction(opname='LOAD_GLOBAL', opcode=91, arg=4, argval='ZeroDivisionError', argrepr='ZeroDivisionError', offset=346, start_offset=346, starts_line=True, line_number=22, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('index', 1, b'\x00\x00'), ('module_keys_version', 1, b'\x00\x00'), ('builtin_keys_version', 1, b'\x00\x00')]), - Instruction(opname='CHECK_EXC_MATCH', opcode=7, arg=None, argval=None, argrepr='', offset=356, start_offset=356, starts_line=False, line_number=22, label=None, positions=None, cache_info=None), - Instruction(opname='POP_JUMP_IF_FALSE', opcode=97, arg=14, argval=390, argrepr='to L13', offset=358, start_offset=358, starts_line=False, line_number=22, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00')]), - Instruction(opname='POP_TOP', opcode=31, arg=None, argval=None, argrepr='', offset=362, start_offset=362, starts_line=False, line_number=22, label=None, positions=None, cache_info=None), - Instruction(opname='LOAD_GLOBAL', opcode=91, arg=3, argval='print', argrepr='print + NULL', offset=364, start_offset=364, starts_line=True, line_number=23, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('index', 1, b'\x00\x00'), ('module_keys_version', 1, b'\x00\x00'), ('builtin_keys_version', 1, b'\x00\x00')]), - Instruction(opname='LOAD_CONST', opcode=83, arg=9, argval='Here we go, here we go, here we go...', argrepr="'Here we go, here we go, here we go...'", offset=374, start_offset=374, starts_line=False, line_number=23, label=None, positions=None, cache_info=None), - Instruction(opname='CALL', opcode=52, arg=1, argval=1, argrepr='', offset=376, start_offset=376, starts_line=False, line_number=23, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]), - Instruction(opname='POP_TOP', opcode=31, arg=None, argval=None, argrepr='', offset=384, start_offset=384, starts_line=False, line_number=23, label=None, positions=None, cache_info=None), - Instruction(opname='POP_EXCEPT', opcode=30, arg=None, argval=None, argrepr='', offset=386, start_offset=386, starts_line=False, line_number=23, label=None, positions=None, cache_info=None), - Instruction(opname='JUMP_BACKWARD_NO_INTERRUPT', opcode=77, arg=52, argval=286, argrepr='to L11', offset=388, start_offset=388, starts_line=False, line_number=23, label=None, positions=None, cache_info=None), - Instruction(opname='RERAISE', opcode=102, arg=0, argval=0, argrepr='', offset=390, start_offset=390, starts_line=True, line_number=22, label=13, positions=None, cache_info=None), - Instruction(opname='COPY', opcode=60, arg=3, argval=3, argrepr='', offset=392, start_offset=392, starts_line=True, line_number=None, label=None, positions=None, cache_info=None), - Instruction(opname='POP_EXCEPT', opcode=30, arg=None, argval=None, argrepr='', offset=394, start_offset=394, starts_line=False, line_number=None, label=None, positions=None, cache_info=None), - Instruction(opname='RERAISE', opcode=102, arg=1, argval=1, argrepr='', offset=396, start_offset=396, starts_line=False, line_number=None, label=None, positions=None, cache_info=None), - Instruction(opname='PUSH_EXC_INFO', opcode=32, arg=None, argval=None, argrepr='', offset=398, start_offset=398, starts_line=False, line_number=None, label=None, positions=None, cache_info=None), - Instruction(opname='LOAD_GLOBAL', opcode=91, arg=3, argval='print', argrepr='print + NULL', offset=400, start_offset=400, starts_line=True, line_number=28, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('index', 1, b'\x00\x00'), ('module_keys_version', 1, b'\x00\x00'), ('builtin_keys_version', 1, b'\x00\x00')]), - Instruction(opname='LOAD_CONST', opcode=83, arg=10, argval="OK, now we're done", argrepr='"OK, now we\'re done"', offset=410, start_offset=410, starts_line=False, line_number=28, label=None, positions=None, cache_info=None), - Instruction(opname='CALL', opcode=52, arg=1, argval=1, argrepr='', offset=412, start_offset=412, starts_line=False, line_number=28, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]), - Instruction(opname='POP_TOP', opcode=31, arg=None, argval=None, argrepr='', offset=420, start_offset=420, starts_line=False, line_number=28, label=None, positions=None, cache_info=None), - Instruction(opname='RERAISE', opcode=102, arg=0, argval=0, argrepr='', offset=422, start_offset=422, starts_line=False, line_number=28, label=None, positions=None, cache_info=None), - Instruction(opname='COPY', opcode=60, arg=3, argval=3, argrepr='', offset=424, start_offset=424, starts_line=True, line_number=None, label=None, positions=None, cache_info=None), - Instruction(opname='POP_EXCEPT', opcode=30, arg=None, argval=None, argrepr='', offset=426, start_offset=426, starts_line=False, line_number=None, label=None, positions=None, cache_info=None), - Instruction(opname='RERAISE', opcode=102, arg=1, argval=1, argrepr='', offset=428, start_offset=428, starts_line=False, line_number=None, label=None, positions=None, cache_info=None), + Instruction(opname='BINARY_OP', opcode=44, arg=23, argval=23, argrepr='-=', offset=154, start_offset=154, starts_line=False, line_number=13, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('type_versions', 1, b'\x00\x00')]), + Instruction(opname='STORE_FAST', opcode=110, arg=0, argval='i', argrepr='i', offset=160, start_offset=160, starts_line=False, line_number=13, label=None, positions=None, cache_info=None), + Instruction(opname='LOAD_FAST', opcode=85, arg=0, argval='i', argrepr='i', offset=162, start_offset=162, starts_line=True, line_number=14, label=None, positions=None, cache_info=None), + Instruction(opname='LOAD_CONST', opcode=83, arg=3, argval=6, argrepr='6', offset=164, start_offset=164, starts_line=False, line_number=14, label=None, positions=None, cache_info=None), + Instruction(opname='COMPARE_OP', opcode=57, arg=148, argval='>', argrepr='bool(>)', offset=166, start_offset=166, starts_line=False, line_number=14, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00')]), + Instruction(opname='POP_JUMP_IF_FALSE', opcode=97, arg=2, argval=178, argrepr='to L7', offset=170, start_offset=170, starts_line=False, line_number=14, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00')]), + Instruction(opname='JUMP_BACKWARD', opcode=76, arg=32, argval=114, argrepr='to L5', offset=174, start_offset=174, starts_line=True, line_number=15, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00')]), + Instruction(opname='LOAD_FAST', opcode=85, arg=0, argval='i', argrepr='i', offset=178, start_offset=178, starts_line=True, line_number=16, label=7, positions=None, cache_info=None), + Instruction(opname='LOAD_CONST', opcode=83, arg=2, argval=4, argrepr='4', offset=180, start_offset=180, starts_line=False, line_number=16, label=None, positions=None, cache_info=None), + Instruction(opname='COMPARE_OP', opcode=57, arg=18, argval='<', argrepr='bool(<)', offset=182, start_offset=182, starts_line=False, line_number=16, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00')]), + Instruction(opname='POP_JUMP_IF_FALSE', opcode=97, arg=1, argval=192, argrepr='to L8', offset=186, start_offset=186, starts_line=False, line_number=16, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00')]), + Instruction(opname='JUMP_FORWARD', opcode=78, arg=20, argval=232, argrepr='to L10', offset=190, start_offset=190, starts_line=True, line_number=17, label=None, positions=None, cache_info=None), + Instruction(opname='LOAD_FAST', opcode=85, arg=0, argval='i', argrepr='i', offset=192, start_offset=192, starts_line=True, line_number=11, label=8, positions=None, cache_info=None), + Instruction(opname='TO_BOOL', opcode=39, arg=None, argval=None, argrepr='', offset=194, start_offset=194, starts_line=False, line_number=11, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('version', 2, b'\x00\x00\x00\x00')]), + Instruction(opname='POP_JUMP_IF_FALSE', opcode=97, arg=2, argval=210, argrepr='to L9', offset=202, start_offset=202, starts_line=False, line_number=11, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00')]), + Instruction(opname='JUMP_BACKWARD', opcode=76, arg=41, argval=128, argrepr='to L6', offset=206, start_offset=206, starts_line=False, line_number=11, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00')]), + Instruction(opname='LOAD_GLOBAL', opcode=91, arg=3, argval='print', argrepr='print + NULL', offset=210, start_offset=210, starts_line=True, line_number=19, label=9, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('index', 1, b'\x00\x00'), ('module_keys_version', 1, b'\x00\x00'), ('builtin_keys_version', 1, b'\x00\x00')]), + Instruction(opname='LOAD_CONST', opcode=83, arg=6, argval='Who let lolcatz into this test suite?', argrepr="'Who let lolcatz into this test suite?'", offset=220, start_offset=220, starts_line=False, line_number=19, label=None, positions=None, cache_info=None), + Instruction(opname='CALL', opcode=52, arg=1, argval=1, argrepr='', offset=222, start_offset=222, starts_line=False, line_number=19, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]), + Instruction(opname='POP_TOP', opcode=31, arg=None, argval=None, argrepr='', offset=230, start_offset=230, starts_line=False, line_number=19, label=None, positions=None, cache_info=None), + Instruction(opname='NOP', opcode=29, arg=None, argval=None, argrepr='', offset=232, start_offset=232, starts_line=True, line_number=20, label=10, positions=None, cache_info=None), + Instruction(opname='LOAD_CONST', opcode=83, arg=5, argval=1, argrepr='1', offset=234, start_offset=234, starts_line=True, line_number=21, label=None, positions=None, cache_info=None), + Instruction(opname='LOAD_CONST', opcode=83, arg=7, argval=0, argrepr='0', offset=236, start_offset=236, starts_line=False, line_number=21, label=None, positions=None, cache_info=None), + Instruction(opname='BINARY_OP', opcode=44, arg=11, argval=11, argrepr='/', offset=238, start_offset=238, starts_line=False, line_number=21, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('type_versions', 1, b'\x00\x00')]), + Instruction(opname='POP_TOP', opcode=31, arg=None, argval=None, argrepr='', offset=244, start_offset=244, starts_line=False, line_number=21, label=None, positions=None, cache_info=None), + Instruction(opname='LOAD_FAST', opcode=85, arg=0, argval='i', argrepr='i', offset=246, start_offset=246, starts_line=True, line_number=25, label=None, positions=None, cache_info=None), + Instruction(opname='BEFORE_WITH', opcode=2, arg=None, argval=None, argrepr='', offset=248, start_offset=248, starts_line=False, line_number=25, label=None, positions=None, cache_info=None), + Instruction(opname='STORE_FAST', opcode=110, arg=1, argval='dodgy', argrepr='dodgy', offset=250, start_offset=250, starts_line=False, line_number=25, label=None, positions=None, cache_info=None), + Instruction(opname='LOAD_GLOBAL', opcode=91, arg=3, argval='print', argrepr='print + NULL', offset=252, start_offset=252, starts_line=True, line_number=26, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('index', 1, b'\x00\x00'), ('module_keys_version', 1, b'\x00\x00'), ('builtin_keys_version', 1, b'\x00\x00')]), + Instruction(opname='LOAD_CONST', opcode=83, arg=8, argval='Never reach this', argrepr="'Never reach this'", offset=262, start_offset=262, starts_line=False, line_number=26, label=None, positions=None, cache_info=None), + Instruction(opname='CALL', opcode=52, arg=1, argval=1, argrepr='', offset=264, start_offset=264, starts_line=False, line_number=26, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]), + Instruction(opname='POP_TOP', opcode=31, arg=None, argval=None, argrepr='', offset=272, start_offset=272, starts_line=False, line_number=26, label=None, positions=None, cache_info=None), + Instruction(opname='LOAD_CONST', opcode=83, arg=0, argval=None, argrepr='None', offset=274, start_offset=274, starts_line=True, line_number=25, label=None, positions=None, cache_info=None), + Instruction(opname='LOAD_CONST', opcode=83, arg=0, argval=None, argrepr='None', offset=276, start_offset=276, starts_line=False, line_number=25, label=None, positions=None, cache_info=None), + Instruction(opname='LOAD_CONST', opcode=83, arg=0, argval=None, argrepr='None', offset=278, start_offset=278, starts_line=False, line_number=25, label=None, positions=None, cache_info=None), + Instruction(opname='CALL', opcode=52, arg=2, argval=2, argrepr='', offset=280, start_offset=280, starts_line=False, line_number=25, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]), + Instruction(opname='POP_TOP', opcode=31, arg=None, argval=None, argrepr='', offset=288, start_offset=288, starts_line=False, line_number=25, label=None, positions=None, cache_info=None), + Instruction(opname='LOAD_GLOBAL', opcode=91, arg=3, argval='print', argrepr='print + NULL', offset=290, start_offset=290, starts_line=True, line_number=28, label=11, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('index', 1, b'\x00\x00'), ('module_keys_version', 1, b'\x00\x00'), ('builtin_keys_version', 1, b'\x00\x00')]), + Instruction(opname='LOAD_CONST', opcode=83, arg=10, argval="OK, now we're done", argrepr='"OK, now we\'re done"', offset=300, start_offset=300, starts_line=False, line_number=28, label=None, positions=None, cache_info=None), + Instruction(opname='CALL', opcode=52, arg=1, argval=1, argrepr='', offset=302, start_offset=302, starts_line=False, line_number=28, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]), + Instruction(opname='POP_TOP', opcode=31, arg=None, argval=None, argrepr='', offset=310, start_offset=310, starts_line=False, line_number=28, label=None, positions=None, cache_info=None), + Instruction(opname='RETURN_CONST', opcode=103, arg=0, argval=None, argrepr='None', offset=312, start_offset=312, starts_line=False, line_number=28, label=None, positions=None, cache_info=None), + Instruction(opname='PUSH_EXC_INFO', opcode=32, arg=None, argval=None, argrepr='', offset=314, start_offset=314, starts_line=True, line_number=25, label=None, positions=None, cache_info=None), + Instruction(opname='WITH_EXCEPT_START', opcode=43, arg=None, argval=None, argrepr='', offset=316, start_offset=316, starts_line=False, line_number=25, label=None, positions=None, cache_info=None), + Instruction(opname='TO_BOOL', opcode=39, arg=None, argval=None, argrepr='', offset=318, start_offset=318, starts_line=False, line_number=25, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('version', 2, b'\x00\x00\x00\x00')]), + Instruction(opname='POP_JUMP_IF_TRUE', opcode=100, arg=1, argval=332, argrepr='to L12', offset=326, start_offset=326, starts_line=False, line_number=25, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00')]), + Instruction(opname='RERAISE', opcode=102, arg=2, argval=2, argrepr='', offset=330, start_offset=330, starts_line=False, line_number=25, label=None, positions=None, cache_info=None), + Instruction(opname='POP_TOP', opcode=31, arg=None, argval=None, argrepr='', offset=332, start_offset=332, starts_line=False, line_number=25, label=12, positions=None, cache_info=None), + Instruction(opname='POP_EXCEPT', opcode=30, arg=None, argval=None, argrepr='', offset=334, start_offset=334, starts_line=False, line_number=25, label=None, positions=None, cache_info=None), + Instruction(opname='POP_TOP', opcode=31, arg=None, argval=None, argrepr='', offset=336, start_offset=336, starts_line=False, line_number=25, label=None, positions=None, cache_info=None), + Instruction(opname='POP_TOP', opcode=31, arg=None, argval=None, argrepr='', offset=338, start_offset=338, starts_line=False, line_number=25, label=None, positions=None, cache_info=None), + Instruction(opname='JUMP_BACKWARD_NO_INTERRUPT', opcode=77, arg=26, argval=290, argrepr='to L11', offset=340, start_offset=340, starts_line=False, line_number=25, label=None, positions=None, cache_info=None), + Instruction(opname='COPY', opcode=60, arg=3, argval=3, argrepr='', offset=342, start_offset=342, starts_line=True, line_number=None, label=None, positions=None, cache_info=None), + Instruction(opname='POP_EXCEPT', opcode=30, arg=None, argval=None, argrepr='', offset=344, start_offset=344, starts_line=False, line_number=None, label=None, positions=None, cache_info=None), + Instruction(opname='RERAISE', opcode=102, arg=1, argval=1, argrepr='', offset=346, start_offset=346, starts_line=False, line_number=None, label=None, positions=None, cache_info=None), + Instruction(opname='PUSH_EXC_INFO', opcode=32, arg=None, argval=None, argrepr='', offset=348, start_offset=348, starts_line=False, line_number=None, label=None, positions=None, cache_info=None), + Instruction(opname='LOAD_GLOBAL', opcode=91, arg=4, argval='ZeroDivisionError', argrepr='ZeroDivisionError', offset=350, start_offset=350, starts_line=True, line_number=22, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('index', 1, b'\x00\x00'), ('module_keys_version', 1, b'\x00\x00'), ('builtin_keys_version', 1, b'\x00\x00')]), + Instruction(opname='CHECK_EXC_MATCH', opcode=7, arg=None, argval=None, argrepr='', offset=360, start_offset=360, starts_line=False, line_number=22, label=None, positions=None, cache_info=None), + Instruction(opname='POP_JUMP_IF_FALSE', opcode=97, arg=14, argval=394, argrepr='to L13', offset=362, start_offset=362, starts_line=False, line_number=22, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00')]), + Instruction(opname='POP_TOP', opcode=31, arg=None, argval=None, argrepr='', offset=366, start_offset=366, starts_line=False, line_number=22, label=None, positions=None, cache_info=None), + Instruction(opname='LOAD_GLOBAL', opcode=91, arg=3, argval='print', argrepr='print + NULL', offset=368, start_offset=368, starts_line=True, line_number=23, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('index', 1, b'\x00\x00'), ('module_keys_version', 1, b'\x00\x00'), ('builtin_keys_version', 1, b'\x00\x00')]), + Instruction(opname='LOAD_CONST', opcode=83, arg=9, argval='Here we go, here we go, here we go...', argrepr="'Here we go, here we go, here we go...'", offset=378, start_offset=378, starts_line=False, line_number=23, label=None, positions=None, cache_info=None), + Instruction(opname='CALL', opcode=52, arg=1, argval=1, argrepr='', offset=380, start_offset=380, starts_line=False, line_number=23, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]), + Instruction(opname='POP_TOP', opcode=31, arg=None, argval=None, argrepr='', offset=388, start_offset=388, starts_line=False, line_number=23, label=None, positions=None, cache_info=None), + Instruction(opname='POP_EXCEPT', opcode=30, arg=None, argval=None, argrepr='', offset=390, start_offset=390, starts_line=False, line_number=23, label=None, positions=None, cache_info=None), + Instruction(opname='JUMP_BACKWARD_NO_INTERRUPT', opcode=77, arg=52, argval=290, argrepr='to L11', offset=392, start_offset=392, starts_line=False, line_number=23, label=None, positions=None, cache_info=None), + Instruction(opname='RERAISE', opcode=102, arg=0, argval=0, argrepr='', offset=394, start_offset=394, starts_line=True, line_number=22, label=13, positions=None, cache_info=None), + Instruction(opname='COPY', opcode=60, arg=3, argval=3, argrepr='', offset=396, start_offset=396, starts_line=True, line_number=None, label=None, positions=None, cache_info=None), + Instruction(opname='POP_EXCEPT', opcode=30, arg=None, argval=None, argrepr='', offset=398, start_offset=398, starts_line=False, line_number=None, label=None, positions=None, cache_info=None), + Instruction(opname='RERAISE', opcode=102, arg=1, argval=1, argrepr='', offset=400, start_offset=400, starts_line=False, line_number=None, label=None, positions=None, cache_info=None), + Instruction(opname='PUSH_EXC_INFO', opcode=32, arg=None, argval=None, argrepr='', offset=402, start_offset=402, starts_line=False, line_number=None, label=None, positions=None, cache_info=None), + Instruction(opname='LOAD_GLOBAL', opcode=91, arg=3, argval='print', argrepr='print + NULL', offset=404, start_offset=404, starts_line=True, line_number=28, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('index', 1, b'\x00\x00'), ('module_keys_version', 1, b'\x00\x00'), ('builtin_keys_version', 1, b'\x00\x00')]), + Instruction(opname='LOAD_CONST', opcode=83, arg=10, argval="OK, now we're done", argrepr='"OK, now we\'re done"', offset=414, start_offset=414, starts_line=False, line_number=28, label=None, positions=None, cache_info=None), + Instruction(opname='CALL', opcode=52, arg=1, argval=1, argrepr='', offset=416, start_offset=416, starts_line=False, line_number=28, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]), + Instruction(opname='POP_TOP', opcode=31, arg=None, argval=None, argrepr='', offset=424, start_offset=424, starts_line=False, line_number=28, label=None, positions=None, cache_info=None), + Instruction(opname='RERAISE', opcode=102, arg=0, argval=0, argrepr='', offset=426, start_offset=426, starts_line=False, line_number=28, label=None, positions=None, cache_info=None), + Instruction(opname='COPY', opcode=60, arg=3, argval=3, argrepr='', offset=428, start_offset=428, starts_line=True, line_number=None, label=None, positions=None, cache_info=None), + Instruction(opname='POP_EXCEPT', opcode=30, arg=None, argval=None, argrepr='', offset=430, start_offset=430, starts_line=False, line_number=None, label=None, positions=None, cache_info=None), + Instruction(opname='RERAISE', opcode=102, arg=1, argval=1, argrepr='', offset=432, start_offset=432, starts_line=False, line_number=None, label=None, positions=None, cache_info=None), ] # One last piece of inspect fodder to check the default line number handling diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-05-21-19-44-59.gh-issue-117581.4KV5jb.rst b/Misc/NEWS.d/next/Core and Builtins/2024-05-21-19-44-59.gh-issue-117581.4KV5jb.rst new file mode 100644 index 00000000000000..faf845c08edeb1 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2024-05-21-19-44-59.gh-issue-117581.4KV5jb.rst @@ -0,0 +1,2 @@ +Change specialization of BINARY_OP to specialize primarily by refcount, +rather than by type. diff --git a/Modules/arraymodule.c b/Modules/arraymodule.c index e6c84d588be98b..efe65f052a09e4 100644 --- a/Modules/arraymodule.c +++ b/Modules/arraymodule.c @@ -3194,6 +3194,8 @@ array_modexec(PyObject *m) ADD_INTERNED(state, iter); CREATE_TYPE(m, state->ArrayType, &array_spec); + state->ArrayType->tp_version_tag = _Py_TYPE_VERSION_ARRAY; + state->ArrayType->tp_flags |= Py_TPFLAGS_VALID_VERSION_TAG; CREATE_TYPE(m, state->ArrayIterType, &arrayiter_spec); Py_SET_TYPE(state->ArrayIterType, &PyType_Type); diff --git a/Objects/bytearrayobject.c b/Objects/bytearrayobject.c index 80679f93cd4c13..5db51e9c6c22a3 100644 --- a/Objects/bytearrayobject.c +++ b/Objects/bytearrayobject.c @@ -2407,7 +2407,8 @@ PyTypeObject PyByteArray_Type = { 0, /* tp_setattro */ &bytearray_as_buffer, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | - _Py_TPFLAGS_MATCH_SELF, /* tp_flags */ + Py_TPFLAGS_VALID_VERSION_TAG | + _Py_TPFLAGS_MATCH_SELF, /* tp_flags */ bytearray_doc, /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ @@ -2427,6 +2428,7 @@ PyTypeObject PyByteArray_Type = { PyType_GenericAlloc, /* tp_alloc */ PyType_GenericNew, /* tp_new */ PyObject_Del, /* tp_free */ + .tp_version_tag = _Py_TYPE_VERSION_BYTEARRAY, }; /*********************** Bytearray Iterator ****************************/ diff --git a/Objects/bytesobject.c b/Objects/bytesobject.c index 459df6ceacf3a8..6ea458e20ecfb4 100644 --- a/Objects/bytesobject.c +++ b/Objects/bytesobject.c @@ -3046,7 +3046,7 @@ PyTypeObject PyBytes_Type = { 0, /* tp_setattro */ &bytes_as_buffer, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | - Py_TPFLAGS_BYTES_SUBCLASS | + Py_TPFLAGS_BYTES_SUBCLASS | Py_TPFLAGS_VALID_VERSION_TAG | _Py_TPFLAGS_MATCH_SELF, /* tp_flags */ bytes_doc, /* tp_doc */ 0, /* tp_traverse */ @@ -3067,6 +3067,7 @@ PyTypeObject PyBytes_Type = { bytes_alloc, /* tp_alloc */ bytes_new, /* tp_new */ PyObject_Del, /* tp_free */ + .tp_version_tag = _Py_TYPE_VERSION_BYTES, }; void diff --git a/Objects/complexobject.c b/Objects/complexobject.c index 943c5ccabfd5c4..58ace5a325f649 100644 --- a/Objects/complexobject.c +++ b/Objects/complexobject.c @@ -1113,7 +1113,8 @@ PyTypeObject PyComplex_Type = { PyObject_GenericGetAttr, /* tp_getattro */ 0, /* tp_setattro */ 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | + Py_TPFLAGS_VALID_VERSION_TAG, /* tp_flags */ complex_new__doc__, /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ @@ -1133,4 +1134,5 @@ PyTypeObject PyComplex_Type = { PyType_GenericAlloc, /* tp_alloc */ complex_new, /* tp_new */ PyObject_Del, /* tp_free */ + .tp_version_tag = _Py_TYPE_VERSION_COMPLEX, }; diff --git a/Objects/dictobject.c b/Objects/dictobject.c index a1ee32b7099f91..628eeeffa4a7d2 100644 --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -4847,7 +4847,7 @@ PyTypeObject PyDict_Type = { PyObject_GenericGetAttr, /* tp_getattro */ 0, /* tp_setattro */ 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_VALID_VERSION_TAG | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_DICT_SUBCLASS | _Py_TPFLAGS_MATCH_SELF | Py_TPFLAGS_MAPPING, /* tp_flags */ dictionary_doc, /* tp_doc */ @@ -4870,6 +4870,7 @@ PyTypeObject PyDict_Type = { dict_new, /* tp_new */ PyObject_GC_Del, /* tp_free */ .tp_vectorcall = dict_vectorcall, + .tp_version_tag = _Py_TYPE_VERSION_DICT, }; /* For backward compatibility with old dictionary interface */ @@ -6499,7 +6500,8 @@ PyTypeObject PyDictItems_Type = { PyObject_GenericGetAttr, /* tp_getattro */ 0, /* tp_setattro */ 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | + Py_TPFLAGS_VALID_VERSION_TAG, /* tp_flags */ 0, /* tp_doc */ dictview_traverse, /* tp_traverse */ 0, /* tp_clear */ @@ -6509,6 +6511,7 @@ PyTypeObject PyDictItems_Type = { 0, /* tp_iternext */ dictitems_methods, /* tp_methods */ .tp_getset = dictview_getset, + .tp_version_tag = _Py_TYPE_VERSION_DICTITEMS, }; /*[clinic input] diff --git a/Objects/floatobject.c b/Objects/floatobject.c index a5bf356cc9c7f0..50b96b1237d924 100644 --- a/Objects/floatobject.c +++ b/Objects/floatobject.c @@ -1898,6 +1898,7 @@ PyTypeObject PyFloat_Type = { 0, /* tp_setattro */ 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | + Py_TPFLAGS_VALID_VERSION_TAG | _Py_TPFLAGS_MATCH_SELF, /* tp_flags */ float_new__doc__, /* tp_doc */ 0, /* tp_traverse */ @@ -1918,6 +1919,7 @@ PyTypeObject PyFloat_Type = { 0, /* tp_alloc */ float_new, /* tp_new */ .tp_vectorcall = (vectorcallfunc)float_vectorcall, + .tp_version_tag = _Py_TYPE_VERSION_FLOAT, }; static void diff --git a/Objects/listobject.c b/Objects/listobject.c index d09bb6391034d1..9bae1561a22314 100644 --- a/Objects/listobject.c +++ b/Objects/listobject.c @@ -754,6 +754,16 @@ list_concat_lock_held(PyListObject *a, PyListObject *b) return (PyObject *)np; } +PyObject * +_PyList_Concat(PyListObject *a, PyListObject *b) +{ + PyObject *ret; + Py_BEGIN_CRITICAL_SECTION2(a, b); + ret = list_concat_lock_held(a, b); + Py_END_CRITICAL_SECTION2(); + return ret; +} + static PyObject * list_concat(PyObject *aa, PyObject *bb) { @@ -765,11 +775,7 @@ list_concat(PyObject *aa, PyObject *bb) } PyListObject *a = (PyListObject *)aa; PyListObject *b = (PyListObject *)bb; - PyObject *ret; - Py_BEGIN_CRITICAL_SECTION2(a, b); - ret = list_concat_lock_held(a, b); - Py_END_CRITICAL_SECTION2(); - return ret; + return _PyList_Concat(a, b); } static PyObject * @@ -3767,6 +3773,7 @@ PyTypeObject PyList_Type = { 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_LIST_SUBCLASS | + Py_TPFLAGS_VALID_VERSION_TAG | _Py_TPFLAGS_MATCH_SELF | Py_TPFLAGS_SEQUENCE, /* tp_flags */ list___init____doc__, /* tp_doc */ list_traverse, /* tp_traverse */ @@ -3788,6 +3795,7 @@ PyTypeObject PyList_Type = { PyType_GenericNew, /* tp_new */ PyObject_GC_Del, /* tp_free */ .tp_vectorcall = list_vectorcall, + .tp_version_tag = _Py_TYPE_VERSION_LIST, }; /*********************** List Iterator **************************/ diff --git a/Objects/longobject.c b/Objects/longobject.c index 2dc2cb7a47b460..bbb5ed1a115272 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -3467,27 +3467,19 @@ _PyLong_Frexp(PyLongObject *a, Py_ssize_t *e) using the round-half-to-even rule in the case of a tie. */ double -PyLong_AsDouble(PyObject *v) +_PyLong_AsDouble(PyLongObject *l) { Py_ssize_t exponent; double x; - if (v == NULL) { - PyErr_BadInternalCall(); - return -1.0; - } - if (!PyLong_Check(v)) { - PyErr_SetString(PyExc_TypeError, "an integer is required"); - return -1.0; - } - if (_PyLong_IsCompact((PyLongObject *)v)) { + if (_PyLong_IsCompact(l)) { /* Fast path; single digit long (31 bits) will cast safely to double. This improves performance of FP/long operations by 20%. */ - return (double)medium_value((PyLongObject *)v); + return (double)medium_value(l); } - x = _PyLong_Frexp((PyLongObject *)v, &exponent); + x = _PyLong_Frexp(l, &exponent); if ((x == -1.0 && PyErr_Occurred()) || exponent > DBL_MAX_EXP) { PyErr_SetString(PyExc_OverflowError, "int too large to convert to float"); @@ -3496,6 +3488,20 @@ PyLong_AsDouble(PyObject *v) return ldexp(x, (int)exponent); } +double +PyLong_AsDouble(PyObject *v) +{ + if (v == NULL) { + PyErr_BadInternalCall(); + return -1.0; + } + if (!PyLong_Check(v)) { + PyErr_SetString(PyExc_TypeError, "an integer is required"); + return -1.0; + } + return _PyLong_AsDouble((PyLongObject *)v); +} + /* Methods */ /* if a < b, return a negative number @@ -3702,6 +3708,40 @@ x_sub(PyLongObject *a, PyLongObject *b) return maybe_small_long(long_normalize(z)); } +PyObject * +_PyLong_Add_1X(PyLongObject *a, PyLongObject *b) +{ + if (_PyLong_BothAreCompact(a, b)) { + stwodigits x = medium_value(a) + medium_value(b); + if (is_medium_int(x)) { + digit abs_x = x < 0 ? -x : x; + _PyLong_SetSignAndDigitCount(a, x<0?-1:1, 1); + a->long_value.ob_digit[0] = abs_x; + return (PyObject *)a; + } + } + PyObject *res = _PyLong_Add(a, b); + Py_DECREF(a); + return res; +} + +PyObject * +_PyLong_Add_X1(PyLongObject *a, PyLongObject *b) +{ + if (_PyLong_BothAreCompact(a, b)) { + stwodigits x = medium_value(a) + medium_value(b); + if (is_medium_int(x)) { + digit abs_x = x < 0 ? -x : x; + _PyLong_SetSignAndDigitCount(b, x<0?-1:1, 1); + b->long_value.ob_digit[0] = abs_x; + return (PyObject *)b; + } + } + PyObject *res = _PyLong_Add(a, b); + Py_DECREF(b); + return res; +} + PyObject * _PyLong_Add(PyLongObject *a, PyLongObject *b) { @@ -4429,22 +4469,26 @@ l_mod(PyLongObject *v, PyLongObject *w, PyLongObject **pmod) return 0; } -static PyObject * -long_div(PyObject *a, PyObject *b) +PyObject * +_PyLong_FloorDiv(PyLongObject *a, PyLongObject *b) { PyLongObject *div; - - CHECK_BINOP(a, b); - - if (_PyLong_DigitCount((PyLongObject*)a) == 1 && _PyLong_DigitCount((PyLongObject*)b) == 1) { - return fast_floor_div((PyLongObject*)a, (PyLongObject*)b); + if (_PyLong_DigitCount(a) == 1 && _PyLong_DigitCount(b) == 1) { + return fast_floor_div(a, b); } - - if (l_divmod((PyLongObject*)a, (PyLongObject*)b, &div, NULL) < 0) + if (l_divmod(a, b, &div, NULL) < 0) { div = NULL; + } return (PyObject *)div; } +static PyObject * +long_div(PyObject *a, PyObject *b) +{ + CHECK_BINOP(a, b); + return _PyLong_FloorDiv((PyLongObject *)a, (PyLongObject *)b); +} + /* PyLong/PyLong -> float, with correctly rounded result. */ #define MANT_DIG_DIGITS (DBL_MANT_DIG / PyLong_SHIFT) @@ -5300,6 +5344,31 @@ long_rshift(PyObject *a, PyObject *b) return long_rshift1((PyLongObject *)a, wordshift, remshift); } +/* Return a >> b. */ +PyObject * +_PyLong_RShiftObject(PyLongObject *a, PyLongObject *b) +{ + if (_PyLong_IsNegative(b)) { + PyErr_SetString(PyExc_ValueError, "negative shift count"); + return NULL; + } + if (_PyLong_BothAreCompact(a, b)) { + stwodigits shift = medium_value(b); + if (shift < (stwodigits)(sizeof(stwodigits) * 8)) { + stwodigits res = Py_ARITHMETIC_RIGHT_SHIFT(stwodigits, medium_value(a), shift); + return _PyLong_FromSTwoDigits(res); + } + else { + return _PyLong_GetZero(); + } + } + Py_ssize_t wordshift; + digit remshift; + if (divmod_shift((PyObject *)b, &wordshift, &remshift) < 0) + return NULL; + return long_rshift1((PyLongObject *)a, wordshift, remshift); +} + /* Return a >> shiftby. */ PyObject * _PyLong_Rshift(PyObject *a, size_t shiftby) @@ -5377,6 +5446,31 @@ long_lshift(PyObject *a, PyObject *b) return long_lshift1((PyLongObject *)a, wordshift, remshift); } + +/* Return a << b. */ +PyObject * +_PyLong_LShiftObject(PyLongObject *a, PyLongObject *b) +{ + if (_PyLong_IsNegative(b)) { + PyErr_SetString(PyExc_ValueError, "negative shift count"); + return NULL; + } + if (_PyLong_BothAreCompact(a, b)) { + stwodigits shift = medium_value(b); + /* A single digit number shifted left by up to + * the size of a single digit number will fit + * into two digits with no overflow */ + if (shift <= (stwodigits)(sizeof(digit) * 8)) { + return _PyLong_FromSTwoDigits(medium_value(a) << shift); + } + } + Py_ssize_t wordshift; + digit remshift; + if (divmod_shift((PyObject *)b, &wordshift, &remshift) < 0) + return NULL; + return long_lshift1((PyLongObject *)a, wordshift, remshift); +} + /* Return a << shiftby. */ PyObject * _PyLong_Lshift(PyObject *a, size_t shiftby) @@ -5533,12 +5627,10 @@ long_bitwise(PyLongObject *a, return (PyObject *)maybe_small_long(long_normalize(z)); } -static PyObject * -long_and(PyObject *a, PyObject *b) +PyObject * +_PyLong_And(PyLongObject *x, PyLongObject *y) { - CHECK_BINOP(a, b); - PyLongObject *x = (PyLongObject*)a; - PyLongObject *y = (PyLongObject*)b; + assert(PyLong_Check(x) && PyLong_Check(y)); if (_PyLong_IsCompact(x) && _PyLong_IsCompact(y)) { return _PyLong_FromSTwoDigits(medium_value(x) & medium_value(y)); } @@ -5546,11 +5638,18 @@ long_and(PyObject *a, PyObject *b) } static PyObject * -long_xor(PyObject *a, PyObject *b) +long_and(PyObject *a, PyObject *b) { CHECK_BINOP(a, b); PyLongObject *x = (PyLongObject*)a; PyLongObject *y = (PyLongObject*)b; + return _PyLong_And(x, y); +} + +PyObject * +_PyLong_Xor(PyLongObject *x, PyLongObject *y) +{ + assert(PyLong_Check(x) && PyLong_Check(y)); if (_PyLong_IsCompact(x) && _PyLong_IsCompact(y)) { return _PyLong_FromSTwoDigits(medium_value(x) ^ medium_value(y)); } @@ -5558,17 +5657,29 @@ long_xor(PyObject *a, PyObject *b) } static PyObject * -long_or(PyObject *a, PyObject *b) +long_xor(PyObject *a, PyObject *b) { CHECK_BINOP(a, b); - PyLongObject *x = (PyLongObject*)a; - PyLongObject *y = (PyLongObject*)b; + return _PyLong_Xor((PyLongObject*)a, (PyLongObject*)b); +} + +PyObject * +_PyLong_Or(PyLongObject *x, PyLongObject *y) +{ + assert(PyLong_Check(x) && PyLong_Check(y)); if (_PyLong_IsCompact(x) && _PyLong_IsCompact(y)) { return _PyLong_FromSTwoDigits(medium_value(x) | medium_value(y)); } return long_bitwise(x, '|', y); } +static PyObject * +long_or(PyObject *a, PyObject *b) +{ + CHECK_BINOP(a, b); + return _PyLong_Or((PyLongObject*)a, (PyLongObject*)b); +} + static PyObject * long_long(PyObject *v) { @@ -6557,7 +6668,7 @@ PyTypeObject PyLong_Type = { 0, /* tp_setattro */ 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | - Py_TPFLAGS_LONG_SUBCLASS | + Py_TPFLAGS_LONG_SUBCLASS | Py_TPFLAGS_VALID_VERSION_TAG | _Py_TPFLAGS_MATCH_SELF, /* tp_flags */ long_doc, /* tp_doc */ 0, /* tp_traverse */ @@ -6579,6 +6690,7 @@ PyTypeObject PyLong_Type = { long_new, /* tp_new */ PyObject_Free, /* tp_free */ .tp_vectorcall = long_vectorcall, + .tp_version_tag = _Py_TYPE_VERSION_INT, }; static PyTypeObject Int_InfoType; diff --git a/Objects/setobject.c b/Objects/setobject.c index 68986bb6a6b557..d13d0ea93d900c 100644 --- a/Objects/setobject.c +++ b/Objects/setobject.c @@ -2471,7 +2471,7 @@ PyTypeObject PySet_Type = { 0, /* tp_setattro */ 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | - Py_TPFLAGS_BASETYPE | + Py_TPFLAGS_BASETYPE | Py_TPFLAGS_VALID_VERSION_TAG | _Py_TPFLAGS_MATCH_SELF, /* tp_flags */ set_doc, /* tp_doc */ (traverseproc)set_traverse, /* tp_traverse */ @@ -2493,6 +2493,7 @@ PyTypeObject PySet_Type = { set_new, /* tp_new */ PyObject_GC_Del, /* tp_free */ .tp_vectorcall = set_vectorcall, + .tp_version_tag = _Py_TYPE_VERSION_SET, }; /* frozenset object ********************************************************/ @@ -2561,7 +2562,7 @@ PyTypeObject PyFrozenSet_Type = { 0, /* tp_setattro */ 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | - Py_TPFLAGS_BASETYPE | + Py_TPFLAGS_BASETYPE | Py_TPFLAGS_VALID_VERSION_TAG | _Py_TPFLAGS_MATCH_SELF, /* tp_flags */ frozenset_doc, /* tp_doc */ (traverseproc)set_traverse, /* tp_traverse */ @@ -2583,6 +2584,7 @@ PyTypeObject PyFrozenSet_Type = { frozenset_new, /* tp_new */ PyObject_GC_Del, /* tp_free */ .tp_vectorcall = frozenset_vectorcall, + .tp_version_tag = _Py_TYPE_VERSION_FROZEN_SET, }; diff --git a/Objects/tupleobject.c b/Objects/tupleobject.c index 5ae1ee9a89af84..557e52b8d3a3af 100644 --- a/Objects/tupleobject.c +++ b/Objects/tupleobject.c @@ -865,6 +865,7 @@ PyTypeObject PyTuple_Type = { 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_TUPLE_SUBCLASS | + Py_TPFLAGS_VALID_VERSION_TAG | _Py_TPFLAGS_MATCH_SELF | Py_TPFLAGS_SEQUENCE, /* tp_flags */ tuple_new__doc__, /* tp_doc */ (traverseproc)tupletraverse, /* tp_traverse */ @@ -886,6 +887,7 @@ PyTypeObject PyTuple_Type = { tuple_new, /* tp_new */ PyObject_GC_Del, /* tp_free */ .tp_vectorcall = tuple_vectorcall, + .tp_version_tag = _Py_TYPE_VERSION_TUPLE, }; /* The following function breaks the notion that tuples are immutable: diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 9d849d83082ccd..354045f19d7af8 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -8284,8 +8284,10 @@ _PyStaticType_InitBuiltin(PyInterpreterState *interp, PyTypeObject *self) self->tp_flags |= Py_TPFLAGS_IMMUTABLETYPE; assert(NEXT_GLOBAL_VERSION_TAG <= _Py_MAX_GLOBAL_TYPE_VERSION_TAG); - self->tp_version_tag = NEXT_GLOBAL_VERSION_TAG++; - self->tp_flags |= Py_TPFLAGS_VALID_VERSION_TAG; + if ((self->tp_flags & Py_TPFLAGS_VALID_VERSION_TAG) == 0) { + self->tp_version_tag = NEXT_GLOBAL_VERSION_TAG++; + self->tp_flags |= Py_TPFLAGS_VALID_VERSION_TAG; + } } else { assert(!ismain); @@ -11434,3 +11436,18 @@ PyTypeObject PySuper_Type = { PyObject_GC_Del, /* tp_free */ .tp_vectorcall = (vectorcallfunc)super_vectorcall, }; + +PyTypeObject *const _Py_PreAllocatedTypes[_Py_TYPE_VERSIONS_PREALLOCATED] = { + [_Py_TYPE_VERSION_INT] = &PyLong_Type, + [_Py_TYPE_VERSION_FLOAT] = &PyFloat_Type, + [_Py_TYPE_VERSION_LIST] = &PyList_Type, + [_Py_TYPE_VERSION_TUPLE] = &PyTuple_Type, + [_Py_TYPE_VERSION_STR] = &PyUnicode_Type, + [_Py_TYPE_VERSION_SET] = &PySet_Type, + [_Py_TYPE_VERSION_FROZEN_SET] = &PyFrozenSet_Type, + [_Py_TYPE_VERSION_DICT] = &PyDict_Type, + [_Py_TYPE_VERSION_BYTES] = &PyBytes_Type, + [_Py_TYPE_VERSION_COMPLEX] = &PyComplex_Type, + [_Py_TYPE_VERSION_DICTITEMS] = &PyDictItems_Type, + [_Py_TYPE_VERSION_BYTEARRAY] = &PyByteArray_Type, +}; diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index eb37b478cc4de1..1496f49542ac34 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -14802,7 +14802,7 @@ PyTypeObject PyUnicode_Type = { 0, /* tp_setattro */ 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | - Py_TPFLAGS_UNICODE_SUBCLASS | + Py_TPFLAGS_UNICODE_SUBCLASS | Py_TPFLAGS_VALID_VERSION_TAG | _Py_TPFLAGS_MATCH_SELF, /* tp_flags */ unicode_doc, /* tp_doc */ 0, /* tp_traverse */ @@ -14824,6 +14824,7 @@ PyTypeObject PyUnicode_Type = { unicode_new, /* tp_new */ PyObject_Del, /* tp_free */ .tp_vectorcall = unicode_vectorcall, + .tp_version_tag = _Py_TYPE_VERSION_STR, }; /* Initialize the Unicode implementation */ diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 9a8198515dea5e..492592a009d5b1 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -416,19 +416,23 @@ dummy_func( } family(BINARY_OP, INLINE_CACHE_ENTRIES_BINARY_OP) = { - BINARY_OP_MULTIPLY_INT, - BINARY_OP_ADD_INT, - BINARY_OP_SUBTRACT_INT, - BINARY_OP_MULTIPLY_FLOAT, - BINARY_OP_ADD_FLOAT, - BINARY_OP_SUBTRACT_FLOAT, - BINARY_OP_ADD_UNICODE, + BINARY_OP_1X, + BINARY_OP_1I, + BINARY_OP_I1, + BINARY_OP_II, + BINARY_OP_IX, + BINARY_OP_X1, + BINARY_OP_XI, + BINARY_OP_XX, // BINARY_OP_INPLACE_ADD_UNICODE, // See comments at that opcode. }; - op(_GUARD_BOTH_INT, (left, right -- left, right)) { - EXIT_IF(!PyLong_CheckExact(left)); - EXIT_IF(!PyLong_CheckExact(right)); + op(_GUARD_NOS_REFCNT1, (value2, unused -- value2, unused)) { + EXIT_IF(Py_REFCNT(value2) != 1); + } + + op(_GUARD_TOS_REFCNT1, (value1 -- value1)) { + EXIT_IF(Py_REFCNT(value1) != 1); } op(_GUARD_NOS_INT, (left, unused -- left, unused)) { @@ -439,40 +443,27 @@ dummy_func( EXIT_IF(!PyLong_CheckExact(value)); } - pure op(_BINARY_OP_MULTIPLY_INT, (left, right -- res)) { - STAT_INC(BINARY_OP, hit); - res = _PyLong_Multiply((PyLongObject *)left, (PyLongObject *)right); - _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); - _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); - ERROR_IF(res == NULL, error); + op(_GUARD_NOS_IMMORTAL, (value2, unused -- value2, unused)) { + EXIT_IF(!_Py_IsImmortal(value2)); } - pure op(_BINARY_OP_ADD_INT, (left, right -- res)) { - STAT_INC(BINARY_OP, hit); - res = _PyLong_Add((PyLongObject *)left, (PyLongObject *)right); - _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); - _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); - ERROR_IF(res == NULL, error); + op(_GUARD_TOS_IMMORTAL, (value1 -- value1)) { + EXIT_IF(!_Py_IsImmortal(value1)); } - pure op(_BINARY_OP_SUBTRACT_INT, (left, right -- res)) { - STAT_INC(BINARY_OP, hit); - res = _PyLong_Subtract((PyLongObject *)left, (PyLongObject *)right); - _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); - _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); - ERROR_IF(res == NULL, error); + op(_GUARD_VERSION_TYPES, (type_version/1, left, right -- left, right)) { + PyTypeObject *lt = Py_TYPE(left); + PyTypeObject *rt = Py_TYPE(right); + EXIT_IF(lt->tp_version_tag != ((type_version & 0xf0) >> 4)); + EXIT_IF(rt->tp_version_tag != (type_version & 0xf)); } - macro(BINARY_OP_MULTIPLY_INT) = - _GUARD_BOTH_INT + unused/1 + _BINARY_OP_MULTIPLY_INT; - macro(BINARY_OP_ADD_INT) = - _GUARD_BOTH_INT + unused/1 + _BINARY_OP_ADD_INT; - macro(BINARY_OP_SUBTRACT_INT) = - _GUARD_BOTH_INT + unused/1 + _BINARY_OP_SUBTRACT_INT; + op(_GUARD_TOS_VERSION, (type_version/1, value1 -- value1)) { + EXIT_IF(Py_TYPE(value1)->tp_version_tag != type_version); + } - op(_GUARD_BOTH_FLOAT, (left, right -- left, right)) { - EXIT_IF(!PyFloat_CheckExact(left)); - EXIT_IF(!PyFloat_CheckExact(right)); + op(_GUARD_NOS_VERSION, (type_version/1, value2, unused -- value2, unused)) { + EXIT_IF(Py_TYPE(value2)->tp_version_tag != type_version); } op(_GUARD_NOS_FLOAT, (left, unused -- left, unused)) { @@ -483,52 +474,110 @@ dummy_func( EXIT_IF(!PyFloat_CheckExact(value)); } - pure op(_BINARY_OP_MULTIPLY_FLOAT, (left, right -- res)) { + op(_BINARY_OP_TABLE_NN, (type_version/1, left, right -- res)) { + // The NN sufix indicates that it does not decref the arguments */ STAT_INC(BINARY_OP, hit); - double dres = - ((PyFloatObject *)left)->ob_fval * - ((PyFloatObject *)right)->ob_fval; - DECREF_INPUTS_AND_REUSE_FLOAT(left, right, dres, res); + res = _Py_BinaryFunctionTable[type_version >> 8](left, right); + ERROR_IF(res == NULL, error); } - pure op(_BINARY_OP_ADD_FLOAT, (left, right -- res)) { + op(_BINARY_OP_TABLE_ND, (type_version/1, left, right -- res)) { + // The ND sufix indicates that it decrefs only the right argument */ STAT_INC(BINARY_OP, hit); - double dres = - ((PyFloatObject *)left)->ob_fval + - ((PyFloatObject *)right)->ob_fval; - DECREF_INPUTS_AND_REUSE_FLOAT(left, right, dres, res); + res = _Py_BinaryFunctionTable[type_version >> 8](left, right); + Py_DECREF(right); + ERROR_IF(res == NULL, error); } - pure op(_BINARY_OP_SUBTRACT_FLOAT, (left, right -- res)) { + op(_BINARY_OP_TABLE_DN, (type_version/1, left, right -- res)) { + // The DN sufix indicates that it decrefs only the left argument */ STAT_INC(BINARY_OP, hit); - double dres = - ((PyFloatObject *)left)->ob_fval - - ((PyFloatObject *)right)->ob_fval; - DECREF_INPUTS_AND_REUSE_FLOAT(left, right, dres, res); + res = _Py_BinaryFunctionTable[type_version >> 8](left, right); + Py_DECREF(left); + ERROR_IF(res == NULL, error); } - macro(BINARY_OP_MULTIPLY_FLOAT) = - _GUARD_BOTH_FLOAT + unused/1 + _BINARY_OP_MULTIPLY_FLOAT; - macro(BINARY_OP_ADD_FLOAT) = - _GUARD_BOTH_FLOAT + unused/1 + _BINARY_OP_ADD_FLOAT; - macro(BINARY_OP_SUBTRACT_FLOAT) = - _GUARD_BOTH_FLOAT + unused/1 + _BINARY_OP_SUBTRACT_FLOAT; + op(_BINARY_OP_TABLE_DD, (type_version/1, left, right -- res)) { + // The DD sufix indicates that it decrefs both arguments */ + STAT_INC(BINARY_OP, hit); + res = _Py_BinaryFunctionTable[type_version >> 8](left, right); + Py_DECREF(left); + Py_DECREF(right); + ERROR_IF(res == NULL, error); + } - op(_GUARD_BOTH_UNICODE, (left, right -- left, right)) { - EXIT_IF(!PyUnicode_CheckExact(left)); - EXIT_IF(!PyUnicode_CheckExact(right)); + macro(BINARY_OP_1I) = + unused/1 + + _GUARD_NOS_REFCNT1 + + _GUARD_TOS_IMMORTAL + + _GUARD_VERSION_TYPES + + unused/-1 + /* Rewind the version */ + _BINARY_OP_TABLE_NN; + + macro(BINARY_OP_1X) = + unused/1 + + _GUARD_NOS_REFCNT1 + + _GUARD_VERSION_TYPES + + unused/-1 + /* Rewind the version */ + _BINARY_OP_TABLE_ND; + + macro(BINARY_OP_I1) = + unused/1 + + _GUARD_NOS_IMMORTAL + + _GUARD_TOS_REFCNT1 + + _GUARD_VERSION_TYPES + + unused/-1 + /* Rewind the version */ + _BINARY_OP_TABLE_NN; + + macro(BINARY_OP_II) = + unused/1 + + _GUARD_NOS_IMMORTAL + + _GUARD_TOS_IMMORTAL + + _GUARD_VERSION_TYPES + + unused/-1 + /* Rewind the version */ + _BINARY_OP_TABLE_NN; + + macro(BINARY_OP_IX) = + unused/1 + + _GUARD_NOS_IMMORTAL + + _GUARD_VERSION_TYPES + + unused/-1 + /* Rewind the version */ + _BINARY_OP_TABLE_ND; + + macro(BINARY_OP_X1) = + unused/1 + + _GUARD_TOS_REFCNT1 + + _GUARD_VERSION_TYPES + + unused/-1 + /* Rewind the version */ + _BINARY_OP_TABLE_DN; + + macro(BINARY_OP_XI) = + unused/1 + + _GUARD_TOS_IMMORTAL + + _GUARD_VERSION_TYPES + + unused/-1 + /* Rewind the version */ + _BINARY_OP_TABLE_DN; + + macro(BINARY_OP_XX) = + unused/1 + + _GUARD_VERSION_TYPES + + unused/-1 + /* Rewind the version */ + _BINARY_OP_TABLE_DD; + + op(_GUARD_BOTH_INT, (left, right -- left, right)) { + EXIT_IF(!PyLong_CheckExact(left)); + EXIT_IF(!PyLong_CheckExact(right)); } - pure op(_BINARY_OP_ADD_UNICODE, (left, right -- res)) { - STAT_INC(BINARY_OP, hit); - res = PyUnicode_Concat(left, right); - _Py_DECREF_SPECIALIZED(left, _PyUnicode_ExactDealloc); - _Py_DECREF_SPECIALIZED(right, _PyUnicode_ExactDealloc); - ERROR_IF(res == NULL, error); + op(_GUARD_BOTH_FLOAT, (left, right -- left, right)) { + EXIT_IF(!PyFloat_CheckExact(left)); + EXIT_IF(!PyFloat_CheckExact(right)); } - macro(BINARY_OP_ADD_UNICODE) = - _GUARD_BOTH_UNICODE + unused/1 + _BINARY_OP_ADD_UNICODE; + op(_GUARD_BOTH_UNICODE, (left, right -- left, right)) { + EXIT_IF(!PyUnicode_CheckExact(left)); + EXIT_IF(!PyUnicode_CheckExact(right)); + } // This is a subtle one. It's a super-instruction for // BINARY_OP_ADD_UNICODE followed by STORE_FAST @@ -563,7 +612,8 @@ dummy_func( } macro(BINARY_OP_INPLACE_ADD_UNICODE) = - _GUARD_BOTH_UNICODE + unused/1 + _BINARY_OP_INPLACE_ADD_UNICODE; + _GUARD_BOTH_UNICODE + unused/2 + _BINARY_OP_INPLACE_ADD_UNICODE; + family(BINARY_SUBSCR, INLINE_CACHE_ENTRIES_BINARY_SUBSCR) = { BINARY_SUBSCR_DICT, @@ -4049,7 +4099,7 @@ dummy_func( ERROR_IF(res == NULL, error); } - macro(BINARY_OP) = _SPECIALIZE_BINARY_OP + _BINARY_OP; + macro(BINARY_OP) = _SPECIALIZE_BINARY_OP + unused/1 + _BINARY_OP; pure inst(SWAP, (bottom, unused[oparg-2], top -- top, unused[oparg-2], bottom)) { diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index e862364cb23e7a..65f52528610289 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -431,16 +431,20 @@ break; } - case _GUARD_BOTH_INT: { - PyObject *right; - PyObject *left; - right = stack_pointer[-1]; - left = stack_pointer[-2]; - if (!PyLong_CheckExact(left)) { + case _GUARD_NOS_REFCNT1: { + PyObject *value2; + value2 = stack_pointer[-2]; + if (Py_REFCNT(value2) != 1) { UOP_STAT_INC(uopcode, miss); JUMP_TO_JUMP_TARGET(); } - if (!PyLong_CheckExact(right)) { + break; + } + + case _GUARD_TOS_REFCNT1: { + PyObject *value1; + value1 = stack_pointer[-1]; + if (Py_REFCNT(value1) != 1) { UOP_STAT_INC(uopcode, miss); JUMP_TO_JUMP_TARGET(); } @@ -467,64 +471,61 @@ break; } - case _BINARY_OP_MULTIPLY_INT: { - PyObject *right; - PyObject *left; - PyObject *res; - right = stack_pointer[-1]; - left = stack_pointer[-2]; - STAT_INC(BINARY_OP, hit); - res = _PyLong_Multiply((PyLongObject *)left, (PyLongObject *)right); - _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); - _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); - if (res == NULL) JUMP_TO_ERROR(); - stack_pointer[-2] = res; - stack_pointer += -1; + case _GUARD_NOS_IMMORTAL: { + PyObject *value2; + value2 = stack_pointer[-2]; + if (!_Py_IsImmortal(value2)) { + UOP_STAT_INC(uopcode, miss); + JUMP_TO_JUMP_TARGET(); + } break; } - case _BINARY_OP_ADD_INT: { - PyObject *right; - PyObject *left; - PyObject *res; - right = stack_pointer[-1]; - left = stack_pointer[-2]; - STAT_INC(BINARY_OP, hit); - res = _PyLong_Add((PyLongObject *)left, (PyLongObject *)right); - _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); - _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); - if (res == NULL) JUMP_TO_ERROR(); - stack_pointer[-2] = res; - stack_pointer += -1; + case _GUARD_TOS_IMMORTAL: { + PyObject *value1; + value1 = stack_pointer[-1]; + if (!_Py_IsImmortal(value1)) { + UOP_STAT_INC(uopcode, miss); + JUMP_TO_JUMP_TARGET(); + } break; } - case _BINARY_OP_SUBTRACT_INT: { + case _GUARD_VERSION_TYPES: { PyObject *right; PyObject *left; - PyObject *res; right = stack_pointer[-1]; left = stack_pointer[-2]; - STAT_INC(BINARY_OP, hit); - res = _PyLong_Subtract((PyLongObject *)left, (PyLongObject *)right); - _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); - _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); - if (res == NULL) JUMP_TO_ERROR(); - stack_pointer[-2] = res; - stack_pointer += -1; + uint16_t type_version = (uint16_t)CURRENT_OPERAND(); + PyTypeObject *lt = Py_TYPE(left); + PyTypeObject *rt = Py_TYPE(right); + if (lt->tp_version_tag != ((type_version & 0xf0) >> 4)) { + UOP_STAT_INC(uopcode, miss); + JUMP_TO_JUMP_TARGET(); + } + if (rt->tp_version_tag != (type_version & 0xf)) { + UOP_STAT_INC(uopcode, miss); + JUMP_TO_JUMP_TARGET(); + } break; } - case _GUARD_BOTH_FLOAT: { - PyObject *right; - PyObject *left; - right = stack_pointer[-1]; - left = stack_pointer[-2]; - if (!PyFloat_CheckExact(left)) { + case _GUARD_TOS_VERSION: { + PyObject *value1; + value1 = stack_pointer[-1]; + uint16_t type_version = (uint16_t)CURRENT_OPERAND(); + if (Py_TYPE(value1)->tp_version_tag != type_version) { UOP_STAT_INC(uopcode, miss); JUMP_TO_JUMP_TARGET(); } - if (!PyFloat_CheckExact(right)) { + break; + } + + case _GUARD_NOS_VERSION: { + PyObject *value2; + value2 = stack_pointer[-2]; + uint16_t type_version = (uint16_t)CURRENT_OPERAND(); + if (Py_TYPE(value2)->tp_version_tag != type_version) { UOP_STAT_INC(uopcode, miss); JUMP_TO_JUMP_TARGET(); } @@ -551,83 +552,119 @@ break; } - case _BINARY_OP_MULTIPLY_FLOAT: { + case _BINARY_OP_TABLE_NN: { PyObject *right; PyObject *left; PyObject *res; right = stack_pointer[-1]; left = stack_pointer[-2]; + uint16_t type_version = (uint16_t)CURRENT_OPERAND(); + // The NN sufix indicates that it does not decref the arguments */ STAT_INC(BINARY_OP, hit); - double dres = - ((PyFloatObject *)left)->ob_fval * - ((PyFloatObject *)right)->ob_fval; - DECREF_INPUTS_AND_REUSE_FLOAT(left, right, dres, res); + res = _Py_BinaryFunctionTable[type_version >> 8](left, right); + if (res == NULL) JUMP_TO_ERROR(); stack_pointer[-2] = res; stack_pointer += -1; break; } - case _BINARY_OP_ADD_FLOAT: { + case _BINARY_OP_TABLE_ND: { PyObject *right; PyObject *left; PyObject *res; right = stack_pointer[-1]; left = stack_pointer[-2]; + uint16_t type_version = (uint16_t)CURRENT_OPERAND(); + // The ND sufix indicates that it decrefs only the right argument */ STAT_INC(BINARY_OP, hit); - double dres = - ((PyFloatObject *)left)->ob_fval + - ((PyFloatObject *)right)->ob_fval; - DECREF_INPUTS_AND_REUSE_FLOAT(left, right, dres, res); + res = _Py_BinaryFunctionTable[type_version >> 8](left, right); + Py_DECREF(right); + if (res == NULL) JUMP_TO_ERROR(); stack_pointer[-2] = res; stack_pointer += -1; break; } - case _BINARY_OP_SUBTRACT_FLOAT: { + case _BINARY_OP_TABLE_DN: { PyObject *right; PyObject *left; PyObject *res; right = stack_pointer[-1]; left = stack_pointer[-2]; + uint16_t type_version = (uint16_t)CURRENT_OPERAND(); + // The DN sufix indicates that it decrefs only the left argument */ STAT_INC(BINARY_OP, hit); - double dres = - ((PyFloatObject *)left)->ob_fval - - ((PyFloatObject *)right)->ob_fval; - DECREF_INPUTS_AND_REUSE_FLOAT(left, right, dres, res); + res = _Py_BinaryFunctionTable[type_version >> 8](left, right); + Py_DECREF(left); + if (res == NULL) JUMP_TO_ERROR(); stack_pointer[-2] = res; stack_pointer += -1; break; } - case _GUARD_BOTH_UNICODE: { + case _BINARY_OP_TABLE_DD: { PyObject *right; PyObject *left; + PyObject *res; right = stack_pointer[-1]; left = stack_pointer[-2]; - if (!PyUnicode_CheckExact(left)) { + uint16_t type_version = (uint16_t)CURRENT_OPERAND(); + // The DD sufix indicates that it decrefs both arguments */ + STAT_INC(BINARY_OP, hit); + res = _Py_BinaryFunctionTable[type_version >> 8](left, right); + Py_DECREF(left); + Py_DECREF(right); + if (res == NULL) JUMP_TO_ERROR(); + stack_pointer[-2] = res; + stack_pointer += -1; + break; + } + + case _GUARD_BOTH_INT: { + PyObject *right; + PyObject *left; + right = stack_pointer[-1]; + left = stack_pointer[-2]; + if (!PyLong_CheckExact(left)) { UOP_STAT_INC(uopcode, miss); JUMP_TO_JUMP_TARGET(); } - if (!PyUnicode_CheckExact(right)) { + if (!PyLong_CheckExact(right)) { UOP_STAT_INC(uopcode, miss); JUMP_TO_JUMP_TARGET(); } break; } - case _BINARY_OP_ADD_UNICODE: { + case _GUARD_BOTH_FLOAT: { PyObject *right; PyObject *left; - PyObject *res; right = stack_pointer[-1]; left = stack_pointer[-2]; - STAT_INC(BINARY_OP, hit); - res = PyUnicode_Concat(left, right); - _Py_DECREF_SPECIALIZED(left, _PyUnicode_ExactDealloc); - _Py_DECREF_SPECIALIZED(right, _PyUnicode_ExactDealloc); - if (res == NULL) JUMP_TO_ERROR(); - stack_pointer[-2] = res; - stack_pointer += -1; + if (!PyFloat_CheckExact(left)) { + UOP_STAT_INC(uopcode, miss); + JUMP_TO_JUMP_TARGET(); + } + if (!PyFloat_CheckExact(right)) { + UOP_STAT_INC(uopcode, miss); + JUMP_TO_JUMP_TARGET(); + } + break; + } + + case _GUARD_BOTH_UNICODE: { + PyObject *right; + PyObject *left; + right = stack_pointer[-1]; + left = stack_pointer[-2]; + if (!PyUnicode_CheckExact(left)) { + UOP_STAT_INC(uopcode, miss); + JUMP_TO_JUMP_TARGET(); + } + if (!PyUnicode_CheckExact(right)) { + UOP_STAT_INC(uopcode, miss); + JUMP_TO_JUMP_TARGET(); + } break; } diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 4402787d96f12e..380f8ed94c086a 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -100,10 +100,10 @@ TARGET(BINARY_OP) { frame->instr_ptr = next_instr; - next_instr += 2; + next_instr += 3; INSTRUCTION_STATS(BINARY_OP); PREDICTED(BINARY_OP); - _Py_CODEUNIT *this_instr = next_instr - 2; + _Py_CODEUNIT *this_instr = next_instr - 3; (void)this_instr; PyObject *rhs; PyObject *lhs; @@ -126,6 +126,7 @@ assert(NB_ADD <= oparg); assert(oparg <= NB_INPLACE_XOR); } + /* Skip 1 cache entry */ // _BINARY_OP { assert(_PyEval_BinaryOps[oparg]); @@ -139,57 +140,84 @@ DISPATCH(); } - TARGET(BINARY_OP_ADD_FLOAT) { - frame->instr_ptr = next_instr; - next_instr += 2; - INSTRUCTION_STATS(BINARY_OP_ADD_FLOAT); - static_assert(INLINE_CACHE_ENTRIES_BINARY_OP == 1, "incorrect cache size"); + TARGET(BINARY_OP_1I) { + _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; + next_instr += 3; + INSTRUCTION_STATS(BINARY_OP_1I); + static_assert(INLINE_CACHE_ENTRIES_BINARY_OP == 2, "incorrect cache size"); + PyObject *value2; + PyObject *value1; PyObject *right; PyObject *left; PyObject *res; - // _GUARD_BOTH_FLOAT - right = stack_pointer[-1]; - left = stack_pointer[-2]; + /* Skip 1 cache entry */ + // _GUARD_NOS_REFCNT1 + value2 = stack_pointer[-2]; { - DEOPT_IF(!PyFloat_CheckExact(left), BINARY_OP); - DEOPT_IF(!PyFloat_CheckExact(right), BINARY_OP); + DEOPT_IF(Py_REFCNT(value2) != 1, BINARY_OP); } - /* Skip 1 cache entry */ - // _BINARY_OP_ADD_FLOAT + // _GUARD_TOS_IMMORTAL + value1 = stack_pointer[-1]; + { + DEOPT_IF(!_Py_IsImmortal(value1), BINARY_OP); + } + // _GUARD_VERSION_TYPES + right = value1; + left = value2; { + uint16_t type_version = read_u16(&this_instr[2].cache); + PyTypeObject *lt = Py_TYPE(left); + PyTypeObject *rt = Py_TYPE(right); + DEOPT_IF(lt->tp_version_tag != ((type_version & 0xf0) >> 4), BINARY_OP); + DEOPT_IF(rt->tp_version_tag != (type_version & 0xf), BINARY_OP); + } + /* Skip -1 cache entry */ + // _BINARY_OP_TABLE_NN + { + uint16_t type_version = read_u16(&this_instr[2].cache); + // The NN sufix indicates that it does not decref the arguments */ STAT_INC(BINARY_OP, hit); - double dres = - ((PyFloatObject *)left)->ob_fval + - ((PyFloatObject *)right)->ob_fval; - DECREF_INPUTS_AND_REUSE_FLOAT(left, right, dres, res); + res = _Py_BinaryFunctionTable[type_version >> 8](left, right); + if (res == NULL) goto pop_2_error; } stack_pointer[-2] = res; stack_pointer += -1; DISPATCH(); } - TARGET(BINARY_OP_ADD_INT) { - frame->instr_ptr = next_instr; - next_instr += 2; - INSTRUCTION_STATS(BINARY_OP_ADD_INT); - static_assert(INLINE_CACHE_ENTRIES_BINARY_OP == 1, "incorrect cache size"); + TARGET(BINARY_OP_1X) { + _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; + next_instr += 3; + INSTRUCTION_STATS(BINARY_OP_1X); + static_assert(INLINE_CACHE_ENTRIES_BINARY_OP == 2, "incorrect cache size"); + PyObject *value2; PyObject *right; PyObject *left; PyObject *res; - // _GUARD_BOTH_INT + /* Skip 1 cache entry */ + // _GUARD_NOS_REFCNT1 + value2 = stack_pointer[-2]; + { + DEOPT_IF(Py_REFCNT(value2) != 1, BINARY_OP); + } + // _GUARD_VERSION_TYPES right = stack_pointer[-1]; - left = stack_pointer[-2]; + left = value2; { - DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP); - DEOPT_IF(!PyLong_CheckExact(right), BINARY_OP); + uint16_t type_version = read_u16(&this_instr[2].cache); + PyTypeObject *lt = Py_TYPE(left); + PyTypeObject *rt = Py_TYPE(right); + DEOPT_IF(lt->tp_version_tag != ((type_version & 0xf0) >> 4), BINARY_OP); + DEOPT_IF(rt->tp_version_tag != (type_version & 0xf), BINARY_OP); } - /* Skip 1 cache entry */ - // _BINARY_OP_ADD_INT + /* Skip -1 cache entry */ + // _BINARY_OP_TABLE_ND { + uint16_t type_version = read_u16(&this_instr[2].cache); + // The ND sufix indicates that it decrefs only the right argument */ STAT_INC(BINARY_OP, hit); - res = _PyLong_Add((PyLongObject *)left, (PyLongObject *)right); - _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); - _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); + res = _Py_BinaryFunctionTable[type_version >> 8](left, right); + Py_DECREF(right); if (res == NULL) goto pop_2_error; } stack_pointer[-2] = res; @@ -197,28 +225,89 @@ DISPATCH(); } - TARGET(BINARY_OP_ADD_UNICODE) { - frame->instr_ptr = next_instr; - next_instr += 2; - INSTRUCTION_STATS(BINARY_OP_ADD_UNICODE); - static_assert(INLINE_CACHE_ENTRIES_BINARY_OP == 1, "incorrect cache size"); + TARGET(BINARY_OP_I1) { + _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; + next_instr += 3; + INSTRUCTION_STATS(BINARY_OP_I1); + static_assert(INLINE_CACHE_ENTRIES_BINARY_OP == 2, "incorrect cache size"); + PyObject *value2; + PyObject *value1; PyObject *right; PyObject *left; PyObject *res; - // _GUARD_BOTH_UNICODE - right = stack_pointer[-1]; - left = stack_pointer[-2]; + /* Skip 1 cache entry */ + // _GUARD_NOS_IMMORTAL + value2 = stack_pointer[-2]; { - DEOPT_IF(!PyUnicode_CheckExact(left), BINARY_OP); - DEOPT_IF(!PyUnicode_CheckExact(right), BINARY_OP); + DEOPT_IF(!_Py_IsImmortal(value2), BINARY_OP); + } + // _GUARD_TOS_REFCNT1 + value1 = stack_pointer[-1]; + { + DEOPT_IF(Py_REFCNT(value1) != 1, BINARY_OP); } + // _GUARD_VERSION_TYPES + right = value1; + left = value2; + { + uint16_t type_version = read_u16(&this_instr[2].cache); + PyTypeObject *lt = Py_TYPE(left); + PyTypeObject *rt = Py_TYPE(right); + DEOPT_IF(lt->tp_version_tag != ((type_version & 0xf0) >> 4), BINARY_OP); + DEOPT_IF(rt->tp_version_tag != (type_version & 0xf), BINARY_OP); + } + /* Skip -1 cache entry */ + // _BINARY_OP_TABLE_NN + { + uint16_t type_version = read_u16(&this_instr[2].cache); + // The NN sufix indicates that it does not decref the arguments */ + STAT_INC(BINARY_OP, hit); + res = _Py_BinaryFunctionTable[type_version >> 8](left, right); + if (res == NULL) goto pop_2_error; + } + stack_pointer[-2] = res; + stack_pointer += -1; + DISPATCH(); + } + + TARGET(BINARY_OP_II) { + _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; + next_instr += 3; + INSTRUCTION_STATS(BINARY_OP_II); + static_assert(INLINE_CACHE_ENTRIES_BINARY_OP == 2, "incorrect cache size"); + PyObject *value2; + PyObject *value1; + PyObject *right; + PyObject *left; + PyObject *res; /* Skip 1 cache entry */ - // _BINARY_OP_ADD_UNICODE + // _GUARD_NOS_IMMORTAL + value2 = stack_pointer[-2]; + { + DEOPT_IF(!_Py_IsImmortal(value2), BINARY_OP); + } + // _GUARD_TOS_IMMORTAL + value1 = stack_pointer[-1]; + { + DEOPT_IF(!_Py_IsImmortal(value1), BINARY_OP); + } + // _GUARD_VERSION_TYPES + right = value1; + left = value2; + { + uint16_t type_version = read_u16(&this_instr[2].cache); + PyTypeObject *lt = Py_TYPE(left); + PyTypeObject *rt = Py_TYPE(right); + DEOPT_IF(lt->tp_version_tag != ((type_version & 0xf0) >> 4), BINARY_OP); + DEOPT_IF(rt->tp_version_tag != (type_version & 0xf), BINARY_OP); + } + /* Skip -1 cache entry */ + // _BINARY_OP_TABLE_NN { + uint16_t type_version = read_u16(&this_instr[2].cache); + // The NN sufix indicates that it does not decref the arguments */ STAT_INC(BINARY_OP, hit); - res = PyUnicode_Concat(left, right); - _Py_DECREF_SPECIALIZED(left, _PyUnicode_ExactDealloc); - _Py_DECREF_SPECIALIZED(right, _PyUnicode_ExactDealloc); + res = _Py_BinaryFunctionTable[type_version >> 8](left, right); if (res == NULL) goto pop_2_error; } stack_pointer[-2] = res; @@ -228,9 +317,9 @@ TARGET(BINARY_OP_INPLACE_ADD_UNICODE) { frame->instr_ptr = next_instr; - next_instr += 2; + next_instr += 3; INSTRUCTION_STATS(BINARY_OP_INPLACE_ADD_UNICODE); - static_assert(INLINE_CACHE_ENTRIES_BINARY_OP == 1, "incorrect cache size"); + static_assert(INLINE_CACHE_ENTRIES_BINARY_OP == 2, "incorrect cache size"); PyObject *right; PyObject *left; // _GUARD_BOTH_UNICODE @@ -240,7 +329,7 @@ DEOPT_IF(!PyUnicode_CheckExact(left), BINARY_OP); DEOPT_IF(!PyUnicode_CheckExact(right), BINARY_OP); } - /* Skip 1 cache entry */ + /* Skip 2 cache entries */ // _BINARY_OP_INPLACE_ADD_UNICODE { assert(next_instr->op.code == STORE_FAST); @@ -271,57 +360,79 @@ DISPATCH(); } - TARGET(BINARY_OP_MULTIPLY_FLOAT) { - frame->instr_ptr = next_instr; - next_instr += 2; - INSTRUCTION_STATS(BINARY_OP_MULTIPLY_FLOAT); - static_assert(INLINE_CACHE_ENTRIES_BINARY_OP == 1, "incorrect cache size"); + TARGET(BINARY_OP_IX) { + _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; + next_instr += 3; + INSTRUCTION_STATS(BINARY_OP_IX); + static_assert(INLINE_CACHE_ENTRIES_BINARY_OP == 2, "incorrect cache size"); + PyObject *value2; PyObject *right; PyObject *left; PyObject *res; - // _GUARD_BOTH_FLOAT + /* Skip 1 cache entry */ + // _GUARD_NOS_IMMORTAL + value2 = stack_pointer[-2]; + { + DEOPT_IF(!_Py_IsImmortal(value2), BINARY_OP); + } + // _GUARD_VERSION_TYPES right = stack_pointer[-1]; - left = stack_pointer[-2]; + left = value2; { - DEOPT_IF(!PyFloat_CheckExact(left), BINARY_OP); - DEOPT_IF(!PyFloat_CheckExact(right), BINARY_OP); + uint16_t type_version = read_u16(&this_instr[2].cache); + PyTypeObject *lt = Py_TYPE(left); + PyTypeObject *rt = Py_TYPE(right); + DEOPT_IF(lt->tp_version_tag != ((type_version & 0xf0) >> 4), BINARY_OP); + DEOPT_IF(rt->tp_version_tag != (type_version & 0xf), BINARY_OP); } - /* Skip 1 cache entry */ - // _BINARY_OP_MULTIPLY_FLOAT + /* Skip -1 cache entry */ + // _BINARY_OP_TABLE_ND { + uint16_t type_version = read_u16(&this_instr[2].cache); + // The ND sufix indicates that it decrefs only the right argument */ STAT_INC(BINARY_OP, hit); - double dres = - ((PyFloatObject *)left)->ob_fval * - ((PyFloatObject *)right)->ob_fval; - DECREF_INPUTS_AND_REUSE_FLOAT(left, right, dres, res); + res = _Py_BinaryFunctionTable[type_version >> 8](left, right); + Py_DECREF(right); + if (res == NULL) goto pop_2_error; } stack_pointer[-2] = res; stack_pointer += -1; DISPATCH(); } - TARGET(BINARY_OP_MULTIPLY_INT) { - frame->instr_ptr = next_instr; - next_instr += 2; - INSTRUCTION_STATS(BINARY_OP_MULTIPLY_INT); - static_assert(INLINE_CACHE_ENTRIES_BINARY_OP == 1, "incorrect cache size"); + TARGET(BINARY_OP_X1) { + _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; + next_instr += 3; + INSTRUCTION_STATS(BINARY_OP_X1); + static_assert(INLINE_CACHE_ENTRIES_BINARY_OP == 2, "incorrect cache size"); + PyObject *value1; PyObject *right; PyObject *left; PyObject *res; - // _GUARD_BOTH_INT - right = stack_pointer[-1]; + /* Skip 1 cache entry */ + // _GUARD_TOS_REFCNT1 + value1 = stack_pointer[-1]; + { + DEOPT_IF(Py_REFCNT(value1) != 1, BINARY_OP); + } + // _GUARD_VERSION_TYPES + right = value1; left = stack_pointer[-2]; { - DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP); - DEOPT_IF(!PyLong_CheckExact(right), BINARY_OP); + uint16_t type_version = read_u16(&this_instr[2].cache); + PyTypeObject *lt = Py_TYPE(left); + PyTypeObject *rt = Py_TYPE(right); + DEOPT_IF(lt->tp_version_tag != ((type_version & 0xf0) >> 4), BINARY_OP); + DEOPT_IF(rt->tp_version_tag != (type_version & 0xf), BINARY_OP); } - /* Skip 1 cache entry */ - // _BINARY_OP_MULTIPLY_INT + /* Skip -1 cache entry */ + // _BINARY_OP_TABLE_DN { + uint16_t type_version = read_u16(&this_instr[2].cache); + // The DN sufix indicates that it decrefs only the left argument */ STAT_INC(BINARY_OP, hit); - res = _PyLong_Multiply((PyLongObject *)left, (PyLongObject *)right); - _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); - _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); + res = _Py_BinaryFunctionTable[type_version >> 8](left, right); + Py_DECREF(left); if (res == NULL) goto pop_2_error; } stack_pointer[-2] = res; @@ -329,57 +440,74 @@ DISPATCH(); } - TARGET(BINARY_OP_SUBTRACT_FLOAT) { - frame->instr_ptr = next_instr; - next_instr += 2; - INSTRUCTION_STATS(BINARY_OP_SUBTRACT_FLOAT); - static_assert(INLINE_CACHE_ENTRIES_BINARY_OP == 1, "incorrect cache size"); + TARGET(BINARY_OP_XI) { + _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; + next_instr += 3; + INSTRUCTION_STATS(BINARY_OP_XI); + static_assert(INLINE_CACHE_ENTRIES_BINARY_OP == 2, "incorrect cache size"); + PyObject *value1; PyObject *right; PyObject *left; PyObject *res; - // _GUARD_BOTH_FLOAT - right = stack_pointer[-1]; + /* Skip 1 cache entry */ + // _GUARD_TOS_IMMORTAL + value1 = stack_pointer[-1]; + { + DEOPT_IF(!_Py_IsImmortal(value1), BINARY_OP); + } + // _GUARD_VERSION_TYPES + right = value1; left = stack_pointer[-2]; { - DEOPT_IF(!PyFloat_CheckExact(left), BINARY_OP); - DEOPT_IF(!PyFloat_CheckExact(right), BINARY_OP); + uint16_t type_version = read_u16(&this_instr[2].cache); + PyTypeObject *lt = Py_TYPE(left); + PyTypeObject *rt = Py_TYPE(right); + DEOPT_IF(lt->tp_version_tag != ((type_version & 0xf0) >> 4), BINARY_OP); + DEOPT_IF(rt->tp_version_tag != (type_version & 0xf), BINARY_OP); } - /* Skip 1 cache entry */ - // _BINARY_OP_SUBTRACT_FLOAT + /* Skip -1 cache entry */ + // _BINARY_OP_TABLE_DN { + uint16_t type_version = read_u16(&this_instr[2].cache); + // The DN sufix indicates that it decrefs only the left argument */ STAT_INC(BINARY_OP, hit); - double dres = - ((PyFloatObject *)left)->ob_fval - - ((PyFloatObject *)right)->ob_fval; - DECREF_INPUTS_AND_REUSE_FLOAT(left, right, dres, res); + res = _Py_BinaryFunctionTable[type_version >> 8](left, right); + Py_DECREF(left); + if (res == NULL) goto pop_2_error; } stack_pointer[-2] = res; stack_pointer += -1; DISPATCH(); } - TARGET(BINARY_OP_SUBTRACT_INT) { - frame->instr_ptr = next_instr; - next_instr += 2; - INSTRUCTION_STATS(BINARY_OP_SUBTRACT_INT); - static_assert(INLINE_CACHE_ENTRIES_BINARY_OP == 1, "incorrect cache size"); + TARGET(BINARY_OP_XX) { + _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; + next_instr += 3; + INSTRUCTION_STATS(BINARY_OP_XX); + static_assert(INLINE_CACHE_ENTRIES_BINARY_OP == 2, "incorrect cache size"); PyObject *right; PyObject *left; PyObject *res; - // _GUARD_BOTH_INT + /* Skip 1 cache entry */ + // _GUARD_VERSION_TYPES right = stack_pointer[-1]; left = stack_pointer[-2]; { - DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP); - DEOPT_IF(!PyLong_CheckExact(right), BINARY_OP); + uint16_t type_version = read_u16(&this_instr[2].cache); + PyTypeObject *lt = Py_TYPE(left); + PyTypeObject *rt = Py_TYPE(right); + DEOPT_IF(lt->tp_version_tag != ((type_version & 0xf0) >> 4), BINARY_OP); + DEOPT_IF(rt->tp_version_tag != (type_version & 0xf), BINARY_OP); } - /* Skip 1 cache entry */ - // _BINARY_OP_SUBTRACT_INT + /* Skip -1 cache entry */ + // _BINARY_OP_TABLE_DD { + uint16_t type_version = read_u16(&this_instr[2].cache); + // The DD sufix indicates that it decrefs both arguments */ STAT_INC(BINARY_OP, hit); - res = _PyLong_Subtract((PyLongObject *)left, (PyLongObject *)right); - _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); - _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); + res = _Py_BinaryFunctionTable[type_version >> 8](left, right); + Py_DECREF(left); + Py_DECREF(right); if (res == NULL) goto pop_2_error; } stack_pointer[-2] = res; diff --git a/Python/opcode_targets.h b/Python/opcode_targets.h index 322483fefecf91..c555f0c6584369 100644 --- a/Python/opcode_targets.h +++ b/Python/opcode_targets.h @@ -149,13 +149,14 @@ static void *opcode_targets[256] = { &&_unknown_opcode, &&_unknown_opcode, &&TARGET_RESUME, - &&TARGET_BINARY_OP_ADD_FLOAT, - &&TARGET_BINARY_OP_ADD_INT, - &&TARGET_BINARY_OP_ADD_UNICODE, - &&TARGET_BINARY_OP_MULTIPLY_FLOAT, - &&TARGET_BINARY_OP_MULTIPLY_INT, - &&TARGET_BINARY_OP_SUBTRACT_FLOAT, - &&TARGET_BINARY_OP_SUBTRACT_INT, + &&TARGET_BINARY_OP_1I, + &&TARGET_BINARY_OP_1X, + &&TARGET_BINARY_OP_I1, + &&TARGET_BINARY_OP_II, + &&TARGET_BINARY_OP_IX, + &&TARGET_BINARY_OP_X1, + &&TARGET_BINARY_OP_XI, + &&TARGET_BINARY_OP_XX, &&TARGET_BINARY_SUBSCR_DICT, &&TARGET_BINARY_SUBSCR_GETITEM, &&TARGET_BINARY_SUBSCR_LIST_INT, @@ -234,7 +235,6 @@ static void *opcode_targets[256] = { &&_unknown_opcode, &&_unknown_opcode, &&_unknown_opcode, - &&_unknown_opcode, &&TARGET_INSTRUMENTED_RESUME, &&TARGET_INSTRUMENTED_END_FOR, &&TARGET_INSTRUMENTED_END_SEND, diff --git a/Python/optimizer.c b/Python/optimizer.c index 5b4a6ff8cb3dad..9833da338b332c 100644 --- a/Python/optimizer.c +++ b/Python/optimizer.c @@ -581,7 +581,7 @@ translate_bytecode_to_trace( _Py_CODEUNIT *initial_instr = instr; int trace_length = 0; // Leave space for possible trailing _EXIT_TRACE - int max_length = buffer_size-2; + int max_length = buffer_size-3; struct { PyFunctionObject *func; PyCodeObject *code; diff --git a/Python/optimizer_analysis.c b/Python/optimizer_analysis.c index e5d3793bd4d204..11ea51b63b1401 100644 --- a/Python/optimizer_analysis.c +++ b/Python/optimizer_analysis.c @@ -13,6 +13,7 @@ * */ #include "Python.h" #include "opcode.h" +#include "pycore_ceval.h" #include "pycore_dict.h" #include "pycore_interp.h" #include "pycore_opcode_metadata.h" @@ -341,6 +342,54 @@ optimize_to_bool( return 0; } +static void +optimize_binary_op( + _PyUOpInstruction *this_instr, + _Py_UOpsContext *ctx, + _Py_UopsSymbol *left, + _Py_UopsSymbol *right, + _Py_UopsSymbol **result_ptr) +{ + PyTypeObject *ltype = sym_get_type(left); + PyTypeObject *rtype = sym_get_type(right); + int oparg = this_instr->oparg; + if ((ltype == &PyLong_Type || ltype == &PyFloat_Type) && + (rtype == &PyLong_Type || rtype == &PyFloat_Type)) + { + if (sym_is_const(left) && sym_is_const(right)) { + PyObject *lhs = sym_get_const(left); + PyObject *rhs = sym_get_const(right); + assert(_PyEval_BinaryOps[oparg]); + PyObject *temp = _PyEval_BinaryOps[oparg](lhs, rhs); + if (temp != NULL) { + *result_ptr = sym_new_const(ctx, temp); + Py_DECREF(temp); + return; + } + else { + PyErr_Clear(); + } + } + if (oparg != NB_TRUE_DIVIDE && oparg != NB_INPLACE_TRUE_DIVIDE && + ltype == &PyLong_Type && rtype == &PyLong_Type) { + /* If both inputs are ints and the op is not division the result is an int */ + *result_ptr = sym_new_type(ctx, &PyLong_Type); + } + else { + /* For any other op combining ints/floats the result is a float */ + *result_ptr = sym_new_type(ctx, &PyFloat_Type); + } + } + else if ((oparg == NB_ADD || oparg == NB_INPLACE_ADD) && + ltype == &PyUnicode_Type && rtype == &PyUnicode_Type) + { + *result_ptr = sym_new_type(ctx, &PyUnicode_Type); + } + else { + *result_ptr = sym_new_unknown(ctx); + } +} + static void eliminate_pop_guard(_PyUOpInstruction *this_instr, bool exit) { @@ -464,15 +513,6 @@ optimize_uops( } return trace_len; -error: - DPRINTF(3, "\n"); - DPRINTF(1, "Encountered error in abstract interpreter\n"); - if (opcode <= MAX_UOP_ID) { - OPT_ERROR_IN_OPCODE(opcode); - } - _Py_uop_abstractcontext_fini(ctx); - return -1; - } diff --git a/Python/optimizer_bytecodes.c b/Python/optimizer_bytecodes.c index a2cb4c0b2c5192..841e6a985e4c6c 100644 --- a/Python/optimizer_bytecodes.c +++ b/Python/optimizer_bytecodes.c @@ -38,6 +38,14 @@ optimize_to_bool( _Py_UopsSymbol *value, _Py_UopsSymbol **result_ptr); +extern void +optimize_binary_op( + _PyUOpInstruction *this_instr, + _Py_UOpsContext *ctx, + _Py_UopsSymbol *left, + _Py_UopsSymbol *right, + _Py_UopsSymbol **result_ptr); + extern void eliminate_pop_guard(_PyUOpInstruction *this_instr, bool exit); @@ -64,6 +72,7 @@ dummy_func(void) { int modified; int curr_space; int max_space; + int type_version; _PyUOpInstruction *first_valid_check_stack; _PyUOpInstruction *corresponding_check_stack; @@ -142,166 +151,27 @@ dummy_func(void) { } op(_BINARY_OP, (left, right -- res)) { - PyTypeObject *ltype = sym_get_type(left); - PyTypeObject *rtype = sym_get_type(right); - if (ltype != NULL && (ltype == &PyLong_Type || ltype == &PyFloat_Type) && - rtype != NULL && (rtype == &PyLong_Type || rtype == &PyFloat_Type)) - { - if (oparg != NB_TRUE_DIVIDE && oparg != NB_INPLACE_TRUE_DIVIDE && - ltype == &PyLong_Type && rtype == &PyLong_Type) { - /* If both inputs are ints and the op is not division the result is an int */ - res = sym_new_type(ctx, &PyLong_Type); - } - else { - /* For any other op combining ints/floats the result is a float */ - res = sym_new_type(ctx, &PyFloat_Type); - } - } - res = sym_new_unknown(ctx); + optimize_binary_op(this_instr, ctx, left, right, &res); } - op(_BINARY_OP_ADD_INT, (left, right -- res)) { - if (sym_is_const(left) && sym_is_const(right) && - sym_matches_type(left, &PyLong_Type) && sym_matches_type(right, &PyLong_Type)) - { - assert(PyLong_CheckExact(sym_get_const(left))); - assert(PyLong_CheckExact(sym_get_const(right))); - PyObject *temp = _PyLong_Add((PyLongObject *)sym_get_const(left), - (PyLongObject *)sym_get_const(right)); - if (temp == NULL) { - goto error; - } - res = sym_new_const(ctx, temp); - Py_DECREF(temp); - // TODO gh-115506: - // replace opcode with constant propagated one and add tests! - } - else { - res = sym_new_type(ctx, &PyLong_Type); - } + op(_BINARY_OP_TABLE_ND, (left, right -- res)) { + (void)type_version; + optimize_binary_op(this_instr, ctx, left, right, &res); } - op(_BINARY_OP_SUBTRACT_INT, (left, right -- res)) { - if (sym_is_const(left) && sym_is_const(right) && - sym_matches_type(left, &PyLong_Type) && sym_matches_type(right, &PyLong_Type)) - { - assert(PyLong_CheckExact(sym_get_const(left))); - assert(PyLong_CheckExact(sym_get_const(right))); - PyObject *temp = _PyLong_Subtract((PyLongObject *)sym_get_const(left), - (PyLongObject *)sym_get_const(right)); - if (temp == NULL) { - goto error; - } - res = sym_new_const(ctx, temp); - Py_DECREF(temp); - // TODO gh-115506: - // replace opcode with constant propagated one and add tests! - } - else { - res = sym_new_type(ctx, &PyLong_Type); - } + op(_BINARY_OP_TABLE_NN, (left, right -- res)) { + (void)type_version; + optimize_binary_op(this_instr, ctx, left, right, &res); } - op(_BINARY_OP_MULTIPLY_INT, (left, right -- res)) { - if (sym_is_const(left) && sym_is_const(right) && - sym_matches_type(left, &PyLong_Type) && sym_matches_type(right, &PyLong_Type)) - { - assert(PyLong_CheckExact(sym_get_const(left))); - assert(PyLong_CheckExact(sym_get_const(right))); - PyObject *temp = _PyLong_Multiply((PyLongObject *)sym_get_const(left), - (PyLongObject *)sym_get_const(right)); - if (temp == NULL) { - goto error; - } - res = sym_new_const(ctx, temp); - Py_DECREF(temp); - // TODO gh-115506: - // replace opcode with constant propagated one and add tests! - } - else { - res = sym_new_type(ctx, &PyLong_Type); - } + op(_BINARY_OP_TABLE_DN, (left, right -- res)) { + (void)type_version; + optimize_binary_op(this_instr, ctx, left, right, &res); } - op(_BINARY_OP_ADD_FLOAT, (left, right -- res)) { - if (sym_is_const(left) && sym_is_const(right) && - sym_matches_type(left, &PyFloat_Type) && sym_matches_type(right, &PyFloat_Type)) - { - assert(PyFloat_CheckExact(sym_get_const(left))); - assert(PyFloat_CheckExact(sym_get_const(right))); - PyObject *temp = PyFloat_FromDouble( - PyFloat_AS_DOUBLE(sym_get_const(left)) + - PyFloat_AS_DOUBLE(sym_get_const(right))); - if (temp == NULL) { - goto error; - } - res = sym_new_const(ctx, temp); - Py_DECREF(temp); - // TODO gh-115506: - // replace opcode with constant propagated one and update tests! - } - else { - res = sym_new_type(ctx, &PyFloat_Type); - } - } - - op(_BINARY_OP_SUBTRACT_FLOAT, (left, right -- res)) { - if (sym_is_const(left) && sym_is_const(right) && - sym_matches_type(left, &PyFloat_Type) && sym_matches_type(right, &PyFloat_Type)) - { - assert(PyFloat_CheckExact(sym_get_const(left))); - assert(PyFloat_CheckExact(sym_get_const(right))); - PyObject *temp = PyFloat_FromDouble( - PyFloat_AS_DOUBLE(sym_get_const(left)) - - PyFloat_AS_DOUBLE(sym_get_const(right))); - if (temp == NULL) { - goto error; - } - res = sym_new_const(ctx, temp); - Py_DECREF(temp); - // TODO gh-115506: - // replace opcode with constant propagated one and update tests! - } - else { - res = sym_new_type(ctx, &PyFloat_Type); - } - } - - op(_BINARY_OP_MULTIPLY_FLOAT, (left, right -- res)) { - if (sym_is_const(left) && sym_is_const(right) && - sym_matches_type(left, &PyFloat_Type) && sym_matches_type(right, &PyFloat_Type)) - { - assert(PyFloat_CheckExact(sym_get_const(left))); - assert(PyFloat_CheckExact(sym_get_const(right))); - PyObject *temp = PyFloat_FromDouble( - PyFloat_AS_DOUBLE(sym_get_const(left)) * - PyFloat_AS_DOUBLE(sym_get_const(right))); - if (temp == NULL) { - goto error; - } - res = sym_new_const(ctx, temp); - Py_DECREF(temp); - // TODO gh-115506: - // replace opcode with constant propagated one and update tests! - } - else { - res = sym_new_type(ctx, &PyFloat_Type); - } - } - - op(_BINARY_OP_ADD_UNICODE, (left, right -- res)) { - if (sym_is_const(left) && sym_is_const(right) && - sym_matches_type(left, &PyUnicode_Type) && sym_matches_type(right, &PyUnicode_Type)) { - PyObject *temp = PyUnicode_Concat(sym_get_const(left), sym_get_const(right)); - if (temp == NULL) { - goto error; - } - res = sym_new_const(ctx, temp); - Py_DECREF(temp); - } - else { - res = sym_new_type(ctx, &PyUnicode_Type); - } + op(_BINARY_OP_TABLE_DD, (left, right -- res)) { + (void)type_version; + optimize_binary_op(this_instr, ctx, left, right, &res); } op(_TO_BOOL, (value -- res)) { @@ -745,6 +615,34 @@ dummy_func(void) { } } + + op(_GUARD_VERSION_TYPES, (type_version/1, left, right -- left, right)) { + PyTypeObject *lguard = _Py_PreAllocatedTypes[(type_version & 0xf0) >> 4]; + PyTypeObject *rguard = _Py_PreAllocatedTypes[type_version & 0xf]; + PyTypeObject *ltype = sym_get_type(left); + PyTypeObject *rtype = sym_get_type(right); + if (ltype != NULL && ltype == lguard) { + if (rtype != NULL && rtype == rguard) { + REPLACE_OP(this_instr, _NOP, 0 ,0); + } + else { + REPLACE_OP(this_instr, _GUARD_TOS_VERSION, 0, type_version & 0xf); + + } + } + else { + if (rtype != NULL && rtype == rguard) { + REPLACE_OP(this_instr, _GUARD_NOS_VERSION, 0, (type_version & 0xf0) >> 4); + } + } + if (lguard != NULL) { + sym_set_type(left, lguard); + } + if (rguard != NULL) { + sym_set_type(right, rguard); + } + } + op(_CHECK_PEP_523, (--)) { /* Setting the eval frame function invalidates * all executors, so no need to check dynamically */ diff --git a/Python/optimizer_cases.c.h b/Python/optimizer_cases.c.h index 1b76f1480b4f11..65ba236f1f68ee 100644 --- a/Python/optimizer_cases.c.h +++ b/Python/optimizer_cases.c.h @@ -182,242 +182,177 @@ break; } - case _GUARD_BOTH_INT: { + case _GUARD_NOS_REFCNT1: { + break; + } + + case _GUARD_TOS_REFCNT1: { + break; + } + + case _GUARD_NOS_INT: { + break; + } + + case _GUARD_TOS_INT: { + break; + } + + case _GUARD_NOS_IMMORTAL: { + break; + } + + case _GUARD_TOS_IMMORTAL: { + break; + } + + case _GUARD_VERSION_TYPES: { _Py_UopsSymbol *right; _Py_UopsSymbol *left; right = stack_pointer[-1]; left = stack_pointer[-2]; - if (sym_matches_type(left, &PyLong_Type)) { - if (sym_matches_type(right, &PyLong_Type)) { - REPLACE_OP(this_instr, _NOP, 0, 0); + uint16_t type_version = (uint16_t)this_instr->operand; + PyTypeObject *lguard = _Py_PreAllocatedTypes[(type_version & 0xf0) >> 4]; + PyTypeObject *rguard = _Py_PreAllocatedTypes[type_version & 0xf]; + PyTypeObject *ltype = sym_get_type(left); + PyTypeObject *rtype = sym_get_type(right); + if (ltype != NULL && ltype == lguard) { + if (rtype != NULL && rtype == rguard) { + REPLACE_OP(this_instr, _NOP, 0 ,0); } else { - REPLACE_OP(this_instr, _GUARD_TOS_INT, 0, 0); + REPLACE_OP(this_instr, _GUARD_TOS_VERSION, 0, type_version & 0xf); } } else { - if (sym_matches_type(right, &PyLong_Type)) { - REPLACE_OP(this_instr, _GUARD_NOS_INT, 0, 0); + if (rtype != NULL && rtype == rguard) { + REPLACE_OP(this_instr, _GUARD_NOS_VERSION, 0, (type_version & 0xf0) >> 4); } } - sym_set_type(left, &PyLong_Type); - sym_set_type(right, &PyLong_Type); + if (lguard != NULL) { + sym_set_type(left, lguard); + } + if (rguard != NULL) { + sym_set_type(right, rguard); + } break; } - case _GUARD_NOS_INT: { + case _GUARD_TOS_VERSION: { break; } - case _GUARD_TOS_INT: { + case _GUARD_NOS_VERSION: { break; } - case _BINARY_OP_MULTIPLY_INT: { - _Py_UopsSymbol *right; - _Py_UopsSymbol *left; - _Py_UopsSymbol *res; - right = stack_pointer[-1]; - left = stack_pointer[-2]; - if (sym_is_const(left) && sym_is_const(right) && - sym_matches_type(left, &PyLong_Type) && sym_matches_type(right, &PyLong_Type)) - { - assert(PyLong_CheckExact(sym_get_const(left))); - assert(PyLong_CheckExact(sym_get_const(right))); - PyObject *temp = _PyLong_Multiply((PyLongObject *)sym_get_const(left), - (PyLongObject *)sym_get_const(right)); - if (temp == NULL) { - goto error; - } - res = sym_new_const(ctx, temp); - Py_DECREF(temp); - // TODO gh-115506: - // replace opcode with constant propagated one and add tests! - } - else { - res = sym_new_type(ctx, &PyLong_Type); - } - stack_pointer[-2] = res; - stack_pointer += -1; + case _GUARD_NOS_FLOAT: { break; } - case _BINARY_OP_ADD_INT: { + case _GUARD_TOS_FLOAT: { + break; + } + + case _BINARY_OP_TABLE_NN: { _Py_UopsSymbol *right; _Py_UopsSymbol *left; _Py_UopsSymbol *res; right = stack_pointer[-1]; left = stack_pointer[-2]; - if (sym_is_const(left) && sym_is_const(right) && - sym_matches_type(left, &PyLong_Type) && sym_matches_type(right, &PyLong_Type)) - { - assert(PyLong_CheckExact(sym_get_const(left))); - assert(PyLong_CheckExact(sym_get_const(right))); - PyObject *temp = _PyLong_Add((PyLongObject *)sym_get_const(left), - (PyLongObject *)sym_get_const(right)); - if (temp == NULL) { - goto error; - } - res = sym_new_const(ctx, temp); - Py_DECREF(temp); - // TODO gh-115506: - // replace opcode with constant propagated one and add tests! - } - else { - res = sym_new_type(ctx, &PyLong_Type); - } + uint16_t type_version = (uint16_t)this_instr->operand; + (void)type_version; + optimize_binary_op(this_instr, ctx, left, right, &res); stack_pointer[-2] = res; stack_pointer += -1; break; } - case _BINARY_OP_SUBTRACT_INT: { + case _BINARY_OP_TABLE_ND: { _Py_UopsSymbol *right; _Py_UopsSymbol *left; _Py_UopsSymbol *res; right = stack_pointer[-1]; left = stack_pointer[-2]; - if (sym_is_const(left) && sym_is_const(right) && - sym_matches_type(left, &PyLong_Type) && sym_matches_type(right, &PyLong_Type)) - { - assert(PyLong_CheckExact(sym_get_const(left))); - assert(PyLong_CheckExact(sym_get_const(right))); - PyObject *temp = _PyLong_Subtract((PyLongObject *)sym_get_const(left), - (PyLongObject *)sym_get_const(right)); - if (temp == NULL) { - goto error; - } - res = sym_new_const(ctx, temp); - Py_DECREF(temp); - // TODO gh-115506: - // replace opcode with constant propagated one and add tests! - } - else { - res = sym_new_type(ctx, &PyLong_Type); - } + uint16_t type_version = (uint16_t)this_instr->operand; + (void)type_version; + optimize_binary_op(this_instr, ctx, left, right, &res); stack_pointer[-2] = res; stack_pointer += -1; break; } - case _GUARD_BOTH_FLOAT: { + case _BINARY_OP_TABLE_DN: { _Py_UopsSymbol *right; _Py_UopsSymbol *left; + _Py_UopsSymbol *res; right = stack_pointer[-1]; left = stack_pointer[-2]; - if (sym_matches_type(left, &PyFloat_Type)) { - if (sym_matches_type(right, &PyFloat_Type)) { - REPLACE_OP(this_instr, _NOP, 0, 0); - } - else { - REPLACE_OP(this_instr, _GUARD_TOS_FLOAT, 0, 0); - } - } - else { - if (sym_matches_type(right, &PyFloat_Type)) { - REPLACE_OP(this_instr, _GUARD_NOS_FLOAT, 0, 0); - } - } - sym_set_type(left, &PyFloat_Type); - sym_set_type(right, &PyFloat_Type); - break; - } - - case _GUARD_NOS_FLOAT: { - break; - } - - case _GUARD_TOS_FLOAT: { + uint16_t type_version = (uint16_t)this_instr->operand; + (void)type_version; + optimize_binary_op(this_instr, ctx, left, right, &res); + stack_pointer[-2] = res; + stack_pointer += -1; break; } - case _BINARY_OP_MULTIPLY_FLOAT: { + case _BINARY_OP_TABLE_DD: { _Py_UopsSymbol *right; _Py_UopsSymbol *left; _Py_UopsSymbol *res; right = stack_pointer[-1]; left = stack_pointer[-2]; - if (sym_is_const(left) && sym_is_const(right) && - sym_matches_type(left, &PyFloat_Type) && sym_matches_type(right, &PyFloat_Type)) - { - assert(PyFloat_CheckExact(sym_get_const(left))); - assert(PyFloat_CheckExact(sym_get_const(right))); - PyObject *temp = PyFloat_FromDouble( - PyFloat_AS_DOUBLE(sym_get_const(left)) * - PyFloat_AS_DOUBLE(sym_get_const(right))); - if (temp == NULL) { - goto error; - } - res = sym_new_const(ctx, temp); - Py_DECREF(temp); - // TODO gh-115506: - // replace opcode with constant propagated one and update tests! - } - else { - res = sym_new_type(ctx, &PyFloat_Type); - } + uint16_t type_version = (uint16_t)this_instr->operand; + (void)type_version; + optimize_binary_op(this_instr, ctx, left, right, &res); stack_pointer[-2] = res; stack_pointer += -1; break; } - case _BINARY_OP_ADD_FLOAT: { + case _GUARD_BOTH_INT: { _Py_UopsSymbol *right; _Py_UopsSymbol *left; - _Py_UopsSymbol *res; right = stack_pointer[-1]; left = stack_pointer[-2]; - if (sym_is_const(left) && sym_is_const(right) && - sym_matches_type(left, &PyFloat_Type) && sym_matches_type(right, &PyFloat_Type)) - { - assert(PyFloat_CheckExact(sym_get_const(left))); - assert(PyFloat_CheckExact(sym_get_const(right))); - PyObject *temp = PyFloat_FromDouble( - PyFloat_AS_DOUBLE(sym_get_const(left)) + - PyFloat_AS_DOUBLE(sym_get_const(right))); - if (temp == NULL) { - goto error; + if (sym_matches_type(left, &PyLong_Type)) { + if (sym_matches_type(right, &PyLong_Type)) { + REPLACE_OP(this_instr, _NOP, 0, 0); + } + else { + REPLACE_OP(this_instr, _GUARD_TOS_INT, 0, 0); } - res = sym_new_const(ctx, temp); - Py_DECREF(temp); - // TODO gh-115506: - // replace opcode with constant propagated one and update tests! } else { - res = sym_new_type(ctx, &PyFloat_Type); + if (sym_matches_type(right, &PyLong_Type)) { + REPLACE_OP(this_instr, _GUARD_NOS_INT, 0, 0); + } } - stack_pointer[-2] = res; - stack_pointer += -1; + sym_set_type(left, &PyLong_Type); + sym_set_type(right, &PyLong_Type); break; } - case _BINARY_OP_SUBTRACT_FLOAT: { + case _GUARD_BOTH_FLOAT: { _Py_UopsSymbol *right; _Py_UopsSymbol *left; - _Py_UopsSymbol *res; right = stack_pointer[-1]; left = stack_pointer[-2]; - if (sym_is_const(left) && sym_is_const(right) && - sym_matches_type(left, &PyFloat_Type) && sym_matches_type(right, &PyFloat_Type)) - { - assert(PyFloat_CheckExact(sym_get_const(left))); - assert(PyFloat_CheckExact(sym_get_const(right))); - PyObject *temp = PyFloat_FromDouble( - PyFloat_AS_DOUBLE(sym_get_const(left)) - - PyFloat_AS_DOUBLE(sym_get_const(right))); - if (temp == NULL) { - goto error; + if (sym_matches_type(left, &PyFloat_Type)) { + if (sym_matches_type(right, &PyFloat_Type)) { + REPLACE_OP(this_instr, _NOP, 0, 0); + } + else { + REPLACE_OP(this_instr, _GUARD_TOS_FLOAT, 0, 0); } - res = sym_new_const(ctx, temp); - Py_DECREF(temp); - // TODO gh-115506: - // replace opcode with constant propagated one and update tests! } else { - res = sym_new_type(ctx, &PyFloat_Type); + if (sym_matches_type(right, &PyFloat_Type)) { + REPLACE_OP(this_instr, _GUARD_NOS_FLOAT, 0, 0); + } } - stack_pointer[-2] = res; - stack_pointer += -1; + sym_set_type(left, &PyFloat_Type); + sym_set_type(right, &PyFloat_Type); break; } @@ -435,29 +370,6 @@ break; } - case _BINARY_OP_ADD_UNICODE: { - _Py_UopsSymbol *right; - _Py_UopsSymbol *left; - _Py_UopsSymbol *res; - right = stack_pointer[-1]; - left = stack_pointer[-2]; - if (sym_is_const(left) && sym_is_const(right) && - sym_matches_type(left, &PyUnicode_Type) && sym_matches_type(right, &PyUnicode_Type)) { - PyObject *temp = PyUnicode_Concat(sym_get_const(left), sym_get_const(right)); - if (temp == NULL) { - goto error; - } - res = sym_new_const(ctx, temp); - Py_DECREF(temp); - } - else { - res = sym_new_type(ctx, &PyUnicode_Type); - } - stack_pointer[-2] = res; - stack_pointer += -1; - break; - } - case _BINARY_SUBSCR: { _Py_UopsSymbol *res; res = sym_new_not_null(ctx); @@ -1842,22 +1754,7 @@ _Py_UopsSymbol *res; right = stack_pointer[-1]; left = stack_pointer[-2]; - PyTypeObject *ltype = sym_get_type(left); - PyTypeObject *rtype = sym_get_type(right); - if (ltype != NULL && (ltype == &PyLong_Type || ltype == &PyFloat_Type) && - rtype != NULL && (rtype == &PyLong_Type || rtype == &PyFloat_Type)) - { - if (oparg != NB_TRUE_DIVIDE && oparg != NB_INPLACE_TRUE_DIVIDE && - ltype == &PyLong_Type && rtype == &PyLong_Type) { - /* If both inputs are ints and the op is not division the result is an int */ - res = sym_new_type(ctx, &PyLong_Type); - } - else { - /* For any other op combining ints/floats the result is a float */ - res = sym_new_type(ctx, &PyFloat_Type); - } - } - res = sym_new_unknown(ctx); + optimize_binary_op(this_instr, ctx, left, right, &res); stack_pointer[-2] = res; stack_pointer += -1; break; diff --git a/Python/specialize.c b/Python/specialize.c index 9ac428c3593f56..9b8cac12faec28 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -6,6 +6,7 @@ #include "pycore_descrobject.h" // _PyMethodWrapper_Type #include "pycore_dict.h" // DICT_KEYS_UNICODE #include "pycore_function.h" // _PyFunction_GetVersionForCurrentState() +#include "pycore_list.h" // _PyList_Concat #include "pycore_long.h" // _PyLong_IsNonNegativeCompact() #include "pycore_moduleobject.h" #include "pycore_object.h" @@ -27,7 +28,7 @@ extern const char *_PyUOpName(int index); #ifdef Py_STATS GCStats _py_gc_stats[NUM_GENERATIONS] = { 0 }; static PyStats _Py_stats_struct = { .gc_stats = _py_gc_stats }; -PyStats *_Py_stats = NULL; +PyStats *_Py_stats = &_Py_stats_struct; // NULL; #define ADD_STAT_TO_DICT(res, field) \ do { \ @@ -313,6 +314,11 @@ print_stats(FILE *out, PyStats *stats) print_optimization_stats(out, &stats->optimization_stats); #endif print_rare_event_stats(out, &stats->rare_event_stats); + for (int i = 0; i < (1<<15); i++) { + if (stats->binary_specialization_failure[i]) { + fprintf(out, "Binary specialization failure[%d]: %" PRIu64 "\n", i, stats->binary_specialization_failure[i]); + } + } } void @@ -410,11 +416,20 @@ do { \ } \ } while (0) + +#define BINARY_SPECIALIZATION_FAIL(lv, rv, kind, oparg) \ +do { \ + if (_Py_stats) { \ + binary_specialization_fail(lv, rv, kind, oparg); \ + } \ +} while (0) + #endif // Py_STATS #ifndef SPECIALIZATION_FAIL # define SPECIALIZATION_FAIL(opcode, kind) ((void)0) +# define BINARY_SPECIALIZATION_FAIL(lv, rv, kind, oparg) ((void)0) #endif // Initialize warmup counters and insert superinstructions. This cannot fail. @@ -1986,144 +2001,434 @@ _Py_Specialize_Call(PyObject *callable, _Py_CODEUNIT *instr, int nargs) } #ifdef Py_STATS -static int -binary_op_fail_kind(int oparg, PyObject *lhs, PyObject *rhs) +static void +binary_specialization_fail(int lv, int rv, int kind, int oparg) { - switch (oparg) { - case NB_ADD: - case NB_INPLACE_ADD: - if (!Py_IS_TYPE(lhs, Py_TYPE(rhs))) { - return SPEC_FAIL_BINARY_OP_ADD_DIFFERENT_TYPES; - } - return SPEC_FAIL_BINARY_OP_ADD_OTHER; - case NB_AND: - case NB_INPLACE_AND: - if (!Py_IS_TYPE(lhs, Py_TYPE(rhs))) { - return SPEC_FAIL_BINARY_OP_AND_DIFFERENT_TYPES; - } - if (PyLong_CheckExact(lhs)) { - return SPEC_FAIL_BINARY_OP_AND_INT; - } - return SPEC_FAIL_BINARY_OP_AND_OTHER; - case NB_FLOOR_DIVIDE: - case NB_INPLACE_FLOOR_DIVIDE: - return SPEC_FAIL_BINARY_OP_FLOOR_DIVIDE; - case NB_LSHIFT: - case NB_INPLACE_LSHIFT: - return SPEC_FAIL_BINARY_OP_LSHIFT; - case NB_MATRIX_MULTIPLY: - case NB_INPLACE_MATRIX_MULTIPLY: - return SPEC_FAIL_BINARY_OP_MATRIX_MULTIPLY; - case NB_MULTIPLY: - case NB_INPLACE_MULTIPLY: - if (!Py_IS_TYPE(lhs, Py_TYPE(rhs))) { - return SPEC_FAIL_BINARY_OP_MULTIPLY_DIFFERENT_TYPES; - } - return SPEC_FAIL_BINARY_OP_MULTIPLY_OTHER; - case NB_OR: - case NB_INPLACE_OR: - return SPEC_FAIL_BINARY_OP_OR; - case NB_POWER: - case NB_INPLACE_POWER: - return SPEC_FAIL_BINARY_OP_POWER; - case NB_REMAINDER: - case NB_INPLACE_REMAINDER: - return SPEC_FAIL_BINARY_OP_REMAINDER; - case NB_RSHIFT: - case NB_INPLACE_RSHIFT: - return SPEC_FAIL_BINARY_OP_RSHIFT; - case NB_SUBTRACT: - case NB_INPLACE_SUBTRACT: - if (!Py_IS_TYPE(lhs, Py_TYPE(rhs))) { - return SPEC_FAIL_BINARY_OP_SUBTRACT_DIFFERENT_TYPES; - } - return SPEC_FAIL_BINARY_OP_SUBTRACT_OTHER; - case NB_TRUE_DIVIDE: - case NB_INPLACE_TRUE_DIVIDE: - if (!Py_IS_TYPE(lhs, Py_TYPE(rhs))) { - return SPEC_FAIL_BINARY_OP_TRUE_DIVIDE_DIFFERENT_TYPES; - } - if (PyFloat_CheckExact(lhs)) { - return SPEC_FAIL_BINARY_OP_TRUE_DIVIDE_FLOAT; + /* Gather stats per op, not family */ + if (lv >= 16) { + lv = 0; + } + if (rv >= 16) { + rv = 0; + } + assert(kind < 4); + assert(oparg < 32); + int hash = (oparg << 10) | (kind << 8) | (lv << 4) | rv; + assert(hash < (1 << 15)); + _Py_stats->binary_specialization_failure[hash]++; +} +#endif // Py_STATS + + +enum Kinds { + REFCOUNTS_11 = 0, + REFCOUNTS_1X = 1, + REFCOUNTS_X1 = 2, + REFCOUNTS_XX = 3, +}; + +typedef struct { + uint8_t oparg; + uint8_t left; + uint8_t right; + uint8_t index_1x; + uint8_t index_x1; + uint8_t index_xx; +} binary_function_entry; + + +static inline double +float_add(PyObject *left, PyObject *right) +{ + assert(PyFloat_CheckExact(left)); + assert(PyFloat_CheckExact(right)); + return PyFloat_AS_DOUBLE(left) + PyFloat_AS_DOUBLE(right); +} + +static inline double +float_sub(PyObject *left, PyObject *right) +{ + assert(PyFloat_CheckExact(left)); + assert(PyFloat_CheckExact(right)); + return PyFloat_AS_DOUBLE(left) - PyFloat_AS_DOUBLE(right); +} + +static inline double +float_mult(PyObject *left, PyObject *right) +{ + assert(PyFloat_CheckExact(left)); + assert(PyFloat_CheckExact(right)); + return PyFloat_AS_DOUBLE(left) * PyFloat_AS_DOUBLE(right); +} + +static PyObject * +binary_add_float_float_xx(PyObject *left, PyObject *right) +{ + return PyFloat_FromDouble(float_add(left, right)); +} + +static PyObject * +binary_add_float_float_1x(PyObject *left, PyObject *right) +{ + ((PyFloatObject *)left)->ob_fval = float_add(left, right); + return left; +} + +static PyObject * +binary_add_float_float_x1(PyObject *left, PyObject *right) +{ + ((PyFloatObject *)right)->ob_fval = float_add(left, right); + return right; +} + +static PyObject * +binary_mult_float_float_xx(PyObject *left, PyObject *right) +{ + return PyFloat_FromDouble(float_mult(left, right)); +} + +static PyObject * +binary_mult_float_float_1x(PyObject *left, PyObject *right) +{ + ((PyFloatObject *)left)->ob_fval = float_mult(left, right); + return left; +} + +static PyObject * +binary_mult_float_float_x1(PyObject *left, PyObject *right) +{ + ((PyFloatObject *)right)->ob_fval = float_mult(left, right); + return right; +} + +static PyObject * +binary_sub_float_float_xx(PyObject *left, PyObject *right) +{ + return PyFloat_FromDouble(float_sub(left, right)); +} + +static PyObject * +binary_sub_float_float_1x(PyObject *left, PyObject *right) +{ + ((PyFloatObject *)left)->ob_fval = float_sub(left, right); + return left; +} + +static PyObject * +binary_sub_float_float_x1(PyObject *left, PyObject *right) +{ + ((PyFloatObject *)right)->ob_fval = float_sub(left, right); + return right; +} + +static PyObject * +binary_add_float_int_xx(PyObject *left, PyObject *right) +{ + assert(PyFloat_CheckExact(left)); + assert(PyLong_CheckExact(right)); + double dleft = PyFloat_AS_DOUBLE(left); + double dright = _PyLong_AsDouble((PyLongObject *)right); + return PyFloat_FromDouble(dleft + dright); +} + +static PyObject * +binary_add_int_float_xx(PyObject *left, PyObject *right) +{ + assert(PyLong_CheckExact(left)); + assert(PyFloat_CheckExact(right)); + double dleft = _PyLong_AsDouble((PyLongObject *)left); + double dright = PyFloat_AS_DOUBLE(right); + return PyFloat_FromDouble(dleft + dright); +} + +static PyObject * +binary_sub_float_int_xx(PyObject *left, PyObject *right) +{ + assert(PyFloat_CheckExact(left)); + assert(PyLong_CheckExact(right)); + double dleft = PyFloat_AS_DOUBLE(left); + double dright = _PyLong_AsDouble((PyLongObject *)right); + return PyFloat_FromDouble(dleft - dright); +} + +static PyObject * +binary_sub_int_float_xx(PyObject *left, PyObject *right) +{ + assert(PyLong_CheckExact(left)); + assert(PyFloat_CheckExact(right)); + double dleft = _PyLong_AsDouble((PyLongObject *)left); + double dright = PyFloat_AS_DOUBLE(right); + return PyFloat_FromDouble(dleft - dright); +} + +static PyObject * +binary_mult_float_int_xx(PyObject *left, PyObject *right) +{ + assert(PyFloat_CheckExact(left)); + assert(PyLong_CheckExact(right)); + double dleft = PyFloat_AS_DOUBLE(left); + double dright = _PyLong_AsDouble((PyLongObject *)right); + return PyFloat_FromDouble(dleft * dright); +} + +static PyObject * +binary_mult_int_float_xx(PyObject *left, PyObject *right) +{ + assert(PyLong_CheckExact(left)); + assert(PyFloat_CheckExact(right)); + double dleft = _PyLong_AsDouble((PyLongObject *)left); + double dright = PyFloat_AS_DOUBLE(right); + return PyFloat_FromDouble(dleft * dright); +} + +/* Must be sorted by operator */ +static const binary_function_entry binary_function_entry_table[] = { + { NB_ADD, _Py_TYPE_VERSION_INT, _Py_TYPE_VERSION_INT, 1, 2, 3}, + { NB_ADD, _Py_TYPE_VERSION_FLOAT, _Py_TYPE_VERSION_FLOAT, 4, 5, 6}, + { NB_ADD, _Py_TYPE_VERSION_STR, _Py_TYPE_VERSION_STR, 0, 0, 16}, + { NB_ADD, _Py_TYPE_VERSION_LIST, _Py_TYPE_VERSION_LIST, 0, 0, 17}, + { NB_ADD, _Py_TYPE_VERSION_FLOAT, _Py_TYPE_VERSION_INT, 0, 0, 19}, + { NB_ADD, _Py_TYPE_VERSION_INT, _Py_TYPE_VERSION_FLOAT, 0, 0, 20}, + + { NB_AND, _Py_TYPE_VERSION_INT, _Py_TYPE_VERSION_INT, 0, 0, 7}, + + { NB_FLOOR_DIVIDE, _Py_TYPE_VERSION_INT, _Py_TYPE_VERSION_INT, 0, 0, 18}, + + { NB_LSHIFT, _Py_TYPE_VERSION_INT, _Py_TYPE_VERSION_INT, 0, 0, 26 }, + + { NB_MULTIPLY, _Py_TYPE_VERSION_INT, _Py_TYPE_VERSION_INT, 0, 0, 9}, + { NB_MULTIPLY, _Py_TYPE_VERSION_FLOAT, _Py_TYPE_VERSION_FLOAT, 10, 11, 12}, + { NB_MULTIPLY, _Py_TYPE_VERSION_FLOAT, _Py_TYPE_VERSION_INT, 0, 0, 23}, + { NB_MULTIPLY, _Py_TYPE_VERSION_INT, _Py_TYPE_VERSION_FLOAT, 0, 0, 24}, + + { NB_REMAINDER, _Py_TYPE_VERSION_STR, _Py_TYPE_VERSION_TUPLE, 0, 0, 28 }, + { NB_REMAINDER, _Py_TYPE_VERSION_STR, _Py_TYPE_VERSION_DICT, 0, 0, 28 }, + { NB_REMAINDER, _Py_TYPE_VERSION_STR, _Py_TYPE_VERSION_STR, 0, 0, 28 }, + { NB_REMAINDER, _Py_TYPE_VERSION_STR, _Py_TYPE_VERSION_INT, 0, 0, 28 }, + + { NB_OR, _Py_TYPE_VERSION_INT, _Py_TYPE_VERSION_INT, 0, 0, 25 }, + + { NB_RSHIFT, _Py_TYPE_VERSION_INT, _Py_TYPE_VERSION_INT, 0, 0, 27 }, + + { NB_SUBTRACT, _Py_TYPE_VERSION_INT, _Py_TYPE_VERSION_INT, 0, 0, 8}, + { NB_SUBTRACT, _Py_TYPE_VERSION_FLOAT, _Py_TYPE_VERSION_FLOAT, 13, 14, 15}, + { NB_SUBTRACT, _Py_TYPE_VERSION_FLOAT, _Py_TYPE_VERSION_INT, 0, 0, 21}, + { NB_SUBTRACT, _Py_TYPE_VERSION_INT, _Py_TYPE_VERSION_FLOAT, 0, 0, 22}, + + { NB_XOR, _Py_TYPE_VERSION_INT, _Py_TYPE_VERSION_INT, 0, 0, 29 }, + + + { NB_INPLACE_ADD, _Py_TYPE_VERSION_STR, _Py_TYPE_VERSION_STR, 0, 0, 16}, + { NB_INPLACE_ADD, _Py_TYPE_VERSION_INT, _Py_TYPE_VERSION_INT, 1, 2, 3}, + { NB_INPLACE_ADD, _Py_TYPE_VERSION_FLOAT, _Py_TYPE_VERSION_FLOAT, 4, 5, 6}, + { NB_INPLACE_ADD, _Py_TYPE_VERSION_FLOAT, _Py_TYPE_VERSION_INT, 0, 0, 19}, + { NB_INPLACE_ADD, _Py_TYPE_VERSION_INT, _Py_TYPE_VERSION_FLOAT, 0, 0, 20}, + + { NB_INPLACE_AND, _Py_TYPE_VERSION_INT, _Py_TYPE_VERSION_INT, 0, 0, 7}, + + { NB_INPLACE_FLOOR_DIVIDE, _Py_TYPE_VERSION_INT, _Py_TYPE_VERSION_INT, 0, 0, 18}, + + { NB_INPLACE_LSHIFT, _Py_TYPE_VERSION_INT, _Py_TYPE_VERSION_INT, 0, 0, 26 }, + + { NB_INPLACE_MULTIPLY, _Py_TYPE_VERSION_INT, _Py_TYPE_VERSION_INT, 0, 0, 9}, + { NB_INPLACE_MULTIPLY, _Py_TYPE_VERSION_FLOAT, _Py_TYPE_VERSION_FLOAT, 10, 11, 12}, + { NB_INPLACE_MULTIPLY, _Py_TYPE_VERSION_FLOAT, _Py_TYPE_VERSION_INT, 0, 0, 23}, + { NB_INPLACE_MULTIPLY, _Py_TYPE_VERSION_INT, _Py_TYPE_VERSION_FLOAT, 0, 0, 24}, + + { NB_INPLACE_REMAINDER, _Py_TYPE_VERSION_STR, _Py_TYPE_VERSION_STR, 0, 0, 28 }, + { NB_INPLACE_REMAINDER, _Py_TYPE_VERSION_STR, _Py_TYPE_VERSION_INT, 0, 0, 28 }, + { NB_INPLACE_REMAINDER, _Py_TYPE_VERSION_STR, _Py_TYPE_VERSION_DICT, 0, 0, 28 }, + { NB_INPLACE_REMAINDER, _Py_TYPE_VERSION_STR, _Py_TYPE_VERSION_TUPLE, 0, 0, 28 }, + + { NB_INPLACE_OR, _Py_TYPE_VERSION_INT, _Py_TYPE_VERSION_INT, 0, 0, 25 }, + + { NB_INPLACE_RSHIFT, _Py_TYPE_VERSION_INT, _Py_TYPE_VERSION_INT, 0, 0, 27 }, + + { NB_INPLACE_SUBTRACT, _Py_TYPE_VERSION_INT, _Py_TYPE_VERSION_INT, 0, 0, 8}, + { NB_INPLACE_SUBTRACT, _Py_TYPE_VERSION_FLOAT, _Py_TYPE_VERSION_FLOAT, 13, 14, 15}, + { NB_INPLACE_SUBTRACT, _Py_TYPE_VERSION_FLOAT, _Py_TYPE_VERSION_INT, 0, 0, 21}, + { NB_INPLACE_SUBTRACT, _Py_TYPE_VERSION_INT, _Py_TYPE_VERSION_FLOAT, 0, 0, 22}, + + { NB_INPLACE_XOR, _Py_TYPE_VERSION_INT, _Py_TYPE_VERSION_INT, 0, 0, 29 }, + + /* Sentinel */ + { NB_OPARG_LAST + 1 } +}; + +const binaryfunc _Py_BinaryFunctionTable[] = { + [0] = NULL, + [1] = (binaryfunc)_PyLong_Add_1X, + [2] = (binaryfunc)_PyLong_Add_X1, + [3] = (binaryfunc)_PyLong_Add, + [4] = binary_add_float_float_1x, + [5] = binary_add_float_float_x1, + [6] = binary_add_float_float_xx, + [7] = (binaryfunc)_PyLong_And, + [8] = (binaryfunc)_PyLong_Subtract, + [9] = (binaryfunc)_PyLong_Multiply, + [10] = binary_mult_float_float_1x, + [11] = binary_mult_float_float_x1, + [12] = binary_mult_float_float_xx, + [13] = binary_sub_float_float_1x, + [14] = binary_sub_float_float_x1, + [15] = binary_sub_float_float_xx, + [16] = PyUnicode_Concat, + [17] = (binaryfunc)_PyList_Concat, + [18] = (binaryfunc)_PyLong_FloorDiv, + [19] = binary_add_float_int_xx, + [20] = binary_add_int_float_xx, + [21] = binary_sub_float_int_xx, + [22] = binary_sub_int_float_xx, + [23] = binary_mult_float_int_xx, + [24] = binary_mult_int_float_xx, + [25] = (binaryfunc)_PyLong_Or, + [26] = (binaryfunc)_PyLong_LShiftObject, + [27] = (binaryfunc)_PyLong_RShiftObject, + [28] = PyUnicode_Format, + [29] = (binaryfunc)_PyLong_Xor, +}; + +static int +lookup_binary_function(int left_version, int right_version, int *refcounts, int oparg) { + assert(oparg < 256); + if (left_version >= _Py_TYPE_VERSIONS_PREALLOCATED) { + return 0; + } + if (right_version >= _Py_TYPE_VERSIONS_PREALLOCATED) { + return 0; + } + /* Skip a few entries for larger opargs */ + int i = oparg; + assert(binary_function_entry_table[i].oparg < oparg || i == 0); + while (binary_function_entry_table[i].oparg < oparg) { + i++; + } + assert(binary_function_entry_table[i].oparg >= oparg); + for (; binary_function_entry_table[i].oparg == oparg; i++) { + const binary_function_entry *entry = &binary_function_entry_table[i]; + if (entry->left == left_version && entry->right == right_version) { + switch (*refcounts) { + case REFCOUNTS_11: + if (entry->index_1x != 0) { + *refcounts = REFCOUNTS_1X; + return entry->index_1x; + } + if (entry->index_x1 != 0) { + *refcounts = REFCOUNTS_X1; + return entry->index_x1; + } + break; + case REFCOUNTS_X1: + if (entry->index_x1 != 0) { + return entry->index_x1; + } + break; + case REFCOUNTS_1X: + if (entry->index_1x != 0) { + return entry->index_1x; + } + break; } - return SPEC_FAIL_BINARY_OP_TRUE_DIVIDE_OTHER; - case NB_XOR: - case NB_INPLACE_XOR: - return SPEC_FAIL_BINARY_OP_XOR; + *refcounts = REFCOUNTS_XX; + return entry->index_xx; + } } - Py_UNREACHABLE(); + assert(i < (int)Py_ARRAY_LENGTH(binary_function_entry_table)); + assert(binary_function_entry_table[i].oparg > oparg); + return 0; } -#endif // Py_STATS void _Py_Specialize_BinaryOp(PyObject *lhs, PyObject *rhs, _Py_CODEUNIT *instr, int oparg, PyObject **locals) { + instr->op.code = BINARY_OP; assert(ENABLE_SPECIALIZATION); assert(_PyOpcode_Caches[BINARY_OP] == INLINE_CACHE_ENTRIES_BINARY_OP); _PyBinaryOpCache *cache = (_PyBinaryOpCache *)(instr + 1); - switch (oparg) { - case NB_ADD: - case NB_INPLACE_ADD: - if (!Py_IS_TYPE(lhs, Py_TYPE(rhs))) { - break; - } - if (PyUnicode_CheckExact(lhs)) { - _Py_CODEUNIT next = instr[INLINE_CACHE_ENTRIES_BINARY_OP + 1]; - bool to_store = (next.op.code == STORE_FAST); - if (to_store && locals[next.op.arg] == lhs) { - instr->op.code = BINARY_OP_INPLACE_ADD_UNICODE; - goto success; - } - instr->op.code = BINARY_OP_ADD_UNICODE; - goto success; - } - if (PyLong_CheckExact(lhs)) { - instr->op.code = BINARY_OP_ADD_INT; - goto success; + int refcounts; + if (Py_REFCNT(lhs) == 1) { + if (Py_REFCNT(rhs) == 1) { + refcounts = REFCOUNTS_11; + } + else { + refcounts = REFCOUNTS_1X; + } + } + else { + if (Py_REFCNT(rhs) == 1) { + refcounts = REFCOUNTS_X1; + } + else { + refcounts = REFCOUNTS_XX; + } + } + int left_version = Py_TYPE(lhs)->tp_version_tag; + int right_version = Py_TYPE(rhs)->tp_version_tag; + int func_index = 0; + if (left_version == _Py_TYPE_VERSION_STR && oparg == NB_ADD) { + _Py_CODEUNIT next = instr[INLINE_CACHE_ENTRIES_BINARY_OP + 1]; + bool to_store = (next.op.code == STORE_FAST); + if (to_store && locals[next.op.arg] == lhs) { + instr->op.code = BINARY_OP_INPLACE_ADD_UNICODE; + goto success; + } + } +#ifdef Py_STATS + int original_refcounts = refcounts; +#endif + func_index = lookup_binary_function(left_version, right_version, &refcounts, oparg); + assert(func_index >= 0 && func_index < 256); + if (func_index == 0) { + BINARY_SPECIALIZATION_FAIL(left_version, right_version, original_refcounts, oparg); + SPECIALIZATION_FAIL(BINARY_OP, oparg); + STAT_INC(BINARY_OP, failure); + cache->counter = adaptive_counter_backoff(cache->counter); + return; + } + switch (refcounts) { + case REFCOUNTS_11: + Py_UNREACHABLE(); + break; + case REFCOUNTS_1X: + if (_Py_IsImmortal(rhs)) { + instr->op.code = BINARY_OP_1I; } - if (PyFloat_CheckExact(lhs)) { - instr->op.code = BINARY_OP_ADD_FLOAT; - goto success; + else { + instr->op.code = BINARY_OP_1X; } break; - case NB_MULTIPLY: - case NB_INPLACE_MULTIPLY: - if (!Py_IS_TYPE(lhs, Py_TYPE(rhs))) { - break; - } - if (PyLong_CheckExact(lhs)) { - instr->op.code = BINARY_OP_MULTIPLY_INT; - goto success; + case REFCOUNTS_X1: + if (_Py_IsImmortal(lhs)) { + instr->op.code = BINARY_OP_I1; } - if (PyFloat_CheckExact(lhs)) { - instr->op.code = BINARY_OP_MULTIPLY_FLOAT; - goto success; + else { + instr->op.code = BINARY_OP_X1; } break; - case NB_SUBTRACT: - case NB_INPLACE_SUBTRACT: - if (!Py_IS_TYPE(lhs, Py_TYPE(rhs))) { - break; - } - if (PyLong_CheckExact(lhs)) { - instr->op.code = BINARY_OP_SUBTRACT_INT; - goto success; + case REFCOUNTS_XX: + if (_Py_IsImmortal(lhs)) { + if (_Py_IsImmortal(rhs)) { + instr->op.code = BINARY_OP_II; + } + else { + instr->op.code = BINARY_OP_IX; + } } - if (PyFloat_CheckExact(lhs)) { - instr->op.code = BINARY_OP_SUBTRACT_FLOAT; - goto success; + else { + if (_Py_IsImmortal(rhs)) { + instr->op.code = BINARY_OP_XI; + } + else { + instr->op.code = BINARY_OP_XX; + } } break; } - SPECIALIZATION_FAIL(BINARY_OP, binary_op_fail_kind(oparg, lhs, rhs)); - STAT_INC(BINARY_OP, failure); - instr->op.code = BINARY_OP; - cache->counter = adaptive_counter_backoff(cache->counter); - return; success: STAT_INC(BINARY_OP, success); cache->counter = adaptive_counter_cooldown(); + cache->type_versions = (func_index << 8) | (left_version << 4) | right_version; } diff --git a/Tools/c-analyzer/cpython/ignored.tsv b/Tools/c-analyzer/cpython/ignored.tsv index a3bdf0396fd3e1..27dd057dd933a0 100644 --- a/Tools/c-analyzer/cpython/ignored.tsv +++ b/Tools/c-analyzer/cpython/ignored.tsv @@ -330,6 +330,7 @@ Objects/obmalloc.c - obmalloc_state_main - Objects/obmalloc.c - obmalloc_state_initialized - Objects/typeobject.c - name_op - Objects/typeobject.c - slotdefs - +Objects/typeobject.c - _Py_PreAllocatedTypes - Objects/unicodeobject.c - stripfuncnames - Objects/unicodeobject.c - utf7_category - Objects/unicodeobject.c unicode_decode_call_errorhandler_wchar argparse - diff --git a/Tools/cases_generator/analyzer.py b/Tools/cases_generator/analyzer.py index e44bebd8f3c4a4..71c3a2b70947c1 100644 --- a/Tools/cases_generator/analyzer.py +++ b/Tools/cases_generator/analyzer.py @@ -407,6 +407,7 @@ def has_error_without_pop(op: parser.InstDef) -> bool: "STAT_INC", "maybe_lltrace_resume_frame", "_PyUnicode_JoinArray", + "Py_REFCNT", "_PyEval_FrameClearAndPop", "_PyFrame_StackPush", "PyCell_New", diff --git a/Tools/cases_generator/generators_common.py b/Tools/cases_generator/generators_common.py index cc9eb8a0e90eeb..6f0302bf4417ca 100644 --- a/Tools/cases_generator/generators_common.py +++ b/Tools/cases_generator/generators_common.py @@ -64,7 +64,7 @@ def replace_deopt( next(tkn_iter) # Semi colon out.emit(", ") assert inst is not None - assert inst.family is not None + assert inst.family is not None, inst.name out.emit(inst.family.name) out.emit(");\n") diff --git a/Tools/cases_generator/parsing.py b/Tools/cases_generator/parsing.py index cc897ff2cbe9aa..6edb16c1204e4c 100644 --- a/Tools/cases_generator/parsing.py +++ b/Tools/cases_generator/parsing.py @@ -351,9 +351,12 @@ def uops(self) -> list[UOp] | None: def uop(self) -> UOp | None: if tkn := self.expect(lx.IDENTIFIER): if self.expect(lx.DIVIDE): + sign = 1 + if negate := self.expect(lx.MINUS): + sign = -1 if num := self.expect(lx.NUMBER): try: - size = int(num.text) + size = sign * int(num.text) except ValueError: raise self.make_syntax_error( f"Expected integer, got {num.text!r}" diff --git a/Tools/scripts/summarize_stats.py b/Tools/scripts/summarize_stats.py index ffbc40e6a37f3d..5cc9b9dd1009c0 100644 --- a/Tools/scripts/summarize_stats.py +++ b/Tools/scripts/summarize_stats.py @@ -557,6 +557,26 @@ def get_rare_events(self) -> list[tuple[str, int]]: if key.startswith(prefix) ] + def get_binary_specialization_failure_stats(self) -> list[tuple[str, int]]: + stats = {} + prefix = "Binary specialization failure" + total = 0 + for key, value in self._data.items(): + if not key.startswith(prefix): + continue + bits, _, rest = key[len(prefix) + 1 :].partition("]") + bits = int(bits) + rtype = bits & 15 + ltype = (bits >> 4) & 15 + kind = (bits >> 8) & 3 + oparg = bits >> 10 + name = f"{oparg} {kind} {ltype} {rtype}" + stats[name] = value + total += int(value) + return [ (key, value) for + (value, key) in + sorted([(value, key) for (key, value) in stats.items()], reverse=True) + ] class JoinMode(enum.Enum): # Join using the first column as a key @@ -774,6 +794,41 @@ def calc_pair_count_table(stats: Stats) -> Rows: """, ) +def binary_failure_section() -> Section: + def calc_binary_failure_table(stats: Stats) -> Rows: + stats = stats.get_binary_specialization_failure_stats() + total = 0 + for (name, count) in stats: + total += int(count) + rows: Rows = [] + for (i, item) in enumerate(stats): + if i == 100: + break; + name, count = item + rows.append( + ( + name, + Count(count), + Ratio(count, total), + ) + ) + return rows + + return Section( + "Binary op specialization failures", + "Binary op specialization failures", + [ + Table( + ("Kind", "Count:", ""), + calc_binary_failure_table, + ) + ], + comparative=False, + doc=""" + Failure counts for binary specialization. + """, + ) + def pre_succ_pairs_section() -> Section: def iter_pre_succ_pairs_tables(base_stats: Stats, head_stats: Stats | None = None): @@ -1302,6 +1357,7 @@ def calc_rows(stats: Stats) -> Rows: gc_stats_section(), optimization_section(), rare_event_section(), + binary_failure_section(), meta_stats_section(), ]