Parse stylesheets without acquiring a shared lock.

This commit is contained in:
Simon Sapin 2017-03-18 14:25:25 +01:00
parent cc046300f0
commit d9491187dc
4 changed files with 42 additions and 42 deletions

View file

@ -159,13 +159,10 @@ impl FetchResponseListener for StylesheetContext {
} }
} }
StylesheetContextSource::Import(ref stylesheet) => { StylesheetContextSource::Import(ref stylesheet) => {
let mut guard = document.style_shared_lock().write();
Stylesheet::update_from_bytes(&stylesheet, Stylesheet::update_from_bytes(&stylesheet,
&data, &data,
protocol_encoding_label, protocol_encoding_label,
Some(environment_encoding), Some(environment_encoding),
&mut guard,
Some(&loader), Some(&loader),
win.css_error_reporter(), win.css_error_reporter(),
ParserContextExtraData::default()); ParserContextExtraData::default());

View file

@ -12,7 +12,7 @@ use media_queries::MediaList;
use parser::ParserContextExtraData; use parser::ParserContextExtraData;
use self::encoding::{EncodingRef, DecoderTrap}; use self::encoding::{EncodingRef, DecoderTrap};
use servo_url::ServoUrl; use servo_url::ServoUrl;
use shared_lock::{SharedRwLock, SharedRwLockWriteGuard}; use shared_lock::SharedRwLock;
use std::str; use std::str;
use stylesheets::{Stylesheet, StylesheetLoader, Origin}; use stylesheets::{Stylesheet, StylesheetLoader, Origin};
@ -78,7 +78,6 @@ impl Stylesheet {
bytes: &[u8], bytes: &[u8],
protocol_encoding_label: Option<&str>, protocol_encoding_label: Option<&str>,
environment_encoding: Option<EncodingRef>, environment_encoding: Option<EncodingRef>,
guard: &mut SharedRwLockWriteGuard,
stylesheet_loader: Option<&StylesheetLoader>, stylesheet_loader: Option<&StylesheetLoader>,
error_reporter: &ParseErrorReporter, error_reporter: &ParseErrorReporter,
extra_data: ParserContextExtraData) { extra_data: ParserContextExtraData) {
@ -86,7 +85,6 @@ impl Stylesheet {
bytes, protocol_encoding_label, environment_encoding); bytes, protocol_encoding_label, environment_encoding);
Self::update_from_str(existing, Self::update_from_str(existing,
&string, &string,
guard,
stylesheet_loader, stylesheet_loader,
error_reporter, error_reporter,
extra_data) extra_data)

View file

@ -21,8 +21,7 @@ use selector_parser::{SelectorImpl, SelectorParser};
use selectors::parser::SelectorList; use selectors::parser::SelectorList;
use servo_config::prefs::PREFS; use servo_config::prefs::PREFS;
use servo_url::ServoUrl; use servo_url::ServoUrl;
use shared_lock::{SharedRwLock, Locked, ToCssWithGuard}; use shared_lock::{SharedRwLock, Locked, ToCssWithGuard, SharedRwLockReadGuard};
use shared_lock::{SharedRwLockReadGuard, SharedRwLockWriteGuard};
use std::cell::Cell; use std::cell::Cell;
use std::fmt; use std::fmt;
use std::sync::Arc; use std::sync::Arc;
@ -556,23 +555,42 @@ impl Stylesheet {
/// Updates an empty stylesheet from a given string of text. /// Updates an empty stylesheet from a given string of text.
pub fn update_from_str(existing: &Stylesheet, pub fn update_from_str(existing: &Stylesheet,
css: &str, css: &str,
guard: &mut SharedRwLockWriteGuard,
stylesheet_loader: Option<&StylesheetLoader>, stylesheet_loader: Option<&StylesheetLoader>,
error_reporter: &ParseErrorReporter, error_reporter: &ParseErrorReporter,
extra_data: ParserContextExtraData) { extra_data: ParserContextExtraData) {
let mut rules = existing.rules.write_with(guard); let mut namespaces = Namespaces::default();
let mut namespaces = existing.namespaces.write(); let (rules, dirty_on_viewport_size_change) = Stylesheet::parse_rules(
css, &existing.base_url, existing.origin, &mut namespaces, &existing.shared_lock,
stylesheet_loader, error_reporter, extra_data,
);
assert!(rules.is_empty()); *existing.namespaces.write() = namespaces;
existing.dirty_on_viewport_size_change
.store(dirty_on_viewport_size_change, Ordering::Release);
// Acquire the lock *after* parsing, to minimize the exclusive section.
let mut guard = existing.shared_lock.write();
*existing.rules.write_with(&mut guard) = CssRules(rules);
}
fn parse_rules(css: &str,
base_url: &ServoUrl,
origin: Origin,
namespaces: &mut Namespaces,
shared_lock: &SharedRwLock,
stylesheet_loader: Option<&StylesheetLoader>,
error_reporter: &ParseErrorReporter,
extra_data: ParserContextExtraData)
-> (Vec<CssRule>, bool) {
let mut rules = Vec::new();
let mut input = Parser::new(css); let mut input = Parser::new(css);
let rule_parser = TopLevelRuleParser { let rule_parser = TopLevelRuleParser {
stylesheet_origin: existing.origin, stylesheet_origin: origin,
namespaces: &mut namespaces, namespaces: namespaces,
shared_lock: &existing.shared_lock, shared_lock: shared_lock,
loader: stylesheet_loader, loader: stylesheet_loader,
context: ParserContext::new_with_extra_data(existing.origin, context: ParserContext::new_with_extra_data(origin,
&existing.base_url, base_url,
error_reporter, error_reporter,
extra_data), extra_data),
state: Cell::new(State::Start), state: Cell::new(State::Start),
@ -584,7 +602,7 @@ impl Stylesheet {
let mut iter = RuleListParser::new_for_stylesheet(&mut input, rule_parser); let mut iter = RuleListParser::new_for_stylesheet(&mut input, rule_parser);
while let Some(result) = iter.next() { while let Some(result) = iter.next() {
match result { match result {
Ok(rule) => rules.0.push(rule), Ok(rule) => rules.push(rule),
Err(range) => { Err(range) => {
let pos = range.start; let pos = range.start;
let message = format!("Invalid rule: '{}'", iter.input.slice(range)); let message = format!("Invalid rule: '{}'", iter.input.slice(range));
@ -594,8 +612,7 @@ impl Stylesheet {
} }
} }
existing.dirty_on_viewport_size_change (rules, input.seen_viewport_percentages())
.store(input.seen_viewport_percentages(), Ordering::Release);
} }
/// Creates an empty stylesheet and parses it with a given base url, origin /// Creates an empty stylesheet and parses it with a given base url, origin
@ -611,28 +628,21 @@ impl Stylesheet {
stylesheet_loader: Option<&StylesheetLoader>, stylesheet_loader: Option<&StylesheetLoader>,
error_reporter: &ParseErrorReporter, error_reporter: &ParseErrorReporter,
extra_data: ParserContextExtraData) -> Stylesheet { extra_data: ParserContextExtraData) -> Stylesheet {
let s = Stylesheet { let mut namespaces = Namespaces::default();
let (rules, dirty_on_viewport_size_change) = Stylesheet::parse_rules(
css, &base_url, origin, &mut namespaces, &shared_lock,
stylesheet_loader, error_reporter, extra_data,
);
Stylesheet {
origin: origin, origin: origin,
base_url: base_url, base_url: base_url,
namespaces: RwLock::new(Namespaces::default()), namespaces: RwLock::new(namespaces),
rules: CssRules::new(Vec::new(), &shared_lock), rules: CssRules::new(rules, &shared_lock),
media: Arc::new(shared_lock.wrap(media)), media: Arc::new(shared_lock.wrap(media)),
shared_lock: shared_lock, shared_lock: shared_lock,
dirty_on_viewport_size_change: AtomicBool::new(false), dirty_on_viewport_size_change: AtomicBool::new(dirty_on_viewport_size_change),
disabled: AtomicBool::new(false), disabled: AtomicBool::new(false),
};
{
let mut guard = s.shared_lock.write();
Self::update_from_str(&s,
css,
&mut guard,
stylesheet_loader,
error_reporter,
extra_data);
} }
s
} }
/// Whether this stylesheet can be dirty on viewport size change. /// Whether this stylesheet can be dirty on viewport size change.

View file

@ -362,8 +362,6 @@ pub extern "C" fn Servo_StyleSheet_ClearAndUpdate(stylesheet: RawServoStyleSheet
referrer: *mut ThreadSafeURIHolder, referrer: *mut ThreadSafeURIHolder,
principal: *mut ThreadSafePrincipalHolder) principal: *mut ThreadSafePrincipalHolder)
{ {
let global_style_data = &*GLOBAL_STYLE_DATA;
let mut guard = global_style_data.shared_lock.write();
let input = unsafe { data.as_ref().unwrap().as_str_unchecked() }; let input = unsafe { data.as_ref().unwrap().as_str_unchecked() };
let extra_data = unsafe { ParserContextExtraData { let extra_data = unsafe { ParserContextExtraData {
base: Some(GeckoArcURI::new(base)), base: Some(GeckoArcURI::new(base)),
@ -384,10 +382,7 @@ pub extern "C" fn Servo_StyleSheet_ClearAndUpdate(stylesheet: RawServoStyleSheet
}; };
let sheet = Stylesheet::as_arc(&stylesheet); let sheet = Stylesheet::as_arc(&stylesheet);
sheet.rules.write_with(&mut guard).0.clear(); Stylesheet::update_from_str(&sheet, input, loader, &StdoutErrorReporter, extra_data);
Stylesheet::update_from_str(&sheet, input, &mut guard, loader,
&StdoutErrorReporter, extra_data);
} }
#[no_mangle] #[no_mangle]