Skip to content

bpo-29988: Only check evalbreaker after calls and on backwards egdes. #18334

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Mar 24, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Only handle asynchronous exceptions and requests to drop the GIL when
returning from a call or on the back edges of loops. Makes sure that
:meth:`__exit__` is always called in with statements, even for interrupts.
83 changes: 37 additions & 46 deletions Python/ceval.c
Original file line number Diff line number Diff line change
Expand Up @@ -1331,7 +1331,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
TARGET_##op

#ifdef LLTRACE
#define FAST_DISPATCH() \
#define DISPATCH() \
{ \
if (!lltrace && !_Py_TracingPossible(ceval2) && !PyDTrace_LINE_ENABLED()) { \
f->f_lasti = INSTR_OFFSET(); \
Expand All @@ -1341,7 +1341,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
goto fast_next_opcode; \
}
#else
#define FAST_DISPATCH() \
#define DISPATCH() \
{ \
if (!_Py_TracingPossible(ceval2) && !PyDTrace_LINE_ENABLED()) { \
f->f_lasti = INSTR_OFFSET(); \
Expand All @@ -1352,20 +1352,17 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
}
#endif

#define DISPATCH() \
{ \
if (!_Py_atomic_load_relaxed(eval_breaker)) { \
FAST_DISPATCH(); \
} \
continue; \
}

#else
#define TARGET(op) op
#define FAST_DISPATCH() goto fast_next_opcode
#define DISPATCH() continue
#define DISPATCH() goto fast_next_opcode

#endif

#define CHECK_EVAL_BREAKER() \
if (_Py_atomic_load_relaxed(eval_breaker)) { \
continue; \
}


/* Tuple access macros */

Expand Down Expand Up @@ -1857,7 +1854,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
and that all operation that succeed call [FAST_]DISPATCH() ! */

case TARGET(NOP): {
FAST_DISPATCH();
DISPATCH();
}

case TARGET(LOAD_FAST): {
Expand All @@ -1870,36 +1867,36 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
}
Py_INCREF(value);
PUSH(value);
FAST_DISPATCH();
DISPATCH();
}

case TARGET(LOAD_CONST): {
PREDICTED(LOAD_CONST);
PyObject *value = GETITEM(consts, oparg);
Py_INCREF(value);
PUSH(value);
FAST_DISPATCH();
DISPATCH();
}

case TARGET(STORE_FAST): {
PREDICTED(STORE_FAST);
PyObject *value = POP();
SETLOCAL(oparg, value);
FAST_DISPATCH();
DISPATCH();
}

case TARGET(POP_TOP): {
PyObject *value = POP();
Py_DECREF(value);
FAST_DISPATCH();
DISPATCH();
}

case TARGET(ROT_TWO): {
PyObject *top = TOP();
PyObject *second = SECOND();
SET_TOP(second);
SET_SECOND(top);
FAST_DISPATCH();
DISPATCH();
}

case TARGET(ROT_THREE): {
Expand All @@ -1909,7 +1906,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
SET_TOP(second);
SET_SECOND(third);
SET_THIRD(top);
FAST_DISPATCH();
DISPATCH();
}

case TARGET(ROT_FOUR): {
Expand All @@ -1921,14 +1918,14 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
SET_SECOND(third);
SET_THIRD(fourth);
SET_FOURTH(top);
FAST_DISPATCH();
DISPATCH();
}

case TARGET(DUP_TOP): {
PyObject *top = TOP();
Py_INCREF(top);
PUSH(top);
FAST_DISPATCH();
DISPATCH();
}

case TARGET(DUP_TOP_TWO): {
Expand All @@ -1939,7 +1936,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
STACK_GROW(2);
SET_TOP(top);
SET_SECOND(second);
FAST_DISPATCH();
DISPATCH();
}

case TARGET(UNARY_POSITIVE): {
Expand Down Expand Up @@ -2704,7 +2701,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
UNWIND_EXCEPT_HANDLER(b);
Py_DECREF(POP());
JUMPBY(oparg);
FAST_DISPATCH();
DISPATCH();
}
else {
PyObject *val = POP();
Expand All @@ -2718,7 +2715,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
PyObject *value = PyExc_AssertionError;
Py_INCREF(value);
PUSH(value);
FAST_DISPATCH();
DISPATCH();
}

case TARGET(LOAD_BUILD_CLASS): {
Expand Down Expand Up @@ -3620,7 +3617,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
Py_DECREF(right);
PREDICT(POP_JUMP_IF_FALSE);
PREDICT(POP_JUMP_IF_TRUE);
FAST_DISPATCH();
DISPATCH();
}

case TARGET(CONTAINS_OP): {
Expand All @@ -3637,7 +3634,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
PUSH(b);
PREDICT(POP_JUMP_IF_FALSE);
PREDICT(POP_JUMP_IF_TRUE);
FAST_DISPATCH();
DISPATCH();
}

#define CANNOT_CATCH_MSG "catching classes that do not inherit from "\
Expand Down Expand Up @@ -3734,7 +3731,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)

