style: Add a very simple use counter implementation.

As simple as I could make it, for now. We can improve on this.

Differential Revision: https://phabricator.services.mozilla.com/D3827
This commit is contained in:
Emilio Cobos Álvarez 2018-08-16 16:38:56 +02:00
parent c3a4b27441
commit c8e5b7f1b0
No known key found for this signature in database
GPG key ID: 056B727BB9C1027C
4 changed files with 105 additions and 45 deletions

View file

@ -157,6 +157,7 @@ pub mod thread_state;
pub mod timer;
pub mod traversal;
pub mod traversal_flags;
pub mod use_counters;
#[macro_use]
#[allow(non_camel_case_types)]
pub mod values;

View file

@ -9,6 +9,7 @@ use cssparser::{Parser, SourceLocation, UnicodeRange};
use error_reporting::{ContextualParseError, ParseErrorReporter};
use style_traits::{OneOrMoreSeparated, ParseError, ParsingMode, Separator};
use stylesheets::{CssRuleType, Namespaces, Origin, UrlExtraData};
use use_counters::UseCounters;
/// Asserts that all ParsingMode flags have a matching ParsingMode value in gecko.
#[cfg(feature = "gecko")]
@ -53,6 +54,8 @@ pub struct ParserContext<'a> {
error_reporter: Option<&'a ParseErrorReporter>,
/// The currently active namespaces.
pub namespaces: Option<&'a Namespaces>,
/// The use counters we want to record while parsing style rules, if any.
pub use_counters: Option<&'a UseCounters>,
}
impl<'a> ParserContext<'a> {
@ -66,7 +69,7 @@ impl<'a> ParserContext<'a> {
quirks_mode: QuirksMode,
error_reporter: Option<&'a ParseErrorReporter>,
) -> Self {
ParserContext {
Self {
stylesheet_origin,
url_data,
rule_type,
@ -74,6 +77,7 @@ impl<'a> ParserContext<'a> {
quirks_mode,
error_reporter,
namespaces: None,
use_counters: None,
}
}
@ -96,14 +100,15 @@ impl<'a> ParserContext<'a> {
)
}
/// Create a parser context based on a previous context, but with a modified rule type.
/// Create a parser context based on a previous context, but with a modified
/// rule type.
#[inline]
pub fn new_with_rule_type(
context: &'a ParserContext,
rule_type: CssRuleType,
namespaces: &'a Namespaces,
) -> ParserContext<'a> {
ParserContext {
Self {
stylesheet_origin: context.stylesheet_origin,
url_data: context.url_data,
rule_type: Some(rule_type),
@ -111,6 +116,7 @@ impl<'a> ParserContext<'a> {
quirks_mode: context.quirks_mode,
namespaces: Some(namespaces),
error_reporter: context.error_reporter,
use_counters: context.use_counters,
}
}

View file

@ -425,6 +425,10 @@ pub mod animated_properties {
#[derive(Clone, Copy, Debug)]
pub struct NonCustomPropertyId(usize);
/// The length of all the non-custom properties.
pub const NON_CUSTOM_PROPERTY_ID_COUNT: usize =
${len(data.longhands) + len(data.shorthands) + len(data.all_aliases())};
% if product == "gecko":
#[allow(dead_code)]
unsafe fn static_assert_nscsspropertyid() {
@ -435,6 +439,11 @@ unsafe fn static_assert_nscsspropertyid() {
% endif
impl NonCustomPropertyId {
/// Returns the underlying index, used for use counter.
pub fn bit(self) -> usize {
self.0
}
#[cfg(feature = "gecko")]
#[inline]
fn to_nscsspropertyid(self) -> nsCSSPropertyID {
@ -450,7 +459,7 @@ impl NonCustomPropertyId {
if prop < 0 {
return Err(());
}
if prop >= ${len(data.longhands) + len(data.shorthands) + len(data.all_aliases())} {
if prop >= NON_CUSTOM_PROPERTY_ID_COUNT as i32 {
return Err(());
}
// unsafe: guaranteed by static_assert_nscsspropertyid above.
@ -460,7 +469,7 @@ impl NonCustomPropertyId {
/// Get the property name.
#[inline]
pub fn name(self) -> &'static str {
static MAP: [&'static str; ${len(data.longhands) + len(data.shorthands) + len(data.all_aliases())}] = [
static MAP: [&'static str; NON_CUSTOM_PROPERTY_ID_COUNT] = [
% for property in data.longhands + data.shorthands + data.all_aliases():
"${property.name}",
% endfor
@ -635,7 +644,7 @@ impl NonCustomPropertyId {
PropertyId::Shorthand(transmute((self.0 - ${len(data.longhands)}) as u16))
}
}
assert!(self.0 < ${len(data.longhands) + len(data.shorthands) + len(data.all_aliases())});
assert!(self.0 < NON_CUSTOM_PROPERTY_ID_COUNT);
let alias_id: AliasId = unsafe {
transmute((self.0 - ${len(data.longhands) + len(data.shorthands)}) as u16)
};
@ -671,7 +680,7 @@ impl From<AliasId> for NonCustomPropertyId {
/// A set of all properties
#[derive(Clone, PartialEq)]
pub struct NonCustomPropertyIdSet {
storage: [u32; (${len(data.longhands) + len(data.shorthands) + len(data.all_aliases())} - 1 + 32) / 32]
storage: [u32; (NON_CUSTOM_PROPERTY_ID_COUNT - 1 + 32) / 32]
}
impl NonCustomPropertyIdSet {
@ -2198,7 +2207,7 @@ impl PropertyDeclaration {
// FIXME: fully implement https://github.com/w3c/csswg-drafts/issues/774
// before adding skip_whitespace here.
// This probably affects some test results.
let value = match input.try(|i| CSSWideKeyword::parse(i)) {
let value = match input.try(CSSWideKeyword::parse) {
Ok(keyword) => DeclaredValueOwned::CSSWideKeyword(keyword),
Err(()) => match ::custom_properties::SpecifiedValue::parse(input) {
Ok(value) => DeclaredValueOwned::Value(value),
@ -2212,12 +2221,12 @@ impl PropertyDeclaration {
name: property_name,
value,
}));
Ok(())
return Ok(());
}
PropertyId::LonghandAlias(id, _) |
PropertyId::Longhand(id) => {
input.skip_whitespace(); // Unnecessary for correctness, but may help try() rewind less.
input.try(|i| CSSWideKeyword::parse(i)).map(|keyword| {
input.try(CSSWideKeyword::parse).map(|keyword| {
PropertyDeclaration::CSSWideKeyword(
WideKeywordDeclaration { id, keyword },
)
@ -2253,12 +2262,12 @@ impl PropertyDeclaration {
})
}).map(|declaration| {
declarations.push(declaration)
})
})?;
}
PropertyId::ShorthandAlias(id, _) |
PropertyId::Shorthand(id) => {
input.skip_whitespace(); // Unnecessary for correctness, but may help try() rewind less.
if let Ok(keyword) = input.try(|i| CSSWideKeyword::parse(i)) {
if let Ok(keyword) = input.try(CSSWideKeyword::parse) {
if id == ShorthandId::All {
declarations.all_shorthand = AllShorthand::CSSWideKeyword(keyword)
} else {
@ -2271,51 +2280,55 @@ impl PropertyDeclaration {
))
}
}
Ok(())
} else {
input.look_for_var_functions();
// Not using parse_entirely here: each ${shorthand.ident}::parse_into function
// needs to do so *before* pushing to `declarations`.
id.parse_into(declarations, context, input).or_else(|err| {
while let Ok(_) = input.next() {} // Look for var() after the error.
if input.seen_var_functions() {
input.reset(&start);
let (first_token_type, css) =
::custom_properties::parse_non_custom_with_var(input).map_err(|e| {
StyleParseErrorKind::new_invalid(
non_custom_id.unwrap().name(),
e,
)
})?;
let unparsed = Arc::new(UnparsedValue {
css: css.into_owned(),
first_token_type: first_token_type,
url_data: context.url_data.clone(),
from_shorthand: Some(id),
});
if id == ShorthandId::All {
declarations.all_shorthand = AllShorthand::WithVariables(unparsed)
} else {
for id in id.longhands() {
declarations.push(
PropertyDeclaration::WithVariables(VariableDeclaration {
id,
value: unparsed.clone(),
})
)
}
}
Ok(())
} else {
Err(StyleParseErrorKind::new_invalid(
if !input.seen_var_functions() {
return Err(StyleParseErrorKind::new_invalid(
non_custom_id.unwrap().name(),
err,
))
));
}
})
input.reset(&start);
let (first_token_type, css) =
::custom_properties::parse_non_custom_with_var(input).map_err(|e| {
StyleParseErrorKind::new_invalid(
non_custom_id.unwrap().name(),
e,
)
})?;
let unparsed = Arc::new(UnparsedValue {
css: css.into_owned(),
first_token_type: first_token_type,
url_data: context.url_data.clone(),
from_shorthand: Some(id),
});
if id == ShorthandId::All {
declarations.all_shorthand = AllShorthand::WithVariables(unparsed)
} else {
for id in id.longhands() {
declarations.push(
PropertyDeclaration::WithVariables(VariableDeclaration {
id,
value: unparsed.clone(),
})
)
}
}
Ok(())
})?;
}
}
}
debug_assert!(non_custom_id.is_some(), "Custom properties should've returned earlier");
if let Some(use_counters) = context.use_counters {
use_counters.non_custom_properties.record(non_custom_id.unwrap());
}
Ok(())
}
}

View file

@ -0,0 +1,40 @@
/* 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/. */
//! Various stuff for CSS property use counters.
use properties::{NonCustomPropertyId, NON_CUSTOM_PROPERTY_ID_COUNT};
// FIXME(emilio): We need AtomicU32 on stable ASAP...
use std::sync::atomic::AtomicUsize;
use std::sync::atomic::Ordering;
#[cfg(target_pointer_width = "64")]
const BITS_PER_ENTRY: usize = 64;
#[cfg(target_pointer_width = "32")]
const BITS_PER_ENTRY: usize = 32;
/// One bit per each non-custom CSS property.
#[derive(Default)]
pub struct NonCustomPropertyUseCounters {
storage: [AtomicUsize; (NON_CUSTOM_PROPERTY_ID_COUNT - 1 + BITS_PER_ENTRY) / BITS_PER_ENTRY],
}
impl NonCustomPropertyUseCounters {
/// Record that a given non-custom property ID has been parsed.
#[inline]
pub fn record(&self, id: NonCustomPropertyId) {
let bit = id.bit();
let bucket = bit / BITS_PER_ENTRY;
let bit_in_bucket = bit % BITS_PER_ENTRY;
self.storage[bucket].fetch_or(1 << bit_in_bucket, Ordering::Relaxed);
}
}
/// The use-counter data related to a given document we want to store.
pub struct UseCounters {
/// The counters for non-custom properties that have been parsed in the
/// document's stylesheets.
pub non_custom_properties: NonCustomPropertyUseCounters,
}