servo: Merge #17615 - Rip out the generic abstractions around ThreadLocalStyleContext (from bholley:simplify_local_context); r=emilio

https://bugzilla.mozilla.org/show_bug.cgi?id=1378540

Source-Repo: https://github.com/servo/servo
Source-Revision: 8923a9e5f0cc292062f852babe878326aff656ef

--HG--
extra : subtree_source : https%3A//hg.mozilla.org/projects/converted-servo-linear
extra : subtree_revision : fd5436ab04b074ecab59f7341e77590975f62656
This commit is contained in:
Bobby Holley 2017-07-05 19:29:01 -07:00
Родитель c5c6d606ca
Коммит df77fb2e20
7 изменённых файлов: 52 добавлений и 102 удалений

Просмотреть файл

@ -18,39 +18,12 @@ use script_layout_interface::{PendingImage, PendingImageState};
use script_traits::PaintWorkletExecutor;
use script_traits::UntrustedNodeAddress;
use servo_url::ServoUrl;
use std::borrow::{Borrow, BorrowMut};
use std::cell::{RefCell, RefMut};
use std::collections::HashMap;
use std::hash::BuildHasherDefault;
use std::sync::{Arc, Mutex};
use std::thread;
use style::context::{SharedStyleContext, ThreadLocalStyleContext};
use style::dom::TElement;
/// TLS data scoped to the traversal.
pub struct ScopedThreadLocalLayoutContext<E: TElement> {
pub style_context: ThreadLocalStyleContext<E>,
}
impl<E: TElement> ScopedThreadLocalLayoutContext<E> {
pub fn new(context: &LayoutContext) -> Self {
ScopedThreadLocalLayoutContext {
style_context: ThreadLocalStyleContext::new(&context.style_context),
}
}
}
impl<E: TElement> Borrow<ThreadLocalStyleContext<E>> for ScopedThreadLocalLayoutContext<E> {
fn borrow(&self) -> &ThreadLocalStyleContext<E> {
&self.style_context
}
}
impl<E: TElement> BorrowMut<ThreadLocalStyleContext<E>> for ScopedThreadLocalLayoutContext<E> {
fn borrow_mut(&mut self) -> &mut ThreadLocalStyleContext<E> {
&mut self.style_context
}
}
use style::context::SharedStyleContext;
thread_local!(static FONT_CONTEXT_KEY: RefCell<Option<FontContext>> = RefCell::new(None));

Просмотреть файл

