Skip to content

Commit 83c85c3

Browse files
rework ad-hoc generation of guards
1 parent da5e7b7 commit 83c85c3

File tree

3 files changed

+101
-56
lines changed

3 files changed

+101
-56
lines changed

Python/bytecodes.c

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5489,23 +5489,35 @@ dummy_func(
54895489
}
54905490

54915491
tier2 op(_GUARD_IP__PUSH_FRAME, (ip/4 --)) {
5492-
// Implementation automatically inserted by Tools/cases/tier2_generator.py
5493-
EXIT_IF(true);
5492+
_Py_CODEUNIT *target = frame->instr_ptr + OFFSET_OF_CORRESPONDING_UOP;
5493+
if (target != (_Py_CODEUNIT *)ip) {
5494+
frame->instr_ptr += OFFSET_OF_CORRESPONDING_UOP;
5495+
EXIT_IF(true);
5496+
}
54945497
}
54955498

54965499
tier2 op(_GUARD_IP_YIELD_VALUE, (ip/4 --)) {
5497-
// Implementation automatically inserted by Tools/cases/tier2_generator.py
5498-
EXIT_IF(true);
5500+
_Py_CODEUNIT *target = frame->instr_ptr + OFFSET_OF_CORRESPONDING_UOP;
5501+
if (target != (_Py_CODEUNIT *)ip) {
5502+
frame->instr_ptr += OFFSET_OF_CORRESPONDING_UOP;
5503+
EXIT_IF(true);
5504+
}
54995505
}
55005506

55015507
tier2 op(_GUARD_IP_RETURN_VALUE, (ip/4 --)) {
5502-
// Implementation automatically inserted by Tools/cases/tier2_generator.py
5503-
EXIT_IF(true);
5508+
_Py_CODEUNIT *target = frame->instr_ptr + OFFSET_OF_CORRESPONDING_UOP;
5509+
if (target != (_Py_CODEUNIT *)ip) {
5510+
frame->instr_ptr += OFFSET_OF_CORRESPONDING_UOP;
5511+
EXIT_IF(true);
5512+
}
55045513
}
55055514

55065515
tier2 op(_GUARD_IP_RETURN_GENERATOR, (ip/4 --)) {
5507-
// Implementation automatically inserted by Tools/cases/tier2_generator.py
5508-
EXIT_IF(true);
5516+
_Py_CODEUNIT *target = frame->instr_ptr + OFFSET_OF_CORRESPONDING_UOP;
5517+
if (target != (_Py_CODEUNIT *)ip) {
5518+
frame->instr_ptr += OFFSET_OF_CORRESPONDING_UOP;
5519+
EXIT_IF(true);
5520+
}
55095521
}
55105522

