aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rw-r--r--Include/internal/pycore_object.h2
-rw-r--r--Include/internal/pycore_opcode_metadata.h4
-rw-r--r--Include/internal/pycore_uop_ids.h207
-rw-r--r--Include/internal/pycore_uop_metadata.h8
-rw-r--r--Objects/typeobject.c43
-rw-r--r--Python/bytecodes.c31
-rw-r--r--Python/executor_cases.c.h41
-rw-r--r--Python/generated_cases.c.h66
-rw-r--r--Python/optimizer_bytecodes.c11
-rw-r--r--Python/optimizer_cases.c.h22
-rw-r--r--Tools/ftscalingbench/ftscalingbench.py13
11 files changed, 244 insertions, 204 deletions
diff --git a/Include/internal/pycore_object.h b/Include/internal/pycore_object.h
index e5034ff4dcc..b7e162c8abc 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 521f7a92cf0..3f01f7d997f 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 e9a536919da..691bc6d6586 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 874756770c1..b2df354fdcc 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 5663aee3c2e..a720a98121d 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 07df22c761f..ad82e0b060d 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 cd265c383bd..c65cc9efa5e 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 911f5ae3e7c..18785c7be4c 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 6f7f9b03d3b..9f1e3f6e1e2 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 983af081e2f..28bca2a373e 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 364c465bc91..926bc66b944 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