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 reference a non-local uri at all.
34    HasNonLocalUriDependency = 0,
35    /// Whether we are likely to be using relative URIs that depend on our path depth.
36    MaybeHasPathBaseUriDependency,
37    /// Whether we are likely to be using relative URIs that depend on our full URI.
38    MaybeHasFullBaseUriDependency,
39    /// Dummy value, used for indexing purposes.
40    Last,
41}
42
43impl CustomUseCounter {
44    #[inline]
45    fn bit(self) -> usize {
46        self as usize
47    }
48}
49
50/// One bit for each custom use counter.
51#[derive(Debug, Default)]
52pub struct CustomUseCounters {
53    storage:
54        [AtomicUsize; ((CustomUseCounter::Last as usize) + BITS_PER_ENTRY - 1) / BITS_PER_ENTRY],
55}
56
57macro_rules! use_counters_methods {
58    ($id: ident) => {
59        /// Returns the bucket a given property belongs in, and the bitmask for that
60        /// property.
61        #[inline(always)]
62        fn bucket_and_pattern(id: $id) -> (usize, usize) {
63            let bit = id.bit();
64            let bucket = bit / BITS_PER_ENTRY;
65            let bit_in_bucket = bit % BITS_PER_ENTRY;
66            (bucket, 1 << bit_in_bucket)
67        }
68
69        /// Record that a given property ID has been parsed.
70        #[inline]
71        pub fn record(&self, id: $id) {
72            let (bucket, pattern) = Self::bucket_and_pattern(id);
73            let bucket = &self.storage[bucket];
74            bucket.fetch_or(pattern, Ordering::Relaxed);
75        }
76
77        /// Returns whether a given property ID has been recorded
78        /// earlier.
79        #[inline]
80        pub fn recorded(&self, id: $id) -> bool {
81            let (bucket, pattern) = Self::bucket_and_pattern(id);
82            self.storage[bucket].load(Ordering::Relaxed) & pattern != 0
83        }
84
85        /// Merge `other` into `self`.
86        #[inline]
87        fn merge(&self, other: &Self) {
88            for (bucket, other_bucket) in self.storage.iter().zip(other.storage.iter()) {
89                bucket.fetch_or(other_bucket.load(Ordering::Relaxed), Ordering::Relaxed);
90            }
91        }
92    };
93}
94
95impl CountedUnknownPropertyUseCounters {
96    use_counters_methods!(CountedUnknownProperty);
97}
98
99impl NonCustomPropertyUseCounters {
100    use_counters_methods!(NonCustomPropertyId);
101}
102
103impl CustomUseCounters {
104    use_counters_methods!(CustomUseCounter);
105}
106
107/// The use-counter data related to a given document we want to store.
108#[derive(Debug, Default)]
109pub struct UseCounters {
110    /// The counters for non-custom properties that have been parsed in the
111    /// document's stylesheets.
112    pub non_custom_properties: NonCustomPropertyUseCounters,
113    /// The counters for css properties which we haven't implemented yet.
114    pub counted_unknown_properties: CountedUnknownPropertyUseCounters,
115    /// Custom counters for virtually everything else.
116    pub custom: CustomUseCounters,
117}
118
119impl UseCounters {
120    /// Merge the use counters.
121    ///
122    /// Used for parallel parsing, where we parse off-main-thread.
123    #[inline]
124    pub fn merge(&self, other: &Self) {
125        self.non_custom_properties
126            .merge(&other.non_custom_properties);
127        self.counted_unknown_properties
128            .merge(&other.counted_unknown_properties);
129        self.custom.merge(&other.custom);
130    }
131}
132
133impl Clone for UseCounters {
134    fn clone(&self) -> Self {
135        let result = Self::default();
136        result.merge(self);
137        result
138    }
139}