style/use_counters/
mod.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
5//! Various stuff for CSS property use counters.
6
7use crate::properties::{property_counts, CountedUnknownProperty, NonCustomPropertyId};
8use std::sync::atomic::{AtomicUsize, Ordering};
9
10#[cfg(target_pointer_width = "64")]
11const BITS_PER_ENTRY: usize = 64;
12
13#[cfg(target_pointer_width = "32")]
14const BITS_PER_ENTRY: usize = 32;
15
16/// One bit per each non-custom CSS property.
17#[derive(Debug, Default)]
18pub struct CountedUnknownPropertyUseCounters {
19    storage:
20        [AtomicUsize; (property_counts::COUNTED_UNKNOWN + BITS_PER_ENTRY - 1) / BITS_PER_ENTRY],
21}
22
23/// One bit per each non-custom CSS property.
24#[derive(Debug, Default)]
25pub struct NonCustomPropertyUseCounters {
26    storage: [AtomicUsize; (property_counts::NON_CUSTOM + BITS_PER_ENTRY - 1) / BITS_PER_ENTRY],
27}
28
29/// A custom style use counter that we may want to record.
30#[derive(Copy, Clone, Debug)]
31#[repr(u32)]
32pub enum CustomUseCounter {
33    /// Whether we are likely to be using relative URIs that depend on our path depth.
34    MaybeHasPathBaseUriDependency = 0,
35    /// Whether we are likely to be using relative URIs that depend on our full URI.
36    MaybeHasFullBaseUriDependency,
37    /// Dummy value, used for indexing purposes.
38    Last,
39}
40
41impl CustomUseCounter {
42    #[inline]
43    fn bit(self) -> usize {
44        self as usize
45    }
46}
47
48/// One bit for each custom use counter.
49#[derive(Debug, Default)]
50pub struct CustomUseCounters {
51    storage:
52        [AtomicUsize; ((CustomUseCounter::Last as usize) + BITS_PER_ENTRY - 1) / BITS_PER_ENTRY],
53}
54
55macro_rules! use_counters_methods {
56    ($id: ident) => {
57        /// Returns the bucket a given property belongs in, and the bitmask for that
58        /// property.
59        #[inline(always)]
60        fn bucket_and_pattern(id: $id) -> (usize, usize) {
61            let bit = id.bit();
62            let bucket = bit / BITS_PER_ENTRY;
63            let bit_in_bucket = bit % BITS_PER_ENTRY;
64            (bucket, 1 << bit_in_bucket)
65        }
66
67        /// Record that a given property ID has been parsed.
68        #[inline]
69        pub fn record(&self, id: $id) {
70            let (bucket, pattern) = Self::bucket_and_pattern(id);
71            let bucket = &self.storage[bucket];
72            bucket.fetch_or(pattern, Ordering::Relaxed);
73        }
74
75        /// Returns whether a given property ID has been recorded
76        /// earlier.
77        #[inline]
78        pub fn recorded(&self, id: $id) -> bool {
79            let (bucket, pattern) = Self::bucket_and_pattern(id);
80            self.storage[bucket].load(Ordering::Relaxed) & pattern != 0
81        }
82
83        /// Merge `other` into `self`.
84        #[inline]
85        fn merge(&self, other: &Self) {
86            for (bucket, other_bucket) in self.storage.iter().zip(other.storage.iter()) {
87                bucket.fetch_or(other_bucket.load(Ordering::Relaxed), Ordering::Relaxed);
88            }
89        }
90    };
91}
92
93impl CountedUnknownPropertyUseCounters {
94    use_counters_methods!(CountedUnknownProperty);
95}
96
97impl NonCustomPropertyUseCounters {
98    use_counters_methods!(NonCustomPropertyId);
99}
100
101impl CustomUseCounters {
102    use_counters_methods!(CustomUseCounter);
103}
104
105/// The use-counter data related to a given document we want to store.
106#[derive(Debug, Default)]
107pub struct UseCounters {
108    /// The counters for non-custom properties that have been parsed in the
109    /// document's stylesheets.
110    pub non_custom_properties: NonCustomPropertyUseCounters,
111    /// The counters for css properties which we haven't implemented yet.
112    pub counted_unknown_properties: CountedUnknownPropertyUseCounters,
113    /// Custom counters for virtually everything else.
114    pub custom: CustomUseCounters,
115}
116
117impl UseCounters {
118    /// Merge the use counters.
119    ///
120    /// Used for parallel parsing, where we parse off-main-thread.
121    #[inline]
122    pub fn merge(&self, other: &Self) {
123        self.non_custom_properties
124            .merge(&other.non_custom_properties);
125        self.counted_unknown_properties
126            .merge(&other.counted_unknown_properties);
127        self.custom.merge(&other.custom);
128    }
129}
130
131impl Clone for UseCounters {
132    fn clone(&self) -> Self {
133        let result = Self::default();
134        result.merge(self);
135        result
136    }
137}