From 7e8d188b6173647c4652b909db690d17369ce981 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Fri, 31 Jan 2025 18:05:13 +0000 Subject: [PATCH 1/2] Set opcode statically to free up a parameter for tailcalling --- Include/internal/pycore_opcode_metadata.h | 22 +- Include/internal/pycore_uop_ids.h | 72 ++-- Include/opcode_ids.h | 30 +- Lib/_opcode_metadata.py | 30 +- Python/bytecodes.c | 51 ++- Python/executor_cases.c.h | 6 +- Python/generated_cases.c.h | 433 ++++++++++++++++++++-- Python/opcode_targets.h | 6 +- Python/optimizer_cases.c.h | 6 +- Tools/cases_generator/analyzer.py | 6 +- Tools/cases_generator/tier1_generator.py | 2 + 11 files changed, 525 insertions(+), 139 deletions(-) diff --git a/Include/internal/pycore_opcode_metadata.h b/Include/internal/pycore_opcode_metadata.h index fe791c090120c9..c8a7f1ecde701d 100644 --- a/Include/internal/pycore_opcode_metadata.h +++ b/Include/internal/pycore_opcode_metadata.h @@ -226,9 +226,9 @@ int _PyOpcode_num_popped(int opcode, int oparg) { case INSTRUMENTED_CALL: return 2 + oparg; case INSTRUMENTED_CALL_FUNCTION_EX: - return 0; + return 4; case INSTRUMENTED_CALL_KW: - return 0; + return 3 + oparg; case INSTRUMENTED_END_FOR: return 2; case INSTRUMENTED_END_SEND: @@ -244,7 +244,7 @@ int _PyOpcode_num_popped(int opcode, int oparg) { case INSTRUMENTED_LINE: return 0; case INSTRUMENTED_LOAD_SUPER_ATTR: - return 0; + return 3; case INSTRUMENTED_NOT_TAKEN: return 0; case INSTRUMENTED_POP_ITER: @@ -701,9 +701,9 @@ int _PyOpcode_num_pushed(int opcode, int oparg) { case INSTRUMENTED_CALL: return 1; case INSTRUMENTED_CALL_FUNCTION_EX: - return 0; + return 1; case INSTRUMENTED_CALL_KW: - return 0; + return 1; case INSTRUMENTED_END_FOR: return 1; case INSTRUMENTED_END_SEND: @@ -719,7 +719,7 @@ int _PyOpcode_num_pushed(int opcode, int oparg) { case INSTRUMENTED_LINE: return 0; case INSTRUMENTED_LOAD_SUPER_ATTR: - return 0; + return 1 + (oparg & 1); case INSTRUMENTED_NOT_TAKEN: return 0; case INSTRUMENTED_POP_ITER: @@ -1388,7 +1388,7 @@ int _PyOpcode_max_stack_effect(int opcode, int oparg, int *effect) { return 0; } case INSTRUMENTED_CALL_KW: { - *effect = 0; + *effect = Py_MAX(0, -2 - oparg); return 0; } case INSTRUMENTED_END_FOR: { @@ -1420,7 +1420,7 @@ int _PyOpcode_max_stack_effect(int opcode, int oparg, int *effect) { return 0; } case INSTRUMENTED_LOAD_SUPER_ATTR: { - *effect = 0; + *effect = Py_MAX(-2, -2 + (oparg & 1)); return 0; } case INSTRUMENTED_NOT_TAKEN: { @@ -2104,8 +2104,8 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[266] = { [IMPORT_FROM] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [IMPORT_NAME] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [INSTRUMENTED_CALL] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, - [INSTRUMENTED_CALL_FUNCTION_EX] = { true, INSTR_FMT_IX, 0 }, - [INSTRUMENTED_CALL_KW] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, + [INSTRUMENTED_CALL_FUNCTION_EX] = { true, INSTR_FMT_IX, HAS_EVAL_BREAK_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, + [INSTRUMENTED_CALL_KW] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, [INSTRUMENTED_END_FOR] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG | HAS_NO_SAVE_IP_FLAG }, [INSTRUMENTED_END_SEND] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, [INSTRUMENTED_FOR_ITER] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_JUMP_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, @@ -2113,7 +2113,7 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[266] = { [INSTRUMENTED_JUMP_BACKWARD] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [INSTRUMENTED_JUMP_FORWARD] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, [INSTRUMENTED_LINE] = { true, INSTR_FMT_IX, HAS_ESCAPES_FLAG }, - [INSTRUMENTED_LOAD_SUPER_ATTR] = { true, INSTR_FMT_IXC, 0 }, + [INSTRUMENTED_LOAD_SUPER_ATTR] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [INSTRUMENTED_NOT_TAKEN] = { true, INSTR_FMT_IX, 0 }, [INSTRUMENTED_POP_ITER] = { true, INSTR_FMT_IX, HAS_ESCAPES_FLAG }, [INSTRUMENTED_POP_JUMP_IF_FALSE] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG }, diff --git a/Include/internal/pycore_uop_ids.h b/Include/internal/pycore_uop_ids.h index 7a6c0d22fe24e5..ca40af55406089 100644 --- a/Include/internal/pycore_uop_ids.h +++ b/Include/internal/pycore_uop_ids.h @@ -152,13 +152,10 @@ extern "C" { #define _INIT_CALL_PY_EXACT_ARGS_2 396 #define _INIT_CALL_PY_EXACT_ARGS_3 397 #define _INIT_CALL_PY_EXACT_ARGS_4 398 -#define _INSTRUMENTED_CALL_FUNCTION_EX INSTRUMENTED_CALL_FUNCTION_EX -#define _INSTRUMENTED_CALL_KW INSTRUMENTED_CALL_KW #define _INSTRUMENTED_FOR_ITER INSTRUMENTED_FOR_ITER #define _INSTRUMENTED_INSTRUCTION INSTRUMENTED_INSTRUCTION #define _INSTRUMENTED_JUMP_FORWARD INSTRUMENTED_JUMP_FORWARD #define _INSTRUMENTED_LINE INSTRUMENTED_LINE -#define _INSTRUMENTED_LOAD_SUPER_ATTR INSTRUMENTED_LOAD_SUPER_ATTR #define _INSTRUMENTED_NOT_TAKEN INSTRUMENTED_NOT_TAKEN #define _INSTRUMENTED_POP_JUMP_IF_FALSE INSTRUMENTED_POP_JUMP_IF_FALSE #define _INSTRUMENTED_POP_JUMP_IF_NONE INSTRUMENTED_POP_JUMP_IF_NONE @@ -242,58 +239,59 @@ extern "C" { #define _MAYBE_EXPAND_METHOD 447 #define _MAYBE_EXPAND_METHOD_KW 448 #define _MONITOR_CALL 449 -#define _MONITOR_JUMP_BACKWARD 450 -#define _MONITOR_RESUME 451 +#define _MONITOR_CALL_KW 450 +#define _MONITOR_JUMP_BACKWARD 451 +#define _MONITOR_RESUME 452 #define _NOP NOP #define _POP_EXCEPT POP_EXCEPT -#define _POP_JUMP_IF_FALSE 452 -#define _POP_JUMP_IF_TRUE 453 +#define _POP_JUMP_IF_FALSE 453 +#define _POP_JUMP_IF_TRUE 454 #define _POP_TOP POP_TOP -#define _POP_TOP_LOAD_CONST_INLINE_BORROW 454 +#define _POP_TOP_LOAD_CONST_INLINE_BORROW 455 #define _PUSH_EXC_INFO PUSH_EXC_INFO -#define _PUSH_FRAME 455 +#define _PUSH_FRAME 456 #define _PUSH_NULL PUSH_NULL -#define _PUSH_NULL_CONDITIONAL 456 -#define _PY_FRAME_GENERAL 457 -#define _PY_FRAME_KW 458 -#define _QUICKEN_RESUME 459 -#define _REPLACE_WITH_TRUE 460 +#define _PUSH_NULL_CONDITIONAL 457 +#define _PY_FRAME_GENERAL 458 +#define _PY_FRAME_KW 459 +#define _QUICKEN_RESUME 460 +#define _REPLACE_WITH_TRUE 461 #define _RESUME_CHECK RESUME_CHECK #define _RETURN_GENERATOR RETURN_GENERATOR #define _RETURN_VALUE RETURN_VALUE -#define _SAVE_RETURN_OFFSET 461 -#define _SEND 462 -#define _SEND_GEN_FRAME 463 +#define _SAVE_RETURN_OFFSET 462 +#define _SEND 463 +#define _SEND_GEN_FRAME 464 #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 464 -#define _STORE_ATTR 465 -#define _STORE_ATTR_INSTANCE_VALUE 466 -#define _STORE_ATTR_SLOT 467 -#define _STORE_ATTR_WITH_HINT 468 +#define _START_EXECUTOR 465 +#define _STORE_ATTR 466 +#define _STORE_ATTR_INSTANCE_VALUE 467 +#define _STORE_ATTR_SLOT 468 +#define _STORE_ATTR_WITH_HINT 469 #define _STORE_DEREF STORE_DEREF -#define _STORE_FAST 469 -#define _STORE_FAST_0 470 -#define _STORE_FAST_1 471 -#define _STORE_FAST_2 472 -#define _STORE_FAST_3 473 -#define _STORE_FAST_4 474 -#define _STORE_FAST_5 475 -#define _STORE_FAST_6 476 -#define _STORE_FAST_7 477 +#define _STORE_FAST 470 +#define _STORE_FAST_0 471 +#define _STORE_FAST_1 472 +#define _STORE_FAST_2 473 +#define _STORE_FAST_3 474 +#define _STORE_FAST_4 475 +#define _STORE_FAST_5 476 +#define _STORE_FAST_6 477 +#define _STORE_FAST_7 478 #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 478 -#define _STORE_SUBSCR 479 +#define _STORE_SLICE 479 +#define _STORE_SUBSCR 480 #define _STORE_SUBSCR_DICT STORE_SUBSCR_DICT #define _STORE_SUBSCR_LIST_INT STORE_SUBSCR_LIST_INT #define _SWAP SWAP -#define _TIER2_RESUME_CHECK 480 -#define _TO_BOOL 481 +#define _TIER2_RESUME_CHECK 481 +#define _TO_BOOL 482 #define _TO_BOOL_BOOL TO_BOOL_BOOL #define _TO_BOOL_INT TO_BOOL_INT #define _TO_BOOL_LIST TO_BOOL_LIST @@ -303,13 +301,13 @@ extern "C" { #define _UNARY_NEGATIVE UNARY_NEGATIVE #define _UNARY_NOT UNARY_NOT #define _UNPACK_EX UNPACK_EX -#define _UNPACK_SEQUENCE 482 +#define _UNPACK_SEQUENCE 483 #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 482 +#define MAX_UOP_ID 483 #ifdef __cplusplus } diff --git a/Include/opcode_ids.h b/Include/opcode_ids.h index 4a9fc15dcd2880..dfe7fa36cccd31 100644 --- a/Include/opcode_ids.h +++ b/Include/opcode_ids.h @@ -214,21 +214,21 @@ extern "C" { #define INSTRUMENTED_END_FOR 235 #define INSTRUMENTED_POP_ITER 236 #define INSTRUMENTED_END_SEND 237 -#define INSTRUMENTED_LOAD_SUPER_ATTR 238 -#define INSTRUMENTED_FOR_ITER 239 -#define INSTRUMENTED_CALL_KW 240 -#define INSTRUMENTED_CALL_FUNCTION_EX 241 -#define INSTRUMENTED_INSTRUCTION 242 -#define INSTRUMENTED_JUMP_FORWARD 243 -#define INSTRUMENTED_NOT_TAKEN 244 -#define INSTRUMENTED_POP_JUMP_IF_TRUE 245 -#define INSTRUMENTED_POP_JUMP_IF_FALSE 246 -#define INSTRUMENTED_POP_JUMP_IF_NONE 247 -#define INSTRUMENTED_POP_JUMP_IF_NOT_NONE 248 -#define INSTRUMENTED_RESUME 249 -#define INSTRUMENTED_RETURN_VALUE 250 -#define INSTRUMENTED_YIELD_VALUE 251 -#define INSTRUMENTED_CALL 252 +#define INSTRUMENTED_FOR_ITER 238 +#define INSTRUMENTED_INSTRUCTION 239 +#define INSTRUMENTED_JUMP_FORWARD 240 +#define INSTRUMENTED_NOT_TAKEN 241 +#define INSTRUMENTED_POP_JUMP_IF_TRUE 242 +#define INSTRUMENTED_POP_JUMP_IF_FALSE 243 +#define INSTRUMENTED_POP_JUMP_IF_NONE 244 +#define INSTRUMENTED_POP_JUMP_IF_NOT_NONE 245 +#define INSTRUMENTED_RESUME 246 +#define INSTRUMENTED_RETURN_VALUE 247 +#define INSTRUMENTED_YIELD_VALUE 248 +#define INSTRUMENTED_LOAD_SUPER_ATTR 249 +#define INSTRUMENTED_CALL 250 +#define INSTRUMENTED_CALL_KW 251 +#define INSTRUMENTED_CALL_FUNCTION_EX 252 #define INSTRUMENTED_JUMP_BACKWARD 253 #define INSTRUMENTED_LINE 254 #define ENTER_EXECUTOR 255 diff --git a/Lib/_opcode_metadata.py b/Lib/_opcode_metadata.py index 12c41374592185..ae3e9bd0ab4940 100644 --- a/Lib/_opcode_metadata.py +++ b/Lib/_opcode_metadata.py @@ -334,21 +334,21 @@ 'INSTRUMENTED_END_FOR': 235, 'INSTRUMENTED_POP_ITER': 236, 'INSTRUMENTED_END_SEND': 237, - 'INSTRUMENTED_LOAD_SUPER_ATTR': 238, - 'INSTRUMENTED_FOR_ITER': 239, - 'INSTRUMENTED_CALL_KW': 240, - 'INSTRUMENTED_CALL_FUNCTION_EX': 241, - 'INSTRUMENTED_INSTRUCTION': 242, - 'INSTRUMENTED_JUMP_FORWARD': 243, - 'INSTRUMENTED_NOT_TAKEN': 244, - 'INSTRUMENTED_POP_JUMP_IF_TRUE': 245, - 'INSTRUMENTED_POP_JUMP_IF_FALSE': 246, - 'INSTRUMENTED_POP_JUMP_IF_NONE': 247, - 'INSTRUMENTED_POP_JUMP_IF_NOT_NONE': 248, - 'INSTRUMENTED_RESUME': 249, - 'INSTRUMENTED_RETURN_VALUE': 250, - 'INSTRUMENTED_YIELD_VALUE': 251, - 'INSTRUMENTED_CALL': 252, + 'INSTRUMENTED_FOR_ITER': 238, + 'INSTRUMENTED_INSTRUCTION': 239, + 'INSTRUMENTED_JUMP_FORWARD': 240, + 'INSTRUMENTED_NOT_TAKEN': 241, + 'INSTRUMENTED_POP_JUMP_IF_TRUE': 242, + 'INSTRUMENTED_POP_JUMP_IF_FALSE': 243, + 'INSTRUMENTED_POP_JUMP_IF_NONE': 244, + 'INSTRUMENTED_POP_JUMP_IF_NOT_NONE': 245, + 'INSTRUMENTED_RESUME': 246, + 'INSTRUMENTED_RETURN_VALUE': 247, + 'INSTRUMENTED_YIELD_VALUE': 248, + 'INSTRUMENTED_LOAD_SUPER_ATTR': 249, + 'INSTRUMENTED_CALL': 250, + 'INSTRUMENTED_CALL_KW': 251, + 'INSTRUMENTED_CALL_FUNCTION_EX': 252, 'INSTRUMENTED_JUMP_BACKWARD': 253, 'JUMP': 256, 'JUMP_IF_FALSE': 257, diff --git a/Python/bytecodes.c b/Python/bytecodes.c index f659a5e5c920a7..e82c9f33f8b1a0 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -2019,12 +2019,10 @@ dummy_func( ERROR_IF(err != 0, error); } - inst(INSTRUMENTED_LOAD_SUPER_ATTR, (unused/1 -- )) { - // cancel out the decrement that will happen in LOAD_SUPER_ATTR; we - // don't want to specialize instrumented instructions - PAUSE_ADAPTIVE_COUNTER(this_instr[1].counter); - GO_TO_INSTRUCTION(LOAD_SUPER_ATTR); - } + macro(INSTRUMENTED_LOAD_SUPER_ATTR) = + counter/1 + + _LOAD_SUPER_ATTR + + _PUSH_NULL_CONDITIONAL; family(LOAD_SUPER_ATTR, INLINE_CACHE_ENTRIES_LOAD_SUPER_ATTR) = { LOAD_SUPER_ATTR_ATTR, @@ -2088,7 +2086,10 @@ dummy_func( attr = PyStackRef_FromPyObjectSteal(attr_o); } - macro(LOAD_SUPER_ATTR) = _SPECIALIZE_LOAD_SUPER_ATTR + _LOAD_SUPER_ATTR + _PUSH_NULL_CONDITIONAL; + macro(LOAD_SUPER_ATTR) = + _SPECIALIZE_LOAD_SUPER_ATTR + + _LOAD_SUPER_ATTR + + _PUSH_NULL_CONDITIONAL; inst(LOAD_SUPER_ATTR_ATTR, (unused/1, global_super_st, class_st, self_st -- attr_st)) { PyObject *global_super = PyStackRef_AsPyObjectBorrow(global_super_st); @@ -4336,18 +4337,23 @@ dummy_func( CALL_KW_NON_PY, }; - inst(INSTRUMENTED_CALL_KW, (counter/1, version/2 -- )) { - int is_meth = !PyStackRef_IsNull(PEEK(oparg + 2)); - int total_args = oparg + is_meth; - PyObject *function = PyStackRef_AsPyObjectBorrow(PEEK(oparg + 3)); - PyObject *arg = total_args == 0 ? &_PyInstrumentation_MISSING - : PyStackRef_AsPyObjectBorrow(PEEK(total_args + 1)); + op(_MONITOR_CALL_KW, (callable[1], self_or_null[1], args[oparg], kwnames -- callable[1], self_or_null[1], args[oparg], kwnames)) { + int is_meth = !PyStackRef_IsNull(self_or_null[0]); + PyObject *arg; + if (is_meth) { + arg = PyStackRef_AsPyObjectBorrow(self_or_null[0]); + } + else if (args) { + arg = PyStackRef_AsPyObjectBorrow(args[0]); + } + else { + arg = &_PyInstrumentation_MISSING; + } + PyObject *function = PyStackRef_AsPyObjectBorrow(callable[0]); int err = _Py_call_instrumentation_2args( tstate, PY_MONITORING_EVENT_CALL, frame, this_instr, function, arg); ERROR_IF(err, error); - PAUSE_ADAPTIVE_COUNTER(this_instr[1].counter); - GO_TO_INSTRUCTION(CALL_KW); } op(_MAYBE_EXPAND_METHOD_KW, (callable[1], self_or_null[1], args[oparg], kwnames_in -- func[1], maybe_self[1], args[oparg], kwnames_out)) { @@ -4526,6 +4532,13 @@ dummy_func( _MAYBE_EXPAND_METHOD_KW + _DO_CALL_KW; + macro(INSTRUMENTED_CALL_KW) = + counter/1 + + unused/2 + + _MONITOR_CALL_KW + + _MAYBE_EXPAND_METHOD_KW + + _DO_CALL_KW; + op(_CHECK_IS_NOT_PY_CALLABLE_KW, (callable[1], unused[1], unused[oparg], kwnames -- callable[1], unused[1], unused[oparg], kwnames)) { PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); EXIT_IF(PyFunction_Check(callable_o)); @@ -4572,10 +4585,6 @@ dummy_func( _CALL_KW_NON_PY + _CHECK_PERIODIC; - inst(INSTRUMENTED_CALL_FUNCTION_EX, ( -- )) { - GO_TO_INSTRUCTION(CALL_FUNCTION_EX); - } - op(_MAKE_CALLARGS_A_TUPLE, (func, unused, callargs, kwargs_in -- func, unused, tuple, kwargs_out)) { PyObject *callargs_o = PyStackRef_AsPyObjectBorrow(callargs); if (PyTuple_CheckExact(callargs_o)) { @@ -4683,6 +4692,10 @@ dummy_func( _DO_CALL_FUNCTION_EX + _CHECK_PERIODIC; + macro(INSTRUMENTED_CALL_FUNCTION_EX) = + _MAKE_CALLARGS_A_TUPLE + + _DO_CALL_FUNCTION_EX + + _CHECK_PERIODIC; inst(MAKE_FUNCTION, (codeobj_st -- func)) { PyObject *codeobj = PyStackRef_AsPyObjectBorrow(codeobj_st); diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index 4addfbcf6d6419..d7e0a3d78bc7bc 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -2516,8 +2516,6 @@ break; } - /* _INSTRUMENTED_LOAD_SUPER_ATTR is not a viable micro-op for tier 2 because it is instrumented */ - case _LOAD_SUPER_ATTR_ATTR: { _PyStackRef self_st; _PyStackRef class_st; @@ -5311,7 +5309,7 @@ break; } - /* _INSTRUMENTED_CALL_KW is not a viable micro-op for tier 2 because it is instrumented */ + /* _MONITOR_CALL_KW is not a viable micro-op for tier 2 because it uses the 'this_instr' variable */ case _MAYBE_EXPAND_METHOD_KW: { _PyStackRef kwnames_in; @@ -5528,8 +5526,6 @@ break; } - /* _INSTRUMENTED_CALL_FUNCTION_EX is not a viable micro-op for tier 2 because it is instrumented */ - case _MAKE_CALLARGS_A_TUPLE: { _PyStackRef kwargs_in; _PyStackRef callargs; diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index ffdad70815caef..ae6aef5a275279 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -932,6 +932,7 @@ PREDICTED_CALL:; _Py_CODEUNIT* const this_instr = next_instr - 4; (void)this_instr; + opcode = CALL; _PyStackRef *callable; _PyStackRef *self_or_null; _PyStackRef *args; @@ -1705,12 +1706,11 @@ } TARGET(CALL_FUNCTION_EX) { - frame->instr_ptr = next_instr; + _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; + (void)this_instr; next_instr += 1; INSTRUCTION_STATS(CALL_FUNCTION_EX); - PREDICTED_CALL_FUNCTION_EX:; - _Py_CODEUNIT* const this_instr = next_instr - 1; - (void)this_instr; + opcode = CALL_FUNCTION_EX; _PyStackRef func; _PyStackRef callargs; _PyStackRef kwargs_in; @@ -1964,6 +1964,7 @@ PREDICTED_CALL_KW:; _Py_CODEUNIT* const this_instr = next_instr - 4; (void)this_instr; + opcode = CALL_KW; _PyStackRef *callable; _PyStackRef *self_or_null; _PyStackRef *args; @@ -2226,6 +2227,7 @@ frame->instr_ptr = next_instr; next_instr += 4; INSTRUCTION_STATS(CALL_KW_NON_PY); + opcode = CALL_KW_NON_PY; static_assert(INLINE_CACHE_ENTRIES_CALL_KW == 3, "incorrect cache size"); _PyStackRef *callable; _PyStackRef kwnames; @@ -2810,6 +2812,7 @@ frame->instr_ptr = next_instr; next_instr += 4; INSTRUCTION_STATS(CALL_NON_PY_GENERAL); + opcode = CALL_NON_PY_GENERAL; static_assert(INLINE_CACHE_ENTRIES_CALL == 3, "incorrect cache size"); _PyStackRef *callable; _PyStackRef *self_or_null; @@ -3895,6 +3898,7 @@ (void)this_instr; next_instr += 1; INSTRUCTION_STATS(ENTER_EXECUTOR); + opcode = ENTER_EXECUTOR; #ifdef _Py_TIER2 PyCodeObject *code = _PyFrame_GetCode(frame); _PyExecutorObject *executor = code->co_executors->executors[oparg & 255]; @@ -3947,6 +3951,7 @@ frame->instr_ptr = next_instr; next_instr += 1; INSTRUCTION_STATS(EXTENDED_ARG); + opcode = EXTENDED_ARG; assert(oparg); opcode = next_instr->op.code; oparg = oparg << 8 | next_instr->op.arg; @@ -4468,6 +4473,7 @@ (void)this_instr; next_instr += 4; INSTRUCTION_STATS(INSTRUMENTED_CALL); + opcode = INSTRUMENTED_CALL; _PyStackRef *callable; _PyStackRef *self_or_null; _PyStackRef *args; @@ -4633,11 +4639,165 @@ } TARGET(INSTRUMENTED_CALL_FUNCTION_EX) { - frame->instr_ptr = next_instr; + _Py_CODEUNIT* const this_instr = frame->instr_ptr = next_instr; + (void)this_instr; next_instr += 1; INSTRUCTION_STATS(INSTRUMENTED_CALL_FUNCTION_EX); - - goto PREDICTED_CALL_FUNCTION_EX; + opcode = INSTRUMENTED_CALL_FUNCTION_EX; + _PyStackRef func; + _PyStackRef callargs; + _PyStackRef kwargs_in; + _PyStackRef tuple; + _PyStackRef kwargs_out; + _PyStackRef func_st; + _PyStackRef callargs_st; + _PyStackRef kwargs_st; + _PyStackRef result; + // _MAKE_CALLARGS_A_TUPLE + { + kwargs_in = stack_pointer[-1]; + callargs = stack_pointer[-2]; + func = stack_pointer[-4]; + PyObject *callargs_o = PyStackRef_AsPyObjectBorrow(callargs); + if (PyTuple_CheckExact(callargs_o)) { + tuple = callargs; + kwargs_out = kwargs_in; + } + else { + _PyFrame_SetStackPointer(frame, stack_pointer); + int err = _Py_Check_ArgsIterable(tstate, PyStackRef_AsPyObjectBorrow(func), callargs_o); + stack_pointer = _PyFrame_GetStackPointer(frame); + if (err < 0) { + goto error; + } + _PyFrame_SetStackPointer(frame, stack_pointer); + PyObject *tuple_o = PySequence_Tuple(callargs_o); + stack_pointer = _PyFrame_GetStackPointer(frame); + if (tuple_o == NULL) { + goto error; + } + kwargs_out = kwargs_in; + PyStackRef_CLOSE(callargs); + tuple = PyStackRef_FromPyObjectSteal(tuple_o); + } + } + // _DO_CALL_FUNCTION_EX + { + kwargs_st = kwargs_out; + callargs_st = tuple; + func_st = func; + PyObject *func = PyStackRef_AsPyObjectBorrow(func_st); + // DICT_MERGE is called before this opcode if there are kwargs. + // It converts all dict subtypes in kwargs into regular dicts. + EVAL_CALL_STAT_INC_IF_FUNCTION(EVAL_CALL_FUNCTION_EX, func); + PyObject *result_o; + assert(!_PyErr_Occurred(tstate)); + if (opcode == INSTRUMENTED_CALL_FUNCTION_EX) { + PyObject *callargs = PyStackRef_AsPyObjectBorrow(callargs_st); + PyObject *kwargs = PyStackRef_AsPyObjectBorrow(kwargs_st); + assert(kwargs == NULL || PyDict_CheckExact(kwargs)); + assert(PyTuple_CheckExact(callargs)); + PyObject *arg = PyTuple_GET_SIZE(callargs) > 0 ? + PyTuple_GET_ITEM(callargs, 0) : &_PyInstrumentation_MISSING; + stack_pointer[-2] = callargs_st; + stack_pointer[-1] = kwargs_st; + _PyFrame_SetStackPointer(frame, stack_pointer); + int err = _Py_call_instrumentation_2args( + tstate, PY_MONITORING_EVENT_CALL, + frame, this_instr, func, arg); + stack_pointer = _PyFrame_GetStackPointer(frame); + if (err) { + goto error; + } + _PyFrame_SetStackPointer(frame, stack_pointer); + result_o = PyObject_Call(func, callargs, kwargs); + stack_pointer = _PyFrame_GetStackPointer(frame); + if (!PyFunction_Check(func) && !PyMethod_Check(func)) { + if (result_o == NULL) { + _PyFrame_SetStackPointer(frame, stack_pointer); + _Py_call_instrumentation_exc2( + tstate, PY_MONITORING_EVENT_C_RAISE, + frame, this_instr, func, arg); + stack_pointer = _PyFrame_GetStackPointer(frame); + } + else { + _PyFrame_SetStackPointer(frame, stack_pointer); + int err = _Py_call_instrumentation_2args( + tstate, PY_MONITORING_EVENT_C_RETURN, + frame, this_instr, func, arg); + stack_pointer = _PyFrame_GetStackPointer(frame); + if (err < 0) { + Py_CLEAR(result_o); + } + } + } + } + else { + if (Py_TYPE(func) == &PyFunction_Type && + tstate->interp->eval_frame == NULL && + ((PyFunctionObject *)func)->vectorcall == _PyFunction_Vectorcall) { + PyObject *callargs = PyStackRef_AsPyObjectSteal(callargs_st); + assert(PyTuple_CheckExact(callargs)); + PyObject *kwargs = PyStackRef_IsNull(kwargs_st) ? NULL : PyStackRef_AsPyObjectSteal(kwargs_st); + assert(kwargs == NULL || PyDict_CheckExact(kwargs)); + Py_ssize_t nargs = PyTuple_GET_SIZE(callargs); + int code_flags = ((PyCodeObject *)PyFunction_GET_CODE(func))->co_flags; + PyObject *locals = code_flags & CO_OPTIMIZED ? NULL : Py_NewRef(PyFunction_GET_GLOBALS(func)); + stack_pointer += -3; + assert(WITHIN_STACK_BOUNDS()); + _PyFrame_SetStackPointer(frame, stack_pointer); + _PyInterpreterFrame *new_frame = _PyEvalFramePushAndInit_Ex( + tstate, func_st, locals, + nargs, callargs, kwargs, frame); + stack_pointer = _PyFrame_GetStackPointer(frame); + // Need to sync the stack since we exit with DISPATCH_INLINED. + stack_pointer += -1; + assert(WITHIN_STACK_BOUNDS()); + if (new_frame == NULL) { + goto error; + } + assert( 1 == 1); + frame->return_offset = 1; + DISPATCH_INLINED(new_frame); + } + PyObject *callargs = PyStackRef_AsPyObjectBorrow(callargs_st); + assert(PyTuple_CheckExact(callargs)); + PyObject *kwargs = PyStackRef_AsPyObjectBorrow(kwargs_st); + assert(kwargs == NULL || PyDict_CheckExact(kwargs)); + stack_pointer[-2] = callargs_st; + stack_pointer[-1] = kwargs_st; + _PyFrame_SetStackPointer(frame, stack_pointer); + result_o = PyObject_Call(func, callargs, kwargs); + stack_pointer = _PyFrame_GetStackPointer(frame); + } + _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_XCLOSE(kwargs_st); + stack_pointer = _PyFrame_GetStackPointer(frame); + PyStackRef_CLOSE(callargs_st); + PyStackRef_CLOSE(func_st); + if (result_o == NULL) goto pop_4_error; + result = PyStackRef_FromPyObjectSteal(result_o); + } + // _CHECK_PERIODIC + { + _Py_CHECK_EMSCRIPTEN_SIGNALS_PERIODICALLY(); + QSBR_QUIESCENT_STATE(tstate); + if (_Py_atomic_load_uintptr_relaxed(&tstate->eval_breaker) & _PY_EVAL_EVENTS_MASK) { + stack_pointer[-4] = result; + stack_pointer += -3; + assert(WITHIN_STACK_BOUNDS()); + _PyFrame_SetStackPointer(frame, stack_pointer); + int err = _Py_HandlePending(tstate); + stack_pointer = _PyFrame_GetStackPointer(frame); + if (err != 0) goto error; + stack_pointer += 3; + assert(WITHIN_STACK_BOUNDS()); + } + } + stack_pointer[-4] = result; + stack_pointer += -3; + assert(WITHIN_STACK_BOUNDS()); + DISPATCH(); } TARGET(INSTRUMENTED_CALL_KW) { @@ -4645,23 +4805,164 @@ (void)this_instr; next_instr += 4; INSTRUCTION_STATS(INSTRUMENTED_CALL_KW); - uint16_t counter = read_u16(&this_instr[1].cache); - (void)counter; - uint32_t version = read_u32(&this_instr[2].cache); - (void)version; - int is_meth = !PyStackRef_IsNull(PEEK(oparg + 2)); - int total_args = oparg + is_meth; - PyObject *function = PyStackRef_AsPyObjectBorrow(PEEK(oparg + 3)); - PyObject *arg = total_args == 0 ? &_PyInstrumentation_MISSING - : PyStackRef_AsPyObjectBorrow(PEEK(total_args + 1)); - _PyFrame_SetStackPointer(frame, stack_pointer); - int err = _Py_call_instrumentation_2args( - tstate, PY_MONITORING_EVENT_CALL, - frame, this_instr, function, arg); - stack_pointer = _PyFrame_GetStackPointer(frame); - if (err) goto error; - PAUSE_ADAPTIVE_COUNTER(this_instr[1].counter); - goto PREDICTED_CALL_KW; + opcode = INSTRUMENTED_CALL_KW; + _PyStackRef *callable; + _PyStackRef *self_or_null; + _PyStackRef *args; + _PyStackRef kwnames; + _PyStackRef kwnames_in; + _PyStackRef *func; + _PyStackRef *maybe_self; + _PyStackRef kwnames_out; + _PyStackRef res; + /* Skip 1 cache entry */ + /* Skip 2 cache entries */ + // _MONITOR_CALL_KW + { + args = &stack_pointer[-1 - oparg]; + self_or_null = &stack_pointer[-2 - oparg]; + callable = &stack_pointer[-3 - oparg]; + int is_meth = !PyStackRef_IsNull(self_or_null[0]); + PyObject *arg; + if (is_meth) { + arg = PyStackRef_AsPyObjectBorrow(self_or_null[0]); + } + else { + if (args) { + arg = PyStackRef_AsPyObjectBorrow(args[0]); + } + else { + arg = &_PyInstrumentation_MISSING; + } + } + PyObject *function = PyStackRef_AsPyObjectBorrow(callable[0]); + _PyFrame_SetStackPointer(frame, stack_pointer); + int err = _Py_call_instrumentation_2args( + tstate, PY_MONITORING_EVENT_CALL, + frame, this_instr, function, arg); + stack_pointer = _PyFrame_GetStackPointer(frame); + if (err) goto error; + } + // _MAYBE_EXPAND_METHOD_KW + { + kwnames_in = stack_pointer[-1]; + func = &stack_pointer[-3 - oparg]; + maybe_self = &stack_pointer[-2 - oparg]; + if (PyStackRef_TYPE(callable[0]) == &PyMethod_Type && PyStackRef_IsNull(self_or_null[0])) { + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); + PyObject *self = ((PyMethodObject *)callable_o)->im_self; + maybe_self[0] = PyStackRef_FromPyObjectNew(self); + PyObject *method = ((PyMethodObject *)callable_o)->im_func; + _PyStackRef temp = callable[0]; + func[0] = PyStackRef_FromPyObjectNew(method); + PyStackRef_CLOSE(temp); + } + kwnames_out = kwnames_in; + } + // _DO_CALL_KW + { + kwnames = kwnames_out; + args = &stack_pointer[-1 - oparg]; + self_or_null = &stack_pointer[-2 - oparg]; + callable = &stack_pointer[-3 - oparg]; + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); + PyObject *kwnames_o = PyStackRef_AsPyObjectBorrow(kwnames); + // oparg counts all of the args, but *not* self: + int total_args = oparg; + _PyStackRef *arguments = args; + if (!PyStackRef_IsNull(self_or_null[0])) { + arguments--; + total_args++; + } + int positional_args = total_args - (int)PyTuple_GET_SIZE(kwnames_o); + // Check if the call can be inlined or not + if (Py_TYPE(callable_o) == &PyFunction_Type && + tstate->interp->eval_frame == NULL && + ((PyFunctionObject *)callable_o)->vectorcall == _PyFunction_Vectorcall) + { + int code_flags = ((PyCodeObject*)PyFunction_GET_CODE(callable_o))->co_flags; + PyObject *locals = code_flags & CO_OPTIMIZED ? NULL : Py_NewRef(PyFunction_GET_GLOBALS(callable_o)); + stack_pointer[-1] = kwnames; + _PyFrame_SetStackPointer(frame, stack_pointer); + _PyInterpreterFrame *new_frame = _PyEvalFramePushAndInit( + tstate, callable[0], locals, + arguments, positional_args, kwnames_o, frame + ); + stack_pointer = _PyFrame_GetStackPointer(frame); + PyStackRef_CLOSE(kwnames); + // Sync stack explicitly since we leave using DISPATCH_INLINED(). + stack_pointer += -3 - oparg; + assert(WITHIN_STACK_BOUNDS()); + // The frame has stolen all the arguments from the stack, + // so there is no need to clean them up. + if (new_frame == NULL) { + goto error; + } + assert( 4 == 1 + INLINE_CACHE_ENTRIES_CALL_KW); + frame->return_offset = 4 ; + DISPATCH_INLINED(new_frame); + } + /* Callable is not a normal Python function */ + STACKREFS_TO_PYOBJECTS(arguments, total_args, args_o); + if (CONVERSION_FAILED(args_o)) { + PyStackRef_CLOSE(callable[0]); + PyStackRef_XCLOSE(self_or_null[0]); + for (int _i = oparg; --_i >= 0;) { + PyStackRef_CLOSE(args[_i]); + } + PyStackRef_CLOSE(kwnames); + { + stack_pointer += -3 - oparg; + assert(WITHIN_STACK_BOUNDS()); + goto error; + } + } + stack_pointer[-1] = kwnames; + _PyFrame_SetStackPointer(frame, stack_pointer); + PyObject *res_o = PyObject_Vectorcall( + callable_o, args_o, + positional_args | PY_VECTORCALL_ARGUMENTS_OFFSET, + kwnames_o); + stack_pointer = _PyFrame_GetStackPointer(frame); + STACKREFS_TO_PYOBJECTS_CLEANUP(args_o); + if (opcode == INSTRUMENTED_CALL_KW) { + PyObject *arg = total_args == 0 ? + &_PyInstrumentation_MISSING : PyStackRef_AsPyObjectBorrow(arguments[0]); + if (res_o == NULL) { + _PyFrame_SetStackPointer(frame, stack_pointer); + _Py_call_instrumentation_exc2( + tstate, PY_MONITORING_EVENT_C_RAISE, + frame, this_instr, callable_o, arg); + stack_pointer = _PyFrame_GetStackPointer(frame); + } + else { + _PyFrame_SetStackPointer(frame, stack_pointer); + int err = _Py_call_instrumentation_2args( + tstate, PY_MONITORING_EVENT_C_RETURN, + frame, this_instr, callable_o, arg); + stack_pointer = _PyFrame_GetStackPointer(frame); + if (err < 0) { + Py_CLEAR(res_o); + } + } + } + PyStackRef_CLOSE(callable[0]); + PyStackRef_XCLOSE(self_or_null[0]); + for (int _i = oparg; --_i >= 0;) { + PyStackRef_CLOSE(args[_i]); + } + PyStackRef_CLOSE(kwnames); + if (res_o == NULL) { + stack_pointer += -3 - oparg; + assert(WITHIN_STACK_BOUNDS()); + goto error; + } + res = PyStackRef_FromPyObjectSteal(res_o); + } + stack_pointer[-3 - oparg] = res; + stack_pointer += -2 - oparg; + assert(WITHIN_STACK_BOUNDS()); + DISPATCH(); } TARGET(INSTRUMENTED_END_FOR) { @@ -4758,6 +5059,7 @@ (void)this_instr; next_instr += 1; INSTRUCTION_STATS(INSTRUMENTED_INSTRUCTION); + opcode = INSTRUMENTED_INSTRUCTION; _PyFrame_SetStackPointer(frame, stack_pointer); int next_opcode = _Py_call_instrumentation_instruction( tstate, frame, this_instr); @@ -4811,6 +5113,7 @@ (void)this_instr; next_instr += 1; INSTRUCTION_STATS(INSTRUMENTED_LINE); + opcode = INSTRUMENTED_LINE; int original_opcode = 0; if (tstate->tracing) { PyCodeObject *code = _PyFrame_GetCode(frame); @@ -4848,11 +5151,84 @@ (void)this_instr; next_instr += 2; INSTRUCTION_STATS(INSTRUMENTED_LOAD_SUPER_ATTR); + opcode = INSTRUMENTED_LOAD_SUPER_ATTR; + _PyStackRef global_super_st; + _PyStackRef class_st; + _PyStackRef self_st; + _PyStackRef attr; + _PyStackRef null = PyStackRef_NULL; /* Skip 1 cache entry */ - // cancel out the decrement that will happen in LOAD_SUPER_ATTR; we - // don't want to specialize instrumented instructions - PAUSE_ADAPTIVE_COUNTER(this_instr[1].counter); - goto PREDICTED_LOAD_SUPER_ATTR; + // _LOAD_SUPER_ATTR + { + self_st = stack_pointer[-1]; + class_st = stack_pointer[-2]; + global_super_st = stack_pointer[-3]; + PyObject *global_super = PyStackRef_AsPyObjectBorrow(global_super_st); + PyObject *class = PyStackRef_AsPyObjectBorrow(class_st); + PyObject *self = PyStackRef_AsPyObjectBorrow(self_st); + if (opcode == INSTRUMENTED_LOAD_SUPER_ATTR) { + PyObject *arg = oparg & 2 ? class : &_PyInstrumentation_MISSING; + _PyFrame_SetStackPointer(frame, stack_pointer); + int err = _Py_call_instrumentation_2args( + tstate, PY_MONITORING_EVENT_CALL, + frame, this_instr, global_super, arg); + stack_pointer = _PyFrame_GetStackPointer(frame); + if (err) { + PyStackRef_CLOSE(global_super_st); + PyStackRef_CLOSE(class_st); + PyStackRef_CLOSE(self_st); + goto pop_3_error; + } + } + // we make no attempt to optimize here; specializations should + // handle any case whose performance we care about + PyObject *stack[] = {class, self}; + _PyFrame_SetStackPointer(frame, stack_pointer); + PyObject *super = PyObject_Vectorcall(global_super, stack, oparg & 2, NULL); + stack_pointer = _PyFrame_GetStackPointer(frame); + if (opcode == INSTRUMENTED_LOAD_SUPER_ATTR) { + PyObject *arg = oparg & 2 ? class : &_PyInstrumentation_MISSING; + if (super == NULL) { + _PyFrame_SetStackPointer(frame, stack_pointer); + _Py_call_instrumentation_exc2( + tstate, PY_MONITORING_EVENT_C_RAISE, + frame, this_instr, global_super, arg); + stack_pointer = _PyFrame_GetStackPointer(frame); + } + else { + _PyFrame_SetStackPointer(frame, stack_pointer); + int err = _Py_call_instrumentation_2args( + tstate, PY_MONITORING_EVENT_C_RETURN, + frame, this_instr, global_super, arg); + stack_pointer = _PyFrame_GetStackPointer(frame); + if (err < 0) { + Py_CLEAR(super); + } + } + } + PyStackRef_CLOSE(global_super_st); + PyStackRef_CLOSE(class_st); + PyStackRef_CLOSE(self_st); + if (super == NULL) goto pop_3_error; + PyObject *name = GETITEM(FRAME_CO_NAMES, oparg >> 2); + stack_pointer += -3; + assert(WITHIN_STACK_BOUNDS()); + _PyFrame_SetStackPointer(frame, stack_pointer); + PyObject *attr_o = PyObject_GetAttr(super, name); + Py_DECREF(super); + stack_pointer = _PyFrame_GetStackPointer(frame); + if (attr_o == NULL) goto error; + attr = PyStackRef_FromPyObjectSteal(attr_o); + } + // _PUSH_NULL_CONDITIONAL + { + null = PyStackRef_NULL; + } + stack_pointer[0] = attr; + if (oparg & 1) stack_pointer[1] = null; + stack_pointer += 1 + (oparg & 1); + assert(WITHIN_STACK_BOUNDS()); + DISPATCH(); } TARGET(INSTRUMENTED_NOT_TAKEN) { @@ -6622,6 +6998,7 @@ PREDICTED_LOAD_SUPER_ATTR:; _Py_CODEUNIT* const this_instr = next_instr - 2; (void)this_instr; + opcode = LOAD_SUPER_ATTR; _PyStackRef global_super_st; _PyStackRef class_st; _PyStackRef self_st; diff --git a/Python/opcode_targets.h b/Python/opcode_targets.h index 09a834bb38fa67..2b84f0281e5356 100644 --- a/Python/opcode_targets.h +++ b/Python/opcode_targets.h @@ -237,10 +237,7 @@ static void *opcode_targets[256] = { &&TARGET_INSTRUMENTED_END_FOR, &&TARGET_INSTRUMENTED_POP_ITER, &&TARGET_INSTRUMENTED_END_SEND, - &&TARGET_INSTRUMENTED_LOAD_SUPER_ATTR, &&TARGET_INSTRUMENTED_FOR_ITER, - &&TARGET_INSTRUMENTED_CALL_KW, - &&TARGET_INSTRUMENTED_CALL_FUNCTION_EX, &&TARGET_INSTRUMENTED_INSTRUCTION, &&TARGET_INSTRUMENTED_JUMP_FORWARD, &&TARGET_INSTRUMENTED_NOT_TAKEN, @@ -251,7 +248,10 @@ static void *opcode_targets[256] = { &&TARGET_INSTRUMENTED_RESUME, &&TARGET_INSTRUMENTED_RETURN_VALUE, &&TARGET_INSTRUMENTED_YIELD_VALUE, + &&TARGET_INSTRUMENTED_LOAD_SUPER_ATTR, &&TARGET_INSTRUMENTED_CALL, + &&TARGET_INSTRUMENTED_CALL_KW, + &&TARGET_INSTRUMENTED_CALL_FUNCTION_EX, &&TARGET_INSTRUMENTED_JUMP_BACKWARD, &&TARGET_INSTRUMENTED_LINE, &&TARGET_ENTER_EXECUTOR, diff --git a/Python/optimizer_cases.c.h b/Python/optimizer_cases.c.h index 2497754745c28b..181634f9fa5550 100644 --- a/Python/optimizer_cases.c.h +++ b/Python/optimizer_cases.c.h @@ -1105,8 +1105,6 @@ break; } - /* _INSTRUMENTED_LOAD_SUPER_ATTR is not a viable micro-op for tier 2 */ - case _LOAD_SUPER_ATTR_ATTR: { JitOptSymbol *attr_st; attr_st = sym_new_not_null(ctx); @@ -2161,7 +2159,7 @@ break; } - /* _INSTRUMENTED_CALL_KW is not a viable micro-op for tier 2 */ + /* _MONITOR_CALL_KW is not a viable micro-op for tier 2 */ case _MAYBE_EXPAND_METHOD_KW: { JitOptSymbol **func; @@ -2236,8 +2234,6 @@ break; } - /* _INSTRUMENTED_CALL_FUNCTION_EX is not a viable micro-op for tier 2 */ - case _MAKE_CALLARGS_A_TUPLE: { JitOptSymbol *tuple; JitOptSymbol *kwargs_out; diff --git a/Tools/cases_generator/analyzer.py b/Tools/cases_generator/analyzer.py index b9293ff4b19951..7ae47a6ce95e3f 100644 --- a/Tools/cases_generator/analyzer.py +++ b/Tools/cases_generator/analyzer.py @@ -24,6 +24,7 @@ class Properties: has_free: bool side_exit: bool pure: bool + uses_opcode: bool tier: int | None = None oparg_and_1: bool = False const_oparg: int = -1 @@ -59,6 +60,7 @@ def from_list(properties: list["Properties"]) -> "Properties": uses_co_consts=any(p.uses_co_consts for p in properties), uses_co_names=any(p.uses_co_names for p in properties), uses_locals=any(p.uses_locals for p in properties), + uses_opcode=any(p.uses_opcode for p in properties), has_free=any(p.has_free for p in properties), side_exit=any(p.side_exit for p in properties), pure=all(p.pure for p in properties), @@ -85,6 +87,7 @@ def infallible(self) -> bool: uses_co_consts=False, uses_co_names=False, uses_locals=False, + uses_opcode=False, has_free=False, side_exit=False, pure=True, @@ -844,7 +847,8 @@ def compute_properties(op: parser.InstDef) -> Properties: uses_co_consts=variable_used(op, "FRAME_CO_CONSTS"), uses_co_names=variable_used(op, "FRAME_CO_NAMES"), uses_locals=(variable_used(op, "GETLOCAL") or variable_used(op, "SETLOCAL")) - and not has_free, + and not has_free, + uses_opcode=variable_used(op, "opcode"), has_free=has_free, pure="pure" in op.annotations, no_save_ip="no_save_ip" in op.annotations, diff --git a/Tools/cases_generator/tier1_generator.py b/Tools/cases_generator/tier1_generator.py index 13430524b26dcd..eed3086c327926 100644 --- a/Tools/cases_generator/tier1_generator.py +++ b/Tools/cases_generator/tier1_generator.py @@ -220,6 +220,8 @@ def generate_tier1_cases( if needs_this: out.emit(f"_Py_CODEUNIT* const this_instr = next_instr - {inst.size};\n") out.emit(unused_guard) + if inst.properties.uses_opcode: + out.emit(f"opcode = {name};\n") if inst.family is not None: out.emit( f"static_assert({inst.family.size} == {inst.size-1}" From 536ee25009fcec1dd2fb2f97f3111654fe595f15 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Fri, 31 Jan 2025 18:09:37 +0000 Subject: [PATCH 2/2] Remove support for GO_TO_INSTRUCTION --- Python/bytecodes.c | 1 - Tools/cases_generator/analyzer.py | 12 ------------ Tools/cases_generator/generators_common.py | 20 +------------------- 3 files changed, 1 insertion(+), 32 deletions(-) diff --git a/Python/bytecodes.c b/Python/bytecodes.c index e82c9f33f8b1a0..260cc4612fcd7b 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -45,7 +45,6 @@ #include "ceval_macros.h" /* Flow control macros */ -#define GO_TO_INSTRUCTION(instname) ((void)0) #define inst(name, ...) case name: #define op(name, ...) /* NAME is ignored */ diff --git a/Tools/cases_generator/analyzer.py b/Tools/cases_generator/analyzer.py index 7ae47a6ce95e3f..7e8668c9fb3df6 100644 --- a/Tools/cases_generator/analyzer.py +++ b/Tools/cases_generator/analyzer.py @@ -734,7 +734,6 @@ def find_escaping_api_calls(instr: parser.InstDef) -> dict[lexer.Token, tuple[le EXITS = { "DISPATCH", - "GO_TO_INSTRUCTION", "Py_UNREACHABLE", "DISPATCH_INLINED", "DISPATCH_GOTO", @@ -1183,17 +1182,6 @@ def analyze_forest(forest: list[parser.AstNode]) -> Analysis: add_label(node, labels) case _: pass - for uop in uops.values(): - tkn_iter = iter(uop.body) - for tkn in tkn_iter: - if tkn.kind == "IDENTIFIER" and tkn.text == "GO_TO_INSTRUCTION": - if next(tkn_iter).kind != "LPAREN": - continue - target = next(tkn_iter) - if target.kind != "IDENTIFIER": - continue - if target.text in instructions: - instructions[target.text].is_target = True for uop in uops.values(): uop.instruction_size = get_instruction_size_for_uop(instructions, uop) # Special case BINARY_OP_INPLACE_ADD_UNICODE diff --git a/Tools/cases_generator/generators_common.py b/Tools/cases_generator/generators_common.py index f1f166ae104ba5..09333d14ab6d34 100644 --- a/Tools/cases_generator/generators_common.py +++ b/Tools/cases_generator/generators_common.py @@ -126,8 +126,7 @@ def __init__(self, out: CWriter): "PyStackRef_AsPyObjectSteal": self.stackref_steal, "DISPATCH": self.dispatch, "INSTRUCTION_SIZE": self.instruction_size, - "POP_INPUT": self.pop_input, - "GO_TO_INSTRUCTION": self.go_to_instruction, + "POP_INPUT": self.pop_input } self.out = out @@ -406,23 +405,6 @@ def sync_sp( self._print_storage(storage) return True - def go_to_instruction( - self, - tkn: Token, - tkn_iter: TokenIterator, - uop: Uop, - storage: Storage, - inst: Instruction | None, - ) -> bool: - next(tkn_iter) - name = next(tkn_iter) - next(tkn_iter) - next(tkn_iter) - assert name.kind == "IDENTIFIER" - self.emit("\n") - self.emit(f"goto PREDICTED_{name.text};\n") - return True - def emit_save(self, storage: Storage) -> None: storage.save(self.out) self._print_storage(storage)