@ -6,7 +6,7 @@
use atomic_refcell::AtomicRefCell;
use construct::FlowConstructor;
use context::{LayoutContext, ScopedThreadLocalLayoutContext};
use context::LayoutContext;
use display_list_builder::DisplayListBuildState;
use flow::{self, PreorderFlowTraversal};
use flow::{CAN_BE_FRAGMENTED, Flow, ImmutableFlowUtils, PostorderFlowTraversal};
@ -55,10 +55,8 @@ impl<'a, E> DomTraversal<E> for RecalcStyleAndConstructFlows<'a>
E::ConcreteNode: LayoutNode,
E::FontMetricsProvider: Send,
{
type ThreadLocalContext = ScopedThreadLocalLayoutContext<E>;
fn process_preorder(&self, traversal_data: &PerLevelTraversalData,
thread_local: &mut Self::ThreadLocalContext, node: E::ConcreteNode) {
context: &mut StyleContext<E>, node: E::ConcreteNode) {
// FIXME(pcwalton): Stop allocating here. Ideally this should just be
// done by the HTML parser.
node.initialize_data();
@ -66,16 +64,12 @@ impl<'a, E> DomTraversal<E> for RecalcStyleAndConstructFlows<'a>
if !node.is_text_node() {
let el = node.as_element().unwrap();
let mut data = el.mutate_data().unwrap();
let mut context = StyleContext {
shared: &self.context.shared_context(),
thread_local: &mut thread_local.style_context,
};
recalc_style_at(self, traversal_data, &mut context, el, &mut data);
recalc_style_at(self, traversal_data, context, el, &mut data);
}
}
fn process_postorder(&self, thread_local: &mut Self::ThreadLocalContext, node: E::ConcreteNode) {
construct_flows_at(&self.context, thread_local, node);
fn process_postorder(&self, _style_context: &mut StyleContext<E>, node: E::ConcreteNode) {
construct_flows_at(&self.context, node);
}
fn text_node_needs_traversal(node: E::ConcreteNode) -> bool {
@ -100,10 +94,6 @@ impl<'a, E> DomTraversal<E> for RecalcStyleAndConstructFlows<'a>
&self.context.style_context
}
fn create_thread_local_context(&self) -> Self::ThreadLocalContext {
ScopedThreadLocalLayoutContext::new(&self.context)
}
fn is_parallel(&self) -> bool {
self.driver.is_parallel()
}
@ -118,9 +108,7 @@ pub trait PostorderNodeMutTraversal<ConcreteThreadSafeLayoutNode: ThreadSafeLayo
/// The flow construction traversal, which builds flows for styled nodes.
#[inline]
#[allow(unsafe_code)]
fn construct_flows_at<N>(context: &LayoutContext,
_thread_local: &mut ScopedThreadLocalLayoutContext<N::ConcreteElement>,
node: N)
fn construct_flows_at<N>(context: &LayoutContext, node: N)
where N: LayoutNode,
{
debug!("construct_flows_at: {:?}", node);

Просмотреть файл

@ -296,7 +296,7 @@ pub trait TElement : Eq + PartialEq + Debug + Hash + Sized + Copy + Clone +
///
/// XXXManishearth It would be better to make this a type parameter on
/// ThreadLocalStyleContext and StyleContext
type FontMetricsProvider: FontMetricsProvider;
type FontMetricsProvider: FontMetricsProvider + Send;
/// Get this element as a node.
fn as_node(&self) -> Self::ConcreteNode;

Просмотреть файл

@ -5,7 +5,7 @@
//! Gecko-specific bits for the styling DOM traversal.
use atomic_refcell::AtomicRefCell;
use context::{SharedStyleContext, StyleContext, ThreadLocalStyleContext};
use context::{SharedStyleContext, StyleContext};
use data::ElementData;
use dom::{NodeInfo, TNode};
use gecko::wrapper::{GeckoElement, GeckoNode};
@ -29,25 +29,19 @@ impl<'a> RecalcStyleOnly<'a> {
}
impl<'recalc, 'le> DomTraversal<GeckoElement<'le>> for RecalcStyleOnly<'recalc> {
type ThreadLocalContext = ThreadLocalStyleContext<GeckoElement<'le>>;
fn process_preorder(&self,
traversal_data: &PerLevelTraversalData,
thread_local: &mut Self::ThreadLocalContext,
context: &mut StyleContext<GeckoElement<'le>>,
node: GeckoNode<'le>)
{
if node.is_element() {
let el = node.as_element().unwrap();
let mut data = unsafe { el.ensure_data() }.borrow_mut();
let mut context = StyleContext {
shared: &self.shared,
thread_local: thread_local,
};
recalc_style_at(self, traversal_data, &mut context, el, &mut data);
recalc_style_at(self, traversal_data, context, el, &mut data);
}
}
fn process_postorder(&self, _: &mut Self::ThreadLocalContext, _: GeckoNode<'le>) {
fn process_postorder(&self, _: &mut StyleContext<GeckoElement<'le>>, _: GeckoNode<'le>) {
unreachable!();
}
@ -66,10 +60,6 @@ impl<'recalc, 'le> DomTraversal<GeckoElement<'le>> for RecalcStyleOnly<'recalc>
&self.shared
}
fn create_thread_local_context(&self) -> Self::ThreadLocalContext {
ThreadLocalStyleContext::new(&self.shared)
}
fn is_parallel(&self) -> bool {
self.driver.is_parallel()
}

Просмотреть файл

@ -23,7 +23,7 @@
#![deny(missing_docs)]
use arrayvec::ArrayVec;
use context::TraversalStatistics;
use context::{StyleContext, ThreadLocalStyleContext, TraversalStatistics};
use dom::{OpaqueNode, SendNode, TElement, TNode};
use rayon;
use scoped_tls::ScopedTLS;
@ -84,7 +84,7 @@ pub fn traverse_dom<E, D>(traversal: &D,
let traversal_data = PerLevelTraversalData {
current_dom_depth: depth,
};
let tls = ScopedTLS::<D::ThreadLocalContext>::new(pool);
let tls = ScopedTLS::<ThreadLocalStyleContext<E>>::new(pool);
let root = root.as_node().opaque();
pool.install(|| {
@ -124,11 +124,11 @@ pub fn traverse_dom<E, D>(traversal: &D,
#[inline(never)]
fn create_thread_local_context<'scope, E, D>(
traversal: &'scope D,
slot: &mut Option<D::ThreadLocalContext>)
slot: &mut Option<ThreadLocalStyleContext<E>>)
where E: TElement + 'scope,
D: DomTraversal<E>
{
*slot = Some(traversal.create_thread_local_context())
*slot = Some(ThreadLocalStyleContext::new(traversal.shared_context()));
}
/// A parallel top-down DOM traversal.
@ -152,7 +152,7 @@ fn top_down_dom<'a, 'scope, E, D>(nodes: &'a [SendNode<E::ConcreteNode>],
scope: &'a rayon::Scope<'scope>,
pool: &'scope rayon::ThreadPool,
traversal: &'scope D,
tls: &'scope ScopedTLS<'scope, D::ThreadLocalContext>)
tls: &'scope ScopedTLS<'scope, ThreadLocalStyleContext<E>>)
where E: TElement + 'scope,
D: DomTraversal<E>,
{
@ -167,7 +167,11 @@ fn top_down_dom<'a, 'scope, E, D>(nodes: &'a [SendNode<E::ConcreteNode>],
// Scope the borrow of the TLS so that the borrow is dropped before
// a potential recursive call when we pass TailCall.
let mut tlc = tls.ensure(
|slot: &mut Option<D::ThreadLocalContext>| create_thread_local_context(traversal, slot));
|slot: &mut Option<ThreadLocalStyleContext<E>>| create_thread_local_context(traversal, slot));
let mut context = StyleContext {
shared: traversal.shared_context(),
thread_local: &mut *tlc,
};
for n in nodes {
// If the last node we processed produced children, spawn them off
@ -199,15 +203,15 @@ fn top_down_dom<'a, 'scope, E, D>(nodes: &'a [SendNode<E::ConcreteNode>],
let node = **n;
let mut children_to_process = 0isize;
traversal.process_preorder(&traversal_data, &mut *tlc, node);
traversal.process_preorder(&traversal_data, &mut context, node);
if let Some(el) = node.as_element() {
traversal.traverse_children(&mut *tlc, el, |_tlc, kid| {
traversal.traverse_children(&mut context, el, |_context, kid| {
children_to_process += 1;
discovered_child_nodes.push(unsafe { SendNode::new(kid) })
});
}
traversal.handle_postorder_traversal(&mut *tlc, root, node,
traversal.handle_postorder_traversal(&mut context, root, node,
children_to_process);
}
}
@ -256,7 +260,7 @@ fn traverse_nodes<'a, 'scope, E, D>(nodes: &[SendNode<E::ConcreteNode>],
scope: &'a rayon::Scope<'scope>,
pool: &'scope rayon::ThreadPool,
traversal: &'scope D,
tls: &'scope ScopedTLS<'scope, D::ThreadLocalContext>)
tls: &'scope ScopedTLS<'scope, ThreadLocalStyleContext<E>>)
where E: TElement + 'scope,
D: DomTraversal<E>,
{

Просмотреть файл

@ -6,8 +6,8 @@
#![deny(missing_docs)]
use context::{StyleContext, ThreadLocalStyleContext};
use dom::{TElement, TNode};
use std::borrow::BorrowMut;
use std::collections::VecDeque;
use time;
use traversal::{DomTraversal, PerLevelTraversalData, PreTraverseToken};
@ -28,7 +28,12 @@ pub fn traverse_dom<E, D>(traversal: &D,
debug_assert!(token.should_traverse());
let mut discovered = VecDeque::<WorkItem<E::ConcreteNode>>::with_capacity(16);
let mut tlc = traversal.create_thread_local_context();
let mut tlc = ThreadLocalStyleContext::new(traversal.shared_context());
let mut context = StyleContext {
shared: traversal.shared_context(),
thread_local: &mut tlc,
};
let root_depth = root.depth();
if token.traverse_unstyled_children_only() {
@ -47,25 +52,24 @@ pub fn traverse_dom<E, D>(traversal: &D,
while let Some(WorkItem(node, depth)) = discovered.pop_front() {
let mut children_to_process = 0isize;
let traversal_data = PerLevelTraversalData { current_dom_depth: depth };
traversal.process_preorder(&traversal_data, &mut tlc, node);
traversal.process_preorder(&traversal_data, &mut context, node);
if let Some(el) = node.as_element() {
traversal.traverse_children(&mut tlc, el, |_tlc, kid| {
traversal.traverse_children(&mut context, el, |_context, kid| {
children_to_process += 1;
discovered.push_back(WorkItem(kid, depth + 1))
});
}
traversal.handle_postorder_traversal(&mut tlc, root.as_node().opaque(),
traversal.handle_postorder_traversal(&mut context, root.as_node().opaque(),
node, children_to_process);
}
// Dump statistics to stdout if requested.
if dump_stats {
let tlsc = tlc.borrow_mut();
tlsc.statistics.finish(traversal, start_time.unwrap());
if tlsc.statistics.is_large_traversal() {
println!("{}", tlsc.statistics);
context.thread_local.statistics.finish(traversal, start_time.unwrap());
if context.thread_local.statistics.is_large_traversal() {
println!("{}", context.thread_local.statistics);
}
}
}

Просмотреть файл

@ -5,7 +5,7 @@
//! Traversing the DOM tree; the bloom filter.
use atomic_refcell::AtomicRefCell;
use context::{ElementCascadeInputs, StyleContext, SharedStyleContext, ThreadLocalStyleContext};
use context::{ElementCascadeInputs, StyleContext, SharedStyleContext};
use data::{ElementData, ElementStyles};
use dom::{DirtyDescendants, NodeInfo, OpaqueNode, TElement, TNode};
use invalidation::element::restyle_hints::{RECASCADE_SELF, RECASCADE_DESCENDANTS, RestyleHint};
@ -13,7 +13,6 @@ use matching::{ChildCascadeRequirement, MatchMethods};
use sharing::{StyleSharingBehavior, StyleSharingTarget};
#[cfg(feature = "servo")] use servo_config::opts;
use smallvec::SmallVec;
use std::borrow::BorrowMut;
/// A per-traversal-level chunk of data. This is sent down by the traversal, and
/// currently only holds the dom depth for the bloom filter.
@ -138,22 +137,17 @@ fn is_servo_nonincremental_layout() -> bool {
/// A DOM Traversal trait, that is used to generically implement styling for
/// Gecko and Servo.
pub trait DomTraversal<E: TElement> : Sync {
/// The thread-local context, used to store non-thread-safe stuff that needs
/// to be used in the traversal, and of which we use one per worker, like
/// the bloom filter, for example.
type ThreadLocalContext: Send + BorrowMut<ThreadLocalStyleContext<E>>;
/// Process `node` on the way down, before its children have been processed.
fn process_preorder(&self,
data: &PerLevelTraversalData,
thread_local: &mut Self::ThreadLocalContext,
context: &mut StyleContext<E>,
node: E::ConcreteNode);
/// Process `node` on the way up, after its children have been processed.
///
/// This is only executed if `needs_postorder_traversal` returns true.
fn process_postorder(&self,
thread_local: &mut Self::ThreadLocalContext,
contect: &mut StyleContext<E>,
node: E::ConcreteNode);
/// Boolean that specifies whether a bottom up traversal should be
@ -177,7 +171,7 @@ pub trait DomTraversal<E: TElement> : Sync {
/// call durign the parallel traversal.
fn handle_postorder_traversal(
&self,
thread_local: &mut Self::ThreadLocalContext,
context: &mut StyleContext<E>,
root: OpaqueNode,
mut node: E::ConcreteNode,
children_to_process: isize
@ -190,7 +184,7 @@ pub trait DomTraversal<E: TElement> : Sync {
if children_to_process == 0 {
// We are a leaf. Walk up the chain.
loop {
self.process_postorder(thread_local, node);
self.process_postorder(context, node);
if node.opaque() == root {
break;
}
@ -404,7 +398,7 @@ pub trait DomTraversal<E: TElement> : Sync {
/// a parameter to keep the logs tidy.
fn should_traverse_children(
&self,
thread_local: &mut ThreadLocalStyleContext<E>,
context: &mut StyleContext<E>,
parent: E,
parent_data: &ElementData,
log: LogBehavior
@ -442,7 +436,7 @@ pub trait DomTraversal<E: TElement> : Sync {
// happens, we may just end up doing wasted work, since Gecko
// recursively drops Servo ElementData when the XBL insertion parent of
// an Element is changed.
if cfg!(feature = "gecko") && thread_local.is_initial_style() &&
if cfg!(feature = "gecko") && context.thread_local.is_initial_style() &&
parent_data.styles.primary().has_moz_binding() {
if log.allow() {
debug!("Parent {:?} has XBL binding, deferring traversal",
@ -458,23 +452,23 @@ pub trait DomTraversal<E: TElement> : Sync {
/// should be enqueued for processing.
fn traverse_children<F>(
&self,
thread_local: &mut Self::ThreadLocalContext,
context: &mut StyleContext<E>,
parent: E,
mut f: F
)
where
F: FnMut(&mut Self::ThreadLocalContext, E::ConcreteNode)
F: FnMut(&mut StyleContext<E>, E::ConcreteNode)
{
// Check if we're allowed to traverse past this element.
let should_traverse =
self.should_traverse_children(
thread_local.borrow_mut(),
context,
parent,
&parent.borrow_data().unwrap(),
MayLog
);
thread_local.borrow_mut().end_element(parent);
context.thread_local.end_element(parent);
if !should_traverse {
return;
}
@ -495,7 +489,7 @@ pub trait DomTraversal<E: TElement> : Sync {
}
}
}
f(thread_local, kid);
f(context, kid);
}
}
}
@ -517,9 +511,6 @@ pub trait DomTraversal<E: TElement> : Sync {
/// Return the shared style context common to all worker threads.
fn shared_context(&self) -> &SharedStyleContext;
/// Creates a thread-local context.
fn create_thread_local_context(&self) -> Self::ThreadLocalContext;
/// Whether we're performing a parallel traversal.
///
/// NB: We do this check on runtime. We could guarantee correctness in this
@ -763,7 +754,7 @@ where
// Preprocess children, propagating restyle hints and handling sibling
// relationships.
let should_traverse_children = traversal.should_traverse_children(
&mut context.thread_local,
context,
element,
&data,
DontLog