Skip to content

Commit a0551fe

Browse files
committed
update family-uniform recording
1 parent fc9da2c commit a0551fe

5 files changed

Lines changed: 29 additions & 27 deletions

File tree

Include/internal/pycore_opcode_metadata.h

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

Lib/test/test_generated_cases.py

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2181,8 +2181,8 @@ 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
)
@@ -2225,10 +2225,13 @@ def test_family_member_maps_non_positional_recorders_by_stack_shape(self):
22252225
family(OP, INLINE_CACHE_ENTRIES_OP) = { OP_SPECIALIZED };
22262226
"""
22272227
output = self.generate_tables(input)
2228+
# Head and member disagree on the slot, so the family records the raw
2229+
# _RECORD_CALLABLE form. The head consumes it directly (no transform);
2230+
# the member transforms it into _RECORD_BOUND_METHOD.
22282231
self.assert_slot_map_lines(
22292232
output,
2230-
"[OP] = {1, 1, {0}}",
2231-
"[OP_SPECIALIZED] = {1, 0, {0}}",
2233+
"[OP] = {1, 0, {0}}",
2234+
"[OP_SPECIALIZED] = {1, 1, {0}}",
22322235
)
22332236

22342237
def test_family_head_records_union_of_member_recorders(self):
@@ -2277,12 +2280,15 @@ def test_family_detects_base_and_specialized_recording_difference(self):
22772280
),
22782281
["_RECORD_TOS_TYPE"],
22792282
)
2280-
self.assertIn("[OP] = {1, {_RECORD_TOS_TYPE_INDEX}}", output)
2281-
self.assertIn("[OP_SPECIALIZED] = {1, {_RECORD_TOS_TYPE_INDEX}}", output)
2283+
# Members disagree on the slot's recorder, so the family records the
2284+
# raw _RECORD_TOS form. The head's _RECORD_TOS consumer matches it
2285+
# directly; the specialized member transforms to _RECORD_TOS_TYPE.
2286+
self.assertIn("[OP] = {1, {_RECORD_TOS_INDEX}}", output)
2287+
self.assertIn("[OP_SPECIALIZED] = {1, {_RECORD_TOS_INDEX}}", output)
22822288
self.assert_slot_map_lines(
22832289
output,
2284-
"[OP] = {1, 1, {0}}",
2285-
"[OP_SPECIALIZED] = {1, 0, {0}}",
2290+
"[OP] = {1, 0, {0}}",
2291+
"[OP_SPECIALIZED] = {1, 1, {0}}",
22862292
)
22872293

22882294
def test_family_head_falls_back_for_missing_member_slots(self):

Python/bytecodes.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3830,7 +3830,6 @@ dummy_func(
38303830

38313831
macro(FOR_ITER_VIRTUAL) =
38323832
unused/1 + // Skip over the counter
3833-
_RECORD_NOS + // Required for family-uniform recording (gh-148571).
38343833
_GUARD_NOS_ITER_VIRTUAL +
38353834
_FOR_ITER_VIRTUAL;
38363835

Python/record_functions.c.h

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

Tools/cases_generator/record_function_generator.py

Lines changed: 13 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -86,33 +86,31 @@ def get_family_record_names(
8686
record_slot_keys: dict[str, str],
8787
) -> list[str]:
8888
member_records = [instruction_records[m.name] for m in family_members]
89-
all_member_names = {n for names in member_records for n in names}
89+
head_records = instruction_records[family_head.name]
9090
records: list[str] = []
9191
slot_index: dict[str, int] = {}
9292

9393
def add(name: str) -> None:
9494
kind = record_slot_keys[name]
95-
# Prefer the raw recorder if any member uses it; otherwise the given form.
96-
raw = f"_RECORD_{kind}"
97-
source = raw if raw in all_member_names else name
9895
existing = slot_index.get(kind)
9996
if existing is None:
10097
slot_index[kind] = len(records)
101-
records.append(source)
102-
elif records[existing] != source:
103-
raise ValueError(
104-
f"Family {family_head.name} has incompatible recorders for "
105-
f"slot {kind}: {records[existing]} and {source}"
106-
)
98+
records.append(name)
99+
elif records[existing] != name:
100+
raw = f"_RECORD_{kind}"
101+
if raw not in record_slot_keys:
102+
raise ValueError(
103+
f"Family {family_head.name} has incompatible recorders for "
104+
f"slot {kind}: {records[existing]} and {name}, "
105+
f"and no raw recorder {raw} exists to use as a base."
106+
)
107+
records[existing] = raw
107108

108109
for names in member_records:
109110
for name in names:
110111
add(name)
111-
# Family head supplies any slots no member exercises.
112-
for name in instruction_records[family_head.name]:
113-
if record_slot_keys[name] not in slot_index:
114-
slot_index[record_slot_keys[name]] = len(records)
115-
records.append(name)
112+
for name in head_records:
113+
add(name)
116114
return records
117115

118116

0 commit comments

Comments
 (0)