]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
Emit RECORD_DYNAMIC_JUMP_TAKEN automatically
authorKen Jin <28750310+Fidget-Spinner@users.noreply.github.com>
Fri, 24 Oct 2025 18:07:37 +0000 (19:07 +0100)
committerKen Jin <28750310+Fidget-Spinner@users.noreply.github.com>
Fri, 24 Oct 2025 18:07:37 +0000 (19:07 +0100)
Misc/NEWS.d/next/Core_and_Builtins/2025-10-18-21-50-44.gh-issue-139109.9QQOzN.rst
Python/bytecodes.c
Python/generated_cases.c.h
Tools/cases_generator/analyzer.py
Tools/cases_generator/generators_common.py

index 3d6f45b2b44781f791049a63a0f04ba5b50e4e84..40b9d19ee42968f059354d1672326f33ee2630d1 100644 (file)
@@ -1 +1 @@
-A new tracing frontend for the JIT compiler has been implemented. Patch by Ken Jin. Design for CPython by Mark Shannon, Ken Jin and Brandt Bucher.
+A new tracing frontend for the JIT compiler has been implemented. Patch by Ken Jin. Design for CPython by Ken Jin, Mark Shannon and Brandt Bucher.
index fc12dc787bce58aa9629f7ce8eb9912ff57c29b2..ee9d41bd5194cf08f3d34ff38f33cb2538032941 100644 (file)
 
 #define USE_COMPUTED_GOTOS 0
 #include "ceval_macros.h"
-#include "ceval_macros.h"
-#include "ceval_macros.h"
-#include "../Include/internal/pycore_code.h"
-#include "../Include/internal/pycore_stackref.h"
 
 /* Flow control macros */
 
@@ -1380,7 +1376,6 @@ dummy_func(
                 if (err == 0) {
                     assert(retval_o != NULL);
                     JUMPBY(oparg);
-                    RECORD_DYNAMIC_JUMP_TAKEN();
                 }
                 else {
                     PyStackRef_CLOSE(v);
@@ -3235,7 +3230,6 @@ dummy_func(
                 }
                 // Jump forward by oparg and skip the following END_FOR
                 JUMPBY(oparg + 1);
-                RECORD_DYNAMIC_JUMP_TAKEN();
                 DISPATCH();
             }
             next = item;
@@ -3297,7 +3291,6 @@ dummy_func(
                 null_or_index = PyStackRef_TagInt(-1);
                 /* Jump forward oparg, then skip following END_FOR instruction */
                 JUMPBY(oparg + 1);
-                RECORD_DYNAMIC_JUMP_TAKEN();
                 DISPATCH();
             }
 #endif
@@ -3375,7 +3368,6 @@ dummy_func(
                 null_or_index = PyStackRef_TagInt(-1);
                 /* Jump forward oparg, then skip following END_FOR instruction */
                 JUMPBY(oparg + 1);
-                RECORD_DYNAMIC_JUMP_TAKEN();
                 DISPATCH();
             }
         }
@@ -3420,7 +3412,6 @@ dummy_func(
             if (r->len <= 0) {
                 // Jump over END_FOR instruction.
                 JUMPBY(oparg + 1);
-                RECORD_DYNAMIC_JUMP_TAKEN();
                 DISPATCH();
             }
         }
index 8169a36a9b956245eeaee64044f8fbf46988b26c..6ed8bce67cc1cf279b5ee3ca6559b786aec9eb12 100644 (file)
                 if (result == 0) {
                     null_or_index = PyStackRef_TagInt(-1);
                     JUMPBY(oparg + 1);
+                    RECORD_DYNAMIC_JUMP_TAKEN();
                     stack_pointer[-1] = null_or_index;
                     DISPATCH();
                 }
                     JUMP_TO_LABEL(error);
                 }
                 JUMPBY(oparg + 1);
+                RECORD_DYNAMIC_JUMP_TAKEN();
                 stack_pointer[-1] = null_or_index;
                 DISPATCH();
             }
index 7a5e8786f2a80440ff267437012a40fad648f171..a525a2bf705559bab8536fa87f62150ea97e6160 100644 (file)
@@ -35,6 +35,7 @@ class Properties:
     pure: bool
     uses_opcode: bool
     needs_guard_ip: bool
+    unpredictable_jump: bool
     tier: int | None = None
     const_oparg: int = -1
     needs_prev: bool = False
@@ -76,7 +77,8 @@ class Properties:
             pure=all(p.pure for p in properties),
             needs_prev=any(p.needs_prev for p in properties),
             no_save_ip=all(p.no_save_ip for p in properties),
-            needs_guard_ip=any(p.needs_guard_ip for p in properties)
+            needs_guard_ip=any(p.needs_guard_ip for p in properties),
+            unpredictable_jump=any(p.unpredictable_jump for p in properties),
         )
 
     @property
