Bug 1370719 - Shrink ElementData by moving pseudo count to type. r=bholley
`ElementStyles` holds an optional list of values for each eager pseudo-element.
However, the type was declared as a slice instead of a fixed size array, so an
extra 8 bytes were being allocated to hold the size, even though it never
changes.
Moving the constant size into the type reduces `ElementStyles` and `ElementData`
by 8 bytes.
MozReview-Commit-ID: GaO6DKFxUMo
--- a/servo/components/style/data.rs
+++ b/servo/components/style/data.rs
@@ -95,18 +95,34 @@ impl RestyleData {
/// Returns whether this element has been part of a restyle.
pub fn contains_restyle_data(&self) -> bool {
self.is_restyle() || !self.hint.is_empty() || !self.damage.is_empty()
}
}
/// A list of computed values for eagerly-cascaded pseudo-elements.
/// Lazily-allocated.
-#[derive(Clone, Debug)]
-pub struct EagerPseudoStyles(pub Option<Box<[Option<Arc<ComputedValues>>]>>);
+#[derive(Debug)]
+pub struct EagerPseudoStyles(pub Option<Box<[Option<Arc<ComputedValues>>; EAGER_PSEUDO_COUNT]>>);
+
+// Manually implement `Clone` here because the derived impl of `Clone` for
+// array types assumes the value inside is `Copy`.
+impl Clone for EagerPseudoValues {
+ fn clone(&self) -> Self {
+ if self.0.is_none() {
+ return EagerPseudoValues(None)
+ }
+ let self_values = self.0.as_ref().unwrap();
+ let mut values: [Option<Arc<ComputedValues>>; EAGER_PSEUDO_COUNT] = Default::default();
+ for i in 0..EAGER_PSEUDO_COUNT {
+ values[i] = self_values[i].clone();
+ }
+ EagerPseudoValues(Some(Box::new(values)))
+ }
+}
impl EagerPseudoStyles {
/// Returns whether there are any pseudo values.
pub fn is_empty(&self) -> bool {
self.0.is_none()
}
/// Returns a reference to the values for a given eager pseudo, if it exists.
@@ -124,17 +140,17 @@ impl EagerPseudoStyles {
/// Returns true if the EagerPseudoStyles has the values for |pseudo|.
pub fn has(&self, pseudo: &PseudoElement) -> bool {
self.get(pseudo).is_some()
}
/// Sets the values for the eager pseudo.
pub fn set(&mut self, pseudo: &PseudoElement, value: Arc<ComputedValues>) {
if self.0.is_none() {
- self.0 = Some(vec![None; EAGER_PSEUDO_COUNT].into_boxed_slice());
+ self.0 = Some(Box::new(Default::default()));
}
self.0.as_mut().unwrap()[pseudo.eager_index()] = Some(value);
}
/// Inserts a pseudo-element. The pseudo-element must not already exist.
pub fn insert(&mut self, pseudo: &PseudoElement, value: Arc<ComputedValues>) {
debug_assert!(!self.has(pseudo));
self.set(pseudo, value);
--- a/servo/tests/unit/stylo/size_of.rs
+++ b/servo/tests/unit/stylo/size_of.rs
@@ -27,19 +27,19 @@ fn size_of_selectors_dummy_types() {
// The size of this is critical to performance on the bloom-basic microbenchmark.
// When iterating over a large Rule array, we want to be able to fast-reject
// selectors (with the inline hashes) with as few cache misses as possible.
size_of_test!(test_size_of_rule, style::stylist::Rule, 32);
size_of_test!(test_size_of_option_arc_cv, Option<Arc<ComputedValues>>, 8);
size_of_test!(test_size_of_option_rule_node, Option<StrongRuleNode>, 8);
-size_of_test!(test_size_of_element_styles, ElementStyles, 24);
+size_of_test!(test_size_of_element_styles, ElementStyles, 16);
size_of_test!(test_size_of_restyle_data, RestyleData, 8);
-size_of_test!(test_size_of_element_data, ElementData, 32);
+size_of_test!(test_size_of_element_data, ElementData, 24);
size_of_test!(test_size_of_property_declaration, style::properties::PropertyDeclaration, 32);
size_of_test!(test_size_of_application_declaration_block, ApplicableDeclarationBlock, 24);
// FIXME(bholley): This can shrink with a little bit of work.
// See https://github.com/servo/servo/issues/17280
size_of_test!(test_size_of_rule_node, RuleNode, 80);