Skip to content

Commit a53ca1d

Browse files
Emit RECORD_DYNAMIC_JUMP_TAKEN automatically
1 parent 6bd1541 commit a53ca1d

File tree

5 files changed

+71
-11
lines changed

5 files changed

+71
-11
lines changed
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +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.
1+
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.

Python/bytecodes.c

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -45,10 +45,6 @@
4545

4646
#define USE_COMPUTED_GOTOS 0
4747
#include "ceval_macros.h"
48-
#include "ceval_macros.h"
49-
#include "ceval_macros.h"
50-
#include "../Include/internal/pycore_code.h"
51-
#include "../Include/internal/pycore_stackref.h"
5248

5349
/* Flow control macros */
5450

@@ -1380,7 +1376,6 @@ dummy_func(
13801376
if (err == 0) {
13811377
assert(retval_o != NULL);
13821378
JUMPBY(oparg);
1383-
RECORD_DYNAMIC_JUMP_TAKEN();
13841379
}
13851380
else {
13861381
PyStackRef_CLOSE(v);
@@ -3235,7 +3230,6 @@ dummy_func(
32353230
}
32363231
// Jump forward by oparg and skip the following END_FOR
32373232
JUMPBY(oparg + 1);
3238-
RECORD_DYNAMIC_JUMP_TAKEN();
32393233
DISPATCH();
32403234
}
32413235
next = item;
@@ -3297,7 +3291,6 @@ dummy_func(
32973291
null_or_index = PyStackRef_TagInt(-1);
32983292
/* Jump forward oparg, then skip following END_FOR instruction */
32993293
JUMPBY(oparg + 1);
3300-
RECORD_DYNAMIC_JUMP_TAKEN();
33013294
DISPATCH();
33023295
}
33033296
#endif
@@ -3375,7 +3368,6 @@ dummy_func(
33753368
null_or_index = PyStackRef_TagInt(-1);
33763369
/* Jump forward oparg, then skip following END_FOR instruction */
33773370
JUMPBY(oparg + 1);
3378-
RECORD_DYNAMIC_JUMP_TAKEN();
33793371
DISPATCH();
33803372
}
33813373
}
@@ -3420,7 +3412,6 @@ dummy_func(
34203412
if (r->len <= 0) {
34213413
// Jump over END_FOR instruction.
34223414
JUMPBY(oparg + 1);
3423-
RECORD_DYNAMIC_JUMP_TAKEN();
34243415
DISPATCH();
34253416
}
34263417
}

Python/generated_cases.c.h

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Tools/cases_generator/analyzer.py

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ class Properties:
3535
pure: bool
3636
uses_opcode: bool
3737
needs_guard_ip: bool
38+
unpredictable_jump: bool
3839
tier: int | None = None
3940
const_oparg: int = -1
4041
needs_prev: bool = False
@@ -76,7 +77,8 @@ def from_list(properties: list["Properties"]) -> "Properties":
7677
pure=all(p.pure for p in properties),
7778
needs_prev=any(p.needs_prev for p in properties),
7879
no_save_ip=all(p.no_save_ip for p in properties),
79-
needs_guard_ip=any(p.needs_guard_ip for p in properties)
80+
needs_guard_ip=any(p.needs_guard_ip for p in properties),
81+
unpredictable_jump=any(p.unpredictable_jump for p in properties),
8082
)
8183

8284
@property
@@ -105,6 +107,7 @@ def infallible(self) -> bool:
105107
pure=True,
106108
no_save_ip=False,
107109
needs_guard_ip=False,
110+
unpredictable_jump=False,
108111
)
109112

110113

@@ -887,6 +890,42 @@ def stmt_escapes(stmt: Stmt) -> bool:
887890
else:
888891
assert False, "Unexpected statement type"
889892

