New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Pack bloom filter hashes better and save a word on Rule #17281
Merged
+253
−98
Merged
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
cf982d1
Shift by KEY_SIZE instead of something larger.
bholley 6e3e7b2
Pack the fourth ancestor hash into the upper byte of the first three …
bholley 3afab14
Make source_order u32 and shrink Rule.
bholley 0caad2f
Use even fewer bits for source order and shrink ApplicableDeclaration…
bholley a98fff1
Hoist ApplicableDeclaration{Block,List} into a separate file.
bholley 2d412d4
Add a size_of test for RuleNode.
bholley File filter...
Filter file types
Jump to…
Jump to file
Failed to load files.
| @@ -0,0 +1,137 @@ | ||
| /* This Source Code Form is subject to the terms of the Mozilla Public | ||
| * License, v. 2.0. If a copy of the MPL was not distributed with this | ||
| * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | ||
|
|
||
| //! Applicable declarations management. | ||
|
|
||
| use properties::PropertyDeclarationBlock; | ||
| use rule_tree::{CascadeLevel, StyleSource}; | ||
| use shared_lock::Locked; | ||
| use smallvec::SmallVec; | ||
| use std::fmt::{Debug, self}; | ||
| use std::mem; | ||
| use stylearc::Arc; | ||
|
|
||
| /// List of applicable declarations. This is a transient structure that shuttles | ||
| /// declarations between selector matching and inserting into the rule tree, and | ||
| /// therefore we want to avoid heap-allocation where possible. | ||
| /// | ||
| /// In measurements on wikipedia, we pretty much never have more than 8 applicable | ||
| /// declarations, so we could consider making this 8 entries instead of 16. | ||
| /// However, it may depend a lot on workload, and stack space is cheap. | ||
| pub type ApplicableDeclarationList = SmallVec<[ApplicableDeclarationBlock; 16]>; | ||
|
|
||
| /// Blink uses 18 bits to store source order, and does not check overflow [1]. | ||
| /// That's a limit that could be reached in realistic webpages, so we use | ||
| /// 24 bits and enforce defined behavior in the overflow case. | ||
| /// | ||
| /// Note that the value of 24 is also hard-coded into the level() accessor, | ||
| /// which does a byte-aligned load of the 4th byte. If you change this value | ||
| /// you'll need to change that as well. | ||
| /// | ||
| /// [1] https://cs.chromium.org/chromium/src/third_party/WebKit/Source/core/css/ | ||
| /// RuleSet.h?l=128&rcl=90140ab80b84d0f889abc253410f44ed54ae04f3 | ||
| const SOURCE_ORDER_BITS: usize = 24; | ||
| const SOURCE_ORDER_MASK: u32 = (1 << SOURCE_ORDER_BITS) - 1; | ||
| const SOURCE_ORDER_MAX: u32 = SOURCE_ORDER_MASK; | ||
|
|
||
| /// Stores the source order of a block and the cascade level it belongs to. | ||
| #[cfg_attr(feature = "servo", derive(HeapSizeOf))] | ||
| #[derive(Copy, Clone, Eq, PartialEq)] | ||
| struct SourceOrderAndCascadeLevel(u32); | ||
|
|
||
| impl SourceOrderAndCascadeLevel { | ||
| fn new(source_order: u32, cascade_level: CascadeLevel) -> SourceOrderAndCascadeLevel { | ||
| let mut bits = ::std::cmp::min(source_order, SOURCE_ORDER_MAX); | ||
| bits |= (cascade_level as u8 as u32) << SOURCE_ORDER_BITS; | ||
| SourceOrderAndCascadeLevel(bits) | ||
| } | ||
|
|
||
| fn order(&self) -> u32 { | ||
| self.0 & SOURCE_ORDER_MASK | ||
| } | ||
|
|
||
| fn level(&self) -> CascadeLevel { | ||
| unsafe { | ||
| // Transmute rather than shifting so that we're sure the compiler | ||
| // emits a simple byte-aligned load. | ||
| let as_bytes: [u8; 4] = mem::transmute(self.0); | ||
| CascadeLevel::from_byte(as_bytes[3]) | ||
| } | ||
| } | ||
| } | ||
|
|
||
| impl Debug for SourceOrderAndCascadeLevel { | ||
| fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||
| f.debug_struct("SourceOrderAndCascadeLevel") | ||
| .field("order", &self.order()) | ||
| .field("level", &self.level()) | ||
| .finish() | ||
| } | ||
| } | ||
|
|
||
| /// A property declaration together with its precedence among rules of equal | ||
| /// specificity so that we can sort them. | ||
| /// | ||
| /// This represents the declarations in a given declaration block for a given | ||
| /// importance. | ||
| #[cfg_attr(feature = "servo", derive(HeapSizeOf))] | ||
| #[derive(Debug, Clone, PartialEq)] | ||
| pub struct ApplicableDeclarationBlock { | ||
| /// The style source, either a style rule, or a property declaration block. | ||
| #[cfg_attr(feature = "servo", ignore_heap_size_of = "Arc")] | ||
| pub source: StyleSource, | ||
| /// The source order of the block, and the cascade level it belongs to. | ||
| order_and_level: SourceOrderAndCascadeLevel, | ||
| /// The specificity of the selector this block is represented by. | ||
| pub specificity: u32, | ||
| } | ||
|
|
||
| impl ApplicableDeclarationBlock { | ||
| /// Constructs an applicable declaration block from a given property | ||
| /// declaration block and importance. | ||
| #[inline] | ||
| pub fn from_declarations(declarations: Arc<Locked<PropertyDeclarationBlock>>, | ||
| level: CascadeLevel) | ||
| -> Self { | ||
| ApplicableDeclarationBlock { | ||
| source: StyleSource::Declarations(declarations), | ||
| order_and_level: SourceOrderAndCascadeLevel::new(0, level), | ||
| specificity: 0, | ||
| } | ||
| } | ||
|
|
||
| /// Constructs an applicable declaration block from the given components | ||
| #[inline] | ||
| pub fn new(source: StyleSource, | ||
| order: u32, | ||
| level: CascadeLevel, | ||
| specificity: u32) -> Self { | ||
| ApplicableDeclarationBlock { | ||
| source: source, | ||
| order_and_level: SourceOrderAndCascadeLevel::new(order, level), | ||
| specificity: specificity, | ||
| } | ||
|
|
||
| } | ||
|
|
||
| /// Returns the source order of the block. | ||
| #[inline] | ||
| pub fn source_order(&self) -> u32 { | ||
| self.order_and_level.order() | ||
| } | ||
|
|
||
| /// Returns the cascade level of the block. | ||
| #[inline] | ||
| pub fn level(&self) -> CascadeLevel { | ||
| self.order_and_level.level() | ||
| } | ||
|
|
||
| /// Convenience method to consume self and return the source alongside the | ||
| /// level. | ||
| #[inline] | ||
| pub fn order_and_level(self) -> (StyleSource, CascadeLevel) { | ||
| let level = self.level(); | ||
| (self.source, level) | ||
| } | ||
| } |
Oops, something went wrong.
ProTip!
Use n and p to navigate between commits in a pull request.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
This comment seems incorrect to me. Based on a cursory reading of this PR, it seems that the hashes are 24 bits, leaving 8 bits unused in a 32 bit word.