]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-139109: Dynamic opcode targets (GH-139111)
authorKen Jin <kenjin@python.org>
Thu, 18 Sep 2025 13:12:07 +0000 (21:12 +0800)
committerGitHub <noreply@github.com>
Thu, 18 Sep 2025 13:12:07 +0000 (14:12 +0100)
Make opcode targets table dynamic

Python/ceval.c
Python/ceval_macros.h
Python/opcode_targets.h
Tools/c-analyzer/cpython/_parser.py
Tools/cases_generator/target_generator.py

index a532f17a97f7a8a858e2f39f32992be90af305d3..7abbc9e9fd12b6166cf395b62f8b7d11311b9729 100644 (file)
@@ -1022,6 +1022,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int
 #if USE_COMPUTED_GOTOS && !_Py_TAIL_CALL_INTERP
 /* Import the static jump table */
 #include "opcode_targets.h"
+    void **opcode_targets = opcode_targets_table;
 #endif
 
 #ifdef Py_STATS
@@ -1101,9 +1102,9 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int
         stack_pointer = _PyFrame_GetStackPointer(frame);
 #if _Py_TAIL_CALL_INTERP
 #   if Py_STATS
-        return _TAIL_CALL_error(frame, stack_pointer, tstate, next_instr, 0, lastopcode);
+        return _TAIL_CALL_error(frame, stack_pointer, tstate, next_instr, instruction_funcptr_table, 0, lastopcode);
 #   else
-        return _TAIL_CALL_error(frame, stack_pointer, tstate, next_instr, 0);
+        return _TAIL_CALL_error(frame, stack_pointer, tstate, next_instr, instruction_funcptr_table, 0);
 #   endif
 #else
         goto error;
@@ -1112,9 +1113,9 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int
 
 #if _Py_TAIL_CALL_INTERP
 #   if Py_STATS
-        return _TAIL_CALL_start_frame(frame, NULL, tstate, NULL, 0, lastopcode);
+        return _TAIL_CALL_start_frame(frame, NULL, tstate, NULL, instruction_funcptr_table, 0, lastopcode);
 #   else
-        return _TAIL_CALL_start_frame(frame, NULL, tstate, NULL, 0);
+        return _TAIL_CALL_start_frame(frame, NULL, tstate, NULL, instruction_funcptr_table, 0);
 #   endif
 #else
     goto start_frame;
index 7799fd11203e71017da0108071da836b6e2852b5..4ed03b7fb01bdfdcbd884234f93c5f6c13fca3f6 100644 (file)
 #endif
 
 #ifdef Py_STATS
-#   define TAIL_CALL_PARAMS _PyInterpreterFrame *frame, _PyStackRef *stack_pointer, PyThreadState *tstate, _Py_CODEUNIT *next_instr, int oparg, int lastopcode
-#   define TAIL_CALL_ARGS frame, stack_pointer, tstate, next_instr, oparg, lastopcode
+#   define TAIL_CALL_PARAMS _PyInterpreterFrame *frame, _PyStackRef *stack_pointer, PyThreadState *tstate, _Py_CODEUNIT *next_instr, const void *instruction_funcptr_table, int oparg, int lastopcode
+#   define TAIL_CALL_ARGS frame, stack_pointer, tstate, next_instr, instruction_funcptr_table, oparg, lastopcode
 #else
-#   define TAIL_CALL_PARAMS _PyInterpreterFrame *frame, _PyStackRef *stack_pointer, PyThreadState *tstate, _Py_CODEUNIT *next_instr, int oparg
-#   define TAIL_CALL_ARGS frame, stack_pointer, tstate, next_instr, oparg
+#   define TAIL_CALL_PARAMS _PyInterpreterFrame *frame, _PyStackRef *stack_pointer, PyThreadState *tstate, _Py_CODEUNIT *next_instr, const void *instruction_funcptr_table, int oparg
+#   define TAIL_CALL_ARGS frame, stack_pointer, tstate, next_instr, instruction_funcptr_table, oparg
 #endif
 
 #if _Py_TAIL_CALL_INTERP