893+
def stmt_has_jump_on_unpredictable_path_body(stmts: list[Stmt] | None, branches_seen: int) -> bool:
894+
if not stmts:
895+
return False, branches_seen
896+
predict = False
897+
seen = 0
898+
for st in stmts:
899+
predict_body, seen_body = stmt_has_jump_on_unpredictable_path(st, branches_seen)
900+
predict = predict or predict_body
901+
seen += seen_body
902+
return predict, seen
903+
904+
def stmt_has_jump_on_unpredictable_path(stmt: Stmt, branches_seen: int) -> bool:
905+
if isinstance(stmt, BlockStmt):
906+
return stmt_has_jump_on_unpredictable_path_body(stmt.body, branches_seen)
907+
elif isinstance(stmt, SimpleStmt):
908+
for tkn in stmt.contents:
909+
if tkn.text == "JUMPBY":
910+
return True, branches_seen
911+
return False, branches_seen
912+
elif isinstance(stmt, IfStmt):
913+
return True, branches_seen + 1
914+
elif isinstance(stmt, MacroIfStmt):
915+
predict, seen = stmt_has_jump_on_unpredictable_path_body(stmt.body, branches_seen)
916+
if stmt.else_body:
917+
predict_else, seen_else = stmt_has_jump_on_unpredictable_path_body(stmt.else_body, branches_seen)
918+
return predict != predict_else, seen + seen_else
919+
return predict, seen
920+
elif isinstance(stmt, ForStmt):
921+
unpredictable, branches_seen = stmt_has_jump_on_unpredictable_path(stmt.body, branches_seen)
922+
return unpredictable, branches_seen + 1
923+
elif isinstance(stmt, WhileStmt):
924+
unpredictable, branches_seen = stmt_has_jump_on_unpredictable_path(stmt.body, branches_seen)
925+
return unpredictable, branches_seen + 1
926+
else:
927+
assert False, f"Unexpected statement type {stmt}"
928+
890929

891930
def compute_properties(op: parser.CodeDef) -> Properties:
892931
escaping_calls = find_escaping_api_calls(op)
@@ -914,6 +953,8 @@ def compute_properties(op: parser.CodeDef) -> Properties:
914953
escapes = stmt_escapes(op.block)
915954
pure = False if isinstance(op, parser.LabelDef) else "pure" in op.annotations
916955
no_save_ip = False if isinstance(op, parser.LabelDef) else "no_save_ip" in op.annotations
956+
unpredictable, branches_seen = stmt_has_jump_on_unpredictable_path(op.block, 0)
957+
unpredictable_jump = False if isinstance(op, parser.LabelDef) else (unpredictable and branches_seen > 0)
917958
return Properties(
918959
escaping_calls=escaping_calls,
919960
escapes=escapes,
@@ -938,6 +979,7 @@ def compute_properties(op: parser.CodeDef) -> Properties:
938979
tier=tier_variable(op),
939980
needs_prev=variable_used(op, "prev_instr"),
940981
needs_guard_ip=variable_used(op, "TIER2_STORE_IP") or variable_used(op, "LLTRACE_RESUME_FRAME") or variable_used(op, "DISPATCH_INLINED"),
982+
unpredictable_jump=unpredictable_jump,
941983
)
942984

943985
def expand(items: list[StackItem], oparg: int) -> list[StackItem]:

Tools/cases_generator/generators_common.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,7 @@ def __init__(self, out: CWriter, labels: dict[str, Label], cannot_escape: bool =
128128
"DISPATCH": self.dispatch,
129129
"INSTRUCTION_SIZE": self.instruction_size,
130130
"stack_pointer": self.stack_pointer,
131+
"JUMPBY": self.jumpby,
131132
}
132133
self.out = out
133134
self.labels = labels
@@ -402,6 +403,30 @@ def sync_sp(
402403
storage.stack.clear(self.out)
403404
return True
404405

406+
def jumpby(
407+
self,
408+
tkn: Token,
409+
tkn_iter: TokenIterator,
410+
uop: CodeSection,
411+
storage: Storage,
412+
inst: Instruction | None,
413+
) -> bool:
414+
self.out.start_line()
415+
self.emit(tkn)
416+
lparen = next(tkn_iter)
417+
self.emit(lparen)
418+
jump = next(tkn_iter)
419+
self.emit(jump)
420+
emit_to(self.out, tkn_iter, "RPAREN")
421+
next(tkn_iter)
422+
self.emit(");\n")
423+
424+
425+
if uop.properties.unpredictable_jump and jump.text != "0":
426+
self.out.start_line()
427+
self.emit("RECORD_DYNAMIC_JUMP_TAKEN();\n")
428+
return True
429+
405430
def stack_pointer(
406431
self,
407432
tkn: Token,

0 commit comments

Comments
 (0)