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:
Mark Shannon 2025-02-12 17:44:59 +00:00 committed by GitHub
parent 3e222e3a15
commit 72f56654d0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
18 changed files with 2228 additions and 921 deletions

View file

@ -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_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(PyObject *)_PyEval_MatchKeys(PyThreadState *tstate, PyObject *map, PyObject *keys);
PyAPI_FUNC(void) _PyEval_MonitorRaise(PyThreadState *tstate, _PyInterpreterFrame *frame, _Py_CODEUNIT *instr); 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(void) _PyEval_FrameClearAndPop(PyThreadState *tstate, _PyInterpreterFrame *frame);
PyAPI_FUNC(PyObject **) _PyObjectArray_FromStackRefArray(_PyStackRef *input, Py_ssize_t nargs, PyObject **scratch); PyAPI_FUNC(PyObject **) _PyObjectArray_FromStackRefArray(_PyStackRef *input, Py_ssize_t nargs, PyObject **scratch);

View file

@ -2001,21 +2001,21 @@ struct opcode_metadata {
extern const struct opcode_metadata _PyOpcode_opcode_metadata[266]; extern const struct opcode_metadata _PyOpcode_opcode_metadata[266];
#ifdef NEED_OPCODE_METADATA #ifdef NEED_OPCODE_METADATA
const struct opcode_metadata _PyOpcode_opcode_metadata[266] = { 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_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_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_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_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_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_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_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_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_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_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 }, [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_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 }, [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_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 }, [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_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 }, [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] = { 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 }, [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 }, [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_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_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 }, [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 }, [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 }, [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_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_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_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_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 }, [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_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_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 }, [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 }, [NOP] = { true, INSTR_FMT_IX, HAS_PURE_FLAG },
[NOT_TAKEN] = { 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_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_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_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_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_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_EXC_INFO] = { true, INSTR_FMT_IX, 0 },
[PUSH_NULL] = { true, INSTR_FMT_IX, HAS_PURE_FLAG }, [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 }, [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] = { 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 }, [RESUME_CHECK] = { true, INSTR_FMT_IX, HAS_DEOPT_FLAG },
[RETURN_GENERATOR] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_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] = { 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 }, [SEND_GEN] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_DEOPT_FLAG },
[SETUP_ANNOTATIONS] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_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 }, [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 }, [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] = { 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_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_LIST] = { true, INSTR_FMT_IXC00, HAS_EXIT_FLAG },
[TO_BOOL_NONE] = { 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_INVERT] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG },
[UNARY_NEGATIVE] = { 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 }, [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] = { 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_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_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 }, [WITH_EXCEPT_START] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG },
[YIELD_VALUE] = { true, INSTR_FMT_IB, HAS_ARG_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 }, [JUMP] = { true, -1, HAS_ARG_FLAG | HAS_JUMP_FLAG | HAS_EVAL_BREAK_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG },

View file

