Only check evalbreaker after calls and on backwards egdes. Makes sure that __exit__ or __aexit__ is called in with statments in case of interrupt.

This commit is contained in:
Mark Shannon 2020-02-03 13:26:20 +00:00
parent 869c0c99b9
commit 6afa580bb4
2 changed files with 40 additions and 46 deletions

View File

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

View File

@ -837,7 +837,7 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)
TARGET_##op
#ifdef LLTRACE
#define FAST_DISPATCH() \
#define DISPATCH() \
{ \
if (!lltrace && !_Py_TracingPossible(ceval) && !PyDTrace_LINE_ENABLED()) { \
f->f_lasti = INSTR_OFFSET(); \
@ -847,7 +847,7 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)
goto fast_next_opcode; \
}
#else
#define FAST_DISPATCH() \
#define DISPATCH() \
{ \
if (!_Py_TracingPossible(ceval) && !PyDTrace_LINE_ENABLED()) { \
f->f_lasti = INSTR_OFFSET(); \
@ -858,20 +858,17 @@ _PyEval_EvalFrameDefault(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 */
@ -1323,7 +1320,7 @@ main_loop:
and that all operation that succeed call [FAST_]DISPATCH() ! */
case TARGET(NOP): {
FAST_DISPATCH();
DISPATCH();
}
case TARGET(LOAD_FAST): {
@ -1336,7 +1333,7 @@ main_loop:
}
Py_INCREF(value);
PUSH(value);
FAST_DISPATCH();
DISPATCH();
}
case TARGET(LOAD_CONST): {
@ -1344,20 +1341,20 @@ main_loop:
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): {
@ -1365,7 +1362,7 @@ main_loop:
PyObject *second = SECOND();
SET_TOP(second);
SET_SECOND(top);
FAST_DISPATCH();
DISPATCH();
}
case TARGET(ROT_THREE): {
@ -1375,7 +1372,7 @@ main_loop:
SET_TOP(second);
SET_SECOND(third);
SET_THIRD(top);
FAST_DISPATCH();
DISPATCH();
}
case TARGET(ROT_FOUR): {
@ -1387,14 +1384,14 @@ main_loop:
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): {
@ -1405,7 +1402,7 @@ main_loop:
STACK_GROW(2);
SET_TOP(top);
SET_SECOND(second);
FAST_DISPATCH();
DISPATCH();
}
case TARGET(UNARY_POSITIVE): {
@ -2147,7 +2144,7 @@ main_loop:
UNWIND_EXCEPT_HANDLER(b);
Py_DECREF(POP());
JUMPBY(oparg);
FAST_DISPATCH();
DISPATCH();
}
else {
PyObject *val = POP();
@ -2161,7 +2158,7 @@ main_loop:
PyObject *value = PyExc_AssertionError;
Py_INCREF(value);
PUSH(value);
FAST_DISPATCH();
DISPATCH();
}
case TARGET(LOAD_BUILD_CLASS): {
@ -2880,7 +2877,7 @@ main_loop:
Py_DECREF(right);
PREDICT(POP_JUMP_IF_FALSE);
PREDICT(POP_JUMP_IF_TRUE);
FAST_DISPATCH();
DISPATCH();
}
case TARGET(CONTAINS_OP): {
@ -2897,7 +2894,7 @@ main_loop:
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 "\
@ -2994,7 +2991,7 @@ main_loop:
case TARGET(JUMP_FORWARD): {
JUMPBY(oparg);
FAST_DISPATCH();
DISPATCH();
}
case TARGET(POP_JUMP_IF_FALSE): {
@ -3003,12 +3000,12 @@ main_loop:
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);
@ -3027,12 +3024,12 @@ main_loop:
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);
@ -3052,11 +3049,11 @@ main_loop:
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) {
@ -3076,11 +3073,11 @@ main_loop:
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) {
@ -3098,18 +3095,8 @@ main_loop:
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_ITER): {
@ -3363,6 +3350,7 @@ main_loop:
PUSH(res);
if (res == NULL)
goto error;
CHECK_EVAL_BREAKER();
DISPATCH();
}
@ -3376,6 +3364,7 @@ main_loop:
if (res == NULL) {
goto error;
}
CHECK_EVAL_BREAKER();
DISPATCH();
}
@ -3395,6 +3384,7 @@ main_loop:
if (res == NULL) {
goto error;
}
CHECK_EVAL_BREAKER();
DISPATCH();
}
@ -3441,6 +3431,7 @@ main_loop:
if (result == NULL) {
goto error;
}
CHECK_EVAL_BREAKER();
DISPATCH();
}