From cb9b02c663121cf89c598e2741fcb901b7731724 Mon Sep 17 00:00:00 2001 From: Sumitha007 Date: Mon, 10 Aug 2026 13:59:44 +0530 Subject: [PATCH 1/2] Specialize list.append for list subclasses --- Include/internal/pycore_opcode_metadata.h | 10 +- Include/internal/pycore_uop_ids.h | 9 +- Include/internal/pycore_uop_metadata.h | 21 ++++ Include/opcode_ids.h | 121 ++++++++++----------- Lib/_opcode_metadata.py | 122 +++++++++++----------- Lib/test/test_opcache.py | 24 ++++- Modules/_testinternalcapi/test_cases.c.h | 96 +++++++++++++++++ Modules/_testinternalcapi/test_targets.h | 9 +- Python/bytecodes.c | 16 +++ Python/executor_cases.c.h | 89 ++++++++++++++++ Python/generated_cases.c.h | 96 +++++++++++++++++ Python/opcode_targets.h | 9 +- Python/optimizer_cases.c.h | 4 + Python/specialize.c | 4 + 14 files changed, 494 insertions(+), 136 deletions(-) diff --git a/Include/internal/pycore_opcode_metadata.h b/Include/internal/pycore_opcode_metadata.h index 457e5c5bf20d2b9..4092776ba1d52ee 100644 --- a/Include/internal/pycore_opcode_metadata.h +++ b/Include/internal/pycore_opcode_metadata.h @@ -132,6 +132,8 @@ int _PyOpcode_num_popped(int opcode, int oparg) { return 3; case CALL_LIST_APPEND: return 3; + case CALL_LIST_APPEND_SUBTYPE: + return 3; case CALL_METHOD_DESCRIPTOR_FAST: return 2 + oparg; case CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS: @@ -627,6 +629,8 @@ int _PyOpcode_num_pushed(int opcode, int oparg) { return 1; case CALL_LIST_APPEND: return 1; + case CALL_LIST_APPEND_SUBTYPE: + return 1; case CALL_METHOD_DESCRIPTOR_FAST: return 1; case CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS: @@ -1147,6 +1151,7 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[267] = { [CALL_KW_PY] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG | HAS_SYNC_SP_FLAG | HAS_NEEDS_GUARD_IP_FLAG | HAS_RECORDS_VALUE_FLAG }, [CALL_LEN] = { true, INSTR_FMT_IXC00, HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, [CALL_LIST_APPEND] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, + [CALL_LIST_APPEND_SUBTYPE] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, [CALL_METHOD_DESCRIPTOR_FAST] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, [CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG | HAS_RECORDS_VALUE_FLAG }, [CALL_METHOD_DESCRIPTOR_NOARGS] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG | HAS_RECORDS_VALUE_FLAG }, @@ -1398,6 +1403,7 @@ _PyOpcode_macro_expansion[256] = { [CALL_KW_PY] = { .nuops = 7, .uops = { { _RECORD_CALLABLE_KW, OPARG_SIMPLE, 0 }, { _CHECK_PEP_523, OPARG_SIMPLE, 1 }, { _CHECK_FUNCTION_VERSION_KW, 2, 1 }, { _CHECK_RECURSION_REMAINING, OPARG_SIMPLE, 3 }, { _PY_FRAME_KW, OPARG_SIMPLE, 3 }, { _SAVE_RETURN_OFFSET, OPARG_SAVE_RETURN_OFFSET, 3 }, { _PUSH_FRAME, OPARG_SIMPLE, 3 } } }, [CALL_LEN] = { .nuops = 5, .uops = { { _GUARD_NOS_NULL, OPARG_SIMPLE, 3 }, { _GUARD_CALLABLE_LEN, OPARG_SIMPLE, 3 }, { _CALL_LEN, OPARG_SIMPLE, 3 }, { _POP_TOP, OPARG_SIMPLE, 3 }, { _POP_TOP, OPARG_SIMPLE, 3 } } }, [CALL_LIST_APPEND] = { .nuops = 6, .uops = { { _GUARD_CALLABLE_LIST_APPEND, OPARG_SIMPLE, 3 }, { _GUARD_NOS_NOT_NULL, OPARG_SIMPLE, 3 }, { _GUARD_NOS_LIST, OPARG_SIMPLE, 3 }, { _CALL_LIST_APPEND, OPARG_SIMPLE, 3 }, { _POP_TOP, OPARG_SIMPLE, 3 }, { _POP_TOP, OPARG_SIMPLE, 3 } } }, + [CALL_LIST_APPEND_SUBTYPE] = { .nuops = 6, .uops = { { _GUARD_CALLABLE_LIST_APPEND, OPARG_SIMPLE, 3 }, { _GUARD_NOS_NOT_NULL, OPARG_SIMPLE, 3 }, { _GUARD_NOS_LIST_SUBTYPE, OPARG_SIMPLE, 3 }, { _CALL_LIST_APPEND, OPARG_SIMPLE, 3 }, { _POP_TOP, OPARG_SIMPLE, 3 }, { _POP_TOP, OPARG_SIMPLE, 3 } } }, [CALL_METHOD_DESCRIPTOR_FAST] = { .nuops = 5, .uops = { { _GUARD_CALLABLE_METHOD_DESCRIPTOR_FAST, OPARG_SIMPLE, 3 }, { _CALL_METHOD_DESCRIPTOR_FAST, OPARG_SIMPLE, 3 }, { _POP_TOP_OPARG, OPARG_SIMPLE, 3 }, { _POP_TOP, OPARG_SIMPLE, 3 }, { _CHECK_PERIODIC_AT_END, OPARG_REPLACED, 3 } } }, [CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS] = { .nuops = 6, .uops = { { _RECORD_CALLABLE, OPARG_SIMPLE, 0 }, { _GUARD_CALLABLE_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS, OPARG_SIMPLE, 3 }, { _CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS, OPARG_SIMPLE, 3 }, { _POP_TOP_OPARG, OPARG_SIMPLE, 3 }, { _POP_TOP, OPARG_SIMPLE, 3 }, { _CHECK_PERIODIC_AT_END, OPARG_REPLACED, 3 } } }, [CALL_METHOD_DESCRIPTOR_NOARGS] = { .nuops = 7, .uops = { { _RECORD_CALLABLE, OPARG_SIMPLE, 0 }, { _GUARD_CALLABLE_METHOD_DESCRIPTOR_NOARGS, OPARG_SIMPLE, 3 }, { _CHECK_RECURSION_LIMIT, OPARG_SIMPLE, 3 }, { _CALL_METHOD_DESCRIPTOR_NOARGS, OPARG_SIMPLE, 3 }, { _POP_TOP, OPARG_SIMPLE, 3 }, { _POP_TOP, OPARG_SIMPLE, 3 }, { _CHECK_PERIODIC_AT_END, OPARG_REPLACED, 3 } } }, @@ -1599,6 +1605,7 @@ const char *_PyOpcode_OpName[267] = { [CALL_KW_PY] = "CALL_KW_PY", [CALL_LEN] = "CALL_LEN", [CALL_LIST_APPEND] = "CALL_LIST_APPEND", + [CALL_LIST_APPEND_SUBTYPE] = "CALL_LIST_APPEND_SUBTYPE", [CALL_METHOD_DESCRIPTOR_FAST] = "CALL_METHOD_DESCRIPTOR_FAST", [CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS] = "CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS", [CALL_METHOD_DESCRIPTOR_NOARGS] = "CALL_METHOD_DESCRIPTOR_NOARGS", @@ -1838,7 +1845,6 @@ const uint8_t _PyOpcode_Deopt[256] = { [125] = 125, [126] = 126, [127] = 127, - [219] = 219, [220] = 220, [221] = 221, [222] = 222, @@ -1899,6 +1905,7 @@ const uint8_t _PyOpcode_Deopt[256] = { [CALL_KW_PY] = CALL_KW, [CALL_LEN] = CALL, [CALL_LIST_APPEND] = CALL, + [CALL_LIST_APPEND_SUBTYPE] = CALL, [CALL_METHOD_DESCRIPTOR_FAST] = CALL, [CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS] = CALL, [CALL_METHOD_DESCRIPTOR_NOARGS] = CALL, @@ -2099,7 +2106,6 @@ const uint8_t _PyOpcode_Deopt[256] = { case 125: \ case 126: \ case 127: \ - case 219: \ case 220: \ case 221: \ case 222: \ diff --git a/Include/internal/pycore_uop_ids.h b/Include/internal/pycore_uop_ids.h index 97f934727a85a36..3af99717b212b2e 100644 --- a/Include/internal/pycore_uop_ids.h +++ b/Include/internal/pycore_uop_ids.h @@ -180,6 +180,7 @@ enum { _GUARD_NOS_INT, _GUARD_NOS_ITER_VIRTUAL, _GUARD_NOS_LIST, + _GUARD_NOS_LIST_SUBTYPE, _GUARD_NOS_NOT_NULL, _GUARD_NOS_NULL, _GUARD_NOS_OVERFLOWED, @@ -364,7 +365,7 @@ enum { _UNPACK_SEQUENCE_UNIQUE_TWO_TUPLE, _YIELD_VALUE, }; -#define MAX_UOP_ID 652 +#define MAX_UOP_ID 653 #define _BUILD_INTERPOLATION BUILD_INTERPOLATION #define _BUILD_LIST BUILD_LIST @@ -874,6 +875,10 @@ enum { _GUARD_NOS_LIST_r12, _GUARD_NOS_LIST_r22, _GUARD_NOS_LIST_r33, + _GUARD_NOS_LIST_SUBTYPE_r02, + _GUARD_NOS_LIST_SUBTYPE_r12, + _GUARD_NOS_LIST_SUBTYPE_r22, + _GUARD_NOS_LIST_SUBTYPE_r33, _GUARD_NOS_NOT_NULL_r02, _GUARD_NOS_NOT_NULL_r12, _GUARD_NOS_NOT_NULL_r22, @@ -1434,7 +1439,7 @@ enum { _WITH_EXCEPT_START_r33, _YIELD_VALUE_r11, }; -#define MAX_UOP_REGS_ID 1645 +#define MAX_UOP_REGS_ID 1650 #ifdef __cplusplus } diff --git a/Include/internal/pycore_uop_metadata.h b/Include/internal/pycore_uop_metadata.h index e52233b21277591..a4e25ffe40fbcc6 100644 --- a/Include/internal/pycore_uop_metadata.h +++ b/Include/internal/pycore_uop_metadata.h @@ -91,6 +91,7 @@ const uint32_t _PyUop_Flags[MAX_UOP_ID+1] = { [_TO_BOOL_BOOL] = HAS_EXIT_FLAG, [_TO_BOOL_INT] = 0, [_GUARD_NOS_LIST] = HAS_EXIT_FLAG, + [_GUARD_NOS_LIST_SUBTYPE] = HAS_EXIT_FLAG, [_GUARD_TOS_LIST] = HAS_EXIT_FLAG, [_GUARD_TOS_SLICE] = HAS_EXIT_FLAG, [_TO_BOOL_LIST] = 0, @@ -948,6 +949,15 @@ const _PyUopCachingInfo _PyUop_Caching[MAX_UOP_ID+1] = { { 3, 3, _GUARD_NOS_LIST_r33 }, }, }, + [_GUARD_NOS_LIST_SUBTYPE] = { + .best = { 0, 1, 2, 3 }, + .entries = { + { 2, 0, _GUARD_NOS_LIST_SUBTYPE_r02 }, + { 2, 1, _GUARD_NOS_LIST_SUBTYPE_r12 }, + { 2, 2, _GUARD_NOS_LIST_SUBTYPE_r22 }, + { 3, 3, _GUARD_NOS_LIST_SUBTYPE_r33 }, + }, + }, [_GUARD_TOS_LIST] = { .best = { 0, 1, 2, 3 }, .entries = { @@ -4053,6 +4063,10 @@ const uint16_t _PyUop_Uncached[MAX_UOP_REGS_ID+1] = { [_GUARD_NOS_LIST_r12] = _GUARD_NOS_LIST, [_GUARD_NOS_LIST_r22] = _GUARD_NOS_LIST, [_GUARD_NOS_LIST_r33] = _GUARD_NOS_LIST, + [_GUARD_NOS_LIST_SUBTYPE_r02] = _GUARD_NOS_LIST_SUBTYPE, + [_GUARD_NOS_LIST_SUBTYPE_r12] = _GUARD_NOS_LIST_SUBTYPE, + [_GUARD_NOS_LIST_SUBTYPE_r22] = _GUARD_NOS_LIST_SUBTYPE, + [_GUARD_NOS_LIST_SUBTYPE_r33] = _GUARD_NOS_LIST_SUBTYPE, [_GUARD_TOS_LIST_r01] = _GUARD_TOS_LIST, [_GUARD_TOS_LIST_r11] = _GUARD_TOS_LIST, [_GUARD_TOS_LIST_r22] = _GUARD_TOS_LIST, @@ -5441,6 +5455,11 @@ const char *const _PyOpcode_uop_name[MAX_UOP_REGS_ID+1] = { [_GUARD_NOS_LIST_r12] = "_GUARD_NOS_LIST_r12", [_GUARD_NOS_LIST_r22] = "_GUARD_NOS_LIST_r22", [_GUARD_NOS_LIST_r33] = "_GUARD_NOS_LIST_r33", + [_GUARD_NOS_LIST_SUBTYPE] = "_GUARD_NOS_LIST_SUBTYPE", + [_GUARD_NOS_LIST_SUBTYPE_r02] = "_GUARD_NOS_LIST_SUBTYPE_r02", + [_GUARD_NOS_LIST_SUBTYPE_r12] = "_GUARD_NOS_LIST_SUBTYPE_r12", + [_GUARD_NOS_LIST_SUBTYPE_r22] = "_GUARD_NOS_LIST_SUBTYPE_r22", + [_GUARD_NOS_LIST_SUBTYPE_r33] = "_GUARD_NOS_LIST_SUBTYPE_r33", [_GUARD_NOS_NOT_NULL] = "_GUARD_NOS_NOT_NULL", [_GUARD_NOS_NOT_NULL_r02] = "_GUARD_NOS_NOT_NULL_r02", [_GUARD_NOS_NOT_NULL_r12] = "_GUARD_NOS_NOT_NULL_r12", @@ -6259,6 +6278,8 @@ int _PyUop_num_popped(int opcode, int oparg) return 1; case _GUARD_NOS_LIST: return 0; + case _GUARD_NOS_LIST_SUBTYPE: + return 0; case _GUARD_TOS_LIST: return 0; case _GUARD_TOS_SLICE: diff --git a/Include/opcode_ids.h b/Include/opcode_ids.h index 11342ae451b9f6c..a6697fe82fb10ed 100644 --- a/Include/opcode_ids.h +++ b/Include/opcode_ids.h @@ -158,66 +158,67 @@ extern "C" { #define CALL_KW_PY 156 #define CALL_LEN 157 #define CALL_LIST_APPEND 158 -#define CALL_METHOD_DESCRIPTOR_FAST 159 -#define CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS 160 -#define CALL_METHOD_DESCRIPTOR_NOARGS 161 -#define CALL_METHOD_DESCRIPTOR_O 162 -#define CALL_NON_PY_GENERAL 163 -#define CALL_PY_EXACT_ARGS 164 -#define CALL_PY_GENERAL 165 -#define CALL_STR_1 166 -#define CALL_TUPLE_1 167 -#define CALL_TYPE_1 168 -#define COMPARE_OP_FLOAT 169 -#define COMPARE_OP_INT 170 -#define COMPARE_OP_STR 171 -#define CONTAINS_OP_DICT 172 -#define CONTAINS_OP_SET 173 -#define FOR_ITER_GEN 174 -#define FOR_ITER_LIST 175 -#define FOR_ITER_RANGE 176 -#define FOR_ITER_TUPLE 177 -#define FOR_ITER_VIRTUAL 178 -#define GET_ITER_SELF 179 -#define GET_ITER_VIRTUAL 180 -#define JUMP_BACKWARD_JIT 181 -#define JUMP_BACKWARD_NO_JIT 182 -#define LOAD_ATTR_CLASS 183 -#define LOAD_ATTR_CLASS_WITH_METACLASS_CHECK 184 -#define LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN 185 -#define LOAD_ATTR_INSTANCE_VALUE 186 -#define LOAD_ATTR_METHOD_LAZY_DICT 187 -#define LOAD_ATTR_METHOD_NO_DICT 188 -#define LOAD_ATTR_METHOD_WITH_VALUES 189 -#define LOAD_ATTR_MODULE 190 -#define LOAD_ATTR_NONDESCRIPTOR_NO_DICT 191 -#define LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES 192 -#define LOAD_ATTR_PROPERTY 193 -#define LOAD_ATTR_SLOT 194 -#define LOAD_ATTR_WITH_HINT 195 -#define LOAD_GLOBAL_BUILTIN 196 -#define LOAD_GLOBAL_MODULE 197 -#define LOAD_SUPER_ATTR_ATTR 198 -#define LOAD_SUPER_ATTR_METHOD 199 -#define RESUME_CHECK 200 -#define RESUME_CHECK_JIT 201 -#define SEND_ASYNC_GEN 202 -#define SEND_GEN 203 -#define SEND_VIRTUAL 204 -#define STORE_ATTR_INSTANCE_VALUE 205 -#define STORE_ATTR_SLOT 206 -#define STORE_ATTR_WITH_HINT 207 -#define STORE_SUBSCR_DICT 208 -#define STORE_SUBSCR_LIST_INT 209 -#define TO_BOOL_ALWAYS_TRUE 210 -#define TO_BOOL_BOOL 211 -#define TO_BOOL_INT 212 -#define TO_BOOL_LIST 213 -#define TO_BOOL_NONE 214 -#define TO_BOOL_STR 215 -#define UNPACK_SEQUENCE_LIST 216 -#define UNPACK_SEQUENCE_TUPLE 217 -#define UNPACK_SEQUENCE_TWO_TUPLE 218 +#define CALL_LIST_APPEND_SUBTYPE 159 +#define CALL_METHOD_DESCRIPTOR_FAST 160 +#define CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS 161 +#define CALL_METHOD_DESCRIPTOR_NOARGS 162 +#define CALL_METHOD_DESCRIPTOR_O 163 +#define CALL_NON_PY_GENERAL 164 +#define CALL_PY_EXACT_ARGS 165 +#define CALL_PY_GENERAL 166 +#define CALL_STR_1 167 +#define CALL_TUPLE_1 168 +#define CALL_TYPE_1 169 +#define COMPARE_OP_FLOAT 170 +#define COMPARE_OP_INT 171 +#define COMPARE_OP_STR 172 +#define CONTAINS_OP_DICT 173 +#define CONTAINS_OP_SET 174 +#define FOR_ITER_GEN 175 +#define FOR_ITER_LIST 176 +#define FOR_ITER_RANGE 177 +#define FOR_ITER_TUPLE 178 +#define FOR_ITER_VIRTUAL 179 +#define GET_ITER_SELF 180 +#define GET_ITER_VIRTUAL 181 +#define JUMP_BACKWARD_JIT 182 +#define JUMP_BACKWARD_NO_JIT 183 +#define LOAD_ATTR_CLASS 184 +#define LOAD_ATTR_CLASS_WITH_METACLASS_CHECK 185 +#define LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN 186 +#define LOAD_ATTR_INSTANCE_VALUE 187 +#define LOAD_ATTR_METHOD_LAZY_DICT 188 +#define LOAD_ATTR_METHOD_NO_DICT 189 +#define LOAD_ATTR_METHOD_WITH_VALUES 190 +#define LOAD_ATTR_MODULE 191 +#define LOAD_ATTR_NONDESCRIPTOR_NO_DICT 192 +#define LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES 193 +#define LOAD_ATTR_PROPERTY 194 +#define LOAD_ATTR_SLOT 195 +#define LOAD_ATTR_WITH_HINT 196 +#define LOAD_GLOBAL_BUILTIN 197 +#define LOAD_GLOBAL_MODULE 198 +#define LOAD_SUPER_ATTR_ATTR 199 +#define LOAD_SUPER_ATTR_METHOD 200 +#define RESUME_CHECK 201 +#define RESUME_CHECK_JIT 202 +#define SEND_ASYNC_GEN 203 +#define SEND_GEN 204 +#define SEND_VIRTUAL 205 +#define STORE_ATTR_INSTANCE_VALUE 206 +#define STORE_ATTR_SLOT 207 +#define STORE_ATTR_WITH_HINT 208 +#define STORE_SUBSCR_DICT 209 +#define STORE_SUBSCR_LIST_INT 210 +#define TO_BOOL_ALWAYS_TRUE 211 +#define TO_BOOL_BOOL 212 +#define TO_BOOL_INT 213 +#define TO_BOOL_LIST 214 +#define TO_BOOL_NONE 215 +#define TO_BOOL_STR 216 +#define UNPACK_SEQUENCE_LIST 217 +#define UNPACK_SEQUENCE_TUPLE 218 +#define UNPACK_SEQUENCE_TWO_TUPLE 219 #define INSTRUMENTED_END_FOR 233 #define INSTRUMENTED_POP_ITER 234 #define INSTRUMENTED_END_SEND 235 diff --git a/Lib/_opcode_metadata.py b/Lib/_opcode_metadata.py index df92eae151d2488..4267236d7a0e4e3 100644 --- a/Lib/_opcode_metadata.py +++ b/Lib/_opcode_metadata.py @@ -112,6 +112,7 @@ "CALL_LEN", "CALL_ISINSTANCE", "CALL_LIST_APPEND", + "CALL_LIST_APPEND_SUBTYPE", "CALL_METHOD_DESCRIPTOR_O", "CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS", "CALL_METHOD_DESCRIPTOR_NOARGS", @@ -164,66 +165,67 @@ CALL_KW_PY=156, CALL_LEN=157, CALL_LIST_APPEND=158, - CALL_METHOD_DESCRIPTOR_FAST=159, - CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS=160, - CALL_METHOD_DESCRIPTOR_NOARGS=161, - CALL_METHOD_DESCRIPTOR_O=162, - CALL_NON_PY_GENERAL=163, - CALL_PY_EXACT_ARGS=164, - CALL_PY_GENERAL=165, - CALL_STR_1=166, - CALL_TUPLE_1=167, - CALL_TYPE_1=168, - COMPARE_OP_FLOAT=169, - COMPARE_OP_INT=170, - COMPARE_OP_STR=171, - CONTAINS_OP_DICT=172, - CONTAINS_OP_SET=173, - FOR_ITER_GEN=174, - FOR_ITER_LIST=175, - FOR_ITER_RANGE=176, - FOR_ITER_TUPLE=177, - FOR_ITER_VIRTUAL=178, - GET_ITER_SELF=179, - GET_ITER_VIRTUAL=180, - JUMP_BACKWARD_JIT=181, - JUMP_BACKWARD_NO_JIT=182, - LOAD_ATTR_CLASS=183, - LOAD_ATTR_CLASS_WITH_METACLASS_CHECK=184, - LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN=185, - LOAD_ATTR_INSTANCE_VALUE=186, - LOAD_ATTR_METHOD_LAZY_DICT=187, - LOAD_ATTR_METHOD_NO_DICT=188, - LOAD_ATTR_METHOD_WITH_VALUES=189, - LOAD_ATTR_MODULE=190, - LOAD_ATTR_NONDESCRIPTOR_NO_DICT=191, - LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES=192, - LOAD_ATTR_PROPERTY=193, - LOAD_ATTR_SLOT=194, - LOAD_ATTR_WITH_HINT=195, - LOAD_GLOBAL_BUILTIN=196, - LOAD_GLOBAL_MODULE=197, - LOAD_SUPER_ATTR_ATTR=198, - LOAD_SUPER_ATTR_METHOD=199, - RESUME_CHECK=200, - RESUME_CHECK_JIT=201, - SEND_ASYNC_GEN=202, - SEND_GEN=203, - SEND_VIRTUAL=204, - STORE_ATTR_INSTANCE_VALUE=205, - STORE_ATTR_SLOT=206, - STORE_ATTR_WITH_HINT=207, - STORE_SUBSCR_DICT=208, - STORE_SUBSCR_LIST_INT=209, - TO_BOOL_ALWAYS_TRUE=210, - TO_BOOL_BOOL=211, - TO_BOOL_INT=212, - TO_BOOL_LIST=213, - TO_BOOL_NONE=214, - TO_BOOL_STR=215, - UNPACK_SEQUENCE_LIST=216, - UNPACK_SEQUENCE_TUPLE=217, - UNPACK_SEQUENCE_TWO_TUPLE=218, + CALL_LIST_APPEND_SUBTYPE=159, + CALL_METHOD_DESCRIPTOR_FAST=160, + CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS=161, + CALL_METHOD_DESCRIPTOR_NOARGS=162, + CALL_METHOD_DESCRIPTOR_O=163, + CALL_NON_PY_GENERAL=164, + CALL_PY_EXACT_ARGS=165, + CALL_PY_GENERAL=166, + CALL_STR_1=167, + CALL_TUPLE_1=168, + CALL_TYPE_1=169, + COMPARE_OP_FLOAT=170, + COMPARE_OP_INT=171, + COMPARE_OP_STR=172, + CONTAINS_OP_DICT=173, + CONTAINS_OP_SET=174, + FOR_ITER_GEN=175, + FOR_ITER_LIST=176, + FOR_ITER_RANGE=177, + FOR_ITER_TUPLE=178, + FOR_ITER_VIRTUAL=179, + GET_ITER_SELF=180, + GET_ITER_VIRTUAL=181, + JUMP_BACKWARD_JIT=182, + JUMP_BACKWARD_NO_JIT=183, + LOAD_ATTR_CLASS=184, + LOAD_ATTR_CLASS_WITH_METACLASS_CHECK=185, + LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN=186, + LOAD_ATTR_INSTANCE_VALUE=187, + LOAD_ATTR_METHOD_LAZY_DICT=188, + LOAD_ATTR_METHOD_NO_DICT=189, + LOAD_ATTR_METHOD_WITH_VALUES=190, + LOAD_ATTR_MODULE=191, + LOAD_ATTR_NONDESCRIPTOR_NO_DICT=192, + LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES=193, + LOAD_ATTR_PROPERTY=194, + LOAD_ATTR_SLOT=195, + LOAD_ATTR_WITH_HINT=196, + LOAD_GLOBAL_BUILTIN=197, + LOAD_GLOBAL_MODULE=198, + LOAD_SUPER_ATTR_ATTR=199, + LOAD_SUPER_ATTR_METHOD=200, + RESUME_CHECK=201, + RESUME_CHECK_JIT=202, + SEND_ASYNC_GEN=203, + SEND_GEN=204, + SEND_VIRTUAL=205, + STORE_ATTR_INSTANCE_VALUE=206, + STORE_ATTR_SLOT=207, + STORE_ATTR_WITH_HINT=208, + STORE_SUBSCR_DICT=209, + STORE_SUBSCR_LIST_INT=210, + TO_BOOL_ALWAYS_TRUE=211, + TO_BOOL_BOOL=212, + TO_BOOL_INT=213, + TO_BOOL_LIST=214, + TO_BOOL_NONE=215, + TO_BOOL_STR=216, + UNPACK_SEQUENCE_LIST=217, + UNPACK_SEQUENCE_TUPLE=218, + UNPACK_SEQUENCE_TWO_TUPLE=219, ) opmap = frozendict( diff --git a/Lib/test/test_opcache.py b/Lib/test/test_opcache.py index 7946550ec0db637..9a14c984557b9d5 100644 --- a/Lib/test/test_opcache.py +++ b/Lib/test/test_opcache.py @@ -2147,8 +2147,8 @@ def get_iter_gen(): @cpython_only @requires_specialization def test_call_list_append(self): - # gh-141367: only exact lists should use - # CALL_LIST_APPEND instruction after specialization. + # gh-141367: list subclasses that inherit list.append + # should use the list append specialization. r = range(_testinternalcapi.SPECIALIZATION_THRESHOLD) @@ -2167,9 +2167,25 @@ def my_list_append(l): class MyList(list): pass my_list_append(MyList()) - self.assert_specialized(my_list_append, "CALL_METHOD_DESCRIPTOR_O") - self.assert_no_opcode(my_list_append, "CALL_LIST_APPEND") + self.assert_specialized(my_list_append, "CALL_LIST_APPEND_SUBTYPE") + self.assert_no_opcode(my_list_append, "CALL_METHOD_DESCRIPTOR_O") self.assert_no_opcode(my_list_append, "CALL") + class MyListOverride(list): + def append(self, value): + self.append_called = True + super().append(value) + + def my_list_override_append(l): + for _ in r: + l.append(1) + + obj = MyListOverride() + my_list_override_append(obj) + self.assertTrue(obj.append_called) + self.assert_no_opcode( + my_list_override_append, "CALL_LIST_APPEND_SUBTYPE" + ) + @cpython_only @requires_specialization diff --git a/Modules/_testinternalcapi/test_cases.c.h b/Modules/_testinternalcapi/test_cases.c.h index a17648a33d4fe4a..074733d62fffffe 100644 --- a/Modules/_testinternalcapi/test_cases.c.h +++ b/Modules/_testinternalcapi/test_cases.c.h @@ -4012,6 +4012,102 @@ DISPATCH(); } + TARGET(CALL_LIST_APPEND_SUBTYPE) { + #if _Py_TAIL_CALL_INTERP + int opcode = CALL_LIST_APPEND_SUBTYPE; + (void)(opcode); + #endif + _Py_CODEUNIT* const this_instr = next_instr; + (void)this_instr; + frame->instr_ptr = next_instr; + next_instr += 4; + INSTRUCTION_STATS(CALL_LIST_APPEND_SUBTYPE); + static_assert(INLINE_CACHE_ENTRIES_CALL == 3, "incorrect cache size"); + _PyStackRef callable; + _PyStackRef nos; + _PyStackRef self; + _PyStackRef arg; + _PyStackRef none; + _PyStackRef c; + _PyStackRef s; + _PyStackRef value; + /* Skip 1 cache entry */ + /* Skip 2 cache entries */ + // _GUARD_CALLABLE_LIST_APPEND + { + callable = stack_pointer[-3]; + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + PyInterpreterState *interp = tstate->interp; + if (callable_o != interp->callable_cache.list_append) { + UPDATE_MISS_STATS(CALL); + assert(_PyOpcode_Deopt[opcode] == (CALL)); + JUMP_TO_PREDICTED(CALL); + } + } + // _GUARD_NOS_NOT_NULL + { + nos = stack_pointer[-2]; + if (PyStackRef_IsNull(nos)) { + UPDATE_MISS_STATS(CALL); + assert(_PyOpcode_Deopt[opcode] == (CALL)); + JUMP_TO_PREDICTED(CALL); + } + } + // _GUARD_NOS_LIST_SUBTYPE + { + PyObject *o = PyStackRef_AsPyObjectBorrow(nos); + if (!PyList_Check(o)) { + UPDATE_MISS_STATS(CALL); + assert(_PyOpcode_Deopt[opcode] == (CALL)); + JUMP_TO_PREDICTED(CALL); + } + } + // _CALL_LIST_APPEND + { + arg = stack_pointer[-1]; + self = nos; + assert(oparg == 1); + PyObject *self_o = PyStackRef_AsPyObjectBorrow(self); + if (!LOCK_OBJECT(self_o)) { + UPDATE_MISS_STATS(CALL); + assert(_PyOpcode_Deopt[opcode] == (CALL)); + JUMP_TO_PREDICTED(CALL); + } + STAT_INC(CALL, hit); + int err = _PyList_AppendTakeRef((PyListObject *)self_o, PyStackRef_AsPyObjectSteal(arg)); + UNLOCK_OBJECT(self_o); + if (err) { + JUMP_TO_LABEL(error); + } + c = callable; + s = self; + none = PyStackRef_None; + } + // _POP_TOP + { + value = s; + stack_pointer[-3] = none; + stack_pointer[-2] = c; + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + _PyFrame_SetStackPointer(frame, stack_pointer); + _PyFrame_StackPointerValidate(frame); + PyStackRef_XCLOSE(value); + _PyFrame_StackPointerInvalidate(frame); + } + // _POP_TOP + { + value = c; + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + _PyFrame_SetStackPointer(frame, stack_pointer); + _PyFrame_StackPointerValidate(frame); + PyStackRef_XCLOSE(value); + _PyFrame_StackPointerInvalidate(frame); + } + DISPATCH(); + } + TARGET(CALL_METHOD_DESCRIPTOR_FAST) { #if _Py_TAIL_CALL_INTERP int opcode = CALL_METHOD_DESCRIPTOR_FAST; diff --git a/Modules/_testinternalcapi/test_targets.h b/Modules/_testinternalcapi/test_targets.h index 91b424773224e4b..53e004c5c619b15 100644 --- a/Modules/_testinternalcapi/test_targets.h +++ b/Modules/_testinternalcapi/test_targets.h @@ -159,6 +159,7 @@ static void *opcode_targets_table[256] = { &&TARGET_CALL_KW_PY, &&TARGET_CALL_LEN, &&TARGET_CALL_LIST_APPEND, + &&TARGET_CALL_LIST_APPEND_SUBTYPE, &&TARGET_CALL_METHOD_DESCRIPTOR_FAST, &&TARGET_CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS, &&TARGET_CALL_METHOD_DESCRIPTOR_NOARGS, @@ -232,7 +233,6 @@ static void *opcode_targets_table[256] = { &&_unknown_opcode, &&_unknown_opcode, &&_unknown_opcode, - &&_unknown_opcode, &&TARGET_INSTRUMENTED_END_FOR, &&TARGET_INSTRUMENTED_POP_ITER, &&TARGET_INSTRUMENTED_END_SEND, @@ -478,7 +478,7 @@ static void *opcode_tracing_targets_table[256] = { &&TARGET_TRACE_RECORD, &&TARGET_TRACE_RECORD, &&TARGET_TRACE_RECORD, - &&_unknown_opcode, + &&TARGET_TRACE_RECORD, &&_unknown_opcode, &&_unknown_opcode, &&_unknown_opcode, @@ -578,6 +578,7 @@ static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_CALL_KW_NON_PY(TAIL_CALL_PARAMS) static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_CALL_KW_PY(TAIL_CALL_PARAMS); static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_CALL_LEN(TAIL_CALL_PARAMS); static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_CALL_LIST_APPEND(TAIL_CALL_PARAMS); +static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_CALL_LIST_APPEND_SUBTYPE(TAIL_CALL_PARAMS); static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_CALL_METHOD_DESCRIPTOR_FAST(TAIL_CALL_PARAMS); static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS(TAIL_CALL_PARAMS); static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_CALL_METHOD_DESCRIPTOR_NOARGS(TAIL_CALL_PARAMS); @@ -821,6 +822,7 @@ static py_tail_call_funcptr instruction_funcptr_handler_table[256] = { [CALL_KW_PY] = _TAIL_CALL_CALL_KW_PY, [CALL_LEN] = _TAIL_CALL_CALL_LEN, [CALL_LIST_APPEND] = _TAIL_CALL_CALL_LIST_APPEND, + [CALL_LIST_APPEND_SUBTYPE] = _TAIL_CALL_CALL_LIST_APPEND_SUBTYPE, [CALL_METHOD_DESCRIPTOR_FAST] = _TAIL_CALL_CALL_METHOD_DESCRIPTOR_FAST, [CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS] = _TAIL_CALL_CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS, [CALL_METHOD_DESCRIPTOR_NOARGS] = _TAIL_CALL_CALL_METHOD_DESCRIPTOR_NOARGS, @@ -1016,7 +1018,6 @@ static py_tail_call_funcptr instruction_funcptr_handler_table[256] = { [125] = _TAIL_CALL_UNKNOWN_OPCODE, [126] = _TAIL_CALL_UNKNOWN_OPCODE, [127] = _TAIL_CALL_UNKNOWN_OPCODE, - [219] = _TAIL_CALL_UNKNOWN_OPCODE, [220] = _TAIL_CALL_UNKNOWN_OPCODE, [221] = _TAIL_CALL_UNKNOWN_OPCODE, [222] = _TAIL_CALL_UNKNOWN_OPCODE, @@ -1079,6 +1080,7 @@ static py_tail_call_funcptr instruction_funcptr_tracing_table[256] = { [CALL_KW_PY] = _TAIL_CALL_TRACE_RECORD, [CALL_LEN] = _TAIL_CALL_TRACE_RECORD, [CALL_LIST_APPEND] = _TAIL_CALL_TRACE_RECORD, + [CALL_LIST_APPEND_SUBTYPE] = _TAIL_CALL_TRACE_RECORD, [CALL_METHOD_DESCRIPTOR_FAST] = _TAIL_CALL_TRACE_RECORD, [CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS] = _TAIL_CALL_TRACE_RECORD, [CALL_METHOD_DESCRIPTOR_NOARGS] = _TAIL_CALL_TRACE_RECORD, @@ -1274,7 +1276,6 @@ static py_tail_call_funcptr instruction_funcptr_tracing_table[256] = { [125] = _TAIL_CALL_UNKNOWN_OPCODE, [126] = _TAIL_CALL_UNKNOWN_OPCODE, [127] = _TAIL_CALL_UNKNOWN_OPCODE, - [219] = _TAIL_CALL_UNKNOWN_OPCODE, [220] = _TAIL_CALL_UNKNOWN_OPCODE, [221] = _TAIL_CALL_UNKNOWN_OPCODE, [222] = _TAIL_CALL_UNKNOWN_OPCODE, diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 4d7b338e2dbd4c3..9b5fed2040288dc 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -533,6 +533,11 @@ dummy_func( EXIT_IF(!PyList_CheckExact(o)); } + op(_GUARD_NOS_LIST_SUBTYPE, (nos, unused -- nos, unused)) { + PyObject *o = PyStackRef_AsPyObjectBorrow(nos); + EXIT_IF(!PyList_Check(o)); + } + op(_GUARD_TOS_LIST, (tos -- tos)) { PyObject *o = PyStackRef_AsPyObjectBorrow(tos); EXIT_IF(!PyList_CheckExact(o)); @@ -4340,6 +4345,7 @@ dummy_func( CALL_LEN, CALL_ISINSTANCE, CALL_LIST_APPEND, + CALL_LIST_APPEND_SUBTYPE, CALL_METHOD_DESCRIPTOR_O, CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS, CALL_METHOD_DESCRIPTOR_NOARGS, @@ -5054,6 +5060,16 @@ dummy_func( POP_TOP + POP_TOP; + macro(CALL_LIST_APPEND_SUBTYPE) = + unused/1 + + unused/2 + + _GUARD_CALLABLE_LIST_APPEND + + _GUARD_NOS_NOT_NULL + + _GUARD_NOS_LIST_SUBTYPE + + _CALL_LIST_APPEND + + POP_TOP + + POP_TOP; + op(_GUARD_CALLABLE_LIST_APPEND, (callable, unused, unused -- callable, unused, unused)){ PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); PyInterpreterState *interp = tstate->interp; diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index e45bbd7cceb295f..205b759c6f9fb37 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -3075,6 +3075,95 @@ break; } + case _GUARD_NOS_LIST_SUBTYPE_r02: { + CHECK_CURRENT_CACHED_VALUES(0); + ASSERT_WITHIN_STACK_BOUNDS_IGNORING_CACHE(__FILE__, __LINE__); + _PyStackRef nos; + nos = stack_pointer[-2]; + PyObject *o = PyStackRef_AsPyObjectBorrow(nos); + if (!PyList_Check(o)) { + UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache1 = stack_pointer[-1]; + _tos_cache0 = nos; + SET_CURRENT_CACHED_VALUES(2); + stack_pointer += -2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + ASSERT_WITHIN_STACK_BOUNDS_IGNORING_CACHE(__FILE__, __LINE__); + break; + } + + case _GUARD_NOS_LIST_SUBTYPE_r12: { + CHECK_CURRENT_CACHED_VALUES(1); + ASSERT_WITHIN_STACK_BOUNDS_IGNORING_CACHE(__FILE__, __LINE__); + _PyStackRef nos; + _PyStackRef _stack_item_0 = _tos_cache0; + nos = stack_pointer[-1]; + PyObject *o = PyStackRef_AsPyObjectBorrow(nos); + if (!PyList_Check(o)) { + UOP_STAT_INC(uopcode, miss); + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(1); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache1 = _stack_item_0; + _tos_cache0 = nos; + SET_CURRENT_CACHED_VALUES(2); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + ASSERT_WITHIN_STACK_BOUNDS_IGNORING_CACHE(__FILE__, __LINE__); + break; + } + + case _GUARD_NOS_LIST_SUBTYPE_r22: { + CHECK_CURRENT_CACHED_VALUES(2); + ASSERT_WITHIN_STACK_BOUNDS_IGNORING_CACHE(__FILE__, __LINE__); + _PyStackRef nos; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + nos = _stack_item_0; + PyObject *o = PyStackRef_AsPyObjectBorrow(nos); + if (!PyList_Check(o)) { + UOP_STAT_INC(uopcode, miss); + _tos_cache1 = _stack_item_1; + _tos_cache0 = nos; + SET_CURRENT_CACHED_VALUES(2); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache1 = _stack_item_1; + _tos_cache0 = nos; + SET_CURRENT_CACHED_VALUES(2); + ASSERT_WITHIN_STACK_BOUNDS_IGNORING_CACHE(__FILE__, __LINE__); + break; + } + + case _GUARD_NOS_LIST_SUBTYPE_r33: { + CHECK_CURRENT_CACHED_VALUES(3); + ASSERT_WITHIN_STACK_BOUNDS_IGNORING_CACHE(__FILE__, __LINE__); + _PyStackRef nos; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + _PyStackRef _stack_item_2 = _tos_cache2; + nos = _stack_item_1; + PyObject *o = PyStackRef_AsPyObjectBorrow(nos); + if (!PyList_Check(o)) { + UOP_STAT_INC(uopcode, miss); + _tos_cache2 = _stack_item_2; + _tos_cache1 = nos; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache2 = _stack_item_2; + _tos_cache1 = nos; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + ASSERT_WITHIN_STACK_BOUNDS_IGNORING_CACHE(__FILE__, __LINE__); + break; + } + case _GUARD_TOS_LIST_r01: { CHECK_CURRENT_CACHED_VALUES(0); ASSERT_WITHIN_STACK_BOUNDS_IGNORING_CACHE(__FILE__, __LINE__); diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 6178dc70c1b80e7..3fca017e8d4e89f 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -4012,6 +4012,102 @@ DISPATCH(); } + TARGET(CALL_LIST_APPEND_SUBTYPE) { + #if _Py_TAIL_CALL_INTERP + int opcode = CALL_LIST_APPEND_SUBTYPE; + (void)(opcode); + #endif + _Py_CODEUNIT* const this_instr = next_instr; + (void)this_instr; + frame->instr_ptr = next_instr; + next_instr += 4; + INSTRUCTION_STATS(CALL_LIST_APPEND_SUBTYPE); + static_assert(INLINE_CACHE_ENTRIES_CALL == 3, "incorrect cache size"); + _PyStackRef callable; + _PyStackRef nos; + _PyStackRef self; + _PyStackRef arg; + _PyStackRef none; + _PyStackRef c; + _PyStackRef s; + _PyStackRef value; + /* Skip 1 cache entry */ + /* Skip 2 cache entries */ + // _GUARD_CALLABLE_LIST_APPEND + { + callable = stack_pointer[-3]; + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + PyInterpreterState *interp = tstate->interp; + if (callable_o != interp->callable_cache.list_append) { + UPDATE_MISS_STATS(CALL); + assert(_PyOpcode_Deopt[opcode] == (CALL)); + JUMP_TO_PREDICTED(CALL); + } + } + // _GUARD_NOS_NOT_NULL + { + nos = stack_pointer[-2]; + if (PyStackRef_IsNull(nos)) { + UPDATE_MISS_STATS(CALL); + assert(_PyOpcode_Deopt[opcode] == (CALL)); + JUMP_TO_PREDICTED(CALL); + } + } + // _GUARD_NOS_LIST_SUBTYPE + { + PyObject *o = PyStackRef_AsPyObjectBorrow(nos); + if (!PyList_Check(o)) { + UPDATE_MISS_STATS(CALL); + assert(_PyOpcode_Deopt[opcode] == (CALL)); + JUMP_TO_PREDICTED(CALL); + } + } + // _CALL_LIST_APPEND + { + arg = stack_pointer[-1]; + self = nos; + assert(oparg == 1); + PyObject *self_o = PyStackRef_AsPyObjectBorrow(self); + if (!LOCK_OBJECT(self_o)) { + UPDATE_MISS_STATS(CALL); + assert(_PyOpcode_Deopt[opcode] == (CALL)); + JUMP_TO_PREDICTED(CALL); + } + STAT_INC(CALL, hit); + int err = _PyList_AppendTakeRef((PyListObject *)self_o, PyStackRef_AsPyObjectSteal(arg)); + UNLOCK_OBJECT(self_o); + if (err) { + JUMP_TO_LABEL(error); + } + c = callable; + s = self; + none = PyStackRef_None; + } + // _POP_TOP + { + value = s; + stack_pointer[-3] = none; + stack_pointer[-2] = c; + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + _PyFrame_SetStackPointer(frame, stack_pointer); + _PyFrame_StackPointerValidate(frame); + PyStackRef_XCLOSE(value); + _PyFrame_StackPointerInvalidate(frame); + } + // _POP_TOP + { + value = c; + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + _PyFrame_SetStackPointer(frame, stack_pointer); + _PyFrame_StackPointerValidate(frame); + PyStackRef_XCLOSE(value); + _PyFrame_StackPointerInvalidate(frame); + } + DISPATCH(); + } + TARGET(CALL_METHOD_DESCRIPTOR_FAST) { #if _Py_TAIL_CALL_INTERP int opcode = CALL_METHOD_DESCRIPTOR_FAST; diff --git a/Python/opcode_targets.h b/Python/opcode_targets.h index 91b424773224e4b..53e004c5c619b15 100644 --- a/Python/opcode_targets.h +++ b/Python/opcode_targets.h @@ -159,6 +159,7 @@ static void *opcode_targets_table[256] = { &&TARGET_CALL_KW_PY, &&TARGET_CALL_LEN, &&TARGET_CALL_LIST_APPEND, + &&TARGET_CALL_LIST_APPEND_SUBTYPE, &&TARGET_CALL_METHOD_DESCRIPTOR_FAST, &&TARGET_CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS, &&TARGET_CALL_METHOD_DESCRIPTOR_NOARGS, @@ -232,7 +233,6 @@ static void *opcode_targets_table[256] = { &&_unknown_opcode, &&_unknown_opcode, &&_unknown_opcode, - &&_unknown_opcode, &&TARGET_INSTRUMENTED_END_FOR, &&TARGET_INSTRUMENTED_POP_ITER, &&TARGET_INSTRUMENTED_END_SEND, @@ -478,7 +478,7 @@ static void *opcode_tracing_targets_table[256] = { &&TARGET_TRACE_RECORD, &&TARGET_TRACE_RECORD, &&TARGET_TRACE_RECORD, - &&_unknown_opcode, + &&TARGET_TRACE_RECORD, &&_unknown_opcode, &&_unknown_opcode, &&_unknown_opcode, @@ -578,6 +578,7 @@ static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_CALL_KW_NON_PY(TAIL_CALL_PARAMS) static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_CALL_KW_PY(TAIL_CALL_PARAMS); static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_CALL_LEN(TAIL_CALL_PARAMS); static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_CALL_LIST_APPEND(TAIL_CALL_PARAMS); +static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_CALL_LIST_APPEND_SUBTYPE(TAIL_CALL_PARAMS); static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_CALL_METHOD_DESCRIPTOR_FAST(TAIL_CALL_PARAMS); static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS(TAIL_CALL_PARAMS); static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_CALL_METHOD_DESCRIPTOR_NOARGS(TAIL_CALL_PARAMS); @@ -821,6 +822,7 @@ static py_tail_call_funcptr instruction_funcptr_handler_table[256] = { [CALL_KW_PY] = _TAIL_CALL_CALL_KW_PY, [CALL_LEN] = _TAIL_CALL_CALL_LEN, [CALL_LIST_APPEND] = _TAIL_CALL_CALL_LIST_APPEND, + [CALL_LIST_APPEND_SUBTYPE] = _TAIL_CALL_CALL_LIST_APPEND_SUBTYPE, [CALL_METHOD_DESCRIPTOR_FAST] = _TAIL_CALL_CALL_METHOD_DESCRIPTOR_FAST, [CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS] = _TAIL_CALL_CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS, [CALL_METHOD_DESCRIPTOR_NOARGS] = _TAIL_CALL_CALL_METHOD_DESCRIPTOR_NOARGS, @@ -1016,7 +1018,6 @@ static py_tail_call_funcptr instruction_funcptr_handler_table[256] = { [125] = _TAIL_CALL_UNKNOWN_OPCODE, [126] = _TAIL_CALL_UNKNOWN_OPCODE, [127] = _TAIL_CALL_UNKNOWN_OPCODE, - [219] = _TAIL_CALL_UNKNOWN_OPCODE, [220] = _TAIL_CALL_UNKNOWN_OPCODE, [221] = _TAIL_CALL_UNKNOWN_OPCODE, [222] = _TAIL_CALL_UNKNOWN_OPCODE, @@ -1079,6 +1080,7 @@ static py_tail_call_funcptr instruction_funcptr_tracing_table[256] = { [CALL_KW_PY] = _TAIL_CALL_TRACE_RECORD, [CALL_LEN] = _TAIL_CALL_TRACE_RECORD, [CALL_LIST_APPEND] = _TAIL_CALL_TRACE_RECORD, + [CALL_LIST_APPEND_SUBTYPE] = _TAIL_CALL_TRACE_RECORD, [CALL_METHOD_DESCRIPTOR_FAST] = _TAIL_CALL_TRACE_RECORD, [CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS] = _TAIL_CALL_TRACE_RECORD, [CALL_METHOD_DESCRIPTOR_NOARGS] = _TAIL_CALL_TRACE_RECORD, @@ -1274,7 +1276,6 @@ static py_tail_call_funcptr instruction_funcptr_tracing_table[256] = { [125] = _TAIL_CALL_UNKNOWN_OPCODE, [126] = _TAIL_CALL_UNKNOWN_OPCODE, [127] = _TAIL_CALL_UNKNOWN_OPCODE, - [219] = _TAIL_CALL_UNKNOWN_OPCODE, [220] = _TAIL_CALL_UNKNOWN_OPCODE, [221] = _TAIL_CALL_UNKNOWN_OPCODE, [222] = _TAIL_CALL_UNKNOWN_OPCODE, diff --git a/Python/optimizer_cases.c.h b/Python/optimizer_cases.c.h index 5e110360b81b445..6249d7a08ceeb27 100644 --- a/Python/optimizer_cases.c.h +++ b/Python/optimizer_cases.c.h @@ -377,6 +377,10 @@ break; } + case _GUARD_NOS_LIST_SUBTYPE: { + break; + } + case _GUARD_TOS_LIST: { JitOptRef tos; tos = stack_pointer[-1]; diff --git a/Python/specialize.c b/Python/specialize.c index 05cb76ff015ff40..b63995ba4c56c03 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -1735,6 +1735,10 @@ specialize_method_descriptor(PyMethodDescrObject *descr, PyObject *self_or_null, specialize(instr, CALL_LIST_APPEND); return 0; } + if (PyList_Check(self_or_null)) { + specialize(instr, CALL_LIST_APPEND_SUBTYPE); + return 0; + } } specialize(instr, CALL_METHOD_DESCRIPTOR_O); return 0; From 068ad80775a3b0c763166231f5c642e83f1dea06 Mon Sep 17 00:00:00 2001 From: Sumitha007 Date: Mon, 10 Aug 2026 14:16:45 +0530 Subject: [PATCH 2/2] Regenerate record function metadata --- Python/record_functions.c.h | 1 + 1 file changed, 1 insertion(+) diff --git a/Python/record_functions.c.h b/Python/record_functions.c.h index 98abe3d0505e202..bb8f910857fdd97 100644 --- a/Python/record_functions.c.h +++ b/Python/record_functions.c.h @@ -186,6 +186,7 @@ const _PyOpcodeRecordEntry _PyOpcode_RecordEntries[256] = { [CALL_LEN] = {1, {_RECORD_CALLABLE_INDEX}}, [CALL_ISINSTANCE] = {1, {_RECORD_CALLABLE_INDEX}}, [CALL_LIST_APPEND] = {1, {_RECORD_CALLABLE_INDEX}}, + [CALL_LIST_APPEND_SUBTYPE] = {1, {_RECORD_CALLABLE_INDEX}}, [CALL_METHOD_DESCRIPTOR_O] = {1, {_RECORD_CALLABLE_INDEX}}, [CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS] = {1, {_RECORD_CALLABLE_INDEX}}, [CALL_METHOD_DESCRIPTOR_NOARGS] = {1, {_RECORD_CALLABLE_INDEX}},