77
88
99useCSV = False
10+ groupSpecializations = False
11+ listGroupSpecializations = False
1012
1113
1214def main (arguments ):
@@ -19,6 +21,10 @@ def main(arguments):
1921 default = False )
2022 parser .add_argument ('-list-category' , type = str ,
2123 help = 'list symbols in category' )
24+ parser .add_argument ('-group-specializations' , action = 'store_true' ,
25+ help = 'group specializations' )
26+ parser .add_argument ('-list-group-specializations' , action = 'store_true' ,
27+ help = 'list group specializations' )
2228 parser .add_argument ('-csv' , dest = 'use_csv' , action = 'store_true' ,
2329 help = 'print results as csv' )
2430 parser .add_argument ('-uncategorized' , action = 'store_true' ,
@@ -34,6 +40,14 @@ def main(arguments):
3440 useCSV = True
3541 print ("Using csv" )
3642
43+ if args .group_specializations :
44+ global groupSpecializations
45+ groupSpecializations = True
46+
47+ if args .list_group_specializations :
48+ global listGroupSpecializations
49+ listGroupSpecializations = True
50+
3751 segments = parse_segments (args .bin , args .arch )
3852
3953 if args .build_categories :
@@ -82,14 +96,49 @@ def add(self, symbol):
8296 self .size += symbol .size
8397
8498
99+ class GenericSpecializationGroupKey (object ):
100+ def __init__ (self , module_name , type_name , specialization ):
101+ self .module_name = module_name
102+ self .type_name = type_name
103+ self .specialization = specialization
104+
105+ def __hash__ (self ):
106+ return hash ((self .module_name , self .type_name , self .specialization ))
107+
108+ def __eq__ (self , other ):
109+ return (self .module_name == other .module_name
110+ and self .type_name == other .type_name
111+ and self .specialization == other .specialization )
112+
113+
114+ class GenericSpecialization (object ):
115+ def __init__ (self , module_name , type_name , specialization ):
116+ self .module_name = module_name
117+ self .type_name = type_name
118+ self .specialization = specialization
119+ self .size = 0
120+ self .symbols = []
121+
122+ def add (self , symbol ):
123+ self .symbols .append (symbol )
124+ self .size += symbol .size
125+
126+ def list_symbols (self ):
127+ for symbol in self .symbols :
128+ print (" " + symbol .name + " " + str (symbol .size ))
129+
130+
85131class Categories (object ):
86132 def __init__ (self ):
87133 self .category_matching = [
88134 ['Objective-C function' , re .compile (r'.*[+-]\[' )],
89135 ['C++' , re .compile (r'_+swift' )],
90- ['Generic specialization of stdlib' ,
91- re .compile (r'.*generic specialization.* of Swift\.' )],
92- ['Generic specialization' ,
136+ ['Generic specialization of stdlib' ,
137+ re .compile (
138+ r'.*generic specialization.* of ' +
139+ r'(static )?(\(extension in Swift\):)?Swift\.'
140+ )],
141+ ['Generic specialization' ,
93142 re .compile (r'.*generic specialization' )],
94143 ['Merged function' , re .compile (r'merged ' )],
95144 ['Key path' , re .compile (r'key path' )],
@@ -178,6 +227,44 @@ def __init__(self):
178227 ['Swift unknown' , re .compile (r'^_\$s.*' )],
179228 ]
180229 self .categories = {}
230+ self .specializations = {}
231+ self .specialization_matcher = re .compile (
232+ r'.*generic specialization <(?P<spec_list>[^>]*)>.* of' +
233+ r' (static )?(\(extension in Swift\):)?(?P<module_name>[^.]*)\.' +
234+ r'(?:(?P<first_type>[^.^(^<]*)\.){0,1}' +
235+ r'(?:(?P<last_type>[^.^(^<]*)\.)*(?P<function_name>[^(^<]*)'
236+ )
237+ self .single_stdlib_specialized_type_matcher = re .compile (
238+ r'(Swift\.)?[^,^.]*$'
239+ )
240+ self .two_specialized_stdlib_types_matcher = re .compile (
241+ r'(Swift\.)?[^,^.]*, (Swift\.)?[^,^.]*$'
242+ )
243+ self .single_specialized_foundation_type_matcher = re .compile (
244+ r'(Foundation\.)?[^,^.]*$'
245+ )
246+ self .two_specialized_foundation_types_matcher = re .compile (
247+ r'(Swift\.)?[^,^.]*, (Foundation\.)?[^,^.]*$'
248+ )
249+ self .two_specialized_foundation_types_matcher2 = re .compile (
250+ r'(Foundation\.)?[^,^.]*, (Foundation\.)?[^,^.]*$'
251+ )
252+ self .two_specialized_foundation_types_matcher3 = re .compile (
253+ r'(Foundation\.)?[^,^.]*, (Swift\.)?[^,^.]*$'
254+ )
255+ self .array_type_matcher = re .compile (r'Array' )
256+ self .dictionary = re .compile (r'Array' )
257+ self .single_specialized_types_matcher = re .compile (
258+ r'(?P<module_name>[^,^.]*)\.(?P<type_name>[^,^.]*)$'
259+ )
260+ self .is_class_type_dict = {}
261+ self .stdlib_and_other_type_matcher = re .compile (
262+ r'(Swift\.)?[^,^.]*, (?P<module_name>[^,^.]*)\.(?P<type_name>[^,^.]*)$'
263+ )
264+ self .foundation_and_other_type_matcher = re .compile (
265+ r'(Foundation\.)?[^,^.]*, (?P<module_name>[^,^.]*)\.' +
266+ r'(?P<type_name>[^,^.]*)$'
267+ )
181268
182269 def categorize_by_name (self , symbol ):
183270 for c in self .category_matching :
@@ -204,12 +291,121 @@ def add(self, symbol):
204291 category_name = self .categorize_by_name (symbol )
205292 if category_name :
206293 self .add_symbol (category_name , symbol )
294+ if (groupSpecializations and
295+ category_name == 'Generic specialization of stdlib' ):
296+ self .add_specialization (symbol )
207297 return
208298 category_name = self .categorize_by_mangled_name (symbol )
209299 if category_name :
210300 self .add_symbol (category_name , symbol )
211301 else :
212302 self .add_symbol ('Unknown' , symbol )
303+ if (groupSpecializations and
304+ category_name == 'Generic specialization of stdlib' ):
305+ self .add_specialization (symbol )
306+
307+ def is_class_type_ (self , type_name , mangled_name ):
308+ match_class_name = str (len (type_name )) + type_name + 'C'
309+ if match_class_name in mangled_name :
310+ return True
311+ return False
312+
313+ def is_class_type (self , type_name , mangled_name ):
314+ existing_categorization = self .is_class_type_dict .get (type_name , 3 )
315+ if existing_categorization == 3 :
316+ is_class = self .is_class_type_ (type_name , mangled_name )
317+ self .is_class_type_dict [type_name ] = is_class
318+ return is_class
319+ else :
320+ return existing_categorization
321+
322+ def is_dictionary_like_type (self , type_name ):
323+ if 'Dictionary' in type_name :
324+ return True
325+ if 'Set' in type_name :
326+ return True
327+ return False
328+
329+ def group_library_types (self , module , type_name , specialization , mangled_name ):
330+ if module != 'Swift' :
331+ return module , type_name , specialization
332+ if self .single_stdlib_specialized_type_matcher .match (specialization ):
333+ return module , 'stdlib' , 'stdlib'
334+ if self .two_specialized_stdlib_types_matcher .match (specialization ):
335+ return module , 'stdlib' , 'stdlib'
336+ if self .single_specialized_foundation_type_matcher .match (specialization ):
337+ return module , 'stdlib' , 'foundation'
338+ if self .two_specialized_foundation_types_matcher .match (specialization ):
339+ return module , 'stdlib' , 'foundation'
340+ if self .two_specialized_foundation_types_matcher2 .match (specialization ):
341+ return module , 'stdlib' , 'foundation'
342+ if self .two_specialized_foundation_types_matcher3 .match (specialization ):
343+ return module , 'stdlib' , 'foundation'
344+ single_spec = self .single_specialized_types_matcher .match (specialization )
345+ if single_spec :
346+ is_class = self .is_class_type (single_spec .group ('type_name' ), mangled_name )
347+ is_dict = type_name is not None and self .is_dictionary_like_type (type_name )
348+ if not is_dict and is_class :
349+ return module , 'stdlib' , 'class'
350+ if is_dict and is_class :
351+ return module , 'stdlib' , 'class(dict)'
352+ stdlib_other_spec = self .stdlib_and_other_type_matcher .match (specialization )
353+ if stdlib_other_spec :
354+ is_class = self .is_class_type (stdlib_other_spec .group ('type_name' ),
355+ mangled_name )
356+ if is_class :
357+ return module , 'stdlib' , 'stdlib, class'
358+ foundation_other_spec = self .foundation_and_other_type_matcher .match (
359+ specialization )
360+ if foundation_other_spec :
361+ is_class = self .is_class_type (foundation_other_spec .group ('type_name' ),
362+ mangled_name )
363+ if is_class :
364+ return module , 'stdlib' , 'foundation, class'
365+ return module , 'stdlib' , 'other'
366+
367+ def add_specialization (self , symbol ):
368+ specialization_match = self .specialization_matcher .match (symbol .name )
369+ if specialization_match :
370+ module = specialization_match .group ('module_name' )
371+ type_name = specialization_match .group ('first_type' )
372+ specialization = specialization_match .group ('spec_list' )
373+ module , type_name , specialization = self .group_library_types (
374+ module , type_name , specialization , symbol .mangled_name )
375+ key = GenericSpecializationGroupKey (module , type_name , specialization )
376+ existing_specialization = self .specializations .get (key )
377+ if existing_specialization :
378+ existing_specialization .add (symbol )
379+ else :
380+ new_specialization = GenericSpecialization (module , type_name ,
381+ specialization )
382+ new_specialization .add (symbol )
383+ self .specializations [key ] = new_specialization
384+ else :
385+ print (symbol .name )
386+ print ('not matched' )
387+ return
388+
389+ def print_specializations (self ):
390+ values = self .specializations .values ()
391+ sorted_specializations = []
392+ for v in values :
393+ sorted_specializations .append (v )
394+
395+ if not sorted_specializations :
396+ return None
397+ else :
398+ sorted_specializations .sort (key = lambda entry : entry .specialization )
399+ sorted_specializations .sort (key = lambda entry : entry .type_name )
400+ sorted_specializations .sort (key = lambda entry : entry .module_name )
401+ print ("Specialization info" )
402+ for spec in sorted_specializations :
403+ print ("%20s.%s %20s %8d" % (spec .module_name , spec .type_name ,
404+ spec .specialization , spec .size ))
405+ if listGroupSpecializations :
406+ spec .list_symbols ()
407+ print ("" )
408+ return None
213409
214410 def categorize (self , symbols ):
215411 for sym in symbols :
@@ -361,6 +557,8 @@ def categorize(segments):
361557 categories .categorize (symbols )
362558 categories .print_summary (section .size )
363559 print ('' )
560+ if groupSpecializations :
561+ categories .print_specializations ()
364562
365563
366564def uncategorized (segments ):
@@ -382,6 +580,9 @@ def list_category(segments, category):
382580 print ('Section %22s: %8d' %
383581 (segment .name + ';' + section .name , section .size ))
384582 categories .print_category (category )
583+ print ('' )
584+ if groupSpecializations :
585+ categories .print_specializations ()
385586
386587
387588if __name__ == '__main__' :
0 commit comments