summaryrefslogtreecommitdiffstats
path: root/Tools/cases_generator
diff options
context:
space:
mode:
authorSam Gross <colesbury@gmail.com>2024-09-24 20:08:18 (GMT)
committerGitHub <noreply@github.com>2024-09-24 20:08:18 (GMT)
commitf4997bb3ac961d6aaf07ce650cd074e28ce6ccd0 (patch)
tree6c82b0fadd282e74c8f81de4a3966666fd210196 /Tools/cases_generator
parentd3c76dff444046504754a437dceebc9a9c87ef18 (diff)
downloadcpython-f4997bb3ac961d6aaf07ce650cd074e28ce6ccd0.zip
cpython-f4997bb3ac961d6aaf07ce650cd074e28ce6ccd0.tar.gz
cpython-f4997bb3ac961d6aaf07ce650cd074e28ce6ccd0.tar.bz2
gh-123923: Defer refcounting for `f_funcobj` in `_PyInterpreterFrame` (#124026)
Use a `_PyStackRef` and defer the reference to `f_funcobj` when possible. This avoids some reference count contention in the common case of executing the same code object from multiple threads concurrently in the free-threaded build.
Diffstat (limited to 'Tools/cases_generator')
-rw-r--r--Tools/cases_generator/analyzer.py12
-rw-r--r--Tools/cases_generator/generators_common.py9
2 files changed, 17 insertions, 4 deletions
diff --git a/Tools/cases_generator/analyzer.py b/Tools/cases_generator/analyzer.py
index 3cc36b6..0680c21 100644
--- a/Tools/cases_generator/analyzer.py
+++ b/Tools/cases_generator/analyzer.py
@@ -365,12 +365,24 @@ def analyze_deferred_refs(node: parser.InstDef) -> dict[lexer.Token, str | None]
offset += 1
return []
+ def in_frame_push(idx: int) -> bool:
+ for tkn in reversed(node.block.tokens[: idx - 1]):
+ if tkn.kind == "SEMI" or tkn.kind == "LBRACE" or tkn.kind == "RBRACE":
+ return False
+ if tkn.kind == "IDENTIFIER" and tkn.text == "_PyFrame_PushUnchecked":
+ return True
+ return False
+
refs: dict[lexer.Token, str | None] = {}
for idx, tkn in enumerate(node.block.tokens):
if tkn.kind != "IDENTIFIER" or tkn.text != "PyStackRef_FromPyObjectNew":
continue
if idx == 0 or node.block.tokens[idx - 1].kind != "EQUALS":
+ if in_frame_push(idx):
+ # PyStackRef_FromPyObjectNew() is called in _PyFrame_PushUnchecked()
+ refs[tkn] = None
+ continue
raise analysis_error("Expected '=' before PyStackRef_FromPyObjectNew", tkn)
lhs = find_assignment_target(idx)
diff --git a/Tools/cases_generator/generators_common.py b/Tools/cases_generator/generators_common.py
index 2f8fcce..4cfd4ad 100644
--- a/Tools/cases_generator/generators_common.py
+++ b/Tools/cases_generator/generators_common.py
@@ -200,15 +200,16 @@ class Emitter:
stack: Stack,
inst: Instruction | None,
) -> None:
- self.out.emit(tkn)
- emit_to(self.out, tkn_iter, "SEMI")
- self.out.emit(";\n")
-
target = uop.deferred_refs[tkn]
if target is None:
# An assignment we don't handle, such as to a pointer or array.
+ self.out.emit(tkn)
return
+ self.out.emit(tkn)
+ emit_to(self.out, tkn_iter, "SEMI")
+ self.out.emit(";\n")
+
# Flush the assignment to the stack. Note that we don't flush the
# stack pointer here, and instead are currently relying on initializing
# unused portions of the stack to NULL.