]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
GH-104584: Don't call executors from JUMP_BACKWARD (GH-109347)
authorBrandt Bucher <brandtbucher@microsoft.com>
Wed, 13 Sep 2023 17:26:50 +0000 (10:26 -0700)
committerGitHub <noreply@github.com>
Wed, 13 Sep 2023 17:26:50 +0000 (10:26 -0700)
Include/cpython/optimizer.h
Python/bytecodes.c
Python/generated_cases.c.h
Python/optimizer.c

index 10457afc180a003decf76df79a3515dcee2ae01c..47536108a9665e1e2a2e56f2020ca0d56bcc3f66 100644 (file)
@@ -40,7 +40,7 @@ PyAPI_FUNC(_PyOptimizerObject *) PyUnstable_GetOptimizer(void);
 
 PyAPI_FUNC(_PyExecutorObject *) PyUnstable_GetExecutor(PyCodeObject *code, int offset);
 
-struct _PyInterpreterFrame *
+int
 _PyOptimizer_BackEdge(struct _PyInterpreterFrame *frame, _Py_CODEUNIT *src, _Py_CODEUNIT *dest, PyObject **stack_pointer);
 
 extern _PyOptimizerObject _PyOptimizer_Default;
index e5be62cf983f213010ef08c8f8ce81b53660dd65..402b27101dbdb65505780af9f4ccece7d812d5af 100644 (file)
@@ -2242,21 +2242,17 @@ dummy_func(
             here[1].cache += (1 << OPTIMIZER_BITS_IN_COUNTER);
             if (here[1].cache > tstate->interp->optimizer_backedge_threshold &&
                 // Double-check that the opcode isn't instrumented or something:
-                here->op.code == JUMP_BACKWARD &&
-                // _PyOptimizer_BackEdge is going to change frame->prev_instr,
-                // which breaks line event calculations:
-                next_instr->op.code != INSTRUMENTED_LINE
-                )
+                here->op.code == JUMP_BACKWARD)
             {
                 OBJECT_STAT_INC(optimization_attempts);
-                frame = _PyOptimizer_BackEdge(frame, here, next_instr, stack_pointer);
-                if (frame == NULL) {
-                    frame = tstate->current_frame;
-                    goto resume_with_error;
+                int optimized = _PyOptimizer_BackEdge(frame, here, next_instr, stack_pointer);
+                ERROR_IF(optimized < 0, error);
+                if (optimized) {
+                    // Rewind and enter the executor:
+                    assert(here->op.code == ENTER_EXECUTOR);
+                    next_instr = here;
                 }
-                assert(frame == tstate->current_frame);
-                here[1].cache &= ((1 << OPTIMIZER_BITS_IN_COUNTER) -1);
-                goto resume_frame;
+                here[1].cache &= ((1 << OPTIMIZER_BITS_IN_COUNTER) - 1);
             }
             #endif  /* ENABLE_SPECIALIZATION */
         }
index fff47a1b636f908593fe650c1d8dde514b950a52..ebb87a86de432e75b64de215f74f1286b1e03bd9 100644 (file)
             here[1].cache += (1 << OPTIMIZER_BITS_IN_COUNTER);
             if (here[1].cache > tstate->interp->optimizer_backedge_threshold &&
                 // Double-check that the opcode isn't instrumented or something:
-                here->op.code == JUMP_BACKWARD &&
-                // _PyOptimizer_BackEdge is going to change frame->prev_instr,
-                // which breaks line event calculations:
-                next_instr->op.code != INSTRUMENTED_LINE
-                )
+                here->op.code == JUMP_BACKWARD)
             {
                 OBJECT_STAT_INC(optimization_attempts);
-                frame = _PyOptimizer_BackEdge(frame, here, next_instr, stack_pointer);
-                if (frame == NULL) {
-                    frame = tstate->current_frame;
-                    goto resume_with_error;
+                int optimized = _PyOptimizer_BackEdge(frame, here, next_instr, stack_pointer);
+                if (optimized < 0) goto error;
+                if (optimized) {
+                    // Rewind and enter the executor:
+                    assert(here->op.code == ENTER_EXECUTOR);
+                    next_instr = here;
                 }
-                assert(frame == tstate->current_frame);
-                here[1].cache &= ((1 << OPTIMIZER_BITS_IN_COUNTER) -1);
-                goto resume_frame;
+                here[1].cache &= ((1 << OPTIMIZER_BITS_IN_COUNTER) - 1);
             }
             #endif  /* ENABLE_SPECIALIZATION */
             DISPATCH();
index 453e3e86f5a1e309fa2832eea6fe325adfb4fa6e..fbdbf7291784c4be655d604a61b6e9cb6ed26ab6 100644 (file)
@@ -154,7 +154,7 @@ PyUnstable_SetOptimizer(_PyOptimizerObject *optimizer)
     Py_DECREF(old);
 }
 
-_PyInterpreterFrame *
+int
 _PyOptimizer_BackEdge(_PyInterpreterFrame *frame, _Py_CODEUNIT *src, _Py_CODEUNIT *dest, PyObject **stack_pointer)
 {
     assert(src->op.code == JUMP_BACKWARD);
@@ -162,18 +162,14 @@ _PyOptimizer_BackEdge(_PyInterpreterFrame *frame, _Py_CODEUNIT *src, _Py_CODEUNI
     assert(PyCode_Check(code));
     PyInterpreterState *interp = _PyInterpreterState_GET();
     if (!has_space_for_executor(code, src)) {
-        goto jump_to_destination;
+        return 0;
     }
     _PyOptimizerObject *opt = interp->optimizer;
     _PyExecutorObject *executor = NULL;
     int err = opt->optimize(opt, code, dest, &executor, (int)(stack_pointer - _PyFrame_Stackbase(frame)));
     if (err <= 0) {
         assert(executor == NULL);
-        if (err < 0) {
-            _PyFrame_SetStackPointer(frame, stack_pointer);
-            return NULL;
-        }
-        goto jump_to_destination;
+        return err;
     }
     int index = get_index_for_executor(code, src);
     if (index < 0) {
@@ -184,16 +180,11 @@ _PyOptimizer_BackEdge(_PyInterpreterFrame *frame, _Py_CODEUNIT *src, _Py_CODEUNI
          * it might get confused by the executor disappearing,
          * but there is not much we can do about that here. */
         Py_DECREF(executor);
-        goto jump_to_destination;
+        return 0;
     }
     insert_executor(code, src, index, executor);
-    assert(frame->prev_instr == src);
-    frame->prev_instr = dest - 1;
-    return executor->execute(executor, frame, stack_pointer);
-jump_to_destination:
-    frame->prev_instr = dest - 1;
-    _PyFrame_SetStackPointer(frame, stack_pointer);
-    return frame;
+    Py_DECREF(executor);
+    return 1;
 }
 
 _PyExecutorObject *