OLD | NEW |
---|---|
1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
2 # Copyright 2016 The Chromium Authors. All rights reserved. | 2 # Copyright 2016 The Chromium Authors. All rights reserved. |
3 # Use of this source code is governed by a BSD-style license that can be | 3 # Use of this source code is governed by a BSD-style license that can be |
4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
5 | 5 |
6 import math | 6 import math |
7 import sys | 7 import sys |
8 | 8 |
9 import json5_generator | 9 import json5_generator |
10 import template_expander | 10 import template_expander |
11 import make_style_builder | 11 import make_style_builder |
12 | 12 |
13 from name_utilities import ( | 13 from name_utilities import ( |
14 enum_for_css_keyword, enum_type_name, enum_value_name, class_member_name, me thod_name, | 14 enum_for_css_keyword, enum_type_name, enum_value_name, class_member_name, me thod_name, |
15 class_name, join_name | 15 class_name, join_name |
16 ) | 16 ) |
17 from collections import defaultdict, OrderedDict | 17 from collections import defaultdict, OrderedDict |
18 from itertools import chain | 18 from itertools import chain |
19 | 19 |
20 # We want to sort fields by their alignment sizes. Specifying the exact alignmen t requirements | |
Bugs Nash
2017/04/28 00:16:51
Add to the comment where the types hard coded here
shend
2017/04/28 01:00:31
done
| |
21 # for each type is impossible because it's platform specific. Instead, we will d efine an ordering | |
22 # on types, from largest alignment size to smallest. This heuristic should work most of the time. | |
23 ALIGNMENT_ORDER = [ | |
24 'FillLayer', 'BorderData', # Aligns like a void * | |
25 'double', | |
26 'LengthBox', 'Length', 'float', | |
27 'Color', 'unsigned', 'int', | |
28 'short', | |
29 'char', | |
30 'bool' | |
31 ] | |
32 | |
20 # TODO(shend): Improve documentation and add docstrings. | 33 # TODO(shend): Improve documentation and add docstrings. |
21 | 34 |
22 | 35 |
23 def _flatten_list(x): | 36 def _flatten_list(x): |
24 """Flattens a list of lists into a single list.""" | 37 """Flattens a list of lists into a single list.""" |
25 return list(chain.from_iterable(x)) | 38 return list(chain.from_iterable(x)) |
26 | 39 |
27 | 40 |
28 def _num_32_bit_words_for_bit_fields(bit_fields): | 41 def _num_32_bit_words_for_bit_fields(bit_fields): |
29 """Gets the number of 32 bit unsigned integers needed store a list of bit fi elds.""" | 42 """Gets the number of 32 bit unsigned integers needed store a list of bit fi elds.""" |
(...skipping 235 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
265 | 278 |
266 # TODO(shend): Get rid of the property/nonproperty field roles. | 279 # TODO(shend): Get rid of the property/nonproperty field roles. |
267 # If the field has_custom_compare_and_copy, then it does not appear in | 280 # If the field has_custom_compare_and_copy, then it does not appear in |
268 # ComputedStyle::operator== and ComputedStyle::CopyNonInheritedFromC ached. | 281 # ComputedStyle::operator== and ComputedStyle::CopyNonInheritedFromC ached. |
269 field_role = 'nonproperty' if property_['has_custom_compare_and_copy '] else 'property' | 282 field_role = 'nonproperty' if property_['has_custom_compare_and_copy '] else 'property' |
270 fields.append(_create_field(field_role, property_)) | 283 fields.append(_create_field(field_role, property_)) |
271 | 284 |
272 return fields | 285 return fields |
273 | 286 |
274 | 287 |
275 def _reorder_fields(fields): | 288 def _reorder_bit_fields(bit_fields): |
276 """ | |
277 Returns a list of fields ordered to minimise padding. | |
278 """ | |
279 # Separate out bit fields from non bit fields | |
280 bit_fields = [field for field in fields if field.is_bit_field] | |
281 non_bit_fields = [field for field in fields if not field.is_bit_field] | |
282 | |
283 # Since fields cannot cross word boundaries, in order to minimize | 289 # Since fields cannot cross word boundaries, in order to minimize |
284 # padding, group fields into buckets so that as many buckets as possible | 290 # padding, group fields into buckets so that as many buckets as possible |
285 # are exactly 32 bits. Although this greedy approach may not always | 291 # are exactly 32 bits. Although this greedy approach may not always |
286 # produce the optimal solution, we add a static_assert to the code to | 292 # produce the optimal solution, we add a static_assert to the code to |
287 # ensure ComputedStyleBase results in the expected size. If that | 293 # ensure ComputedStyleBase results in the expected size. If that |
288 # static_assert fails, this code is falling into the small number of | 294 # static_assert fails, this code is falling into the small number of |
289 # cases that are suboptimal, and may need to be rethought. | 295 # cases that are suboptimal, and may need to be rethought. |
290 # For more details on packing bit fields to reduce padding, see: | 296 # For more details on packing bit fields to reduce padding, see: |
291 # http://www.catb.org/esr/structure-packing/#_bitfields | 297 # http://www.catb.org/esr/structure-packing/#_bitfields |
292 field_buckets = [] | 298 field_buckets = [] |
293 # Consider fields in descending order of size to reduce fragmentation | 299 # Consider fields in descending order of size to reduce fragmentation |
294 # when they are selected. Ties broken in alphabetical order by name. | 300 # when they are selected. Ties broken in alphabetical order by name. |
295 for field in sorted(bit_fields, key=lambda f: (-f.size, f.name)): | 301 for field in sorted(bit_fields, key=lambda f: (-f.size, f.name)): |
296 added_to_bucket = False | 302 added_to_bucket = False |
297 # Go through each bucket and add this field if it will not increase | 303 # Go through each bucket and add this field if it will not increase |
298 # the bucket's size to larger than 32 bits. Otherwise, make a new | 304 # the bucket's size to larger than 32 bits. Otherwise, make a new |
299 # bucket containing only this field. | 305 # bucket containing only this field. |
300 for bucket in field_buckets: | 306 for bucket in field_buckets: |
301 if sum(f.size for f in bucket) + field.size <= 32: | 307 if sum(f.size for f in bucket) + field.size <= 32: |
302 bucket.append(field) | 308 bucket.append(field) |
303 added_to_bucket = True | 309 added_to_bucket = True |
304 break | 310 break |
305 if not added_to_bucket: | 311 if not added_to_bucket: |
306 field_buckets.append([field]) | 312 field_buckets.append([field]) |
307 | 313 |
314 return _flatten_list(field_buckets) | |
315 | |
316 | |
317 def _reorder_non_bit_fields(non_bit_fields): | |
318 # A general rule of thumb is to sort members by their alignment requirement | |
319 # (from biggest aligned to smallest). If we don't know its alignment, we | |
320 # assume the worst and put it at the front. | |
321 known_alignment = [field for field in non_bit_fields if field.type_name in A LIGNMENT_ORDER] | |
Bugs Nash
2017/04/28 00:16:51
nit: swap these lines so that unknown_alignment co
shend
2017/04/28 01:00:30
done
| |
322 unknown_alignment = [field for field in non_bit_fields if field.type_name no t in ALIGNMENT_ORDER] | |
323 return unknown_alignment + list(sorted(known_alignment, key=lambda f: ALIGNM ENT_ORDER.index(f.type_name))) | |
324 | |
325 | |
326 def _reorder_fields(fields): | |
327 """ | |
328 Returns a list of fields ordered to minimise padding. | |
329 """ | |
330 # Separate out bit fields from non bit fields | |
331 bit_fields = [field for field in fields if field.is_bit_field] | |
332 non_bit_fields = [field for field in fields if not field.is_bit_field] | |
333 | |
308 # Non bit fields go first, then the bit fields. | 334 # Non bit fields go first, then the bit fields. |
309 return list(non_bit_fields) + _flatten_list(field_buckets) | 335 return _reorder_non_bit_fields(non_bit_fields) + _reorder_bit_fields(bit_fie lds) |
310 | 336 |
311 | 337 |
312 class ComputedStyleBaseWriter(make_style_builder.StyleBuilderWriter): | 338 class ComputedStyleBaseWriter(make_style_builder.StyleBuilderWriter): |
313 def __init__(self, json5_file_paths): | 339 def __init__(self, json5_file_paths): |
314 # Read CSS properties | 340 # Read CSS properties |
315 super(ComputedStyleBaseWriter, self).__init__([json5_file_paths[0]]) | 341 super(ComputedStyleBaseWriter, self).__init__([json5_file_paths[0]]) |
316 | 342 |
317 # Ignore shorthand properties | 343 # Ignore shorthand properties |
318 for property_ in self._properties.values(): | 344 for property_ in self._properties.values(): |
319 if property_['field_template'] is not None: | 345 if property_['field_template'] is not None: |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
378 | 404 |
379 @template_expander.use_jinja('ComputedStyleBaseConstants.h.tmpl') | 405 @template_expander.use_jinja('ComputedStyleBaseConstants.h.tmpl') |
380 def generate_base_computed_style_constants(self): | 406 def generate_base_computed_style_constants(self): |
381 return { | 407 return { |
382 'properties': self._properties, | 408 'properties': self._properties, |
383 'enums': self._generated_enums, | 409 'enums': self._generated_enums, |
384 } | 410 } |
385 | 411 |
386 if __name__ == '__main__': | 412 if __name__ == '__main__': |
387 json5_generator.Maker(ComputedStyleBaseWriter).main() | 413 json5_generator.Maker(ComputedStyleBaseWriter).main() |
OLD | NEW |