Skip to main content

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: [AtomicUsize; property_counts::COUNTED_UNKNOWN.div_ceil(BITS_PER_ENTRY)],
20}
21
22/// One bit per each non-custom CSS property.
23#[derive(Debug, Default)]
24pub struct NonCustomPropertyUseCounters {
25    storage: [AtomicUsize; property_counts::NON_CUSTOM.div_ceil(BITS_PER_ENTRY)],
26}
27
28/// A custom style use counter that we may want to record.
29#[derive(Copy, Clone, Debug)]
30#[repr(u32)]
31pub enum CustomUseCounter {
32    /// Whether we reference a non-local uri at all.
33    HasNonLocalUriDependency = 0,
34    /// Whether we are likely to be using relative URIs that depend on our path depth.
35    MaybeHasPathBaseUriDependency,
36    /// Whether we are likely to be using relative URIs that depend on our full URI.
37    MaybeHasFullBaseUriDependency,
38    /// Dummy value, used for indexing purposes.
39    Last,
40}
41
42impl CustomUseCounter {
43    #[inline]
44    fn bit(self) -> usize {
45        self as usize
46    }
47}
48
49/// One bit for each custom use counter.
50#[derive(Debug, Default)]
51pub struct CustomUseCounters {
52    storage: [AtomicUsize; (CustomUseCounter::Last as usize).div_ceil(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}