From 0b157abbb1a969a5da698fb3a8a427ddb4771104 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Fri, 26 Apr 2024 12:36:31 +0100 Subject: [PATCH 01/17] Add CALL_PY_GENERAL and CALL_BOUND_METHOD_GENERAL call specializations. --- Include/internal/pycore_opcode_metadata.h | 27 ++- Include/internal/pycore_uop_ids.h | 262 +++++++++++----------- Include/internal/pycore_uop_metadata.h | 24 ++ Include/opcode_ids.h | 117 +++++----- Lib/_opcode_metadata.py | 120 +++++----- Lib/test/test_dis.py | 2 +- Python/bytecodes.c | 98 ++++++++ Python/ceval.c | 2 + Python/executor_cases.c.h | 134 +++++++++++ Python/generated_cases.c.h | 208 +++++++++++++++++ Python/opcode_targets.h | 6 +- Python/optimizer_bytecodes.c | 11 +- Python/optimizer_cases.c.h | 54 ++++- Python/specialize.c | 40 ++-- Tools/cases_generator/analyzer.py | 1 + 15 files changed, 830 insertions(+), 276 deletions(-) diff --git a/Include/internal/pycore_opcode_metadata.h b/Include/internal/pycore_opcode_metadata.h index d10224c70f82f5..45df8bb8a8ff0c 100644 --- a/Include/internal/pycore_opcode_metadata.h +++ b/Include/internal/pycore_opcode_metadata.h @@ -95,6 +95,8 @@ int _PyOpcode_num_popped(int opcode, int oparg) { return 2 + oparg; case CALL_BOUND_METHOD_EXACT_ARGS: return 2 + oparg; + case CALL_BOUND_METHOD_GENERAL: + return 2 + oparg; case CALL_BUILTIN_CLASS: return 2 + oparg; case CALL_BUILTIN_FAST: @@ -125,8 +127,12 @@ int _PyOpcode_num_popped(int opcode, int oparg) { return 2 + oparg; case CALL_METHOD_DESCRIPTOR_O: return 2 + oparg; + case CALL_NON_PY_GENERAL: + return 2 + oparg; case CALL_PY_EXACT_ARGS: return 2 + oparg; + case CALL_PY_GENERAL: + return 2 + oparg; case CALL_PY_WITH_DEFAULTS: return 2 + oparg; case CALL_STR_1: @@ -524,6 +530,8 @@ int _PyOpcode_num_pushed(int opcode, int oparg) { return 1; case CALL_BOUND_METHOD_EXACT_ARGS: return 0; + case CALL_BOUND_METHOD_GENERAL: + return 0; case CALL_BUILTIN_CLASS: return 1; case CALL_BUILTIN_FAST: @@ -554,8 +562,12 @@ int _PyOpcode_num_pushed(int opcode, int oparg) { return 1; case CALL_METHOD_DESCRIPTOR_O: return 1; + case CALL_NON_PY_GENERAL: + return 1; case CALL_PY_EXACT_ARGS: return 0; + case CALL_PY_GENERAL: + return 0; case CALL_PY_WITH_DEFAULTS: return 1; case CALL_STR_1: @@ -985,6 +997,7 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[268] = { [CALL] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, [CALL_ALLOC_AND_ENTER_INIT] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, [CALL_BOUND_METHOD_EXACT_ARGS] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG }, + [CALL_BOUND_METHOD_GENERAL] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, [CALL_BUILTIN_CLASS] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [CALL_BUILTIN_FAST] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [CALL_BUILTIN_FAST_WITH_KEYWORDS] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, @@ -1000,7 +1013,9 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[268] = { [CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [CALL_METHOD_DESCRIPTOR_NOARGS] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [CALL_METHOD_DESCRIPTOR_O] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, + [CALL_NON_PY_GENERAL] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [CALL_PY_EXACT_ARGS] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG }, + [CALL_PY_GENERAL] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, [CALL_PY_WITH_DEFAULTS] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_DEOPT_FLAG }, [CALL_STR_1] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [CALL_TUPLE_1] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, @@ -1211,6 +1226,7 @@ _PyOpcode_macro_expansion[256] = { [BUILD_STRING] = { .nuops = 1, .uops = { { _BUILD_STRING, 0, 0 } } }, [BUILD_TUPLE] = { .nuops = 1, .uops = { { _BUILD_TUPLE, 0, 0 } } }, [CALL_BOUND_METHOD_EXACT_ARGS] = { .nuops = 8, .uops = { { _CHECK_PEP_523, 0, 0 }, { _CHECK_CALL_BOUND_METHOD_EXACT_ARGS, 0, 0 }, { _INIT_CALL_BOUND_METHOD_EXACT_ARGS, 0, 0 }, { _CHECK_FUNCTION_EXACT_ARGS, 2, 1 }, { _CHECK_STACK_SPACE, 0, 0 }, { _INIT_CALL_PY_EXACT_ARGS, 0, 0 }, { _SAVE_RETURN_OFFSET, 7, 3 }, { _PUSH_FRAME, 0, 0 } } }, + [CALL_BOUND_METHOD_GENERAL] = { .nuops = 5, .uops = { { _CHECK_PEP_523, 0, 0 }, { _CHECK_IS_METHOD, 0, 0 }, { _EXPAND_METHOD, 0, 0 }, { _CALL_PY_GENERAL, 0, 0 }, { _PUSH_FRAME, 0, 0 } } }, [CALL_BUILTIN_CLASS] = { .nuops = 2, .uops = { { _CALL_BUILTIN_CLASS, 0, 0 }, { _CHECK_PERIODIC, 0, 0 } } }, [CALL_BUILTIN_FAST] = { .nuops = 2, .uops = { { _CALL_BUILTIN_FAST, 0, 0 }, { _CHECK_PERIODIC, 0, 0 } } }, [CALL_BUILTIN_FAST_WITH_KEYWORDS] = { .nuops = 2, .uops = { { _CALL_BUILTIN_FAST_WITH_KEYWORDS, 0, 0 }, { _CHECK_PERIODIC, 0, 0 } } }, @@ -1223,7 +1239,9 @@ _PyOpcode_macro_expansion[256] = { [CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS] = { .nuops = 2, .uops = { { _CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS, 0, 0 }, { _CHECK_PERIODIC, 0, 0 } } }, [CALL_METHOD_DESCRIPTOR_NOARGS] = { .nuops = 2, .uops = { { _CALL_METHOD_DESCRIPTOR_NOARGS, 0, 0 }, { _CHECK_PERIODIC, 0, 0 } } }, [CALL_METHOD_DESCRIPTOR_O] = { .nuops = 2, .uops = { { _CALL_METHOD_DESCRIPTOR_O, 0, 0 }, { _CHECK_PERIODIC, 0, 0 } } }, + [CALL_NON_PY_GENERAL] = { .nuops = 4, .uops = { { _CHECK_IS_NOT_PY_CALLABLE, 0, 0 }, { _EXPAND_METHOD, 0, 0 }, { _CALL_NON_PY_GENERAL, 0, 0 }, { _CHECK_PERIODIC, 0, 0 } } }, [CALL_PY_EXACT_ARGS] = { .nuops = 6, .uops = { { _CHECK_PEP_523, 0, 0 }, { _CHECK_FUNCTION_EXACT_ARGS, 2, 1 }, { _CHECK_STACK_SPACE, 0, 0 }, { _INIT_CALL_PY_EXACT_ARGS, 0, 0 }, { _SAVE_RETURN_OFFSET, 7, 3 }, { _PUSH_FRAME, 0, 0 } } }, + [CALL_PY_GENERAL] = { .nuops = 4, .uops = { { _CHECK_PEP_523, 0, 0 }, { _CHECK_IS_FUNCTION, 0, 0 }, { _CALL_PY_GENERAL, 0, 0 }, { _PUSH_FRAME, 0, 0 } } }, [CALL_STR_1] = { .nuops = 2, .uops = { { _CALL_STR_1, 0, 0 }, { _CHECK_PERIODIC, 0, 0 } } }, [CALL_TUPLE_1] = { .nuops = 2, .uops = { { _CALL_TUPLE_1, 0, 0 }, { _CHECK_PERIODIC, 0, 0 } } }, [CALL_TYPE_1] = { .nuops = 1, .uops = { { _CALL_TYPE_1, 0, 0 } } }, @@ -1383,6 +1401,7 @@ const char *_PyOpcode_OpName[268] = { [CALL] = "CALL", [CALL_ALLOC_AND_ENTER_INIT] = "CALL_ALLOC_AND_ENTER_INIT", [CALL_BOUND_METHOD_EXACT_ARGS] = "CALL_BOUND_METHOD_EXACT_ARGS", + [CALL_BOUND_METHOD_GENERAL] = "CALL_BOUND_METHOD_GENERAL", [CALL_BUILTIN_CLASS] = "CALL_BUILTIN_CLASS", [CALL_BUILTIN_FAST] = "CALL_BUILTIN_FAST", [CALL_BUILTIN_FAST_WITH_KEYWORDS] = "CALL_BUILTIN_FAST_WITH_KEYWORDS", @@ -1398,7 +1417,9 @@ const char *_PyOpcode_OpName[268] = { [CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS] = "CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS", [CALL_METHOD_DESCRIPTOR_NOARGS] = "CALL_METHOD_DESCRIPTOR_NOARGS", [CALL_METHOD_DESCRIPTOR_O] = "CALL_METHOD_DESCRIPTOR_O", + [CALL_NON_PY_GENERAL] = "CALL_NON_PY_GENERAL", [CALL_PY_EXACT_ARGS] = "CALL_PY_EXACT_ARGS", + [CALL_PY_GENERAL] = "CALL_PY_GENERAL", [CALL_PY_WITH_DEFAULTS] = "CALL_PY_WITH_DEFAULTS", [CALL_STR_1] = "CALL_STR_1", [CALL_TUPLE_1] = "CALL_TUPLE_1", @@ -1636,6 +1657,7 @@ const uint8_t _PyOpcode_Deopt[256] = { [CALL] = CALL, [CALL_ALLOC_AND_ENTER_INIT] = CALL, [CALL_BOUND_METHOD_EXACT_ARGS] = CALL, + [CALL_BOUND_METHOD_GENERAL] = CALL, [CALL_BUILTIN_CLASS] = CALL, [CALL_BUILTIN_FAST] = CALL, [CALL_BUILTIN_FAST_WITH_KEYWORDS] = CALL, @@ -1651,7 +1673,9 @@ const uint8_t _PyOpcode_Deopt[256] = { [CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS] = CALL, [CALL_METHOD_DESCRIPTOR_NOARGS] = CALL, [CALL_METHOD_DESCRIPTOR_O] = CALL, + [CALL_NON_PY_GENERAL] = CALL, [CALL_PY_EXACT_ARGS] = CALL, + [CALL_PY_GENERAL] = CALL, [CALL_PY_WITH_DEFAULTS] = CALL, [CALL_STR_1] = CALL, [CALL_TUPLE_1] = CALL, @@ -1852,9 +1876,6 @@ const uint8_t _PyOpcode_Deopt[256] = { case 146: \ case 147: \ case 148: \ - case 221: \ - case 222: \ - case 223: \ case 224: \ case 225: \ case 226: \ diff --git a/Include/internal/pycore_uop_ids.h b/Include/internal/pycore_uop_ids.h index aa3940456b62f2..a2d8090a17d0af 100644 --- a/Include/internal/pycore_uop_ids.h +++ b/Include/internal/pycore_uop_ids.h @@ -51,32 +51,37 @@ extern "C" { #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_PY_GENERAL 321 #define _CALL_PY_WITH_DEFAULTS CALL_PY_WITH_DEFAULTS -#define _CALL_STR_1 320 -#define _CALL_TUPLE_1 321 +#define _CALL_STR_1 322 +#define _CALL_TUPLE_1 323 #define _CALL_TYPE_1 CALL_TYPE_1 -#define _CHECK_ATTR_CLASS 322 -#define _CHECK_ATTR_METHOD_LAZY_DICT 323 -#define _CHECK_ATTR_MODULE 324 -#define _CHECK_ATTR_WITH_HINT 325 -#define _CHECK_CALL_BOUND_METHOD_EXACT_ARGS 326 +#define _CHECK_ATTR_CLASS 324 +#define _CHECK_ATTR_METHOD_LAZY_DICT 325 +#define _CHECK_ATTR_MODULE 326 +#define _CHECK_ATTR_WITH_HINT 327 +#define _CHECK_CALL_BOUND_METHOD_EXACT_ARGS 328 #define _CHECK_EG_MATCH CHECK_EG_MATCH #define _CHECK_EXC_MATCH CHECK_EXC_MATCH -#define _CHECK_FUNCTION 327 -#define _CHECK_FUNCTION_EXACT_ARGS 328 -#define _CHECK_MANAGED_OBJECT_HAS_VALUES 329 -#define _CHECK_PEP_523 330 -#define _CHECK_PERIODIC 331 -#define _CHECK_STACK_SPACE 332 -#define _CHECK_STACK_SPACE_OPERAND 333 -#define _CHECK_VALIDITY 334 -#define _CHECK_VALIDITY_AND_SET_IP 335 -#define _COLD_EXIT 336 -#define _COMPARE_OP 337 -#define _COMPARE_OP_FLOAT 338 -#define _COMPARE_OP_INT 339 -#define _COMPARE_OP_STR 340 -#define _CONTAINS_OP 341 +#define _CHECK_FUNCTION 329 +#define _CHECK_FUNCTION_EXACT_ARGS 330 +#define _CHECK_IS_FUNCTION 331 +#define _CHECK_IS_METHOD 332 +#define _CHECK_IS_NOT_PY_CALLABLE 333 +#define _CHECK_MANAGED_OBJECT_HAS_VALUES 334 +#define _CHECK_PEP_523 335 +#define _CHECK_PERIODIC 336 +#define _CHECK_STACK_SPACE 337 +#define _CHECK_STACK_SPACE_OPERAND 338 +#define _CHECK_VALIDITY 339 +#define _CHECK_VALIDITY_AND_SET_IP 340 +#define _COLD_EXIT 341 +#define _COMPARE_OP 342 +#define _COMPARE_OP_FLOAT 343 +#define _COMPARE_OP_INT 344 +#define _COMPARE_OP_STR 345 +#define _CONTAINS_OP 346 #define _CONTAINS_OP_DICT CONTAINS_OP_DICT #define _CONTAINS_OP_SET CONTAINS_OP_SET #define _CONVERT_VALUE CONVERT_VALUE @@ -88,52 +93,53 @@ extern "C" { #define _DELETE_GLOBAL DELETE_GLOBAL #define _DELETE_NAME DELETE_NAME #define _DELETE_SUBSCR DELETE_SUBSCR -#define _DEOPT 342 +#define _DEOPT 347 #define _DICT_MERGE DICT_MERGE #define _DICT_UPDATE DICT_UPDATE -#define _DYNAMIC_EXIT 343 +#define _DYNAMIC_EXIT 348 #define _END_SEND END_SEND -#define _ERROR_POP_N 344 +#define _ERROR_POP_N 349 #define _EXIT_INIT_CHECK EXIT_INIT_CHECK -#define _FATAL_ERROR 345 +#define _EXPAND_METHOD 350 +#define _FATAL_ERROR 351 #define _FORMAT_SIMPLE FORMAT_SIMPLE #define _FORMAT_WITH_SPEC FORMAT_WITH_SPEC -#define _FOR_ITER 346 -#define _FOR_ITER_GEN_FRAME 347 -#define _FOR_ITER_TIER_TWO 348 +#define _FOR_ITER 352 +#define _FOR_ITER_GEN_FRAME 353 +#define _FOR_ITER_TIER_TWO 354 #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 349 -#define _GUARD_BOTH_INT 350 -#define _GUARD_BOTH_UNICODE 351 -#define _GUARD_BUILTINS_VERSION 352 -#define _GUARD_DORV_NO_DICT 353 -#define _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT 354 -#define _GUARD_GLOBALS_VERSION 355 -#define _GUARD_IS_FALSE_POP 356 -#define _GUARD_IS_NONE_POP 357 -#define _GUARD_IS_NOT_NONE_POP 358 -#define _GUARD_IS_TRUE_POP 359 -#define _GUARD_KEYS_VERSION 360 -#define _GUARD_NOS_FLOAT 361 -#define _GUARD_NOS_INT 362 -#define _GUARD_NOT_EXHAUSTED_LIST 363 -#define _GUARD_NOT_EXHAUSTED_RANGE 364 -#define _GUARD_NOT_EXHAUSTED_TUPLE 365 -#define _GUARD_TOS_FLOAT 366 -#define _GUARD_TOS_INT 367 -#define _GUARD_TYPE_VERSION 368 -#define _INIT_CALL_BOUND_METHOD_EXACT_ARGS 369 -#define _INIT_CALL_PY_EXACT_ARGS 370 -#define _INIT_CALL_PY_EXACT_ARGS_0 371 -#define _INIT_CALL_PY_EXACT_ARGS_1 372 -#define _INIT_CALL_PY_EXACT_ARGS_2 373 -#define _INIT_CALL_PY_EXACT_ARGS_3 374 -#define _INIT_CALL_PY_EXACT_ARGS_4 375 +#define _GUARD_BOTH_FLOAT 355 +#define _GUARD_BOTH_INT 356 +#define _GUARD_BOTH_UNICODE 357 +#define _GUARD_BUILTINS_VERSION 358 +#define _GUARD_DORV_NO_DICT 359 +#define _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT 360 +#define _GUARD_GLOBALS_VERSION 361 +#define _GUARD_IS_FALSE_POP 362 +#define _GUARD_IS_NONE_POP 363 +#define _GUARD_IS_NOT_NONE_POP 364 +#define _GUARD_IS_TRUE_POP 365 +#define _GUARD_KEYS_VERSION 366 +#define _GUARD_NOS_FLOAT 367 +#define _GUARD_NOS_INT 368 +#define _GUARD_NOT_EXHAUSTED_LIST 369 +#define _GUARD_NOT_EXHAUSTED_RANGE 370 +#define _GUARD_NOT_EXHAUSTED_TUPLE 371 +#define _GUARD_TOS_FLOAT 372 +#define _GUARD_TOS_INT 373 +#define _GUARD_TYPE_VERSION 374 +#define _INIT_CALL_BOUND_METHOD_EXACT_ARGS 375 +#define _INIT_CALL_PY_EXACT_ARGS 376 +#define _INIT_CALL_PY_EXACT_ARGS_0 377 +#define _INIT_CALL_PY_EXACT_ARGS_1 378 +#define _INIT_CALL_PY_EXACT_ARGS_2 379 +#define _INIT_CALL_PY_EXACT_ARGS_3 380 +#define _INIT_CALL_PY_EXACT_ARGS_4 381 #define _INSTRUMENTED_CALL INSTRUMENTED_CALL #define _INSTRUMENTED_CALL_FUNCTION_EX INSTRUMENTED_CALL_FUNCTION_EX #define _INSTRUMENTED_CALL_KW INSTRUMENTED_CALL_KW @@ -150,65 +156,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 376 -#define _IS_NONE 377 +#define _INTERNAL_INCREMENT_OPT_COUNTER 382 +#define _IS_NONE 383 #define _IS_OP IS_OP -#define _ITER_CHECK_LIST 378 -#define _ITER_CHECK_RANGE 379 -#define _ITER_CHECK_TUPLE 380 -#define _ITER_JUMP_LIST 381 -#define _ITER_JUMP_RANGE 382 -#define _ITER_JUMP_TUPLE 383 -#define _ITER_NEXT_LIST 384 -#define _ITER_NEXT_RANGE 385 -#define _ITER_NEXT_TUPLE 386 -#define _JUMP_TO_TOP 387 +#define _ITER_CHECK_LIST 384 +#define _ITER_CHECK_RANGE 385 +#define _ITER_CHECK_TUPLE 386 +#define _ITER_JUMP_LIST 387 +#define _ITER_JUMP_RANGE 388 +#define _ITER_JUMP_TUPLE 389 +#define _ITER_NEXT_LIST 390 +#define _ITER_NEXT_RANGE 391 +#define _ITER_NEXT_TUPLE 392 +#define _JUMP_TO_TOP 393 #define _LIST_APPEND LIST_APPEND #define _LIST_EXTEND LIST_EXTEND #define _LOAD_ASSERTION_ERROR LOAD_ASSERTION_ERROR -#define _LOAD_ATTR 388 -#define _LOAD_ATTR_CLASS 389 -#define _LOAD_ATTR_CLASS_0 390 -#define _LOAD_ATTR_CLASS_1 391 +#define _LOAD_ATTR 394 +#define _LOAD_ATTR_CLASS 395 +#define _LOAD_ATTR_CLASS_0 396 +#define _LOAD_ATTR_CLASS_1 397 #define _LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN -#define _LOAD_ATTR_INSTANCE_VALUE 392 -#define _LOAD_ATTR_INSTANCE_VALUE_0 393 -#define _LOAD_ATTR_INSTANCE_VALUE_1 394 -#define _LOAD_ATTR_METHOD_LAZY_DICT 395 -#define _LOAD_ATTR_METHOD_NO_DICT 396 -#define _LOAD_ATTR_METHOD_WITH_VALUES 397 -#define _LOAD_ATTR_MODULE 398 -#define _LOAD_ATTR_NONDESCRIPTOR_NO_DICT 399 -#define _LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES 400 +#define _LOAD_ATTR_INSTANCE_VALUE 398 +#define _LOAD_ATTR_INSTANCE_VALUE_0 399 +#define _LOAD_ATTR_INSTANCE_VALUE_1 400 +#define _LOAD_ATTR_METHOD_LAZY_DICT 401 +#define _LOAD_ATTR_METHOD_NO_DICT 402 +#define _LOAD_ATTR_METHOD_WITH_VALUES 403 +#define _LOAD_ATTR_MODULE 404 +#define _LOAD_ATTR_NONDESCRIPTOR_NO_DICT 405 +#define _LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES 406 #define _LOAD_ATTR_PROPERTY LOAD_ATTR_PROPERTY -#define _LOAD_ATTR_SLOT 401 -#define _LOAD_ATTR_SLOT_0 402 -#define _LOAD_ATTR_SLOT_1 403 -#define _LOAD_ATTR_WITH_HINT 404 +#define _LOAD_ATTR_SLOT 407 +#define _LOAD_ATTR_SLOT_0 408 +#define _LOAD_ATTR_SLOT_1 409 +#define _LOAD_ATTR_WITH_HINT 410 #define _LOAD_BUILD_CLASS LOAD_BUILD_CLASS #define _LOAD_CONST LOAD_CONST -#define _LOAD_CONST_INLINE 405 -#define _LOAD_CONST_INLINE_BORROW 406 -#define _LOAD_CONST_INLINE_BORROW_WITH_NULL 407 -#define _LOAD_CONST_INLINE_WITH_NULL 408 +#define _LOAD_CONST_INLINE 411 +#define _LOAD_CONST_INLINE_BORROW 412 +#define _LOAD_CONST_INLINE_BORROW_WITH_NULL 413 +#define _LOAD_CONST_INLINE_WITH_NULL 414 #define _LOAD_DEREF LOAD_DEREF -#define _LOAD_FAST 409 -#define _LOAD_FAST_0 410 -#define _LOAD_FAST_1 411 -#define _LOAD_FAST_2 412 -#define _LOAD_FAST_3 413 -#define _LOAD_FAST_4 414 -#define _LOAD_FAST_5 415 -#define _LOAD_FAST_6 416 -#define _LOAD_FAST_7 417 +#define _LOAD_FAST 415 +#define _LOAD_FAST_0 416 +#define _LOAD_FAST_1 417 +#define _LOAD_FAST_2 418 +#define _LOAD_FAST_3 419 +#define _LOAD_FAST_4 420 +#define _LOAD_FAST_5 421 +#define _LOAD_FAST_6 422 +#define _LOAD_FAST_7 423 #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 418 -#define _LOAD_GLOBAL_BUILTINS 419 -#define _LOAD_GLOBAL_MODULE 420 +#define _LOAD_GLOBAL 424 +#define _LOAD_GLOBAL_BUILTINS 425 +#define _LOAD_GLOBAL_MODULE 426 #define _LOAD_LOCALS LOAD_LOCALS #define _LOAD_NAME LOAD_NAME #define _LOAD_SUPER_ATTR_ATTR LOAD_SUPER_ATTR_ATTR @@ -222,51 +228,51 @@ extern "C" { #define _MATCH_SEQUENCE MATCH_SEQUENCE #define _NOP NOP #define _POP_EXCEPT POP_EXCEPT -#define _POP_FRAME 421 -#define _POP_JUMP_IF_FALSE 422 -#define _POP_JUMP_IF_TRUE 423 +#define _POP_FRAME 427 +#define _POP_JUMP_IF_FALSE 428 +#define _POP_JUMP_IF_TRUE 429 #define _POP_TOP POP_TOP -#define _POP_TOP_LOAD_CONST_INLINE_BORROW 424 +#define _POP_TOP_LOAD_CONST_INLINE_BORROW 430 #define _PUSH_EXC_INFO PUSH_EXC_INFO -#define _PUSH_FRAME 425 +#define _PUSH_FRAME 431 #define _PUSH_NULL PUSH_NULL -#define _REPLACE_WITH_TRUE 426 +#define _REPLACE_WITH_TRUE 432 #define _RESUME_CHECK RESUME_CHECK #define _RETURN_GENERATOR RETURN_GENERATOR -#define _SAVE_RETURN_OFFSET 427 -#define _SEND 428 +#define _SAVE_RETURN_OFFSET 433 +#define _SEND 434 #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 _SIDE_EXIT 429 -#define _START_EXECUTOR 430 -#define _STORE_ATTR 431 -#define _STORE_ATTR_INSTANCE_VALUE 432 -#define _STORE_ATTR_SLOT 433 +#define _SIDE_EXIT 435 +#define _START_EXECUTOR 436 +#define _STORE_ATTR 437 +#define _STORE_ATTR_INSTANCE_VALUE 438 +#define _STORE_ATTR_SLOT 439 #define _STORE_ATTR_WITH_HINT STORE_ATTR_WITH_HINT #define _STORE_DEREF STORE_DEREF -#define _STORE_FAST 434 -#define _STORE_FAST_0 435 -#define _STORE_FAST_1 436 -#define _STORE_FAST_2 437 -#define _STORE_FAST_3 438 -#define _STORE_FAST_4 439 -#define _STORE_FAST_5 440 -#define _STORE_FAST_6 441 -#define _STORE_FAST_7 442 +#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_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 443 +#define _STORE_SUBSCR 449 #define _STORE_SUBSCR_DICT STORE_SUBSCR_DICT #define _STORE_SUBSCR_LIST_INT STORE_SUBSCR_LIST_INT #define _SWAP SWAP -#define _TIER2_RESUME_CHECK 444 -#define _TO_BOOL 445 +#define _TIER2_RESUME_CHECK 450 +#define _TO_BOOL 451 #define _TO_BOOL_BOOL TO_BOOL_BOOL #define _TO_BOOL_INT TO_BOOL_INT #define _TO_BOOL_LIST TO_BOOL_LIST @@ -276,13 +282,13 @@ extern "C" { #define _UNARY_NEGATIVE UNARY_NEGATIVE #define _UNARY_NOT UNARY_NOT #define _UNPACK_EX UNPACK_EX -#define _UNPACK_SEQUENCE 446 +#define _UNPACK_SEQUENCE 452 #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 446 +#define MAX_UOP_ID 452 #ifdef __cplusplus } diff --git a/Include/internal/pycore_uop_metadata.h b/Include/internal/pycore_uop_metadata.h index d0860024e0db4d..7f6090c23b590e 100644 --- a/Include/internal/pycore_uop_metadata.h +++ b/Include/internal/pycore_uop_metadata.h @@ -193,6 +193,12 @@ const uint16_t _PyUop_Flags[MAX_UOP_ID+1] = { [_CHECK_ATTR_METHOD_LAZY_DICT] = HAS_DEOPT_FLAG, [_LOAD_ATTR_METHOD_LAZY_DICT] = HAS_ARG_FLAG, [_CHECK_PERIODIC] = HAS_EVAL_BREAK_FLAG, + [_CALL_PY_GENERAL] = HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG, + [_CHECK_IS_FUNCTION] = HAS_ARG_FLAG | HAS_DEOPT_FLAG, + [_CHECK_IS_METHOD] = HAS_ARG_FLAG | HAS_DEOPT_FLAG, + [_EXPAND_METHOD] = HAS_ARG_FLAG, + [_CHECK_IS_NOT_PY_CALLABLE] = HAS_ARG_FLAG | HAS_DEOPT_FLAG, + [_CALL_NON_PY_GENERAL] = HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, [_CHECK_CALL_BOUND_METHOD_EXACT_ARGS] = HAS_ARG_FLAG | HAS_DEOPT_FLAG, [_INIT_CALL_BOUND_METHOD_EXACT_ARGS] = HAS_ARG_FLAG, [_CHECK_PEP_523] = HAS_DEOPT_FLAG, @@ -296,6 +302,8 @@ const char *const _PyOpcode_uop_name[MAX_UOP_ID+1] = { [_CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS] = "_CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS", [_CALL_METHOD_DESCRIPTOR_NOARGS] = "_CALL_METHOD_DESCRIPTOR_NOARGS", [_CALL_METHOD_DESCRIPTOR_O] = "_CALL_METHOD_DESCRIPTOR_O", + [_CALL_NON_PY_GENERAL] = "_CALL_NON_PY_GENERAL", + [_CALL_PY_GENERAL] = "_CALL_PY_GENERAL", [_CALL_STR_1] = "_CALL_STR_1", [_CALL_TUPLE_1] = "_CALL_TUPLE_1", [_CALL_TYPE_1] = "_CALL_TYPE_1", @@ -308,6 +316,9 @@ const char *const _PyOpcode_uop_name[MAX_UOP_ID+1] = { [_CHECK_EXC_MATCH] = "_CHECK_EXC_MATCH", [_CHECK_FUNCTION] = "_CHECK_FUNCTION", [_CHECK_FUNCTION_EXACT_ARGS] = "_CHECK_FUNCTION_EXACT_ARGS", + [_CHECK_IS_FUNCTION] = "_CHECK_IS_FUNCTION", + [_CHECK_IS_METHOD] = "_CHECK_IS_METHOD", + [_CHECK_IS_NOT_PY_CALLABLE] = "_CHECK_IS_NOT_PY_CALLABLE", [_CHECK_MANAGED_OBJECT_HAS_VALUES] = "_CHECK_MANAGED_OBJECT_HAS_VALUES", [_CHECK_PEP_523] = "_CHECK_PEP_523", [_CHECK_PERIODIC] = "_CHECK_PERIODIC", @@ -340,6 +351,7 @@ const char *const _PyOpcode_uop_name[MAX_UOP_ID+1] = { [_ERROR_POP_N] = "_ERROR_POP_N", [_EXIT_INIT_CHECK] = "_EXIT_INIT_CHECK", [_EXIT_TRACE] = "_EXIT_TRACE", + [_EXPAND_METHOD] = "_EXPAND_METHOD", [_FATAL_ERROR] = "_FATAL_ERROR", [_FORMAT_SIMPLE] = "_FORMAT_SIMPLE", [_FORMAT_WITH_SPEC] = "_FORMAT_WITH_SPEC", @@ -852,6 +864,18 @@ int _PyUop_num_popped(int opcode, int oparg) return 1; case _CHECK_PERIODIC: return 0; + case _CALL_PY_GENERAL: + return 2 + oparg; + case _CHECK_IS_FUNCTION: + return 2 + oparg; + case _CHECK_IS_METHOD: + return 2 + oparg; + case _EXPAND_METHOD: + return 2 + oparg; + case _CHECK_IS_NOT_PY_CALLABLE: + return 2 + oparg; + case _CALL_NON_PY_GENERAL: + return 2 + oparg; case _CHECK_CALL_BOUND_METHOD_EXACT_ARGS: return 2 + oparg; case _INIT_CALL_BOUND_METHOD_EXACT_ARGS: diff --git a/Include/opcode_ids.h b/Include/opcode_ids.h index 185205c6870edc..4e9825a0132668 100644 --- a/Include/opcode_ids.h +++ b/Include/opcode_ids.h @@ -144,63 +144,66 @@ extern "C" { #define BINARY_SUBSCR_TUPLE_INT 161 #define CALL_ALLOC_AND_ENTER_INIT 162 #define CALL_BOUND_METHOD_EXACT_ARGS 163 -#define CALL_BUILTIN_CLASS 164 -#define CALL_BUILTIN_FAST 165 -#define CALL_BUILTIN_FAST_WITH_KEYWORDS 166 -#define CALL_BUILTIN_O 167 -#define CALL_ISINSTANCE 168 -#define CALL_LEN 169 -#define CALL_LIST_APPEND 170 -#define CALL_METHOD_DESCRIPTOR_FAST 171 -#define CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS 172 -#define CALL_METHOD_DESCRIPTOR_NOARGS 173 -#define CALL_METHOD_DESCRIPTOR_O 174 -#define CALL_PY_EXACT_ARGS 175 -#define CALL_PY_WITH_DEFAULTS 176 -#define CALL_STR_1 177 -#define CALL_TUPLE_1 178 -#define CALL_TYPE_1 179 -#define COMPARE_OP_FLOAT 180 -#define COMPARE_OP_INT 181 -#define COMPARE_OP_STR 182 -#define CONTAINS_OP_DICT 183 -#define CONTAINS_OP_SET 184 -#define FOR_ITER_GEN 185 -#define FOR_ITER_LIST 186 -#define FOR_ITER_RANGE 187 -#define FOR_ITER_TUPLE 188 -#define LOAD_ATTR_CLASS 189 -#define LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN 190 -#define LOAD_ATTR_INSTANCE_VALUE 191 -#define LOAD_ATTR_METHOD_LAZY_DICT 192 -#define LOAD_ATTR_METHOD_NO_DICT 193 -#define LOAD_ATTR_METHOD_WITH_VALUES 194 -#define LOAD_ATTR_MODULE 195 -#define LOAD_ATTR_NONDESCRIPTOR_NO_DICT 196 -#define LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES 197 -#define LOAD_ATTR_PROPERTY 198 -#define LOAD_ATTR_SLOT 199 -#define LOAD_ATTR_WITH_HINT 200 -#define LOAD_GLOBAL_BUILTIN 201 -#define LOAD_GLOBAL_MODULE 202 -#define LOAD_SUPER_ATTR_ATTR 203 -#define LOAD_SUPER_ATTR_METHOD 204 -#define RESUME_CHECK 205 -#define SEND_GEN 206 -#define STORE_ATTR_INSTANCE_VALUE 207 -#define STORE_ATTR_SLOT 208 -#define STORE_ATTR_WITH_HINT 209 -#define STORE_SUBSCR_DICT 210 -#define STORE_SUBSCR_LIST_INT 211 -#define TO_BOOL_ALWAYS_TRUE 212 -#define TO_BOOL_BOOL 213 -#define TO_BOOL_INT 214 -#define TO_BOOL_LIST 215 -#define TO_BOOL_NONE 216 -#define TO_BOOL_STR 217 -#define UNPACK_SEQUENCE_LIST 218 -#define UNPACK_SEQUENCE_TUPLE 219 -#define UNPACK_SEQUENCE_TWO_TUPLE 220 +#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_PY_WITH_DEFAULTS 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 b5bafe6302bc9e..462ab439e0caf8 100644 --- a/Lib/_opcode_metadata.py +++ b/Lib/_opcode_metadata.py @@ -104,6 +104,9 @@ "CALL_METHOD_DESCRIPTOR_NOARGS", "CALL_METHOD_DESCRIPTOR_FAST", "CALL_ALLOC_AND_ENTER_INIT", + "CALL_PY_GENERAL", + "CALL_BOUND_METHOD_GENERAL", + "CALL_NON_PY_GENERAL", ], } @@ -123,63 +126,66 @@ 'BINARY_SUBSCR_TUPLE_INT': 161, 'CALL_ALLOC_AND_ENTER_INIT': 162, 'CALL_BOUND_METHOD_EXACT_ARGS': 163, - 'CALL_BUILTIN_CLASS': 164, - 'CALL_BUILTIN_FAST': 165, - 'CALL_BUILTIN_FAST_WITH_KEYWORDS': 166, - 'CALL_BUILTIN_O': 167, - 'CALL_ISINSTANCE': 168, - 'CALL_LEN': 169, - 'CALL_LIST_APPEND': 170, - 'CALL_METHOD_DESCRIPTOR_FAST': 171, - 'CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS': 172, - 'CALL_METHOD_DESCRIPTOR_NOARGS': 173, - 'CALL_METHOD_DESCRIPTOR_O': 174, - 'CALL_PY_EXACT_ARGS': 175, - 'CALL_PY_WITH_DEFAULTS': 176, - 'CALL_STR_1': 177, - 'CALL_TUPLE_1': 178, - 'CALL_TYPE_1': 179, - 'COMPARE_OP_FLOAT': 180, - 'COMPARE_OP_INT': 181, - 'COMPARE_OP_STR': 182, - 'CONTAINS_OP_DICT': 183, - 'CONTAINS_OP_SET': 184, - 'FOR_ITER_GEN': 185, - 'FOR_ITER_LIST': 186, - 'FOR_ITER_RANGE': 187, - 'FOR_ITER_TUPLE': 188, - 'LOAD_ATTR_CLASS': 189, - 'LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN': 190, - 'LOAD_ATTR_INSTANCE_VALUE': 191, - 'LOAD_ATTR_METHOD_LAZY_DICT': 192, - 'LOAD_ATTR_METHOD_NO_DICT': 193, - 'LOAD_ATTR_METHOD_WITH_VALUES': 194, - 'LOAD_ATTR_MODULE': 195, - 'LOAD_ATTR_NONDESCRIPTOR_NO_DICT': 196, - 'LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES': 197, - 'LOAD_ATTR_PROPERTY': 198, - 'LOAD_ATTR_SLOT': 199, - 'LOAD_ATTR_WITH_HINT': 200, - 'LOAD_GLOBAL_BUILTIN': 201, - 'LOAD_GLOBAL_MODULE': 202, - 'LOAD_SUPER_ATTR_ATTR': 203, - 'LOAD_SUPER_ATTR_METHOD': 204, - 'RESUME_CHECK': 205, - 'SEND_GEN': 206, - 'STORE_ATTR_INSTANCE_VALUE': 207, - 'STORE_ATTR_SLOT': 208, - 'STORE_ATTR_WITH_HINT': 209, - 'STORE_SUBSCR_DICT': 210, - 'STORE_SUBSCR_LIST_INT': 211, - 'TO_BOOL_ALWAYS_TRUE': 212, - 'TO_BOOL_BOOL': 213, - 'TO_BOOL_INT': 214, - 'TO_BOOL_LIST': 215, - 'TO_BOOL_NONE': 216, - 'TO_BOOL_STR': 217, - 'UNPACK_SEQUENCE_LIST': 218, - 'UNPACK_SEQUENCE_TUPLE': 219, - 'UNPACK_SEQUENCE_TWO_TUPLE': 220, + '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_PY_WITH_DEFAULTS': 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/test/test_dis.py b/Lib/test/test_dis.py index 747a73829fa705..b68ed3baadc652 100644 --- a/Lib/test/test_dis.py +++ b/Lib/test/test_dis.py @@ -840,7 +840,7 @@ def loop_test(): %3d LOAD_GLOBAL_MODULE 1 (load_test + NULL) LOAD_FAST 0 (i) - CALL_PY_WITH_DEFAULTS 1 + CALL_PY_GENERAL 1 POP_TOP JUMP_BACKWARD 16 (to L1) diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 9769cfe68aaeba..11e4d151e11313 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -3057,6 +3057,9 @@ dummy_func( CALL_METHOD_DESCRIPTOR_NOARGS, CALL_METHOD_DESCRIPTOR_FAST, CALL_ALLOC_AND_ENTER_INIT, + CALL_PY_GENERAL, + CALL_BOUND_METHOD_GENERAL, + CALL_NON_PY_GENERAL, }; specializing op(_SPECIALIZE_CALL, (counter/1, callable, self_or_null, args[oparg] -- callable, self_or_null, args[oparg])) { @@ -3146,6 +3149,101 @@ dummy_func( macro(CALL) = _SPECIALIZE_CALL + unused/2 + _CALL + _CHECK_PERIODIC; + op(_CALL_PY_GENERAL, (callable, self_or_null, args[oparg] -- new_frame: _PyInterpreterFrame*)) { + // oparg counts all of the args, but *not* self: + int total_args = oparg; + if (self_or_null != NULL) { + args--; + total_args++; + } + assert(Py_TYPE(callable) == &PyFunction_Type); + int code_flags = ((PyCodeObject*)PyFunction_GET_CODE(callable))->co_flags; + PyObject *locals = code_flags & CO_OPTIMIZED ? NULL : Py_NewRef(PyFunction_GET_GLOBALS(callable)); + new_frame = _PyEvalFramePushAndInit( + tstate, (PyFunctionObject *)callable, locals, + args, total_args, NULL + ); + // The frame has stolen all the arguments from the stack, + // so there is no need to clean them up. + SYNC_SP(); + if (new_frame == NULL) { + ERROR_NO_POP(); + } + frame->return_offset = (uint16_t)(1 + INLINE_CACHE_ENTRIES_CALL); + } + + op(_CHECK_IS_FUNCTION, (callable, unused, unused[oparg] -- callable, unused, unused[oparg])) { + DEOPT_IF(!PyFunction_Check(callable)); + } + + macro(CALL_PY_GENERAL) = + unused/1 + // Skip over the counter + unused/2 + + _CHECK_PEP_523 + + _CHECK_IS_FUNCTION + + _CALL_PY_GENERAL + + _PUSH_FRAME; + + op(_CHECK_IS_METHOD, (callable, null, unused[oparg] -- callable, null, unused[oparg])) { + DEOPT_IF(Py_TYPE(callable) != &PyMethod_Type); + DEOPT_IF(!PyFunction_Check(((PyMethodObject *)callable)->im_func)); + DEOPT_IF(null != NULL); + } + + op(_EXPAND_METHOD, (callable, null, unused[oparg] -- method, self, unused[oparg])) { + assert(null == NULL); + assert(Py_TYPE(callable) == &PyMethod_Type); + self = ((PyMethodObject *)callable)->im_self; + Py_INCREF(self); + stack_pointer[-1 - oparg] = self; // Patch stack as it is used by _CALL_PY_GENERAL + method = ((PyMethodObject *)callable)->im_func; + assert(PyFunction_Check(method)); + Py_INCREF(method); + Py_DECREF(callable); + } + + macro(CALL_BOUND_METHOD_GENERAL) = + unused/1 + // Skip over the counter + unused/2 + + _CHECK_PEP_523 + + _CHECK_IS_METHOD + + _EXPAND_METHOD + + _CALL_PY_GENERAL + + _PUSH_FRAME; + + op(_CHECK_IS_NOT_PY_CALLABLE, (callable, unused, unused[oparg] -- callable, unused, unused[oparg])) { + DEOPT_IF(PyFunction_Check(callable)); + DEOPT_IF(Py_TYPE(callable) == &PyMethod_Type); + } + + op(_CALL_NON_PY_GENERAL, (callable, self_or_null, args[oparg] -- res)) { + int total_args = oparg; + if (self_or_null != NULL) { + args--; + total_args++; + } + /* Callable is not a normal Python function */ + res = PyObject_Vectorcall( + callable, args, + total_args | PY_VECTORCALL_ARGUMENTS_OFFSET, + NULL); + assert(opcode != INSTRUMENTED_CALL); + assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); + Py_DECREF(callable); + for (int i = 0; i < total_args; i++) { + Py_DECREF(args[i]); + } + ERROR_IF(res == NULL, error); + } + + macro(CALL_NON_PY_GENERAL) = + unused/1 + // Skip over the counter + unused/2 + + _CHECK_IS_NOT_PY_CALLABLE + + _EXPAND_METHOD + + _CALL_NON_PY_GENERAL + + _CHECK_PERIODIC; + op(_CHECK_CALL_BOUND_METHOD_EXACT_ARGS, (callable, null, unused[oparg] -- callable, null, unused[oparg])) { DEOPT_IF(null != NULL); DEOPT_IF(Py_TYPE(callable) != &PyMethod_Type); diff --git a/Python/ceval.c b/Python/ceval.c index 59498bc826e941..a9696d7b775003 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -1730,6 +1730,8 @@ _PyEvalFramePushAndInit(PyThreadState *tstate, PyFunctionObject *func, return frame; fail: /* Consume the references */ + Py_DECREF(func); + Py_XDECREF(locals); for (size_t i = 0; i < argcount; i++) { Py_DECREF(args[i]); } diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index 03db9b623cbd86..59a5e4cdb789b0 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -3032,6 +3032,140 @@ break; } + case _CALL_PY_GENERAL: { + PyObject **args; + PyObject *self_or_null; + PyObject *callable; + _PyInterpreterFrame *new_frame; + oparg = CURRENT_OPARG(); + args = &stack_pointer[-oparg]; + self_or_null = stack_pointer[-1 - oparg]; + callable = stack_pointer[-2 - oparg]; + // oparg counts all of the args, but *not* self: + int total_args = oparg; + if (self_or_null != NULL) { + args--; + total_args++; + } + assert(Py_TYPE(callable) == &PyFunction_Type); + int code_flags = ((PyCodeObject*)PyFunction_GET_CODE(callable))->co_flags; + PyObject *locals = code_flags & CO_OPTIMIZED ? NULL : Py_NewRef(PyFunction_GET_GLOBALS(callable)); + new_frame = _PyEvalFramePushAndInit( + tstate, (PyFunctionObject *)callable, locals, + args, total_args, NULL + ); + // The frame has stolen all the arguments from the stack, + // so there is no need to clean them up. + stack_pointer += -2 - oparg; + if (new_frame == NULL) { + JUMP_TO_ERROR(); + } + frame->return_offset = (uint16_t)(1 + INLINE_CACHE_ENTRIES_CALL); + stack_pointer[0] = (PyObject *)new_frame; + stack_pointer += 1; + break; + } + + case _CHECK_IS_FUNCTION: { + PyObject *callable; + oparg = CURRENT_OPARG(); + callable = stack_pointer[-2 - oparg]; + if (!PyFunction_Check(callable)) { + UOP_STAT_INC(uopcode, miss); + JUMP_TO_JUMP_TARGET(); + } + break; + } + + case _CHECK_IS_METHOD: { + PyObject *null; + PyObject *callable; + oparg = CURRENT_OPARG(); + null = stack_pointer[-1 - oparg]; + callable = stack_pointer[-2 - oparg]; + if (Py_TYPE(callable) != &PyMethod_Type) { + UOP_STAT_INC(uopcode, miss); + JUMP_TO_JUMP_TARGET(); + } + if (!PyFunction_Check(((PyMethodObject *)callable)->im_func)) { + UOP_STAT_INC(uopcode, miss); + JUMP_TO_JUMP_TARGET(); + } + if (null != NULL) { + UOP_STAT_INC(uopcode, miss); + JUMP_TO_JUMP_TARGET(); + } + break; + } + + case _EXPAND_METHOD: { + PyObject *null; + PyObject *callable; + PyObject *method; + PyObject *self; + oparg = CURRENT_OPARG(); + null = stack_pointer[-1 - oparg]; + callable = stack_pointer[-2 - oparg]; + assert(null == NULL); + assert(Py_TYPE(callable) == &PyMethod_Type); + self = ((PyMethodObject *)callable)->im_self; + Py_INCREF(self); + stack_pointer[-1 - oparg] = self; // Patch stack as it is used by _CALL_PY_GENERAL + method = ((PyMethodObject *)callable)->im_func; + assert(PyFunction_Check(method)); + Py_INCREF(method); + Py_DECREF(callable); + stack_pointer[-2 - oparg] = method; + stack_pointer[-1 - oparg] = self; + break; + } + + case _CHECK_IS_NOT_PY_CALLABLE: { + PyObject *callable; + oparg = CURRENT_OPARG(); + callable = stack_pointer[-2 - oparg]; + if (PyFunction_Check(callable)) { + UOP_STAT_INC(uopcode, miss); + JUMP_TO_JUMP_TARGET(); + } + if (Py_TYPE(callable) == &PyMethod_Type) { + UOP_STAT_INC(uopcode, miss); + JUMP_TO_JUMP_TARGET(); + } + break; + } + + case _CALL_NON_PY_GENERAL: { + PyObject **args; + PyObject *self_or_null; + PyObject *callable; + PyObject *res; + oparg = CURRENT_OPARG(); + args = &stack_pointer[-oparg]; + self_or_null = stack_pointer[-1 - oparg]; + callable = stack_pointer[-2 - oparg]; + int total_args = oparg; + if (self_or_null != NULL) { + args--; + total_args++; + } + /* Callable is not a normal Python function */ + res = PyObject_Vectorcall( + callable, args, + total_args | PY_VECTORCALL_ARGUMENTS_OFFSET, + NULL); + assert(opcode != INSTRUMENTED_CALL); + assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); + Py_DECREF(callable); + for (int i = 0; i < total_args; i++) { + Py_DECREF(args[i]); + } + if (res == NULL) JUMP_TO_ERROR(); + stack_pointer[-2 - oparg] = res; + stack_pointer += -1 - oparg; + break; + } + case _CHECK_CALL_BOUND_METHOD_EXACT_ARGS: { PyObject *null; PyObject *callable; diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 2a0f268ce6ed54..4b3929fe3b0eeb 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -1002,6 +1002,87 @@ DISPATCH(); } + TARGET(CALL_BOUND_METHOD_GENERAL) { + frame->instr_ptr = next_instr; + next_instr += 4; + INSTRUCTION_STATS(CALL_BOUND_METHOD_GENERAL); + static_assert(INLINE_CACHE_ENTRIES_CALL == 3, "incorrect cache size"); + PyObject *null; + PyObject *callable; + PyObject *method; + PyObject *self; + PyObject **args; + PyObject *self_or_null; + _PyInterpreterFrame *new_frame; + /* Skip 1 cache entry */ + /* Skip 2 cache entries */ + // _CHECK_PEP_523 + { + DEOPT_IF(tstate->interp->eval_frame, CALL); + } + // _CHECK_IS_METHOD + null = stack_pointer[-1 - oparg]; + callable = stack_pointer[-2 - oparg]; + { + DEOPT_IF(Py_TYPE(callable) != &PyMethod_Type, CALL); + DEOPT_IF(!PyFunction_Check(((PyMethodObject *)callable)->im_func), CALL); + DEOPT_IF(null != NULL, CALL); + } + // _EXPAND_METHOD + { + assert(null == NULL); + assert(Py_TYPE(callable) == &PyMethod_Type); + self = ((PyMethodObject *)callable)->im_self; + Py_INCREF(self); + stack_pointer[-1 - oparg] = self; // Patch stack as it is used by _CALL_PY_GENERAL + method = ((PyMethodObject *)callable)->im_func; + assert(PyFunction_Check(method)); + Py_INCREF(method); + Py_DECREF(callable); + } + // _CALL_PY_GENERAL + args = &stack_pointer[-oparg]; + self_or_null = self; + callable = method; + { + // oparg counts all of the args, but *not* self: + int total_args = oparg; + if (self_or_null != NULL) { + args--; + total_args++; + } + assert(Py_TYPE(callable) == &PyFunction_Type); + int code_flags = ((PyCodeObject*)PyFunction_GET_CODE(callable))->co_flags; + PyObject *locals = code_flags & CO_OPTIMIZED ? NULL : Py_NewRef(PyFunction_GET_GLOBALS(callable)); + new_frame = _PyEvalFramePushAndInit( + tstate, (PyFunctionObject *)callable, locals, + args, total_args, NULL + ); + // The frame has stolen all the arguments from the stack, + // so there is no need to clean them up. + stack_pointer += -2 - oparg; + if (new_frame == NULL) { + goto error; + } + frame->return_offset = (uint16_t)(1 + INLINE_CACHE_ENTRIES_CALL); + } + // _PUSH_FRAME + { + // Write it out explicitly because it's subtly different. + // Eventually this should be the only occurrence of this code. + assert(tstate->interp->eval_frame == NULL); + _PyFrame_SetStackPointer(frame, stack_pointer); + new_frame->previous = frame; + CALL_STAT_INC(inlined_py_calls); + frame = tstate->current_frame = new_frame; + tstate->py_recursion_remaining--; + LOAD_SP(); + LOAD_IP(0); + LLTRACE_RESUME_FRAME(); + } + DISPATCH(); + } + TARGET(CALL_BUILTIN_CLASS) { frame->instr_ptr = next_instr; next_instr += 4; @@ -1713,6 +1794,71 @@ DISPATCH(); } + TARGET(CALL_NON_PY_GENERAL) { + frame->instr_ptr = next_instr; + next_instr += 4; + INSTRUCTION_STATS(CALL_NON_PY_GENERAL); + static_assert(INLINE_CACHE_ENTRIES_CALL == 3, "incorrect cache size"); + PyObject *callable; + PyObject *null; + PyObject *method; + PyObject *self; + PyObject **args; + PyObject *self_or_null; + PyObject *res; + /* Skip 1 cache entry */ + /* Skip 2 cache entries */ + // _CHECK_IS_NOT_PY_CALLABLE + callable = stack_pointer[-2 - oparg]; + { + DEOPT_IF(PyFunction_Check(callable), CALL); + DEOPT_IF(Py_TYPE(callable) == &PyMethod_Type, CALL); + } + // _EXPAND_METHOD + null = stack_pointer[-1 - oparg]; + { + assert(null == NULL); + assert(Py_TYPE(callable) == &PyMethod_Type); + self = ((PyMethodObject *)callable)->im_self; + Py_INCREF(self); + stack_pointer[-1 - oparg] = self; // Patch stack as it is used by _CALL_PY_GENERAL + method = ((PyMethodObject *)callable)->im_func; + assert(PyFunction_Check(method)); + Py_INCREF(method); + Py_DECREF(callable); + } + // _CALL_NON_PY_GENERAL + args = &stack_pointer[-oparg]; + self_or_null = self; + callable = method; + { + int total_args = oparg; + if (self_or_null != NULL) { + args--; + total_args++; + } + /* Callable is not a normal Python function */ + res = PyObject_Vectorcall( + callable, args, + total_args | PY_VECTORCALL_ARGUMENTS_OFFSET, + NULL); + assert(opcode != INSTRUMENTED_CALL); + assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); + Py_DECREF(callable); + for (int i = 0; i < total_args; i++) { + Py_DECREF(args[i]); + } + if (res == NULL) { stack_pointer += -4 - oparg; goto error; } + } + // _CHECK_PERIODIC + { + } + stack_pointer[-2 - oparg] = res; + stack_pointer += -1 - oparg; + CHECK_EVAL_BREAKER(); + DISPATCH(); + } + TARGET(CALL_PY_EXACT_ARGS) { _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; next_instr += 4; @@ -1786,6 +1932,68 @@ DISPATCH(); } + TARGET(CALL_PY_GENERAL) { + frame->instr_ptr = next_instr; + next_instr += 4; + INSTRUCTION_STATS(CALL_PY_GENERAL); + static_assert(INLINE_CACHE_ENTRIES_CALL == 3, "incorrect cache size"); + PyObject *callable; + PyObject **args; + PyObject *self_or_null; + _PyInterpreterFrame *new_frame; + /* Skip 1 cache entry */ + /* Skip 2 cache entries */ + // _CHECK_PEP_523 + { + DEOPT_IF(tstate->interp->eval_frame, CALL); + } + // _CHECK_IS_FUNCTION + callable = stack_pointer[-2 - oparg]; + { + DEOPT_IF(!PyFunction_Check(callable), CALL); + } + // _CALL_PY_GENERAL + args = &stack_pointer[-oparg]; + self_or_null = stack_pointer[-1 - oparg]; + { + // oparg counts all of the args, but *not* self: + int total_args = oparg; + if (self_or_null != NULL) { + args--; + total_args++; + } + assert(Py_TYPE(callable) == &PyFunction_Type); + int code_flags = ((PyCodeObject*)PyFunction_GET_CODE(callable))->co_flags; + PyObject *locals = code_flags & CO_OPTIMIZED ? NULL : Py_NewRef(PyFunction_GET_GLOBALS(callable)); + new_frame = _PyEvalFramePushAndInit( + tstate, (PyFunctionObject *)callable, locals, + args, total_args, NULL + ); + // The frame has stolen all the arguments from the stack, + // so there is no need to clean them up. + stack_pointer += -2 - oparg; + if (new_frame == NULL) { + goto error; + } + frame->return_offset = (uint16_t)(1 + INLINE_CACHE_ENTRIES_CALL); + } + // _PUSH_FRAME + { + // Write it out explicitly because it's subtly different. + // Eventually this should be the only occurrence of this code. + assert(tstate->interp->eval_frame == NULL); + _PyFrame_SetStackPointer(frame, stack_pointer); + new_frame->previous = frame; + CALL_STAT_INC(inlined_py_calls); + frame = tstate->current_frame = new_frame; + tstate->py_recursion_remaining--; + LOAD_SP(); + LOAD_IP(0); + LLTRACE_RESUME_FRAME(); + } + DISPATCH(); + } + TARGET(CALL_PY_WITH_DEFAULTS) { _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; next_instr += 4; diff --git a/Python/opcode_targets.h b/Python/opcode_targets.h index 4061ba33cea53e..5eaee6c48c50d2 100644 --- a/Python/opcode_targets.h +++ b/Python/opcode_targets.h @@ -163,6 +163,7 @@ static void *opcode_targets[256] = { &&TARGET_BINARY_SUBSCR_TUPLE_INT, &&TARGET_CALL_ALLOC_AND_ENTER_INIT, &&TARGET_CALL_BOUND_METHOD_EXACT_ARGS, + &&TARGET_CALL_BOUND_METHOD_GENERAL, &&TARGET_CALL_BUILTIN_CLASS, &&TARGET_CALL_BUILTIN_FAST, &&TARGET_CALL_BUILTIN_FAST_WITH_KEYWORDS, @@ -174,7 +175,9 @@ static void *opcode_targets[256] = { &&TARGET_CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS, &&TARGET_CALL_METHOD_DESCRIPTOR_NOARGS, &&TARGET_CALL_METHOD_DESCRIPTOR_O, + &&TARGET_CALL_NON_PY_GENERAL, &&TARGET_CALL_PY_EXACT_ARGS, + &&TARGET_CALL_PY_GENERAL, &&TARGET_CALL_PY_WITH_DEFAULTS, &&TARGET_CALL_STR_1, &&TARGET_CALL_TUPLE_1, @@ -232,9 +235,6 @@ static void *opcode_targets[256] = { &&_unknown_opcode, &&_unknown_opcode, &&_unknown_opcode, - &&_unknown_opcode, - &&_unknown_opcode, - &&_unknown_opcode, &&TARGET_INSTRUMENTED_RESUME, &&TARGET_INSTRUMENTED_END_FOR, &&TARGET_INSTRUMENTED_END_SEND, diff --git a/Python/optimizer_bytecodes.c b/Python/optimizer_bytecodes.c index 60763286178c71..a2a1670d95437d 100644 --- a/Python/optimizer_bytecodes.c +++ b/Python/optimizer_bytecodes.c @@ -629,6 +629,15 @@ dummy_func(void) { frame_new(ctx, co, localsplus_start, n_locals_already_filled, 0)); } + op(_CALL_PY_GENERAL, (callable, self_or_null, args[oparg] -- new_frame: _Py_UOpsAbstractFrame *)) { + /* The _Py_UOpsAbstractFrame design assumes that we can copy arguments across directly */ + (void)callable; + (void)self_or_null; + (void)args; + first_valid_check_stack = NULL; + goto done; + } + op(_POP_FRAME, (retval -- res)) { SYNC_SP(); ctx->frame->stack_pointer = stack_pointer; @@ -718,7 +727,7 @@ dummy_func(void) { if (first_valid_check_stack == NULL) { first_valid_check_stack = corresponding_check_stack; } - else { + else if (corresponding_check_stack) { // delete all but the first valid _CHECK_STACK_SPACE corresponding_check_stack->opcode = _NOP; } diff --git a/Python/optimizer_cases.c.h b/Python/optimizer_cases.c.h index e680d76141776f..68b1c363f8908b 100644 --- a/Python/optimizer_cases.c.h +++ b/Python/optimizer_cases.c.h @@ -1559,6 +1559,58 @@ break; } + case _CALL_PY_GENERAL: { + _Py_UopsSymbol **args; + _Py_UopsSymbol *self_or_null; + _Py_UopsSymbol *callable; + _Py_UOpsAbstractFrame *new_frame; + args = &stack_pointer[-oparg]; + self_or_null = stack_pointer[-1 - oparg]; + callable = stack_pointer[-2 - oparg]; + /* The _Py_UOpsAbstractFrame design assumes that we can copy arguments across directly */ + (void)callable; + (void)self_or_null; + (void)args; + first_valid_check_stack = NULL; + goto done; + stack_pointer[-2 - oparg] = (_Py_UopsSymbol *)new_frame; + stack_pointer += -1 - oparg; + break; + } + + case _CHECK_IS_FUNCTION: { + break; + } + + case _CHECK_IS_METHOD: { + break; + } + + case _EXPAND_METHOD: { + _Py_UopsSymbol *method; + _Py_UopsSymbol *self; + method = sym_new_not_null(ctx); + if (method == NULL) goto out_of_space; + self = sym_new_not_null(ctx); + if (self == NULL) goto out_of_space; + stack_pointer[-2 - oparg] = method; + stack_pointer[-1 - oparg] = self; + break; + } + + case _CHECK_IS_NOT_PY_CALLABLE: { + break; + } + + case _CALL_NON_PY_GENERAL: { + _Py_UopsSymbol *res; + res = sym_new_not_null(ctx); + if (res == NULL) goto out_of_space; + stack_pointer[-2 - oparg] = res; + stack_pointer += -1 - oparg; + break; + } + case _CHECK_CALL_BOUND_METHOD_EXACT_ARGS: { _Py_UopsSymbol *null; _Py_UopsSymbol *callable; @@ -1692,7 +1744,7 @@ if (first_valid_check_stack == NULL) { first_valid_check_stack = corresponding_check_stack; } - else { + else if (corresponding_check_stack) { // delete all but the first valid _CHECK_STACK_SPACE corresponding_check_stack->opcode = _NOP; } diff --git a/Python/specialize.c b/Python/specialize.c index 72114f27f69c52..7c1365d6aafeb7 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -1917,36 +1917,26 @@ specialize_py_call(PyFunctionObject *func, _Py_CODEUNIT *instr, int nargs, SPECIALIZATION_FAIL(CALL, SPEC_FAIL_CALL_PEP_523); return -1; } - if (kind != SIMPLE_FUNCTION) { - SPECIALIZATION_FAIL(CALL, kind); - return -1; - } - int argcount = code->co_argcount; - int defcount = func->func_defaults == NULL ? 0 : (int)PyTuple_GET_SIZE(func->func_defaults); - int min_args = argcount-defcount; - // GH-105840: min_args is negative when somebody sets too many __defaults__! - if (min_args < 0 || nargs > argcount || nargs < min_args) { - SPECIALIZATION_FAIL(CALL, SPEC_FAIL_WRONG_NUMBER_ARGUMENTS); + int argcount = -1; + if (kind == SPEC_FAIL_CODE_NOT_OPTIMIZED) { + SPECIALIZATION_FAIL(CALL, SPEC_FAIL_CODE_NOT_OPTIMIZED); return -1; } - assert(nargs <= argcount && nargs >= min_args); - assert(min_args >= 0 && defcount >= 0); - assert(defcount == 0 || func->func_defaults != NULL); - int version = _PyFunction_GetVersionForCurrentState(func); - if (version == 0) { - SPECIALIZATION_FAIL(CALL, SPEC_FAIL_OUT_OF_VERSIONS); - return -1; + if (kind == SIMPLE_FUNCTION) { + argcount = code->co_argcount; } - write_u32(cache->func_version, version); - if (argcount == nargs) { + if (argcount == nargs + bound_method) { + int version = _PyFunction_GetVersionForCurrentState(func); + if (version == 0) { + SPECIALIZATION_FAIL(CALL, SPEC_FAIL_OUT_OF_VERSIONS); + return -1; + } + write_u32(cache->func_version, version); instr->op.code = bound_method ? CALL_BOUND_METHOD_EXACT_ARGS : CALL_PY_EXACT_ARGS; } - else if (bound_method) { - SPECIALIZATION_FAIL(CALL, SPEC_FAIL_CALL_BOUND_METHOD); - return -1; - } else { - instr->op.code = CALL_PY_WITH_DEFAULTS; + instr->op.code = bound_method ? CALL_BOUND_METHOD_GENERAL : CALL_PY_GENERAL; + return 0; } return 0; } @@ -2047,7 +2037,7 @@ _Py_Specialize_Call(PyObject *callable, _Py_CODEUNIT *instr, int nargs) else if (PyMethod_Check(callable)) { PyObject *func = ((PyMethodObject *)callable)->im_func; if (PyFunction_Check(func)) { - fail = specialize_py_call((PyFunctionObject *)func, instr, nargs+1, true); + fail = specialize_py_call((PyFunctionObject *)func, instr, nargs, true); } else { SPECIALIZATION_FAIL(CALL, SPEC_FAIL_CALL_BOUND_METHOD); diff --git a/Tools/cases_generator/analyzer.py b/Tools/cases_generator/analyzer.py index fdb635486b9531..4028bf8e085f4e 100644 --- a/Tools/cases_generator/analyzer.py +++ b/Tools/cases_generator/analyzer.py @@ -533,6 +533,7 @@ def compute_properties(op: parser.InstDef) -> Properties: exits_if = variable_used(op, "EXIT_IF") if deopts_if and exits_if: tkn = op.tokens[0] + print(op.tokens) raise lexer.make_syntax_error( "Op cannot contain both EXIT_IF and DEOPT_IF", tkn.filename, From 2262f9886b721081b8dad8175da23adf2e81de1c Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Fri, 26 Apr 2024 14:46:53 +0100 Subject: [PATCH 02/17] Add CALL_NON_PY_GENERAL call specialization --- Include/internal/pycore_opcode_metadata.h | 2 +- Lib/test/test_call.py | 13 +++++++++---- Python/bytecodes.c | 3 +-- Python/executor_cases.c.h | 2 +- Python/generated_cases.c.h | 23 +++-------------------- Python/specialize.c | 9 ++++----- Tools/cases_generator/analyzer.py | 1 - 7 files changed, 19 insertions(+), 34 deletions(-) diff --git a/Include/internal/pycore_opcode_metadata.h b/Include/internal/pycore_opcode_metadata.h index 45df8bb8a8ff0c..1b5d406f63b0a1 100644 --- a/Include/internal/pycore_opcode_metadata.h +++ b/Include/internal/pycore_opcode_metadata.h @@ -1239,7 +1239,7 @@ _PyOpcode_macro_expansion[256] = { [CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS] = { .nuops = 2, .uops = { { _CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS, 0, 0 }, { _CHECK_PERIODIC, 0, 0 } } }, [CALL_METHOD_DESCRIPTOR_NOARGS] = { .nuops = 2, .uops = { { _CALL_METHOD_DESCRIPTOR_NOARGS, 0, 0 }, { _CHECK_PERIODIC, 0, 0 } } }, [CALL_METHOD_DESCRIPTOR_O] = { .nuops = 2, .uops = { { _CALL_METHOD_DESCRIPTOR_O, 0, 0 }, { _CHECK_PERIODIC, 0, 0 } } }, - [CALL_NON_PY_GENERAL] = { .nuops = 4, .uops = { { _CHECK_IS_NOT_PY_CALLABLE, 0, 0 }, { _EXPAND_METHOD, 0, 0 }, { _CALL_NON_PY_GENERAL, 0, 0 }, { _CHECK_PERIODIC, 0, 0 } } }, + [CALL_NON_PY_GENERAL] = { .nuops = 3, .uops = { { _CHECK_IS_NOT_PY_CALLABLE, 0, 0 }, { _CALL_NON_PY_GENERAL, 0, 0 }, { _CHECK_PERIODIC, 0, 0 } } }, [CALL_PY_EXACT_ARGS] = { .nuops = 6, .uops = { { _CHECK_PEP_523, 0, 0 }, { _CHECK_FUNCTION_EXACT_ARGS, 2, 1 }, { _CHECK_STACK_SPACE, 0, 0 }, { _INIT_CALL_PY_EXACT_ARGS, 0, 0 }, { _SAVE_RETURN_OFFSET, 7, 3 }, { _PUSH_FRAME, 0, 0 } } }, [CALL_PY_GENERAL] = { .nuops = 4, .uops = { { _CHECK_PEP_523, 0, 0 }, { _CHECK_IS_FUNCTION, 0, 0 }, { _CALL_PY_GENERAL, 0, 0 }, { _PUSH_FRAME, 0, 0 } } }, [CALL_STR_1] = { .nuops = 2, .uops = { { _CALL_STR_1, 0, 0 }, { _CHECK_PERIODIC, 0, 0 } } }, diff --git a/Lib/test/test_call.py b/Lib/test/test_call.py index d3f4d6c29c5536..8f94d3d79c6bec 100644 --- a/Lib/test/test_call.py +++ b/Lib/test/test_call.py @@ -46,11 +46,16 @@ def test_frames_are_popped_after_failed_calls(self): # recovering from failed calls: def f(): pass - for _ in range(1000): - try: - f(None) - except TypeError: + class C: + def m(self): pass + callables = [ f, C.m, [].__len__ ] + for c in callables: + for _ in range(1000): + try: + c(None) + except TypeError: + pass # BOOM! diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 11e4d151e11313..bc61f08a8222a9 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -3217,6 +3217,7 @@ dummy_func( } op(_CALL_NON_PY_GENERAL, (callable, self_or_null, args[oparg] -- res)) { + assert(opcode != INSTRUMENTED_CALL); int total_args = oparg; if (self_or_null != NULL) { args--; @@ -3227,7 +3228,6 @@ dummy_func( callable, args, total_args | PY_VECTORCALL_ARGUMENTS_OFFSET, NULL); - assert(opcode != INSTRUMENTED_CALL); assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); Py_DECREF(callable); for (int i = 0; i < total_args; i++) { @@ -3240,7 +3240,6 @@ dummy_func( unused/1 + // Skip over the counter unused/2 + _CHECK_IS_NOT_PY_CALLABLE + - _EXPAND_METHOD + _CALL_NON_PY_GENERAL + _CHECK_PERIODIC; diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index 59a5e4cdb789b0..7974fbccb15f68 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -3144,6 +3144,7 @@ args = &stack_pointer[-oparg]; self_or_null = stack_pointer[-1 - oparg]; callable = stack_pointer[-2 - oparg]; + assert(opcode != INSTRUMENTED_CALL); int total_args = oparg; if (self_or_null != NULL) { args--; @@ -3154,7 +3155,6 @@ callable, args, total_args | PY_VECTORCALL_ARGUMENTS_OFFSET, NULL); - assert(opcode != INSTRUMENTED_CALL); assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); Py_DECREF(callable); for (int i = 0; i < total_args; i++) { diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 4b3929fe3b0eeb..d30305595b2102 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -1800,9 +1800,6 @@ INSTRUCTION_STATS(CALL_NON_PY_GENERAL); static_assert(INLINE_CACHE_ENTRIES_CALL == 3, "incorrect cache size"); PyObject *callable; - PyObject *null; - PyObject *method; - PyObject *self; PyObject **args; PyObject *self_or_null; PyObject *res; @@ -1814,24 +1811,11 @@ DEOPT_IF(PyFunction_Check(callable), CALL); DEOPT_IF(Py_TYPE(callable) == &PyMethod_Type, CALL); } - // _EXPAND_METHOD - null = stack_pointer[-1 - oparg]; - { - assert(null == NULL); - assert(Py_TYPE(callable) == &PyMethod_Type); - self = ((PyMethodObject *)callable)->im_self; - Py_INCREF(self); - stack_pointer[-1 - oparg] = self; // Patch stack as it is used by _CALL_PY_GENERAL - method = ((PyMethodObject *)callable)->im_func; - assert(PyFunction_Check(method)); - Py_INCREF(method); - Py_DECREF(callable); - } // _CALL_NON_PY_GENERAL args = &stack_pointer[-oparg]; - self_or_null = self; - callable = method; + self_or_null = stack_pointer[-1 - oparg]; { + assert(opcode != INSTRUMENTED_CALL); int total_args = oparg; if (self_or_null != NULL) { args--; @@ -1842,13 +1826,12 @@ callable, args, total_args | PY_VECTORCALL_ARGUMENTS_OFFSET, NULL); - assert(opcode != INSTRUMENTED_CALL); assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); Py_DECREF(callable); for (int i = 0; i < total_args; i++) { Py_DECREF(args[i]); } - if (res == NULL) { stack_pointer += -4 - oparg; goto error; } + if (res == NULL) { stack_pointer += -2 - oparg; goto error; } } // _CHECK_PERIODIC { diff --git a/Python/specialize.c b/Python/specialize.c index 7c1365d6aafeb7..347a18a880f739 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -1981,9 +1981,8 @@ specialize_c_call(PyObject *callable, _Py_CODEUNIT *instr, int nargs) return 0; } default: - SPECIALIZATION_FAIL(CALL, - builtin_call_fail_kind(PyCFunction_GET_FLAGS(callable))); - return 1; + instr->op.code = CALL_NON_PY_GENERAL; + return 0; } } @@ -2045,8 +2044,8 @@ _Py_Specialize_Call(PyObject *callable, _Py_CODEUNIT *instr, int nargs) } } else { - SPECIALIZATION_FAIL(CALL, call_fail_kind(callable)); - fail = -1; + instr->op.code = CALL_NON_PY_GENERAL; + fail = 0; } if (fail) { STAT_INC(CALL, failure); diff --git a/Tools/cases_generator/analyzer.py b/Tools/cases_generator/analyzer.py index 4028bf8e085f4e..fdb635486b9531 100644 --- a/Tools/cases_generator/analyzer.py +++ b/Tools/cases_generator/analyzer.py @@ -533,7 +533,6 @@ def compute_properties(op: parser.InstDef) -> Properties: exits_if = variable_used(op, "EXIT_IF") if deopts_if and exits_if: tkn = op.tokens[0] - print(op.tokens) raise lexer.make_syntax_error( "Op cannot contain both EXIT_IF and DEOPT_IF", tkn.filename, From 4af43c2bcdee8853ffbe6df293319764e0af3316 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Fri, 26 Apr 2024 14:52:31 +0100 Subject: [PATCH 03/17] Remove CALL_PY_WITH_DEFAULTS specialization --- Include/internal/pycore_opcode_metadata.h | 8 +- Include/internal/pycore_uop_ids.h | 1 - Include/opcode_ids.h | 89 +++++++++++----------- Lib/_opcode_metadata.py | 90 +++++++++++------------ Python/bytecodes.c | 35 --------- Python/executor_cases.c.h | 2 - Python/generated_cases.c.h | 46 ------------ Python/opcode_targets.h | 2 +- Python/optimizer_cases.c.h | 2 - 9 files changed, 90 insertions(+), 185 deletions(-) diff --git a/Include/internal/pycore_opcode_metadata.h b/Include/internal/pycore_opcode_metadata.h index 1b5d406f63b0a1..9457bff1379060 100644 --- a/Include/internal/pycore_opcode_metadata.h +++ b/Include/internal/pycore_opcode_metadata.h @@ -133,8 +133,6 @@ int _PyOpcode_num_popped(int opcode, int oparg) { return 2 + oparg; case CALL_PY_GENERAL: return 2 + oparg; - case CALL_PY_WITH_DEFAULTS: - return 2 + oparg; case CALL_STR_1: return 3; case CALL_TUPLE_1: @@ -568,8 +566,6 @@ int _PyOpcode_num_pushed(int opcode, int oparg) { return 0; case CALL_PY_GENERAL: return 0; - case CALL_PY_WITH_DEFAULTS: - return 1; case CALL_STR_1: return 1; case CALL_TUPLE_1: @@ -1016,7 +1012,6 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[268] = { [CALL_NON_PY_GENERAL] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [CALL_PY_EXACT_ARGS] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG }, [CALL_PY_GENERAL] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, - [CALL_PY_WITH_DEFAULTS] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_DEOPT_FLAG }, [CALL_STR_1] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [CALL_TUPLE_1] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [CALL_TYPE_1] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_DEOPT_FLAG }, @@ -1420,7 +1415,6 @@ const char *_PyOpcode_OpName[268] = { [CALL_NON_PY_GENERAL] = "CALL_NON_PY_GENERAL", [CALL_PY_EXACT_ARGS] = "CALL_PY_EXACT_ARGS", [CALL_PY_GENERAL] = "CALL_PY_GENERAL", - [CALL_PY_WITH_DEFAULTS] = "CALL_PY_WITH_DEFAULTS", [CALL_STR_1] = "CALL_STR_1", [CALL_TUPLE_1] = "CALL_TUPLE_1", [CALL_TYPE_1] = "CALL_TYPE_1", @@ -1676,7 +1670,6 @@ const uint8_t _PyOpcode_Deopt[256] = { [CALL_NON_PY_GENERAL] = CALL, [CALL_PY_EXACT_ARGS] = CALL, [CALL_PY_GENERAL] = CALL, - [CALL_PY_WITH_DEFAULTS] = CALL, [CALL_STR_1] = CALL, [CALL_TUPLE_1] = CALL, [CALL_TYPE_1] = CALL, @@ -1876,6 +1869,7 @@ 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_uop_ids.h b/Include/internal/pycore_uop_ids.h index a2d8090a17d0af..b025a3a893d93b 100644 --- a/Include/internal/pycore_uop_ids.h +++ b/Include/internal/pycore_uop_ids.h @@ -53,7 +53,6 @@ extern "C" { #define _CALL_METHOD_DESCRIPTOR_O 319 #define _CALL_NON_PY_GENERAL 320 #define _CALL_PY_GENERAL 321 -#define _CALL_PY_WITH_DEFAULTS CALL_PY_WITH_DEFAULTS #define _CALL_STR_1 322 #define _CALL_TUPLE_1 323 #define _CALL_TYPE_1 CALL_TYPE_1 diff --git a/Include/opcode_ids.h b/Include/opcode_ids.h index 4e9825a0132668..647f7c0ecb1ec8 100644 --- a/Include/opcode_ids.h +++ b/Include/opcode_ids.h @@ -159,51 +159,50 @@ extern "C" { #define CALL_NON_PY_GENERAL 176 #define CALL_PY_EXACT_ARGS 177 #define CALL_PY_GENERAL 178 -#define CALL_PY_WITH_DEFAULTS 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 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 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 462ab439e0caf8..b3d7b8103e86c4 100644 --- a/Lib/_opcode_metadata.py +++ b/Lib/_opcode_metadata.py @@ -88,7 +88,6 @@ "CALL": [ "CALL_BOUND_METHOD_EXACT_ARGS", "CALL_PY_EXACT_ARGS", - "CALL_PY_WITH_DEFAULTS", "CALL_TYPE_1", "CALL_STR_1", "CALL_TUPLE_1", @@ -141,51 +140,50 @@ 'CALL_NON_PY_GENERAL': 176, 'CALL_PY_EXACT_ARGS': 177, 'CALL_PY_GENERAL': 178, - 'CALL_PY_WITH_DEFAULTS': 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, + '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, } opmap = { diff --git a/Python/bytecodes.c b/Python/bytecodes.c index bc61f08a8222a9..c922338b592cea 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -3041,7 +3041,6 @@ dummy_func( family(CALL, INLINE_CACHE_ENTRIES_CALL) = { CALL_BOUND_METHOD_EXACT_ARGS, CALL_PY_EXACT_ARGS, - CALL_PY_WITH_DEFAULTS, CALL_TYPE_1, CALL_STR_1, CALL_TUPLE_1, @@ -3323,40 +3322,6 @@ dummy_func( _SAVE_RETURN_OFFSET + _PUSH_FRAME; - inst(CALL_PY_WITH_DEFAULTS, (unused/1, func_version/2, callable, self_or_null, args[oparg] -- unused)) { - DEOPT_IF(tstate->interp->eval_frame); - int argcount = oparg; - if (self_or_null != NULL) { - args--; - argcount++; - } - DEOPT_IF(!PyFunction_Check(callable)); - PyFunctionObject *func = (PyFunctionObject *)callable; - DEOPT_IF(func->func_version != func_version); - PyCodeObject *code = (PyCodeObject *)func->func_code; - assert(func->func_defaults); - assert(PyTuple_CheckExact(func->func_defaults)); - int defcount = (int)PyTuple_GET_SIZE(func->func_defaults); - assert(defcount <= code->co_argcount); - int min_args = code->co_argcount - defcount; - DEOPT_IF(argcount > code->co_argcount); - DEOPT_IF(argcount < min_args); - DEOPT_IF(!_PyThreadState_HasStackSpace(tstate, code->co_framesize)); - STAT_INC(CALL, hit); - _PyInterpreterFrame *new_frame = _PyFrame_PushUnchecked(tstate, func, code->co_argcount); - for (int i = 0; i < argcount; i++) { - new_frame->localsplus[i] = args[i]; - } - for (int i = argcount; i < code->co_argcount; i++) { - PyObject *def = PyTuple_GET_ITEM(func->func_defaults, i - min_args); - new_frame->localsplus[i] = Py_NewRef(def); - } - // Manipulate stack and cache directly since we leave using DISPATCH_INLINED(). - STACK_SHRINK(oparg + 2); - frame->return_offset = (uint16_t)(next_instr - this_instr); - DISPATCH_INLINED(new_frame); - } - inst(CALL_TYPE_1, (unused/1, unused/2, callable, null, arg -- res)) { assert(oparg == 1); DEOPT_IF(null != NULL); diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index 7974fbccb15f68..bdbc471dd95505 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -3410,8 +3410,6 @@ break; } - /* _CALL_PY_WITH_DEFAULTS is not a viable micro-op for tier 2 because it uses the 'this_instr' variable */ - case _CALL_TYPE_1: { PyObject *arg; PyObject *null; diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index d30305595b2102..e97f0c5cde4707 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -1977,52 +1977,6 @@ DISPATCH(); } - TARGET(CALL_PY_WITH_DEFAULTS) { - _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; - next_instr += 4; - INSTRUCTION_STATS(CALL_PY_WITH_DEFAULTS); - static_assert(INLINE_CACHE_ENTRIES_CALL == 3, "incorrect cache size"); - PyObject **args; - PyObject *self_or_null; - PyObject *callable; - /* Skip 1 cache entry */ - args = &stack_pointer[-oparg]; - self_or_null = stack_pointer[-1 - oparg]; - callable = stack_pointer[-2 - oparg]; - uint32_t func_version = read_u32(&this_instr[2].cache); - DEOPT_IF(tstate->interp->eval_frame, CALL); - int argcount = oparg; - if (self_or_null != NULL) { - args--; - argcount++; - } - DEOPT_IF(!PyFunction_Check(callable), CALL); - PyFunctionObject *func = (PyFunctionObject *)callable; - DEOPT_IF(func->func_version != func_version, CALL); - PyCodeObject *code = (PyCodeObject *)func->func_code; - assert(func->func_defaults); - assert(PyTuple_CheckExact(func->func_defaults)); - int defcount = (int)PyTuple_GET_SIZE(func->func_defaults); - assert(defcount <= code->co_argcount); - int min_args = code->co_argcount - defcount; - DEOPT_IF(argcount > code->co_argcount, CALL); - DEOPT_IF(argcount < min_args, CALL); - DEOPT_IF(!_PyThreadState_HasStackSpace(tstate, code->co_framesize), CALL); - STAT_INC(CALL, hit); - _PyInterpreterFrame *new_frame = _PyFrame_PushUnchecked(tstate, func, code->co_argcount); - for (int i = 0; i < argcount; i++) { - new_frame->localsplus[i] = args[i]; - } - for (int i = argcount; i < code->co_argcount; i++) { - PyObject *def = PyTuple_GET_ITEM(func->func_defaults, i - min_args); - new_frame->localsplus[i] = Py_NewRef(def); - } - // Manipulate stack and cache directly since we leave using DISPATCH_INLINED(). - STACK_SHRINK(oparg + 2); - frame->return_offset = (uint16_t)(next_instr - this_instr); - DISPATCH_INLINED(new_frame); - } - TARGET(CALL_STR_1) { frame->instr_ptr = next_instr; next_instr += 4; diff --git a/Python/opcode_targets.h b/Python/opcode_targets.h index 5eaee6c48c50d2..fa4f1f8cbb475a 100644 --- a/Python/opcode_targets.h +++ b/Python/opcode_targets.h @@ -178,7 +178,6 @@ static void *opcode_targets[256] = { &&TARGET_CALL_NON_PY_GENERAL, &&TARGET_CALL_PY_EXACT_ARGS, &&TARGET_CALL_PY_GENERAL, - &&TARGET_CALL_PY_WITH_DEFAULTS, &&TARGET_CALL_STR_1, &&TARGET_CALL_TUPLE_1, &&TARGET_CALL_TYPE_1, @@ -235,6 +234,7 @@ 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_cases.c.h b/Python/optimizer_cases.c.h index 68b1c363f8908b..c80a6e5363ae3e 100644 --- a/Python/optimizer_cases.c.h +++ b/Python/optimizer_cases.c.h @@ -1752,8 +1752,6 @@ break; } - /* _CALL_PY_WITH_DEFAULTS is not a viable micro-op for tier 2 */ - case _CALL_TYPE_1: { _Py_UopsSymbol *res; res = sym_new_not_null(ctx); From b7795e3fa6e8e9226c6fda9861b2e5d67e1f07d3 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Fri, 26 Apr 2024 17:54:22 +0100 Subject: [PATCH 04/17] Fix JIT build --- Include/internal/pycore_frame.h | 5 +++++ Python/bytecodes.c | 2 ++ Python/ceval.c | 6 +----- Python/executor_cases.c.h | 2 ++ Python/generated_cases.c.h | 2 ++ 5 files changed, 12 insertions(+), 5 deletions(-) diff --git a/Include/internal/pycore_frame.h b/Include/internal/pycore_frame.h index 37ae5ae850389b..e13fdd9bb2e01c 100644 --- a/Include/internal/pycore_frame.h +++ b/Include/internal/pycore_frame.h @@ -318,6 +318,11 @@ PyGenObject *_PyFrame_GetGenerator(_PyInterpreterFrame *frame) return (PyGenObject *)(((char *)frame) - offset_in_gen); } +PyAPI_FUNC(_PyInterpreterFrame *) +_PyEvalFramePushAndInit(PyThreadState *tstate, PyFunctionObject *func, + PyObject *locals, PyObject* const* args, + size_t argcount, PyObject *kwnames); + #ifdef __cplusplus } #endif diff --git a/Python/bytecodes.c b/Python/bytecodes.c index c922338b592cea..c54763ce719d74 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -3216,7 +3216,9 @@ dummy_func( } op(_CALL_NON_PY_GENERAL, (callable, self_or_null, args[oparg] -- res)) { +#if TIER_ONE assert(opcode != INSTRUMENTED_CALL); +#endif int total_args = oparg; if (self_or_null != NULL) { args--; diff --git a/Python/ceval.c b/Python/ceval.c index a9696d7b775003..de6784a5dabe0a 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -247,10 +247,6 @@ static PyObject * import_name(PyThreadState *, _PyInterpreterFrame *, static PyObject * import_from(PyThreadState *, PyObject *, PyObject *); static int check_args_iterable(PyThreadState *, PyObject *func, PyObject *vararg); static int get_exception_handler(PyCodeObject *, int, int*, int*, int*); -static _PyInterpreterFrame * -_PyEvalFramePushAndInit(PyThreadState *tstate, PyFunctionObject *func, - PyObject *locals, PyObject* const* args, - size_t argcount, PyObject *kwnames); static _PyInterpreterFrame * _PyEvalFramePushAndInit_Ex(PyThreadState *tstate, PyFunctionObject *func, PyObject *locals, Py_ssize_t nargs, PyObject *callargs, PyObject *kwargs); @@ -1710,7 +1706,7 @@ _PyEval_FrameClearAndPop(PyThreadState *tstate, _PyInterpreterFrame * frame) } /* Consumes references to func, locals and all the args */ -static _PyInterpreterFrame * +_PyInterpreterFrame * _PyEvalFramePushAndInit(PyThreadState *tstate, PyFunctionObject *func, PyObject *locals, PyObject* const* args, size_t argcount, PyObject *kwnames) diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index bdbc471dd95505..30ac5fc2dada94 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -3144,7 +3144,9 @@ args = &stack_pointer[-oparg]; self_or_null = stack_pointer[-1 - oparg]; callable = stack_pointer[-2 - oparg]; + #if TIER_ONE assert(opcode != INSTRUMENTED_CALL); + #endif int total_args = oparg; if (self_or_null != NULL) { args--; diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index e97f0c5cde4707..95a0d2c15eee4f 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -1815,7 +1815,9 @@ args = &stack_pointer[-oparg]; self_or_null = stack_pointer[-1 - oparg]; { + #if TIER_ONE assert(opcode != INSTRUMENTED_CALL); + #endif int total_args = oparg; if (self_or_null != NULL) { args--; From e5c7dce7e0e2b83580928884d713d8bfba328a26 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Tue, 30 Apr 2024 12:18:13 +0100 Subject: [PATCH 05/17] Use CALL_NON_PY_GENERAL in more cases when otherwise failing to specialize --- Python/specialize.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/Python/specialize.c b/Python/specialize.c index 347a18a880f739..7f52c84f405881 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -1789,8 +1789,7 @@ specialize_class_call(PyObject *callable, _Py_CODEUNIT *instr, int nargs) return -1; } if (Py_TYPE(tp) != &PyType_Type) { - SPECIALIZATION_FAIL(CALL, SPEC_FAIL_CALL_METACLASS); - return -1; + goto generic; } if (tp->tp_new == PyBaseObject_Type.tp_new) { PyFunctionObject *init = get_init_for_simple_managed_python_class(tp); @@ -1807,10 +1806,10 @@ specialize_class_call(PyObject *callable, _Py_CODEUNIT *instr, int nargs) _Py_SET_OPCODE(*instr, CALL_ALLOC_AND_ENTER_INIT); return 0; } - return -1; } - SPECIALIZATION_FAIL(CALL, SPEC_FAIL_CALL_CLASS_MUTABLE); - return -1; +generic: + instr->op.code = CALL_NON_PY_GENERAL; + return 0; } #ifdef Py_STATS @@ -1901,8 +1900,8 @@ specialize_method_descriptor(PyMethodDescrObject *descr, _Py_CODEUNIT *instr, return 0; } } - SPECIALIZATION_FAIL(CALL, meth_descr_call_fail_kind(descr->d_method->ml_flags)); - return -1; + instr->op.code = CALL_NON_PY_GENERAL; + return 0; } static int @@ -1936,7 +1935,6 @@ specialize_py_call(PyFunctionObject *func, _Py_CODEUNIT *instr, int nargs, } else { instr->op.code = bound_method ? CALL_BOUND_METHOD_GENERAL : CALL_PY_GENERAL; - return 0; } return 0; } @@ -1945,6 +1943,7 @@ static int specialize_c_call(PyObject *callable, _Py_CODEUNIT *instr, int nargs) { if (PyCFunction_GET_FUNCTION(callable) == NULL) { + SPECIALIZATION_FAIL(CALL, SPEC_FAIL_OTHER); return 1; } switch (PyCFunction_GET_FLAGS(callable) & From 61abb3b1a1f5849746ed2f59e24ef0229cf1d524 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Thu, 2 May 2024 16:48:56 +0100 Subject: [PATCH 06/17] Delete unused code --- Python/specialize.c | 74 --------------------------------------------- 1 file changed, 74 deletions(-) diff --git a/Python/specialize.c b/Python/specialize.c index 7f52c84f405881..15e4950fb2f9ad 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -1812,53 +1812,6 @@ specialize_class_call(PyObject *callable, _Py_CODEUNIT *instr, int nargs) return 0; } -#ifdef Py_STATS -static int -builtin_call_fail_kind(int ml_flags) -{ - switch (ml_flags & (METH_VARARGS | METH_FASTCALL | METH_NOARGS | METH_O | - METH_KEYWORDS | METH_METHOD)) { - case METH_VARARGS: - return SPEC_FAIL_CALL_CFUNC_VARARGS; - case METH_VARARGS | METH_KEYWORDS: - return SPEC_FAIL_CALL_CFUNC_VARARGS_KEYWORDS; - case METH_NOARGS: - return SPEC_FAIL_CALL_CFUNC_NOARGS; - case METH_METHOD | METH_FASTCALL | METH_KEYWORDS: - return SPEC_FAIL_CALL_CFUNC_METHOD_FASTCALL_KEYWORDS; - /* These cases should be optimized, but return "other" just in case */ - case METH_O: - case METH_FASTCALL: - case METH_FASTCALL | METH_KEYWORDS: - return SPEC_FAIL_OTHER; - default: - return SPEC_FAIL_CALL_BAD_CALL_FLAGS; - } -} - -static int -meth_descr_call_fail_kind(int ml_flags) -{ - switch (ml_flags & (METH_VARARGS | METH_FASTCALL | METH_NOARGS | METH_O | - METH_KEYWORDS | METH_METHOD)) { - case METH_VARARGS: - return SPEC_FAIL_CALL_METH_DESCR_VARARGS; - case METH_VARARGS | METH_KEYWORDS: - return SPEC_FAIL_CALL_METH_DESCR_VARARGS_KEYWORDS; - case METH_METHOD | METH_FASTCALL | METH_KEYWORDS: - return SPEC_FAIL_CALL_METH_DESCR_METHOD_FASTCALL_KEYWORDS; - /* These cases should be optimized, but return "other" just in case */ - case METH_NOARGS: - case METH_O: - case METH_FASTCALL: - case METH_FASTCALL | METH_KEYWORDS: - return SPEC_FAIL_OTHER; - default: - return SPEC_FAIL_CALL_BAD_CALL_FLAGS; - } -} -#endif // Py_STATS - static int specialize_method_descriptor(PyMethodDescrObject *descr, _Py_CODEUNIT *instr, int nargs) @@ -1985,33 +1938,6 @@ specialize_c_call(PyObject *callable, _Py_CODEUNIT *instr, int nargs) } } -#ifdef Py_STATS -static int -call_fail_kind(PyObject *callable) -{ - assert(!PyCFunction_CheckExact(callable)); - assert(!PyFunction_Check(callable)); - assert(!PyType_Check(callable)); - assert(!Py_IS_TYPE(callable, &PyMethodDescr_Type)); - assert(!PyMethod_Check(callable)); - if (PyInstanceMethod_Check(callable)) { - return SPEC_FAIL_CALL_INSTANCE_METHOD; - } - // builtin method - else if (PyCMethod_Check(callable)) { - return SPEC_FAIL_CALL_CMETHOD; - } - else if (Py_TYPE(callable) == &PyWrapperDescr_Type) { - return SPEC_FAIL_CALL_OPERATOR_WRAPPER; - } - else if (Py_TYPE(callable) == &_PyMethodWrapper_Type) { - return SPEC_FAIL_CALL_METHOD_WRAPPER; - } - return SPEC_FAIL_OTHER; -} -#endif // Py_STATS - - void _Py_Specialize_Call(PyObject *callable, _Py_CODEUNIT *instr, int nargs) { From b49bc86ae60b17530847302b2d8987a411313517 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Fri, 3 May 2024 10:20:04 +0100 Subject: [PATCH 07/17] Make sure that function version number is checked when tracing through calls. --- Include/internal/pycore_opcode_metadata.h | 8 ++++---- Include/internal/pycore_uop_ids.h | 8 ++++---- Include/internal/pycore_uop_metadata.h | 12 ++++++------ Python/bytecodes.c | 23 +++++++++++++---------- Python/ceval.c | 18 +++--------------- Python/executor_cases.c.h | 16 ++++++++++++++-- Python/generated_cases.c.h | 16 ++++++++++------ Python/optimizer.c | 1 + Python/optimizer_cases.c.h | 4 ++-- Python/specialize.c | 12 ++++++------ 10 files changed, 63 insertions(+), 55 deletions(-) diff --git a/Include/internal/pycore_opcode_metadata.h b/Include/internal/pycore_opcode_metadata.h index 9457bff1379060..64cf04e0e8b69c 100644 --- a/Include/internal/pycore_opcode_metadata.h +++ b/Include/internal/pycore_opcode_metadata.h @@ -993,7 +993,7 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[268] = { [CALL] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, [CALL_ALLOC_AND_ENTER_INIT] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, [CALL_BOUND_METHOD_EXACT_ARGS] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG }, - [CALL_BOUND_METHOD_GENERAL] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, + [CALL_BOUND_METHOD_GENERAL] = { 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_BUILTIN_CLASS] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [CALL_BUILTIN_FAST] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [CALL_BUILTIN_FAST_WITH_KEYWORDS] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, @@ -1011,7 +1011,7 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[268] = { [CALL_METHOD_DESCRIPTOR_O] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [CALL_NON_PY_GENERAL] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [CALL_PY_EXACT_ARGS] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG }, - [CALL_PY_GENERAL] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, + [CALL_PY_GENERAL] = { 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_STR_1] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [CALL_TUPLE_1] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [CALL_TYPE_1] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_DEOPT_FLAG }, @@ -1221,7 +1221,7 @@ _PyOpcode_macro_expansion[256] = { [BUILD_STRING] = { .nuops = 1, .uops = { { _BUILD_STRING, 0, 0 } } }, [BUILD_TUPLE] = { .nuops = 1, .uops = { { _BUILD_TUPLE, 0, 0 } } }, [CALL_BOUND_METHOD_EXACT_ARGS] = { .nuops = 8, .uops = { { _CHECK_PEP_523, 0, 0 }, { _CHECK_CALL_BOUND_METHOD_EXACT_ARGS, 0, 0 }, { _INIT_CALL_BOUND_METHOD_EXACT_ARGS, 0, 0 }, { _CHECK_FUNCTION_EXACT_ARGS, 2, 1 }, { _CHECK_STACK_SPACE, 0, 0 }, { _INIT_CALL_PY_EXACT_ARGS, 0, 0 }, { _SAVE_RETURN_OFFSET, 7, 3 }, { _PUSH_FRAME, 0, 0 } } }, - [CALL_BOUND_METHOD_GENERAL] = { .nuops = 5, .uops = { { _CHECK_PEP_523, 0, 0 }, { _CHECK_IS_METHOD, 0, 0 }, { _EXPAND_METHOD, 0, 0 }, { _CALL_PY_GENERAL, 0, 0 }, { _PUSH_FRAME, 0, 0 } } }, + [CALL_BOUND_METHOD_GENERAL] = { .nuops = 5, .uops = { { _CHECK_PEP_523, 0, 0 }, { _CHECK_METHOD_VERSION, 2, 1 }, { _EXPAND_METHOD, 0, 0 }, { _CALL_PY_GENERAL, 0, 0 }, { _PUSH_FRAME, 0, 0 } } }, [CALL_BUILTIN_CLASS] = { .nuops = 2, .uops = { { _CALL_BUILTIN_CLASS, 0, 0 }, { _CHECK_PERIODIC, 0, 0 } } }, [CALL_BUILTIN_FAST] = { .nuops = 2, .uops = { { _CALL_BUILTIN_FAST, 0, 0 }, { _CHECK_PERIODIC, 0, 0 } } }, [CALL_BUILTIN_FAST_WITH_KEYWORDS] = { .nuops = 2, .uops = { { _CALL_BUILTIN_FAST_WITH_KEYWORDS, 0, 0 }, { _CHECK_PERIODIC, 0, 0 } } }, @@ -1236,7 +1236,7 @@ _PyOpcode_macro_expansion[256] = { [CALL_METHOD_DESCRIPTOR_O] = { .nuops = 2, .uops = { { _CALL_METHOD_DESCRIPTOR_O, 0, 0 }, { _CHECK_PERIODIC, 0, 0 } } }, [CALL_NON_PY_GENERAL] = { .nuops = 3, .uops = { { _CHECK_IS_NOT_PY_CALLABLE, 0, 0 }, { _CALL_NON_PY_GENERAL, 0, 0 }, { _CHECK_PERIODIC, 0, 0 } } }, [CALL_PY_EXACT_ARGS] = { .nuops = 6, .uops = { { _CHECK_PEP_523, 0, 0 }, { _CHECK_FUNCTION_EXACT_ARGS, 2, 1 }, { _CHECK_STACK_SPACE, 0, 0 }, { _INIT_CALL_PY_EXACT_ARGS, 0, 0 }, { _SAVE_RETURN_OFFSET, 7, 3 }, { _PUSH_FRAME, 0, 0 } } }, - [CALL_PY_GENERAL] = { .nuops = 4, .uops = { { _CHECK_PEP_523, 0, 0 }, { _CHECK_IS_FUNCTION, 0, 0 }, { _CALL_PY_GENERAL, 0, 0 }, { _PUSH_FRAME, 0, 0 } } }, + [CALL_PY_GENERAL] = { .nuops = 4, .uops = { { _CHECK_PEP_523, 0, 0 }, { _CHECK_FUNCTION_VERSION, 2, 1 }, { _CALL_PY_GENERAL, 0, 0 }, { _PUSH_FRAME, 0, 0 } } }, [CALL_STR_1] = { .nuops = 2, .uops = { { _CALL_STR_1, 0, 0 }, { _CHECK_PERIODIC, 0, 0 } } }, [CALL_TUPLE_1] = { .nuops = 2, .uops = { { _CALL_TUPLE_1, 0, 0 }, { _CHECK_PERIODIC, 0, 0 } } }, [CALL_TYPE_1] = { .nuops = 1, .uops = { { _CALL_TYPE_1, 0, 0 } } }, diff --git a/Include/internal/pycore_uop_ids.h b/Include/internal/pycore_uop_ids.h index b025a3a893d93b..caa8a0e2f1236c 100644 --- a/Include/internal/pycore_uop_ids.h +++ b/Include/internal/pycore_uop_ids.h @@ -65,10 +65,10 @@ extern "C" { #define _CHECK_EXC_MATCH CHECK_EXC_MATCH #define _CHECK_FUNCTION 329 #define _CHECK_FUNCTION_EXACT_ARGS 330 -#define _CHECK_IS_FUNCTION 331 -#define _CHECK_IS_METHOD 332 -#define _CHECK_IS_NOT_PY_CALLABLE 333 -#define _CHECK_MANAGED_OBJECT_HAS_VALUES 334 +#define _CHECK_FUNCTION_VERSION 331 +#define _CHECK_IS_NOT_PY_CALLABLE 332 +#define _CHECK_MANAGED_OBJECT_HAS_VALUES 333 +#define _CHECK_METHOD_VERSION 334 #define _CHECK_PEP_523 335 #define _CHECK_PERIODIC 336 #define _CHECK_STACK_SPACE 337 diff --git a/Include/internal/pycore_uop_metadata.h b/Include/internal/pycore_uop_metadata.h index 7f6090c23b590e..bc1bd50a2011f9 100644 --- a/Include/internal/pycore_uop_metadata.h +++ b/Include/internal/pycore_uop_metadata.h @@ -194,8 +194,8 @@ const uint16_t _PyUop_Flags[MAX_UOP_ID+1] = { [_LOAD_ATTR_METHOD_LAZY_DICT] = HAS_ARG_FLAG, [_CHECK_PERIODIC] = HAS_EVAL_BREAK_FLAG, [_CALL_PY_GENERAL] = HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG, - [_CHECK_IS_FUNCTION] = HAS_ARG_FLAG | HAS_DEOPT_FLAG, - [_CHECK_IS_METHOD] = HAS_ARG_FLAG | HAS_DEOPT_FLAG, + [_CHECK_FUNCTION_VERSION] = HAS_ARG_FLAG | HAS_EXIT_FLAG, + [_CHECK_METHOD_VERSION] = HAS_ARG_FLAG | HAS_EXIT_FLAG, [_EXPAND_METHOD] = HAS_ARG_FLAG, [_CHECK_IS_NOT_PY_CALLABLE] = HAS_ARG_FLAG | HAS_DEOPT_FLAG, [_CALL_NON_PY_GENERAL] = HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, @@ -316,10 +316,10 @@ const char *const _PyOpcode_uop_name[MAX_UOP_ID+1] = { [_CHECK_EXC_MATCH] = "_CHECK_EXC_MATCH", [_CHECK_FUNCTION] = "_CHECK_FUNCTION", [_CHECK_FUNCTION_EXACT_ARGS] = "_CHECK_FUNCTION_EXACT_ARGS", - [_CHECK_IS_FUNCTION] = "_CHECK_IS_FUNCTION", - [_CHECK_IS_METHOD] = "_CHECK_IS_METHOD", + [_CHECK_FUNCTION_VERSION] = "_CHECK_FUNCTION_VERSION", [_CHECK_IS_NOT_PY_CALLABLE] = "_CHECK_IS_NOT_PY_CALLABLE", [_CHECK_MANAGED_OBJECT_HAS_VALUES] = "_CHECK_MANAGED_OBJECT_HAS_VALUES", + [_CHECK_METHOD_VERSION] = "_CHECK_METHOD_VERSION", [_CHECK_PEP_523] = "_CHECK_PEP_523", [_CHECK_PERIODIC] = "_CHECK_PERIODIC", [_CHECK_STACK_SPACE] = "_CHECK_STACK_SPACE", @@ -866,9 +866,9 @@ int _PyUop_num_popped(int opcode, int oparg) return 0; case _CALL_PY_GENERAL: return 2 + oparg; - case _CHECK_IS_FUNCTION: + case _CHECK_FUNCTION_VERSION: return 2 + oparg; - case _CHECK_IS_METHOD: + case _CHECK_METHOD_VERSION: return 2 + oparg; case _EXPAND_METHOD: return 2 + oparg; diff --git a/Python/bytecodes.c b/Python/bytecodes.c index c54763ce719d74..0499bd0f422043 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -3171,22 +3171,26 @@ dummy_func( frame->return_offset = (uint16_t)(1 + INLINE_CACHE_ENTRIES_CALL); } - op(_CHECK_IS_FUNCTION, (callable, unused, unused[oparg] -- callable, unused, unused[oparg])) { - DEOPT_IF(!PyFunction_Check(callable)); + op(_CHECK_FUNCTION_VERSION, (func_version/2, callable, unused, unused[oparg] -- callable, unused, unused[oparg])) { + EXIT_IF(!PyFunction_Check(callable)); + PyFunctionObject *func = (PyFunctionObject *)callable; + EXIT_IF(func->func_version != func_version); } + macro(CALL_PY_GENERAL) = unused/1 + // Skip over the counter - unused/2 + _CHECK_PEP_523 + - _CHECK_IS_FUNCTION + + _CHECK_FUNCTION_VERSION + _CALL_PY_GENERAL + _PUSH_FRAME; - op(_CHECK_IS_METHOD, (callable, null, unused[oparg] -- callable, null, unused[oparg])) { - DEOPT_IF(Py_TYPE(callable) != &PyMethod_Type); - DEOPT_IF(!PyFunction_Check(((PyMethodObject *)callable)->im_func)); - DEOPT_IF(null != NULL); + op(_CHECK_METHOD_VERSION, (func_version/2, callable, null, unused[oparg] -- callable, null, unused[oparg])) { + EXIT_IF(Py_TYPE(callable) != &PyMethod_Type); + EXIT_IF(!PyFunction_Check(((PyMethodObject *)callable)->im_func)); + PyFunctionObject *func = (PyFunctionObject *)callable; + EXIT_IF(func->func_version != func_version); + EXIT_IF(null != NULL); } op(_EXPAND_METHOD, (callable, null, unused[oparg] -- method, self, unused[oparg])) { @@ -3203,9 +3207,8 @@ dummy_func( macro(CALL_BOUND_METHOD_GENERAL) = unused/1 + // Skip over the counter - unused/2 + _CHECK_PEP_523 + - _CHECK_IS_METHOD + + _CHECK_METHOD_VERSION + _EXPAND_METHOD + _CALL_PY_GENERAL + _PUSH_FRAME; diff --git a/Python/ceval.c b/Python/ceval.c index de6784a5dabe0a..814f2deae57076 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -107,7 +107,7 @@ static void dump_stack(_PyInterpreterFrame *frame, PyObject **stack_pointer) { PyObject **stack_base = _PyFrame_Stackbase(frame); - PyObject *exc = PyErr_GetRaisedException(); + // PyObject *exc = PyErr_GetRaisedException(); printf(" stack=["); for (PyObject **ptr = stack_base; ptr < stack_pointer; ptr++) { if (ptr != stack_base) { @@ -117,24 +117,12 @@ dump_stack(_PyInterpreterFrame *frame, PyObject **stack_pointer) printf(""); continue; } - if ( - *ptr == Py_None - || PyBool_Check(*ptr) - || PyLong_CheckExact(*ptr) - || PyFloat_CheckExact(*ptr) - || PyUnicode_CheckExact(*ptr) - ) { - if (PyObject_Print(*ptr, stdout, 0) == 0) { - continue; - } - PyErr_Clear(); - } // Don't call __repr__(), it might recurse into the interpreter. printf("<%s at %p>", Py_TYPE(*ptr)->tp_name, (void *)(*ptr)); } printf("]\n"); - fflush(stdout); - PyErr_SetRaisedException(exc); + // fflush(stdout); + // PyErr_SetRaisedException(exc); } static void diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index 30ac5fc2dada94..90126b1dfdb1d6 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -3066,23 +3066,30 @@ break; } - case _CHECK_IS_FUNCTION: { + case _CHECK_FUNCTION_VERSION: { PyObject *callable; oparg = CURRENT_OPARG(); callable = stack_pointer[-2 - oparg]; + uint32_t func_version = (uint32_t)CURRENT_OPERAND(); if (!PyFunction_Check(callable)) { UOP_STAT_INC(uopcode, miss); JUMP_TO_JUMP_TARGET(); } + PyFunctionObject *func = (PyFunctionObject *)callable; + if (func->func_version != func_version) { + UOP_STAT_INC(uopcode, miss); + JUMP_TO_JUMP_TARGET(); + } break; } - case _CHECK_IS_METHOD: { + case _CHECK_METHOD_VERSION: { PyObject *null; PyObject *callable; oparg = CURRENT_OPARG(); null = stack_pointer[-1 - oparg]; callable = stack_pointer[-2 - oparg]; + uint32_t func_version = (uint32_t)CURRENT_OPERAND(); if (Py_TYPE(callable) != &PyMethod_Type) { UOP_STAT_INC(uopcode, miss); JUMP_TO_JUMP_TARGET(); @@ -3091,6 +3098,11 @@ UOP_STAT_INC(uopcode, miss); JUMP_TO_JUMP_TARGET(); } + PyFunctionObject *func = (PyFunctionObject *)callable; + if (func->func_version != func_version) { + UOP_STAT_INC(uopcode, miss); + JUMP_TO_JUMP_TARGET(); + } if (null != NULL) { UOP_STAT_INC(uopcode, miss); JUMP_TO_JUMP_TARGET(); diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 95a0d2c15eee4f..9c0c5f1b5ff20a 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -1003,7 +1003,7 @@ } TARGET(CALL_BOUND_METHOD_GENERAL) { - frame->instr_ptr = next_instr; + _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; next_instr += 4; INSTRUCTION_STATS(CALL_BOUND_METHOD_GENERAL); static_assert(INLINE_CACHE_ENTRIES_CALL == 3, "incorrect cache size"); @@ -1015,17 +1015,19 @@ PyObject *self_or_null; _PyInterpreterFrame *new_frame; /* Skip 1 cache entry */ - /* Skip 2 cache entries */ // _CHECK_PEP_523 { DEOPT_IF(tstate->interp->eval_frame, CALL); } - // _CHECK_IS_METHOD + // _CHECK_METHOD_VERSION null = stack_pointer[-1 - oparg]; callable = stack_pointer[-2 - oparg]; { + uint32_t func_version = read_u32(&this_instr[2].cache); DEOPT_IF(Py_TYPE(callable) != &PyMethod_Type, CALL); DEOPT_IF(!PyFunction_Check(((PyMethodObject *)callable)->im_func), CALL); + PyFunctionObject *func = (PyFunctionObject *)callable; + DEOPT_IF(func->func_version != func_version, CALL); DEOPT_IF(null != NULL, CALL); } // _EXPAND_METHOD @@ -1918,7 +1920,7 @@ } TARGET(CALL_PY_GENERAL) { - frame->instr_ptr = next_instr; + _Py_CODEUNIT *this_instr = frame->instr_ptr = next_instr; next_instr += 4; INSTRUCTION_STATS(CALL_PY_GENERAL); static_assert(INLINE_CACHE_ENTRIES_CALL == 3, "incorrect cache size"); @@ -1927,15 +1929,17 @@ PyObject *self_or_null; _PyInterpreterFrame *new_frame; /* Skip 1 cache entry */ - /* Skip 2 cache entries */ // _CHECK_PEP_523 { DEOPT_IF(tstate->interp->eval_frame, CALL); } - // _CHECK_IS_FUNCTION + // _CHECK_FUNCTION_VERSION callable = stack_pointer[-2 - oparg]; { + uint32_t func_version = read_u32(&this_instr[2].cache); DEOPT_IF(!PyFunction_Check(callable), CALL); + PyFunctionObject *func = (PyFunctionObject *)callable; + DEOPT_IF(func->func_version != func_version, CALL); } // _CALL_PY_GENERAL args = &stack_pointer[-oparg]; diff --git a/Python/optimizer.c b/Python/optimizer.c index 56768ae8f542f6..a626110aa483d7 100644 --- a/Python/optimizer.c +++ b/Python/optimizer.c @@ -987,6 +987,7 @@ static void make_exit(_PyUOpInstruction *inst, int opcode, int target) { inst->opcode = opcode; inst->oparg = 0; + inst->operand = 0; inst->format = UOP_FORMAT_TARGET; inst->target = target; } diff --git a/Python/optimizer_cases.c.h b/Python/optimizer_cases.c.h index c80a6e5363ae3e..dcb3efc857c4a9 100644 --- a/Python/optimizer_cases.c.h +++ b/Python/optimizer_cases.c.h @@ -1578,11 +1578,11 @@ break; } - case _CHECK_IS_FUNCTION: { + case _CHECK_FUNCTION_VERSION: { break; } - case _CHECK_IS_METHOD: { + case _CHECK_METHOD_VERSION: { break; } diff --git a/Python/specialize.c b/Python/specialize.c index 15e4950fb2f9ad..9ac428c3593f56 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -1877,13 +1877,13 @@ specialize_py_call(PyFunctionObject *func, _Py_CODEUNIT *instr, int nargs, if (kind == SIMPLE_FUNCTION) { argcount = code->co_argcount; } + int version = _PyFunction_GetVersionForCurrentState(func); + if (version == 0) { + SPECIALIZATION_FAIL(CALL, SPEC_FAIL_OUT_OF_VERSIONS); + return -1; + } + write_u32(cache->func_version, version); if (argcount == nargs + bound_method) { - int version = _PyFunction_GetVersionForCurrentState(func); - if (version == 0) { - SPECIALIZATION_FAIL(CALL, SPEC_FAIL_OUT_OF_VERSIONS); - return -1; - } - write_u32(cache->func_version, version); instr->op.code = bound_method ? CALL_BOUND_METHOD_EXACT_ARGS : CALL_PY_EXACT_ARGS; } else { From f42519deb6d93beb270e2de3d60517b20dcc3f39 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Fri, 3 May 2024 10:22:32 +0100 Subject: [PATCH 08/17] whitespace --- Python/bytecodes.c | 1 - 1 file changed, 1 deletion(-) diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 0499bd0f422043..0ffefe6f737caa 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -3177,7 +3177,6 @@ dummy_func( EXIT_IF(func->func_version != func_version); } - macro(CALL_PY_GENERAL) = unused/1 + // Skip over the counter _CHECK_PEP_523 + From 1a2dcfe6df12ef827905fd65ab21ec3dcaa0e68e Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Fri, 3 May 2024 10:49:04 +0100 Subject: [PATCH 09/17] Check verion on function, not method --- Python/bytecodes.c | 6 +++--- Python/executor_cases.c.h | 6 +++--- Python/generated_cases.c.h | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 0ffefe6f737caa..6b18fc426ca315 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -3186,9 +3186,9 @@ dummy_func( op(_CHECK_METHOD_VERSION, (func_version/2, callable, null, unused[oparg] -- callable, null, unused[oparg])) { EXIT_IF(Py_TYPE(callable) != &PyMethod_Type); - EXIT_IF(!PyFunction_Check(((PyMethodObject *)callable)->im_func)); - PyFunctionObject *func = (PyFunctionObject *)callable; - EXIT_IF(func->func_version != func_version); + PyObject *func = ((PyMethodObject *)callable)->im_func; + EXIT_IF(!PyFunction_Check(func)); + EXIT_IF(((PyFunctionObject *)func)->func_version != func_version); EXIT_IF(null != NULL); } diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index 90126b1dfdb1d6..fd77cdce879a28 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -3094,12 +3094,12 @@ UOP_STAT_INC(uopcode, miss); JUMP_TO_JUMP_TARGET(); } - if (!PyFunction_Check(((PyMethodObject *)callable)->im_func)) { + PyObject *func = ((PyMethodObject *)callable)->im_func; + if (!PyFunction_Check(func)) { UOP_STAT_INC(uopcode, miss); JUMP_TO_JUMP_TARGET(); } - PyFunctionObject *func = (PyFunctionObject *)callable; - if (func->func_version != func_version) { + if (((PyFunctionObject *)func)->func_version != func_version) { UOP_STAT_INC(uopcode, miss); JUMP_TO_JUMP_TARGET(); } diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 9c0c5f1b5ff20a..5e961639ef70f4 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -1025,9 +1025,9 @@ { uint32_t func_version = read_u32(&this_instr[2].cache); DEOPT_IF(Py_TYPE(callable) != &PyMethod_Type, CALL); - DEOPT_IF(!PyFunction_Check(((PyMethodObject *)callable)->im_func), CALL); - PyFunctionObject *func = (PyFunctionObject *)callable; - DEOPT_IF(func->func_version != func_version, CALL); + PyObject *func = ((PyMethodObject *)callable)->im_func; + DEOPT_IF(!PyFunction_Check(func), CALL); + DEOPT_IF(((PyFunctionObject *)func)->func_version != func_version, CALL); DEOPT_IF(null != NULL, CALL); } // _EXPAND_METHOD From 62ff43c9a35c701b807a759b905a36f2bd7723be Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Fri, 3 May 2024 11:37:50 +0100 Subject: [PATCH 10/17] Lower WASI C recursion limit again --- Include/cpython/pystate.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Include/cpython/pystate.h b/Include/cpython/pystate.h index 0611e299403031..badf76df86d371 100644 --- a/Include/cpython/pystate.h +++ b/Include/cpython/pystate.h @@ -193,7 +193,12 @@ struct _ts { #ifdef Py_DEBUG // A debug build is likely built with low optimization level which implies // higher stack memory usage than a release build: use a lower limit. -# define Py_C_RECURSION_LIMIT 500 +# if defined(__wasi__) + // Based on wasmtime 16. +# define Py_C_RECURSION_LIMIT 400 +# else +# define Py_C_RECURSION_LIMIT 500 +# endif #elif defined(__s390x__) # define Py_C_RECURSION_LIMIT 800 #elif defined(_WIN32) && defined(_M_ARM64) From 71c6d4140837b800cce7d3ac97d638609d4e0d22 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Fri, 3 May 2024 12:38:47 +0100 Subject: [PATCH 11/17] Get test passing on wasi --- Lib/test/test_dynamic.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/test_dynamic.py b/Lib/test/test_dynamic.py index 0aa3be6a1bde6a..48b7161ac3f183 100644 --- a/Lib/test/test_dynamic.py +++ b/Lib/test/test_dynamic.py @@ -141,7 +141,7 @@ def __missing__(self, key): return int(key.removeprefix("_number_")) # Need more than 256 variables to use EXTENDED_ARGS - variables = 400 + variables = 300 code = "lambda: " + "+".join(f"_number_{i}" for i in range(variables)) sum_func = eval(code, MyGlobals()) expected = sum(range(variables)) From 0b4077327d84275682adfc7f54053c7651cdb8da Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Fri, 3 May 2024 13:01:45 +0100 Subject: [PATCH 12/17] Lower WASI C recursion limit again --- Include/cpython/pystate.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Include/cpython/pystate.h b/Include/cpython/pystate.h index badf76df86d371..2fbe8866b7b46b 100644 --- a/Include/cpython/pystate.h +++ b/Include/cpython/pystate.h @@ -195,7 +195,7 @@ struct _ts { // higher stack memory usage than a release build: use a lower limit. # if defined(__wasi__) // Based on wasmtime 16. -# define Py_C_RECURSION_LIMIT 400 +# define Py_C_RECURSION_LIMIT 350 # else # define Py_C_RECURSION_LIMIT 500 # endif From 02cdf2f12fdcbe2b1c6103d8e93c8ab22a37e4c9 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Fri, 3 May 2024 13:58:47 +0100 Subject: [PATCH 13/17] Yet another attempt to get the WASI build to work --- Include/cpython/pystate.h | 2 +- Lib/test/test_dynamic.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Include/cpython/pystate.h b/Include/cpython/pystate.h index 2fbe8866b7b46b..f3ef7896266304 100644 --- a/Include/cpython/pystate.h +++ b/Include/cpython/pystate.h @@ -195,7 +195,7 @@ struct _ts { // higher stack memory usage than a release build: use a lower limit. # if defined(__wasi__) // Based on wasmtime 16. -# define Py_C_RECURSION_LIMIT 350 +# define Py_C_RECURSION_LIMIT 300 # else # define Py_C_RECURSION_LIMIT 500 # endif diff --git a/Lib/test/test_dynamic.py b/Lib/test/test_dynamic.py index 48b7161ac3f183..f6c1a5bb73e819 100644 --- a/Lib/test/test_dynamic.py +++ b/Lib/test/test_dynamic.py @@ -141,7 +141,7 @@ def __missing__(self, key): return int(key.removeprefix("_number_")) # Need more than 256 variables to use EXTENDED_ARGS - variables = 300 + variables = 270 code = "lambda: " + "+".join(f"_number_{i}" for i in range(variables)) sum_func = eval(code, MyGlobals()) expected = sum(range(variables)) From 1831eb3939164dd9493f82668f86dffeb5b15135 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Fri, 3 May 2024 14:42:06 +0100 Subject: [PATCH 14/17] Skip test for WASI --- Include/cpython/pystate.h | 7 +------ Lib/test/test_dynamic.py | 5 +++-- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/Include/cpython/pystate.h b/Include/cpython/pystate.h index f3ef7896266304..0611e299403031 100644 --- a/Include/cpython/pystate.h +++ b/Include/cpython/pystate.h @@ -193,12 +193,7 @@ struct _ts { #ifdef Py_DEBUG // A debug build is likely built with low optimization level which implies // higher stack memory usage than a release build: use a lower limit. -# if defined(__wasi__) - // Based on wasmtime 16. -# define Py_C_RECURSION_LIMIT 300 -# else -# define Py_C_RECURSION_LIMIT 500 -# endif +# define Py_C_RECURSION_LIMIT 500 #elif defined(__s390x__) # define Py_C_RECURSION_LIMIT 800 #elif defined(_WIN32) && defined(_M_ARM64) diff --git a/Lib/test/test_dynamic.py b/Lib/test/test_dynamic.py index f6c1a5bb73e819..632052f61769bb 100644 --- a/Lib/test/test_dynamic.py +++ b/Lib/test/test_dynamic.py @@ -4,7 +4,7 @@ import sys import unittest -from test.support import swap_item, swap_attr +from test.support import swap_item, swap_attr, is_wasi class RebindBuiltinsTests(unittest.TestCase): @@ -134,6 +134,7 @@ def test_eval_gives_lambda_custom_globals(self): self.assertEqual(foo(), 7) + @unittest.skipIf(is_wasi and Py_DEBUG, "requires too much stack") def test_load_global_specialization_failure_keeps_oparg(self): # https://github.com/python/cpython/issues/91625 class MyGlobals(dict): @@ -141,7 +142,7 @@ def __missing__(self, key): return int(key.removeprefix("_number_")) # Need more than 256 variables to use EXTENDED_ARGS - variables = 270 + variables = 400 code = "lambda: " + "+".join(f"_number_{i}" for i in range(variables)) sum_func = eval(code, MyGlobals()) expected = sum(range(variables)) From 7819b1c0e058e4190d78b34ccfd946e317ce1ff0 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Fri, 3 May 2024 15:10:44 +0100 Subject: [PATCH 15/17] Skip another test for WASI --- Lib/test/test_dynamic.py | 2 +- Lib/test/test_glob.py | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_dynamic.py b/Lib/test/test_dynamic.py index 632052f61769bb..21bece26b893c6 100644 --- a/Lib/test/test_dynamic.py +++ b/Lib/test/test_dynamic.py @@ -4,7 +4,7 @@ import sys import unittest -from test.support import swap_item, swap_attr, is_wasi +from test.support import swap_item, swap_attr, is_wasi, Py_DEBUG class RebindBuiltinsTests(unittest.TestCase): diff --git a/Lib/test/test_glob.py b/Lib/test/test_glob.py index 70ee35ed2850bc..b72640bd871ba6 100644 --- a/Lib/test/test_glob.py +++ b/Lib/test/test_glob.py @@ -6,6 +6,7 @@ import unittest import warnings +from test.support import is_wasi, Py_DEBUG from test.support.os_helper import (TESTFN, skip_unless_symlink, can_symlink, create_empty_file, change_cwd) @@ -366,6 +367,8 @@ def test_glob_named_pipe(self): self.assertEqual(self.rglob('mypipe', 'sub'), []) self.assertEqual(self.rglob('mypipe', '*'), []) + + @unittest.skipIf(is_wasi and Py_DEBUG, "requires too much stack") def test_glob_many_open_files(self): depth = 30 base = os.path.join(self.tempdir, 'deep') From 857d152acc589038f46ab727e217d35ddb9579f6 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Sat, 4 May 2024 09:21:56 +0100 Subject: [PATCH 16/17] Address some review comments --- Include/internal/pycore_opcode_metadata.h | 2 +- Include/internal/pycore_uop_metadata.h | 4 ++-- Lib/test/test_call.py | 2 +- Python/bytecodes.c | 8 ++++---- Python/ceval.c | 18 +++++++++++++++--- 5 files changed, 23 insertions(+), 11 deletions(-) diff --git a/Include/internal/pycore_opcode_metadata.h b/Include/internal/pycore_opcode_metadata.h index 64cf04e0e8b69c..20aa980f22ef9d 100644 --- a/Include/internal/pycore_opcode_metadata.h +++ b/Include/internal/pycore_opcode_metadata.h @@ -1009,7 +1009,7 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[268] = { [CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [CALL_METHOD_DESCRIPTOR_NOARGS] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [CALL_METHOD_DESCRIPTOR_O] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, - [CALL_NON_PY_GENERAL] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, + [CALL_NON_PY_GENERAL] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [CALL_PY_EXACT_ARGS] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG }, [CALL_PY_GENERAL] = { 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_STR_1] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, diff --git a/Include/internal/pycore_uop_metadata.h b/Include/internal/pycore_uop_metadata.h index bc1bd50a2011f9..1c76dc1beb54c3 100644 --- a/Include/internal/pycore_uop_metadata.h +++ b/Include/internal/pycore_uop_metadata.h @@ -197,9 +197,9 @@ const uint16_t _PyUop_Flags[MAX_UOP_ID+1] = { [_CHECK_FUNCTION_VERSION] = HAS_ARG_FLAG | HAS_EXIT_FLAG, [_CHECK_METHOD_VERSION] = HAS_ARG_FLAG | HAS_EXIT_FLAG, [_EXPAND_METHOD] = HAS_ARG_FLAG, - [_CHECK_IS_NOT_PY_CALLABLE] = HAS_ARG_FLAG | HAS_DEOPT_FLAG, + [_CHECK_IS_NOT_PY_CALLABLE] = HAS_ARG_FLAG | HAS_EXIT_FLAG, [_CALL_NON_PY_GENERAL] = HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, - [_CHECK_CALL_BOUND_METHOD_EXACT_ARGS] = HAS_ARG_FLAG | HAS_DEOPT_FLAG, + [_CHECK_CALL_BOUND_METHOD_EXACT_ARGS] = HAS_ARG_FLAG | HAS_EXIT_FLAG, [_INIT_CALL_BOUND_METHOD_EXACT_ARGS] = HAS_ARG_FLAG, [_CHECK_PEP_523] = HAS_DEOPT_FLAG, [_CHECK_FUNCTION_EXACT_ARGS] = HAS_ARG_FLAG | HAS_EXIT_FLAG, diff --git a/Lib/test/test_call.py b/Lib/test/test_call.py index 8f94d3d79c6bec..7ea27929138da3 100644 --- a/Lib/test/test_call.py +++ b/Lib/test/test_call.py @@ -49,7 +49,7 @@ def f(): class C: def m(self): pass - callables = [ f, C.m, [].__len__ ] + callables = [f, C.m, [].__len__] for c in callables: for _ in range(1000): try: diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 6b18fc426ca315..4b06e676ef1c3a 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -3213,8 +3213,8 @@ dummy_func( _PUSH_FRAME; op(_CHECK_IS_NOT_PY_CALLABLE, (callable, unused, unused[oparg] -- callable, unused, unused[oparg])) { - DEOPT_IF(PyFunction_Check(callable)); - DEOPT_IF(Py_TYPE(callable) == &PyMethod_Type); + EXIT_IF(PyFunction_Check(callable)); + EXIT_IF(Py_TYPE(callable) == &PyMethod_Type); } op(_CALL_NON_PY_GENERAL, (callable, self_or_null, args[oparg] -- res)) { @@ -3247,8 +3247,8 @@ dummy_func( _CHECK_PERIODIC; op(_CHECK_CALL_BOUND_METHOD_EXACT_ARGS, (callable, null, unused[oparg] -- callable, null, unused[oparg])) { - DEOPT_IF(null != NULL); - DEOPT_IF(Py_TYPE(callable) != &PyMethod_Type); + EXIT_IF(null != NULL); + EXIT_IF(Py_TYPE(callable) != &PyMethod_Type); } op(_INIT_CALL_BOUND_METHOD_EXACT_ARGS, (callable, unused, unused[oparg] -- func, self, unused[oparg])) { diff --git a/Python/ceval.c b/Python/ceval.c index 814f2deae57076..de6784a5dabe0a 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -107,7 +107,7 @@ static void dump_stack(_PyInterpreterFrame *frame, PyObject **stack_pointer) { PyObject **stack_base = _PyFrame_Stackbase(frame); - // PyObject *exc = PyErr_GetRaisedException(); + PyObject *exc = PyErr_GetRaisedException(); printf(" stack=["); for (PyObject **ptr = stack_base; ptr < stack_pointer; ptr++) { if (ptr != stack_base) { @@ -117,12 +117,24 @@ dump_stack(_PyInterpreterFrame *frame, PyObject **stack_pointer) printf(""); continue; } + if ( + *ptr == Py_None + || PyBool_Check(*ptr) + || PyLong_CheckExact(*ptr) + || PyFloat_CheckExact(*ptr) + || PyUnicode_CheckExact(*ptr) + ) { + if (PyObject_Print(*ptr, stdout, 0) == 0) { + continue; + } + PyErr_Clear(); + } // Don't call __repr__(), it might recurse into the interpreter. printf("<%s at %p>", Py_TYPE(*ptr)->tp_name, (void *)(*ptr)); } printf("]\n"); - // fflush(stdout); - // PyErr_SetRaisedException(exc); + fflush(stdout); + PyErr_SetRaisedException(exc); } static void From 839d16e009c57c379b5dfc1fa1387a6a2259b49e Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Sat, 4 May 2024 09:32:34 +0100 Subject: [PATCH 17/17] Use _SAVE_RETURN_OFFSET in general call instructions --- Include/internal/pycore_opcode_metadata.h | 4 +- Include/internal/pycore_uop_ids.h | 222 +++++++++++----------- Include/internal/pycore_uop_metadata.h | 6 +- Python/bytecodes.c | 11 +- Python/executor_cases.c.h | 5 +- Python/generated_cases.c.h | 26 ++- Python/optimizer_bytecodes.c | 2 +- Python/optimizer_cases.c.h | 2 +- 8 files changed, 147 insertions(+), 131 deletions(-) diff --git a/Include/internal/pycore_opcode_metadata.h b/Include/internal/pycore_opcode_metadata.h index 20aa980f22ef9d..2a237bc6dd8ee5 100644 --- a/Include/internal/pycore_opcode_metadata.h +++ b/Include/internal/pycore_opcode_metadata.h @@ -1221,7 +1221,7 @@ _PyOpcode_macro_expansion[256] = { [BUILD_STRING] = { .nuops = 1, .uops = { { _BUILD_STRING, 0, 0 } } }, [BUILD_TUPLE] = { .nuops = 1, .uops = { { _BUILD_TUPLE, 0, 0 } } }, [CALL_BOUND_METHOD_EXACT_ARGS] = { .nuops = 8, .uops = { { _CHECK_PEP_523, 0, 0 }, { _CHECK_CALL_BOUND_METHOD_EXACT_ARGS, 0, 0 }, { _INIT_CALL_BOUND_METHOD_EXACT_ARGS, 0, 0 }, { _CHECK_FUNCTION_EXACT_ARGS, 2, 1 }, { _CHECK_STACK_SPACE, 0, 0 }, { _INIT_CALL_PY_EXACT_ARGS, 0, 0 }, { _SAVE_RETURN_OFFSET, 7, 3 }, { _PUSH_FRAME, 0, 0 } } }, - [CALL_BOUND_METHOD_GENERAL] = { .nuops = 5, .uops = { { _CHECK_PEP_523, 0, 0 }, { _CHECK_METHOD_VERSION, 2, 1 }, { _EXPAND_METHOD, 0, 0 }, { _CALL_PY_GENERAL, 0, 0 }, { _PUSH_FRAME, 0, 0 } } }, + [CALL_BOUND_METHOD_GENERAL] = { .nuops = 6, .uops = { { _CHECK_PEP_523, 0, 0 }, { _CHECK_METHOD_VERSION, 2, 1 }, { _EXPAND_METHOD, 0, 0 }, { _PY_FRAME_GENERAL, 0, 0 }, { _SAVE_RETURN_OFFSET, 7, 3 }, { _PUSH_FRAME, 0, 0 } } }, [CALL_BUILTIN_CLASS] = { .nuops = 2, .uops = { { _CALL_BUILTIN_CLASS, 0, 0 }, { _CHECK_PERIODIC, 0, 0 } } }, [CALL_BUILTIN_FAST] = { .nuops = 2, .uops = { { _CALL_BUILTIN_FAST, 0, 0 }, { _CHECK_PERIODIC, 0, 0 } } }, [CALL_BUILTIN_FAST_WITH_KEYWORDS] = { .nuops = 2, .uops = { { _CALL_BUILTIN_FAST_WITH_KEYWORDS, 0, 0 }, { _CHECK_PERIODIC, 0, 0 } } }, @@ -1236,7 +1236,7 @@ _PyOpcode_macro_expansion[256] = { [CALL_METHOD_DESCRIPTOR_O] = { .nuops = 2, .uops = { { _CALL_METHOD_DESCRIPTOR_O, 0, 0 }, { _CHECK_PERIODIC, 0, 0 } } }, [CALL_NON_PY_GENERAL] = { .nuops = 3, .uops = { { _CHECK_IS_NOT_PY_CALLABLE, 0, 0 }, { _CALL_NON_PY_GENERAL, 0, 0 }, { _CHECK_PERIODIC, 0, 0 } } }, [CALL_PY_EXACT_ARGS] = { .nuops = 6, .uops = { { _CHECK_PEP_523, 0, 0 }, { _CHECK_FUNCTION_EXACT_ARGS, 2, 1 }, { _CHECK_STACK_SPACE, 0, 0 }, { _INIT_CALL_PY_EXACT_ARGS, 0, 0 }, { _SAVE_RETURN_OFFSET, 7, 3 }, { _PUSH_FRAME, 0, 0 } } }, - [CALL_PY_GENERAL] = { .nuops = 4, .uops = { { _CHECK_PEP_523, 0, 0 }, { _CHECK_FUNCTION_VERSION, 2, 1 }, { _CALL_PY_GENERAL, 0, 0 }, { _PUSH_FRAME, 0, 0 } } }, + [CALL_PY_GENERAL] = { .nuops = 5, .uops = { { _CHECK_PEP_523, 0, 0 }, { _CHECK_FUNCTION_VERSION, 2, 1 }, { _PY_FRAME_GENERAL, 0, 0 }, { _SAVE_RETURN_OFFSET, 7, 3 }, { _PUSH_FRAME, 0, 0 } } }, [CALL_STR_1] = { .nuops = 2, .uops = { { _CALL_STR_1, 0, 0 }, { _CHECK_PERIODIC, 0, 0 } } }, [CALL_TUPLE_1] = { .nuops = 2, .uops = { { _CALL_TUPLE_1, 0, 0 }, { _CHECK_PERIODIC, 0, 0 } } }, [CALL_TYPE_1] = { .nuops = 1, .uops = { { _CALL_TYPE_1, 0, 0 } } }, diff --git a/Include/internal/pycore_uop_ids.h b/Include/internal/pycore_uop_ids.h index caa8a0e2f1236c..b1726200740035 100644 --- a/Include/internal/pycore_uop_ids.h +++ b/Include/internal/pycore_uop_ids.h @@ -52,35 +52,34 @@ extern "C" { #define _CALL_METHOD_DESCRIPTOR_NOARGS 318 #define _CALL_METHOD_DESCRIPTOR_O 319 #define _CALL_NON_PY_GENERAL 320 -#define _CALL_PY_GENERAL 321 -#define _CALL_STR_1 322 -#define _CALL_TUPLE_1 323 +#define _CALL_STR_1 321 +#define _CALL_TUPLE_1 322 #define _CALL_TYPE_1 CALL_TYPE_1 -#define _CHECK_ATTR_CLASS 324 -#define _CHECK_ATTR_METHOD_LAZY_DICT 325 -#define _CHECK_ATTR_MODULE 326 -#define _CHECK_ATTR_WITH_HINT 327 -#define _CHECK_CALL_BOUND_METHOD_EXACT_ARGS 328 +#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_EG_MATCH CHECK_EG_MATCH #define _CHECK_EXC_MATCH CHECK_EXC_MATCH -#define _CHECK_FUNCTION 329 -#define _CHECK_FUNCTION_EXACT_ARGS 330 -#define _CHECK_FUNCTION_VERSION 331 -#define _CHECK_IS_NOT_PY_CALLABLE 332 -#define _CHECK_MANAGED_OBJECT_HAS_VALUES 333 -#define _CHECK_METHOD_VERSION 334 -#define _CHECK_PEP_523 335 -#define _CHECK_PERIODIC 336 -#define _CHECK_STACK_SPACE 337 -#define _CHECK_STACK_SPACE_OPERAND 338 -#define _CHECK_VALIDITY 339 -#define _CHECK_VALIDITY_AND_SET_IP 340 -#define _COLD_EXIT 341 -#define _COMPARE_OP 342 -#define _COMPARE_OP_FLOAT 343 -#define _COMPARE_OP_INT 344 -#define _COMPARE_OP_STR 345 -#define _CONTAINS_OP 346 +#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 _CONTAINS_OP_DICT CONTAINS_OP_DICT #define _CONTAINS_OP_SET CONTAINS_OP_SET #define _CONVERT_VALUE CONVERT_VALUE @@ -92,53 +91,53 @@ extern "C" { #define _DELETE_GLOBAL DELETE_GLOBAL #define _DELETE_NAME DELETE_NAME #define _DELETE_SUBSCR DELETE_SUBSCR -#define _DEOPT 347 +#define _DEOPT 346 #define _DICT_MERGE DICT_MERGE #define _DICT_UPDATE DICT_UPDATE -#define _DYNAMIC_EXIT 348 +#define _DYNAMIC_EXIT 347 #define _END_SEND END_SEND -#define _ERROR_POP_N 349 +#define _ERROR_POP_N 348 #define _EXIT_INIT_CHECK EXIT_INIT_CHECK -#define _EXPAND_METHOD 350 -#define _FATAL_ERROR 351 +#define _EXPAND_METHOD 349 +#define _FATAL_ERROR 350 #define _FORMAT_SIMPLE FORMAT_SIMPLE #define _FORMAT_WITH_SPEC FORMAT_WITH_SPEC -#define _FOR_ITER 352 -#define _FOR_ITER_GEN_FRAME 353 -#define _FOR_ITER_TIER_TWO 354 +#define _FOR_ITER 351 +#define _FOR_ITER_GEN_FRAME 352 +#define _FOR_ITER_TIER_TWO 353 #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 355 -#define _GUARD_BOTH_INT 356 -#define _GUARD_BOTH_UNICODE 357 -#define _GUARD_BUILTINS_VERSION 358 -#define _GUARD_DORV_NO_DICT 359 -#define _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT 360 -#define _GUARD_GLOBALS_VERSION 361 -#define _GUARD_IS_FALSE_POP 362 -#define _GUARD_IS_NONE_POP 363 -#define _GUARD_IS_NOT_NONE_POP 364 -#define _GUARD_IS_TRUE_POP 365 -#define _GUARD_KEYS_VERSION 366 -#define _GUARD_NOS_FLOAT 367 -#define _GUARD_NOS_INT 368 -#define _GUARD_NOT_EXHAUSTED_LIST 369 -#define _GUARD_NOT_EXHAUSTED_RANGE 370 -#define _GUARD_NOT_EXHAUSTED_TUPLE 371 -#define _GUARD_TOS_FLOAT 372 -#define _GUARD_TOS_INT 373 -#define _GUARD_TYPE_VERSION 374 -#define _INIT_CALL_BOUND_METHOD_EXACT_ARGS 375 -#define _INIT_CALL_PY_EXACT_ARGS 376 -#define _INIT_CALL_PY_EXACT_ARGS_0 377 -#define _INIT_CALL_PY_EXACT_ARGS_1 378 -#define _INIT_CALL_PY_EXACT_ARGS_2 379 -#define _INIT_CALL_PY_EXACT_ARGS_3 380 -#define _INIT_CALL_PY_EXACT_ARGS_4 381 +#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_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 _INSTRUMENTED_CALL INSTRUMENTED_CALL #define _INSTRUMENTED_CALL_FUNCTION_EX INSTRUMENTED_CALL_FUNCTION_EX #define _INSTRUMENTED_CALL_KW INSTRUMENTED_CALL_KW @@ -155,65 +154,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 382 -#define _IS_NONE 383 +#define _INTERNAL_INCREMENT_OPT_COUNTER 381 +#define _IS_NONE 382 #define _IS_OP IS_OP -#define _ITER_CHECK_LIST 384 -#define _ITER_CHECK_RANGE 385 -#define _ITER_CHECK_TUPLE 386 -#define _ITER_JUMP_LIST 387 -#define _ITER_JUMP_RANGE 388 -#define _ITER_JUMP_TUPLE 389 -#define _ITER_NEXT_LIST 390 -#define _ITER_NEXT_RANGE 391 -#define _ITER_NEXT_TUPLE 392 -#define _JUMP_TO_TOP 393 +#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 _LIST_APPEND LIST_APPEND #define _LIST_EXTEND LIST_EXTEND #define _LOAD_ASSERTION_ERROR LOAD_ASSERTION_ERROR -#define _LOAD_ATTR 394 -#define _LOAD_ATTR_CLASS 395 -#define _LOAD_ATTR_CLASS_0 396 -#define _LOAD_ATTR_CLASS_1 397 +#define _LOAD_ATTR 393 +#define _LOAD_ATTR_CLASS 394 +#define _LOAD_ATTR_CLASS_0 395 +#define _LOAD_ATTR_CLASS_1 396 #define _LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN -#define _LOAD_ATTR_INSTANCE_VALUE 398 -#define _LOAD_ATTR_INSTANCE_VALUE_0 399 -#define _LOAD_ATTR_INSTANCE_VALUE_1 400 -#define _LOAD_ATTR_METHOD_LAZY_DICT 401 -#define _LOAD_ATTR_METHOD_NO_DICT 402 -#define _LOAD_ATTR_METHOD_WITH_VALUES 403 -#define _LOAD_ATTR_MODULE 404 -#define _LOAD_ATTR_NONDESCRIPTOR_NO_DICT 405 -#define _LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES 406 +#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_PROPERTY LOAD_ATTR_PROPERTY -#define _LOAD_ATTR_SLOT 407 -#define _LOAD_ATTR_SLOT_0 408 -#define _LOAD_ATTR_SLOT_1 409 -#define _LOAD_ATTR_WITH_HINT 410 +#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_BUILD_CLASS LOAD_BUILD_CLASS #define _LOAD_CONST LOAD_CONST -#define _LOAD_CONST_INLINE 411 -#define _LOAD_CONST_INLINE_BORROW 412 -#define _LOAD_CONST_INLINE_BORROW_WITH_NULL 413 -#define _LOAD_CONST_INLINE_WITH_NULL 414 +#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_DEREF LOAD_DEREF -#define _LOAD_FAST 415 -#define _LOAD_FAST_0 416 -#define _LOAD_FAST_1 417 -#define _LOAD_FAST_2 418 -#define _LOAD_FAST_3 419 -#define _LOAD_FAST_4 420 -#define _LOAD_FAST_5 421 -#define _LOAD_FAST_6 422 -#define _LOAD_FAST_7 423 +#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_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 424 -#define _LOAD_GLOBAL_BUILTINS 425 -#define _LOAD_GLOBAL_MODULE 426 +#define _LOAD_GLOBAL 423 +#define _LOAD_GLOBAL_BUILTINS 424 +#define _LOAD_GLOBAL_MODULE 425 #define _LOAD_LOCALS LOAD_LOCALS #define _LOAD_NAME LOAD_NAME #define _LOAD_SUPER_ATTR_ATTR LOAD_SUPER_ATTR_ATTR @@ -227,14 +226,15 @@ extern "C" { #define _MATCH_SEQUENCE MATCH_SEQUENCE #define _NOP NOP #define _POP_EXCEPT POP_EXCEPT -#define _POP_FRAME 427 -#define _POP_JUMP_IF_FALSE 428 -#define _POP_JUMP_IF_TRUE 429 +#define _POP_FRAME 426 +#define _POP_JUMP_IF_FALSE 427 +#define _POP_JUMP_IF_TRUE 428 #define _POP_TOP POP_TOP -#define _POP_TOP_LOAD_CONST_INLINE_BORROW 430 +#define _POP_TOP_LOAD_CONST_INLINE_BORROW 429 #define _PUSH_EXC_INFO PUSH_EXC_INFO -#define _PUSH_FRAME 431 +#define _PUSH_FRAME 430 #define _PUSH_NULL PUSH_NULL +#define _PY_FRAME_GENERAL 431 #define _REPLACE_WITH_TRUE 432 #define _RESUME_CHECK RESUME_CHECK #define _RETURN_GENERATOR RETURN_GENERATOR diff --git a/Include/internal/pycore_uop_metadata.h b/Include/internal/pycore_uop_metadata.h index 1c76dc1beb54c3..1783e1d44e96c1 100644 --- a/Include/internal/pycore_uop_metadata.h +++ b/Include/internal/pycore_uop_metadata.h @@ -193,7 +193,7 @@ const uint16_t _PyUop_Flags[MAX_UOP_ID+1] = { [_CHECK_ATTR_METHOD_LAZY_DICT] = HAS_DEOPT_FLAG, [_LOAD_ATTR_METHOD_LAZY_DICT] = HAS_ARG_FLAG, [_CHECK_PERIODIC] = HAS_EVAL_BREAK_FLAG, - [_CALL_PY_GENERAL] = HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG, + [_PY_FRAME_GENERAL] = HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG, [_CHECK_FUNCTION_VERSION] = HAS_ARG_FLAG | HAS_EXIT_FLAG, [_CHECK_METHOD_VERSION] = HAS_ARG_FLAG | HAS_EXIT_FLAG, [_EXPAND_METHOD] = HAS_ARG_FLAG, @@ -303,7 +303,6 @@ const char *const _PyOpcode_uop_name[MAX_UOP_ID+1] = { [_CALL_METHOD_DESCRIPTOR_NOARGS] = "_CALL_METHOD_DESCRIPTOR_NOARGS", [_CALL_METHOD_DESCRIPTOR_O] = "_CALL_METHOD_DESCRIPTOR_O", [_CALL_NON_PY_GENERAL] = "_CALL_NON_PY_GENERAL", - [_CALL_PY_GENERAL] = "_CALL_PY_GENERAL", [_CALL_STR_1] = "_CALL_STR_1", [_CALL_TUPLE_1] = "_CALL_TUPLE_1", [_CALL_TYPE_1] = "_CALL_TYPE_1", @@ -462,6 +461,7 @@ const char *const _PyOpcode_uop_name[MAX_UOP_ID+1] = { [_PUSH_EXC_INFO] = "_PUSH_EXC_INFO", [_PUSH_FRAME] = "_PUSH_FRAME", [_PUSH_NULL] = "_PUSH_NULL", + [_PY_FRAME_GENERAL] = "_PY_FRAME_GENERAL", [_REPLACE_WITH_TRUE] = "_REPLACE_WITH_TRUE", [_RESUME_CHECK] = "_RESUME_CHECK", [_RETURN_GENERATOR] = "_RETURN_GENERATOR", @@ -864,7 +864,7 @@ int _PyUop_num_popped(int opcode, int oparg) return 1; case _CHECK_PERIODIC: return 0; - case _CALL_PY_GENERAL: + case _PY_FRAME_GENERAL: return 2 + oparg; case _CHECK_FUNCTION_VERSION: return 2 + oparg; diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 4b06e676ef1c3a..34347f079eb17e 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -3148,7 +3148,7 @@ dummy_func( macro(CALL) = _SPECIALIZE_CALL + unused/2 + _CALL + _CHECK_PERIODIC; - op(_CALL_PY_GENERAL, (callable, self_or_null, args[oparg] -- new_frame: _PyInterpreterFrame*)) { + op(_PY_FRAME_GENERAL, (callable, self_or_null, args[oparg] -- new_frame: _PyInterpreterFrame*)) { // oparg counts all of the args, but *not* self: int total_args = oparg; if (self_or_null != NULL) { @@ -3168,7 +3168,6 @@ dummy_func( if (new_frame == NULL) { ERROR_NO_POP(); } - frame->return_offset = (uint16_t)(1 + INLINE_CACHE_ENTRIES_CALL); } op(_CHECK_FUNCTION_VERSION, (func_version/2, callable, unused, unused[oparg] -- callable, unused, unused[oparg])) { @@ -3181,7 +3180,8 @@ dummy_func( unused/1 + // Skip over the counter _CHECK_PEP_523 + _CHECK_FUNCTION_VERSION + - _CALL_PY_GENERAL + + _PY_FRAME_GENERAL + + _SAVE_RETURN_OFFSET + _PUSH_FRAME; op(_CHECK_METHOD_VERSION, (func_version/2, callable, null, unused[oparg] -- callable, null, unused[oparg])) { @@ -3197,7 +3197,7 @@ dummy_func( assert(Py_TYPE(callable) == &PyMethod_Type); self = ((PyMethodObject *)callable)->im_self; Py_INCREF(self); - stack_pointer[-1 - oparg] = self; // Patch stack as it is used by _CALL_PY_GENERAL + stack_pointer[-1 - oparg] = self; // Patch stack as it is used by _PY_FRAME_GENERAL method = ((PyMethodObject *)callable)->im_func; assert(PyFunction_Check(method)); Py_INCREF(method); @@ -3209,7 +3209,8 @@ dummy_func( _CHECK_PEP_523 + _CHECK_METHOD_VERSION + _EXPAND_METHOD + - _CALL_PY_GENERAL + + _PY_FRAME_GENERAL + + _SAVE_RETURN_OFFSET + _PUSH_FRAME; op(_CHECK_IS_NOT_PY_CALLABLE, (callable, unused, unused[oparg] -- callable, unused, unused[oparg])) { diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index fd77cdce879a28..9add4cd22a7f8e 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -3032,7 +3032,7 @@ break; } - case _CALL_PY_GENERAL: { + case _PY_FRAME_GENERAL: { PyObject **args; PyObject *self_or_null; PyObject *callable; @@ -3060,7 +3060,6 @@ if (new_frame == NULL) { JUMP_TO_ERROR(); } - frame->return_offset = (uint16_t)(1 + INLINE_CACHE_ENTRIES_CALL); stack_pointer[0] = (PyObject *)new_frame; stack_pointer += 1; break; @@ -3122,7 +3121,7 @@ assert(Py_TYPE(callable) == &PyMethod_Type); self = ((PyMethodObject *)callable)->im_self; Py_INCREF(self); - stack_pointer[-1 - oparg] = self; // Patch stack as it is used by _CALL_PY_GENERAL + stack_pointer[-1 - oparg] = self; // Patch stack as it is used by _PY_FRAME_GENERAL method = ((PyMethodObject *)callable)->im_func; assert(PyFunction_Check(method)); Py_INCREF(method); diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 5e961639ef70f4..48a995a7491f3e 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -1036,13 +1036,13 @@ assert(Py_TYPE(callable) == &PyMethod_Type); self = ((PyMethodObject *)callable)->im_self; Py_INCREF(self); - stack_pointer[-1 - oparg] = self; // Patch stack as it is used by _CALL_PY_GENERAL + stack_pointer[-1 - oparg] = self; // Patch stack as it is used by _PY_FRAME_GENERAL method = ((PyMethodObject *)callable)->im_func; assert(PyFunction_Check(method)); Py_INCREF(method); Py_DECREF(callable); } - // _CALL_PY_GENERAL + // _PY_FRAME_GENERAL args = &stack_pointer[-oparg]; self_or_null = self; callable = method; @@ -1066,7 +1066,15 @@ if (new_frame == NULL) { goto error; } - frame->return_offset = (uint16_t)(1 + INLINE_CACHE_ENTRIES_CALL); + } + // _SAVE_RETURN_OFFSET + { + #if TIER_ONE + frame->return_offset = (uint16_t)(next_instr - this_instr); + #endif + #if TIER_TWO + frame->return_offset = oparg; + #endif } // _PUSH_FRAME { @@ -1941,7 +1949,7 @@ PyFunctionObject *func = (PyFunctionObject *)callable; DEOPT_IF(func->func_version != func_version, CALL); } - // _CALL_PY_GENERAL + // _PY_FRAME_GENERAL args = &stack_pointer[-oparg]; self_or_null = stack_pointer[-1 - oparg]; { @@ -1964,7 +1972,15 @@ if (new_frame == NULL) { goto error; } - frame->return_offset = (uint16_t)(1 + INLINE_CACHE_ENTRIES_CALL); + } + // _SAVE_RETURN_OFFSET + { + #if TIER_ONE + frame->return_offset = (uint16_t)(next_instr - this_instr); + #endif + #if TIER_TWO + frame->return_offset = oparg; + #endif } // _PUSH_FRAME { diff --git a/Python/optimizer_bytecodes.c b/Python/optimizer_bytecodes.c index a2a1670d95437d..928bc03382b8fb 100644 --- a/Python/optimizer_bytecodes.c +++ b/Python/optimizer_bytecodes.c @@ -629,7 +629,7 @@ dummy_func(void) { frame_new(ctx, co, localsplus_start, n_locals_already_filled, 0)); } - op(_CALL_PY_GENERAL, (callable, self_or_null, args[oparg] -- new_frame: _Py_UOpsAbstractFrame *)) { + op(_PY_FRAME_GENERAL, (callable, self_or_null, args[oparg] -- new_frame: _Py_UOpsAbstractFrame *)) { /* The _Py_UOpsAbstractFrame design assumes that we can copy arguments across directly */ (void)callable; (void)self_or_null; diff --git a/Python/optimizer_cases.c.h b/Python/optimizer_cases.c.h index dcb3efc857c4a9..4beae8e0fd03fa 100644 --- a/Python/optimizer_cases.c.h +++ b/Python/optimizer_cases.c.h @@ -1559,7 +1559,7 @@ break; } - case _CALL_PY_GENERAL: { + case _PY_FRAME_GENERAL: { _Py_UopsSymbol **args; _Py_UopsSymbol *self_or_null; _Py_UopsSymbol *callable;