aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBoris Zbarsky <bzbarsky@mit.edu>2017-06-08 12:35:06 -0400
committerBoris Zbarsky <bzbarsky@mit.edu>2017-06-08 13:02:36 -0400
commit93271e199b8b7f6ec20d1546b384ea7ab9155759 (patch)
treefdeffa703729cc91a6bbd2f651315a1289e0e2e2
parent3616b8f0c3c7c1beba4d0977ea3a4fb2a5f9c835 (diff)
downloadservo-93271e199b8b7f6ec20d1546b384ea7ab9155759.tar.gz
servo-93271e199b8b7f6ec20d1546b384ea7ab9155759.zip
Reduce the size of top_down_dom stackframes.
The idea is to put the memmoving of the ThreadLocalContext out of line from the point of view of top_down_dom so we don't need to allocate a large chunk of stack space for it.
-rw-r--r--components/style/parallel.rs16
-rw-r--r--components/style/scoped_tls.rs12
2 files changed, 24 insertions, 4 deletions
diff --git a/components/style/parallel.rs b/components/style/parallel.rs
index 859548d3c8b..fecdff844a6 100644
--- a/components/style/parallel.rs
+++ b/components/style/parallel.rs
@@ -125,6 +125,19 @@ pub fn traverse_dom<E, D>(traversal: &D,
}
}
+/// A callback to create our thread local context. This needs to be
+/// out of line so we don't allocate stack space for the entire struct
+/// in the caller.
+#[inline(never)]
+fn create_thread_local_context<'scope, E, D>(
+ traversal: &'scope D,
+ slot: &mut Option<D::ThreadLocalContext>)
+ where E: TElement + 'scope,
+ D: DomTraversal<E>
+{
+ *slot = Some(traversal.create_thread_local_context())
+}
+
/// A parallel top-down DOM traversal.
///
/// This algorithm traverses the DOM in a breadth-first, top-down manner. The
@@ -153,7 +166,8 @@ 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(|| traversal.create_thread_local_context());
+ let mut tlc = tls.ensure(
+ |slot: &mut Option<D::ThreadLocalContext>| create_thread_local_context(traversal, slot));
for n in nodes {
// If the last node we processed produced children, spawn them off
diff --git a/components/style/scoped_tls.rs b/components/style/scoped_tls.rs
index 78537bce5f9..b1ccb4c7179 100644
--- a/components/style/scoped_tls.rs
+++ b/components/style/scoped_tls.rs
@@ -9,6 +9,7 @@
use rayon;
use std::cell::{Ref, RefCell, RefMut};
+use std::ops::DerefMut;
/// A scoped TLS set, that is alive during the `'scope` lifetime.
///
@@ -52,11 +53,16 @@ impl<'scope, T: Send> ScopedTLS<'scope, T> {
}
/// Ensure that the current data this thread owns is initialized, or
- /// initialize it using `f`.
- pub fn ensure<F: FnOnce() -> T>(&self, f: F) -> RefMut<T> {
+ /// initialize it using `f`. We want ensure() to be fast and inline, and we
+ /// want to inline the memmove that initializes the Option<T>. But we don't
+ /// want to inline space for the entire large T struct in our stack frame.
+ /// That's why we hand `f` a mutable borrow to write to instead of just
+ /// having it return a T.
+ #[inline(always)]
+ pub fn ensure<F: FnOnce(&mut Option<T>)>(&self, f: F) -> RefMut<T> {
let mut opt = self.borrow_mut();
if opt.is_none() {
- *opt = Some(f());
+ f(opt.deref_mut());
}
RefMut::map(opt, |x| x.as_mut().unwrap())