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__`.
This commit is contained in:
Sam Gross 2025-04-21 15:54:25 -04:00 committed by GitHub
parent 8dfa840773
commit da53660f35
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 247 additions and 207 deletions

View file

@ -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.

View file

@ -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 } } },

View file

@ -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
}

View file

@ -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:

View file

@ -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

View file

@ -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()

View file

@ -4407,43 +4407,42 @@
break;
}
case _LOAD_SPECIAL: {
_PyStackRef owner;
_PyStackRef attr;
_PyStackRef self_or_null;
oparg = CURRENT_OPARG();
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;
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 *method_and_self;
oparg = CURRENT_OPARG();
method_and_self = &stack_pointer[-2];
PyObject *name = _Py_SpecialMethods[oparg].name;
_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;
}

View file

@ -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);
}
JUMP_TO_LABEL(error);
_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);
}
}
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();
}

View file

@ -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, (--)) {

View file

@ -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);

View file

@ -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