Use an AtomicRefCell instead of a RwLock for caching intrinsic sizes (#34384)

It panics if the value is mutably borrowed concurrently, but this allows
it to perform better.

Signed-off-by: Oriol Brufau <obrufau@igalia.com>
This commit is contained in:
Oriol Brufau 2024-11-26 14:35:41 +01:00 committed by GitHub
parent 63793ccbb7
commit d034385f76
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -2,9 +2,8 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use std::sync::RwLock;
use app_units::Au; use app_units::Au;
use atomic_refcell::AtomicRefCell;
use serde::Serialize; use serde::Serialize;
use servo_arc::Arc; use servo_arc::Arc;
use style::properties::ComputedValues; use style::properties::ComputedValues;
@ -41,7 +40,8 @@ pub(crate) struct NonReplacedFormattingContext {
#[serde(skip_serializing)] #[serde(skip_serializing)]
pub style: Arc<ComputedValues>, pub style: Arc<ComputedValues>,
/// If it was requested during construction /// If it was requested during construction
pub content_sizes_result: RwLock<Option<(SizeConstraint, InlineContentSizesResult)>>, #[serde(skip_serializing)]
pub content_sizes_result: AtomicRefCell<Option<(SizeConstraint, InlineContentSizesResult)>>,
pub contents: NonReplacedFormattingContextContents, pub contents: NonReplacedFormattingContextContents,
} }
@ -169,7 +169,7 @@ impl IndependentFormattingContext {
Self::NonReplaced(NonReplacedFormattingContext { Self::NonReplaced(NonReplacedFormattingContext {
style: Arc::clone(&node_and_style_info.style), style: Arc::clone(&node_and_style_info.style),
base_fragment_info, base_fragment_info,
content_sizes_result: RwLock::default(), content_sizes_result: AtomicRefCell::default(),
contents, contents,
}) })
}, },
@ -298,24 +298,20 @@ impl NonReplacedFormattingContext {
layout_context: &LayoutContext, layout_context: &LayoutContext,
constraint_space: &ConstraintSpace, constraint_space: &ConstraintSpace,
) -> InlineContentSizesResult { ) -> InlineContentSizesResult {
if let Ok(Some((previous_cb_block_size, result))) = let mut cache = self.content_sizes_result.borrow_mut();
self.content_sizes_result.read().as_deref() if let Some((previous_cb_block_size, result)) = *cache {
{
if !result.depends_on_block_constraints || if !result.depends_on_block_constraints ||
*previous_cb_block_size == constraint_space.block_size previous_cb_block_size == constraint_space.block_size
{ {
return *result; return result;
} }
// TODO: Should we keep multiple caches for various block sizes? // TODO: Should we keep multiple caches for various block sizes?
} }
let writer = self.content_sizes_result.write();
let result = self let result = self
.contents .contents
.inline_content_sizes(layout_context, constraint_space); .inline_content_sizes(layout_context, constraint_space);
if let Ok(mut cache) = writer {
*cache = Some((constraint_space.block_size, result)); *cache = Some((constraint_space.block_size, result));
}
result result
} }