55115523
label(pop_2_error) {

Python/executor_cases.c.h

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

Tools/cases_generator/tier2_generator.py

Lines changed: 41 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ class Tier2Emitter(Emitter):
6363
def __init__(self, out: CWriter, labels: dict[str, Label]):
6464
super().__init__(out, labels)
6565
self._replacers["oparg"] = self.oparg
66+
self._replacers["OFFSET_OF_CORRESPONDING_UOP"] = self.offset_of_corresponding_uop
6667

6768
def goto_error(self, offset: int, storage: Storage) -> str:
6869
# To do: Add jump targets for popping values.
@@ -134,6 +135,19 @@ def oparg(
134135
self.out.emit_at(uop.name[-1], tkn)
135136
return True
136137

138+
def offset_of_corresponding_uop(
139+
self,
140+
tkn: Token,
141+
tkn_iter: TokenIterator,
142+
uop: CodeSection,
143+
storage: Storage,
144+
inst: Instruction | None,
145+
) -> bool:
146+
assert uop.name.startswith("_GUARD_IP")
147+
rest = uop.name[len("_GUARD_IP"):]
148+
self.emit(f" OFFSET_OF{rest};\n")
149+
next(tkn_iter)
150+
return True
137151

138152
def write_uop(uop: Uop, emitter: Emitter, stack: Stack) -> Stack:
139153
locals: dict[str, Local] = {}
@@ -165,33 +179,6 @@ def write_uop(uop: Uop, emitter: Emitter, stack: Stack) -> Stack:
165179
SKIPS = ("_EXTENDED_ARG",)
166180

167181

168-
def generate_guard_ips(
169-
analysis: Analysis,
170-
emitter: Tier2Emitter,
171-
) -> None:
172-
for name, uop in analysis.uops.items():
173-
for stmt in uop.body.body:
174-
tkn_iter = iter(stmt.tokens())
175-
for token in tkn_iter:
176-
if token.kind == "IDENTIFIER" and token.text == "LOAD_IP":
177-
offset = []
178-
while token.kind != "SEMI":
179-
offset.append(token.text)
180-
token = next(tkn_iter)
181-
# 1: to remove the LOAD_IP text
182-
offset_str = "".join(offset[1:])
183-
emitter.emit(f"case _GUARD_IP_{name}: {{\n")
184-
emitter.emit("PyObject *ip = (PyObject *)CURRENT_OPERAND0();\n")
185-
emitter.emit(f"if (frame->instr_ptr + {offset_str} != (_Py_CODEUNIT *)ip) {{\n")
186-
emitter.emit(f"frame->instr_ptr += {offset_str};\n")
187-
emitter.emit(f"UOP_STAT_INC(uopcode, miss);\n")
188-
emitter.emit("JUMP_TO_JUMP_TARGET();\n")
189-
emitter.emit("}\n")
190-
emitter.emit("break;\n")
191-
emitter.emit("}\n")
192-
emitter.emit("\n")
193-
194-
195182
def generate_tier2(
196183
filenames: list[str], analysis: Analysis, outfile: TextIO, lines: bool
197184
) -> None:
@@ -207,13 +194,35 @@ def generate_tier2(
207194
out = CWriter(outfile, 2, lines)
208195
emitter = Tier2Emitter(out, analysis.labels)
209196
out.emit("\n")
197+
offset_strs: list[tuple[str, str]] = []
198+
for name, uop in analysis.uops.items():
199+
if not f"_GUARD_IP_{name}" in analysis.uops:
200+
continue
201+
tkn_iter = uop.body.tokens()
202+
found = False
203+
offset_str = ""
204+
for token in tkn_iter:
205+
if token.kind == "IDENTIFIER" and token.text == "LOAD_IP":
206+
if found:
207+
raise analysis_error("Cannot have two LOAD_IP in a guarded single uop.", uop.body.open)
208+
offset = []
209+
while token.kind != "SEMI":
210+
offset.append(token.text)
211+
token = next(tkn_iter)
212+
# 1: to remove the LOAD_IP text
213+
offset_str = "".join(offset[1:])
214+
found = True
215+
assert offset_str
216+
out.emit(f"#define OFFSET_OF_{name} ({offset_str})\n")
217+
offset_strs.append((name, offset_str))
218+
219+
out.emit("\n")
220+
210221
for name, uop in analysis.uops.items():
211222
if uop.properties.tier == 1:
212223
continue
213224
if uop.is_super():
214225
continue
215-
if name.startswith("_GUARD_IP"):
216-
continue
217226
why_not_viable = uop.why_not_viable()
218227
if why_not_viable is not None:
219228
out.emit(
@@ -231,7 +240,9 @@ def generate_tier2(
231240
out.emit("}")
232241
out.emit("\n\n")
233242

234-
generate_guard_ips(analysis, emitter)
243+
for name, offset_str in offset_strs:
244+
out.emit(f"#undef OFFSET_OF{name}\n")
245+
out.emit("\n")
235246
outfile.write("#undef TIER_TWO\n")
236247

237248

0 commit comments

Comments
 (0)