@@ -2087,6 +2087,17 @@ def generate_tables(self, input: str) -> str:
20872087 record_function_generator .generate_recorder_tables (analysis , out )
20882088 return buf .getvalue ()
20892089
2090+ def get_slot_map_section (self , output : str ) -> str :
2091+ return output .split (
2092+ "const _PyOpcodeRecordSlotMap _PyOpcode_RecordSlotMaps[256] = {\n " ,
2093+ 1 ,
2094+ )[1 ].split ("};\n \n " , 1 )[0 ]
2095+
2096+ def assert_slot_map_lines (self , output : str , * lines : str ) -> None :
2097+ slot_map_section = self .get_slot_map_section (output )
2098+ for line in lines :
2099+ self .assertIn (line , slot_map_section )
2100+
20902101 def test_single_recording_uop_generates_count (self ):
20912102 input = """
20922103 tier2 op(_RECORD_TOS, (value -- value)) {
@@ -2145,25 +2156,67 @@ def test_four_recording_uops_rejected(self):
21452156 with self .assertRaisesRegex (ValueError , "exceeds MAX_RECORDED_VALUES" ):
21462157 self .generate_tables (input )
21472158
2148- def test_family_member_inherits_recorder_shape (self ):
2159+ def test_family_member_needs_transform_only_when_shape_changes (self ):
21492160 input = """
21502161 tier2 op(_RECORD_TOS, (value -- value)) {
21512162 RECORD_VALUE(value);
21522163 }
2164+ tier2 op(_RECORD_TOS_TYPE, (value -- value)) {
2165+ RECORD_VALUE(Py_TYPE(value));
2166+ }
21532167 op(_DO_STUFF, (value -- res)) {
21542168 res = value;
21552169 }
2156- macro(OP) = _RECORD_TOS + _DO_STUFF;
2157- inst(OP_SPECIALIZED, (value -- res)) {
2158- res = value;
2170+ macro(OP_RAW) = _RECORD_TOS + _DO_STUFF;
2171+ macro(OP_RAW_SPECIALIZED) = _RECORD_TOS_TYPE + _DO_STUFF;
2172+ family(OP_RAW, INLINE_CACHE_ENTRIES_OP_RAW) = { OP_RAW_SPECIALIZED };
2173+
2174+ macro(OP_TYPED) = _RECORD_TOS_TYPE + _DO_STUFF;
2175+ macro(OP_TYPED_SPECIALIZED) = _RECORD_TOS_TYPE + _DO_STUFF;
2176+ family(OP_TYPED, INLINE_CACHE_ENTRIES_OP_TYPED) = { OP_TYPED_SPECIALIZED };
2177+ """
2178+ output = self .generate_tables (input )
2179+ self .assert_slot_map_lines (
2180+ output ,
2181+ "[OP_RAW_SPECIALIZED] = {1, 1, {0}}" ,
2182+ "[OP_TYPED_SPECIALIZED] = {1, 0, {0}}" ,
2183+ )
2184+
2185+ def test_family_member_maps_positional_recorders_to_family_slots (self ):
2186+ input = """
2187+ tier2 op(_RECORD_TOS, (sub -- sub)) {
2188+ RECORD_VALUE(sub);
21592189 }
2190+ tier2 op(_RECORD_NOS, (container, sub -- container, sub)) {
2191+ RECORD_VALUE(container);
2192+ }
2193+ op(_DO_STUFF, (container, sub -- res)) {
2194+ res = container;
2195+ }
2196+ macro(OP) = _RECORD_TOS + _RECORD_NOS + _DO_STUFF;
2197+ macro(OP_SPECIALIZED) = _RECORD_NOS + _DO_STUFF;
21602198 family(OP, INLINE_CACHE_ENTRIES_OP) = { OP_SPECIALIZED };
21612199 """
21622200 output = self .generate_tables (input )
2163- self .assertIn ("[OP] = {1, {_RECORD_TOS_INDEX}}" , output )
2164- self .assertIn ("[OP_SPECIALIZED] = {1, {_RECORD_TOS_INDEX}}" , output )
2165- self .assertIn ("const uint8_t _PyOpcode_RecordIsFamilyOverride[256] = {" , output )
2166- self .assertIn ("[OP_SPECIALIZED] = 1" , output )
2201+ self .assert_slot_map_lines (output , "[OP_SPECIALIZED] = {1, 0, {1}}" )
2202+
2203+ def test_family_member_maps_non_positional_recorders_by_stack_shape (self ):
2204+ input = """
2205+ tier2 op(_RECORD_CALLABLE, (callable, self, args[oparg] -- callable, self, args[oparg])) {
2206+ RECORD_VALUE(callable);
2207+ }
2208+ tier2 op(_RECORD_BOUND_METHOD, (callable, self, args[oparg] -- callable, self, args[oparg])) {
2209+ RECORD_VALUE(callable);
2210+ }
2211+ op(_DO_STUFF, (callable, self, args[oparg] -- res)) {
2212+ res = callable;
2213+ }
2214+ macro(OP) = _RECORD_CALLABLE + _DO_STUFF;
2215+ macro(OP_SPECIALIZED) = _RECORD_BOUND_METHOD + _DO_STUFF;
2216+ family(OP, INLINE_CACHE_ENTRIES_OP) = { OP_SPECIALIZED };
2217+ """
2218+ output = self .generate_tables (input )
2219+ self .assert_slot_map_lines (output , "[OP_SPECIALIZED] = {1, 1, {0}}" )
21672220
21682221class TestGeneratedAbstractCases (unittest .TestCase ):
21692222 def setUp (self ) -> None :
0 commit comments