Skip to content

Commit

Permalink
Remove cached thread local context from LayoutContext
Browse files Browse the repository at this point in the history
Remove cached thread local context from LayoutContext, use LayoutContext for
assign_inline_sizes(), and simplify the parallel flow traversal code.
  • Loading branch information
stshine committed Feb 8, 2017
1 parent f07bfaa commit 336aa79
Show file tree
Hide file tree
Showing 24 changed files with 323 additions and 420 deletions.
4 changes: 2 additions & 2 deletions components/layout/animation.rs
Expand Up @@ -4,7 +4,7 @@

//! CSS transitions and animations.

use context::SharedLayoutContext;
use context::LayoutContext;
use flow::{self, Flow};
use gfx::display_list::OpaqueNode;
use ipc_channel::ipc::IpcSender;
Expand Down Expand Up @@ -132,7 +132,7 @@ pub fn update_animation_state(constellation_chan: &IpcSender<ConstellationMsg>,
// NB: This is specific for SelectorImpl, since the layout context and the
// flows are SelectorImpl specific too. If that goes away at some point,
// this should be made generic.
pub fn recalc_style_for_animations(context: &SharedLayoutContext,
pub fn recalc_style_for_animations(context: &LayoutContext,
flow: &mut Flow,
animations: &HashMap<OpaqueNode,
Vec<Animation>>) {
Expand Down
39 changes: 20 additions & 19 deletions components/layout/block.rs
Expand Up @@ -28,7 +28,7 @@
#![deny(unsafe_code)]

use app_units::{Au, MAX_AU};
use context::{LayoutContext, SharedLayoutContext};
use context::LayoutContext;
use display_list_builder::{BorderPaintingMode, DisplayListBuildState, FragmentDisplayListBuilding};
use display_list_builder::BlockFlowDisplayListBuilding;
use euclid::{Point2D, Rect, Size2D};
Expand Down Expand Up @@ -767,11 +767,11 @@ impl BlockFlow {
/// `inline(always)` because this is only ever called by in-order or non-in-order top-level
/// methods.
#[inline(always)]
pub fn assign_block_size_block_base<'a>(&mut self,
layout_context: &'a LayoutContext<'a>,
mut fragmentation_context: Option<FragmentationContext>,
margins_may_collapse: MarginsMayCollapseFlag)
-> Option<Arc<Flow>> {
pub fn assign_block_size_block_base(&mut self,
layout_context: &LayoutContext,
mut fragmentation_context: Option<FragmentationContext>,
margins_may_collapse: MarginsMayCollapseFlag)
-> Option<Arc<Flow>> {
let _scope = layout_debug_scope!("assign_block_size_block_base {:x}",
self.base.debug_id());

Expand Down Expand Up @@ -1462,9 +1462,9 @@ impl BlockFlow {
/// on the floats we could see at the time of inline-size assignment. The job of this function,
/// therefore, is not only to assign the final size but also to perform the layout again for
/// this block formatting context if our speculation was wrong.
fn assign_inline_position_for_formatting_context<'a>(&mut self,
layout_context: &'a LayoutContext<'a>,
content_box: LogicalRect<Au>) {
fn assign_inline_position_for_formatting_context(&mut self,
layout_context: &LayoutContext,
content_box: LogicalRect<Au>) {
debug_assert!(self.formatting_context_type() != FormattingContextType::None);

if !self.base.restyle_damage.intersects(REFLOW_OUT_OF_FLOW | REFLOW) {
Expand Down Expand Up @@ -1546,10 +1546,10 @@ impl BlockFlow {
// float speculation, instead of acting on the actual results.
self.fragment.border_box.size.inline = inline_size;
// Assign final-final inline sizes on all our children.
self.assign_inline_sizes(&layout_context.shared.style_context);
self.assign_inline_sizes(layout_context);
// Re-run layout on our children.
for child in flow::mut_base(self).children.iter_mut() {
sequential::traverse_flow_tree_preorder(child, layout_context.shared);
sequential::traverse_flow_tree_preorder(child, layout_context);
}
// Assign our final-final block size.
self.assign_block_size(layout_context);
Expand Down Expand Up @@ -1883,9 +1883,10 @@ impl Flow for BlockFlow {
///
/// Dual fragments consume some inline-size first, and the remainder is assigned to all child
/// (block) contexts.
fn assign_inline_sizes(&mut self, shared_context: &SharedStyleContext) {
fn assign_inline_sizes(&mut self, layout_context: &LayoutContext) {
let _scope = layout_debug_scope!("block::assign_inline_sizes {:x}", self.base.debug_id());

let shared_context = layout_context.shared_context();
self.compute_inline_sizes(shared_context);

// Move in from the inline-start border edge.
Expand Down Expand Up @@ -1914,11 +1915,11 @@ impl Flow for BlockFlow {
}
}

fn assign_block_size_for_inorder_child_if_necessary<'a>(&mut self,
layout_context: &'a LayoutContext<'a>,
parent_thread_id: u8,
content_box: LogicalRect<Au>)
-> bool {
fn assign_block_size_for_inorder_child_if_necessary(&mut self,
layout_context: &LayoutContext,
parent_thread_id: u8,
content_box: LogicalRect<Au>)
-> bool {
if self.base.flags.is_float() {
return false
}
Expand Down Expand Up @@ -1950,7 +1951,7 @@ impl Flow for BlockFlow {
false
}

fn assign_block_size<'a>(&mut self, ctx: &'a LayoutContext<'a>) {
fn assign_block_size(&mut self, ctx: &LayoutContext) {
let remaining = Flow::fragment(self, ctx, None);
debug_assert!(remaining.is_none());
}
Expand Down Expand Up @@ -1998,7 +1999,7 @@ impl Flow for BlockFlow {
}
}

fn compute_absolute_position(&mut self, _layout_context: &SharedLayoutContext) {
fn compute_absolute_position(&mut self, _layout_context: &LayoutContext) {
// FIXME (mbrubeck): Get the real container size, taking the container writing mode into
// account. Must handle vertical writing modes.
let container_size = Size2D::new(self.base.block_container_inline_size, Au(0));
Expand Down
31 changes: 18 additions & 13 deletions components/layout/construct.rs
Expand Up @@ -15,7 +15,7 @@

use app_units::Au;
use block::BlockFlow;
use context::LayoutContext;
use context::{LayoutContext, with_thread_local_font_context};
use data::{HAS_NEWLY_CONSTRUCTED_FLOW, PersistentLayoutData};
use flex::FlexFlow;
use floats::FloatKind;
Expand Down Expand Up @@ -315,7 +315,7 @@ impl InlineFragmentsAccumulator {
/// An object that knows how to create flows.
pub struct FlowConstructor<'a, N: ThreadSafeLayoutNode> {
/// The layout context.
pub layout_context: &'a LayoutContext<'a>,
pub layout_context: &'a LayoutContext,
/// Satisfy the compiler about the unused parameters, which we use to improve the ergonomics of
/// the ensuing impl {} by removing the need to parameterize all the methods individually.
phantom2: PhantomData<N>,
Expand All @@ -324,7 +324,7 @@ pub struct FlowConstructor<'a, N: ThreadSafeLayoutNode> {
impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode>
FlowConstructor<'a, ConcreteThreadSafeLayoutNode> {
/// Creates a new flow constructor.
pub fn new(layout_context: &'a LayoutContext<'a>) -> Self {
pub fn new(layout_context: &'a LayoutContext) -> Self {
FlowConstructor {
layout_context: layout_context,
phantom2: PhantomData,
Expand All @@ -351,12 +351,12 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode>
}
Some(LayoutNodeType::Element(LayoutElementType::HTMLImageElement)) => {
let image_info = box ImageFragmentInfo::new(node.image_url(),
&self.layout_context.shared);
&self.layout_context);
SpecificFragmentInfo::Image(image_info)
}
Some(LayoutNodeType::Element(LayoutElementType::HTMLObjectElement)) => {
let image_info = box ImageFragmentInfo::new(node.object_data(),
&self.layout_context.shared);
&self.layout_context);
SpecificFragmentInfo::Image(image_info)
}
Some(LayoutNodeType::Element(LayoutElementType::HTMLTableElement)) => {
Expand Down Expand Up @@ -434,8 +434,10 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode>
// for runs might collapse so much whitespace away that only hypothetical fragments
// remain. In that case the inline flow will compute its ascent and descent to be zero.
let scanned_fragments =
TextRunScanner::new().scan_for_runs(&mut self.layout_context.font_context(),
fragments.fragments);
with_thread_local_font_context(self.layout_context, |font_context| {
TextRunScanner::new().scan_for_runs(font_context,
mem::replace(&mut fragments.fragments, LinkedList::new()))
});
let mut inline_flow_ref =
FlowRef::new(Arc::new(InlineFlow::from_fragments(scanned_fragments,
node.style(self.style_context()).writing_mode)));
Expand Down Expand Up @@ -464,8 +466,9 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode>
// FIXME(#6503): Use Arc::get_mut().unwrap() here.
let inline_flow = FlowRef::deref_mut(&mut inline_flow_ref).as_mut_inline();
inline_flow.minimum_line_metrics =
inline_flow.minimum_line_metrics(&mut self.layout_context.font_context(),
&node.style(self.style_context()))
with_thread_local_font_context(self.layout_context, |font_context| {
inline_flow.minimum_line_metrics(font_context, &node.style(self.style_context()))
});
}

inline_flow_ref.finish();
Expand Down Expand Up @@ -1216,7 +1219,7 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode>
let marker_fragments = match node.style(self.style_context()).get_list().list_style_image {
Either::First(ref url_value) => {
let image_info = box ImageFragmentInfo::new(url_value.url().map(|u| u.clone()),
&self.layout_context.shared);
&self.layout_context);
vec![Fragment::new(node, SpecificFragmentInfo::Image(image_info), self.layout_context)]
}
Either::Second(_none) => {
Expand All @@ -1232,9 +1235,11 @@ impl<'a, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode>
SpecificFragmentInfo::UnscannedText(
box UnscannedTextFragmentInfo::new(text, None)),
self.layout_context));
let marker_fragments = TextRunScanner::new().scan_for_runs(
&mut self.layout_context.font_context(),
unscanned_marker_fragments);
let marker_fragments =
with_thread_local_font_context(self.layout_context, |mut font_context| {
TextRunScanner::new().scan_for_runs(&mut font_context,
unscanned_marker_fragments)
});
marker_fragments.fragments
}
ListStyleTypeContent::GeneratedContent(info) => {
Expand Down
85 changes: 21 additions & 64 deletions components/layout/context.rs
Expand Up @@ -20,7 +20,6 @@ use std::borrow::{Borrow, BorrowMut};
use std::cell::{RefCell, RefMut};
use std::collections::HashMap;
use std::hash::BuildHasherDefault;
use std::rc::Rc;
use std::sync::{Arc, Mutex};
use style::context::{SharedStyleContext, ThreadLocalStyleContext};
use style::dom::TElement;
Expand All @@ -31,9 +30,9 @@ pub struct ScopedThreadLocalLayoutContext<E: TElement> {
}

impl<E: TElement> ScopedThreadLocalLayoutContext<E> {
pub fn new(shared: &SharedLayoutContext) -> Self {
pub fn new(context: &LayoutContext) -> Self {
ScopedThreadLocalLayoutContext {
style_context: ThreadLocalStyleContext::new(&shared.style_context),
style_context: ThreadLocalStyleContext::new(&context.style_context),
}
}
}
Expand All @@ -50,53 +49,33 @@ impl<E: TElement> BorrowMut<ThreadLocalStyleContext<E>> for ScopedThreadLocalLay
}
}

/// TLS data that persists across traversals.
pub struct PersistentThreadLocalLayoutContext {
// FontContext uses Rc all over the place and so isn't Send, which means we
// can't use ScopedTLS for it. There's also no reason to scope it to the
// traversal, and performance is probably better if we don't.
pub font_context: RefCell<FontContext>,
}

impl PersistentThreadLocalLayoutContext {
pub fn new(shared: &SharedLayoutContext) -> Rc<Self> {
let font_cache_thread = shared.font_cache_thread.lock().unwrap().clone();
Rc::new(PersistentThreadLocalLayoutContext {
font_context: RefCell::new(FontContext::new(font_cache_thread)),
})
}
}
thread_local!(static FONT_CONTEXT_KEY: RefCell<Option<FontContext>> = RefCell::new(None));

impl HeapSizeOf for PersistentThreadLocalLayoutContext {
fn heap_size_of_children(&self) -> usize {
self.font_context.heap_size_of_children()
}
}

thread_local!(static LOCAL_CONTEXT_KEY: RefCell<Option<Rc<PersistentThreadLocalLayoutContext>>> = RefCell::new(None));

fn create_or_get_persistent_context(shared: &SharedLayoutContext)
-> Rc<PersistentThreadLocalLayoutContext> {
LOCAL_CONTEXT_KEY.with(|r| {
let mut r = r.borrow_mut();
if let Some(context) = r.clone() {
context
} else {
let context = PersistentThreadLocalLayoutContext::new(shared);
*r = Some(context.clone());
context
pub fn with_thread_local_font_context<F, R>(layout_context: &LayoutContext, f: F) -> R
where F: FnOnce(&mut FontContext) -> R
{
FONT_CONTEXT_KEY.with(|k| {
let mut font_context = k.borrow_mut();
if font_context.is_none() {
let font_cache_thread = layout_context.font_cache_thread.lock().unwrap().clone();
*font_context = Some(FontContext::new(font_cache_thread));
}
f(&mut RefMut::map(font_context, |x| x.as_mut().unwrap()))
})
}

pub fn heap_size_of_persistent_local_context() -> usize {
LOCAL_CONTEXT_KEY.with(|r| {
r.borrow().clone().map_or(0, |context| context.heap_size_of_children())
FONT_CONTEXT_KEY.with(|r| {
if let Some(ref context) = *r.borrow() {
context.heap_size_of_children()
} else {
0
}
})
}

/// Layout information shared among all workers. This must be thread-safe.
pub struct SharedLayoutContext {
pub struct LayoutContext {
/// Bits shared by the layout and style system.
pub style_context: SharedStyleContext,

Expand All @@ -115,34 +94,12 @@ pub struct SharedLayoutContext {
BuildHasherDefault<FnvHasher>>>>,
}

pub struct LayoutContext<'a> {
pub shared: &'a SharedLayoutContext,
pub persistent: Rc<PersistentThreadLocalLayoutContext>,
}

impl<'a> LayoutContext<'a> {
pub fn new(shared: &'a SharedLayoutContext) -> Self
{
LayoutContext {
shared: shared,
persistent: create_or_get_persistent_context(shared),
}
}
}

impl<'a> LayoutContext<'a> {
impl LayoutContext {
#[inline(always)]
pub fn shared_context(&self) -> &SharedStyleContext {
&self.shared.style_context
}

#[inline(always)]
pub fn font_context(&self) -> RefMut<FontContext> {
self.persistent.font_context.borrow_mut()
&self.style_context
}
}

impl SharedLayoutContext {
fn get_or_request_image_synchronously(&self, url: ServoUrl, use_placeholder: UsePlaceholder)
-> Option<Arc<Image>> {
debug_assert!(opts::get().output_file.is_some() || opts::get().exit_after_load);
Expand Down
10 changes: 5 additions & 5 deletions components/layout/display_list_builder.rs
Expand Up @@ -13,7 +13,7 @@
use app_units::{AU_PER_PX, Au};
use block::{BlockFlow, BlockStackingContextType};
use canvas_traits::{CanvasData, CanvasMsg, FromLayoutMsg};
use context::SharedLayoutContext;
use context::LayoutContext;
use euclid::{Point2D, Rect, SideOffsets2D, Size2D, TypedSize2D};
use flex::FlexFlow;
use flow::{BaseFlow, Flow, IS_ABSOLUTELY_POSITIONED};
Expand Down Expand Up @@ -93,7 +93,7 @@ fn get_cyclic<T>(arr: &[T], index: usize) -> &T {
}

pub struct DisplayListBuildState<'a> {
pub shared_layout_context: &'a SharedLayoutContext,
pub layout_context: &'a LayoutContext,
pub root_stacking_context: StackingContext,
pub items: HashMap<StackingContextId, Vec<DisplayItem>>,
pub stacking_context_children: HashMap<StackingContextId, Vec<StackingContext>>,
Expand All @@ -114,9 +114,9 @@ pub struct DisplayListBuildState<'a> {
}

impl<'a> DisplayListBuildState<'a> {
pub fn new(shared_layout_context: &'a SharedLayoutContext) -> DisplayListBuildState<'a> {
pub fn new(layout_context: &'a LayoutContext) -> DisplayListBuildState<'a> {
DisplayListBuildState {
shared_layout_context: shared_layout_context,
layout_context: layout_context,
root_stacking_context: StackingContext::root(),
items: HashMap::new(),
stacking_context_children: HashMap::new(),
Expand Down Expand Up @@ -682,7 +682,7 @@ impl FragmentDisplayListBuilding for Fragment {
image_url: &ServoUrl,
index: usize) {
let background = style.get_background();
let webrender_image = state.shared_layout_context
let webrender_image = state.layout_context
.get_webrender_image_for_url(image_url.clone(),
UsePlaceholder::No);

Expand Down

0 comments on commit 336aa79

Please sign in to comment.