@ -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] = HAS_ARG_FLAG | HAS_LOCAL_FLAG | HAS_ESCAPES_FLAG,
[_STORE_FAST_LOAD_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, [_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, [_PUSH_NULL] = HAS_PURE_FLAG,
[_END_FOR] = HAS_ESCAPES_FLAG | HAS_NO_SAVE_IP_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_NEGATIVE] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG,
[_UNARY_NOT] = HAS_PURE_FLAG, [_UNARY_NOT] = HAS_PURE_FLAG,
[_TO_BOOL] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, [_TO_BOOL] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG,
[_TO_BOOL_BOOL] = HAS_EXIT_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_LIST] = HAS_EXIT_FLAG,
[_TO_BOOL_NONE] = HAS_EXIT_FLAG, [_TO_BOOL_NONE] = HAS_EXIT_FLAG,
[_TO_BOOL_STR] = HAS_EXIT_FLAG, [_TO_BOOL_STR] = HAS_EXIT_FLAG | HAS_ESCAPES_FLAG,
[_REPLACE_WITH_TRUE] = 0, [_REPLACE_WITH_TRUE] = HAS_ESCAPES_FLAG,
[_UNARY_INVERT] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, [_UNARY_INVERT] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG,
[_GUARD_BOTH_INT] = HAS_EXIT_FLAG, [_GUARD_BOTH_INT] = HAS_EXIT_FLAG,
[_GUARD_NOS_INT] = HAS_EXIT_FLAG, [_GUARD_NOS_INT] = HAS_EXIT_FLAG,
[_GUARD_TOS_INT] = HAS_EXIT_FLAG, [_GUARD_TOS_INT] = HAS_EXIT_FLAG,
[_BINARY_OP_MULTIPLY_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_PURE_FLAG, [_BINARY_OP_ADD_INT] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG | HAS_PURE_FLAG,
[_BINARY_OP_SUBTRACT_INT] = HAS_ERROR_FLAG | HAS_PURE_FLAG, [_BINARY_OP_SUBTRACT_INT] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG | HAS_PURE_FLAG,
[_GUARD_BOTH_FLOAT] = HAS_EXIT_FLAG, [_GUARD_BOTH_FLOAT] = HAS_EXIT_FLAG,
[_GUARD_NOS_FLOAT] = HAS_EXIT_FLAG, [_GUARD_NOS_FLOAT] = HAS_EXIT_FLAG,
[_GUARD_TOS_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, [_BINARY_OP_SUBTRACT_FLOAT] = HAS_ERROR_FLAG | HAS_PURE_FLAG,
[_GUARD_BOTH_UNICODE] = HAS_EXIT_FLAG, [_GUARD_BOTH_UNICODE] = HAS_EXIT_FLAG,
[_BINARY_OP_ADD_UNICODE] = HAS_ERROR_FLAG | HAS_PURE_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, [_GUARD_BINARY_OP_EXTEND] = HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG,
[_BINARY_OP_EXTEND] = HAS_ESCAPES_FLAG | HAS_PURE_FLAG, [_BINARY_OP_EXTEND] = HAS_ESCAPES_FLAG | HAS_PURE_FLAG,
[_BINARY_SLICE] = HAS_ERROR_FLAG | HAS_ESCAPES_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, [_DELETE_SUBSCR] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG,
[_CALL_INTRINSIC_1] = HAS_ARG_FLAG | 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, [_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_AITER] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG,
[_GET_ANEXT] = HAS_ERROR_FLAG | HAS_ERROR_NO_POP_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, [_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, [_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, [_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] = 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_TUPLE] = HAS_ARG_FLAG | HAS_DEOPT_FLAG,
[_UNPACK_SEQUENCE_LIST] = 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, [_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_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, [_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_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_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, [_IMPORT_FROM] = HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG,
[_IS_NONE] = 0, [_IS_NONE] = 0,
@ -204,8 +204,8 @@ const uint16_t _PyUop_Flags[MAX_UOP_ID+1] = {
[_GUARD_KEYS_VERSION] = HAS_DEOPT_FLAG, [_GUARD_KEYS_VERSION] = HAS_DEOPT_FLAG,
[_LOAD_ATTR_METHOD_WITH_VALUES] = HAS_ARG_FLAG, [_LOAD_ATTR_METHOD_WITH_VALUES] = HAS_ARG_FLAG,
[_LOAD_ATTR_METHOD_NO_DICT] = HAS_ARG_FLAG, [_LOAD_ATTR_METHOD_NO_DICT] = HAS_ARG_FLAG,
[_LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES] = HAS_ARG_FLAG, [_LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES] = HAS_ARG_FLAG | HAS_ESCAPES_FLAG,
[_LOAD_ATTR_NONDESCRIPTOR_NO_DICT] = HAS_ARG_FLAG, [_LOAD_ATTR_NONDESCRIPTOR_NO_DICT] = HAS_ARG_FLAG | HAS_ESCAPES_FLAG,
[_CHECK_ATTR_METHOD_LAZY_DICT] = HAS_DEOPT_FLAG, [_CHECK_ATTR_METHOD_LAZY_DICT] = HAS_DEOPT_FLAG,
[_LOAD_ATTR_METHOD_LAZY_DICT] = HAS_ARG_FLAG, [_LOAD_ATTR_METHOD_LAZY_DICT] = HAS_ARG_FLAG,
[_MAYBE_EXPAND_METHOD] = HAS_ARG_FLAG | HAS_ESCAPES_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_SIMPLE] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG,
[_FORMAT_WITH_SPEC] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, [_FORMAT_WITH_SPEC] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG,
[_COPY] = HAS_ARG_FLAG | HAS_PURE_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, [_SWAP] = HAS_ARG_FLAG | HAS_PURE_FLAG,
[_GUARD_IS_TRUE_POP] = HAS_EXIT_FLAG, [_GUARD_IS_TRUE_POP] = HAS_EXIT_FLAG,
[_GUARD_IS_FALSE_POP] = HAS_EXIT_FLAG, [_GUARD_IS_FALSE_POP] = HAS_EXIT_FLAG,

View file

@ -1723,6 +1723,7 @@ class TestGeneratedCases(unittest.TestCase):
input = """ input = """
inst(BALANCED, ( -- )) { inst(BALANCED, ( -- )) {
SAVE_STACK(); SAVE_STACK();
code();
RELOAD_STACK(); RELOAD_STACK();
} }
""" """
@ -1737,12 +1738,36 @@ class TestGeneratedCases(unittest.TestCase):
next_instr += 1; next_instr += 1;
INSTRUCTION_STATS(BALANCED); INSTRUCTION_STATS(BALANCED);
_PyFrame_SetStackPointer(frame, stack_pointer); _PyFrame_SetStackPointer(frame, stack_pointer);
code();
stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer = _PyFrame_GetStackPointer(frame);
DISPATCH(); DISPATCH();
} }
""" """
self.run_cases_test(input, output) 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): def test_stack_reload_only(self):
input = """ input = """

View file

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

View file

@ -2994,6 +2994,11 @@ _Py_Dealloc(PyObject *op)
destructor dealloc = type->tp_dealloc; destructor dealloc = type->tp_dealloc;
#ifdef Py_DEBUG #ifdef Py_DEBUG
PyThreadState *tstate = _PyThreadState_GET(); 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; PyObject *old_exc = tstate != NULL ? tstate->current_exception : NULL;
// Keep the old exception type alive to prevent undefined behavior // Keep the old exception type alive to prevent undefined behavior
// on (tstate->curexc_type != old_exc_type) below // on (tstate->curexc_type != old_exc_type) below

View file

@ -361,7 +361,7 @@ dummy_func(
} }
pure inst(POP_TOP, (value --)) { pure inst(POP_TOP, (value --)) {
DECREF_INPUTS(); PyStackRef_CLOSE(value);
} }
pure inst(PUSH_NULL, (-- res)) { pure inst(PUSH_NULL, (-- res)) {
@ -388,7 +388,7 @@ dummy_func(
ERROR_NO_POP(); ERROR_NO_POP();
} }
} }
DECREF_INPUTS(); PyStackRef_CLOSE(value);
} }
tier1 inst(INSTRUMENTED_POP_ITER, (iter -- )) { tier1 inst(INSTRUMENTED_POP_ITER, (iter -- )) {
@ -400,7 +400,7 @@ dummy_func(
(void)receiver; (void)receiver;
val = value; val = value;
DEAD(value); DEAD(value);
DECREF_INPUTS(); PyStackRef_CLOSE(receiver);
} }
tier1 inst(INSTRUMENTED_END_SEND, (receiver, value -- val)) { tier1 inst(INSTRUMENTED_END_SEND, (receiver, value -- val)) {
@ -418,7 +418,7 @@ dummy_func(
inst(UNARY_NEGATIVE, (value -- res)) { inst(UNARY_NEGATIVE, (value -- res)) {
PyObject *res_o = PyNumber_Negative(PyStackRef_AsPyObjectBorrow(value)); PyObject *res_o = PyNumber_Negative(PyStackRef_AsPyObjectBorrow(value));
DECREF_INPUTS(); PyStackRef_CLOSE(value);
ERROR_IF(res_o == NULL, error); ERROR_IF(res_o == NULL, error);
res = PyStackRef_FromPyObjectSteal(res_o); res = PyStackRef_FromPyObjectSteal(res_o);
} }
@ -453,7 +453,7 @@ dummy_func(
op(_TO_BOOL, (value -- res)) { op(_TO_BOOL, (value -- res)) {
int err = PyObject_IsTrue(PyStackRef_AsPyObjectBorrow(value)); int err = PyObject_IsTrue(PyStackRef_AsPyObjectBorrow(value));
DECREF_INPUTS(); PyStackRef_CLOSE(value);
ERROR_IF(err < 0, error); ERROR_IF(err < 0, error);
res = err ? PyStackRef_True : PyStackRef_False; res = err ? PyStackRef_True : PyStackRef_False;
} }
@ -475,7 +475,7 @@ dummy_func(
res = PyStackRef_False; res = PyStackRef_False;
} }
else { else {
DECREF_INPUTS(); PyStackRef_CLOSE(value);
res = PyStackRef_True; res = PyStackRef_True;
} }
} }
@ -507,13 +507,13 @@ dummy_func(
} }
else { else {
assert(Py_SIZE(value_o)); assert(Py_SIZE(value_o));
DECREF_INPUTS(); PyStackRef_CLOSE(value);
res = PyStackRef_True; res = PyStackRef_True;
} }
} }
op(_REPLACE_WITH_TRUE, (value -- res)) { op(_REPLACE_WITH_TRUE, (value -- res)) {
DECREF_INPUTS(); PyStackRef_CLOSE(value);
res = PyStackRef_True; res = PyStackRef_True;
} }
@ -524,7 +524,7 @@ dummy_func(
inst(UNARY_INVERT, (value -- res)) { inst(UNARY_INVERT, (value -- res)) {
PyObject *res_o = PyNumber_Invert(PyStackRef_AsPyObjectBorrow(value)); PyObject *res_o = PyNumber_Invert(PyStackRef_AsPyObjectBorrow(value));
DECREF_INPUTS(); PyStackRef_CLOSE(value);
ERROR_IF(res_o == NULL, error); ERROR_IF(res_o == NULL, error);
res = PyStackRef_FromPyObjectSteal(res_o); res = PyStackRef_FromPyObjectSteal(res_o);
} }
@ -721,7 +721,7 @@ dummy_func(
// At the end we just skip over the STORE_FAST. // At the end we just skip over the STORE_FAST.
op(_BINARY_OP_INPLACE_ADD_UNICODE, (left, right --)) { op(_BINARY_OP_INPLACE_ADD_UNICODE, (left, right --)) {
PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); 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(left_o));
assert(PyUnicode_CheckExact(right_o)); assert(PyUnicode_CheckExact(right_o));
@ -752,8 +752,7 @@ dummy_func(
PyObject *temp = PyStackRef_AsPyObjectSteal(*target_local); PyObject *temp = PyStackRef_AsPyObjectSteal(*target_local);
PyUnicode_Append(&temp, right_o); PyUnicode_Append(&temp, right_o);
*target_local = PyStackRef_FromPyObjectSteal(temp); *target_local = PyStackRef_FromPyObjectSteal(temp);
PyStackRef_CLOSE_SPECIALIZED(right, _PyUnicode_ExactDealloc); Py_DECREF(right_o);
DEAD(right);
ERROR_IF(PyStackRef_IsNull(*target_local), error); ERROR_IF(PyStackRef_IsNull(*target_local), error);
#if TIER_ONE #if TIER_ONE
// The STORE_FAST is already done. This is done here in 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])) { inst(SET_ADD, (set, unused[oparg-1], v -- set, unused[oparg-1])) {
int err = PySet_Add(PyStackRef_AsPyObjectBorrow(set), int err = PySet_Add(PyStackRef_AsPyObjectBorrow(set),
PyStackRef_AsPyObjectBorrow(v)); PyStackRef_AsPyObjectBorrow(v));
DECREF_INPUTS(); PyStackRef_CLOSE(v);
ERROR_IF(err, error); ERROR_IF(err, error);
} }
@ -1048,7 +1047,7 @@ dummy_func(
inst(CALL_INTRINSIC_1, (value -- res)) { inst(CALL_INTRINSIC_1, (value -- res)) {
assert(oparg <= MAX_INTRINSIC_1); assert(oparg <= MAX_INTRINSIC_1);
PyObject *res_o = _PyIntrinsics_UnaryFunctions[oparg].func(tstate, PyStackRef_AsPyObjectBorrow(value)); PyObject *res_o = _PyIntrinsics_UnaryFunctions[oparg].func(tstate, PyStackRef_AsPyObjectBorrow(value));
DECREF_INPUTS(); PyStackRef_CLOSE(value);
ERROR_IF(res_o == NULL, error); ERROR_IF(res_o == NULL, error);
res = PyStackRef_FromPyObjectSteal(res_o); res = PyStackRef_FromPyObjectSteal(res_o);
} }
@ -1135,12 +1134,12 @@ dummy_func(
"'async for' requires an object with " "'async for' requires an object with "
"__aiter__ method, got %.100s", "__aiter__ method, got %.100s",
type->tp_name); type->tp_name);
DECREF_INPUTS(); PyStackRef_CLOSE(obj);
ERROR_IF(true, error); ERROR_IF(true, error);
} }
iter_o = (*getter)(obj_o); iter_o = (*getter)(obj_o);
DECREF_INPUTS(); PyStackRef_CLOSE(obj);
ERROR_IF(iter_o == NULL, error); ERROR_IF(iter_o == NULL, error);
if (Py_TYPE(iter_o)->tp_as_async == NULL || if (Py_TYPE(iter_o)->tp_as_async == NULL ||
@ -1166,7 +1165,7 @@ dummy_func(
inst(GET_AWAITABLE, (iterable -- iter)) { inst(GET_AWAITABLE, (iterable -- iter)) {
PyObject *iter_o = _PyEval_GetAwaitable(PyStackRef_AsPyObjectBorrow(iterable), oparg); PyObject *iter_o = _PyEval_GetAwaitable(PyStackRef_AsPyObjectBorrow(iterable), oparg);
DECREF_INPUTS(); PyStackRef_CLOSE(iterable);
ERROR_IF(iter_o == NULL, error); ERROR_IF(iter_o == NULL, error);
iter = PyStackRef_FromPyObjectSteal(iter_o); iter = PyStackRef_FromPyObjectSteal(iter_o);
} }
@ -1228,7 +1227,7 @@ dummy_func(
JUMPBY(oparg); JUMPBY(oparg);
} }
else { else {
DECREF_INPUTS(); PyStackRef_CLOSE(v);
ERROR_IF(true, error); 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); PyObject *exc_value = PyStackRef_AsPyObjectBorrow(exc_value_st);
#ifndef Py_TAIL_CALL_INTERP #ifndef Py_TAIL_CALL_INTERP
assert(throwflag); assert(throwflag);
@ -1366,9 +1365,9 @@ dummy_func(
int matches = PyErr_GivenExceptionMatches(exc_value, PyExc_StopIteration); int matches = PyErr_GivenExceptionMatches(exc_value, PyExc_StopIteration);
if (matches) { if (matches) {
none = PyStackRef_None;
value = PyStackRef_FromPyObjectNew(((PyStopIterationObject *)exc_value)->value); value = PyStackRef_FromPyObjectNew(((PyStopIterationObject *)exc_value)->value);
DECREF_INPUTS(); DECREF_INPUTS();
none = PyStackRef_None;
} }
else { else {
_PyErr_SetRaisedException(tstate, Py_NewRef(exc_value)); _PyErr_SetRaisedException(tstate, Py_NewRef(exc_value));
@ -1410,7 +1409,7 @@ dummy_func(
if (ns == NULL) { if (ns == NULL) {
_PyErr_Format(tstate, PyExc_SystemError, _PyErr_Format(tstate, PyExc_SystemError,
"no locals found when storing %R", name); "no locals found when storing %R", name);
DECREF_INPUTS(); PyStackRef_CLOSE(v);
ERROR_IF(true, error); ERROR_IF(true, error);
} }
if (PyDict_CheckExact(ns)) { if (PyDict_CheckExact(ns)) {
@ -1419,7 +1418,7 @@ dummy_func(
else { else {
err = PyObject_SetItem(ns, name, PyStackRef_AsPyObjectBorrow(v)); err = PyObject_SetItem(ns, name, PyStackRef_AsPyObjectBorrow(v));
} }
DECREF_INPUTS(); PyStackRef_CLOSE(v);
ERROR_IF(err, error); ERROR_IF(err, error);
} }
@ -1462,10 +1461,10 @@ dummy_func(
(void)counter; (void)counter;
} }
op(_UNPACK_SEQUENCE, (seq -- output[oparg])) { op(_UNPACK_SEQUENCE, (seq -- output[oparg], top[0])) {
_PyStackRef *top = output + oparg; PyObject *seq_o = PyStackRef_AsPyObjectSteal(seq);
int res = _PyEval_UnpackIterableStackRef(tstate, seq, oparg, -1, top); int res = _PyEval_UnpackIterableStackRef(tstate, seq_o, oparg, -1, top);
DECREF_INPUTS(); Py_DECREF(seq_o);
ERROR_IF(res == 0, error); ERROR_IF(res == 0, error);
} }
@ -1479,7 +1478,7 @@ dummy_func(
STAT_INC(UNPACK_SEQUENCE, hit); STAT_INC(UNPACK_SEQUENCE, hit);
val0 = PyStackRef_FromPyObjectNew(PyTuple_GET_ITEM(seq_o, 0)); val0 = PyStackRef_FromPyObjectNew(PyTuple_GET_ITEM(seq_o, 0));
val1 = PyStackRef_FromPyObjectNew(PyTuple_GET_ITEM(seq_o, 1)); val1 = PyStackRef_FromPyObjectNew(PyTuple_GET_ITEM(seq_o, 1));
DECREF_INPUTS(); PyStackRef_CLOSE(seq);
} }
inst(UNPACK_SEQUENCE_TUPLE, (unused/1, seq -- values[oparg])) { inst(UNPACK_SEQUENCE_TUPLE, (unused/1, seq -- values[oparg])) {
@ -1511,10 +1510,10 @@ dummy_func(
DECREF_INPUTS(); DECREF_INPUTS();
} }
inst(UNPACK_EX, (seq -- left[oparg & 0xFF], unused, right[oparg >> 8])) { inst(UNPACK_EX, (seq -- left[oparg & 0xFF], unused, right[oparg >> 8], top[0])) {
_PyStackRef *top = right + (oparg >> 8); PyObject *seq_o = PyStackRef_AsPyObjectSteal(seq);
int res = _PyEval_UnpackIterableStackRef(tstate, seq, oparg & 0xFF, oparg >> 8, top); int res = _PyEval_UnpackIterableStackRef(tstate, seq_o, oparg & 0xFF, oparg >> 8, top);
DECREF_INPUTS(); Py_DECREF(seq_o);
ERROR_IF(res == 0, error); ERROR_IF(res == 0, error);
} }
@ -1550,14 +1549,14 @@ dummy_func(
inst(DELETE_ATTR, (owner --)) { inst(DELETE_ATTR, (owner --)) {
PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); PyObject *name = GETITEM(FRAME_CO_NAMES, oparg);
int err = PyObject_DelAttr(PyStackRef_AsPyObjectBorrow(owner), name); int err = PyObject_DelAttr(PyStackRef_AsPyObjectBorrow(owner), name);
DECREF_INPUTS(); PyStackRef_CLOSE(owner);
ERROR_IF(err, error); ERROR_IF(err, error);
} }
inst(STORE_GLOBAL, (v --)) { inst(STORE_GLOBAL, (v --)) {
PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); PyObject *name = GETITEM(FRAME_CO_NAMES, oparg);
int err = PyDict_SetItem(GLOBALS(), name, PyStackRef_AsPyObjectBorrow(v)); int err = PyDict_SetItem(GLOBALS(), name, PyStackRef_AsPyObjectBorrow(v));
DECREF_INPUTS(); PyStackRef_CLOSE(v);
ERROR_IF(err, error); ERROR_IF(err, error);
} }
@ -1589,7 +1588,7 @@ dummy_func(
PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); PyObject *name = GETITEM(FRAME_CO_NAMES, oparg);
PyObject *v_o; PyObject *v_o;
int err = PyMapping_GetOptionalItem(PyStackRef_AsPyObjectBorrow(mod_or_class_dict), name, &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); ERROR_IF(err < 0, error);
if (v_o == NULL) { if (v_o == NULL) {
if (PyDict_CheckExact(GLOBALS()) if (PyDict_CheckExact(GLOBALS())
@ -1885,17 +1884,17 @@ dummy_func(
"Value after * must be an iterable, not %.200s", "Value after * must be an iterable, not %.200s",
Py_TYPE(iterable)->tp_name); Py_TYPE(iterable)->tp_name);
} }
DECREF_INPUTS(); PyStackRef_CLOSE(iterable_st);
ERROR_IF(true, error); ERROR_IF(true, error);
} }
assert(Py_IsNone(none_val)); assert(Py_IsNone(none_val));
DECREF_INPUTS(); PyStackRef_CLOSE(iterable_st);
} }
inst(SET_UPDATE, (set, unused[oparg-1], iterable -- set, unused[oparg-1])) { inst(SET_UPDATE, (set, unused[oparg-1], iterable -- set, unused[oparg-1])) {
int err = _PySet_Update(PyStackRef_AsPyObjectBorrow(set), int err = _PySet_Update(PyStackRef_AsPyObjectBorrow(set),
PyStackRef_AsPyObjectBorrow(iterable)); PyStackRef_AsPyObjectBorrow(iterable));
DECREF_INPUTS(); PyStackRef_CLOSE(iterable);
ERROR_IF(err < 0, error); ERROR_IF(err < 0, error);
} }
@ -1970,10 +1969,10 @@ dummy_func(
"'%.200s' object is not a mapping", "'%.200s' object is not a mapping",
Py_TYPE(update_o)->tp_name); Py_TYPE(update_o)->tp_name);
} }
DECREF_INPUTS(); PyStackRef_CLOSE(update);
ERROR_IF(true, error); 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])) { 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); int err = _PyDict_MergeEx(dict_o, update_o, 2);
if (err < 0) { if (err < 0) {
_PyEval_FormatKwargsError(tstate, callable_o, update_o); _PyEval_FormatKwargsError(tstate, callable_o, update_o);
DECREF_INPUTS(); PyStackRef_CLOSE(update);
ERROR_IF(true, error); ERROR_IF(true, error);
} }
DECREF_INPUTS(); PyStackRef_CLOSE(update);
} }
inst(MAP_ADD, (dict_st, unused[oparg - 1], key, value -- dict_st, unused[oparg - 1])) { 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. CALL that it's not a method call.
meth | NULL | arg1 | ... | argN meth | NULL | arg1 | ... | argN
*/ */
DECREF_INPUTS(); PyStackRef_CLOSE(owner);
ERROR_IF(attr_o == NULL, error); ERROR_IF(attr_o == NULL, error);
self_or_null[0] = PyStackRef_NULL; self_or_null[0] = PyStackRef_NULL;
} }
@ -2180,13 +2179,12 @@ dummy_func(
else { else {
/* Classic, pushes one value. */ /* Classic, pushes one value. */
attr_o = PyObject_GetAttr(PyStackRef_AsPyObjectBorrow(owner), name); attr_o = PyObject_GetAttr(PyStackRef_AsPyObjectBorrow(owner), name);
DECREF_INPUTS(); PyStackRef_CLOSE(owner);
ERROR_IF(attr_o == NULL, error); ERROR_IF(attr_o == NULL, error);
} }
attr = PyStackRef_FromPyObjectSteal(attr_o); attr = PyStackRef_FromPyObjectSteal(attr_o);
} }
macro(LOAD_ATTR) = macro(LOAD_ATTR) =
_SPECIALIZE_LOAD_ATTR + _SPECIALIZE_LOAD_ATTR +
unused/8 + unused/8 +
@ -2736,12 +2734,11 @@ dummy_func(
assert(PyExceptionInstance_Check(left_o)); assert(PyExceptionInstance_Check(left_o));
int err = _PyEval_CheckExceptTypeValid(tstate, right_o); int err = _PyEval_CheckExceptTypeValid(tstate, right_o);
if (err < 0) { if (err < 0) {
DECREF_INPUTS(); ERROR_NO_POP();
ERROR_IF(true, error);
} }
int res = PyErr_GivenExceptionMatches(left_o, right_o); int res = PyErr_GivenExceptionMatches(left_o, right_o);
DECREF_INPUTS(); PyStackRef_CLOSE(right);
b = res ? PyStackRef_True : PyStackRef_False; b = res ? PyStackRef_True : PyStackRef_False;
} }
@ -2968,7 +2965,7 @@ dummy_func(
inst(GET_ITER, (iterable -- iter)) { inst(GET_ITER, (iterable -- iter)) {
/* before: [obj]; after [getiter(obj)] */ /* before: [obj]; after [getiter(obj)] */
PyObject *iter_o = PyObject_GetIter(PyStackRef_AsPyObjectBorrow(iterable)); PyObject *iter_o = PyObject_GetIter(PyStackRef_AsPyObjectBorrow(iterable));
DECREF_INPUTS(); PyStackRef_CLOSE(iterable);
ERROR_IF(iter_o == NULL, error); ERROR_IF(iter_o == NULL, error);
iter = PyStackRef_FromPyObjectSteal(iter_o); iter = PyStackRef_FromPyObjectSteal(iter_o);
} }
@ -3410,7 +3407,7 @@ dummy_func(
assert((oparg & 1) == 0); assert((oparg & 1) == 0);
STAT_INC(LOAD_ATTR, hit); STAT_INC(LOAD_ATTR, hit);
assert(descr != NULL); assert(descr != NULL);
DECREF_INPUTS(); PyStackRef_CLOSE(owner);
attr = PyStackRef_FromPyObjectNew(descr); attr = PyStackRef_FromPyObjectNew(descr);
} }
@ -3426,7 +3423,7 @@ dummy_func(
assert(Py_TYPE(PyStackRef_AsPyObjectBorrow(owner))->tp_dictoffset == 0); assert(Py_TYPE(PyStackRef_AsPyObjectBorrow(owner))->tp_dictoffset == 0);
STAT_INC(LOAD_ATTR, hit); STAT_INC(LOAD_ATTR, hit);
assert(descr != NULL); assert(descr != NULL);
DECREF_INPUTS(); PyStackRef_CLOSE(owner);
attr = PyStackRef_FromPyObjectNew(descr); attr = PyStackRef_FromPyObjectNew(descr);
} }
@ -4797,9 +4794,11 @@ dummy_func(
assert(_PyEval_BinaryOps[oparg]); assert(_PyEval_BinaryOps[oparg]);
PyObject *res_o = _PyEval_BinaryOps[oparg](lhs_o, rhs_o); PyObject *res_o = _PyEval_BinaryOps[oparg](lhs_o, rhs_o);
DECREF_INPUTS(); if (res_o == NULL) {
ERROR_IF(res_o == NULL, error); ERROR_NO_POP();
}
res = PyStackRef_FromPyObjectSteal(res_o); res = PyStackRef_FromPyObjectSteal(res_o);
DECREF_INPUTS();
} }
macro(BINARY_OP) = _SPECIALIZE_BINARY_OP + unused/4 + _BINARY_OP; macro(BINARY_OP) = _SPECIALIZE_BINARY_OP + unused/4 + _BINARY_OP;
@ -5267,10 +5266,12 @@ dummy_func(
goto exit_unwind; goto exit_unwind;
} }
next_instr = frame->instr_ptr; next_instr = frame->instr_ptr;
LLTRACE_RESUME_FRAME();
#ifdef Py_DEBUG #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, /* _PyEval_EvalFrameDefault() must not be called with an exception set,
because it can clear it (directly or indirectly) and so the because it can clear it (directly or indirectly) and so the
caller loses its exception */ caller loses its exception */

