[Python-checkins] bpo-44878: Remove loop from interpreter. All dispatching is done by gotos. (GH-27727)

markshannon webhook-mailer at python.org
Thu Aug 12 06:47:47 EDT 2021


https://github.com/python/cpython/commit/a530a9538f3f444bebd2d2b71fe5f2e747e76d73
commit: a530a9538f3f444bebd2d2b71fe5f2e747e76d73
branch: main
author: Mark Shannon <mark at hotpy.org>
committer: markshannon <mark at hotpy.org>
date: 2021-08-12T11:47:38+01:00
summary:

bpo-44878: Remove loop from interpreter. All dispatching is done by gotos. (GH-27727)

files:
A Misc/NEWS.d/next/Core and Builtins/2021-08-11-14-12-41.bpo-44878.pAbBfc.rst
M Python/ceval.c

diff --git a/Misc/NEWS.d/next/Core and Builtins/2021-08-11-14-12-41.bpo-44878.pAbBfc.rst b/Misc/NEWS.d/next/Core and Builtins/2021-08-11-14-12-41.bpo-44878.pAbBfc.rst
new file mode 100644
index 0000000000000..9e07fa8a25df0
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2021-08-11-14-12-41.bpo-44878.pAbBfc.rst	
@@ -0,0 +1,2 @@
+Remove the loop from the bytecode interpreter. All instructions end with a
+DISPATCH macro, so the loop is now redundant.
diff --git a/Python/ceval.c b/Python/ceval.c
index e8c4e4c8c07eb..f494e8477fac7 100644
--- a/Python/ceval.c
+++ b/Python/ceval.c
@@ -1280,7 +1280,7 @@ eval_frame_handle_pending(PyThreadState *tstate)
 
 #define CHECK_EVAL_BREAKER() \
     if (_Py_atomic_load_relaxed(eval_breaker)) { \
-        continue; \
+        goto check_eval_breaker; \
     }
 
 
@@ -1584,7 +1584,8 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
     assert(!_PyErr_Occurred(tstate));
 #endif
 
-    for (;;) {
+check_eval_breaker:
+    {
         assert(STACK_LEVEL() >= 0); /* else underflow */
         assert(STACK_LEVEL() <= co->co_stacksize);  /* else overflow */
         assert(!_PyErr_Occurred(tstate));
@@ -4292,6 +4293,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
             CHECK_EVAL_BREAKER();
             DISPATCH();
         }
+
         TARGET(CALL_METHOD_KW): {
             /* Designed to work in tandem with LOAD_METHOD. Same as CALL_METHOD
             but pops TOS to get a tuple of keyword names. */
@@ -4315,6 +4317,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
             CHECK_EVAL_BREAKER();
             DISPATCH();
         }
+
         TARGET(CALL_FUNCTION): {
             PREDICTED(CALL_FUNCTION);
             PyObject **sp, *res;
@@ -4621,7 +4624,17 @@ MISS_WITH_OPARG_COUNTER(BINARY_SUBSCR)
         int level, handler, lasti;
         if (get_exception_handler(co, offset, &level, &handler, &lasti) == 0) {
             // No handlers, so exit.
-            break;
+            assert(retval == NULL);
+            assert(_PyErr_Occurred(tstate));
+
+            /* Pop remaining stack entries. */
+            while (!EMPTY()) {
+                PyObject *o = POP();
+                Py_XDECREF(o);
+            }
+            frame->stackdepth = 0;
+            frame->f_state = FRAME_RAISED;
+            goto exiting;
         }
 
         assert(STACK_LEVEL() >= level);
@@ -4661,18 +4674,8 @@ MISS_WITH_OPARG_COUNTER(BINARY_SUBSCR)
         NEXTOPARG();
         PRE_DISPATCH_GOTO();
         DISPATCH_GOTO();
-    } /* main loop */
-
-    assert(retval == NULL);
-    assert(_PyErr_Occurred(tstate));
-
-    /* Pop remaining stack entries. */
-    while (!EMPTY()) {
-        PyObject *o = POP();
-        Py_XDECREF(o);
     }
-    frame->stackdepth = 0;
-    frame->f_state = FRAME_RAISED;
+
 exiting:
     if (cframe.use_tracing) {
         if (tstate->c_tracefunc) {



More information about the Python-checkins mailing list