@@ -105,6 +107,7 @@ SKIP_PROPERTIES = Properties(
     pure=True,
     no_save_ip=False,
     needs_guard_ip=False,
+    unpredictable_jump=False,
 )
 
 
@@ -887,6 +890,42 @@ def stmt_escapes(stmt: Stmt) -> bool:
     else:
         assert False, "Unexpected statement type"
 
+def stmt_has_jump_on_unpredictable_path_body(stmts: list[Stmt] | None, branches_seen: int) -> bool:
+    if not stmts:
+        return False, branches_seen
+    predict = False
+    seen = 0
+    for st in stmts:
+        predict_body, seen_body = stmt_has_jump_on_unpredictable_path(st, branches_seen)
+        predict = predict or predict_body
+        seen += seen_body
+    return predict, seen
+
+def stmt_has_jump_on_unpredictable_path(stmt: Stmt, branches_seen: int) -> bool:
+    if isinstance(stmt, BlockStmt):
+        return stmt_has_jump_on_unpredictable_path_body(stmt.body, branches_seen)
+    elif isinstance(stmt, SimpleStmt):
+        for tkn in stmt.contents:
+            if tkn.text == "JUMPBY":
+                return True, branches_seen
+        return False, branches_seen
+    elif isinstance(stmt, IfStmt):
+        return True, branches_seen + 1
+    elif isinstance(stmt, MacroIfStmt):
+        predict, seen = stmt_has_jump_on_unpredictable_path_body(stmt.body, branches_seen)
+        if stmt.else_body:
+            predict_else, seen_else = stmt_has_jump_on_unpredictable_path_body(stmt.else_body, branches_seen)
+            return predict != predict_else, seen + seen_else
+        return predict, seen
+    elif isinstance(stmt, ForStmt):
+        unpredictable, branches_seen = stmt_has_jump_on_unpredictable_path(stmt.body, branches_seen)
+        return unpredictable, branches_seen + 1
+    elif isinstance(stmt, WhileStmt):
+        unpredictable, branches_seen = stmt_has_jump_on_unpredictable_path(stmt.body, branches_seen)
+        return unpredictable, branches_seen + 1
+    else:
+        assert False, f"Unexpected statement type {stmt}"
+
 
 def compute_properties(op: parser.CodeDef) -> Properties:
     escaping_calls = find_escaping_api_calls(op)
@@ -914,6 +953,8 @@ def compute_properties(op: parser.CodeDef) -> Properties:
     escapes = stmt_escapes(op.block)
     pure = False if isinstance(op, parser.LabelDef) else "pure" in op.annotations
     no_save_ip = False if isinstance(op, parser.LabelDef) else "no_save_ip" in op.annotations
+    unpredictable, branches_seen = stmt_has_jump_on_unpredictable_path(op.block, 0)
+    unpredictable_jump = False if isinstance(op, parser.LabelDef) else (unpredictable and branches_seen > 0)
     return Properties(
         escaping_calls=escaping_calls,
         escapes=escapes,
@@ -938,6 +979,7 @@ def compute_properties(op: parser.CodeDef) -> Properties:
         tier=tier_variable(op),
         needs_prev=variable_used(op, "prev_instr"),
         needs_guard_ip=variable_used(op, "TIER2_STORE_IP") or variable_used(op, "LLTRACE_RESUME_FRAME") or variable_used(op, "DISPATCH_INLINED"),
+        unpredictable_jump=unpredictable_jump,
     )
 
 def expand(items: list[StackItem], oparg: int) -> list[StackItem]:
index 804bd9773b164a9a4161907c915113e21ca1a9e1..fed0b4c1643a30acddf76551ccdbe1f0695d125a 100644 (file)
@@ -128,6 +128,7 @@ class Emitter:
             "DISPATCH": self.dispatch,
             "INSTRUCTION_SIZE": self.instruction_size,
             "stack_pointer": self.stack_pointer,
+            "JUMPBY": self.jumpby,
         }
         self.out = out
         self.labels = labels
@@ -402,6 +403,30 @@ class Emitter:
         storage.stack.clear(self.out)
         return True
 
+    def jumpby(
+        self,
+        tkn: Token,
+        tkn_iter: TokenIterator,
+        uop: CodeSection,
+        storage: Storage,
+        inst: Instruction | None,
+    ) -> bool:
+        self.out.start_line()
+        self.emit(tkn)
+        lparen = next(tkn_iter)
+        self.emit(lparen)
+        jump = next(tkn_iter)
+        self.emit(jump)
+        emit_to(self.out, tkn_iter, "RPAREN")
+        next(tkn_iter)
+        self.emit(");\n")
+
+
+        if uop.properties.unpredictable_jump and jump.text != "0":
+            self.out.start_line()
+            self.emit("RECORD_DYNAMIC_JUMP_TAKEN();\n")
+        return True
+
     def stack_pointer(
         self,
         tkn: Token,