mirror of
https://github.com/servo/servo.git
synced 2025-08-03 12:40:06 +01:00
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.
This commit is contained in:
parent
3616b8f0c3
commit
93271e199b
2 changed files with 24 additions and 4 deletions
|
@ -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
|
||||
|
|
|
@ -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())
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue