mirror of
https://github.com/python/cpython.git
synced 2025-07-07 19:35:27 +00:00
GH-128682: Account for escapes in DECREF_INPUTS
(GH-129953)
* Handle escapes in DECREF_INPUTS * Mark a few more functions as escaping * Replace DECREF_INPUTS with PyStackRef_CLOSE where possible
This commit is contained in:
parent
3e222e3a15
commit
72f56654d0
18 changed files with 2228 additions and 921 deletions
|
@ -274,7 +274,7 @@ PyAPI_FUNC(PyObject *) _PyEval_ImportName(PyThreadState *, _PyInterpreterFrame *
|
|||
PyAPI_FUNC(PyObject *)_PyEval_MatchClass(PyThreadState *tstate, PyObject *subject, PyObject *type, Py_ssize_t nargs, PyObject *kwargs);
|
||||
PyAPI_FUNC(PyObject *)_PyEval_MatchKeys(PyThreadState *tstate, PyObject *map, PyObject *keys);
|
||||
PyAPI_FUNC(void) _PyEval_MonitorRaise(PyThreadState *tstate, _PyInterpreterFrame *frame, _Py_CODEUNIT *instr);
|
||||
PyAPI_FUNC(int) _PyEval_UnpackIterableStackRef(PyThreadState *tstate, _PyStackRef v, int argcnt, int argcntafter, _PyStackRef *sp);
|
||||
PyAPI_FUNC(int) _PyEval_UnpackIterableStackRef(PyThreadState *tstate, PyObject *v, int argcnt, int argcntafter, _PyStackRef *sp);
|
||||
PyAPI_FUNC(void) _PyEval_FrameClearAndPop(PyThreadState *tstate, _PyInterpreterFrame *frame);
|
||||
PyAPI_FUNC(PyObject **) _PyObjectArray_FromStackRefArray(_PyStackRef *input, Py_ssize_t nargs, PyObject **scratch);
|
||||
|
||||
|
|
32
Include/internal/pycore_opcode_metadata.h
generated
32
Include/internal/pycore_opcode_metadata.h
generated
|
@ -2001,21 +2001,21 @@ struct opcode_metadata {
|
|||
extern const struct opcode_metadata _PyOpcode_opcode_metadata[266];
|
||||
#ifdef NEED_OPCODE_METADATA
|
||||
const struct opcode_metadata _PyOpcode_opcode_metadata[266] = {
|
||||
[BINARY_OP] = { true, INSTR_FMT_IBC0000, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG },
|
||||
[BINARY_OP] = { true, INSTR_FMT_IBC0000, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG },
|
||||
[BINARY_OP_ADD_FLOAT] = { true, INSTR_FMT_IXC0000, HAS_EXIT_FLAG | HAS_ERROR_FLAG },
|
||||
[BINARY_OP_ADD_INT] = { true, INSTR_FMT_IXC0000, HAS_EXIT_FLAG | HAS_ERROR_FLAG },
|
||||
[BINARY_OP_ADD_INT] = { true, INSTR_FMT_IXC0000, HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG },
|
||||
[BINARY_OP_ADD_UNICODE] = { true, INSTR_FMT_IXC0000, HAS_EXIT_FLAG | HAS_ERROR_FLAG },
|
||||
[BINARY_OP_EXTEND] = { true, INSTR_FMT_IXC0000, HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG },
|
||||
[BINARY_OP_INPLACE_ADD_UNICODE] = { true, INSTR_FMT_IXC0000, HAS_LOCAL_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG },
|
||||
[BINARY_OP_INPLACE_ADD_UNICODE] = { true, INSTR_FMT_IXC0000, HAS_LOCAL_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG },
|
||||
[BINARY_OP_MULTIPLY_FLOAT] = { true, INSTR_FMT_IXC0000, HAS_EXIT_FLAG | HAS_ERROR_FLAG },
|
||||
[BINARY_OP_MULTIPLY_INT] = { true, INSTR_FMT_IXC0000, HAS_EXIT_FLAG | HAS_ERROR_FLAG },
|
||||
[BINARY_OP_MULTIPLY_INT] = { true, INSTR_FMT_IXC0000, HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG },
|
||||
[BINARY_OP_SUBSCR_DICT] = { true, INSTR_FMT_IXC0000, HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG },
|
||||
[BINARY_OP_SUBSCR_GETITEM] = { true, INSTR_FMT_IXC0000, HAS_DEOPT_FLAG },
|
||||
[BINARY_OP_SUBSCR_LIST_INT] = { true, INSTR_FMT_IXC0000, HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG },
|
||||
[BINARY_OP_SUBSCR_STR_INT] = { true, INSTR_FMT_IXC0000, HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG },
|
||||
[BINARY_OP_SUBSCR_TUPLE_INT] = { true, INSTR_FMT_IXC0000, HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG },
|
||||
[BINARY_OP_SUBTRACT_FLOAT] = { true, INSTR_FMT_IXC0000, HAS_EXIT_FLAG | HAS_ERROR_FLAG },
|
||||
[BINARY_OP_SUBTRACT_INT] = { true, INSTR_FMT_IXC0000, HAS_EXIT_FLAG | HAS_ERROR_FLAG },
|
||||
[BINARY_OP_SUBTRACT_INT] = { true, INSTR_FMT_IXC0000, HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG },
|
||||
[BINARY_SLICE] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG },
|
||||
[BUILD_LIST] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG },
|
||||
[BUILD_MAP] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG },
|
||||
|
@ -2053,7 +2053,7 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[266] = {
|
|||
[CALL_TUPLE_1] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG },
|
||||
[CALL_TYPE_1] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG },
|
||||
[CHECK_EG_MATCH] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG },
|
||||
[CHECK_EXC_MATCH] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG },
|
||||
[CHECK_EXC_MATCH] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG },
|
||||
[CLEANUP_THROW] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG },
|
||||
[COMPARE_OP] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG },
|
||||
[COMPARE_OP_FLOAT] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_EXIT_FLAG },
|
||||
|
@ -2075,7 +2075,7 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[266] = {
|
|||
[DICT_UPDATE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG },
|
||||
[END_ASYNC_FOR] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG },
|
||||
[END_FOR] = { true, INSTR_FMT_IX, HAS_ESCAPES_FLAG | HAS_NO_SAVE_IP_FLAG },
|
||||
[END_SEND] = { true, INSTR_FMT_IX, HAS_PURE_FLAG },
|
||||
[END_SEND] = { true, INSTR_FMT_IX, HAS_ESCAPES_FLAG | HAS_PURE_FLAG },
|
||||
[ENTER_EXECUTOR] = { true, INSTR_FMT_IB, HAS_ARG_FLAG },
|
||||
[EXIT_INIT_CHECK] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG },
|
||||
[EXTENDED_ARG] = { true, INSTR_FMT_IB, HAS_ARG_FLAG },
|
||||
|
@ -2132,8 +2132,8 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[266] = {
|
|||
[LOAD_ATTR_METHOD_NO_DICT] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_EXIT_FLAG },
|
||||
[LOAD_ATTR_METHOD_WITH_VALUES] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG },
|
||||
[LOAD_ATTR_MODULE] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG },
|
||||
[LOAD_ATTR_NONDESCRIPTOR_NO_DICT] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_EXIT_FLAG },
|
||||
[LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG },
|
||||
[LOAD_ATTR_NONDESCRIPTOR_NO_DICT] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_EXIT_FLAG | HAS_ESCAPES_FLAG },
|
||||
[LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ESCAPES_FLAG },
|
||||
[LOAD_ATTR_PROPERTY] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG },
|
||||
[LOAD_ATTR_SLOT] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG },
|
||||
[LOAD_ATTR_WITH_HINT] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG },
|
||||
|
@ -2169,12 +2169,12 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[266] = {
|
|||
[NOP] = { true, INSTR_FMT_IX, HAS_PURE_FLAG },
|
||||
[NOT_TAKEN] = { true, INSTR_FMT_IX, HAS_PURE_FLAG },
|
||||
[POP_EXCEPT] = { true, INSTR_FMT_IX, HAS_ESCAPES_FLAG },
|
||||
[POP_ITER] = { true, INSTR_FMT_IX, HAS_PURE_FLAG },
|
||||
[POP_ITER] = { true, INSTR_FMT_IX, HAS_ESCAPES_FLAG | HAS_PURE_FLAG },
|
||||
[POP_JUMP_IF_FALSE] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_JUMP_FLAG },
|
||||
[POP_JUMP_IF_NONE] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_JUMP_FLAG },
|
||||
[POP_JUMP_IF_NOT_NONE] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_JUMP_FLAG },
|
||||
[POP_JUMP_IF_TRUE] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_JUMP_FLAG },
|
||||
[POP_TOP] = { true, INSTR_FMT_IX, HAS_PURE_FLAG },
|
||||
[POP_TOP] = { true, INSTR_FMT_IX, HAS_ESCAPES_FLAG | HAS_PURE_FLAG },
|
||||
[PUSH_EXC_INFO] = { true, INSTR_FMT_IX, 0 },
|
||||
[PUSH_NULL] = { true, INSTR_FMT_IX, HAS_PURE_FLAG },
|
||||
[RAISE_VARARGS] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG },
|
||||
|
@ -2183,7 +2183,7 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[266] = {
|
|||
[RESUME] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG },
|
||||
[RESUME_CHECK] = { true, INSTR_FMT_IX, HAS_DEOPT_FLAG },
|
||||
[RETURN_GENERATOR] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG },
|
||||
[RETURN_VALUE] = { true, INSTR_FMT_IX, 0 },
|
||||
[RETURN_VALUE] = { true, INSTR_FMT_IX, HAS_ESCAPES_FLAG },
|
||||
[SEND] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_JUMP_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG },
|
||||
[SEND_GEN] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_DEOPT_FLAG },
|
||||
[SETUP_ANNOTATIONS] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG },
|
||||
|
@ -2206,12 +2206,12 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[266] = {
|
|||
[STORE_SUBSCR_LIST_INT] = { true, INSTR_FMT_IXC, HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG },
|
||||
[SWAP] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_PURE_FLAG },
|
||||
[TO_BOOL] = { true, INSTR_FMT_IXC00, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG },
|
||||
[TO_BOOL_ALWAYS_TRUE] = { true, INSTR_FMT_IXC00, HAS_EXIT_FLAG },
|
||||
[TO_BOOL_ALWAYS_TRUE] = { true, INSTR_FMT_IXC00, HAS_EXIT_FLAG | HAS_ESCAPES_FLAG },
|
||||
[TO_BOOL_BOOL] = { true, INSTR_FMT_IXC00, HAS_EXIT_FLAG },
|
||||
[TO_BOOL_INT] = { true, INSTR_FMT_IXC00, HAS_EXIT_FLAG },
|
||||
[TO_BOOL_INT] = { true, INSTR_FMT_IXC00, HAS_EXIT_FLAG | HAS_ESCAPES_FLAG },
|
||||
[TO_BOOL_LIST] = { true, INSTR_FMT_IXC00, HAS_EXIT_FLAG },
|
||||
[TO_BOOL_NONE] = { true, INSTR_FMT_IXC00, HAS_EXIT_FLAG },
|
||||
[TO_BOOL_STR] = { true, INSTR_FMT_IXC00, HAS_EXIT_FLAG },
|
||||
[TO_BOOL_STR] = { true, INSTR_FMT_IXC00, HAS_EXIT_FLAG | HAS_ESCAPES_FLAG },
|
||||
[UNARY_INVERT] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG },
|
||||
[UNARY_NEGATIVE] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG },
|
||||
[UNARY_NOT] = { true, INSTR_FMT_IX, HAS_PURE_FLAG },
|
||||
|
@ -2219,7 +2219,7 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[266] = {
|
|||
[UNPACK_SEQUENCE] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG },
|
||||
[UNPACK_SEQUENCE_LIST] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_DEOPT_FLAG },
|
||||
[UNPACK_SEQUENCE_TUPLE] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_DEOPT_FLAG },
|
||||
[UNPACK_SEQUENCE_TWO_TUPLE] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_DEOPT_FLAG },
|
||||
[UNPACK_SEQUENCE_TWO_TUPLE] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG },
|
||||
[WITH_EXCEPT_START] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG },
|
||||
[YIELD_VALUE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG },
|
||||
[JUMP] = { true, -1, HAS_ARG_FLAG | HAS_JUMP_FLAG | HAS_EVAL_BREAK_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG },
|
||||
|
|
30
Include/internal/pycore_uop_metadata.h
generated
30
Include/internal/pycore_uop_metadata.h
generated
|
@ -53,26 +53,26 @@ const uint16_t _PyUop_Flags[MAX_UOP_ID+1] = {
|
|||
[_STORE_FAST] = HAS_ARG_FLAG | HAS_LOCAL_FLAG | HAS_ESCAPES_FLAG,
|
||||
[_STORE_FAST_LOAD_FAST] = HAS_ARG_FLAG | HAS_LOCAL_FLAG | HAS_ESCAPES_FLAG,
|
||||
[_STORE_FAST_STORE_FAST] = HAS_ARG_FLAG | HAS_LOCAL_FLAG | HAS_ESCAPES_FLAG,
|
||||
[_POP_TOP] = HAS_PURE_FLAG,
|
||||
[_POP_TOP] = HAS_ESCAPES_FLAG | HAS_PURE_FLAG,
|
||||
[_PUSH_NULL] = HAS_PURE_FLAG,
|
||||
[_END_FOR] = HAS_ESCAPES_FLAG | HAS_NO_SAVE_IP_FLAG,
|
||||
[_END_SEND] = HAS_PURE_FLAG,
|
||||
[_END_SEND] = HAS_ESCAPES_FLAG | HAS_PURE_FLAG,
|
||||
[_UNARY_NEGATIVE] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG,
|
||||
[_UNARY_NOT] = HAS_PURE_FLAG,
|
||||
[_TO_BOOL] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG,
|
||||
[_TO_BOOL_BOOL] = HAS_EXIT_FLAG,
|
||||
[_TO_BOOL_INT] = HAS_EXIT_FLAG,
|
||||
[_TO_BOOL_INT] = HAS_EXIT_FLAG | HAS_ESCAPES_FLAG,
|
||||
[_TO_BOOL_LIST] = HAS_EXIT_FLAG,
|
||||
[_TO_BOOL_NONE] = HAS_EXIT_FLAG,
|
||||
[_TO_BOOL_STR] = HAS_EXIT_FLAG,
|
||||
[_REPLACE_WITH_TRUE] = 0,
|
||||
[_TO_BOOL_STR] = HAS_EXIT_FLAG | HAS_ESCAPES_FLAG,
|
||||
[_REPLACE_WITH_TRUE] = HAS_ESCAPES_FLAG,
|
||||
[_UNARY_INVERT] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG,
|
||||
[_GUARD_BOTH_INT] = HAS_EXIT_FLAG,
|
||||
[_GUARD_NOS_INT] = HAS_EXIT_FLAG,
|
||||
[_GUARD_TOS_INT] = HAS_EXIT_FLAG,
|
||||
[_BINARY_OP_MULTIPLY_INT] = HAS_ERROR_FLAG | HAS_PURE_FLAG,
|
||||
[_BINARY_OP_ADD_INT] = HAS_ERROR_FLAG | HAS_PURE_FLAG,
|
||||
[_BINARY_OP_SUBTRACT_INT] = HAS_ERROR_FLAG | HAS_PURE_FLAG,
|
||||
[_BINARY_OP_MULTIPLY_INT] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG | HAS_PURE_FLAG,
|
||||
[_BINARY_OP_ADD_INT] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG | HAS_PURE_FLAG,
|
||||
[_BINARY_OP_SUBTRACT_INT] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG | HAS_PURE_FLAG,
|
||||
[_GUARD_BOTH_FLOAT] = HAS_EXIT_FLAG,
|
||||
[_GUARD_NOS_FLOAT] = HAS_EXIT_FLAG,
|
||||
[_GUARD_TOS_FLOAT] = HAS_EXIT_FLAG,
|
||||
|
@ -81,7 +81,7 @@ const uint16_t _PyUop_Flags[MAX_UOP_ID+1] = {
|
|||
[_BINARY_OP_SUBTRACT_FLOAT] = HAS_ERROR_FLAG | HAS_PURE_FLAG,
|
||||
[_GUARD_BOTH_UNICODE] = HAS_EXIT_FLAG,
|
||||
[_BINARY_OP_ADD_UNICODE] = HAS_ERROR_FLAG | HAS_PURE_FLAG,
|
||||
[_BINARY_OP_INPLACE_ADD_UNICODE] = HAS_LOCAL_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG,
|
||||
[_BINARY_OP_INPLACE_ADD_UNICODE] = HAS_LOCAL_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG,
|
||||
[_GUARD_BINARY_OP_EXTEND] = HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG,
|
||||
[_BINARY_OP_EXTEND] = HAS_ESCAPES_FLAG | HAS_PURE_FLAG,
|
||||
[_BINARY_SLICE] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG,
|
||||
|
@ -100,7 +100,7 @@ const uint16_t _PyUop_Flags[MAX_UOP_ID+1] = {
|
|||
[_DELETE_SUBSCR] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG,
|
||||
[_CALL_INTRINSIC_1] = HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG,
|
||||
[_CALL_INTRINSIC_2] = HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG,
|
||||
[_RETURN_VALUE] = 0,
|
||||
[_RETURN_VALUE] = HAS_ESCAPES_FLAG,
|
||||
[_GET_AITER] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG,
|
||||
[_GET_ANEXT] = HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG,
|
||||
[_GET_AWAITABLE] = HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG,
|
||||
|
@ -112,7 +112,7 @@ const uint16_t _PyUop_Flags[MAX_UOP_ID+1] = {
|
|||
[_STORE_NAME] = HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG,
|
||||
[_DELETE_NAME] = HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG,
|
||||
[_UNPACK_SEQUENCE] = HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG,
|
||||
[_UNPACK_SEQUENCE_TWO_TUPLE] = HAS_ARG_FLAG | HAS_DEOPT_FLAG,
|
||||
[_UNPACK_SEQUENCE_TWO_TUPLE] = HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG,
|
||||
[_UNPACK_SEQUENCE_TUPLE] = HAS_ARG_FLAG | HAS_DEOPT_FLAG,
|
||||
[_UNPACK_SEQUENCE_LIST] = HAS_ARG_FLAG | HAS_DEOPT_FLAG,
|
||||
[_UNPACK_EX] = HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG,
|
||||
|
@ -175,7 +175,7 @@ const uint16_t _PyUop_Flags[MAX_UOP_ID+1] = {
|
|||
[_CONTAINS_OP_SET] = HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG,
|
||||
[_CONTAINS_OP_DICT] = HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG,
|
||||
[_CHECK_EG_MATCH] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG,
|
||||
[_CHECK_EXC_MATCH] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG,
|
||||
[_CHECK_EXC_MATCH] = HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG,
|
||||
[_IMPORT_NAME] = HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG,
|
||||
[_IMPORT_FROM] = HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG,
|
||||
[_IS_NONE] = 0,
|
||||
|
@ -204,8 +204,8 @@ const uint16_t _PyUop_Flags[MAX_UOP_ID+1] = {
|
|||
[_GUARD_KEYS_VERSION] = HAS_DEOPT_FLAG,
|
||||
[_LOAD_ATTR_METHOD_WITH_VALUES] = HAS_ARG_FLAG,
|
||||
[_LOAD_ATTR_METHOD_NO_DICT] = HAS_ARG_FLAG,
|
||||
[_LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES] = HAS_ARG_FLAG,
|
||||
[_LOAD_ATTR_NONDESCRIPTOR_NO_DICT] = HAS_ARG_FLAG,
|
||||
[_LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES] = HAS_ARG_FLAG | HAS_ESCAPES_FLAG,
|
||||
[_LOAD_ATTR_NONDESCRIPTOR_NO_DICT] = HAS_ARG_FLAG | HAS_ESCAPES_FLAG,
|
||||
[_CHECK_ATTR_METHOD_LAZY_DICT] = HAS_DEOPT_FLAG,
|
||||
[_LOAD_ATTR_METHOD_LAZY_DICT] = HAS_ARG_FLAG,
|
||||
[_MAYBE_EXPAND_METHOD] = HAS_ARG_FLAG | HAS_ESCAPES_FLAG,
|
||||
|
@ -261,7 +261,7 @@ const uint16_t _PyUop_Flags[MAX_UOP_ID+1] = {
|
|||
[_FORMAT_SIMPLE] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG,
|
||||
[_FORMAT_WITH_SPEC] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG,
|
||||
[_COPY] = HAS_ARG_FLAG | HAS_PURE_FLAG,
|
||||
[_BINARY_OP] = HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG,
|
||||
[_BINARY_OP] = HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG,
|
||||
[_SWAP] = HAS_ARG_FLAG | HAS_PURE_FLAG,
|
||||
[_GUARD_IS_TRUE_POP] = HAS_EXIT_FLAG,
|
||||
[_GUARD_IS_FALSE_POP] = HAS_EXIT_FLAG,
|
||||
|
|
|
@ -1723,6 +1723,7 @@ class TestGeneratedCases(unittest.TestCase):
|
|||
input = """
|
||||
inst(BALANCED, ( -- )) {
|
||||
SAVE_STACK();
|
||||
code();
|
||||
RELOAD_STACK();
|
||||
}
|
||||
"""
|
||||
|
@ -1737,12 +1738,36 @@ class TestGeneratedCases(unittest.TestCase):
|
|||
next_instr += 1;
|
||||
INSTRUCTION_STATS(BALANCED);
|
||||
_PyFrame_SetStackPointer(frame, stack_pointer);
|
||||
code();
|
||||
stack_pointer = _PyFrame_GetStackPointer(frame);
|
||||
DISPATCH();
|
||||
}
|
||||
"""
|
||||
self.run_cases_test(input, output)
|
||||
|
||||
def test_stack_save_reload_paired(self):
|
||||
|
||||
input = """
|
||||
inst(BALANCED, ( -- )) {
|
||||
SAVE_STACK();
|
||||
RELOAD_STACK();
|
||||
}
|
||||
"""
|
||||
|
||||
output = """
|
||||
TARGET(BALANCED) {
|
||||
#if defined(Py_TAIL_CALL_INTERP)
|
||||
int opcode = BALANCED;
|
||||
(void)(opcode);
|
||||
#endif
|
||||
frame->instr_ptr = next_instr;
|
||||
next_instr += 1;
|
||||
INSTRUCTION_STATS(BALANCED);
|
||||
DISPATCH();
|
||||
}
|
||||
"""
|
||||
self.run_cases_test(input, output)
|
||||
|
||||
def test_stack_reload_only(self):
|
||||
|
||||
input = """
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
The internal (evaluation) stack is now spilled to memory whenever execution
|
||||
esacpes from the interpreter or JIT compiled code. This should have no
|
||||
observable effect in either Python or builtin extensions, but will allow
|
||||
various important optimizations in the future.
|
|
@ -2994,6 +2994,11 @@ _Py_Dealloc(PyObject *op)
|
|||
destructor dealloc = type->tp_dealloc;
|
||||
#ifdef Py_DEBUG
|
||||
PyThreadState *tstate = _PyThreadState_GET();
|
||||
#ifndef Py_GIL_DISABLED
|
||||
/* This assertion doesn't hold for the free-threading build, as
|
||||
* PyStackRef_CLOSE_SPECIALIZED is not implemented */
|
||||
assert(tstate->current_frame == NULL || tstate->current_frame->stackpointer != NULL);
|
||||
#endif
|
||||
PyObject *old_exc = tstate != NULL ? tstate->current_exception : NULL;
|
||||
// Keep the old exception type alive to prevent undefined behavior
|
||||
// on (tstate->curexc_type != old_exc_type) below
|
||||
|
|
|
@ -361,7 +361,7 @@ dummy_func(
|
|||
}
|
||||
|
||||
pure inst(POP_TOP, (value --)) {
|
||||
DECREF_INPUTS();
|
||||
PyStackRef_CLOSE(value);
|
||||
}
|
||||
|
||||
pure inst(PUSH_NULL, (-- res)) {
|
||||
|
@ -388,7 +388,7 @@ dummy_func(
|
|||
ERROR_NO_POP();
|
||||
}
|
||||
}
|
||||
DECREF_INPUTS();
|
||||
PyStackRef_CLOSE(value);
|
||||
}
|
||||
|
||||
tier1 inst(INSTRUMENTED_POP_ITER, (iter -- )) {
|
||||
|
@ -400,7 +400,7 @@ dummy_func(
|
|||
(void)receiver;
|
||||
val = value;
|
||||
DEAD(value);
|
||||
DECREF_INPUTS();
|
||||
PyStackRef_CLOSE(receiver);
|
||||
}
|
||||
|
||||
tier1 inst(INSTRUMENTED_END_SEND, (receiver, value -- val)) {
|
||||
|
@ -418,7 +418,7 @@ dummy_func(
|
|||
|
||||
inst(UNARY_NEGATIVE, (value -- res)) {
|
||||
PyObject *res_o = PyNumber_Negative(PyStackRef_AsPyObjectBorrow(value));
|
||||
DECREF_INPUTS();
|
||||
PyStackRef_CLOSE(value);
|
||||
ERROR_IF(res_o == NULL, error);
|
||||
res = PyStackRef_FromPyObjectSteal(res_o);
|
||||
}
|
||||
|
@ -453,7 +453,7 @@ dummy_func(
|
|||
|
||||
op(_TO_BOOL, (value -- res)) {
|
||||
int err = PyObject_IsTrue(PyStackRef_AsPyObjectBorrow(value));
|
||||
DECREF_INPUTS();
|
||||
PyStackRef_CLOSE(value);
|
||||
ERROR_IF(err < 0, error);
|
||||
res = err ? PyStackRef_True : PyStackRef_False;
|
||||
}
|
||||
|
@ -475,7 +475,7 @@ dummy_func(
|
|||
res = PyStackRef_False;
|
||||
}
|
||||
else {
|
||||
DECREF_INPUTS();
|
||||
PyStackRef_CLOSE(value);
|
||||
res = PyStackRef_True;
|
||||
}
|
||||
}
|
||||
|
@ -507,13 +507,13 @@ dummy_func(
|
|||
}
|
||||
else {
|
||||
assert(Py_SIZE(value_o));
|
||||
DECREF_INPUTS();
|
||||
PyStackRef_CLOSE(value);
|
||||
res = PyStackRef_True;
|
||||
}
|
||||
}
|
||||
|
||||
op(_REPLACE_WITH_TRUE, (value -- res)) {
|
||||
DECREF_INPUTS();
|
||||
PyStackRef_CLOSE(value);
|
||||
res = PyStackRef_True;
|
||||
}
|
||||
|
||||
|
@ -524,7 +524,7 @@ dummy_func(
|
|||
|
||||
inst(UNARY_INVERT, (value -- res)) {
|
||||
PyObject *res_o = PyNumber_Invert(PyStackRef_AsPyObjectBorrow(value));
|
||||
DECREF_INPUTS();
|
||||
PyStackRef_CLOSE(value);
|
||||
ERROR_IF(res_o == NULL, error);
|
||||
res = PyStackRef_FromPyObjectSteal(res_o);
|
||||
}
|
||||
|
@ -721,7 +721,7 @@ dummy_func(
|
|||
// At the end we just skip over the STORE_FAST.
|
||||
op(_BINARY_OP_INPLACE_ADD_UNICODE, (left, right --)) {
|
||||
PyObject *left_o = PyStackRef_AsPyObjectBorrow(left);
|
||||
PyObject *right_o = PyStackRef_AsPyObjectBorrow(right);
|
||||
PyObject *right_o = PyStackRef_AsPyObjectSteal(right);
|
||||
assert(PyUnicode_CheckExact(left_o));
|
||||
assert(PyUnicode_CheckExact(right_o));
|
||||
|
||||
|
@ -752,8 +752,7 @@ dummy_func(
|
|||
PyObject *temp = PyStackRef_AsPyObjectSteal(*target_local);
|
||||
PyUnicode_Append(&temp, right_o);
|
||||
*target_local = PyStackRef_FromPyObjectSteal(temp);
|
||||
PyStackRef_CLOSE_SPECIALIZED(right, _PyUnicode_ExactDealloc);
|
||||
DEAD(right);
|
||||
Py_DECREF(right_o);
|
||||
ERROR_IF(PyStackRef_IsNull(*target_local), error);
|
||||
#if TIER_ONE
|
||||
// The STORE_FAST is already done. This is done here in tier one,
|
||||
|
@ -967,7 +966,7 @@ dummy_func(
|
|||
inst(SET_ADD, (set, unused[oparg-1], v -- set, unused[oparg-1])) {
|
||||
int err = PySet_Add(PyStackRef_AsPyObjectBorrow(set),
|
||||
PyStackRef_AsPyObjectBorrow(v));
|
||||
DECREF_INPUTS();
|
||||
PyStackRef_CLOSE(v);
|
||||
ERROR_IF(err, error);
|
||||
}
|
||||
|
||||
|
@ -1048,7 +1047,7 @@ dummy_func(
|
|||
inst(CALL_INTRINSIC_1, (value -- res)) {
|
||||
assert(oparg <= MAX_INTRINSIC_1);
|
||||
PyObject *res_o = _PyIntrinsics_UnaryFunctions[oparg].func(tstate, PyStackRef_AsPyObjectBorrow(value));
|
||||
DECREF_INPUTS();
|
||||
PyStackRef_CLOSE(value);
|
||||
ERROR_IF(res_o == NULL, error);
|
||||
res = PyStackRef_FromPyObjectSteal(res_o);
|
||||
}
|
||||
|
@ -1135,12 +1134,12 @@ dummy_func(
|
|||
"'async for' requires an object with "
|
||||
"__aiter__ method, got %.100s",
|
||||
type->tp_name);
|
||||
DECREF_INPUTS();
|
||||
PyStackRef_CLOSE(obj);
|
||||
ERROR_IF(true, error);
|
||||
}
|
||||
|
||||
iter_o = (*getter)(obj_o);
|
||||
DECREF_INPUTS();
|
||||
PyStackRef_CLOSE(obj);
|
||||
ERROR_IF(iter_o == NULL, error);
|
||||
|
||||
if (Py_TYPE(iter_o)->tp_as_async == NULL ||
|
||||
|
@ -1166,7 +1165,7 @@ dummy_func(
|
|||
|
||||
inst(GET_AWAITABLE, (iterable -- iter)) {
|
||||
PyObject *iter_o = _PyEval_GetAwaitable(PyStackRef_AsPyObjectBorrow(iterable), oparg);
|
||||
DECREF_INPUTS();
|
||||
PyStackRef_CLOSE(iterable);
|
||||
ERROR_IF(iter_o == NULL, error);
|
||||
iter = PyStackRef_FromPyObjectSteal(iter_o);
|
||||
}
|
||||
|
@ -1228,7 +1227,7 @@ dummy_func(
|
|||
JUMPBY(oparg);
|
||||
}
|
||||
else {
|
||||
DECREF_INPUTS();
|
||||
PyStackRef_CLOSE(v);
|
||||
ERROR_IF(true, error);
|
||||
}
|
||||
}
|
||||
|
@ -1357,7 +1356,7 @@ dummy_func(
|
|||
}
|
||||
}
|
||||
|
||||
tier1 inst(CLEANUP_THROW, (sub_iter_st, last_sent_val_st, exc_value_st -- none, value)) {
|
||||
tier1 inst(CLEANUP_THROW, (sub_iter, last_sent_val, exc_value_st -- none, value)) {
|
||||
PyObject *exc_value = PyStackRef_AsPyObjectBorrow(exc_value_st);
|
||||
#ifndef Py_TAIL_CALL_INTERP
|
||||
assert(throwflag);
|
||||
|
@ -1366,9 +1365,9 @@ dummy_func(
|
|||
|
||||
int matches = PyErr_GivenExceptionMatches(exc_value, PyExc_StopIteration);
|
||||
if (matches) {
|
||||
none = PyStackRef_None;
|
||||
value = PyStackRef_FromPyObjectNew(((PyStopIterationObject *)exc_value)->value);
|
||||
DECREF_INPUTS();
|
||||
none = PyStackRef_None;
|
||||
}
|
||||
else {
|
||||
_PyErr_SetRaisedException(tstate, Py_NewRef(exc_value));
|
||||
|
@ -1410,7 +1409,7 @@ dummy_func(
|
|||
if (ns == NULL) {
|
||||
_PyErr_Format(tstate, PyExc_SystemError,
|
||||
"no locals found when storing %R", name);
|
||||
DECREF_INPUTS();
|
||||
PyStackRef_CLOSE(v);
|
||||
ERROR_IF(true, error);
|
||||
}
|
||||
if (PyDict_CheckExact(ns)) {
|
||||
|
@ -1419,7 +1418,7 @@ dummy_func(
|
|||
else {
|
||||
err = PyObject_SetItem(ns, name, PyStackRef_AsPyObjectBorrow(v));
|
||||
}
|
||||
DECREF_INPUTS();
|
||||
PyStackRef_CLOSE(v);
|
||||
ERROR_IF(err, error);
|
||||
}
|
||||
|
||||
|
@ -1462,10 +1461,10 @@ dummy_func(
|
|||
(void)counter;
|
||||
}
|
||||
|
||||
op(_UNPACK_SEQUENCE, (seq -- output[oparg])) {
|
||||
_PyStackRef *top = output + oparg;
|
||||
int res = _PyEval_UnpackIterableStackRef(tstate, seq, oparg, -1, top);
|
||||
DECREF_INPUTS();
|
||||
op(_UNPACK_SEQUENCE, (seq -- output[oparg], top[0])) {
|
||||
PyObject *seq_o = PyStackRef_AsPyObjectSteal(seq);
|
||||
int res = _PyEval_UnpackIterableStackRef(tstate, seq_o, oparg, -1, top);
|
||||
Py_DECREF(seq_o);
|
||||
ERROR_IF(res == 0, error);
|
||||
}
|
||||
|
||||
|
@ -1479,7 +1478,7 @@ dummy_func(
|
|||
STAT_INC(UNPACK_SEQUENCE, hit);
|
||||
val0 = PyStackRef_FromPyObjectNew(PyTuple_GET_ITEM(seq_o, 0));
|
||||
val1 = PyStackRef_FromPyObjectNew(PyTuple_GET_ITEM(seq_o, 1));
|
||||
DECREF_INPUTS();
|
||||
PyStackRef_CLOSE(seq);
|
||||
}
|
||||
|
||||
inst(UNPACK_SEQUENCE_TUPLE, (unused/1, seq -- values[oparg])) {
|
||||
|
@ -1511,10 +1510,10 @@ dummy_func(
|
|||
DECREF_INPUTS();
|
||||
}
|
||||
|
||||
inst(UNPACK_EX, (seq -- left[oparg & 0xFF], unused, right[oparg >> 8])) {
|
||||
_PyStackRef *top = right + (oparg >> 8);
|
||||
int res = _PyEval_UnpackIterableStackRef(tstate, seq, oparg & 0xFF, oparg >> 8, top);
|
||||
DECREF_INPUTS();
|
||||
inst(UNPACK_EX, (seq -- left[oparg & 0xFF], unused, right[oparg >> 8], top[0])) {
|
||||
PyObject *seq_o = PyStackRef_AsPyObjectSteal(seq);
|
||||
int res = _PyEval_UnpackIterableStackRef(tstate, seq_o, oparg & 0xFF, oparg >> 8, top);
|
||||
Py_DECREF(seq_o);
|
||||
ERROR_IF(res == 0, error);
|
||||
}
|
||||
|
||||
|
@ -1550,14 +1549,14 @@ dummy_func(
|
|||
inst(DELETE_ATTR, (owner --)) {
|
||||
PyObject *name = GETITEM(FRAME_CO_NAMES, oparg);
|
||||
int err = PyObject_DelAttr(PyStackRef_AsPyObjectBorrow(owner), name);
|
||||
DECREF_INPUTS();
|
||||
PyStackRef_CLOSE(owner);
|
||||
ERROR_IF(err, error);
|
||||
}
|
||||
|
||||
inst(STORE_GLOBAL, (v --)) {
|
||||
PyObject *name = GETITEM(FRAME_CO_NAMES, oparg);
|
||||
int err = PyDict_SetItem(GLOBALS(), name, PyStackRef_AsPyObjectBorrow(v));
|
||||
DECREF_INPUTS();
|
||||
PyStackRef_CLOSE(v);
|
||||
ERROR_IF(err, error);
|
||||
}
|
||||
|
||||
|
@ -1589,7 +1588,7 @@ dummy_func(
|
|||
PyObject *name = GETITEM(FRAME_CO_NAMES, oparg);
|
||||
PyObject *v_o;
|
||||
int err = PyMapping_GetOptionalItem(PyStackRef_AsPyObjectBorrow(mod_or_class_dict), name, &v_o);
|
||||
DECREF_INPUTS();
|
||||
PyStackRef_CLOSE(mod_or_class_dict);
|
||||
ERROR_IF(err < 0, error);
|
||||
if (v_o == NULL) {
|
||||
if (PyDict_CheckExact(GLOBALS())
|
||||
|
@ -1885,17 +1884,17 @@ dummy_func(
|
|||
"Value after * must be an iterable, not %.200s",
|
||||
Py_TYPE(iterable)->tp_name);
|
||||
}
|
||||
DECREF_INPUTS();
|
||||
PyStackRef_CLOSE(iterable_st);
|
||||
ERROR_IF(true, error);
|
||||
}
|
||||
assert(Py_IsNone(none_val));
|
||||
DECREF_INPUTS();
|
||||
PyStackRef_CLOSE(iterable_st);
|
||||
}
|
||||
|
||||
inst(SET_UPDATE, (set, unused[oparg-1], iterable -- set, unused[oparg-1])) {
|
||||
int err = _PySet_Update(PyStackRef_AsPyObjectBorrow(set),
|
||||
PyStackRef_AsPyObjectBorrow(iterable));
|
||||
DECREF_INPUTS();
|
||||
PyStackRef_CLOSE(iterable);
|
||||
ERROR_IF(err < 0, error);
|
||||
}
|
||||
|
||||
|
@ -1970,10 +1969,10 @@ dummy_func(
|
|||
"'%.200s' object is not a mapping",
|
||||
Py_TYPE(update_o)->tp_name);
|
||||
}
|
||||
DECREF_INPUTS();
|
||||
PyStackRef_CLOSE(update);
|
||||
ERROR_IF(true, error);
|
||||
}
|
||||
DECREF_INPUTS();
|
||||
PyStackRef_CLOSE(update);
|
||||
}
|
||||
|
||||
inst(DICT_MERGE, (callable, unused, unused, dict, unused[oparg - 1], update -- callable, unused, unused, dict, unused[oparg - 1])) {
|
||||
|
@ -1984,10 +1983,10 @@ dummy_func(
|
|||
int err = _PyDict_MergeEx(dict_o, update_o, 2);
|
||||
if (err < 0) {
|
||||
_PyEval_FormatKwargsError(tstate, callable_o, update_o);
|
||||
DECREF_INPUTS();
|
||||
PyStackRef_CLOSE(update);
|
||||
ERROR_IF(true, error);
|
||||
}
|
||||
DECREF_INPUTS();
|
||||
PyStackRef_CLOSE(update);
|
||||
}
|
||||
|
||||
inst(MAP_ADD, (dict_st, unused[oparg - 1], key, value -- dict_st, unused[oparg - 1])) {
|
||||
|
@ -2172,7 +2171,7 @@ dummy_func(
|
|||
CALL that it's not a method call.
|
||||
meth | NULL | arg1 | ... | argN
|
||||
*/
|
||||
DECREF_INPUTS();
|
||||
PyStackRef_CLOSE(owner);
|
||||
ERROR_IF(attr_o == NULL, error);
|
||||
self_or_null[0] = PyStackRef_NULL;
|
||||
}
|
||||
|
@ -2180,13 +2179,12 @@ dummy_func(
|
|||
else {
|
||||
/* Classic, pushes one value. */
|
||||
attr_o = PyObject_GetAttr(PyStackRef_AsPyObjectBorrow(owner), name);
|
||||
DECREF_INPUTS();
|
||||
PyStackRef_CLOSE(owner);
|
||||
ERROR_IF(attr_o == NULL, error);
|
||||
}
|
||||
attr = PyStackRef_FromPyObjectSteal(attr_o);
|
||||
}
|
||||
|
||||
|
||||
macro(LOAD_ATTR) =
|
||||
_SPECIALIZE_LOAD_ATTR +
|
||||
unused/8 +
|
||||
|
@ -2736,12 +2734,11 @@ dummy_func(
|
|||
assert(PyExceptionInstance_Check(left_o));
|
||||
int err = _PyEval_CheckExceptTypeValid(tstate, right_o);
|
||||
if (err < 0) {
|
||||
DECREF_INPUTS();
|
||||
ERROR_IF(true, error);
|
||||
ERROR_NO_POP();
|
||||
}
|
||||
|
||||
int res = PyErr_GivenExceptionMatches(left_o, right_o);
|
||||
DECREF_INPUTS();
|
||||
PyStackRef_CLOSE(right);
|
||||
b = res ? PyStackRef_True : PyStackRef_False;
|
||||
}
|
||||
|
||||
|
@ -2968,7 +2965,7 @@ dummy_func(
|
|||
inst(GET_ITER, (iterable -- iter)) {
|
||||
/* before: [obj]; after [getiter(obj)] */
|
||||
PyObject *iter_o = PyObject_GetIter(PyStackRef_AsPyObjectBorrow(iterable));
|
||||
DECREF_INPUTS();
|
||||
PyStackRef_CLOSE(iterable);
|
||||
ERROR_IF(iter_o == NULL, error);
|
||||
iter = PyStackRef_FromPyObjectSteal(iter_o);
|
||||
}
|
||||
|
@ -3410,7 +3407,7 @@ dummy_func(
|
|||
assert((oparg & 1) == 0);
|
||||
STAT_INC(LOAD_ATTR, hit);
|
||||
assert(descr != NULL);
|
||||
DECREF_INPUTS();
|
||||
PyStackRef_CLOSE(owner);
|
||||
attr = PyStackRef_FromPyObjectNew(descr);
|
||||
}
|
||||
|
||||
|
@ -3426,7 +3423,7 @@ dummy_func(
|
|||
assert(Py_TYPE(PyStackRef_AsPyObjectBorrow(owner))->tp_dictoffset == 0);
|
||||
STAT_INC(LOAD_ATTR, hit);
|
||||
assert(descr != NULL);
|
||||
DECREF_INPUTS();
|
||||
PyStackRef_CLOSE(owner);
|
||||
attr = PyStackRef_FromPyObjectNew(descr);
|
||||
}
|
||||
|
||||
|
@ -4797,9 +4794,11 @@ dummy_func(
|
|||
|
||||
assert(_PyEval_BinaryOps[oparg]);
|
||||
PyObject *res_o = _PyEval_BinaryOps[oparg](lhs_o, rhs_o);
|
||||
DECREF_INPUTS();
|
||||
ERROR_IF(res_o == NULL, error);
|
||||
if (res_o == NULL) {
|
||||
ERROR_NO_POP();
|
||||
}
|
||||
res = PyStackRef_FromPyObjectSteal(res_o);
|
||||
DECREF_INPUTS();
|
||||
}
|
||||
|
||||
macro(BINARY_OP) = _SPECIALIZE_BINARY_OP + unused/4 + _BINARY_OP;
|
||||
|
@ -5267,10 +5266,12 @@ dummy_func(
|
|||
goto exit_unwind;
|
||||
}
|
||||
next_instr = frame->instr_ptr;
|
||||
|
||||
LLTRACE_RESUME_FRAME();
|
||||
|
||||
#ifdef Py_DEBUG
|
||||
int lltrace = maybe_lltrace_resume_frame(frame, GLOBALS());
|
||||
if (lltrace < 0) {
|
||||
JUMP_TO_LABEL(exit_unwind);
|
||||
}
|
||||
frame->lltrace = lltrace;
|
||||
/* _PyEval_EvalFrameDefault() must not be called with an exception set,
|
||||
because it can clear it (directly or indirectly) and so the
|
||||
caller loses its exception */
|
||||
|
|
|
@ -135,6 +135,7 @@
|
|||
static void
|
||||
dump_stack(_PyInterpreterFrame *frame, _PyStackRef *stack_pointer)
|
||||
{
|
||||
_PyFrame_SetStackPointer(frame, stack_pointer);
|
||||
_PyStackRef *stack_base = _PyFrame_Stackbase(frame);
|
||||
PyObject *exc = PyErr_GetRaisedException();
|
||||
printf(" stack=[");
|
||||
|
@ -165,6 +166,7 @@ dump_stack(_PyInterpreterFrame *frame, _PyStackRef *stack_pointer)
|
|||
printf("]\n");
|
||||
fflush(stdout);
|
||||
PyErr_SetRaisedException(exc);
|
||||
_PyFrame_GetStackPointer(frame);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -799,6 +801,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int
|
|||
#ifndef Py_TAIL_CALL_INTERP
|
||||
uint8_t opcode; /* Current opcode */
|
||||
int oparg; /* Current opcode argument, if any */
|
||||
assert(tstate->current_frame == NULL || tstate->current_frame->stackpointer != NULL);
|
||||
#endif
|
||||
_PyInterpreterFrame entry_frame;
|
||||
|
||||
|
@ -858,8 +861,8 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int
|
|||
/* Because this avoids the RESUME, we need to update instrumentation */
|
||||
_Py_Instrument(_PyFrame_GetCode(frame), tstate->interp);
|
||||
next_instr = frame->instr_ptr;
|
||||
stack_pointer = _PyFrame_GetStackPointer(frame);
|
||||
monitor_throw(tstate, frame, next_instr);
|
||||
stack_pointer = _PyFrame_GetStackPointer(frame);
|
||||
#ifdef Py_TAIL_CALL_INTERP
|
||||
return _TAIL_CALL_error(frame, stack_pointer, tstate, next_instr, 0);
|
||||
#else
|
||||
|
@ -2012,7 +2015,7 @@ _PyEval_ExceptionGroupMatch(_PyInterpreterFrame *frame, PyObject* exc_value,
|
|||
*/
|
||||
|
||||
int
|
||||
_PyEval_UnpackIterableStackRef(PyThreadState *tstate, _PyStackRef v_stackref,
|
||||
_PyEval_UnpackIterableStackRef(PyThreadState *tstate, PyObject *v,
|
||||
int argcnt, int argcntafter, _PyStackRef *sp)
|
||||
{
|
||||
int i = 0, j = 0;
|
||||
|
@ -2020,8 +2023,6 @@ _PyEval_UnpackIterableStackRef(PyThreadState *tstate, _PyStackRef v_stackref,
|
|||
PyObject *it; /* iter(v) */
|
||||
PyObject *w;
|
||||
PyObject *l = NULL; /* variable list */
|
||||
|
||||
PyObject *v = PyStackRef_AsPyObjectBorrow(v_stackref);
|
||||
assert(v != NULL);
|
||||
|
||||
it = PyObject_GetIter(v);
|
||||
|
|
|
@ -118,7 +118,9 @@
|
|||
#ifdef Py_DEBUG
|
||||
#define LLTRACE_RESUME_FRAME() \
|
||||
do { \
|
||||
_PyFrame_SetStackPointer(frame, stack_pointer); \
|
||||
int lltrace = maybe_lltrace_resume_frame(frame, GLOBALS()); \
|
||||
stack_pointer = _PyFrame_GetStackPointer(frame); \
|
||||
if (lltrace < 0) { \
|
||||
JUMP_TO_LABEL(exit_unwind); \
|
||||
} \
|
||||
|
@ -409,17 +411,21 @@ do { \
|
|||
} while (0)
|
||||
#endif
|
||||
|
||||
#define GOTO_TIER_ONE(TARGET) \
|
||||
do { \
|
||||
next_instr = (TARGET); \
|
||||
OPT_HIST(trace_uop_execution_counter, trace_run_length_hist); \
|
||||
Py_CLEAR(tstate->previous_executor); \
|
||||
if (next_instr == NULL) { \
|
||||
next_instr = frame->instr_ptr; \
|
||||
goto error; \
|
||||
} \
|
||||
DISPATCH(); \
|
||||
} while (0)
|
||||
#define GOTO_TIER_ONE(TARGET) \
|
||||
do \
|
||||
{ \
|
||||
next_instr = (TARGET); \
|
||||
OPT_HIST(trace_uop_execution_counter, trace_run_length_hist); \
|
||||
_PyFrame_SetStackPointer(frame, stack_pointer); \
|
||||
Py_CLEAR(tstate->previous_executor); \
|
||||
stack_pointer = _PyFrame_GetStackPointer(frame); \
|
||||
if (next_instr == NULL) \
|
||||
{ \
|
||||
next_instr = frame->instr_ptr; \
|
||||
goto error; \
|
||||
} \
|
||||
DISPATCH(); \
|
||||
} while (0)
|
||||
|
||||
#define CURRENT_OPARG() (next_uop[-1].oparg)
|
||||
#define CURRENT_OPERAND0() (next_uop[-1].operand0)
|
||||
|
|
1127
Python/executor_cases.c.h
generated
1127
Python/executor_cases.c.h
generated
File diff suppressed because it is too large
Load diff
|
@ -1996,6 +1996,7 @@ Py_ssize_t
|
|||
_PyGC_Collect(PyThreadState *tstate, int generation, _PyGC_Reason reason)
|
||||
{
|
||||
GCState *gcstate = &tstate->interp->gc;
|
||||
assert(tstate->current_frame == NULL || tstate->current_frame->stackpointer != NULL);
|
||||
|
||||
int expected = 0;
|
||||
if (!_Py_atomic_compare_exchange_int(&gcstate->collecting, &expected, 1)) {
|
||||
|
|
1562
Python/generated_cases.c.h
generated
1562
Python/generated_cases.c.h
generated
File diff suppressed because it is too large
Load diff
18
Python/optimizer_cases.c.h
generated
18
Python/optimizer_cases.c.h
generated
|
@ -273,14 +273,16 @@
|
|||
{
|
||||
assert(PyLong_CheckExact(sym_get_const(left)));
|
||||
assert(PyLong_CheckExact(sym_get_const(right)));
|
||||
stack_pointer += -2;
|
||||
assert(WITHIN_STACK_BOUNDS());
|
||||
PyObject *temp = _PyLong_Multiply((PyLongObject *)sym_get_const(left),
|
||||
(PyLongObject *)sym_get_const(right));
|
||||
if (temp == NULL) {
|
||||
goto error;
|
||||
}
|
||||
res = sym_new_const(ctx, temp);
|
||||
stack_pointer[-2] = res;
|
||||
stack_pointer += -1;
|
||||
stack_pointer[0] = res;
|
||||
stack_pointer += 1;
|
||||
assert(WITHIN_STACK_BOUNDS());
|
||||
Py_DECREF(temp);
|
||||
// TODO gh-115506:
|
||||
|
@ -306,14 +308,16 @@
|
|||
{
|
||||
assert(PyLong_CheckExact(sym_get_const(left)));
|
||||
assert(PyLong_CheckExact(sym_get_const(right)));
|
||||
stack_pointer += -2;
|
||||
assert(WITHIN_STACK_BOUNDS());
|
||||
PyObject *temp = _PyLong_Add((PyLongObject *)sym_get_const(left),
|
||||
(PyLongObject *)sym_get_const(right));
|
||||
if (temp == NULL) {
|
||||
goto error;
|
||||
}
|
||||
res = sym_new_const(ctx, temp);
|
||||
stack_pointer[-2] = res;
|
||||
stack_pointer += -1;
|
||||
stack_pointer[0] = res;
|
||||
stack_pointer += 1;
|
||||
assert(WITHIN_STACK_BOUNDS());
|
||||
Py_DECREF(temp);
|
||||
// TODO gh-115506:
|
||||
|
@ -339,14 +343,16 @@
|
|||
{
|
||||
assert(PyLong_CheckExact(sym_get_const(left)));
|
||||
assert(PyLong_CheckExact(sym_get_const(right)));
|
||||
stack_pointer += -2;
|
||||
assert(WITHIN_STACK_BOUNDS());
|
||||
PyObject *temp = _PyLong_Subtract((PyLongObject *)sym_get_const(left),
|
||||
(PyLongObject *)sym_get_const(right));
|
||||
if (temp == NULL) {
|
||||
goto error;
|
||||
}
|
||||
res = sym_new_const(ctx, temp);
|
||||
stack_pointer[-2] = res;
|
||||
stack_pointer += -1;
|
||||
stack_pointer[0] = res;
|
||||
stack_pointer += 1;
|
||||
assert(WITHIN_STACK_BOUNDS());
|
||||
Py_DECREF(temp);
|
||||
// TODO gh-115506:
|
||||
|
|
|
@ -602,7 +602,6 @@ NON_ESCAPING_FUNCTIONS = (
|
|||
"PyTuple_GET_ITEM",
|
||||
"PyTuple_GET_SIZE",
|
||||
"PyType_HasFeature",
|
||||
"PyUnicode_Append",
|
||||
"PyUnicode_Concat",
|
||||
"PyUnicode_GET_LENGTH",
|
||||
"PyUnicode_READ_CHAR",
|
||||
|
@ -619,7 +618,6 @@ NON_ESCAPING_FUNCTIONS = (
|
|||
"_PyCode_CODE",
|
||||
"_PyDictValues_AddToInsertionOrder",
|
||||
"_PyErr_Occurred",
|
||||
"_PyEval_FrameClearAndPop",
|
||||
"_PyFloat_FromDouble_ConsumeInputs",
|
||||
"_PyFrame_GetBytecode",
|
||||
"_PyFrame_GetCode",
|
||||
|
@ -633,15 +631,12 @@ NON_ESCAPING_FUNCTIONS = (
|
|||
"_PyList_AppendTakeRef",
|
||||
"_PyList_FromStackRefStealOnSuccess",
|
||||
"_PyList_ITEMS",
|
||||
"_PyLong_Add",
|
||||
"_PyLong_CompactValue",
|
||||
"_PyLong_DigitCount",
|
||||
"_PyLong_IsCompact",
|
||||
"_PyLong_IsNegative",
|
||||
"_PyLong_IsNonNegativeCompact",
|
||||
"_PyLong_IsZero",
|
||||
"_PyLong_Multiply",
|
||||
"_PyLong_Subtract",
|
||||
"_PyManagedDictPointer_IsValues",
|
||||
"_PyObject_GC_IS_TRACKED",
|
||||
"_PyObject_GC_MAY_BE_TRACKED",
|
||||
|
|
|
@ -15,6 +15,8 @@ class CWriter:
|
|||
self.line_directives = line_directives
|
||||
self.last_token = None
|
||||
self.newline = True
|
||||
self.pending_spill = False
|
||||
self.pending_reload = False
|
||||
|
||||
def set_position(self, tkn: Token) -> None:
|
||||
if self.last_token is not None:
|
||||
|
@ -33,6 +35,7 @@ class CWriter:
|
|||
self.newline = False
|
||||
|
||||
def emit_at(self, txt: str, where: Token) -> None:
|
||||
self.maybe_write_spill()
|
||||
self.set_position(where)
|
||||
self.out.write(txt)
|
||||
|
||||
|
@ -109,6 +112,7 @@ class CWriter:
|
|||
self.last_token = None
|
||||
|
||||
def emit(self, txt: str | Token) -> None:
|
||||
self.maybe_write_spill()
|
||||
if isinstance(txt, Token):
|
||||
self.emit_token(txt)
|
||||
elif isinstance(txt, str):
|
||||
|
@ -122,6 +126,28 @@ class CWriter:
|
|||
self.newline = True
|
||||
self.last_token = None
|
||||
|
||||
def emit_spill(self) -> None:
|
||||
if self.pending_reload:
|
||||
self.pending_reload = False
|
||||
return
|
||||
assert not self.pending_spill
|
||||
self.pending_spill = True
|
||||
|
||||
def maybe_write_spill(self) -> None:
|
||||
if self.pending_spill:
|
||||
self.pending_spill = False
|
||||
self.emit_str("_PyFrame_SetStackPointer(frame, stack_pointer);\n")
|
||||
elif self.pending_reload:
|
||||
self.pending_reload = False
|
||||
self.emit_str("stack_pointer = _PyFrame_GetStackPointer(frame);\n")
|
||||
|
||||
def emit_reload(self) -> None:
|
||||
if self.pending_spill:
|
||||
self.pending_spill = False
|
||||
return
|
||||
assert not self.pending_reload
|
||||
self.pending_reload = True
|
||||
|
||||
@contextlib.contextmanager
|
||||
def header_guard(self, name: str) -> Iterator[None]:
|
||||
self.out.write(
|
||||
|
|
|
@ -243,29 +243,13 @@ class Emitter:
|
|||
next(tkn_iter)
|
||||
next(tkn_iter)
|
||||
next(tkn_iter)
|
||||
self.out.emit_at("", tkn)
|
||||
for var in storage.inputs:
|
||||
if not var.defined:
|
||||
continue
|
||||
if var.name == "null":
|
||||
continue
|
||||
close = "PyStackRef_CLOSE"
|
||||
if "null" in var.name or var.condition and var.condition != "1":
|
||||
close = "PyStackRef_XCLOSE"
|
||||
if var.size:
|
||||
if var.size == "1":
|
||||
self.out.emit(f"{close}({var.name}[0]);\n")
|
||||
else:
|
||||
self.out.emit(f"for (int _i = {var.size}; --_i >= 0;) {{\n")
|
||||
self.out.emit(f"{close}({var.name}[_i]);\n")
|
||||
self.out.emit("}\n")
|
||||
elif var.condition:
|
||||
if var.condition != "0":
|
||||
self.out.emit(f"{close}({var.name});\n")
|
||||
else:
|
||||
self.out.emit(f"{close}({var.name});\n")
|
||||
for input in storage.inputs:
|
||||
input.defined = False
|
||||
try:
|
||||
storage.close_inputs(self.out)
|
||||
except StackError as ex:
|
||||
raise analysis_error(ex.args[0], tkn)
|
||||
except Exception as ex:
|
||||
ex.args = (ex.args[0] + str(tkn),)
|
||||
raise
|
||||
return True
|
||||
|
||||
def kill_inputs(
|
||||
|
@ -301,7 +285,9 @@ class Emitter:
|
|||
var.defined = False
|
||||
break
|
||||
else:
|
||||
raise analysis_error(f"'{name}' is not a live input-only variable", name_tkn)
|
||||
raise analysis_error(
|
||||
f"'{name}' is not a live input-only variable", name_tkn
|
||||
)
|
||||
return True
|
||||
|
||||
def stackref_kill(
|
||||
|
@ -344,7 +330,7 @@ class Emitter:
|
|||
self.out.emit(comma)
|
||||
dealloc = next(tkn_iter)
|
||||
if dealloc.kind != "IDENTIFIER":
|
||||
raise analysis_error("Expected identifier", dealloc)
|
||||
raise analysis_error("Expected identifier", dealloc)
|
||||
self.out.emit(dealloc)
|
||||
if name.kind == "IDENTIFIER":
|
||||
escapes = dealloc.text not in NON_ESCAPING_DEALLOCS
|
||||
|
@ -518,7 +504,7 @@ class Emitter:
|
|||
self.emit(next(tkn_iter))
|
||||
maybe_if = tkn_iter.peek()
|
||||
if maybe_if and maybe_if.kind == "IF":
|
||||
#Emit extra braces around the if to get scoping right
|
||||
# Emit extra braces around the if to get scoping right
|
||||
self.emit(" {\n")
|
||||
self.emit(next(tkn_iter))
|
||||
else_reachable, rbrace, else_storage = self._emit_if(tkn_iter, uop, storage, inst)
|
||||
|
|
|
@ -154,11 +154,11 @@ def write_uop(
|
|||
var.defined = False
|
||||
storage = emitter.emit_tokens(override, storage, None)
|
||||
out.start_line()
|
||||
storage.flush(out, cast_type="JitOptSymbol *")
|
||||
storage.flush(out)
|
||||
else:
|
||||
emit_default(out, uop, stack)
|
||||
out.start_line()
|
||||
stack.flush(out, cast_type="JitOptSymbol *")
|
||||
stack.flush(out)
|
||||
except StackError as ex:
|
||||
raise analysis_error(ex.args[0], prototype.body[0]) # from None
|
||||
|
||||
|
@ -201,7 +201,7 @@ def generate_abstract_interpreter(
|
|||
declare_variables(override, out, skip_inputs=False)
|
||||
else:
|
||||
declare_variables(uop, out, skip_inputs=True)
|
||||
stack = Stack(False)
|
||||
stack = Stack(extract_bits=False, cast_type="JitOptSymbol *")
|
||||
write_uop(override, uop, out, stack, debug, skip_inputs=(override is None))
|
||||
out.start_line()
|
||||
out.emit("break;\n")
|
||||
|
|
|
@ -224,12 +224,13 @@ def array_or_scalar(var: StackItem | Local) -> str:
|
|||
return "array" if var.is_array() else "scalar"
|
||||
|
||||
class Stack:
|
||||
def __init__(self, extract_bits: bool=True) -> None:
|
||||
def __init__(self, extract_bits: bool=True, cast_type: str = "uintptr_t") -> None:
|
||||
self.top_offset = StackOffset.empty()
|
||||
self.base_offset = StackOffset.empty()
|
||||
self.variables: list[Local] = []
|
||||
self.defined: set[str] = set()
|
||||
self.extract_bits = extract_bits
|
||||
self.cast_type = cast_type
|
||||
|
||||
def pop(self, var: StackItem) -> tuple[str, Local]:
|
||||
self.top_offset.pop(var)
|
||||
|
@ -298,8 +299,8 @@ class Stack:
|
|||
out: CWriter,
|
||||
var: StackItem,
|
||||
base_offset: StackOffset,
|
||||
cast_type: str = "uintptr_t",
|
||||
extract_bits: bool = True,
|
||||
cast_type: str,
|
||||
extract_bits: bool,
|
||||
) -> None:
|
||||
cast = f"({cast_type})" if var.type else ""
|
||||
bits = ".bits" if cast and extract_bits else ""
|
||||
|
@ -315,9 +316,7 @@ class Stack:
|
|||
out.emit(f"stack_pointer += {number};\n")
|
||||
out.emit("assert(WITHIN_STACK_BOUNDS());\n")
|
||||
|
||||
def flush(
|
||||
self, out: CWriter, cast_type: str = "uintptr_t"
|
||||
) -> None:
|
||||
def flush(self, out: CWriter) -> None:
|
||||
out.start_line()
|
||||
var_offset = self.base_offset.copy()
|
||||
for var in self.variables:
|
||||
|
@ -325,7 +324,7 @@ class Stack:
|
|||
var.defined and
|
||||
not var.in_memory
|
||||
):
|
||||
Stack._do_emit(out, var.item, var_offset, cast_type, self.extract_bits)
|
||||
Stack._do_emit(out, var.item, var_offset, self.cast_type, self.extract_bits)
|
||||
var.in_memory = True
|
||||
var_offset.push(var.item)
|
||||
number = self.top_offset.to_c()
|
||||
|
@ -347,7 +346,7 @@ class Stack:
|
|||
)
|
||||
|
||||
def copy(self) -> "Stack":
|
||||
other = Stack(self.extract_bits)
|
||||
other = Stack(self.extract_bits, self.cast_type)
|
||||
other.top_offset = self.top_offset.copy()
|
||||
other.base_offset = self.base_offset.copy()
|
||||
other.variables = [var.copy() for var in self.variables]
|
||||
|
@ -508,17 +507,26 @@ class Storage:
|
|||
return True
|
||||
return False
|
||||
|
||||
def flush(self, out: CWriter, cast_type: str = "uintptr_t") -> None:
|
||||
def flush(self, out: CWriter) -> None:
|
||||
self.clear_dead_inputs()
|
||||
self._push_defined_outputs()
|
||||
self.stack.flush(out, cast_type)
|
||||
self.stack.flush(out)
|
||||
|
||||
def save(self, out: CWriter) -> None:
|
||||
assert self.spilled >= 0
|
||||
if self.spilled == 0:
|
||||
self.flush(out)
|
||||
out.start_line()
|
||||
out.emit("_PyFrame_SetStackPointer(frame, stack_pointer);\n")
|
||||
out.emit_spill()
|
||||
self.spilled += 1
|
||||
|
||||
def save_inputs(self, out: CWriter) -> None:
|
||||
assert self.spilled >= 0
|
||||
if self.spilled == 0:
|
||||
self.clear_dead_inputs()
|
||||
self.stack.flush(out)
|
||||
out.start_line()
|
||||
out.emit_spill()
|
||||
self.spilled += 1
|
||||
|
||||
def reload(self, out: CWriter) -> None:
|
||||
|
@ -528,7 +536,7 @@ class Storage:
|
|||
self.spilled -= 1
|
||||
if self.spilled == 0:
|
||||
out.start_line()
|
||||
out.emit("stack_pointer = _PyFrame_GetStackPointer(frame);\n")
|
||||
out.emit_reload()
|
||||
|
||||
@staticmethod
|
||||
def for_uop(stack: Stack, uop: Uop) -> tuple[list[str], "Storage"]:
|
||||
|
@ -637,3 +645,91 @@ class Storage:
|
|||
outputs = ", ".join([var.compact_str() for var in self.outputs])
|
||||
peeks = ", ".join([var.name for var in self.peeks])
|
||||
return f"{stack_comment[:-2]}{next_line}inputs: {inputs}{next_line}outputs: {outputs}{next_line}peeks: {peeks} */"
|
||||
|
||||
def close_inputs(self, out: CWriter) -> None:
|
||||
tmp_defined = False
|
||||
def close_named(close: str, name: str, overwrite: str) -> None:
|
||||
nonlocal tmp_defined
|
||||
if overwrite:
|
||||
if not tmp_defined:
|
||||
out.emit("_PyStackRef ")
|
||||
tmp_defined = True
|
||||
out.emit(f"tmp = {name};\n")
|
||||
out.emit(f"{name} = {overwrite};\n")
|
||||
if not var.is_array():
|
||||
var.in_memory = False
|
||||
self.flush(out)
|
||||
out.emit(f"{close}(tmp);\n")
|
||||
else:
|
||||
out.emit(f"{close}({name});\n")
|
||||
|
||||
def close_variable(var: Local, overwrite: str) -> None:
|
||||
nonlocal tmp_defined
|
||||
close = "PyStackRef_CLOSE"
|
||||
if "null" in var.name or var.condition and var.condition != "1":
|
||||
close = "PyStackRef_XCLOSE"
|
||||
if var.size:
|
||||
if var.size == "1":
|
||||
close_named(close, f"{var.name}[0]", overwrite)
|
||||
else:
|
||||
if overwrite and not tmp_defined:
|
||||
out.emit("_PyStackRef tmp;\n")
|
||||
tmp_defined = True
|
||||
out.emit(f"for (int _i = {var.size}; --_i >= 0;) {{\n")
|
||||
close_named(close, f"{var.name}[_i]", overwrite)
|
||||
out.emit("}\n")
|
||||
else:
|
||||
if var.condition and var.condition == "0":
|
||||
return
|
||||
close_named(close, var.name, overwrite)
|
||||
|
||||
self.clear_dead_inputs()
|
||||
if not self.inputs:
|
||||
return
|
||||
output: Local | None = None
|
||||
for var in self.outputs:
|
||||
if var.is_array():
|
||||
if len(self.inputs) > 1:
|
||||
raise StackError("Cannot call DECREF_INPUTS with multiple live input(s) and array output")
|
||||
elif var.defined:
|
||||
if output is not None:
|
||||
raise StackError("Cannot call DECREF_INPUTS with more than one live output")
|
||||
output = var
|
||||
self.save_inputs(out)
|
||||
if output is not None:
|
||||
lowest = self.inputs[0]
|
||||
if lowest.is_array():
|
||||
try:
|
||||
size = int(lowest.size)
|
||||
except:
|
||||
size = -1
|
||||
if size <= 0:
|
||||
raise StackError("Cannot call DECREF_INPUTS with non fixed size array as lowest input on stack")
|
||||
if size > 1:
|
||||
raise StackError("Cannot call DECREF_INPUTS with array size > 1 as lowest input on stack")
|
||||
output.defined = False
|
||||
close_variable(lowest, output.name)
|
||||
else:
|
||||
lowest.in_memory = False
|
||||
output.defined = False
|
||||
close_variable(lowest, output.name)
|
||||
to_close = self.inputs[: 0 if output is not None else None: -1]
|
||||
if len(to_close) == 1 and not to_close[0].is_array():
|
||||
self.reload(out)
|
||||
to_close[0].defined = False
|
||||
self.flush(out)
|
||||
self.save_inputs(out)
|
||||
close_variable(to_close[0], "")
|
||||
self.reload(out)
|
||||
else:
|
||||
for var in to_close:
|
||||
assert var.defined or var.is_array()
|
||||
close_variable(var, "PyStackRef_NULL")
|
||||
self.reload(out)
|
||||
for var in self.inputs:
|
||||
var.defined = False
|
||||
if output is not None:
|
||||
output.defined = True
|
||||
# MyPy false positive
|
||||
lowest.defined = False # type: ignore[possibly-undefined]
|
||||
self.flush(out)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue