Chromium Code Reviews| 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 |