https://github.com/python/cpython/commit/da53660f35db2dfb1e6181e603468dfe5758f3b8 commit: da53660f35db2dfb1e6181e603468dfe5758f3b8 branch: main author: Sam Gross <colesb...@gmail.com> committer: colesbury <colesb...@gmail.com> date: 2025-04-21T15:54:25-04:00 summary:
gh-131586: Avoid refcount contention in context managers (gh-131851) This avoid reference count contention in the free threading build when calling special methods like `__enter__` and `__exit__`. files: M Include/internal/pycore_object.h M Include/internal/pycore_opcode_metadata.h M Include/internal/pycore_uop_ids.h M Include/internal/pycore_uop_metadata.h M Objects/typeobject.c M Python/bytecodes.c M Python/executor_cases.c.h M Python/generated_cases.c.h M Python/optimizer_bytecodes.c M Python/optimizer_cases.c.h M Tools/ftscalingbench/ftscalingbench.py diff --git a/Include/internal/pycore_object.h b/Include/internal/pycore_object.h index e5034ff4dcc42b..b7e162c8abcabf 100644 --- a/Include/internal/pycore_object.h +++ b/Include/internal/pycore_object.h @@ -950,7 +950,7 @@ extern int _PyObject_IsInstanceDictEmpty(PyObject *); // Export for 'math' shared extension PyAPI_FUNC(PyObject*) _PyObject_LookupSpecial(PyObject *, PyObject *); -PyAPI_FUNC(PyObject*) _PyObject_LookupSpecialMethod(PyObject *self, PyObject *attr, PyObject **self_or_null); +PyAPI_FUNC(int) _PyObject_LookupSpecialMethod(PyObject *attr, _PyStackRef *method_and_self); // Calls the method named `attr` on `self`, but does not set an exception if // the attribute does not exist. diff --git a/Include/internal/pycore_opcode_metadata.h b/Include/internal/pycore_opcode_metadata.h index 521f7a92cf08c4..3f01f7d997f57b 100644 --- a/Include/internal/pycore_opcode_metadata.h +++ b/Include/internal/pycore_opcode_metadata.h @@ -1218,7 +1218,7 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[266] = { [LOAD_LOCALS] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [LOAD_NAME] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [LOAD_SMALL_INT] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, - [LOAD_SPECIAL] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, + [LOAD_SPECIAL] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, [LOAD_SUPER_ATTR] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [LOAD_SUPER_ATTR_ATTR] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [LOAD_SUPER_ATTR_METHOD] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, @@ -1427,7 +1427,7 @@ _PyOpcode_macro_expansion[256] = { [LOAD_LOCALS] = { .nuops = 1, .uops = { { _LOAD_LOCALS, OPARG_SIMPLE, 0 } } }, [LOAD_NAME] = { .nuops = 1, .uops = { { _LOAD_NAME, OPARG_SIMPLE, 0 } } }, [LOAD_SMALL_INT] = { .nuops = 1, .uops = { { _LOAD_SMALL_INT, OPARG_SIMPLE, 0 } } }, - [LOAD_SPECIAL] = { .nuops = 1, .uops = { { _LOAD_SPECIAL, OPARG_SIMPLE, 0 } } }, + [LOAD_SPECIAL] = { .nuops = 2, .uops = { { _INSERT_NULL, OPARG_SIMPLE, 0 }, { _LOAD_SPECIAL, OPARG_SIMPLE, 0 } } }, [LOAD_SUPER_ATTR_ATTR] = { .nuops = 1, .uops = { { _LOAD_SUPER_ATTR_ATTR, OPARG_SIMPLE, 1 } } }, [LOAD_SUPER_ATTR_METHOD] = { .nuops = 1, .uops = { { _LOAD_SUPER_ATTR_METHOD, OPARG_SIMPLE, 1 } } }, [MAKE_CELL] = { .nuops = 1, .uops = { { _MAKE_CELL, OPARG_SIMPLE, 0 } } }, diff --git a/Include/internal/pycore_uop_ids.h b/Include/internal/pycore_uop_ids.h index e9a536919da598..691bc6d6586b0a 100644 --- a/Include/internal/pycore_uop_ids.h +++ b/Include/internal/pycore_uop_ids.h @@ -151,6 +151,7 @@ extern "C" { #define _INIT_CALL_PY_EXACT_ARGS_2 401 #define _INIT_CALL_PY_EXACT_ARGS_3 402 #define _INIT_CALL_PY_EXACT_ARGS_4 403 +#define _INSERT_NULL 404 #define _INSTRUMENTED_FOR_ITER INSTRUMENTED_FOR_ITER #define _INSTRUMENTED_INSTRUCTION INSTRUMENTED_INSTRUCTION #define _INSTRUMENTED_JUMP_FORWARD INSTRUMENTED_JUMP_FORWARD @@ -160,163 +161,163 @@ extern "C" { #define _INSTRUMENTED_POP_JUMP_IF_NONE INSTRUMENTED_POP_JUMP_IF_NONE #define _INSTRUMENTED_POP_JUMP_IF_NOT_NONE INSTRUMENTED_POP_JUMP_IF_NOT_NONE #define _INSTRUMENTED_POP_JUMP_IF_TRUE INSTRUMENTED_POP_JUMP_IF_TRUE -#define _IS_NONE 404 +#define _IS_NONE 405 #define _IS_OP IS_OP -#define _ITER_CHECK_LIST 405 -#define _ITER_CHECK_RANGE 406 -#define _ITER_CHECK_TUPLE 407 -#define _ITER_JUMP_LIST 408 -#define _ITER_JUMP_RANGE 409 -#define _ITER_JUMP_TUPLE 410 -#define _ITER_NEXT_LIST 411 -#define _ITER_NEXT_LIST_TIER_TWO 412 -#define _ITER_NEXT_RANGE 413 -#define _ITER_NEXT_TUPLE 414 -#define _JUMP_TO_TOP 415 +#define _ITER_CHECK_LIST 406 +#define _ITER_CHECK_RANGE 407 +#define _ITER_CHECK_TUPLE 408 +#define _ITER_JUMP_LIST 409 +#define _ITER_JUMP_RANGE 410 +#define _ITER_JUMP_TUPLE 411 +#define _ITER_NEXT_LIST 412 +#define _ITER_NEXT_LIST_TIER_TWO 413 +#define _ITER_NEXT_RANGE 414 +#define _ITER_NEXT_TUPLE 415 +#define _JUMP_TO_TOP 416 #define _LIST_APPEND LIST_APPEND #define _LIST_EXTEND LIST_EXTEND -#define _LOAD_ATTR 416 -#define _LOAD_ATTR_CLASS 417 +#define _LOAD_ATTR 417 +#define _LOAD_ATTR_CLASS 418 #define _LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN -#define _LOAD_ATTR_INSTANCE_VALUE 418 -#define _LOAD_ATTR_METHOD_LAZY_DICT 419 -#define _LOAD_ATTR_METHOD_NO_DICT 420 -#define _LOAD_ATTR_METHOD_WITH_VALUES 421 -#define _LOAD_ATTR_MODULE 422 -#define _LOAD_ATTR_NONDESCRIPTOR_NO_DICT 423 -#define _LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES 424 -#define _LOAD_ATTR_PROPERTY_FRAME 425 -#define _LOAD_ATTR_SLOT 426 -#define _LOAD_ATTR_WITH_HINT 427 +#define _LOAD_ATTR_INSTANCE_VALUE 419 +#define _LOAD_ATTR_METHOD_LAZY_DICT 420 +#define _LOAD_ATTR_METHOD_NO_DICT 421 +#define _LOAD_ATTR_METHOD_WITH_VALUES 422 +#define _LOAD_ATTR_MODULE 423 +#define _LOAD_ATTR_NONDESCRIPTOR_NO_DICT 424 +#define _LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES 425 +#define _LOAD_ATTR_PROPERTY_FRAME 426 +#define _LOAD_ATTR_SLOT 427 +#define _LOAD_ATTR_WITH_HINT 428 #define _LOAD_BUILD_CLASS LOAD_BUILD_CLASS -#define _LOAD_BYTECODE 428 +#define _LOAD_BYTECODE 429 #define _LOAD_COMMON_CONSTANT LOAD_COMMON_CONSTANT #define _LOAD_CONST LOAD_CONST #define _LOAD_CONST_IMMORTAL LOAD_CONST_IMMORTAL -#define _LOAD_CONST_INLINE 429 -#define _LOAD_CONST_INLINE_BORROW 430 +#define _LOAD_CONST_INLINE 430 +#define _LOAD_CONST_INLINE_BORROW 431 #define _LOAD_CONST_MORTAL LOAD_CONST_MORTAL #define _LOAD_DEREF LOAD_DEREF -#define _LOAD_FAST 431 -#define _LOAD_FAST_0 432 -#define _LOAD_FAST_1 433 -#define _LOAD_FAST_2 434 -#define _LOAD_FAST_3 435 -#define _LOAD_FAST_4 436 -#define _LOAD_FAST_5 437 -#define _LOAD_FAST_6 438 -#define _LOAD_FAST_7 439 +#define _LOAD_FAST 432 +#define _LOAD_FAST_0 433 +#define _LOAD_FAST_1 434 +#define _LOAD_FAST_2 435 +#define _LOAD_FAST_3 436 +#define _LOAD_FAST_4 437 +#define _LOAD_FAST_5 438 +#define _LOAD_FAST_6 439 +#define _LOAD_FAST_7 440 #define _LOAD_FAST_AND_CLEAR LOAD_FAST_AND_CLEAR -#define _LOAD_FAST_BORROW 440 -#define _LOAD_FAST_BORROW_0 441 -#define _LOAD_FAST_BORROW_1 442 -#define _LOAD_FAST_BORROW_2 443 -#define _LOAD_FAST_BORROW_3 444 -#define _LOAD_FAST_BORROW_4 445 -#define _LOAD_FAST_BORROW_5 446 -#define _LOAD_FAST_BORROW_6 447 -#define _LOAD_FAST_BORROW_7 448 +#define _LOAD_FAST_BORROW 441 +#define _LOAD_FAST_BORROW_0 442 +#define _LOAD_FAST_BORROW_1 443 +#define _LOAD_FAST_BORROW_2 444 +#define _LOAD_FAST_BORROW_3 445 +#define _LOAD_FAST_BORROW_4 446 +#define _LOAD_FAST_BORROW_5 447 +#define _LOAD_FAST_BORROW_6 448 +#define _LOAD_FAST_BORROW_7 449 #define _LOAD_FAST_BORROW_LOAD_FAST_BORROW LOAD_FAST_BORROW_LOAD_FAST_BORROW #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 449 -#define _LOAD_GLOBAL_BUILTINS 450 -#define _LOAD_GLOBAL_MODULE 451 +#define _LOAD_GLOBAL 450 +#define _LOAD_GLOBAL_BUILTINS 451 +#define _LOAD_GLOBAL_MODULE 452 #define _LOAD_LOCALS LOAD_LOCALS #define _LOAD_NAME LOAD_NAME -#define _LOAD_SMALL_INT 452 -#define _LOAD_SMALL_INT_0 453 -#define _LOAD_SMALL_INT_1 454 -#define _LOAD_SMALL_INT_2 455 -#define _LOAD_SMALL_INT_3 456 -#define _LOAD_SPECIAL LOAD_SPECIAL +#define _LOAD_SMALL_INT 453 +#define _LOAD_SMALL_INT_0 454 +#define _LOAD_SMALL_INT_1 455 +#define _LOAD_SMALL_INT_2 456 +#define _LOAD_SMALL_INT_3 457 +#define _LOAD_SPECIAL 458 #define _LOAD_SUPER_ATTR_ATTR LOAD_SUPER_ATTR_ATTR #define _LOAD_SUPER_ATTR_METHOD LOAD_SUPER_ATTR_METHOD -#define _MAKE_CALLARGS_A_TUPLE 457 +#define _MAKE_CALLARGS_A_TUPLE 459 #define _MAKE_CELL MAKE_CELL #define _MAKE_FUNCTION MAKE_FUNCTION -#define _MAKE_WARM 458 +#define _MAKE_WARM 460 #define _MAP_ADD MAP_ADD #define _MATCH_CLASS MATCH_CLASS #define _MATCH_KEYS MATCH_KEYS #define _MATCH_MAPPING MATCH_MAPPING #define _MATCH_SEQUENCE MATCH_SEQUENCE -#define _MAYBE_EXPAND_METHOD 459 -#define _MAYBE_EXPAND_METHOD_KW 460 -#define _MONITOR_CALL 461 -#define _MONITOR_CALL_KW 462 -#define _MONITOR_JUMP_BACKWARD 463 -#define _MONITOR_RESUME 464 +#define _MAYBE_EXPAND_METHOD 461 +#define _MAYBE_EXPAND_METHOD_KW 462 +#define _MONITOR_CALL 463 +#define _MONITOR_CALL_KW 464 +#define _MONITOR_JUMP_BACKWARD 465 +#define _MONITOR_RESUME 466 #define _NOP NOP #define _POP_EXCEPT POP_EXCEPT -#define _POP_JUMP_IF_FALSE 465 -#define _POP_JUMP_IF_TRUE 466 +#define _POP_JUMP_IF_FALSE 467 +#define _POP_JUMP_IF_TRUE 468 #define _POP_TOP POP_TOP -#define _POP_TOP_LOAD_CONST_INLINE 467 -#define _POP_TOP_LOAD_CONST_INLINE_BORROW 468 -#define _POP_TWO_LOAD_CONST_INLINE_BORROW 469 +#define _POP_TOP_LOAD_CONST_INLINE 469 +#define _POP_TOP_LOAD_CONST_INLINE_BORROW 470 +#define _POP_TWO_LOAD_CONST_INLINE_BORROW 471 #define _PUSH_EXC_INFO PUSH_EXC_INFO -#define _PUSH_FRAME 470 +#define _PUSH_FRAME 472 #define _PUSH_NULL PUSH_NULL -#define _PUSH_NULL_CONDITIONAL 471 -#define _PY_FRAME_GENERAL 472 -#define _PY_FRAME_KW 473 -#define _QUICKEN_RESUME 474 -#define _REPLACE_WITH_TRUE 475 +#define _PUSH_NULL_CONDITIONAL 473 +#define _PY_FRAME_GENERAL 474 +#define _PY_FRAME_KW 475 +#define _QUICKEN_RESUME 476 +#define _REPLACE_WITH_TRUE 477 #define _RESUME_CHECK RESUME_CHECK #define _RETURN_GENERATOR RETURN_GENERATOR #define _RETURN_VALUE RETURN_VALUE -#define _SAVE_RETURN_OFFSET 476 -#define _SEND 477 -#define _SEND_GEN_FRAME 478 +#define _SAVE_RETURN_OFFSET 478 +#define _SEND 479 +#define _SEND_GEN_FRAME 480 #define _SETUP_ANNOTATIONS SETUP_ANNOTATIONS #define _SET_ADD SET_ADD #define _SET_FUNCTION_ATTRIBUTE SET_FUNCTION_ATTRIBUTE #define _SET_UPDATE SET_UPDATE -#define _START_EXECUTOR 479 -#define _STORE_ATTR 480 -#define _STORE_ATTR_INSTANCE_VALUE 481 -#define _STORE_ATTR_SLOT 482 -#define _STORE_ATTR_WITH_HINT 483 +#define _START_EXECUTOR 481 +#define _STORE_ATTR 482 +#define _STORE_ATTR_INSTANCE_VALUE 483 +#define _STORE_ATTR_SLOT 484 +#define _STORE_ATTR_WITH_HINT 485 #define _STORE_DEREF STORE_DEREF -#define _STORE_FAST 484 -#define _STORE_FAST_0 485 -#define _STORE_FAST_1 486 -#define _STORE_FAST_2 487 -#define _STORE_FAST_3 488 -#define _STORE_FAST_4 489 -#define _STORE_FAST_5 490 -#define _STORE_FAST_6 491 -#define _STORE_FAST_7 492 +#define _STORE_FAST 486 +#define _STORE_FAST_0 487 +#define _STORE_FAST_1 488 +#define _STORE_FAST_2 489 +#define _STORE_FAST_3 490 +#define _STORE_FAST_4 491 +#define _STORE_FAST_5 492 +#define _STORE_FAST_6 493 +#define _STORE_FAST_7 494 #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 493 -#define _STORE_SUBSCR 494 -#define _STORE_SUBSCR_DICT 495 -#define _STORE_SUBSCR_LIST_INT 496 +#define _STORE_SLICE 495 +#define _STORE_SUBSCR 496 +#define _STORE_SUBSCR_DICT 497 +#define _STORE_SUBSCR_LIST_INT 498 #define _SWAP SWAP -#define _TIER2_RESUME_CHECK 497 -#define _TO_BOOL 498 +#define _TIER2_RESUME_CHECK 499 +#define _TO_BOOL 500 #define _TO_BOOL_BOOL TO_BOOL_BOOL #define _TO_BOOL_INT TO_BOOL_INT -#define _TO_BOOL_LIST 499 +#define _TO_BOOL_LIST 501 #define _TO_BOOL_NONE TO_BOOL_NONE -#define _TO_BOOL_STR 500 +#define _TO_BOOL_STR 502 #define _UNARY_INVERT UNARY_INVERT #define _UNARY_NEGATIVE UNARY_NEGATIVE #define _UNARY_NOT UNARY_NOT #define _UNPACK_EX UNPACK_EX -#define _UNPACK_SEQUENCE 501 -#define _UNPACK_SEQUENCE_LIST 502 -#define _UNPACK_SEQUENCE_TUPLE 503 -#define _UNPACK_SEQUENCE_TWO_TUPLE 504 +#define _UNPACK_SEQUENCE 503 +#define _UNPACK_SEQUENCE_LIST 504 +#define _UNPACK_SEQUENCE_TUPLE 505 +#define _UNPACK_SEQUENCE_TWO_TUPLE 506 #define _WITH_EXCEPT_START WITH_EXCEPT_START #define _YIELD_VALUE YIELD_VALUE -#define MAX_UOP_ID 504 +#define MAX_UOP_ID 506 #ifdef __cplusplus } diff --git a/Include/internal/pycore_uop_metadata.h b/Include/internal/pycore_uop_metadata.h index 874756770c1871..b2df354fdcc61b 100644 --- a/Include/internal/pycore_uop_metadata.h +++ b/Include/internal/pycore_uop_metadata.h @@ -209,7 +209,8 @@ const uint16_t _PyUop_Flags[MAX_UOP_ID+1] = { [_GUARD_NOT_EXHAUSTED_RANGE] = HAS_EXIT_FLAG, [_ITER_NEXT_RANGE] = HAS_ERROR_FLAG, [_FOR_ITER_GEN_FRAME] = HAS_ARG_FLAG | HAS_DEOPT_FLAG, - [_LOAD_SPECIAL] = HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, + [_INSERT_NULL] = 0, + [_LOAD_SPECIAL] = HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG, [_WITH_EXCEPT_START] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, [_PUSH_EXC_INFO] = 0, [_GUARD_DORV_VALUES_INST_ATTR_FROM_DICT] = HAS_DEOPT_FLAG, @@ -445,6 +446,7 @@ const char *const _PyOpcode_uop_name[MAX_UOP_ID+1] = { [_INIT_CALL_PY_EXACT_ARGS_2] = "_INIT_CALL_PY_EXACT_ARGS_2", [_INIT_CALL_PY_EXACT_ARGS_3] = "_INIT_CALL_PY_EXACT_ARGS_3", [_INIT_CALL_PY_EXACT_ARGS_4] = "_INIT_CALL_PY_EXACT_ARGS_4", + [_INSERT_NULL] = "_INSERT_NULL", [_IS_NONE] = "_IS_NONE", [_IS_OP] = "_IS_OP", [_ITER_CHECK_LIST] = "_ITER_CHECK_LIST", @@ -970,8 +972,10 @@ int _PyUop_num_popped(int opcode, int oparg) return 0; case _FOR_ITER_GEN_FRAME: return 0; - case _LOAD_SPECIAL: + case _INSERT_NULL: return 1; + case _LOAD_SPECIAL: + return 0; case _WITH_EXCEPT_START: return 0; case _PUSH_EXC_INFO: diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 5663aee3c2e069..a720a98121dc93 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -2794,32 +2794,37 @@ _PyObject_LookupSpecial(PyObject *self, PyObject *attr) return res; } -/* Steals a reference to self */ -PyObject * -_PyObject_LookupSpecialMethod(PyObject *self, PyObject *attr, PyObject **self_or_null) +// Lookup the method name `attr` on `self`. On entry, `method_and_self[0]` +// is null and `method_and_self[1]` is `self`. On exit, `method_and_self[0]` +// is the method object and `method_and_self[1]` is `self` if the method is +// not bound. +// Return 1 on success, -1 on error, and 0 if the method is missing. +int +_PyObject_LookupSpecialMethod(PyObject *attr, _PyStackRef *method_and_self) { - PyObject *res; - - res = _PyType_LookupRef(Py_TYPE(self), attr); - if (res == NULL) { - Py_DECREF(self); - *self_or_null = NULL; - return NULL; + PyObject *self = PyStackRef_AsPyObjectBorrow(method_and_self[1]); + _PyType_LookupStackRefAndVersion(Py_TYPE(self), attr, &method_and_self[0]); + PyObject *method_o = PyStackRef_AsPyObjectBorrow(method_and_self[0]); + if (method_o == NULL) { + return 0; } - if (_PyType_HasFeature(Py_TYPE(res), Py_TPFLAGS_METHOD_DESCRIPTOR)) { + if (_PyType_HasFeature(Py_TYPE(method_o), Py_TPFLAGS_METHOD_DESCRIPTOR)) { /* Avoid temporary PyMethodObject */ - *self_or_null = self; + return 1; } - else { - descrgetfunc f = Py_TYPE(res)->tp_descr_get; - if (f != NULL) { - Py_SETREF(res, f(res, self, (PyObject *)(Py_TYPE(self)))); + + descrgetfunc f = Py_TYPE(method_o)->tp_descr_get; + if (f != NULL) { + PyObject *func = f(method_o, self, (PyObject *)(Py_TYPE(self))); + if (func == NULL) { + return -1; } - *self_or_null = NULL; - Py_DECREF(self); + PyStackRef_CLEAR(method_and_self[0]); // clear method + method_and_self[0] = PyStackRef_FromPyObjectSteal(func); } - return res; + PyStackRef_CLEAR(method_and_self[1]); // clear self + return 1; } static int diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 07df22c761fc1c..ad82e0b060de79 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -3417,28 +3417,33 @@ dummy_func( _FOR_ITER_GEN_FRAME + _PUSH_FRAME; - inst(LOAD_SPECIAL, (owner -- attr, self_or_null)) { - assert(oparg <= SPECIAL_MAX); - PyObject *owner_o = PyStackRef_AsPyObjectSteal(owner); + op(_INSERT_NULL, (self -- method_and_self[2])) { + method_and_self[1] = self; + method_and_self[0] = PyStackRef_NULL; + DEAD(self); + } + + op(_LOAD_SPECIAL, (method_and_self[2] -- method_and_self[2])) { PyObject *name = _Py_SpecialMethods[oparg].name; - PyObject *self_or_null_o; - PyObject *attr_o = _PyObject_LookupSpecialMethod(owner_o, name, &self_or_null_o); - if (attr_o == NULL) { - if (!_PyErr_Occurred(tstate)) { - const char *errfmt = _PyEval_SpecialMethodCanSuggest(owner_o, oparg) + int err = _PyObject_LookupSpecialMethod(name, method_and_self); + if (err <= 0) { + if (err == 0) { + PyObject *owner = PyStackRef_AsPyObjectBorrow(method_and_self[1]); + const char *errfmt = _PyEval_SpecialMethodCanSuggest(owner, oparg) ? _Py_SpecialMethods[oparg].error_suggestion : _Py_SpecialMethods[oparg].error; assert(!_PyErr_Occurred(tstate)); assert(errfmt != NULL); - _PyErr_Format(tstate, PyExc_TypeError, errfmt, owner_o); + _PyErr_Format(tstate, PyExc_TypeError, errfmt, owner); } - ERROR_IF(true, error); + ERROR_NO_POP(); } - attr = PyStackRef_FromPyObjectSteal(attr_o); - self_or_null = self_or_null_o == NULL ? - PyStackRef_NULL : PyStackRef_FromPyObjectSteal(self_or_null_o); } + macro(LOAD_SPECIAL) = + _INSERT_NULL + + _LOAD_SPECIAL; + inst(WITH_EXCEPT_START, (exit_func, exit_self, lasti, unused, val -- exit_func, exit_self, lasti, unused, val, res)) { /* At the top of the stack are 4 values: - val: TOP = exc_info() diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index cd265c383bd380..c65cc9efa5e5eb 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -4407,43 +4407,42 @@ break; } + case _INSERT_NULL: { + _PyStackRef self; + _PyStackRef *method_and_self; + self = stack_pointer[-1]; + method_and_self = &stack_pointer[-1]; + method_and_self[1] = self; + method_and_self[0] = PyStackRef_NULL; + stack_pointer += 1; + assert(WITHIN_STACK_BOUNDS()); + break; + } + case _LOAD_SPECIAL: { - _PyStackRef owner; - _PyStackRef attr; - _PyStackRef self_or_null; + _PyStackRef *method_and_self; oparg = CURRENT_OPARG(); - owner = stack_pointer[-1]; - assert(oparg <= SPECIAL_MAX); - PyObject *owner_o = PyStackRef_AsPyObjectSteal(owner); + method_and_self = &stack_pointer[-2]; PyObject *name = _Py_SpecialMethods[oparg].name; - PyObject *self_or_null_o; - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); _PyFrame_SetStackPointer(frame, stack_pointer); - PyObject *attr_o = _PyObject_LookupSpecialMethod(owner_o, name, &self_or_null_o); + int err = _PyObject_LookupSpecialMethod(name, method_and_self); stack_pointer = _PyFrame_GetStackPointer(frame); - if (attr_o == NULL) { - if (!_PyErr_Occurred(tstate)) { + if (err <= 0) { + if (err == 0) { + PyObject *owner = PyStackRef_AsPyObjectBorrow(method_and_self[1]); _PyFrame_SetStackPointer(frame, stack_pointer); - const char *errfmt = _PyEval_SpecialMethodCanSuggest(owner_o, oparg) + const char *errfmt = _PyEval_SpecialMethodCanSuggest(owner, oparg) ? _Py_SpecialMethods[oparg].error_suggestion : _Py_SpecialMethods[oparg].error; stack_pointer = _PyFrame_GetStackPointer(frame); assert(!_PyErr_Occurred(tstate)); assert(errfmt != NULL); _PyFrame_SetStackPointer(frame, stack_pointer); - _PyErr_Format(tstate, PyExc_TypeError, errfmt, owner_o); + _PyErr_Format(tstate, PyExc_TypeError, errfmt, owner); stack_pointer = _PyFrame_GetStackPointer(frame); } JUMP_TO_ERROR(); } - attr = PyStackRef_FromPyObjectSteal(attr_o); - self_or_null = self_or_null_o == NULL ? - PyStackRef_NULL : PyStackRef_FromPyObjectSteal(self_or_null_o); - stack_pointer[0] = attr; - stack_pointer[1] = self_or_null; - stack_pointer += 2; - assert(WITHIN_STACK_BOUNDS()); break; } diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 911f5ae3e7c0d7..18785c7be4c4e2 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -9342,41 +9342,41 @@ frame->instr_ptr = next_instr; next_instr += 1; INSTRUCTION_STATS(LOAD_SPECIAL); - _PyStackRef owner; - _PyStackRef attr; - _PyStackRef self_or_null; - owner = stack_pointer[-1]; - assert(oparg <= SPECIAL_MAX); - PyObject *owner_o = PyStackRef_AsPyObjectSteal(owner); - PyObject *name = _Py_SpecialMethods[oparg].name; - PyObject *self_or_null_o; - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); - _PyFrame_SetStackPointer(frame, stack_pointer); - PyObject *attr_o = _PyObject_LookupSpecialMethod(owner_o, name, &self_or_null_o); - stack_pointer = _PyFrame_GetStackPointer(frame); - if (attr_o == NULL) { - if (!_PyErr_Occurred(tstate)) { - _PyFrame_SetStackPointer(frame, stack_pointer); - const char *errfmt = _PyEval_SpecialMethodCanSuggest(owner_o, oparg) - ? _Py_SpecialMethods[oparg].error_suggestion - : _Py_SpecialMethods[oparg].error; - stack_pointer = _PyFrame_GetStackPointer(frame); - assert(!_PyErr_Occurred(tstate)); - assert(errfmt != NULL); - _PyFrame_SetStackPointer(frame, stack_pointer); - _PyErr_Format(tstate, PyExc_TypeError, errfmt, owner_o); - stack_pointer = _PyFrame_GetStackPointer(frame); + _PyStackRef self; + _PyStackRef *method_and_self; + // _INSERT_NULL + { + self = stack_pointer[-1]; + method_and_self = &stack_pointer[-1]; + method_and_self[1] = self; + method_and_self[0] = PyStackRef_NULL; + } + // _LOAD_SPECIAL + { + method_and_self = &stack_pointer[-1]; + PyObject *name = _Py_SpecialMethods[oparg].name; + stack_pointer += 1; + assert(WITHIN_STACK_BOUNDS()); + _PyFrame_SetStackPointer(frame, stack_pointer); + int err = _PyObject_LookupSpecialMethod(name, method_and_self); + stack_pointer = _PyFrame_GetStackPointer(frame); + if (err <= 0) { + if (err == 0) { + PyObject *owner = PyStackRef_AsPyObjectBorrow(method_and_self[1]); + _PyFrame_SetStackPointer(frame, stack_pointer); + const char *errfmt = _PyEval_SpecialMethodCanSuggest(owner, oparg) + ? _Py_SpecialMethods[oparg].error_suggestion + : _Py_SpecialMethods[oparg].error; + stack_pointer = _PyFrame_GetStackPointer(frame); + assert(!_PyErr_Occurred(tstate)); + assert(errfmt != NULL); + _PyFrame_SetStackPointer(frame, stack_pointer); + _PyErr_Format(tstate, PyExc_TypeError, errfmt, owner); + stack_pointer = _PyFrame_GetStackPointer(frame); + } + JUMP_TO_LABEL(error); } - JUMP_TO_LABEL(error); } - attr = PyStackRef_FromPyObjectSteal(attr_o); - self_or_null = self_or_null_o == NULL ? - PyStackRef_NULL : PyStackRef_FromPyObjectSteal(self_or_null_o); - stack_pointer[0] = attr; - stack_pointer[1] = self_or_null; - stack_pointer += 2; - assert(WITHIN_STACK_BOUNDS()); DISPATCH(); } diff --git a/Python/optimizer_bytecodes.c b/Python/optimizer_bytecodes.c index 6f7f9b03d3bf06..9f1e3f6e1e2289 100644 --- a/Python/optimizer_bytecodes.c +++ b/Python/optimizer_bytecodes.c @@ -897,9 +897,14 @@ dummy_func(void) { } } - op(_LOAD_SPECIAL, (owner -- attr, self_or_null)) { - attr = sym_new_not_null(ctx); - self_or_null = sym_new_unknown(ctx); + op(_INSERT_NULL, (self -- method_and_self[2])) { + method_and_self[0] = sym_new_null(ctx); + method_and_self[1] = self; + } + + op(_LOAD_SPECIAL, (method_and_self[2] -- method_and_self[2])) { + method_and_self[0] = sym_new_not_null(ctx); + method_and_self[1] = sym_new_unknown(ctx); } op(_JUMP_TO_TOP, (--)) { diff --git a/Python/optimizer_cases.c.h b/Python/optimizer_cases.c.h index 983af081e2f8cd..28bca2a373ec2e 100644 --- a/Python/optimizer_cases.c.h +++ b/Python/optimizer_cases.c.h @@ -1553,18 +1553,26 @@ break; } - case _LOAD_SPECIAL: { - JitOptSymbol *attr; - JitOptSymbol *self_or_null; - attr = sym_new_not_null(ctx); - self_or_null = sym_new_unknown(ctx); - stack_pointer[-1] = attr; - stack_pointer[0] = self_or_null; + case _INSERT_NULL: { + JitOptSymbol *self; + JitOptSymbol **method_and_self; + self = stack_pointer[-1]; + method_and_self = &stack_pointer[-1]; + method_and_self[0] = sym_new_null(ctx); + method_and_self[1] = self; stack_pointer += 1; assert(WITHIN_STACK_BOUNDS()); break; } + case _LOAD_SPECIAL: { + JitOptSymbol **method_and_self; + method_and_self = &stack_pointer[-2]; + method_and_self[0] = sym_new_not_null(ctx); + method_and_self[1] = sym_new_unknown(ctx); + break; + } + case _WITH_EXCEPT_START: { JitOptSymbol *res; res = sym_new_not_null(ctx); diff --git a/Tools/ftscalingbench/ftscalingbench.py b/Tools/ftscalingbench/ftscalingbench.py index 364c465bc91b0b..926bc66b944c6f 100644 --- a/Tools/ftscalingbench/ftscalingbench.py +++ b/Tools/ftscalingbench/ftscalingbench.py @@ -65,6 +65,19 @@ def object_lookup_special(): for i in range(N): round(i / N) +class MyContextManager: + def __enter__(self): + pass + def __exit__(self, exc_type, exc_value, traceback): + pass + +@register_benchmark +def context_manager(): + N = 1000 * WORK_SCALE + for i in range(N): + with MyContextManager(): + pass + @register_benchmark def mult_constant(): x = 1.0 _______________________________________________ Python-checkins mailing list -- python-checkins@python.org To unsubscribe send an email to python-checkins-le...@python.org https://mail.python.org/mailman3/lists/python-checkins.python.org/ Member address: arch...@mail-archive.com