View file

@ -135,6 +135,7 @@
static void static void
dump_stack(_PyInterpreterFrame *frame, _PyStackRef *stack_pointer) dump_stack(_PyInterpreterFrame *frame, _PyStackRef *stack_pointer)
{ {
_PyFrame_SetStackPointer(frame, stack_pointer);
_PyStackRef *stack_base = _PyFrame_Stackbase(frame); _PyStackRef *stack_base = _PyFrame_Stackbase(frame);
PyObject *exc = PyErr_GetRaisedException(); PyObject *exc = PyErr_GetRaisedException();
printf(" stack=["); printf(" stack=[");
@ -165,6 +166,7 @@ dump_stack(_PyInterpreterFrame *frame, _PyStackRef *stack_pointer)
printf("]\n"); printf("]\n");
fflush(stdout); fflush(stdout);
PyErr_SetRaisedException(exc); PyErr_SetRaisedException(exc);
_PyFrame_GetStackPointer(frame);
} }
static void static void
@ -799,6 +801,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int
#ifndef Py_TAIL_CALL_INTERP #ifndef Py_TAIL_CALL_INTERP
uint8_t opcode; /* Current opcode */ uint8_t opcode; /* Current opcode */
int oparg; /* Current opcode argument, if any */ int oparg; /* Current opcode argument, if any */
assert(tstate->current_frame == NULL || tstate->current_frame->stackpointer != NULL);
#endif #endif
_PyInterpreterFrame entry_frame; _PyInterpreterFrame entry_frame;
@ -858,8 +861,8 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int
/* Because this avoids the RESUME, we need to update instrumentation */ /* Because this avoids the RESUME, we need to update instrumentation */
_Py_Instrument(_PyFrame_GetCode(frame), tstate->interp); _Py_Instrument(_PyFrame_GetCode(frame), tstate->interp);
next_instr = frame->instr_ptr; next_instr = frame->instr_ptr;
stack_pointer = _PyFrame_GetStackPointer(frame);
monitor_throw(tstate, frame, next_instr); monitor_throw(tstate, frame, next_instr);
stack_pointer = _PyFrame_GetStackPointer(frame);
#ifdef Py_TAIL_CALL_INTERP #ifdef Py_TAIL_CALL_INTERP
return _TAIL_CALL_error(frame, stack_pointer, tstate, next_instr, 0); return _TAIL_CALL_error(frame, stack_pointer, tstate, next_instr, 0);
#else #else
@ -2012,7 +2015,7 @@ _PyEval_ExceptionGroupMatch(_PyInterpreterFrame *frame, PyObject* exc_value,
*/ */
int int
_PyEval_UnpackIterableStackRef(PyThreadState *tstate, _PyStackRef v_stackref, _PyEval_UnpackIterableStackRef(PyThreadState *tstate, PyObject *v,
int argcnt, int argcntafter, _PyStackRef *sp) int argcnt, int argcntafter, _PyStackRef *sp)
{ {
int i = 0, j = 0; int i = 0, j = 0;
@ -2020,8 +2023,6 @@ _PyEval_UnpackIterableStackRef(PyThreadState *tstate, _PyStackRef v_stackref,
PyObject *it; /* iter(v) */ PyObject *it; /* iter(v) */
PyObject *w; PyObject *w;
PyObject *l = NULL; /* variable list */ PyObject *l = NULL; /* variable list */
PyObject *v = PyStackRef_AsPyObjectBorrow(v_stackref);
assert(v != NULL); assert(v != NULL);
it = PyObject_GetIter(v); it = PyObject_GetIter(v);

View file

@ -118,7 +118,9 @@
#ifdef Py_DEBUG #ifdef Py_DEBUG
#define LLTRACE_RESUME_FRAME() \ #define LLTRACE_RESUME_FRAME() \
do { \ do { \
_PyFrame_SetStackPointer(frame, stack_pointer); \
int lltrace = maybe_lltrace_resume_frame(frame, GLOBALS()); \ int lltrace = maybe_lltrace_resume_frame(frame, GLOBALS()); \
stack_pointer = _PyFrame_GetStackPointer(frame); \
if (lltrace < 0) { \ if (lltrace < 0) { \
JUMP_TO_LABEL(exit_unwind); \ JUMP_TO_LABEL(exit_unwind); \
} \ } \
@ -409,17 +411,21 @@ do { \
} while (0) } while (0)
#endif #endif
#define GOTO_TIER_ONE(TARGET) \ #define GOTO_TIER_ONE(TARGET) \
do { \ do \
next_instr = (TARGET); \ { \
OPT_HIST(trace_uop_execution_counter, trace_run_length_hist); \ next_instr = (TARGET); \
Py_CLEAR(tstate->previous_executor); \ OPT_HIST(trace_uop_execution_counter, trace_run_length_hist); \
if (next_instr == NULL) { \ _PyFrame_SetStackPointer(frame, stack_pointer); \
next_instr = frame->instr_ptr; \ Py_CLEAR(tstate->previous_executor); \
goto error; \ stack_pointer = _PyFrame_GetStackPointer(frame); \
} \ if (next_instr == NULL) \
DISPATCH(); \ { \
} while (0) next_instr = frame->instr_ptr; \
goto error; \
} \
DISPATCH(); \
} while (0)
#define CURRENT_OPARG() (next_uop[-1].oparg) #define CURRENT_OPARG() (next_uop[-1].oparg)
#define CURRENT_OPERAND0() (next_uop[-1].operand0) #define CURRENT_OPERAND0() (next_uop[-1].operand0)

1127
Python/executor_cases.c.h generated

File diff suppressed because it is too large Load diff

View file

@ -1996,6 +1996,7 @@ Py_ssize_t
_PyGC_Collect(PyThreadState *tstate, int generation, _PyGC_Reason reason) _PyGC_Collect(PyThreadState *tstate, int generation, _PyGC_Reason reason)
{ {
GCState *gcstate = &tstate->interp->gc; GCState *gcstate = &tstate->interp->gc;
assert(tstate->current_frame == NULL || tstate->current_frame->stackpointer != NULL);
int expected = 0; int expected = 0;
if (!_Py_atomic_compare_exchange_int(&gcstate->collecting, &expected, 1)) { if (!_Py_atomic_compare_exchange_int(&gcstate->collecting, &expected, 1)) {

File diff suppressed because it is too large Load diff

View file

@ -273,14 +273,16 @@
{ {
assert(PyLong_CheckExact(sym_get_const(left))); assert(PyLong_CheckExact(sym_get_const(left)));
assert(PyLong_CheckExact(sym_get_const(right))); assert(PyLong_CheckExact(sym_get_const(right)));
stack_pointer += -2;
assert(WITHIN_STACK_BOUNDS());
PyObject *temp = _PyLong_Multiply((PyLongObject *)sym_get_const(left), PyObject *temp = _PyLong_Multiply((PyLongObject *)sym_get_const(left),
(PyLongObject *)sym_get_const(right)); (PyLongObject *)sym_get_const(right));
if (temp == NULL) { if (temp == NULL) {
goto error; goto error;
} }
res = sym_new_const(ctx, temp); res = sym_new_const(ctx, temp);
stack_pointer[-2] = res; stack_pointer[0] = res;
stack_pointer += -1; stack_pointer += 1;
assert(WITHIN_STACK_BOUNDS()); assert(WITHIN_STACK_BOUNDS());
Py_DECREF(temp); Py_DECREF(temp);
// TODO gh-115506: // TODO gh-115506:
@ -306,14 +308,16 @@
{ {
assert(PyLong_CheckExact(sym_get_const(left))); assert(PyLong_CheckExact(sym_get_const(left)));
assert(PyLong_CheckExact(sym_get_const(right))); assert(PyLong_CheckExact(sym_get_const(right)));
stack_pointer += -2;
assert(WITHIN_STACK_BOUNDS());
PyObject *temp = _PyLong_Add((PyLongObject *)sym_get_const(left), PyObject *temp = _PyLong_Add((PyLongObject *)sym_get_const(left),
(PyLongObject *)sym_get_const(right)); (PyLongObject *)sym_get_const(right));
if (temp == NULL) { if (temp == NULL) {
goto error; goto error;
} }
res = sym_new_const(ctx, temp); res = sym_new_const(ctx, temp);
stack_pointer[-2] = res; stack_pointer[0] = res;
stack_pointer += -1; stack_pointer += 1;
assert(WITHIN_STACK_BOUNDS()); assert(WITHIN_STACK_BOUNDS());
Py_DECREF(temp); Py_DECREF(temp);
// TODO gh-115506: // TODO gh-115506:
@ -339,14 +343,16 @@
{ {
assert(PyLong_CheckExact(sym_get_const(left))); assert(PyLong_CheckExact(sym_get_const(left)));
assert(PyLong_CheckExact(sym_get_const(right))); assert(PyLong_CheckExact(sym_get_const(right)));
stack_pointer += -2;
assert(WITHIN_STACK_BOUNDS());
PyObject *temp = _PyLong_Subtract((PyLongObject *)sym_get_const(left), PyObject *temp = _PyLong_Subtract((PyLongObject *)sym_get_const(left),
(PyLongObject *)sym_get_const(right)); (PyLongObject *)sym_get_const(right));
if (temp == NULL) { if (temp == NULL) {
goto error; goto error;
} }
res = sym_new_const(ctx, temp); res = sym_new_const(ctx, temp);
stack_pointer[-2] = res; stack_pointer[0] = res;
stack_pointer += -1; stack_pointer += 1;
assert(WITHIN_STACK_BOUNDS()); assert(WITHIN_STACK_BOUNDS());
Py_DECREF(temp); Py_DECREF(temp);
// TODO gh-115506: // TODO gh-115506:

View file

@ -602,7 +602,6 @@ NON_ESCAPING_FUNCTIONS = (
"PyTuple_GET_ITEM", "PyTuple_GET_ITEM",
"PyTuple_GET_SIZE", "PyTuple_GET_SIZE",
"PyType_HasFeature", "PyType_HasFeature",
"PyUnicode_Append",
"PyUnicode_Concat", "PyUnicode_Concat",
"PyUnicode_GET_LENGTH", "PyUnicode_GET_LENGTH",
"PyUnicode_READ_CHAR", "PyUnicode_READ_CHAR",
@ -619,7 +618,6 @@ NON_ESCAPING_FUNCTIONS = (
"_PyCode_CODE", "_PyCode_CODE",
"_PyDictValues_AddToInsertionOrder", "_PyDictValues_AddToInsertionOrder",
"_PyErr_Occurred", "_PyErr_Occurred",
"_PyEval_FrameClearAndPop",
"_PyFloat_FromDouble_ConsumeInputs", "_PyFloat_FromDouble_ConsumeInputs",
"_PyFrame_GetBytecode", "_PyFrame_GetBytecode",
"_PyFrame_GetCode", "_PyFrame_GetCode",
@ -633,15 +631,12 @@ NON_ESCAPING_FUNCTIONS = (
"_PyList_AppendTakeRef", "_PyList_AppendTakeRef",
"_PyList_FromStackRefStealOnSuccess", "_PyList_FromStackRefStealOnSuccess",
"_PyList_ITEMS", "_PyList_ITEMS",
"_PyLong_Add",
"_PyLong_CompactValue", "_PyLong_CompactValue",
"_PyLong_DigitCount", "_PyLong_DigitCount",
"_PyLong_IsCompact", "_PyLong_IsCompact",
"_PyLong_IsNegative", "_PyLong_IsNegative",
"_PyLong_IsNonNegativeCompact", "_PyLong_IsNonNegativeCompact",
"_PyLong_IsZero", "_PyLong_IsZero",
"_PyLong_Multiply",
"_PyLong_Subtract",
"_PyManagedDictPointer_IsValues", "_PyManagedDictPointer_IsValues",
"_PyObject_GC_IS_TRACKED", "_PyObject_GC_IS_TRACKED",
"_PyObject_GC_MAY_BE_TRACKED", "_PyObject_GC_MAY_BE_TRACKED",

View file

@ -15,6 +15,8 @@ class CWriter:
self.line_directives = line_directives self.line_directives = line_directives
self.last_token = None self.last_token = None
self.newline = True self.newline = True
self.pending_spill = False
self.pending_reload = False
def set_position(self, tkn: Token) -> None: def set_position(self, tkn: Token) -> None:
if self.last_token is not None: if self.last_token is not None:
@ -33,6 +35,7 @@ class CWriter:
self.newline = False self.newline = False
def emit_at(self, txt: str, where: Token) -> None: def emit_at(self, txt: str, where: Token) -> None:
self.maybe_write_spill()
self.set_position(where) self.set_position(where)
self.out.write(txt) self.out.write(txt)
@ -109,6 +112,7 @@ class CWriter:
self.last_token = None self.last_token = None
def emit(self, txt: str | Token) -> None: def emit(self, txt: str | Token) -> None:
self.maybe_write_spill()
if isinstance(txt, Token): if isinstance(txt, Token):
self.emit_token(txt) self.emit_token(txt)
elif isinstance(txt, str): elif isinstance(txt, str):
@ -122,6 +126,28 @@ class CWriter:
self.newline = True self.newline = True
self.last_token = None 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 @contextlib.contextmanager
def header_guard(self, name: str) -> Iterator[None]: def header_guard(self, name: str) -> Iterator[None]:
self.out.write( self.out.write(

View file

@ -243,29 +243,13 @@ class Emitter:
next(tkn_iter) next(tkn_iter)
next(tkn_iter) next(tkn_iter)
next(tkn_iter) next(tkn_iter)
self.out.emit_at("", tkn) try:
for var in storage.inputs: storage.close_inputs(self.out)
if not var.defined: except StackError as ex:
continue raise analysis_error(ex.args[0], tkn)
if var.name == "null": except Exception as ex:
continue ex.args = (ex.args[0] + str(tkn),)
close = "PyStackRef_CLOSE" raise
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
return True return True
def kill_inputs( def kill_inputs(
@ -301,7 +285,9 @@ class Emitter:
var.defined = False var.defined = False
break break
else: 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 return True
def stackref_kill( def stackref_kill(
@ -344,7 +330,7 @@ class Emitter:
self.out.emit(comma) self.out.emit(comma)
dealloc = next(tkn_iter) dealloc = next(tkn_iter)
if dealloc.kind != "IDENTIFIER": if dealloc.kind != "IDENTIFIER":
raise analysis_error("Expected identifier", dealloc) raise analysis_error("Expected identifier", dealloc)
self.out.emit(dealloc) self.out.emit(dealloc)
if name.kind == "IDENTIFIER": if name.kind == "IDENTIFIER":
escapes = dealloc.text not in NON_ESCAPING_DEALLOCS escapes = dealloc.text not in NON_ESCAPING_DEALLOCS
@ -518,7 +504,7 @@ class Emitter:
self.emit(next(tkn_iter)) self.emit(next(tkn_iter))
maybe_if = tkn_iter.peek() maybe_if = tkn_iter.peek()
if maybe_if and maybe_if.kind == "IF": 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(" {\n")
self.emit(next(tkn_iter)) self.emit(next(tkn_iter))
else_reachable, rbrace, else_storage = self._emit_if(tkn_iter, uop, storage, inst) else_reachable, rbrace, else_storage = self._emit_if(tkn_iter, uop, storage, inst)

View file

@ -154,11 +154,11 @@ def write_uop(
var.defined = False var.defined = False
storage = emitter.emit_tokens(override, storage, None) storage = emitter.emit_tokens(override, storage, None)
out.start_line() out.start_line()
storage.flush(out, cast_type="JitOptSymbol *") storage.flush(out)
else: else:
emit_default(out, uop, stack) emit_default(out, uop, stack)
out.start_line() out.start_line()
stack.flush(out, cast_type="JitOptSymbol *") stack.flush(out)
except StackError as ex: except StackError as ex:
raise analysis_error(ex.args[0], prototype.body[0]) # from None 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) declare_variables(override, out, skip_inputs=False)
else: else:
declare_variables(uop, out, skip_inputs=True) 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)) write_uop(override, uop, out, stack, debug, skip_inputs=(override is None))
out.start_line() out.start_line()
out.emit("break;\n") out.emit("break;\n")

View file

@ -224,12 +224,13 @@ def array_or_scalar(var: StackItem | Local) -> str:
return "array" if var.is_array() else "scalar" return "array" if var.is_array() else "scalar"
class Stack: 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.top_offset = StackOffset.empty()
self.base_offset = StackOffset.empty() self.base_offset = StackOffset.empty()
self.variables: list[Local] = [] self.variables: list[Local] = []
self.defined: set[str] = set() self.defined: set[str] = set()
self.extract_bits = extract_bits self.extract_bits = extract_bits
self.cast_type = cast_type
def pop(self, var: StackItem) -> tuple[str, Local]: def pop(self, var: StackItem) -> tuple[str, Local]:
self.top_offset.pop(var) self.top_offset.pop(var)
@ -298,8 +299,8 @@ class Stack:
out: CWriter, out: CWriter,
var: StackItem, var: StackItem,
base_offset: StackOffset, base_offset: StackOffset,
cast_type: str = "uintptr_t", cast_type: str,
extract_bits: bool = True, extract_bits: bool,
) -> None: ) -> None:
cast = f"({cast_type})" if var.type else "" cast = f"({cast_type})" if var.type else ""
bits = ".bits" if cast and extract_bits else "" bits = ".bits" if cast and extract_bits else ""
@ -315,9 +316,7 @@ class Stack:
out.emit(f"stack_pointer += {number};\n") out.emit(f"stack_pointer += {number};\n")
out.emit("assert(WITHIN_STACK_BOUNDS());\n") out.emit("assert(WITHIN_STACK_BOUNDS());\n")
def flush( def flush(self, out: CWriter) -> None:
self, out: CWriter, cast_type: str = "uintptr_t"
) -> None:
out.start_line() out.start_line()
var_offset = self.base_offset.copy() var_offset = self.base_offset.copy()
for var in self.variables: for var in self.variables:
@ -325,7 +324,7 @@ class Stack:
var.defined and var.defined and
not var.in_memory 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.in_memory = True
var_offset.push(var.item) var_offset.push(var.item)
number = self.top_offset.to_c() number = self.top_offset.to_c()
@ -347,7 +346,7 @@ class Stack:
) )
def copy(self) -> "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.top_offset = self.top_offset.copy()
other.base_offset = self.base_offset.copy() other.base_offset = self.base_offset.copy()
other.variables = [var.copy() for var in self.variables] other.variables = [var.copy() for var in self.variables]
@ -508,17 +507,26 @@ class Storage:
return True return True
return False return False
def flush(self, out: CWriter, cast_type: str = "uintptr_t") -> None: def flush(self, out: CWriter) -> None:
self.clear_dead_inputs() self.clear_dead_inputs()
self._push_defined_outputs() self._push_defined_outputs()
self.stack.flush(out, cast_type) self.stack.flush(out)
def save(self, out: CWriter) -> None: def save(self, out: CWriter) -> None:
assert self.spilled >= 0 assert self.spilled >= 0
if self.spilled == 0: if self.spilled == 0:
self.flush(out) self.flush(out)
out.start_line() 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 self.spilled += 1
def reload(self, out: CWriter) -> None: def reload(self, out: CWriter) -> None:
@ -528,7 +536,7 @@ class Storage:
self.spilled -= 1 self.spilled -= 1
if self.spilled == 0: if self.spilled == 0:
out.start_line() out.start_line()
out.emit("stack_pointer = _PyFrame_GetStackPointer(frame);\n") out.emit_reload()
@staticmethod @staticmethod
def for_uop(stack: Stack, uop: Uop) -> tuple[list[str], "Storage"]: 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]) outputs = ", ".join([var.compact_str() for var in self.outputs])
peeks = ", ".join([var.name for var in self.peeks]) 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} */" 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)