Skip to content

Commit 5617cec

Browse files
committed
fix recorder
1 parent 246fe14 commit 5617cec

5 files changed

Lines changed: 163 additions & 102 deletions

File tree

Lib/test/test_generated_cases.py

Lines changed: 38 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2181,12 +2181,37 @@ def test_family_member_needs_transform_only_when_shape_changes(self):
21812181
output = self.generate_tables(input)
21822182
self.assert_slot_map_lines(
21832183
output,
2184-
"[OP_RAW] = {1, 1, {0}}",
2185-
"[OP_RAW_SPECIALIZED] = {1, 0, {0}}",
2184+
"[OP_RAW] = {1, 0, {0}}",
2185+
"[OP_RAW_SPECIALIZED] = {1, 1, {0}}",
21862186
"[OP_TYPED] = {1, 0, {0}}",
21872187
"[OP_TYPED_SPECIALIZED] = {1, 0, {0}}",
21882188
)
21892189

2190+
def test_record_transform_generated_from_recording_uop(self):
2191+
input = """
2192+
tier2 op(_RECORD_TOS, (tos -- tos)) {
2193+
RECORD_VALUE(PyStackRef_AsPyObjectBorrow(tos));
2194+
}
2195+
tier2 op(_RECORD_TOS_TYPE, (tos -- tos)) {
2196+
RECORD_VALUE(Py_TYPE(PyStackRef_AsPyObjectBorrow(tos)));
2197+
}
2198+
op(_DO_STUFF, (tos -- res)) {
2199+
res = tos;
2200+
}
2201+
macro(OP) = _RECORD_TOS + _DO_STUFF;
2202+
macro(OP_SPECIALIZED) = _RECORD_TOS_TYPE + _DO_STUFF;
2203+
family(OP, INLINE_CACHE_ENTRIES_OP) = { OP_SPECIALIZED };
2204+
"""
2205+
output = self.generate_tables(input)
2206+
self.assertIn("_PyOpcode_RecordTransform_TOS_TYPE", output)
2207+
self.assertIn("tos = PyStackRef_FromPyObjectBorrow(recorded_value);", output)
2208+
self.assertIn(
2209+
"transformed_value = (PyObject *)Py_TYPE(PyStackRef_AsPyObjectBorrow(tos));",
2210+
output,
2211+
)
2212+
self.assertIn("return _PyOpcode_RecordTransform_TOS_TYPE(value);", output)
2213+
self.assertNotIn("record_trace_transform_to_type", output)
2214+
21902215
def test_family_member_maps_positional_recorders_to_family_slots(self):
21912216
input = """
21922217
tier2 op(_RECORD_TOS, (sub -- sub)) {
@@ -2227,8 +2252,8 @@ def test_family_member_maps_non_positional_recorders_by_stack_shape(self):
22272252
output = self.generate_tables(input)
22282253
self.assert_slot_map_lines(
22292254
output,
2230-
"[OP] = {1, 1, {0}}",
2231-
"[OP_SPECIALIZED] = {1, 0, {0}}",
2255+
"[OP] = {1, 0, {0}}",
2256+
"[OP_SPECIALIZED] = {1, 1, {0}}",
22322257
)
22332258

22342259
def test_family_head_records_union_of_member_recorders(self):
@@ -2243,7 +2268,12 @@ def test_family_head_records_union_of_member_recorders(self):
22432268
macro(OP_SPECIALIZED) = _RECORD_TOS + _DO_STUFF;
22442269
family(OP, INLINE_CACHE_ENTRIES_OP) = { OP_SPECIALIZED };
22452270
"""
2271+
analysis = self.analyze_input(input)
22462272
output = self.generate_tables(input)
2273+
self.assertEqual(
2274+
analysis.families["OP"].member_record_names,
2275+
("_RECORD_TOS",),
2276+
)
22472277
self.assertIn("[OP] = {1, {_RECORD_TOS_INDEX}}", output)
22482278
self.assertIn("[OP_SPECIALIZED] = {1, {_RECORD_TOS_INDEX}}", output)
22492279
self.assert_slot_map_lines(output, "[OP_SPECIALIZED] = {1, 0, {0}}")
@@ -2277,12 +2307,12 @@ def test_family_detects_base_and_specialized_recording_difference(self):
22772307
),
22782308
["_RECORD_TOS_TYPE"],
22792309
)
2280-
self.assertIn("[OP] = {1, {_RECORD_TOS_TYPE_INDEX}}", output)
2281-
self.assertIn("[OP_SPECIALIZED] = {1, {_RECORD_TOS_TYPE_INDEX}}", output)
2310+
self.assertIn("[OP] = {1, {_RECORD_TOS_INDEX}}", output)
2311+
self.assertIn("[OP_SPECIALIZED] = {1, {_RECORD_TOS_INDEX}}", output)
22822312
self.assert_slot_map_lines(
22832313
output,
2284-
"[OP] = {1, 1, {0}}",
2285-
"[OP_SPECIALIZED] = {1, 0, {0}}",
2314+
"[OP] = {1, 0, {0}}",
2315+
"[OP_SPECIALIZED] = {1, 1, {0}}",
22862316
)
22872317

22882318
def test_family_head_falls_back_for_missing_member_slots(self):

Python/optimizer.c

Lines changed: 0 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -660,44 +660,6 @@ is_terminator(const _PyUOpInstruction *uop)
660660
);
661661
}
662662

663-
static PyObject *
664-
record_trace_transform_to_type(PyObject *value)
665-
{
666-
PyObject *tp = Py_NewRef((PyObject *)Py_TYPE(value));
667-
Py_DECREF(value);
668-
return tp;
669-
}
670-
671-
/* _RECORD_NOS_GEN_FUNC and _RECORD_3OS_GEN_FUNC record the raw receiver.
672-
* If it is a generator, return its function object; otherwise return NULL.
673-
*/
674-
static PyObject *
675-
record_trace_transform_gen_func(PyObject *value)
676-
{
677-
PyObject *func = NULL;
678-
if (PyGen_Check(value)) {
679-
_PyStackRef f = ((PyGenObject *)value)->gi_iframe.f_funcobj;
680-
if (!PyStackRef_IsNull(f)) {
681-
func = Py_NewRef(PyStackRef_AsPyObjectBorrow(f));
682-
}
683-
}
684-
Py_DECREF(value);
685-
return func;
686-
}
687-
688-
/* _RECORD_BOUND_METHOD records the raw callable.
689-
* Keep it only for bound methods; otherwise return NULL.
690-
*/
691-
static PyObject *
692-
record_trace_transform_bound_method(PyObject *value)
693-
{
694-
if (Py_TYPE(value) == &PyMethod_Type) {
695-
return value;
696-
}
697-
Py_DECREF(value);
698-
return NULL;
699-
}
700-
701663
/* Returns 1 on success (added to trace), 0 on trace end.
702664
*/
703665
// gh-142543: inlining this function causes stack overflows

Python/record_functions.c.h

Lines changed: 43 additions & 6 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: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -322,6 +322,17 @@ class Family:
322322
size: str
323323
members: list[Instruction]
324324

325+
@property
326+
def member_record_names(self) -> tuple[str, ...]:
327+
seen: set[str] = set()
328+
names: list[str] = []
329+
for member in self.members:
330+
for part in member.parts:
331+
if part.properties.records_value and part.name not in seen:
332+
seen.add(part.name)
333+
names.append(part.name)
334+
return tuple(names)
335+
325336
def dump(self, indent: str) -> None:
326337
print(indent, self.name, "= ", ", ".join([m.name for m in self.members]))
327338

0 commit comments

Comments
 (0)