mirror of
https://github.com/python/cpython.git
synced 2026-05-06 04:37:33 -04:00
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:
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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: \
|
||||
|
||||
Generated
+1244
-1220
File diff suppressed because it is too large
Load Diff
Generated
+115
-16
@@ -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:
|
||||
|
||||
Generated
+17
-15
@@ -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
|
||||
|
||||
Generated
+19
-15
@@ -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(
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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'),
|
||||
|
||||
Generated
+147
-52
@@ -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;
|
||||
|
||||
Generated
+10
-8
@@ -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,
|
||||
|
||||
@@ -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
@@ -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
@@ -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));
|
||||
}
|
||||
|
||||
@@ -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
@@ -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);
|
||||
|
||||
Generated
+586
-95
@@ -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());
|
||||
|
||||
Generated
+147
-52
@@ -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;
|
||||
|
||||
@@ -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"
|
||||
|
||||
Generated
+10
-8
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 //
|
||||
|
||||
|
||||
Generated
+72
-15
@@ -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];
|
||||
|
||||
Generated
+4
-2
@@ -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}},
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -717,6 +717,7 @@ NON_ESCAPING_FUNCTIONS = (
|
||||
"_Py_GatherStats_GetIter",
|
||||
"_PyStolenTuple_Free",
|
||||
"PyObject_GC_UnTrack",
|
||||
"_PyErr_ExceptionMatches",
|
||||
)
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user