mirror of
https://github.com/servo/servo.git
synced 2025-08-05 13:40:08 +01:00
style: Pack the shadow cascade order in ApplicableDeclarationBlock.
I didn't bother not shifting there. We need to load the whole thing and shift for at least one of cascade level / shadow cascade order. Callers of level() other than for_rule_tree are non-existent in release builds, so we'd be doing the shift anyway. I can implement the same thing for shadow_cascade_order too, but I don't think that optimization is measurable in any way, either, the compiler should make the decision. And just in case, the simpler version actually generated less instructions in: https://play.rust-lang.org/?gist=ceadb0d3cbce4eeca76e4d9ab9a1c744&version=nightly with the simple thing. Bug: 1455032 Reviewed-by: heycam MozReview-Commit-ID: 8xPBJmlcyKh
This commit is contained in:
parent
b1fbb28b8a
commit
b5c18c24fe
3 changed files with 57 additions and 38 deletions
|
@ -10,7 +10,6 @@ use servo_arc::Arc;
|
||||||
use shared_lock::Locked;
|
use shared_lock::Locked;
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
use std::fmt::{self, Debug};
|
use std::fmt::{self, Debug};
|
||||||
use std::mem;
|
|
||||||
|
|
||||||
/// List of applicable declarations. This is a transient structure that shuttles
|
/// List of applicable declarations. This is a transient structure that shuttles
|
||||||
/// declarations between selector matching and inserting into the rule tree, and
|
/// declarations between selector matching and inserting into the rule tree, and
|
||||||
|
@ -25,45 +24,67 @@ pub type ApplicableDeclarationList = SmallVec<[ApplicableDeclarationBlock; 16]>;
|
||||||
/// That's a limit that could be reached in realistic webpages, so we use
|
/// That's a limit that could be reached in realistic webpages, so we use
|
||||||
/// 24 bits and enforce defined behavior in the overflow case.
|
/// 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/
|
/// [1] https://cs.chromium.org/chromium/src/third_party/WebKit/Source/core/css/
|
||||||
/// RuleSet.h?l=128&rcl=90140ab80b84d0f889abc253410f44ed54ae04f3
|
/// RuleSet.h?l=128&rcl=90140ab80b84d0f889abc253410f44ed54ae04f3
|
||||||
|
const SOURCE_ORDER_SHIFT: usize = 0;
|
||||||
const SOURCE_ORDER_BITS: usize = 24;
|
const SOURCE_ORDER_BITS: usize = 24;
|
||||||
const SOURCE_ORDER_MASK: u32 = (1 << SOURCE_ORDER_BITS) - 1;
|
const SOURCE_ORDER_MAX: u32 = (1 << SOURCE_ORDER_BITS) - 1;
|
||||||
const SOURCE_ORDER_MAX: u32 = SOURCE_ORDER_MASK;
|
const SOURCE_ORDER_MASK: u32 = SOURCE_ORDER_MAX << SOURCE_ORDER_SHIFT;
|
||||||
|
|
||||||
/// Stores the source order of a block and the cascade level it belongs to.
|
/// We store up-to-15 shadow order levels.
|
||||||
|
///
|
||||||
|
/// You'd need an element slotted across 16 components with ::slotted rules to
|
||||||
|
/// trigger this as of this writing, which looks... Unlikely.
|
||||||
|
const SHADOW_CASCADE_ORDER_SHIFT: usize = SOURCE_ORDER_BITS;
|
||||||
|
const SHADOW_CASCADE_ORDER_BITS: usize = 4;
|
||||||
|
const SHADOW_CASCADE_ORDER_MAX: u8 = (1 << SHADOW_CASCADE_ORDER_BITS) - 1;
|
||||||
|
const SHADOW_CASCADE_ORDER_MASK: u32 = (SHADOW_CASCADE_ORDER_MAX as u32) << SHADOW_CASCADE_ORDER_SHIFT;
|
||||||
|
|
||||||
|
const CASCADE_LEVEL_SHIFT: usize = SOURCE_ORDER_BITS + SHADOW_CASCADE_ORDER_BITS;
|
||||||
|
const CASCADE_LEVEL_BITS: usize = 4;
|
||||||
|
const CASCADE_LEVEL_MAX: u8 = (1 << CASCADE_LEVEL_BITS) - 1;
|
||||||
|
const CASCADE_LEVEL_MASK: u32 = (CASCADE_LEVEL_MAX as u32) << CASCADE_LEVEL_SHIFT;
|
||||||
|
|
||||||
|
/// Stores the source order of a block, the cascade level it belongs to, and the
|
||||||
|
/// counter needed to handle Shadow DOM cascade order properly.
|
||||||
#[derive(Clone, Copy, Eq, MallocSizeOf, PartialEq)]
|
#[derive(Clone, Copy, Eq, MallocSizeOf, PartialEq)]
|
||||||
struct SourceOrderAndCascadeLevel(u32);
|
struct ApplicableDeclarationBits(u32);
|
||||||
|
|
||||||
impl SourceOrderAndCascadeLevel {
|
impl ApplicableDeclarationBits {
|
||||||
fn new(source_order: u32, cascade_level: CascadeLevel) -> SourceOrderAndCascadeLevel {
|
fn new(
|
||||||
|
source_order: u32,
|
||||||
|
cascade_level: CascadeLevel,
|
||||||
|
shadow_cascade_order: ShadowCascadeOrder,
|
||||||
|
) -> Self {
|
||||||
|
debug_assert!(
|
||||||
|
cascade_level as u8 <= CASCADE_LEVEL_MAX,
|
||||||
|
"Gotta find more bits!"
|
||||||
|
);
|
||||||
let mut bits = ::std::cmp::min(source_order, SOURCE_ORDER_MAX);
|
let mut bits = ::std::cmp::min(source_order, SOURCE_ORDER_MAX);
|
||||||
bits |= (cascade_level as u8 as u32) << SOURCE_ORDER_BITS;
|
bits |= ((shadow_cascade_order & SHADOW_CASCADE_ORDER_MAX) as u32) << SHADOW_CASCADE_ORDER_SHIFT;
|
||||||
SourceOrderAndCascadeLevel(bits)
|
bits |= (cascade_level as u8 as u32) << CASCADE_LEVEL_SHIFT;
|
||||||
|
ApplicableDeclarationBits(bits)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn order(&self) -> u32 {
|
fn source_order(&self) -> u32 {
|
||||||
self.0 & SOURCE_ORDER_MASK
|
(self.0 & SOURCE_ORDER_MASK) >> SOURCE_ORDER_SHIFT
|
||||||
|
}
|
||||||
|
|
||||||
|
fn shadow_cascade_order(&self) -> ShadowCascadeOrder {
|
||||||
|
((self.0 & SHADOW_CASCADE_ORDER_MASK) >> SHADOW_CASCADE_ORDER_SHIFT) as ShadowCascadeOrder
|
||||||
}
|
}
|
||||||
|
|
||||||
fn level(&self) -> CascadeLevel {
|
fn level(&self) -> CascadeLevel {
|
||||||
unsafe {
|
let byte = ((self.0 & CASCADE_LEVEL_MASK) >> CASCADE_LEVEL_SHIFT) as u8;
|
||||||
// Transmute rather than shifting so that we're sure the compiler
|
unsafe { CascadeLevel::from_byte(byte) }
|
||||||
// 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 {
|
impl Debug for ApplicableDeclarationBits {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
f.debug_struct("SourceOrderAndCascadeLevel")
|
f.debug_struct("ApplicableDeclarationBits")
|
||||||
.field("order", &self.order())
|
.field("source_order", &self.source_order())
|
||||||
|
.field("shadow_cascade_order", &self.shadow_cascade_order())
|
||||||
.field("level", &self.level())
|
.field("level", &self.level())
|
||||||
.finish()
|
.finish()
|
||||||
}
|
}
|
||||||
|
@ -79,12 +100,11 @@ pub struct ApplicableDeclarationBlock {
|
||||||
/// The style source, either a style rule, or a property declaration block.
|
/// The style source, either a style rule, or a property declaration block.
|
||||||
#[ignore_malloc_size_of = "Arc"]
|
#[ignore_malloc_size_of = "Arc"]
|
||||||
pub source: StyleSource,
|
pub source: StyleSource,
|
||||||
/// The source order of the block, and the cascade level it belongs to.
|
/// The bits containing the source order, cascade level, and shadow cascade
|
||||||
order_and_level: SourceOrderAndCascadeLevel,
|
/// order.
|
||||||
|
bits: ApplicableDeclarationBits,
|
||||||
/// The specificity of the selector this block is represented by.
|
/// The specificity of the selector this block is represented by.
|
||||||
pub specificity: u32,
|
pub specificity: u32,
|
||||||
/// The order in the tree of trees we carry on.
|
|
||||||
pub shadow_cascade_order: ShadowCascadeOrder,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ApplicableDeclarationBlock {
|
impl ApplicableDeclarationBlock {
|
||||||
|
@ -97,9 +117,8 @@ impl ApplicableDeclarationBlock {
|
||||||
) -> Self {
|
) -> Self {
|
||||||
ApplicableDeclarationBlock {
|
ApplicableDeclarationBlock {
|
||||||
source: StyleSource::Declarations(declarations),
|
source: StyleSource::Declarations(declarations),
|
||||||
order_and_level: SourceOrderAndCascadeLevel::new(0, level),
|
bits: ApplicableDeclarationBits::new(0, level, 0),
|
||||||
specificity: 0,
|
specificity: 0,
|
||||||
shadow_cascade_order: 0,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -110,26 +129,25 @@ impl ApplicableDeclarationBlock {
|
||||||
order: u32,
|
order: u32,
|
||||||
level: CascadeLevel,
|
level: CascadeLevel,
|
||||||
specificity: u32,
|
specificity: u32,
|
||||||
shadow_cascade_order: u32,
|
shadow_cascade_order: ShadowCascadeOrder,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
ApplicableDeclarationBlock {
|
ApplicableDeclarationBlock {
|
||||||
source,
|
source,
|
||||||
order_and_level: SourceOrderAndCascadeLevel::new(order, level),
|
bits: ApplicableDeclarationBits::new(order, level, shadow_cascade_order),
|
||||||
specificity,
|
specificity,
|
||||||
shadow_cascade_order,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the source order of the block.
|
/// Returns the source order of the block.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn source_order(&self) -> u32 {
|
pub fn source_order(&self) -> u32 {
|
||||||
self.order_and_level.order()
|
self.bits.source_order()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the cascade level of the block.
|
/// Returns the cascade level of the block.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn level(&self) -> CascadeLevel {
|
pub fn level(&self) -> CascadeLevel {
|
||||||
self.order_and_level.level()
|
self.bits.level()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Convenience method to consume self and return the right thing for the
|
/// Convenience method to consume self and return the right thing for the
|
||||||
|
@ -137,6 +155,7 @@ impl ApplicableDeclarationBlock {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn for_rule_tree(self) -> (StyleSource, CascadeLevel, ShadowCascadeOrder) {
|
pub fn for_rule_tree(self) -> (StyleSource, CascadeLevel, ShadowCascadeOrder) {
|
||||||
let level = self.level();
|
let level = self.level();
|
||||||
(self.source, level, self.shadow_cascade_order)
|
let cascade_order = self.bits.shadow_cascade_order();
|
||||||
|
(self.source, level, cascade_order)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -170,7 +170,7 @@ const FREE_LIST_LOCKED: *mut RuleNode = 0x02 as *mut RuleNode;
|
||||||
///
|
///
|
||||||
/// In particular, it'd be `0` for the innermost shadow host, `1` for the next,
|
/// In particular, it'd be `0` for the innermost shadow host, `1` for the next,
|
||||||
/// and so on.
|
/// and so on.
|
||||||
pub type ShadowCascadeOrder = u32;
|
pub type ShadowCascadeOrder = u8;
|
||||||
|
|
||||||
impl RuleTree {
|
impl RuleTree {
|
||||||
/// Construct a new rule tree.
|
/// Construct a new rule tree.
|
||||||
|
|
|
@ -35,7 +35,7 @@ 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_property_declaration, style::properties::PropertyDeclaration, 32);
|
||||||
|
|
||||||
size_of_test!(test_size_of_application_declaration_block, ApplicableDeclarationBlock, 32);
|
size_of_test!(test_size_of_application_declaration_block, ApplicableDeclarationBlock, 24);
|
||||||
size_of_test!(test_size_of_rule_node, RuleNode, 80);
|
size_of_test!(test_size_of_rule_node, RuleNode, 80);
|
||||||
|
|
||||||
// This is huge, but we allocate it on the stack and then never move it,
|
// This is huge, but we allocate it on the stack and then never move it,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue