7
7
8
8
9
9
useCSV = False
10
+ groupSpecializations = False
11
+ listGroupSpecializations = False
10
12
11
13
12
14
def main (arguments ):
@@ -19,6 +21,10 @@ def main(arguments):
19
21
default = False )
20
22
parser .add_argument ('-list-category' , type = str ,
21
23
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' )
22
28
parser .add_argument ('-csv' , dest = 'use_csv' , action = 'store_true' ,
23
29
help = 'print results as csv' )
24
30
parser .add_argument ('-uncategorized' , action = 'store_true' ,
@@ -34,6 +40,14 @@ def main(arguments):
34
40
useCSV = True
35
41
print ("Using csv" )
36
42
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
+
37
51
segments = parse_segments (args .bin , args .arch )
38
52
39
53
if args .build_categories :
@@ -82,14 +96,49 @@ def add(self, symbol):
82
96
self .size += symbol .size
83
97
84
98
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
+
85
131
class Categories (object ):
86
132
def __init__ (self ):
87
133
self .category_matching = [
88
134
['Objective-C function' , re .compile (r'.*[+-]\[' )],
89
135
['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' ,
93
142
re .compile (r'.*generic specialization' )],
94
143
['Merged function' , re .compile (r'merged ' )],
95
144
['Key path' , re .compile (r'key path' )],
@@ -178,6 +227,44 @@ def __init__(self):
178
227
['Swift unknown' , re .compile (r'^_\$s.*' )],
179
228
]
180
229
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
+ )
181
268
182
269
def categorize_by_name (self , symbol ):
183
270
for c in self .category_matching :
@@ -204,12 +291,121 @@ def add(self, symbol):
204
291
category_name = self .categorize_by_name (symbol )
205
292
if category_name :
206
293
self .add_symbol (category_name , symbol )
294
+ if (groupSpecializations and
295
+ category_name == 'Generic specialization of stdlib' ):
296
+ self .add_specialization (symbol )
207
297
return
208
298
category_name = self .categorize_by_mangled_name (symbol )
209
299
if category_name :
210
300
self .add_symbol (category_name , symbol )
211
301
else :
212
302
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
213
409
214
410
def categorize (self , symbols ):
215
411
for sym in symbols :
@@ -361,6 +557,8 @@ def categorize(segments):
361
557
categories .categorize (symbols )
362
558
categories .print_summary (section .size )
363
559
print ('' )
560
+ if groupSpecializations :
561
+ categories .print_specializations ()
364
562
365
563
366
564
def uncategorized (segments ):
@@ -382,6 +580,9 @@ def list_category(segments, category):
382
580
print ('Section %22s: %8d' %
383
581
(segment .name + ';' + section .name , section .size ))
384
582
categories .print_category (category )
583
+ print ('' )
584
+ if groupSpecializations :
585
+ categories .print_specializations ()
385
586
386
587
387
588
if __name__ == '__main__' :
0 commit comments