@@ -87,7 +87,7 @@
 #   define TARGET(op) Py_PRESERVE_NONE_CC PyObject *_TAIL_CALL_##op(TAIL_CALL_PARAMS)
 #   define DISPATCH_GOTO() \
         do { \
-            Py_MUSTTAIL return (INSTRUCTION_TABLE[opcode])(TAIL_CALL_ARGS); \
+            Py_MUSTTAIL return (((py_tail_call_funcptr *)instruction_funcptr_table)[opcode])(TAIL_CALL_ARGS); \
         } while (0)
 #   define JUMP_TO_LABEL(name) \
         do { \
 #   ifdef Py_STATS
 #       define JUMP_TO_PREDICTED(name) \
             do { \
-                Py_MUSTTAIL return (_TAIL_CALL_##name)(frame, stack_pointer, tstate, this_instr, oparg, lastopcode); \
+                Py_MUSTTAIL return (_TAIL_CALL_##name)(frame, stack_pointer, tstate, this_instr, instruction_funcptr_table, oparg, lastopcode); \
             } while (0)
 #   else
 #       define JUMP_TO_PREDICTED(name) \
             do { \
-                Py_MUSTTAIL return (_TAIL_CALL_##name)(frame, stack_pointer, tstate, this_instr, oparg); \
+                Py_MUSTTAIL return (_TAIL_CALL_##name)(frame, stack_pointer, tstate, this_instr, instruction_funcptr_table, oparg); \
             } while (0)
 #   endif
 #    define LABEL(name) TARGET(name)
index 33607b2115f5d0c2d24417ee1bfd7f1bef3ad093..6dd443e1655ed02c432f20c5899f702ebc863387 100644 (file)
@@ -1,5 +1,5 @@
 #if !_Py_TAIL_CALL_INTERP
-static void *opcode_targets[256] = {
+static void *opcode_targets_table[256] = {
     &&TARGET_CACHE,
     &&TARGET_BINARY_SLICE,
     &&TARGET_BUILD_TEMPLATE,
@@ -258,7 +258,7 @@ static void *opcode_targets[256] = {
     &&TARGET_ENTER_EXECUTOR,
 };
 #else /* _Py_TAIL_CALL_INTERP */
-static py_tail_call_funcptr INSTRUCTION_TABLE[256];
+static py_tail_call_funcptr instruction_funcptr_table[256];
 
 Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_pop_2_error(TAIL_CALL_PARAMS);
 Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_pop_1_error(TAIL_CALL_PARAMS);
@@ -503,7 +503,7 @@ Py_PRESERVE_NONE_CC static PyObject *_TAIL_CALL_UNKNOWN_OPCODE(TAIL_CALL_PARAMS)
 JUMP_TO_LABEL(error);
 }
 
-static py_tail_call_funcptr INSTRUCTION_TABLE[256] = {
+static py_tail_call_funcptr instruction_funcptr_table[256] = {
     [BINARY_OP] = _TAIL_CALL_BINARY_OP,
     [BINARY_OP_ADD_FLOAT] = _TAIL_CALL_BINARY_OP_ADD_FLOAT,
     [BINARY_OP_ADD_INT] = _TAIL_CALL_BINARY_OP_ADD_INT,
index bd30809b0fba43fb3e5fd2d78842554b399d3241..17c56c9e8762c6dd508b86d9df277e460b802a58 100644 (file)
@@ -80,6 +80,7 @@ EXCLUDED = format_conf_lines([
     'Python/generated_cases.c.h',
     'Python/executor_cases.c.h',
     'Python/optimizer_cases.c.h',
+    'Python/opcode_targets.h',
     # XXX: Throws errors if PY_VERSION_HEX is not mocked out
     'Modules/clinic/_testclinic_depr.c.h',
 
index 1a1a014837e25905d17716997e92283b074d39c0..324ef2773abe28021b8377260a54ed314256a14b 100644 (file)
@@ -27,7 +27,7 @@ def write_opcode_targets(analysis: Analysis, out: CWriter) -> None:
         if op < 256:
             targets[op] = f"&&TARGET_{name},\n"
     out.emit("#if !_Py_TAIL_CALL_INTERP\n")
-    out.emit("static void *opcode_targets[256] = {\n")
+    out.emit("static void *opcode_targets_table[256] = {\n")
     for target in targets:
         out.emit(target)
     out.emit("};\n")
@@ -38,7 +38,7 @@ def function_proto(name: str) -> str:
 
 
 def write_tailcall_dispatch_table(analysis: Analysis, out: CWriter) -> None:
-    out.emit("static py_tail_call_funcptr INSTRUCTION_TABLE[256];\n")
+    out.emit("static py_tail_call_funcptr instruction_funcptr_table[256];\n")
     out.emit("\n")
 
     # Emit function prototypes for labels.
@@ -60,7 +60,7 @@ def write_tailcall_dispatch_table(analysis: Analysis, out: CWriter) -> None:
     out.emit("\n")
 
     # Emit the dispatch table.
-    out.emit("static py_tail_call_funcptr INSTRUCTION_TABLE[256] = {\n")
+    out.emit("static py_tail_call_funcptr instruction_funcptr_table[256] = {\n")
     for name in sorted(analysis.instructions.keys()):
         out.emit(f"[{name}] = _TAIL_CALL_{name},\n")
     named_values = analysis.opmap.values()