GH-143732: SEND specialization (GH-148963)

* SEND specialization. Adds 2 new specialized instructions:

* SEND_VIRTUAL: for sends to virtual iterators e.g lists and tuples
* SEND_ASYNC_GEN: for sends to async generators

Tweak FOR_ITER_VIRTUAL so that SEND_VIRTUAL and FOR_ITER_VIRTUAL use equivalent guards
This commit is contained in:
Mark Shannon
2026-05-05 15:19:16 +01:00
committed by GitHub
parent ffb543d32f
commit 70bd1c2dd2
29 changed files with 2662 additions and 1548 deletions
+5 -1
View File
@@ -241,7 +241,11 @@ struct _typeobject {
* Otherwise, limited to MAX_VERSIONS_PER_CLASS (defined elsewhere).
*/
uint16_t tp_versions_used;
_Py_iteritemfunc _tp_iteritem; /* Virtual iterator next function */
/* Virtual iterator next function.
* This function must escape to any code that can result in
* the GC being run, such as Py_DECREF. */
_Py_iteritemfunc _tp_iteritem;
};
#define _Py_ATTR_CACHE_UNUSED (30000) // (see tp_versions_used)
+8
View File
@@ -60,6 +60,14 @@ PyAPI_FUNC(int) _Py_convert_optional_to_non_negative_ssize_t(PyObject *, void *)
// Export for 'math' shared extension.
PyAPI_FUNC(PyObject*) _PyNumber_Index(PyObject *o);
typedef struct {
PyObject *object;
PySendResult kind;
} PySendResultPair;
// Same as PyIter_Send but returns a struct for MSVC tailcall support
PyAPI_FUNC(PySendResultPair) _PyIter_Send(PyObject *iter, PyObject *arg);
#ifdef __cplusplus
}
#endif
+2
View File
@@ -40,6 +40,8 @@ extern PyTypeObject _PyCoroWrapper_Type;
extern PyTypeObject _PyAsyncGenWrappedValue_Type;
extern PyTypeObject _PyAsyncGenAThrow_Type;
PyAPI_FUNC(PySendResult) _PyAsyncGenASend_Send(PyObject *iter, PyObject *arg, PyObject **result);
#ifdef __cplusplus
}
#endif
+2 -1
View File
@@ -296,6 +296,7 @@ Known values:
Python 3.15a8 3663 (Merge GET_ITER and GET_YIELD_FROM_ITER. Modify SEND to make it a bit more like FOR_ITER)
Python 3.15a8 3664 (Fix __qualname__ for __annotate__ functions)
Python 3.15a8 3665 (Add FOR_ITER_VIRTUAL and GET_ITER specializations)
Python 3.15b1 3666 (Add SEND_VIRTUAL and SEND_ASYNC_GEN specializations)
Python 3.16 will start with 3700
@@ -309,7 +310,7 @@ PC/launcher.c must also be updated.
*/
#define PYC_MAGIC_NUMBER 3665
#define PYC_MAGIC_NUMBER 3666
/* This is equivalent to converting PYC_MAGIC_NUMBER to 2 bytes
(little-endian) and then appending b'\r\n'. */
#define PYC_MAGIC_NUMBER_TOKEN \
+18 -6
View File
@@ -438,8 +438,12 @@ int _PyOpcode_num_popped(int opcode, int oparg) {
return 1;
case SEND:
return 3;
case SEND_ASYNC_GEN:
return 3;
case SEND_GEN:
return 3;
case SEND_VIRTUAL:
return 3;
case SETUP_ANNOTATIONS:
return 0;
case SETUP_CLEANUP:
@@ -935,8 +939,12 @@ int _PyOpcode_num_pushed(int opcode, int oparg) {
return 1;
case SEND:
return 3;
case SEND_ASYNC_GEN:
return 3;
case SEND_GEN:
return 2;
case SEND_VIRTUAL:
return 3;
case SETUP_ANNOTATIONS:
return 0;
case SETUP_CLEANUP:
@@ -1298,7 +1306,9 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[267] = {
[RETURN_GENERATOR] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG | HAS_NEEDS_GUARD_IP_FLAG },
[RETURN_VALUE] = { true, INSTR_FMT_IX, HAS_ESCAPES_FLAG | HAS_NEEDS_GUARD_IP_FLAG },
[SEND] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_JUMP_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG | HAS_SYNC_SP_FLAG | HAS_NEEDS_GUARD_IP_FLAG },
[SEND_ASYNC_GEN] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_JUMP_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG | HAS_UNPREDICTABLE_JUMP_FLAG },
[SEND_GEN] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_SYNC_SP_FLAG | HAS_NEEDS_GUARD_IP_FLAG | HAS_RECORDS_VALUE_FLAG },
[SEND_VIRTUAL] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_JUMP_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG | HAS_UNPREDICTABLE_JUMP_FLAG },
[SETUP_ANNOTATIONS] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG },
[SET_ADD] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG },
[SET_FUNCTION_ATTRIBUTE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG },
@@ -1443,7 +1453,7 @@ _PyOpcode_macro_expansion[256] = {
[FOR_ITER_LIST] = { .nuops = 3, .uops = { { _ITER_CHECK_LIST, OPARG_SIMPLE, 1 }, { _ITER_JUMP_LIST, OPARG_REPLACED, 1 }, { _ITER_NEXT_LIST, OPARG_REPLACED, 1 } } },
[FOR_ITER_RANGE] = { .nuops = 3, .uops = { { _ITER_CHECK_RANGE, OPARG_SIMPLE, 1 }, { _ITER_JUMP_RANGE, OPARG_REPLACED, 1 }, { _ITER_NEXT_RANGE, OPARG_SIMPLE, 1 } } },
[FOR_ITER_TUPLE] = { .nuops = 3, .uops = { { _ITER_CHECK_TUPLE, OPARG_SIMPLE, 1 }, { _ITER_JUMP_TUPLE, OPARG_REPLACED, 1 }, { _ITER_NEXT_TUPLE, OPARG_SIMPLE, 1 } } },
[FOR_ITER_VIRTUAL] = { .nuops = 2, .uops = { { _GUARD_NOS_ITER_VIRTUAL, OPARG_SIMPLE, 1 }, { _FOR_ITER_VIRTUAL, OPARG_REPLACED, 1 } } },
[FOR_ITER_VIRTUAL] = { .nuops = 2, .uops = { { _GUARD_TOS_NOT_NULL, OPARG_SIMPLE, 1 }, { _FOR_ITER_VIRTUAL, OPARG_REPLACED, 1 } } },
[GET_AITER] = { .nuops = 1, .uops = { { _GET_AITER, OPARG_SIMPLE, 0 } } },
[GET_ANEXT] = { .nuops = 1, .uops = { { _GET_ANEXT, OPARG_SIMPLE, 0 } } },
[GET_AWAITABLE] = { .nuops = 1, .uops = { { _GET_AWAITABLE, OPARG_SIMPLE, 0 } } },
@@ -1514,7 +1524,9 @@ _PyOpcode_macro_expansion[256] = {
[RESUME_CHECK] = { .nuops = 1, .uops = { { _RESUME_CHECK, OPARG_SIMPLE, 1 } } },
[RETURN_GENERATOR] = { .nuops = 1, .uops = { { _RETURN_GENERATOR, OPARG_SIMPLE, 0 } } },
[RETURN_VALUE] = { .nuops = 2, .uops = { { _MAKE_HEAP_SAFE, OPARG_SIMPLE, 0 }, { _RETURN_VALUE, OPARG_SIMPLE, 0 } } },
[SEND_ASYNC_GEN] = { .nuops = 2, .uops = { { _GUARD_3OS_ASYNC_GEN_ASEND, OPARG_SIMPLE, 1 }, { _SEND_ASYNC_GEN, OPARG_REPLACED, 1 } } },
[SEND_GEN] = { .nuops = 4, .uops = { { _RECORD_3OS_GEN_FUNC, OPARG_SIMPLE, 1 }, { _CHECK_PEP_523, OPARG_SIMPLE, 1 }, { _SEND_GEN_FRAME, OPARG_SIMPLE, 1 }, { _PUSH_FRAME, OPARG_SIMPLE, 1 } } },
[SEND_VIRTUAL] = { .nuops = 3, .uops = { { _GUARD_TOS_IS_NONE, OPARG_SIMPLE, 1 }, { _GUARD_NOS_NOT_NULL, OPARG_SIMPLE, 1 }, { _SEND_VIRTUAL, OPARG_REPLACED, 1 } } },
[SETUP_ANNOTATIONS] = { .nuops = 1, .uops = { { _SETUP_ANNOTATIONS, OPARG_SIMPLE, 0 } } },
[SET_ADD] = { .nuops = 1, .uops = { { _SET_ADD, OPARG_SIMPLE, 0 } } },
[SET_FUNCTION_ATTRIBUTE] = { .nuops = 1, .uops = { { _SET_FUNCTION_ATTRIBUTE, OPARG_SIMPLE, 0 } } },
@@ -1758,7 +1770,9 @@ const char *_PyOpcode_OpName[267] = {
[RETURN_GENERATOR] = "RETURN_GENERATOR",
[RETURN_VALUE] = "RETURN_VALUE",
[SEND] = "SEND",
[SEND_ASYNC_GEN] = "SEND_ASYNC_GEN",
[SEND_GEN] = "SEND_GEN",
[SEND_VIRTUAL] = "SEND_VIRTUAL",
[SETUP_ANNOTATIONS] = "SETUP_ANNOTATIONS",
[SETUP_CLEANUP] = "SETUP_CLEANUP",
[SETUP_FINALLY] = "SETUP_FINALLY",
@@ -1810,6 +1824,7 @@ const uint8_t _PyOpcode_Caches[256] = {
[TO_BOOL] = 3,
[STORE_SUBSCR] = 1,
[SEND] = 1,
[FOR_ITER] = 1,
[UNPACK_SEQUENCE] = 1,
[STORE_ATTR] = 4,
[LOAD_GLOBAL] = 4,
@@ -1823,7 +1838,6 @@ const uint8_t _PyOpcode_Caches[256] = {
[POP_JUMP_IF_NONE] = 1,
[POP_JUMP_IF_NOT_NONE] = 1,
[GET_ITER] = 1,
[FOR_ITER] = 1,
[CALL] = 3,
[CALL_KW] = 3,
[CALL_FUNCTION_EX] = 1,
@@ -1842,8 +1856,6 @@ const uint8_t _PyOpcode_Deopt[256] = {
[125] = 125,
[126] = 126,
[127] = 127,
[217] = 217,
[218] = 218,
[219] = 219,
[220] = 220,
[221] = 221,
@@ -2052,7 +2064,9 @@ const uint8_t _PyOpcode_Deopt[256] = {
[RETURN_GENERATOR] = RETURN_GENERATOR,
[RETURN_VALUE] = RETURN_VALUE,
[SEND] = SEND,
[SEND_ASYNC_GEN] = SEND,
[SEND_GEN] = SEND,
[SEND_VIRTUAL] = SEND,
[SETUP_ANNOTATIONS] = SETUP_ANNOTATIONS,
[SET_ADD] = SET_ADD,
[SET_FUNCTION_ATTRIBUTE] = SET_FUNCTION_ATTRIBUTE,
@@ -2103,8 +2117,6 @@ const uint8_t _PyOpcode_Deopt[256] = {
case 125: \
case 126: \
case 127: \
case 217: \
case 218: \
case 219: \
case 220: \
case 221: \
+1244 -1220
View File
File diff suppressed because it is too large Load Diff
+115 -16
View File
@@ -168,6 +168,11 @@ const uint32_t _PyUop_Flags[MAX_UOP_ID+1] = {
[_GET_ANEXT] = HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG,
[_GET_AWAITABLE] = HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG,
[_SEND_GEN_FRAME] = HAS_ARG_FLAG | HAS_EXIT_FLAG,
[_GUARD_TOS_IS_NONE] = HAS_EXIT_FLAG,
[_GUARD_NOS_NOT_NULL] = HAS_EXIT_FLAG,
[_SEND_VIRTUAL_TIER_TWO] = HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG,
[_GUARD_3OS_ASYNC_GEN_ASEND] = HAS_EXIT_FLAG,
[_SEND_ASYNC_GEN_TIER_TWO] = HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG,
[_YIELD_VALUE] = HAS_ARG_FLAG | HAS_ESCAPES_FLAG | HAS_NEEDS_GUARD_IP_FLAG,
[_POP_EXCEPT] = HAS_ESCAPES_FLAG,
[_LOAD_COMMON_CONSTANT] = HAS_ARG_FLAG,
@@ -265,6 +270,7 @@ const uint32_t _PyUop_Flags[MAX_UOP_ID+1] = {
[_GUARD_TYPE_ITER] = HAS_EXIT_FLAG,
[_ITER_NEXT_INLINE] = HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG,
[_GUARD_NOS_ITER_VIRTUAL] = HAS_EXIT_FLAG,
[_GUARD_TOS_NOT_NULL] = HAS_EXIT_FLAG,
[_FOR_ITER_VIRTUAL_TIER_TWO] = HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG,
[_ITER_CHECK_LIST] = HAS_EXIT_FLAG,
[_GUARD_NOT_EXHAUSTED_LIST] = HAS_EXIT_FLAG,
@@ -310,7 +316,6 @@ const uint32_t _PyUop_Flags[MAX_UOP_ID+1] = {
[_INIT_CALL_PY_EXACT_ARGS] = HAS_ARG_FLAG | HAS_PURE_FLAG,
[_PUSH_FRAME] = HAS_SYNC_SP_FLAG | HAS_NEEDS_GUARD_IP_FLAG,
[_GUARD_NOS_NULL] = HAS_EXIT_FLAG,
[_GUARD_NOS_NOT_NULL] = HAS_EXIT_FLAG,
[_GUARD_THIRD_NULL] = HAS_EXIT_FLAG,
[_GUARD_CALLABLE_TYPE_1] = HAS_EXIT_FLAG,
[_CALL_TYPE_1] = HAS_ARG_FLAG,
@@ -1641,6 +1646,51 @@ const _PyUopCachingInfo _PyUop_Caching[MAX_UOP_ID+1] = {
{ 3, 3, _SEND_GEN_FRAME_r33 },
},
},
[_GUARD_TOS_IS_NONE] = {
.best = { 0, 1, 2, 3 },
.entries = {
{ 1, 0, _GUARD_TOS_IS_NONE_r01 },
{ 1, 1, _GUARD_TOS_IS_NONE_r11 },
{ 2, 2, _GUARD_TOS_IS_NONE_r22 },
{ 3, 3, _GUARD_TOS_IS_NONE_r33 },
},
},
[_GUARD_NOS_NOT_NULL] = {
.best = { 0, 1, 2, 3 },
.entries = {
{ 2, 0, _GUARD_NOS_NOT_NULL_r02 },
{ 2, 1, _GUARD_NOS_NOT_NULL_r12 },
{ 2, 2, _GUARD_NOS_NOT_NULL_r22 },
{ 3, 3, _GUARD_NOS_NOT_NULL_r33 },
},
},
[_SEND_VIRTUAL_TIER_TWO] = {
.best = { 0, 1, 2, 3 },
.entries = {
{ 3, 0, _SEND_VIRTUAL_TIER_TWO_r03 },
{ 3, 1, _SEND_VIRTUAL_TIER_TWO_r13 },
{ 3, 2, _SEND_VIRTUAL_TIER_TWO_r23 },
{ 3, 3, _SEND_VIRTUAL_TIER_TWO_r33 },
},
},
[_GUARD_3OS_ASYNC_GEN_ASEND] = {
.best = { 0, 1, 2, 3 },
.entries = {
{ 3, 0, _GUARD_3OS_ASYNC_GEN_ASEND_r03 },
{ 3, 1, _GUARD_3OS_ASYNC_GEN_ASEND_r13 },
{ 3, 2, _GUARD_3OS_ASYNC_GEN_ASEND_r23 },
{ 3, 3, _GUARD_3OS_ASYNC_GEN_ASEND_r33 },
},
},
[_SEND_ASYNC_GEN_TIER_TWO] = {
.best = { 3, 3, 3, 3 },
.entries = {
{ -1, -1, -1 },
{ -1, -1, -1 },
{ -1, -1, -1 },
{ 3, 3, _SEND_ASYNC_GEN_TIER_TWO_r33 },
},
},
[_YIELD_VALUE] = {
.best = { 1, 1, 1, 1 },
.entries = {
@@ -2514,6 +2564,15 @@ const _PyUopCachingInfo _PyUop_Caching[MAX_UOP_ID+1] = {
{ 3, 3, _GUARD_NOS_ITER_VIRTUAL_r33 },
},
},
[_GUARD_TOS_NOT_NULL] = {
.best = { 0, 1, 2, 3 },
.entries = {
{ 1, 0, _GUARD_TOS_NOT_NULL_r01 },
{ 1, 1, _GUARD_TOS_NOT_NULL_r11 },
{ 2, 2, _GUARD_TOS_NOT_NULL_r22 },
{ 3, 3, _GUARD_TOS_NOT_NULL_r33 },
},
},
[_FOR_ITER_VIRTUAL_TIER_TWO] = {
.best = { 2, 2, 2, 2 },
.entries = {
@@ -2919,15 +2978,6 @@ const _PyUopCachingInfo _PyUop_Caching[MAX_UOP_ID+1] = {
{ 3, 3, _GUARD_NOS_NULL_r33 },
},
},
[_GUARD_NOS_NOT_NULL] = {
.best = { 0, 1, 2, 3 },
.entries = {
{ 2, 0, _GUARD_NOS_NOT_NULL_r02 },
{ 2, 1, _GUARD_NOS_NOT_NULL_r12 },
{ 2, 2, _GUARD_NOS_NOT_NULL_r22 },
{ 3, 3, _GUARD_NOS_NOT_NULL_r33 },
},
},
[_GUARD_THIRD_NULL] = {
.best = { 0, 1, 2, 3 },
.entries = {
@@ -4252,6 +4302,23 @@ const uint16_t _PyUop_Uncached[MAX_UOP_REGS_ID+1] = {
[_GET_ANEXT_r12] = _GET_ANEXT,
[_GET_AWAITABLE_r11] = _GET_AWAITABLE,
[_SEND_GEN_FRAME_r33] = _SEND_GEN_FRAME,
[_GUARD_TOS_IS_NONE_r01] = _GUARD_TOS_IS_NONE,
[_GUARD_TOS_IS_NONE_r11] = _GUARD_TOS_IS_NONE,
[_GUARD_TOS_IS_NONE_r22] = _GUARD_TOS_IS_NONE,
[_GUARD_TOS_IS_NONE_r33] = _GUARD_TOS_IS_NONE,
[_GUARD_NOS_NOT_NULL_r02] = _GUARD_NOS_NOT_NULL,
[_GUARD_NOS_NOT_NULL_r12] = _GUARD_NOS_NOT_NULL,
[_GUARD_NOS_NOT_NULL_r22] = _GUARD_NOS_NOT_NULL,
[_GUARD_NOS_NOT_NULL_r33] = _GUARD_NOS_NOT_NULL,
[_SEND_VIRTUAL_TIER_TWO_r03] = _SEND_VIRTUAL_TIER_TWO,
[_SEND_VIRTUAL_TIER_TWO_r13] = _SEND_VIRTUAL_TIER_TWO,
[_SEND_VIRTUAL_TIER_TWO_r23] = _SEND_VIRTUAL_TIER_TWO,
[_SEND_VIRTUAL_TIER_TWO_r33] = _SEND_VIRTUAL_TIER_TWO,
[_GUARD_3OS_ASYNC_GEN_ASEND_r03] = _GUARD_3OS_ASYNC_GEN_ASEND,
[_GUARD_3OS_ASYNC_GEN_ASEND_r13] = _GUARD_3OS_ASYNC_GEN_ASEND,
[_GUARD_3OS_ASYNC_GEN_ASEND_r23] = _GUARD_3OS_ASYNC_GEN_ASEND,
[_GUARD_3OS_ASYNC_GEN_ASEND_r33] = _GUARD_3OS_ASYNC_GEN_ASEND,
[_SEND_ASYNC_GEN_TIER_TWO_r33] = _SEND_ASYNC_GEN_TIER_TWO,
[_YIELD_VALUE_r11] = _YIELD_VALUE,
[_POP_EXCEPT_r10] = _POP_EXCEPT,
[_LOAD_COMMON_CONSTANT_r01] = _LOAD_COMMON_CONSTANT,
@@ -4427,6 +4494,10 @@ const uint16_t _PyUop_Uncached[MAX_UOP_REGS_ID+1] = {
[_GUARD_NOS_ITER_VIRTUAL_r12] = _GUARD_NOS_ITER_VIRTUAL,
[_GUARD_NOS_ITER_VIRTUAL_r22] = _GUARD_NOS_ITER_VIRTUAL,
[_GUARD_NOS_ITER_VIRTUAL_r33] = _GUARD_NOS_ITER_VIRTUAL,
[_GUARD_TOS_NOT_NULL_r01] = _GUARD_TOS_NOT_NULL,
[_GUARD_TOS_NOT_NULL_r11] = _GUARD_TOS_NOT_NULL,
[_GUARD_TOS_NOT_NULL_r22] = _GUARD_TOS_NOT_NULL,
[_GUARD_TOS_NOT_NULL_r33] = _GUARD_TOS_NOT_NULL,
[_FOR_ITER_VIRTUAL_TIER_TWO_r23] = _FOR_ITER_VIRTUAL_TIER_TWO,
[_ITER_CHECK_LIST_r02] = _ITER_CHECK_LIST,
[_ITER_CHECK_LIST_r12] = _ITER_CHECK_LIST,
@@ -4525,10 +4596,6 @@ const uint16_t _PyUop_Uncached[MAX_UOP_REGS_ID+1] = {
[_GUARD_NOS_NULL_r12] = _GUARD_NOS_NULL,
[_GUARD_NOS_NULL_r22] = _GUARD_NOS_NULL,
[_GUARD_NOS_NULL_r33] = _GUARD_NOS_NULL,
[_GUARD_NOS_NOT_NULL_r02] = _GUARD_NOS_NOT_NULL,
[_GUARD_NOS_NOT_NULL_r12] = _GUARD_NOS_NOT_NULL,
[_GUARD_NOS_NOT_NULL_r22] = _GUARD_NOS_NOT_NULL,
[_GUARD_NOS_NOT_NULL_r33] = _GUARD_NOS_NOT_NULL,
[_GUARD_THIRD_NULL_r03] = _GUARD_THIRD_NULL,
[_GUARD_THIRD_NULL_r13] = _GUARD_THIRD_NULL,
[_GUARD_THIRD_NULL_r23] = _GUARD_THIRD_NULL,
@@ -5206,6 +5273,11 @@ const char *const _PyOpcode_uop_name[MAX_UOP_REGS_ID+1] = {
[_GET_ITER_TRAD_r12] = "_GET_ITER_TRAD_r12",
[_GET_LEN] = "_GET_LEN",
[_GET_LEN_r12] = "_GET_LEN_r12",
[_GUARD_3OS_ASYNC_GEN_ASEND] = "_GUARD_3OS_ASYNC_GEN_ASEND",
[_GUARD_3OS_ASYNC_GEN_ASEND_r03] = "_GUARD_3OS_ASYNC_GEN_ASEND_r03",
[_GUARD_3OS_ASYNC_GEN_ASEND_r13] = "_GUARD_3OS_ASYNC_GEN_ASEND_r13",
[_GUARD_3OS_ASYNC_GEN_ASEND_r23] = "_GUARD_3OS_ASYNC_GEN_ASEND_r23",
[_GUARD_3OS_ASYNC_GEN_ASEND_r33] = "_GUARD_3OS_ASYNC_GEN_ASEND_r33",
[_GUARD_BINARY_OP_EXTEND] = "_GUARD_BINARY_OP_EXTEND",
[_GUARD_BINARY_OP_EXTEND_r22] = "_GUARD_BINARY_OP_EXTEND_r22",
[_GUARD_BINARY_OP_EXTEND_LHS] = "_GUARD_BINARY_OP_EXTEND_LHS",
@@ -5531,11 +5603,21 @@ const char *const _PyOpcode_uop_name[MAX_UOP_REGS_ID+1] = {
[_GUARD_TOS_INT_r11] = "_GUARD_TOS_INT_r11",
[_GUARD_TOS_INT_r22] = "_GUARD_TOS_INT_r22",
[_GUARD_TOS_INT_r33] = "_GUARD_TOS_INT_r33",
[_GUARD_TOS_IS_NONE] = "_GUARD_TOS_IS_NONE",
[_GUARD_TOS_IS_NONE_r01] = "_GUARD_TOS_IS_NONE_r01",
[_GUARD_TOS_IS_NONE_r11] = "_GUARD_TOS_IS_NONE_r11",
[_GUARD_TOS_IS_NONE_r22] = "_GUARD_TOS_IS_NONE_r22",
[_GUARD_TOS_IS_NONE_r33] = "_GUARD_TOS_IS_NONE_r33",
[_GUARD_TOS_LIST] = "_GUARD_TOS_LIST",
[_GUARD_TOS_LIST_r01] = "_GUARD_TOS_LIST_r01",
[_GUARD_TOS_LIST_r11] = "_GUARD_TOS_LIST_r11",
[_GUARD_TOS_LIST_r22] = "_GUARD_TOS_LIST_r22",
[_GUARD_TOS_LIST_r33] = "_GUARD_TOS_LIST_r33",
[_GUARD_TOS_NOT_NULL] = "_GUARD_TOS_NOT_NULL",
[_GUARD_TOS_NOT_NULL_r01] = "_GUARD_TOS_NOT_NULL_r01",
[_GUARD_TOS_NOT_NULL_r11] = "_GUARD_TOS_NOT_NULL_r11",
[_GUARD_TOS_NOT_NULL_r22] = "_GUARD_TOS_NOT_NULL_r22",
[_GUARD_TOS_NOT_NULL_r33] = "_GUARD_TOS_NOT_NULL_r33",
[_GUARD_TOS_OVERFLOWED] = "_GUARD_TOS_OVERFLOWED",
[_GUARD_TOS_OVERFLOWED_r01] = "_GUARD_TOS_OVERFLOWED_r01",
[_GUARD_TOS_OVERFLOWED_r11] = "_GUARD_TOS_OVERFLOWED_r11",
@@ -5952,8 +6034,15 @@ const char *const _PyOpcode_uop_name[MAX_UOP_REGS_ID+1] = {
[_SAVE_RETURN_OFFSET_r11] = "_SAVE_RETURN_OFFSET_r11",
[_SAVE_RETURN_OFFSET_r22] = "_SAVE_RETURN_OFFSET_r22",
[_SAVE_RETURN_OFFSET_r33] = "_SAVE_RETURN_OFFSET_r33",
[_SEND_ASYNC_GEN_TIER_TWO] = "_SEND_ASYNC_GEN_TIER_TWO",
[_SEND_ASYNC_GEN_TIER_TWO_r33] = "_SEND_ASYNC_GEN_TIER_TWO_r33",
[_SEND_GEN_FRAME] = "_SEND_GEN_FRAME",
[_SEND_GEN_FRAME_r33] = "_SEND_GEN_FRAME_r33",
[_SEND_VIRTUAL_TIER_TWO] = "_SEND_VIRTUAL_TIER_TWO",
[_SEND_VIRTUAL_TIER_TWO_r03] = "_SEND_VIRTUAL_TIER_TWO_r03",
[_SEND_VIRTUAL_TIER_TWO_r13] = "_SEND_VIRTUAL_TIER_TWO_r13",
[_SEND_VIRTUAL_TIER_TWO_r23] = "_SEND_VIRTUAL_TIER_TWO_r23",
[_SEND_VIRTUAL_TIER_TWO_r33] = "_SEND_VIRTUAL_TIER_TWO_r33",
[_SETUP_ANNOTATIONS] = "_SETUP_ANNOTATIONS",
[_SETUP_ANNOTATIONS_r00] = "_SETUP_ANNOTATIONS_r00",
[_SET_ADD] = "_SET_ADD",
@@ -6401,6 +6490,16 @@ int _PyUop_num_popped(int opcode, int oparg)
return 1;
case _SEND_GEN_FRAME:
return 1;
case _GUARD_TOS_IS_NONE:
return 0;
case _GUARD_NOS_NOT_NULL:
return 0;
case _SEND_VIRTUAL_TIER_TWO:
return 1;
case _GUARD_3OS_ASYNC_GEN_ASEND:
return 0;
case _SEND_ASYNC_GEN_TIER_TWO:
return 3;
case _YIELD_VALUE:
return 1;
case _POP_EXCEPT:
@@ -6595,6 +6694,8 @@ int _PyUop_num_popped(int opcode, int oparg)
return 0;
case _GUARD_NOS_ITER_VIRTUAL:
return 0;
case _GUARD_TOS_NOT_NULL:
return 0;
case _FOR_ITER_VIRTUAL_TIER_TWO:
return 0;
case _ITER_CHECK_LIST:
@@ -6685,8 +6786,6 @@ int _PyUop_num_popped(int opcode, int oparg)
return 1;
case _GUARD_NOS_NULL:
return 0;
case _GUARD_NOS_NOT_NULL:
return 0;
case _GUARD_THIRD_NULL:
return 0;
case _GUARD_CALLABLE_TYPE_1:
+17 -15
View File
@@ -204,21 +204,23 @@ extern "C" {
#define LOAD_SUPER_ATTR_METHOD 199
#define RESUME_CHECK 200
#define RESUME_CHECK_JIT 201
#define SEND_GEN 202
#define STORE_ATTR_INSTANCE_VALUE 203
#define STORE_ATTR_SLOT 204
#define STORE_ATTR_WITH_HINT 205
#define STORE_SUBSCR_DICT 206
#define STORE_SUBSCR_LIST_INT 207
#define TO_BOOL_ALWAYS_TRUE 208
#define TO_BOOL_BOOL 209
#define TO_BOOL_INT 210
#define TO_BOOL_LIST 211
#define TO_BOOL_NONE 212
#define TO_BOOL_STR 213
#define UNPACK_SEQUENCE_LIST 214
#define UNPACK_SEQUENCE_TUPLE 215
#define UNPACK_SEQUENCE_TWO_TUPLE 216
#define SEND_ASYNC_GEN 202
#define SEND_GEN 203
#define SEND_VIRTUAL 204
#define STORE_ATTR_INSTANCE_VALUE 205
#define STORE_ATTR_SLOT 206
#define STORE_ATTR_WITH_HINT 207
#define STORE_SUBSCR_DICT 208
#define STORE_SUBSCR_LIST_INT 209
#define TO_BOOL_ALWAYS_TRUE 210
#define TO_BOOL_BOOL 211
#define TO_BOOL_INT 212
#define TO_BOOL_LIST 213
#define TO_BOOL_NONE 214
#define TO_BOOL_STR 215
#define UNPACK_SEQUENCE_LIST 216
#define UNPACK_SEQUENCE_TUPLE 217
#define UNPACK_SEQUENCE_TWO_TUPLE 218
#define INSTRUMENTED_END_FOR 233
#define INSTRUMENTED_POP_ITER 234
#define INSTRUMENTED_END_SEND 235
+19 -15
View File
@@ -39,6 +39,8 @@ _specializations = frozendict(
),
SEND=(
"SEND_GEN",
"SEND_VIRTUAL",
"SEND_ASYNC_GEN",
),
UNPACK_SEQUENCE=(
"UNPACK_SEQUENCE_TWO_TUPLE",
@@ -205,21 +207,23 @@ _specialized_opmap = frozendict(
LOAD_SUPER_ATTR_METHOD=199,
RESUME_CHECK=200,
RESUME_CHECK_JIT=201,
SEND_GEN=202,
STORE_ATTR_INSTANCE_VALUE=203,
STORE_ATTR_SLOT=204,
STORE_ATTR_WITH_HINT=205,
STORE_SUBSCR_DICT=206,
STORE_SUBSCR_LIST_INT=207,
TO_BOOL_ALWAYS_TRUE=208,
TO_BOOL_BOOL=209,
TO_BOOL_INT=210,
TO_BOOL_LIST=211,
TO_BOOL_NONE=212,
TO_BOOL_STR=213,
UNPACK_SEQUENCE_LIST=214,
UNPACK_SEQUENCE_TUPLE=215,
UNPACK_SEQUENCE_TWO_TUPLE=216,
SEND_ASYNC_GEN=202,
SEND_GEN=203,
SEND_VIRTUAL=204,
STORE_ATTR_INSTANCE_VALUE=205,
STORE_ATTR_SLOT=206,
STORE_ATTR_WITH_HINT=207,
STORE_SUBSCR_DICT=208,
STORE_SUBSCR_LIST_INT=209,
TO_BOOL_ALWAYS_TRUE=210,
TO_BOOL_BOOL=211,
TO_BOOL_INT=212,
TO_BOOL_LIST=213,
TO_BOOL_NONE=214,
TO_BOOL_STR=215,
UNPACK_SEQUENCE_LIST=216,
UNPACK_SEQUENCE_TUPLE=217,
UNPACK_SEQUENCE_TWO_TUPLE=218,
)
opmap = frozendict(
+18
View File
@@ -5524,6 +5524,24 @@ class TestUopsOptimization(unittest.TestCase):
# _POP_TOP_NOP is a sign the optimizer ran and didn't hit bottom.
self.assertGreaterEqual(count_ops(ex, "_POP_TOP_NOP"), 1)
def test_send_virtual(self):
def send_list(n):
yield from list(range(n))
def testfunc(n):
for _ in send_list(n):
pass
for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD):
# Ensure SEND is specialized to SEND_VIRTUAL
send_list(10)
res, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD*2)
self.assertIsNotNone(ex)
uops = get_opnames(ex)
self.assertIn("_FOR_ITER_GEN_FRAME", uops)
self.assertIn("_SEND_VIRTUAL_TIER_TWO", uops)
def test_binary_op_subscr_init_frame(self):
class B:
def __getitem__(self, other):
+42
View File
@@ -1637,6 +1637,37 @@ class TestSpecializer(TestBase):
self.assert_specialized(send_yield_from, "SEND_GEN")
self.assert_no_opcode(send_yield_from, "SEND")
@cpython_only
@requires_specialization
def test_send_yield_from_iter(self):
L = list(range(100))
def send_yield_from():
yield from L
for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD):
list(send_yield_from())
self.assert_specialized(send_yield_from, "SEND_VIRTUAL")
self.assert_no_opcode(send_yield_from, "SEND")
@cpython_only
@requires_specialization
def test_send_async_for(self):
async def g():
yield None
async def send_for():
async for _ in g():
break
for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD):
try:
send_for().send(None)
except StopIteration:
pass
self.assert_specialized(send_for, "SEND_ASYNC_GEN")
self.assert_no_opcode(send_for, "SEND")
@cpython_only
@requires_specialization
def test_store_attr_slot(self):
@@ -2154,6 +2185,17 @@ class TestSpecializer(TestBase):
finally:
sys.modules.pop("test_module_with_getattr", None)
@cpython_only
@requires_specialization
def test_specialized_iter_doesnt_skip_send_check(self):
def gen_func(seq):
yield from seq
gen = gen_func(list(range(10)))
for _ in range(3):
gen.send(None)
with self.assertRaises(AttributeError):
gen.send(1)
@cpython_only
@requires_specialization
-3
View File
@@ -666,21 +666,18 @@ class TraceTestCase(unittest.TestCase):
(-2, 'line'),
(-1, 'line'),
(-1, 'return'),
(1, 'exception'),
(2, 'line'),
(1, 'line'),
(-1, 'call'),
(-2, 'line'),
(-1, 'line'),
(-1, 'return'),
(1, 'exception'),
(2, 'line'),
(1, 'line'),
(-1, 'call'),
(-2, 'line'),
(-1, 'line'),
(-1, 'return'),
(1, 'exception'),
(2, 'line'),
(1, 'line'),
(-1, 'call'),
+147 -52
View File
@@ -3782,8 +3782,7 @@
// _GUARD_NOS_NOT_NULL
{
nos = stack_pointer[-2];
PyObject *o = PyStackRef_AsPyObjectBorrow(nos);
if (o == NULL) {
if (PyStackRef_IsNull(nos)) {
UPDATE_MISS_STATS(CALL);
assert(_PyOpcode_Deopt[opcode] == (CALL));
JUMP_TO_PREDICTED(CALL);
@@ -5784,9 +5783,7 @@
int err = PyDict_Update(dict_o, update_o);
stack_pointer = _PyFrame_GetStackPointer(frame);
if (err < 0) {
_PyFrame_SetStackPointer(frame, stack_pointer);
int matches = _PyErr_ExceptionMatches(tstate, PyExc_AttributeError);
stack_pointer = _PyFrame_GetStackPointer(frame);
if (matches) {
_PyFrame_SetStackPointer(frame, stack_pointer);
PyObject *exc = _PyErr_GetRaisedException(tstate);
@@ -6407,15 +6404,14 @@
next_instr += 2;
INSTRUCTION_STATS(FOR_ITER_VIRTUAL);
static_assert(INLINE_CACHE_ENTRIES_FOR_ITER == 1, "incorrect cache size");
_PyStackRef iter;
_PyStackRef null_or_index;
_PyStackRef iter;
_PyStackRef next;
/* Skip 1 cache entry */
// _GUARD_NOS_ITER_VIRTUAL
// _GUARD_TOS_NOT_NULL
{
iter = stack_pointer[-2];
PyObject *iter_o = PyStackRef_AsPyObjectBorrow(iter);
if (Py_TYPE(iter_o)->_tp_iteritem == NULL) {
null_or_index = stack_pointer[-1];
if (PyStackRef_IsNull(null_or_index)) {
UPDATE_MISS_STATS(FOR_ITER);
assert(_PyOpcode_Deopt[opcode] == (FOR_ITER));
JUMP_TO_PREDICTED(FOR_ITER);
@@ -6423,7 +6419,7 @@
}
// _FOR_ITER_VIRTUAL
{
null_or_index = stack_pointer[-1];
iter = stack_pointer[-2];
PyObject *iter_o = PyStackRef_AsPyObjectBorrow(iter);
Py_ssize_t index = PyStackRef_UntagInt(null_or_index);
_PyFrame_SetStackPointer(frame, stack_pointer);
@@ -8238,9 +8234,7 @@
PyObject *none_val = _PyList_Extend((PyListObject *)list, iterable);
stack_pointer = _PyFrame_GetStackPointer(frame);
if (none_val == NULL) {
_PyFrame_SetStackPointer(frame, stack_pointer);
int matches = _PyErr_ExceptionMatches(tstate, PyExc_TypeError);
stack_pointer = _PyFrame_GetStackPointer(frame);
if (matches &&
(Py_TYPE(iterable)->tp_iter == NULL && !PySequence_Check(iterable)))
{
@@ -11117,7 +11111,6 @@
v = stack_pointer[-1];
null_or_index = stack_pointer[-2];
PyObject *receiver_o = PyStackRef_AsPyObjectBorrow(receiver);
PyObject *retval_o;
assert(frame->owner != FRAME_OWNED_BY_INTERPRETER);
if (!IS_PEP523_HOOKED(tstate) &&
(Py_TYPE(receiver_o) == &PyGen_Type || Py_TYPE(receiver_o) == &PyCoro_Type) &&
@@ -11136,7 +11129,7 @@
gen_frame->previous = frame;
DISPATCH_INLINED(gen_frame);
}
if (!PyStackRef_IsNull(null_or_index)) {
if (!PyStackRef_IsNull(null_or_index) && PyStackRef_IsNone(v)) {
_PyFrame_SetStackPointer(frame, stack_pointer);
_PyStackRef item = _PyForIter_VirtualIteratorNext(tstate, frame, receiver, &null_or_index);
stack_pointer = _PyFrame_GetStackPointer(frame);
@@ -11151,51 +11144,89 @@
retval = item;
}
else {
if (PyStackRef_IsNone(v) && PyIter_Check(receiver_o)) {
_PyFrame_SetStackPointer(frame, stack_pointer);
retval_o = Py_TYPE(receiver_o)->tp_iternext(receiver_o);
stack_pointer = _PyFrame_GetStackPointer(frame);
PyObject *v_o = PyStackRef_AsPyObjectBorrow(v);
_PyFrame_SetStackPointer(frame, stack_pointer);
PySendResultPair res = _PyIter_Send(receiver_o, v_o);
stack_pointer = _PyFrame_GetStackPointer(frame);
if (res.kind == PYGEN_ERROR) {
JUMP_TO_LABEL(error);
}
else {
_PyFrame_SetStackPointer(frame, stack_pointer);
retval_o = PyObject_CallMethodOneArg(receiver_o,
&_Py_ID(send),
PyStackRef_AsPyObjectBorrow(v));
stack_pointer = _PyFrame_GetStackPointer(frame);
stack_pointer += -1;
ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__);
_PyFrame_SetStackPointer(frame, stack_pointer);
PyStackRef_CLOSE(v);
stack_pointer = _PyFrame_GetStackPointer(frame);
retval = PyStackRef_FromPyObjectSteal(res.object);
if (res.kind == PYGEN_RETURN) {
JUMPBY(oparg);
}
if (retval_o == NULL) {
_PyFrame_SetStackPointer(frame, stack_pointer);
int matches = _PyErr_ExceptionMatches(tstate, PyExc_StopIteration);
stack_pointer = _PyFrame_GetStackPointer(frame);
if (matches) {
_PyFrame_SetStackPointer(frame, stack_pointer);
_PyEval_MonitorRaise(tstate, frame, this_instr);
stack_pointer = _PyFrame_GetStackPointer(frame);
}
_PyFrame_SetStackPointer(frame, stack_pointer);
int err = _PyGen_FetchStopIterationValue(&retval_o);
stack_pointer = _PyFrame_GetStackPointer(frame);
if (err == 0) {
assert(retval_o != NULL);
JUMPBY(oparg);
}
else {
stack_pointer += -1;
ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__);
_PyFrame_SetStackPointer(frame, stack_pointer);
PyStackRef_CLOSE(v);
stack_pointer = _PyFrame_GetStackPointer(frame);
JUMP_TO_LABEL(error);
}
}
retval = PyStackRef_FromPyObjectSteal(retval_o);
stack_pointer += 1;
}
stack_pointer[-2] = null_or_index;
stack_pointer[-1] = retval;
}
stack_pointer[-2] = null_or_index;
stack_pointer[-1] = retval;
DISPATCH();
}
TARGET(SEND_ASYNC_GEN) {
#if _Py_TAIL_CALL_INTERP
int opcode = SEND_ASYNC_GEN;
(void)(opcode);
#endif
_Py_CODEUNIT* const this_instr = next_instr;
(void)this_instr;
frame->instr_ptr = next_instr;
next_instr += 2;
INSTRUCTION_STATS(SEND_ASYNC_GEN);
static_assert(INLINE_CACHE_ENTRIES_SEND == 1, "incorrect cache size");
_PyStackRef iter;
_PyStackRef null_in;
_PyStackRef v;
_PyStackRef asend;
_PyStackRef null_out;
_PyStackRef retval;
/* Skip 1 cache entry */
// _GUARD_3OS_ASYNC_GEN_ASEND
{
iter = stack_pointer[-3];
PyObject *iter_o = PyStackRef_AsPyObjectBorrow(iter);
if (!PyAsyncGenASend_CheckExact(iter_o)) {
UPDATE_MISS_STATS(SEND);
assert(_PyOpcode_Deopt[opcode] == (SEND));
JUMP_TO_PREDICTED(SEND);
}
}
// _SEND_ASYNC_GEN
{
v = stack_pointer[-1];
null_in = stack_pointer[-2];
PyObject *iter_o = PyStackRef_AsPyObjectBorrow(iter);
assert(PyAsyncGenASend_CheckExact(iter_o));
PyObject *val = PyStackRef_AsPyObjectBorrow(v);
PyObject *retval_o;
_PyFrame_SetStackPointer(frame, stack_pointer);
PySendResult what = _PyAsyncGenASend_Send(iter_o, val, &retval_o);
stack_pointer = _PyFrame_GetStackPointer(frame);
if (what == PYGEN_ERROR) {
JUMP_TO_LABEL(error);
}
stack_pointer += -1;
ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__);
_PyFrame_SetStackPointer(frame, stack_pointer);
PyStackRef_CLOSE(v);
stack_pointer = _PyFrame_GetStackPointer(frame);
asend = iter;
null_out = null_in;
retval = PyStackRef_FromPyObjectSteal(retval_o);
if (what == PYGEN_RETURN) {
JUMPBY(oparg);
}
}
stack_pointer[-2] = asend;
stack_pointer[-1] = null_out;
stack_pointer[0] = retval;
stack_pointer += 1;
ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__);
DISPATCH();
}
@@ -11268,6 +11299,70 @@
DISPATCH();
}
TARGET(SEND_VIRTUAL) {
#if _Py_TAIL_CALL_INTERP
int opcode = SEND_VIRTUAL;
(void)(opcode);
#endif
_Py_CODEUNIT* const this_instr = next_instr;
(void)this_instr;
frame->instr_ptr = next_instr;
next_instr += 2;
INSTRUCTION_STATS(SEND_VIRTUAL);
static_assert(INLINE_CACHE_ENTRIES_SEND == 1, "incorrect cache size");
_PyStackRef val;
_PyStackRef nos;
_PyStackRef iter;
_PyStackRef null_or_index;
_PyStackRef none;
_PyStackRef next;
/* Skip 1 cache entry */
// _GUARD_TOS_IS_NONE
{
val = stack_pointer[-1];
if (!PyStackRef_IsNone(val)) {
UPDATE_MISS_STATS(SEND);
assert(_PyOpcode_Deopt[opcode] == (SEND));
JUMP_TO_PREDICTED(SEND);
}
}
// _GUARD_NOS_NOT_NULL
{
nos = stack_pointer[-2];
if (PyStackRef_IsNull(nos)) {
UPDATE_MISS_STATS(SEND);
assert(_PyOpcode_Deopt[opcode] == (SEND));
JUMP_TO_PREDICTED(SEND);
}
}
// _SEND_VIRTUAL
{
none = val;
null_or_index = nos;
iter = stack_pointer[-3];
PyObject *iter_o = PyStackRef_AsPyObjectBorrow(iter);
Py_ssize_t index = PyStackRef_UntagInt(null_or_index);
_PyFrame_SetStackPointer(frame, stack_pointer);
_PyObjectIndexPair next_index = Py_TYPE(iter_o)->_tp_iteritem(iter_o, index);
stack_pointer = _PyFrame_GetStackPointer(frame);
PyObject *next_o = next_index.object;
index = next_index.index;
if (next_o == NULL) {
if (index < 0) {
JUMP_TO_LABEL(error);
}
next = none;
JUMPBY(oparg);
DISPATCH();
}
next = PyStackRef_FromPyObjectSteal(next_o);
null_or_index = PyStackRef_TagInt(index);
}
stack_pointer[-2] = null_or_index;
stack_pointer[-1] = next;
DISPATCH();
}
TARGET(SETUP_ANNOTATIONS) {
#if _Py_TAIL_CALL_INTERP
int opcode = SETUP_ANNOTATIONS;
+10 -8
View File
@@ -202,7 +202,9 @@ static void *opcode_targets_table[256] = {
&&TARGET_LOAD_SUPER_ATTR_METHOD,
&&TARGET_RESUME_CHECK,
&&TARGET_RESUME_CHECK_JIT,
&&TARGET_SEND_ASYNC_GEN,
&&TARGET_SEND_GEN,
&&TARGET_SEND_VIRTUAL,
&&TARGET_STORE_ATTR_INSTANCE_VALUE,
&&TARGET_STORE_ATTR_SLOT,
&&TARGET_STORE_ATTR_WITH_HINT,
@@ -231,8 +233,6 @@ static void *opcode_targets_table[256] = {
&&_unknown_opcode,
&&_unknown_opcode,
&&_unknown_opcode,
&&_unknown_opcode,
&&_unknown_opcode,
&&TARGET_INSTRUMENTED_END_FOR,
&&TARGET_INSTRUMENTED_POP_ITER,
&&TARGET_INSTRUMENTED_END_SEND,
@@ -476,8 +476,8 @@ static void *opcode_tracing_targets_table[256] = {
&&TARGET_TRACE_RECORD,
&&TARGET_TRACE_RECORD,
&&TARGET_TRACE_RECORD,
&&_unknown_opcode,
&&_unknown_opcode,
&&TARGET_TRACE_RECORD,
&&TARGET_TRACE_RECORD,
&&_unknown_opcode,
&&_unknown_opcode,
&&_unknown_opcode,
@@ -725,7 +725,9 @@ static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_RESUME_CHECK_JIT(TAIL_CALL_PARAM
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_RETURN_GENERATOR(TAIL_CALL_PARAMS);
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_RETURN_VALUE(TAIL_CALL_PARAMS);
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_SEND(TAIL_CALL_PARAMS);
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_SEND_ASYNC_GEN(TAIL_CALL_PARAMS);
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_SEND_GEN(TAIL_CALL_PARAMS);
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_SEND_VIRTUAL(TAIL_CALL_PARAMS);
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_SETUP_ANNOTATIONS(TAIL_CALL_PARAMS);
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_SET_ADD(TAIL_CALL_PARAMS);
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_SET_FUNCTION_ATTRIBUTE(TAIL_CALL_PARAMS);
@@ -969,7 +971,9 @@ static py_tail_call_funcptr instruction_funcptr_handler_table[256] = {
[RETURN_GENERATOR] = _TAIL_CALL_RETURN_GENERATOR,
[RETURN_VALUE] = _TAIL_CALL_RETURN_VALUE,
[SEND] = _TAIL_CALL_SEND,
[SEND_ASYNC_GEN] = _TAIL_CALL_SEND_ASYNC_GEN,
[SEND_GEN] = _TAIL_CALL_SEND_GEN,
[SEND_VIRTUAL] = _TAIL_CALL_SEND_VIRTUAL,
[SETUP_ANNOTATIONS] = _TAIL_CALL_SETUP_ANNOTATIONS,
[SET_ADD] = _TAIL_CALL_SET_ADD,
[SET_FUNCTION_ATTRIBUTE] = _TAIL_CALL_SET_FUNCTION_ATTRIBUTE,
@@ -1015,8 +1019,6 @@ static py_tail_call_funcptr instruction_funcptr_handler_table[256] = {
[125] = _TAIL_CALL_UNKNOWN_OPCODE,
[126] = _TAIL_CALL_UNKNOWN_OPCODE,
[127] = _TAIL_CALL_UNKNOWN_OPCODE,
[217] = _TAIL_CALL_UNKNOWN_OPCODE,
[218] = _TAIL_CALL_UNKNOWN_OPCODE,
[219] = _TAIL_CALL_UNKNOWN_OPCODE,
[220] = _TAIL_CALL_UNKNOWN_OPCODE,
[221] = _TAIL_CALL_UNKNOWN_OPCODE,
@@ -1227,7 +1229,9 @@ static py_tail_call_funcptr instruction_funcptr_tracing_table[256] = {
[RETURN_GENERATOR] = _TAIL_CALL_TRACE_RECORD,
[RETURN_VALUE] = _TAIL_CALL_TRACE_RECORD,
[SEND] = _TAIL_CALL_TRACE_RECORD,
[SEND_ASYNC_GEN] = _TAIL_CALL_TRACE_RECORD,
[SEND_GEN] = _TAIL_CALL_TRACE_RECORD,
[SEND_VIRTUAL] = _TAIL_CALL_TRACE_RECORD,
[SETUP_ANNOTATIONS] = _TAIL_CALL_TRACE_RECORD,
[SET_ADD] = _TAIL_CALL_TRACE_RECORD,
[SET_FUNCTION_ATTRIBUTE] = _TAIL_CALL_TRACE_RECORD,
@@ -1273,8 +1277,6 @@ static py_tail_call_funcptr instruction_funcptr_tracing_table[256] = {
[125] = _TAIL_CALL_UNKNOWN_OPCODE,
[126] = _TAIL_CALL_UNKNOWN_OPCODE,
[127] = _TAIL_CALL_UNKNOWN_OPCODE,
[217] = _TAIL_CALL_UNKNOWN_OPCODE,
[218] = _TAIL_CALL_UNKNOWN_OPCODE,
[219] = _TAIL_CALL_UNKNOWN_OPCODE,
[220] = _TAIL_CALL_UNKNOWN_OPCODE,
[221] = _TAIL_CALL_UNKNOWN_OPCODE,
+8
View File
@@ -2951,3 +2951,11 @@ PyIter_Send(PyObject *iter, PyObject *arg, PyObject **result)
}
return PYGEN_ERROR;
}
PySendResultPair
_PyIter_Send(PyObject *iter, PyObject *arg)
{
PySendResultPair pair;
pair.kind = PyIter_Send(iter, arg, &pair.object);
return pair;
}
+15 -4
View File
@@ -2002,6 +2002,19 @@ async_gen_asend_send(PyObject *self, PyObject *arg)
return result;
}
PySendResult
_PyAsyncGenASend_Send(PyObject *iter, PyObject *arg, PyObject **result)
{
*result = async_gen_asend_send(iter, arg);
if (*result != NULL) {
return PYGEN_NEXT;
}
if (_PyGen_FetchStopIterationValue(result) == 0) {
return PYGEN_RETURN;
}
return PYGEN_ERROR;
}
static PyObject *
async_gen_asend_iternext(PyObject *ags)
@@ -2090,10 +2103,8 @@ static PyMethodDef async_gen_asend_methods[] = {
static PyAsyncMethods async_gen_asend_as_async = {
PyObject_SelfIter, /* am_await */
0, /* am_aiter */
0, /* am_anext */
0, /* am_send */
.am_await = PyObject_SelfIter,
.am_send = _PyAsyncGenASend_Send,
};
+124 -32
View File
@@ -1649,6 +1649,8 @@ dummy_func(
family(SEND, INLINE_CACHE_ENTRIES_SEND) = {
SEND_GEN,
SEND_VIRTUAL,
SEND_ASYNC_GEN,
};
specializing op(_SPECIALIZE_SEND, (counter/1, receiver, unused, unused -- receiver, unused, unused)) {
@@ -1663,9 +1665,8 @@ dummy_func(
#endif /* ENABLE_SPECIALIZATION */
}
op(_SEND, (receiver, null_or_index, v -- receiver, null_or_index, retval)) {
tier1 op(_SEND, (receiver, null_or_index, v -- receiver, null_or_index, retval)) {
PyObject *receiver_o = PyStackRef_AsPyObjectBorrow(receiver);
PyObject *retval_o;
assert(frame->owner != FRAME_OWNED_BY_INTERPRETER);
if (!IS_PEP523_HOOKED(tstate) &&
(Py_TYPE(receiver_o) == &PyGen_Type || Py_TYPE(receiver_o) == &PyCoro_Type) &&
@@ -1684,7 +1685,7 @@ dummy_func(
gen_frame->previous = frame;
DISPATCH_INLINED(gen_frame);
}
if (!PyStackRef_IsNull(null_or_index)) {
if (!PyStackRef_IsNull(null_or_index) && PyStackRef_IsNone(v)) {
_PyStackRef item = _PyForIter_VirtualIteratorNext(tstate, frame, receiver, &null_or_index);
if (!PyStackRef_IsValid(item)) {
if (PyStackRef_IsError(item)) {
@@ -1694,34 +1695,20 @@ dummy_func(
DISPATCH();
}
retval = item;
DEAD(v);
}
else {
if (PyStackRef_IsNone(v) && PyIter_Check(receiver_o)) {
retval_o = Py_TYPE(receiver_o)->tp_iternext(receiver_o);
PyObject *v_o = PyStackRef_AsPyObjectBorrow(v);
PySendResultPair res = _PyIter_Send(receiver_o, v_o);
if (res.kind == PYGEN_ERROR) {
ERROR_NO_POP();
}
else {
retval_o = PyObject_CallMethodOneArg(receiver_o,
&_Py_ID(send),
PyStackRef_AsPyObjectBorrow(v));
PyStackRef_CLOSE(v);
retval = PyStackRef_FromPyObjectSteal(res.object);
if (res.kind == PYGEN_RETURN) {
JUMPBY(oparg);
}
if (retval_o == NULL) {
int matches = _PyErr_ExceptionMatches(tstate, PyExc_StopIteration);
if (matches) {
_PyEval_MonitorRaise(tstate, frame, this_instr);
}
int err = _PyGen_FetchStopIterationValue(&retval_o);
if (err == 0) {
assert(retval_o != NULL);
JUMPBY(oparg);
}
else {
PyStackRef_CLOSE(v);
ERROR_IF(true);
}
}
retval = PyStackRef_FromPyObjectSteal(retval_o);
}
PyStackRef_CLOSE(v);
}
macro(SEND) = _SPECIALIZE_SEND + _SEND;
@@ -1749,6 +1736,112 @@ dummy_func(
_SEND_GEN_FRAME +
_PUSH_FRAME;
op(_GUARD_TOS_IS_NONE, (val -- val)) {
EXIT_IF(!PyStackRef_IsNone(val));
}
macro(FOR_ITER) = _SPECIALIZE_FOR_ITER + _FOR_ITER;
op(_GUARD_NOS_NOT_NULL, (nos, unused -- nos, unused)) {
EXIT_IF(PyStackRef_IsNull(nos));
}
replaced op(_SEND_VIRTUAL, (iter, null_or_index, none -- iter, null_or_index, next)) {
PyObject *iter_o = PyStackRef_AsPyObjectBorrow(iter);
Py_ssize_t index = PyStackRef_UntagInt(null_or_index);
_PyObjectIndexPair next_index = Py_TYPE(iter_o)->_tp_iteritem(iter_o, index);
PyObject *next_o = next_index.object;
index = next_index.index;
if (next_o == NULL) {
if (index < 0) {
ERROR_NO_POP();
}
next = none;
DEAD(none);
JUMPBY(oparg);
DISPATCH();
}
DEAD(none);
next = PyStackRef_FromPyObjectSteal(next_o);
null_or_index = PyStackRef_TagInt(index);
}
op(_SEND_VIRTUAL_TIER_TWO, (iter, null_or_index, none -- iter, null_or_index, next)) {
assert(PyStackRef_IsNone(none));
PyObject *iter_o = PyStackRef_AsPyObjectBorrow(iter);
Py_ssize_t index = PyStackRef_UntagInt(null_or_index);
_PyObjectIndexPair next_index = CALL_TP_ITERITEM_NO_ESCAPE(iter_o, index);
PyObject *next_o = next_index.object;
index = next_index.index;
if (next_o == NULL) {
if (index < 0) {
ERROR_NO_POP();
}
next = none;
DEAD(none);
EXIT_IF(true);
}
DEAD(none);
next = PyStackRef_FromPyObjectSteal(next_o);
null_or_index = PyStackRef_TagInt(index);
}
macro(SEND_VIRTUAL) =
unused/1 +
_GUARD_TOS_IS_NONE +
_GUARD_NOS_NOT_NULL +
_SEND_VIRTUAL;
op(_GUARD_3OS_ASYNC_GEN_ASEND, (iter, null_or_index, value -- iter, null_or_index, value)) {
PyObject *iter_o = PyStackRef_AsPyObjectBorrow(iter);
EXIT_IF(!PyAsyncGenASend_CheckExact(iter_o));
}
replaced op(_SEND_ASYNC_GEN, (iter, null_in, v -- asend, null_out, retval)) {
PyObject *iter_o = PyStackRef_AsPyObjectBorrow(iter);
assert(PyAsyncGenASend_CheckExact(iter_o));
PyObject *val = PyStackRef_AsPyObjectBorrow(v);
PyObject *retval_o;
PySendResult what = _PyAsyncGenASend_Send(iter_o, val, &retval_o);
if (what == PYGEN_ERROR) {
ERROR_NO_POP();
}
PyStackRef_CLOSE(v);
asend = iter;
DEAD(iter);
null_out = null_in;
DEAD(null_in);
retval = PyStackRef_FromPyObjectSteal(retval_o);
if (what == PYGEN_RETURN) {
JUMPBY(oparg);
}
}
macro(SEND_ASYNC_GEN) =
unused/1 +
_GUARD_3OS_ASYNC_GEN_ASEND +
_SEND_ASYNC_GEN;
tier2 op(_SEND_ASYNC_GEN_TIER_TWO, (iter, null_in, v -- asend, null_out, retval)) {
PyObject *iter_o = PyStackRef_AsPyObjectBorrow(iter);
assert(PyAsyncGenASend_CheckExact(iter_o));
PyObject *val = PyStackRef_AsPyObjectBorrow(v);
PyObject *retval_o;
PySendResult what = _PyAsyncGenASend_Send(iter_o, val, &retval_o);
if (what == PYGEN_ERROR) {
ERROR_NO_POP();
}
PyStackRef_CLOSE(v);
asend = iter;
DEAD(iter);
null_out = null_in;
DEAD(null_in);
retval = PyStackRef_FromPyObjectSteal(retval_o);
EXIT_IF(what == PYGEN_RETURN);
}
op(_YIELD_VALUE, (retval -- value)) {
// NOTE: It's important that YIELD_VALUE never raises an exception!
// The compiler treats any exception raised here as a failed close()
@@ -3803,6 +3896,10 @@ dummy_func(
EXIT_IF(Py_TYPE(iter_o)->_tp_iteritem == NULL);
}
op(_GUARD_TOS_NOT_NULL, (null_or_index -- null_or_index)) {
EXIT_IF(PyStackRef_IsNull(null_or_index));
}
replaced op(_FOR_ITER_VIRTUAL, (iter, null_or_index -- iter, null_or_index, next)) {
PyObject *iter_o = PyStackRef_AsPyObjectBorrow(iter);
Py_ssize_t index = PyStackRef_UntagInt(null_or_index);
@@ -3823,7 +3920,7 @@ dummy_func(
macro(FOR_ITER_VIRTUAL) =
unused/1 + // Skip over the counter
_GUARD_NOS_ITER_VIRTUAL +
_GUARD_TOS_NOT_NULL +
_FOR_ITER_VIRTUAL;
op(_FOR_ITER_VIRTUAL_TIER_TWO, (iter, null_or_index -- iter, null_or_index, next)) {
@@ -4606,11 +4703,6 @@ dummy_func(
EXIT_IF(!PyStackRef_IsNull(null));
}
op(_GUARD_NOS_NOT_NULL, (nos, unused -- nos, unused)) {
PyObject *o = PyStackRef_AsPyObjectBorrow(nos);
EXIT_IF(o == NULL);
}
op(_GUARD_THIRD_NULL, (null, unused, unused -- null, unused, unused)) {
EXIT_IF(!PyStackRef_IsNull(null));
}
+3
View File
@@ -640,3 +640,6 @@ gen_try_set_executing(PyGenObject *gen)
(PyLongObject *)PyStackRef_AsPyObjectBorrow(left), \
(PyLongObject *)PyStackRef_AsPyObjectBorrow(right)); \
}
#define CALL_TP_ITERITEM_NO_ESCAPE(ITER, INDEX) \
Py_TYPE(ITER)->_tp_iteritem((ITER), (INDEX))
+1 -1
View File
@@ -2156,7 +2156,7 @@ codegen_for(compiler *c, stmt_ty s)
USE_LABEL(c, cleanup);
/* It is important for instrumentation that the `END_FOR` comes first.
* Iteration over a generator will jump to the first of these instructions,
* but a non-generator will jump to a later instruction.
* but a non-generator will jump to the second instruction.
*/
ADDOP(c, NO_LOCATION, END_FOR);
ADDOP(c, NO_LOCATION, POP_ITER);
+586 -95
View File
@@ -8768,8 +8768,6 @@
break;
}
/* _SEND is not a viable micro-op for tier 2 because it uses the 'this_instr' variable */
case _SEND_GEN_FRAME_r33: {
CHECK_CURRENT_CACHED_VALUES(3);
assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE());
@@ -8816,6 +8814,511 @@
break;
}
case _GUARD_TOS_IS_NONE_r01: {
CHECK_CURRENT_CACHED_VALUES(0);
assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE());
_PyStackRef val;
val = stack_pointer[-1];
if (!PyStackRef_IsNone(val)) {
UOP_STAT_INC(uopcode, miss);
SET_CURRENT_CACHED_VALUES(0);
JUMP_TO_JUMP_TARGET();
}
_tos_cache0 = val;
SET_CURRENT_CACHED_VALUES(1);
stack_pointer += -1;
ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__);
assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE());
break;
}
case _GUARD_TOS_IS_NONE_r11: {
CHECK_CURRENT_CACHED_VALUES(1);
assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE());
_PyStackRef val;
_PyStackRef _stack_item_0 = _tos_cache0;
val = _stack_item_0;
if (!PyStackRef_IsNone(val)) {
UOP_STAT_INC(uopcode, miss);
_tos_cache0 = val;
SET_CURRENT_CACHED_VALUES(1);
JUMP_TO_JUMP_TARGET();
}
_tos_cache0 = val;
SET_CURRENT_CACHED_VALUES(1);
assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE());
break;
}
case _GUARD_TOS_IS_NONE_r22: {
CHECK_CURRENT_CACHED_VALUES(2);
assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE());
_PyStackRef val;
_PyStackRef _stack_item_0 = _tos_cache0;
_PyStackRef _stack_item_1 = _tos_cache1;
val = _stack_item_1;
if (!PyStackRef_IsNone(val)) {
UOP_STAT_INC(uopcode, miss);
_tos_cache1 = val;
_tos_cache0 = _stack_item_0;
SET_CURRENT_CACHED_VALUES(2);
JUMP_TO_JUMP_TARGET();
}
_tos_cache1 = val;
_tos_cache0 = _stack_item_0;
SET_CURRENT_CACHED_VALUES(2);
assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE());
break;
}
case _GUARD_TOS_IS_NONE_r33: {
CHECK_CURRENT_CACHED_VALUES(3);
assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE());
_PyStackRef val;
_PyStackRef _stack_item_0 = _tos_cache0;
_PyStackRef _stack_item_1 = _tos_cache1;
_PyStackRef _stack_item_2 = _tos_cache2;
val = _stack_item_2;
if (!PyStackRef_IsNone(val)) {
UOP_STAT_INC(uopcode, miss);
_tos_cache2 = val;
_tos_cache1 = _stack_item_1;
_tos_cache0 = _stack_item_0;
SET_CURRENT_CACHED_VALUES(3);
JUMP_TO_JUMP_TARGET();
}
_tos_cache2 = val;
_tos_cache1 = _stack_item_1;
_tos_cache0 = _stack_item_0;
SET_CURRENT_CACHED_VALUES(3);
assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE());
break;
}
case _GUARD_NOS_NOT_NULL_r02: {
CHECK_CURRENT_CACHED_VALUES(0);
assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE());
_PyStackRef nos;
nos = stack_pointer[-2];
if (PyStackRef_IsNull(nos)) {
UOP_STAT_INC(uopcode, miss);
SET_CURRENT_CACHED_VALUES(0);
JUMP_TO_JUMP_TARGET();
}
_tos_cache1 = stack_pointer[-1];
_tos_cache0 = nos;
SET_CURRENT_CACHED_VALUES(2);
stack_pointer += -2;
ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__);
assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE());
break;
}
case _GUARD_NOS_NOT_NULL_r12: {
CHECK_CURRENT_CACHED_VALUES(1);
assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE());
_PyStackRef nos;
_PyStackRef _stack_item_0 = _tos_cache0;
nos = stack_pointer[-1];
if (PyStackRef_IsNull(nos)) {
UOP_STAT_INC(uopcode, miss);
_tos_cache0 = _stack_item_0;
SET_CURRENT_CACHED_VALUES(1);
JUMP_TO_JUMP_TARGET();
}
_tos_cache1 = _stack_item_0;
_tos_cache0 = nos;
SET_CURRENT_CACHED_VALUES(2);
stack_pointer += -1;
ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__);
assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE());
break;
}
case _GUARD_NOS_NOT_NULL_r22: {
CHECK_CURRENT_CACHED_VALUES(2);
assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE());
_PyStackRef nos;
_PyStackRef _stack_item_0 = _tos_cache0;
_PyStackRef _stack_item_1 = _tos_cache1;
nos = _stack_item_0;
if (PyStackRef_IsNull(nos)) {
UOP_STAT_INC(uopcode, miss);
_tos_cache1 = _stack_item_1;
_tos_cache0 = nos;
SET_CURRENT_CACHED_VALUES(2);
JUMP_TO_JUMP_TARGET();
}
_tos_cache1 = _stack_item_1;
_tos_cache0 = nos;
SET_CURRENT_CACHED_VALUES(2);
assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE());
break;
}
case _GUARD_NOS_NOT_NULL_r33: {
CHECK_CURRENT_CACHED_VALUES(3);
assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE());
_PyStackRef nos;
_PyStackRef _stack_item_0 = _tos_cache0;
_PyStackRef _stack_item_1 = _tos_cache1;
_PyStackRef _stack_item_2 = _tos_cache2;
nos = _stack_item_1;
if (PyStackRef_IsNull(nos)) {
UOP_STAT_INC(uopcode, miss);
_tos_cache2 = _stack_item_2;
_tos_cache1 = nos;
_tos_cache0 = _stack_item_0;
SET_CURRENT_CACHED_VALUES(3);
JUMP_TO_JUMP_TARGET();
}
_tos_cache2 = _stack_item_2;
_tos_cache1 = nos;
_tos_cache0 = _stack_item_0;
SET_CURRENT_CACHED_VALUES(3);
assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE());
break;
}
/* _SEND_VIRTUAL is not a viable micro-op for tier 2 because it is replaced */
case _SEND_VIRTUAL_TIER_TWO_r03: {
CHECK_CURRENT_CACHED_VALUES(0);
assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE());
_PyStackRef none;
_PyStackRef null_or_index;
_PyStackRef iter;
_PyStackRef next;
none = stack_pointer[-1];
null_or_index = stack_pointer[-2];
iter = stack_pointer[-3];
assert(PyStackRef_IsNone(none));
PyObject *iter_o = PyStackRef_AsPyObjectBorrow(iter);
Py_ssize_t index = PyStackRef_UntagInt(null_or_index);
_PyObjectIndexPair next_index = CALL_TP_ITERITEM_NO_ESCAPE(iter_o, index);
PyObject *next_o = next_index.object;
index = next_index.index;
if (next_o == NULL) {
if (index < 0) {
SET_CURRENT_CACHED_VALUES(0);
JUMP_TO_ERROR();
}
next = none;
if (true) {
UOP_STAT_INC(uopcode, miss);
SET_CURRENT_CACHED_VALUES(0);
JUMP_TO_JUMP_TARGET();
}
}
next = PyStackRef_FromPyObjectSteal(next_o);
null_or_index = PyStackRef_TagInt(index);
_tos_cache2 = next;
_tos_cache1 = null_or_index;
_tos_cache0 = iter;
SET_CURRENT_CACHED_VALUES(3);
stack_pointer += -3;
ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__);
assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE());
break;
}
case _SEND_VIRTUAL_TIER_TWO_r13: {
CHECK_CURRENT_CACHED_VALUES(1);
assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE());
_PyStackRef none;
_PyStackRef null_or_index;
_PyStackRef iter;
_PyStackRef next;
_PyStackRef _stack_item_0 = _tos_cache0;
none = _stack_item_0;
null_or_index = stack_pointer[-1];
iter = stack_pointer[-2];
assert(PyStackRef_IsNone(none));
PyObject *iter_o = PyStackRef_AsPyObjectBorrow(iter);
Py_ssize_t index = PyStackRef_UntagInt(null_or_index);
_PyObjectIndexPair next_index = CALL_TP_ITERITEM_NO_ESCAPE(iter_o, index);
PyObject *next_o = next_index.object;
index = next_index.index;
if (next_o == NULL) {
if (index < 0) {
stack_pointer[0] = none;
stack_pointer += 1;
ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__);
SET_CURRENT_CACHED_VALUES(0);
JUMP_TO_ERROR();
}
next = none;
if (true) {
UOP_STAT_INC(uopcode, miss);
_tos_cache0 = stack_pointer[0];
SET_CURRENT_CACHED_VALUES(1);
JUMP_TO_JUMP_TARGET();
}
}
next = PyStackRef_FromPyObjectSteal(next_o);
null_or_index = PyStackRef_TagInt(index);
_tos_cache2 = next;
_tos_cache1 = null_or_index;
_tos_cache0 = iter;
SET_CURRENT_CACHED_VALUES(3);
stack_pointer += -2;
ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__);
assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE());
break;
}
case _SEND_VIRTUAL_TIER_TWO_r23: {
CHECK_CURRENT_CACHED_VALUES(2);
assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE());
_PyStackRef none;
_PyStackRef null_or_index;
_PyStackRef iter;
_PyStackRef next;
_PyStackRef _stack_item_0 = _tos_cache0;
_PyStackRef _stack_item_1 = _tos_cache1;
none = _stack_item_1;
null_or_index = _stack_item_0;
iter = stack_pointer[-1];
assert(PyStackRef_IsNone(none));
PyObject *iter_o = PyStackRef_AsPyObjectBorrow(iter);
Py_ssize_t index = PyStackRef_UntagInt(null_or_index);
_PyObjectIndexPair next_index = CALL_TP_ITERITEM_NO_ESCAPE(iter_o, index);
PyObject *next_o = next_index.object;
index = next_index.index;
if (next_o == NULL) {
if (index < 0) {
stack_pointer[0] = null_or_index;
stack_pointer[1] = none;
stack_pointer += 2;
ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__);
SET_CURRENT_CACHED_VALUES(0);
JUMP_TO_ERROR();
}
next = none;
if (true) {
UOP_STAT_INC(uopcode, miss);
_tos_cache1 = stack_pointer[1];
_tos_cache0 = null_or_index;
SET_CURRENT_CACHED_VALUES(2);
JUMP_TO_JUMP_TARGET();
}
}
next = PyStackRef_FromPyObjectSteal(next_o);
null_or_index = PyStackRef_TagInt(index);
_tos_cache2 = next;
_tos_cache1 = null_or_index;
_tos_cache0 = iter;
SET_CURRENT_CACHED_VALUES(3);
stack_pointer += -1;
ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__);
assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE());
break;
}
case _SEND_VIRTUAL_TIER_TWO_r33: {
CHECK_CURRENT_CACHED_VALUES(3);
assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE());
_PyStackRef none;
_PyStackRef null_or_index;
_PyStackRef iter;
_PyStackRef next;
_PyStackRef _stack_item_0 = _tos_cache0;
_PyStackRef _stack_item_1 = _tos_cache1;
_PyStackRef _stack_item_2 = _tos_cache2;
none = _stack_item_2;
null_or_index = _stack_item_1;
iter = _stack_item_0;
assert(PyStackRef_IsNone(none));
PyObject *iter_o = PyStackRef_AsPyObjectBorrow(iter);
Py_ssize_t index = PyStackRef_UntagInt(null_or_index);
_PyObjectIndexPair next_index = CALL_TP_ITERITEM_NO_ESCAPE(iter_o, index);
PyObject *next_o = next_index.object;
index = next_index.index;
if (next_o == NULL) {
if (index < 0) {
stack_pointer[0] = iter;
stack_pointer[1] = null_or_index;
stack_pointer[2] = none;
stack_pointer += 3;
ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__);
SET_CURRENT_CACHED_VALUES(0);
JUMP_TO_ERROR();
}
next = none;
if (true) {
UOP_STAT_INC(uopcode, miss);
_tos_cache2 = stack_pointer[2];
_tos_cache1 = null_or_index;
_tos_cache0 = iter;
SET_CURRENT_CACHED_VALUES(3);
JUMP_TO_JUMP_TARGET();
}
}
next = PyStackRef_FromPyObjectSteal(next_o);
null_or_index = PyStackRef_TagInt(index);
_tos_cache2 = next;
_tos_cache1 = null_or_index;
_tos_cache0 = iter;
SET_CURRENT_CACHED_VALUES(3);
assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE());
break;
}
case _GUARD_3OS_ASYNC_GEN_ASEND_r03: {
CHECK_CURRENT_CACHED_VALUES(0);
assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE());
_PyStackRef iter;
iter = stack_pointer[-3];
PyObject *iter_o = PyStackRef_AsPyObjectBorrow(iter);
if (!PyAsyncGenASend_CheckExact(iter_o)) {
UOP_STAT_INC(uopcode, miss);
SET_CURRENT_CACHED_VALUES(0);
JUMP_TO_JUMP_TARGET();
}
_tos_cache2 = stack_pointer[-1];
_tos_cache1 = stack_pointer[-2];
_tos_cache0 = iter;
SET_CURRENT_CACHED_VALUES(3);
stack_pointer += -3;
ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__);
assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE());
break;
}
case _GUARD_3OS_ASYNC_GEN_ASEND_r13: {
CHECK_CURRENT_CACHED_VALUES(1);
assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE());
_PyStackRef iter;
_PyStackRef _stack_item_0 = _tos_cache0;
iter = stack_pointer[-2];
PyObject *iter_o = PyStackRef_AsPyObjectBorrow(iter);
if (!PyAsyncGenASend_CheckExact(iter_o)) {
UOP_STAT_INC(uopcode, miss);
_tos_cache0 = _stack_item_0;
SET_CURRENT_CACHED_VALUES(1);
JUMP_TO_JUMP_TARGET();
}
_tos_cache2 = _stack_item_0;
_tos_cache1 = stack_pointer[-1];
_tos_cache0 = iter;
SET_CURRENT_CACHED_VALUES(3);
stack_pointer += -2;
ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__);
assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE());
break;
}
case _GUARD_3OS_ASYNC_GEN_ASEND_r23: {
CHECK_CURRENT_CACHED_VALUES(2);
assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE());
_PyStackRef iter;
_PyStackRef _stack_item_0 = _tos_cache0;
_PyStackRef _stack_item_1 = _tos_cache1;
iter = stack_pointer[-1];
PyObject *iter_o = PyStackRef_AsPyObjectBorrow(iter);
if (!PyAsyncGenASend_CheckExact(iter_o)) {
UOP_STAT_INC(uopcode, miss);
_tos_cache1 = _stack_item_1;
_tos_cache0 = _stack_item_0;
SET_CURRENT_CACHED_VALUES(2);
JUMP_TO_JUMP_TARGET();
}
_tos_cache2 = _stack_item_1;
_tos_cache1 = _stack_item_0;
_tos_cache0 = iter;
SET_CURRENT_CACHED_VALUES(3);
stack_pointer += -1;
ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__);
assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE());
break;
}
case _GUARD_3OS_ASYNC_GEN_ASEND_r33: {
CHECK_CURRENT_CACHED_VALUES(3);
assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE());
_PyStackRef iter;
_PyStackRef _stack_item_0 = _tos_cache0;
_PyStackRef _stack_item_1 = _tos_cache1;
_PyStackRef _stack_item_2 = _tos_cache2;
iter = _stack_item_0;
PyObject *iter_o = PyStackRef_AsPyObjectBorrow(iter);
if (!PyAsyncGenASend_CheckExact(iter_o)) {
UOP_STAT_INC(uopcode, miss);
_tos_cache2 = _stack_item_2;
_tos_cache1 = _stack_item_1;
_tos_cache0 = iter;
SET_CURRENT_CACHED_VALUES(3);
JUMP_TO_JUMP_TARGET();
}
_tos_cache2 = _stack_item_2;
_tos_cache1 = _stack_item_1;
_tos_cache0 = iter;
SET_CURRENT_CACHED_VALUES(3);
assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE());
break;
}
/* _SEND_ASYNC_GEN is not a viable micro-op for tier 2 because it is replaced */
case _SEND_ASYNC_GEN_TIER_TWO_r33: {
CHECK_CURRENT_CACHED_VALUES(3);
assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE());
_PyStackRef v;
_PyStackRef null_in;
_PyStackRef iter;
_PyStackRef asend;
_PyStackRef null_out;
_PyStackRef retval;
_PyStackRef _stack_item_0 = _tos_cache0;
_PyStackRef _stack_item_1 = _tos_cache1;
_PyStackRef _stack_item_2 = _tos_cache2;
v = _stack_item_2;
null_in = _stack_item_1;
iter = _stack_item_0;
PyObject *iter_o = PyStackRef_AsPyObjectBorrow(iter);
assert(PyAsyncGenASend_CheckExact(iter_o));
PyObject *val = PyStackRef_AsPyObjectBorrow(v);
PyObject *retval_o;
stack_pointer[0] = iter;
stack_pointer[1] = null_in;
stack_pointer[2] = v;
stack_pointer += 3;
ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__);
_PyFrame_SetStackPointer(frame, stack_pointer);
PySendResult what = _PyAsyncGenASend_Send(iter_o, val, &retval_o);
stack_pointer = _PyFrame_GetStackPointer(frame);
if (what == PYGEN_ERROR) {
SET_CURRENT_CACHED_VALUES(0);
JUMP_TO_ERROR();
}
stack_pointer += -1;
ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__);
_PyFrame_SetStackPointer(frame, stack_pointer);
PyStackRef_CLOSE(v);
stack_pointer = _PyFrame_GetStackPointer(frame);
asend = iter;
null_out = null_in;
retval = PyStackRef_FromPyObjectSteal(retval_o);
if (what == PYGEN_RETURN) {
UOP_STAT_INC(uopcode, miss);
_tos_cache2 = stack_pointer[-1];
_tos_cache1 = stack_pointer[-2];
_tos_cache0 = stack_pointer[-3];
SET_CURRENT_CACHED_VALUES(3);
stack_pointer += -3;
ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__);
JUMP_TO_JUMP_TARGET();
}
_tos_cache2 = retval;
_tos_cache1 = null_out;
_tos_cache0 = asend;
SET_CURRENT_CACHED_VALUES(3);
stack_pointer += -2;
ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__);
assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE());
break;
}
case _YIELD_VALUE_r11: {
CHECK_CURRENT_CACHED_VALUES(1);
assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE());
@@ -10320,9 +10823,7 @@
PyObject *none_val = _PyList_Extend((PyListObject *)list, iterable);
stack_pointer = _PyFrame_GetStackPointer(frame);
if (none_val == NULL) {
_PyFrame_SetStackPointer(frame, stack_pointer);
int matches = _PyErr_ExceptionMatches(tstate, PyExc_TypeError);
stack_pointer = _PyFrame_GetStackPointer(frame);
if (matches &&
(Py_TYPE(iterable)->tp_iter == NULL && !PySequence_Check(iterable)))
{
@@ -10535,9 +11036,7 @@
int err = PyDict_Update(dict_o, update_o);
stack_pointer = _PyFrame_GetStackPointer(frame);
if (err < 0) {
_PyFrame_SetStackPointer(frame, stack_pointer);
int matches = _PyErr_ExceptionMatches(tstate, PyExc_AttributeError);
stack_pointer = _PyFrame_GetStackPointer(frame);
if (matches) {
_PyFrame_SetStackPointer(frame, stack_pointer);
PyObject *exc = _PyErr_GetRaisedException(tstate);
@@ -14309,6 +14808,87 @@
break;
}
case _GUARD_TOS_NOT_NULL_r01: {
CHECK_CURRENT_CACHED_VALUES(0);
assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE());
_PyStackRef null_or_index;
null_or_index = stack_pointer[-1];
if (PyStackRef_IsNull(null_or_index)) {
UOP_STAT_INC(uopcode, miss);
SET_CURRENT_CACHED_VALUES(0);
JUMP_TO_JUMP_TARGET();
}
_tos_cache0 = null_or_index;
SET_CURRENT_CACHED_VALUES(1);
stack_pointer += -1;
ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__);
assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE());
break;
}
case _GUARD_TOS_NOT_NULL_r11: {
CHECK_CURRENT_CACHED_VALUES(1);
assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE());
_PyStackRef null_or_index;
_PyStackRef _stack_item_0 = _tos_cache0;
null_or_index = _stack_item_0;
if (PyStackRef_IsNull(null_or_index)) {
UOP_STAT_INC(uopcode, miss);
_tos_cache0 = null_or_index;
SET_CURRENT_CACHED_VALUES(1);
JUMP_TO_JUMP_TARGET();
}
_tos_cache0 = null_or_index;
SET_CURRENT_CACHED_VALUES(1);
assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE());
break;
}
case _GUARD_TOS_NOT_NULL_r22: {
CHECK_CURRENT_CACHED_VALUES(2);
assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE());
_PyStackRef null_or_index;
_PyStackRef _stack_item_0 = _tos_cache0;
_PyStackRef _stack_item_1 = _tos_cache1;
null_or_index = _stack_item_1;
if (PyStackRef_IsNull(null_or_index)) {
UOP_STAT_INC(uopcode, miss);
_tos_cache1 = null_or_index;
_tos_cache0 = _stack_item_0;
SET_CURRENT_CACHED_VALUES(2);
JUMP_TO_JUMP_TARGET();
}
_tos_cache1 = null_or_index;
_tos_cache0 = _stack_item_0;
SET_CURRENT_CACHED_VALUES(2);
assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE());
break;
}
case _GUARD_TOS_NOT_NULL_r33: {
CHECK_CURRENT_CACHED_VALUES(3);
assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE());
_PyStackRef null_or_index;
_PyStackRef _stack_item_0 = _tos_cache0;
_PyStackRef _stack_item_1 = _tos_cache1;
_PyStackRef _stack_item_2 = _tos_cache2;
null_or_index = _stack_item_2;
if (PyStackRef_IsNull(null_or_index)) {
UOP_STAT_INC(uopcode, miss);
_tos_cache2 = null_or_index;
_tos_cache1 = _stack_item_1;
_tos_cache0 = _stack_item_0;
SET_CURRENT_CACHED_VALUES(3);
JUMP_TO_JUMP_TARGET();
}
_tos_cache2 = null_or_index;
_tos_cache1 = _stack_item_1;
_tos_cache0 = _stack_item_0;
SET_CURRENT_CACHED_VALUES(3);
assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE());
break;
}
/* _FOR_ITER_VIRTUAL is not a viable micro-op for tier 2 because it is replaced */
case _FOR_ITER_VIRTUAL_TIER_TWO_r23: {
@@ -16934,95 +17514,6 @@
break;
}
case _GUARD_NOS_NOT_NULL_r02: {
CHECK_CURRENT_CACHED_VALUES(0);
assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE());
_PyStackRef nos;
nos = stack_pointer[-2];
PyObject *o = PyStackRef_AsPyObjectBorrow(nos);
if (o == NULL) {
UOP_STAT_INC(uopcode, miss);
SET_CURRENT_CACHED_VALUES(0);
JUMP_TO_JUMP_TARGET();
}
_tos_cache1 = stack_pointer[-1];
_tos_cache0 = nos;
SET_CURRENT_CACHED_VALUES(2);
stack_pointer += -2;
ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__);
assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE());
break;
}
case _GUARD_NOS_NOT_NULL_r12: {
CHECK_CURRENT_CACHED_VALUES(1);
assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE());
_PyStackRef nos;
_PyStackRef _stack_item_0 = _tos_cache0;
nos = stack_pointer[-1];
PyObject *o = PyStackRef_AsPyObjectBorrow(nos);
if (o == NULL) {
UOP_STAT_INC(uopcode, miss);
_tos_cache0 = _stack_item_0;
SET_CURRENT_CACHED_VALUES(1);
JUMP_TO_JUMP_TARGET();
}
_tos_cache1 = _stack_item_0;
_tos_cache0 = nos;
SET_CURRENT_CACHED_VALUES(2);
stack_pointer += -1;
ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__);
assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE());
break;
}
case _GUARD_NOS_NOT_NULL_r22: {
CHECK_CURRENT_CACHED_VALUES(2);
assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE());
_PyStackRef nos;
_PyStackRef _stack_item_0 = _tos_cache0;
_PyStackRef _stack_item_1 = _tos_cache1;
nos = _stack_item_0;
PyObject *o = PyStackRef_AsPyObjectBorrow(nos);
if (o == NULL) {
UOP_STAT_INC(uopcode, miss);
_tos_cache1 = _stack_item_1;
_tos_cache0 = nos;
SET_CURRENT_CACHED_VALUES(2);
JUMP_TO_JUMP_TARGET();
}
_tos_cache1 = _stack_item_1;
_tos_cache0 = nos;
SET_CURRENT_CACHED_VALUES(2);
assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE());
break;
}
case _GUARD_NOS_NOT_NULL_r33: {
CHECK_CURRENT_CACHED_VALUES(3);
assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE());
_PyStackRef nos;
_PyStackRef _stack_item_0 = _tos_cache0;
_PyStackRef _stack_item_1 = _tos_cache1;
_PyStackRef _stack_item_2 = _tos_cache2;
nos = _stack_item_1;
PyObject *o = PyStackRef_AsPyObjectBorrow(nos);
if (o == NULL) {
UOP_STAT_INC(uopcode, miss);
_tos_cache2 = _stack_item_2;
_tos_cache1 = nos;
_tos_cache0 = _stack_item_0;
SET_CURRENT_CACHED_VALUES(3);
JUMP_TO_JUMP_TARGET();
}
_tos_cache2 = _stack_item_2;
_tos_cache1 = nos;
_tos_cache0 = _stack_item_0;
SET_CURRENT_CACHED_VALUES(3);
assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE());
break;
}
case _GUARD_THIRD_NULL_r03: {
CHECK_CURRENT_CACHED_VALUES(0);
assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE());
+147 -52
View File
@@ -3782,8 +3782,7 @@
// _GUARD_NOS_NOT_NULL
{
nos = stack_pointer[-2];
PyObject *o = PyStackRef_AsPyObjectBorrow(nos);
if (o == NULL) {
if (PyStackRef_IsNull(nos)) {
UPDATE_MISS_STATS(CALL);
assert(_PyOpcode_Deopt[opcode] == (CALL));
JUMP_TO_PREDICTED(CALL);
@@ -5784,9 +5783,7 @@
int err = PyDict_Update(dict_o, update_o);
stack_pointer = _PyFrame_GetStackPointer(frame);
if (err < 0) {
_PyFrame_SetStackPointer(frame, stack_pointer);
int matches = _PyErr_ExceptionMatches(tstate, PyExc_AttributeError);
stack_pointer = _PyFrame_GetStackPointer(frame);
if (matches) {
_PyFrame_SetStackPointer(frame, stack_pointer);
PyObject *exc = _PyErr_GetRaisedException(tstate);
@@ -6407,15 +6404,14 @@
next_instr += 2;
INSTRUCTION_STATS(FOR_ITER_VIRTUAL);
static_assert(INLINE_CACHE_ENTRIES_FOR_ITER == 1, "incorrect cache size");
_PyStackRef iter;
_PyStackRef null_or_index;
_PyStackRef iter;
_PyStackRef next;
/* Skip 1 cache entry */
// _GUARD_NOS_ITER_VIRTUAL
// _GUARD_TOS_NOT_NULL
{
iter = stack_pointer[-2];
PyObject *iter_o = PyStackRef_AsPyObjectBorrow(iter);
if (Py_TYPE(iter_o)->_tp_iteritem == NULL) {
null_or_index = stack_pointer[-1];
if (PyStackRef_IsNull(null_or_index)) {
UPDATE_MISS_STATS(FOR_ITER);
assert(_PyOpcode_Deopt[opcode] == (FOR_ITER));
JUMP_TO_PREDICTED(FOR_ITER);
@@ -6423,7 +6419,7 @@
}
// _FOR_ITER_VIRTUAL
{
null_or_index = stack_pointer[-1];
iter = stack_pointer[-2];
PyObject *iter_o = PyStackRef_AsPyObjectBorrow(iter);
Py_ssize_t index = PyStackRef_UntagInt(null_or_index);
_PyFrame_SetStackPointer(frame, stack_pointer);
@@ -8237,9 +8233,7 @@
PyObject *none_val = _PyList_Extend((PyListObject *)list, iterable);
stack_pointer = _PyFrame_GetStackPointer(frame);
if (none_val == NULL) {
_PyFrame_SetStackPointer(frame, stack_pointer);
int matches = _PyErr_ExceptionMatches(tstate, PyExc_TypeError);
stack_pointer = _PyFrame_GetStackPointer(frame);
if (matches &&
(Py_TYPE(iterable)->tp_iter == NULL && !PySequence_Check(iterable)))
{
@@ -11114,7 +11108,6 @@
v = stack_pointer[-1];
null_or_index = stack_pointer[-2];
PyObject *receiver_o = PyStackRef_AsPyObjectBorrow(receiver);
PyObject *retval_o;
assert(frame->owner != FRAME_OWNED_BY_INTERPRETER);
if (!IS_PEP523_HOOKED(tstate) &&
(Py_TYPE(receiver_o) == &PyGen_Type || Py_TYPE(receiver_o) == &PyCoro_Type) &&
@@ -11133,7 +11126,7 @@
gen_frame->previous = frame;
DISPATCH_INLINED(gen_frame);
}
if (!PyStackRef_IsNull(null_or_index)) {
if (!PyStackRef_IsNull(null_or_index) && PyStackRef_IsNone(v)) {
_PyFrame_SetStackPointer(frame, stack_pointer);
_PyStackRef item = _PyForIter_VirtualIteratorNext(tstate, frame, receiver, &null_or_index);
stack_pointer = _PyFrame_GetStackPointer(frame);
@@ -11148,51 +11141,89 @@
retval = item;
}
else {
if (PyStackRef_IsNone(v) && PyIter_Check(receiver_o)) {
_PyFrame_SetStackPointer(frame, stack_pointer);
retval_o = Py_TYPE(receiver_o)->tp_iternext(receiver_o);
stack_pointer = _PyFrame_GetStackPointer(frame);
PyObject *v_o = PyStackRef_AsPyObjectBorrow(v);
_PyFrame_SetStackPointer(frame, stack_pointer);
PySendResultPair res = _PyIter_Send(receiver_o, v_o);
stack_pointer = _PyFrame_GetStackPointer(frame);
if (res.kind == PYGEN_ERROR) {
JUMP_TO_LABEL(error);
}
else {
_PyFrame_SetStackPointer(frame, stack_pointer);
retval_o = PyObject_CallMethodOneArg(receiver_o,
&_Py_ID(send),
PyStackRef_AsPyObjectBorrow(v));
stack_pointer = _PyFrame_GetStackPointer(frame);
stack_pointer += -1;
ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__);
_PyFrame_SetStackPointer(frame, stack_pointer);
PyStackRef_CLOSE(v);
stack_pointer = _PyFrame_GetStackPointer(frame);
retval = PyStackRef_FromPyObjectSteal(res.object);
if (res.kind == PYGEN_RETURN) {
JUMPBY(oparg);
}
if (retval_o == NULL) {
_PyFrame_SetStackPointer(frame, stack_pointer);
int matches = _PyErr_ExceptionMatches(tstate, PyExc_StopIteration);
stack_pointer = _PyFrame_GetStackPointer(frame);
if (matches) {
_PyFrame_SetStackPointer(frame, stack_pointer);
_PyEval_MonitorRaise(tstate, frame, this_instr);
stack_pointer = _PyFrame_GetStackPointer(frame);
}
_PyFrame_SetStackPointer(frame, stack_pointer);
int err = _PyGen_FetchStopIterationValue(&retval_o);
stack_pointer = _PyFrame_GetStackPointer(frame);
if (err == 0) {
assert(retval_o != NULL);
JUMPBY(oparg);
}
else {
stack_pointer += -1;
ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__);
_PyFrame_SetStackPointer(frame, stack_pointer);
PyStackRef_CLOSE(v);
stack_pointer = _PyFrame_GetStackPointer(frame);
JUMP_TO_LABEL(error);
}
}
retval = PyStackRef_FromPyObjectSteal(retval_o);
stack_pointer += 1;
}
stack_pointer[-2] = null_or_index;
stack_pointer[-1] = retval;
}
stack_pointer[-2] = null_or_index;
stack_pointer[-1] = retval;
DISPATCH();
}
TARGET(SEND_ASYNC_GEN) {
#if _Py_TAIL_CALL_INTERP
int opcode = SEND_ASYNC_GEN;
(void)(opcode);
#endif
_Py_CODEUNIT* const this_instr = next_instr;
(void)this_instr;
frame->instr_ptr = next_instr;
next_instr += 2;
INSTRUCTION_STATS(SEND_ASYNC_GEN);
static_assert(INLINE_CACHE_ENTRIES_SEND == 1, "incorrect cache size");
_PyStackRef iter;
_PyStackRef null_in;
_PyStackRef v;
_PyStackRef asend;
_PyStackRef null_out;
_PyStackRef retval;
/* Skip 1 cache entry */
// _GUARD_3OS_ASYNC_GEN_ASEND
{
iter = stack_pointer[-3];
PyObject *iter_o = PyStackRef_AsPyObjectBorrow(iter);
if (!PyAsyncGenASend_CheckExact(iter_o)) {
UPDATE_MISS_STATS(SEND);
assert(_PyOpcode_Deopt[opcode] == (SEND));
JUMP_TO_PREDICTED(SEND);
}
}
// _SEND_ASYNC_GEN
{
v = stack_pointer[-1];
null_in = stack_pointer[-2];
PyObject *iter_o = PyStackRef_AsPyObjectBorrow(iter);
assert(PyAsyncGenASend_CheckExact(iter_o));
PyObject *val = PyStackRef_AsPyObjectBorrow(v);
PyObject *retval_o;
_PyFrame_SetStackPointer(frame, stack_pointer);
PySendResult what = _PyAsyncGenASend_Send(iter_o, val, &retval_o);
stack_pointer = _PyFrame_GetStackPointer(frame);
if (what == PYGEN_ERROR) {
JUMP_TO_LABEL(error);
}
stack_pointer += -1;
ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__);
_PyFrame_SetStackPointer(frame, stack_pointer);
PyStackRef_CLOSE(v);
stack_pointer = _PyFrame_GetStackPointer(frame);
asend = iter;
null_out = null_in;
retval = PyStackRef_FromPyObjectSteal(retval_o);
if (what == PYGEN_RETURN) {
JUMPBY(oparg);
}
}
stack_pointer[-2] = asend;
stack_pointer[-1] = null_out;
stack_pointer[0] = retval;
stack_pointer += 1;
ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__);
DISPATCH();
}
@@ -11265,6 +11296,70 @@
DISPATCH();
}
TARGET(SEND_VIRTUAL) {
#if _Py_TAIL_CALL_INTERP
int opcode = SEND_VIRTUAL;
(void)(opcode);
#endif
_Py_CODEUNIT* const this_instr = next_instr;
(void)this_instr;
frame->instr_ptr = next_instr;
next_instr += 2;
INSTRUCTION_STATS(SEND_VIRTUAL);
static_assert(INLINE_CACHE_ENTRIES_SEND == 1, "incorrect cache size");
_PyStackRef val;
_PyStackRef nos;
_PyStackRef iter;
_PyStackRef null_or_index;
_PyStackRef none;
_PyStackRef next;
/* Skip 1 cache entry */
// _GUARD_TOS_IS_NONE
{
val = stack_pointer[-1];
if (!PyStackRef_IsNone(val)) {
UPDATE_MISS_STATS(SEND);
assert(_PyOpcode_Deopt[opcode] == (SEND));
JUMP_TO_PREDICTED(SEND);
}
}
// _GUARD_NOS_NOT_NULL
{
nos = stack_pointer[-2];
if (PyStackRef_IsNull(nos)) {
UPDATE_MISS_STATS(SEND);
assert(_PyOpcode_Deopt[opcode] == (SEND));
JUMP_TO_PREDICTED(SEND);
}
}
// _SEND_VIRTUAL
{
none = val;
null_or_index = nos;
iter = stack_pointer[-3];
PyObject *iter_o = PyStackRef_AsPyObjectBorrow(iter);
Py_ssize_t index = PyStackRef_UntagInt(null_or_index);
_PyFrame_SetStackPointer(frame, stack_pointer);
_PyObjectIndexPair next_index = Py_TYPE(iter_o)->_tp_iteritem(iter_o, index);
stack_pointer = _PyFrame_GetStackPointer(frame);
PyObject *next_o = next_index.object;
index = next_index.index;
if (next_o == NULL) {
if (index < 0) {
JUMP_TO_LABEL(error);
}
next = none;
JUMPBY(oparg);
DISPATCH();
}
next = PyStackRef_FromPyObjectSteal(next_o);
null_or_index = PyStackRef_TagInt(index);
}
stack_pointer[-2] = null_or_index;
stack_pointer[-1] = next;
DISPATCH();
}
TARGET(SETUP_ANNOTATIONS) {
#if _Py_TAIL_CALL_INTERP
int opcode = SETUP_ANNOTATIONS;
+1
View File
@@ -11,6 +11,7 @@
#include "pycore_floatobject.h"
#include "pycore_frame.h"
#include "pycore_function.h"
#include "pycore_genobject.h"
#include "pycore_import.h"
#include "pycore_interpframe.h"
#include "pycore_interpolation.h"
+10 -8
View File
@@ -202,7 +202,9 @@ static void *opcode_targets_table[256] = {
&&TARGET_LOAD_SUPER_ATTR_METHOD,
&&TARGET_RESUME_CHECK,
&&TARGET_RESUME_CHECK_JIT,
&&TARGET_SEND_ASYNC_GEN,
&&TARGET_SEND_GEN,
&&TARGET_SEND_VIRTUAL,
&&TARGET_STORE_ATTR_INSTANCE_VALUE,
&&TARGET_STORE_ATTR_SLOT,
&&TARGET_STORE_ATTR_WITH_HINT,
@@ -231,8 +233,6 @@ static void *opcode_targets_table[256] = {
&&_unknown_opcode,
&&_unknown_opcode,
&&_unknown_opcode,
&&_unknown_opcode,
&&_unknown_opcode,
&&TARGET_INSTRUMENTED_END_FOR,
&&TARGET_INSTRUMENTED_POP_ITER,
&&TARGET_INSTRUMENTED_END_SEND,
@@ -476,8 +476,8 @@ static void *opcode_tracing_targets_table[256] = {
&&TARGET_TRACE_RECORD,
&&TARGET_TRACE_RECORD,
&&TARGET_TRACE_RECORD,
&&_unknown_opcode,
&&_unknown_opcode,
&&TARGET_TRACE_RECORD,
&&TARGET_TRACE_RECORD,
&&_unknown_opcode,
&&_unknown_opcode,
&&_unknown_opcode,
@@ -725,7 +725,9 @@ static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_RESUME_CHECK_JIT(TAIL_CALL_PARAM
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_RETURN_GENERATOR(TAIL_CALL_PARAMS);
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_RETURN_VALUE(TAIL_CALL_PARAMS);
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_SEND(TAIL_CALL_PARAMS);
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_SEND_ASYNC_GEN(TAIL_CALL_PARAMS);
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_SEND_GEN(TAIL_CALL_PARAMS);
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_SEND_VIRTUAL(TAIL_CALL_PARAMS);
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_SETUP_ANNOTATIONS(TAIL_CALL_PARAMS);
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_SET_ADD(TAIL_CALL_PARAMS);
static PyObject *Py_PRESERVE_NONE_CC _TAIL_CALL_SET_FUNCTION_ATTRIBUTE(TAIL_CALL_PARAMS);
@@ -969,7 +971,9 @@ static py_tail_call_funcptr instruction_funcptr_handler_table[256] = {
[RETURN_GENERATOR] = _TAIL_CALL_RETURN_GENERATOR,
[RETURN_VALUE] = _TAIL_CALL_RETURN_VALUE,
[SEND] = _TAIL_CALL_SEND,
[SEND_ASYNC_GEN] = _TAIL_CALL_SEND_ASYNC_GEN,
[SEND_GEN] = _TAIL_CALL_SEND_GEN,
[SEND_VIRTUAL] = _TAIL_CALL_SEND_VIRTUAL,
[SETUP_ANNOTATIONS] = _TAIL_CALL_SETUP_ANNOTATIONS,
[SET_ADD] = _TAIL_CALL_SET_ADD,
[SET_FUNCTION_ATTRIBUTE] = _TAIL_CALL_SET_FUNCTION_ATTRIBUTE,
@@ -1015,8 +1019,6 @@ static py_tail_call_funcptr instruction_funcptr_handler_table[256] = {
[125] = _TAIL_CALL_UNKNOWN_OPCODE,
[126] = _TAIL_CALL_UNKNOWN_OPCODE,
[127] = _TAIL_CALL_UNKNOWN_OPCODE,
[217] = _TAIL_CALL_UNKNOWN_OPCODE,
[218] = _TAIL_CALL_UNKNOWN_OPCODE,
[219] = _TAIL_CALL_UNKNOWN_OPCODE,
[220] = _TAIL_CALL_UNKNOWN_OPCODE,
[221] = _TAIL_CALL_UNKNOWN_OPCODE,
@@ -1227,7 +1229,9 @@ static py_tail_call_funcptr instruction_funcptr_tracing_table[256] = {
[RETURN_GENERATOR] = _TAIL_CALL_TRACE_RECORD,
[RETURN_VALUE] = _TAIL_CALL_TRACE_RECORD,
[SEND] = _TAIL_CALL_TRACE_RECORD,
[SEND_ASYNC_GEN] = _TAIL_CALL_TRACE_RECORD,
[SEND_GEN] = _TAIL_CALL_TRACE_RECORD,
[SEND_VIRTUAL] = _TAIL_CALL_TRACE_RECORD,
[SETUP_ANNOTATIONS] = _TAIL_CALL_TRACE_RECORD,
[SET_ADD] = _TAIL_CALL_TRACE_RECORD,
[SET_FUNCTION_ATTRIBUTE] = _TAIL_CALL_TRACE_RECORD,
@@ -1273,8 +1277,6 @@ static py_tail_call_funcptr instruction_funcptr_tracing_table[256] = {
[125] = _TAIL_CALL_UNKNOWN_OPCODE,
[126] = _TAIL_CALL_UNKNOWN_OPCODE,
[127] = _TAIL_CALL_UNKNOWN_OPCODE,
[217] = _TAIL_CALL_UNKNOWN_OPCODE,
[218] = _TAIL_CALL_UNKNOWN_OPCODE,
[219] = _TAIL_CALL_UNKNOWN_OPCODE,
[220] = _TAIL_CALL_UNKNOWN_OPCODE,
[221] = _TAIL_CALL_UNKNOWN_OPCODE,
+10 -2
View File
@@ -500,6 +500,8 @@ _PyUOp_Replacements[MAX_UOP_ID + 1] = {
[_ITER_NEXT_LIST] = _ITER_NEXT_LIST_TIER_TWO,
[_CHECK_PERIODIC_AT_END] = _TIER2_RESUME_CHECK,
[_LOAD_BYTECODE] = _NOP,
[_SEND_VIRTUAL] = _SEND_VIRTUAL_TIER_TWO,
[_SEND_ASYNC_GEN] = _SEND_ASYNC_GEN_TIER_TWO,
};
static const uint8_t
@@ -1000,8 +1002,14 @@ _PyJit_translate_single_bytecode_to_trace(
else {
int extended_arg = orig_oparg > 255;
uint32_t jump_target = next_inst + orig_oparg + extended_arg;
assert(_Py_GetBaseCodeUnit(old_code, jump_target).op.code == END_FOR);
assert(_Py_GetBaseCodeUnit(old_code, jump_target+1).op.code == POP_ITER);
/* Jump must be to an "END" either END_FOR or END_SEND */
assert((
_Py_GetBaseCodeUnit(old_code, jump_target).op.code == END_FOR &&
_Py_GetBaseCodeUnit(old_code, jump_target+1).op.code == POP_ITER
)
||
_Py_GetBaseCodeUnit(old_code, jump_target).op.code == END_SEND
);
if (is_for_iter_test[uop]) {
target = jump_target + 1;
}
+25
View File
@@ -2701,7 +2701,32 @@ dummy_func(void) {
stack_pointer = sym_set_stack_depth((int)this_instr->operand1, stack_pointer);
}
op(_GUARD_TOS_NOT_NULL, (null_or_index -- null_or_index)) {
if (sym_is_not_null(null_or_index)) {
REPLACE_OP(this_instr, _NOP, 0, 0);
}
else {
sym_set_non_null(null_or_index);
}
}
op(_GUARD_3OS_ASYNC_GEN_ASEND, (iter, null_or_index, value -- iter, null_or_index, value)) {
if (sym_matches_type(iter, &_PyAsyncGenASend_Type)) {
REPLACE_OP(this_instr, _NOP, 0, 0);
}
else {
sym_set_type(iter, &_PyAsyncGenASend_Type);
}
}
op(_GET_ANEXT, (aiter -- aiter, awaitable)) {
if (sym_matches_type(aiter, &PyAsyncGen_Type)) {
awaitable = sym_new_type(ctx, &_PyAsyncGenASend_Type);
}
else {
awaitable = sym_new_not_null(ctx);
}
}
// END BYTECODES //
+72 -15
View File
@@ -1860,8 +1860,15 @@
}
case _GET_ANEXT: {
JitOptRef aiter;
JitOptRef awaitable;
awaitable = sym_new_not_null(ctx);
aiter = stack_pointer[-1];
if (sym_matches_type(aiter, &PyAsyncGen_Type)) {
awaitable = sym_new_type(ctx, &_PyAsyncGenASend_Type);
}
else {
awaitable = sym_new_not_null(ctx);
}
CHECK_STACK_BOUNDS(1);
stack_pointer[0] = awaitable;
stack_pointer += 1;
@@ -1876,8 +1883,6 @@
break;
}
/* _SEND is not a viable micro-op for tier 2 */
case _SEND_GEN_FRAME: {
JitOptRef v;
JitOptRef receiver;
@@ -1896,6 +1901,58 @@
break;
}
case _GUARD_TOS_IS_NONE: {
break;
}
case _GUARD_NOS_NOT_NULL: {
JitOptRef nos;
nos = stack_pointer[-2];
if (sym_is_not_null(nos)) {
ADD_OP(_NOP, 0, 0);
}
else {
sym_set_non_null(nos);
}
break;
}
/* _SEND_VIRTUAL is not a viable micro-op for tier 2 */
case _SEND_VIRTUAL_TIER_TWO: {
JitOptRef next;
next = sym_new_not_null(ctx);
stack_pointer[-1] = next;
break;
}
case _GUARD_3OS_ASYNC_GEN_ASEND: {
JitOptRef iter;
iter = stack_pointer[-3];
if (sym_matches_type(iter, &_PyAsyncGenASend_Type)) {
REPLACE_OP(this_instr, _NOP, 0, 0);
}
else {
sym_set_type(iter, &_PyAsyncGenASend_Type);
}
break;
}
/* _SEND_ASYNC_GEN is not a viable micro-op for tier 2 */
case _SEND_ASYNC_GEN_TIER_TWO: {
JitOptRef asend;
JitOptRef null_out;
JitOptRef retval;
asend = sym_new_not_null(ctx);
null_out = sym_new_not_null(ctx);
retval = sym_new_not_null(ctx);
stack_pointer[-3] = asend;
stack_pointer[-2] = null_out;
stack_pointer[-1] = retval;
break;
}
case _YIELD_VALUE: {
JitOptRef retval;
JitOptRef value;
@@ -3687,6 +3744,18 @@
break;
}
case _GUARD_TOS_NOT_NULL: {
JitOptRef null_or_index;
null_or_index = stack_pointer[-1];
if (sym_is_not_null(null_or_index)) {
REPLACE_OP(this_instr, _NOP, 0, 0);
}
else {
sym_set_non_null(null_or_index);
}
break;
}
/* _FOR_ITER_VIRTUAL is not a viable micro-op for tier 2 */
case _FOR_ITER_VIRTUAL_TIER_TWO: {
@@ -4211,18 +4280,6 @@
break;
}
case _GUARD_NOS_NOT_NULL: {
JitOptRef nos;
nos = stack_pointer[-2];
if (sym_is_not_null(nos)) {
ADD_OP(_NOP, 0, 0);
}
else {
sym_set_non_null(nos);
}
break;
}
case _GUARD_THIRD_NULL: {
JitOptRef null;
null = stack_pointer[-3];
+4 -2
View File
@@ -137,6 +137,9 @@ const _PyOpcodeRecordEntry _PyOpcode_RecordEntries[256] = {
[STORE_SUBSCR_DICT] = {1, {_RECORD_NOS_TYPE_INDEX}},
[SEND] = {1, {_RECORD_3OS_GEN_FUNC_INDEX}},
[SEND_GEN] = {1, {_RECORD_3OS_GEN_FUNC_INDEX}},
[FOR_ITER] = {1, {_RECORD_NOS_INDEX}},
[SEND_VIRTUAL] = {1, {_RECORD_3OS_GEN_FUNC_INDEX}},
[SEND_ASYNC_GEN] = {1, {_RECORD_3OS_GEN_FUNC_INDEX}},
[STORE_ATTR] = {1, {_RECORD_TOS_TYPE_INDEX}},
[LOAD_SUPER_ATTR] = {1, {_RECORD_NOS_INDEX}},
[LOAD_SUPER_ATTR_METHOD] = {1, {_RECORD_NOS_INDEX}},
@@ -155,7 +158,6 @@ const _PyOpcodeRecordEntry _PyOpcode_RecordEntries[256] = {
[GET_ITER] = {1, {_RECORD_TOS_TYPE_INDEX}},
[GET_ITER_SELF] = {1, {_RECORD_TOS_TYPE_INDEX}},
[GET_ITER_VIRTUAL] = {1, {_RECORD_TOS_TYPE_INDEX}},
[FOR_ITER] = {1, {_RECORD_NOS_INDEX}},
[FOR_ITER_VIRTUAL] = {1, {_RECORD_NOS_INDEX}},
[FOR_ITER_LIST] = {1, {_RECORD_NOS_INDEX}},
[FOR_ITER_TUPLE] = {1, {_RECORD_NOS_INDEX}},
@@ -204,6 +206,7 @@ const _PyOpcodeRecordSlotMap _PyOpcode_RecordSlotMaps[256] = {
[BINARY_OP_SUBSCR_GETITEM] = {1, 0, {0}},
[STORE_SUBSCR_DICT] = {1, 0, {0}},
[SEND_GEN] = {1, 0, {0}},
[FOR_ITER] = {1, 1, {0}},
[LOAD_SUPER_ATTR_METHOD] = {1, 0, {0}},
[LOAD_ATTR_INSTANCE_VALUE] = {1, 1, {0}},
[LOAD_ATTR_WITH_HINT] = {1, 1, {0}},
@@ -218,7 +221,6 @@ const _PyOpcodeRecordSlotMap _PyOpcode_RecordSlotMaps[256] = {
[GET_ITER] = {1, 0, {0}},
[GET_ITER_SELF] = {1, 0, {0}},
[GET_ITER_VIRTUAL] = {1, 0, {0}},
[FOR_ITER] = {1, 1, {0}},
[FOR_ITER_GEN] = {1, 1, {0}},
[LOAD_SPECIAL] = {1, 0, {0}},
[LOAD_ATTR_METHOD_WITH_VALUES] = {1, 1, {0}},
+8
View File
@@ -2761,6 +2761,14 @@ _Py_Specialize_Send(_PyStackRef receiver_st, _Py_CODEUNIT *instr)
specialize(instr, SEND_GEN);
return;
}
if (tp->_tp_iteritem != NULL) {
specialize(instr, SEND_VIRTUAL);
return;
}
if (tp == &_PyAsyncGenASend_Type) {
specialize(instr, SEND_ASYNC_GEN);
return;
}
SPECIALIZATION_FAIL(SEND,
_PySpecialization_ClassifyIterator(receiver));
failure:
+1
View File
@@ -717,6 +717,7 @@ NON_ESCAPING_FUNCTIONS = (
"_Py_GatherStats_GetIter",
"_PyStolenTuple_Free",
"PyObject_GC_UnTrack",
"_PyErr_ExceptionMatches",
)