case TARGET(JUMP_FORWARD): {
JUMPBY(oparg);
FAST_DISPATCH();
DISPATCH();
}

case TARGET(POP_JUMP_IF_FALSE): {
Expand All @@ -3743,12 +3740,12 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
int err;
if (cond == Py_True) {
Py_DECREF(cond);
FAST_DISPATCH();
DISPATCH();
}
if (cond == Py_False) {
Py_DECREF(cond);
JUMPTO(oparg);
FAST_DISPATCH();
DISPATCH();
}
err = PyObject_IsTrue(cond);
Py_DECREF(cond);
Expand All @@ -3767,12 +3764,12 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
int err;
if (cond == Py_False) {
Py_DECREF(cond);
FAST_DISPATCH();
DISPATCH();
}
if (cond == Py_True) {
Py_DECREF(cond);
JUMPTO(oparg);
FAST_DISPATCH();
DISPATCH();
}
err = PyObject_IsTrue(cond);
Py_DECREF(cond);
Expand All @@ -3792,11 +3789,11 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
if (cond == Py_True) {
STACK_SHRINK(1);
Py_DECREF(cond);
FAST_DISPATCH();
DISPATCH();
}
if (cond == Py_False) {
JUMPTO(oparg);
FAST_DISPATCH();
DISPATCH();
}
err = PyObject_IsTrue(cond);
if (err > 0) {
Expand All @@ -3816,11 +3813,11 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
if (cond == Py_False) {
STACK_SHRINK(1);
Py_DECREF(cond);
FAST_DISPATCH();
DISPATCH();
}
if (cond == Py_True) {
JUMPTO(oparg);
FAST_DISPATCH();
DISPATCH();
}
err = PyObject_IsTrue(cond);
if (err > 0) {
Expand All @@ -3838,18 +3835,8 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
case TARGET(JUMP_ABSOLUTE): {
PREDICTED(JUMP_ABSOLUTE);
JUMPTO(oparg);
#if FAST_LOOPS
/* Enabling this path speeds-up all while and for-loops by bypassing
the per-loop checks for signals. By default, this should be turned-off
because it prevents detection of a control-break in tight loops like
"while 1: pass". Compile with this option turned-on when you need
the speed-up and do not need break checking inside tight loops (ones
that contain only instructions ending with FAST_DISPATCH).
*/
FAST_DISPATCH();
#else
CHECK_EVAL_BREAKER();
DISPATCH();
#endif
}

case TARGET(GET_LEN): {
Expand Down Expand Up @@ -4260,6 +4247,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
PUSH(res);
if (res == NULL)
goto error;
CHECK_EVAL_BREAKER();
DISPATCH();
}

Expand All @@ -4273,6 +4261,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
if (res == NULL) {
goto error;
}
CHECK_EVAL_BREAKER();
DISPATCH();
}

Expand All @@ -4292,6 +4281,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
if (res == NULL) {
goto error;
}
CHECK_EVAL_BREAKER();
DISPATCH();
}

Expand Down Expand Up @@ -4338,6 +4328,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
if (result == NULL) {
goto error;
}
CHECK_EVAL_BREAKER();
DISPATCH();
}

Expand Down