diff --git a/components/layout/data.rs b/components/layout/data.rs index 5f6672d1488..b965bc44ebd 100644 --- a/components/layout/data.rs +++ b/components/layout/data.rs @@ -8,8 +8,7 @@ use script_layout_interface::StyleData; #[repr(C)] pub struct StyleAndLayoutData { - /// Data accessed by script_layout_interface. This must be first to allow - /// casting between StyleAndLayoutData and StyleData. + /// The style data associated with a node. pub style_data: StyleData, /// The layout data associated with a node. pub layout_data: AtomicRefCell, diff --git a/components/layout/query.rs b/components/layout/query.rs index cd3e75bf28c..d7c4d7e8987 100644 --- a/components/layout/query.rs +++ b/components/layout/query.rs @@ -6,6 +6,7 @@ use crate::construct::ConstructionResult; use crate::context::LayoutContext; +use crate::data::StyleAndLayoutData; use crate::display_list::items::{DisplayList, OpaqueNode, ScrollOffsetMap}; use crate::display_list::IndexableText; use crate::flow::{Flow, GetBaseFlow}; @@ -26,7 +27,6 @@ use script_layout_interface::rpc::{OffsetParentResponse, ResolvedStyleResponse, use script_layout_interface::wrapper_traits::{ LayoutNode, ThreadSafeLayoutElement, ThreadSafeLayoutNode, }; -use script_layout_interface::StyleData; use script_layout_interface::{LayoutElementType, LayoutNodeType}; use script_traits::LayoutMsg as ConstellationMsg; use script_traits::UntrustedNodeAddress; @@ -1037,8 +1037,13 @@ fn inner_text_collection_steps<'dom>( }; let element_data = unsafe { - node.get_style_and_layout_data() - .map(|d| &(*(d.ptr.as_ptr() as *mut StyleData)).element_data) + &node.get_style_and_layout_data().as_ref().map(|opaque| { + &opaque + .downcast_ref::() + .unwrap() + .style_data + .element_data + }) }; if element_data.is_none() { diff --git a/components/layout/traversal.rs b/components/layout/traversal.rs index 244531cee46..6b280ebf52f 100644 --- a/components/layout/traversal.rs +++ b/components/layout/traversal.rs @@ -73,7 +73,7 @@ where // flow construction: // (1) They child doesn't yet have layout data (preorder traversal initializes it). // (2) The parent element has restyle damage (so the text flow also needs fixup). - node.get_raw_data().is_none() || !parent_data.damage.is_empty() + (unsafe { node.get_raw_data().is_none() }) || !parent_data.damage.is_empty() } fn shared_context(&self) -> &SharedStyleContext { diff --git a/components/layout/wrapper.rs b/components/layout/wrapper.rs index 60eace1f16a..9e2626e090e 100644 --- a/components/layout/wrapper.rs +++ b/components/layout/wrapper.rs @@ -52,11 +52,11 @@ where T: GetLayoutData<'dom>, { fn borrow_layout_data(&self) -> Option> { - self.get_raw_data().map(|d| d.layout_data.borrow()) + unsafe { self.get_raw_data().map(|d| d.layout_data.borrow()) } } fn mutate_layout_data(&self) -> Option> { - self.get_raw_data().map(|d| d.layout_data.borrow_mut()) + unsafe { self.get_raw_data().map(|d| d.layout_data.borrow_mut()) } } fn flow_debug_id(self) -> usize { @@ -66,18 +66,16 @@ where } pub trait GetRawData { - fn get_raw_data(&self) -> Option<&StyleAndLayoutData>; + unsafe fn get_raw_data(&self) -> Option<&StyleAndLayoutData>; } impl<'dom, T> GetRawData for T where T: GetLayoutData<'dom>, { - fn get_raw_data(&self) -> Option<&StyleAndLayoutData> { - self.get_style_and_layout_data().map(|opaque| { - let container = opaque.ptr.as_ptr() as *mut StyleAndLayoutData; - unsafe { &*container } - }) + unsafe fn get_raw_data(&self) -> Option<&StyleAndLayoutData> { + self.get_style_and_layout_data() + .map(|opaque| opaque.downcast_ref().unwrap()) } } @@ -146,7 +144,7 @@ where debug_assert!(node.is_element()); } - let damage = { + let damage = unsafe { let data = node.get_raw_data().unwrap(); if !data diff --git a/components/layout_2020/dom_traversal.rs b/components/layout_2020/dom_traversal.rs index ef4570a85bb..13d11bdc2a7 100644 --- a/components/layout_2020/dom_traversal.rs +++ b/components/layout_2020/dom_traversal.rs @@ -446,10 +446,13 @@ where self.opaque() } + #[allow(unsafe_code)] fn layout_data_mut(&self) -> AtomicRefMut { - self.get_raw_data() - .map(|d| d.layout_data.borrow_mut()) - .unwrap() + unsafe { + self.get_raw_data() + .map(|d| d.layout_data.borrow_mut()) + .unwrap() + } } fn element_box_slot(&self) -> BoxSlot<'dom> { diff --git a/components/layout_2020/traversal.rs b/components/layout_2020/traversal.rs index b57fe2b63f1..b535aba4a2b 100644 --- a/components/layout_2020/traversal.rs +++ b/components/layout_2020/traversal.rs @@ -63,7 +63,7 @@ where } fn text_node_needs_traversal(node: E::ConcreteNode, parent_data: &ElementData) -> bool { - node.get_raw_data().is_none() || !parent_data.damage.is_empty() + (unsafe { node.get_raw_data().is_none() }) || !parent_data.damage.is_empty() } fn shared_context(&self) -> &SharedStyleContext { diff --git a/components/layout_2020/wrapper.rs b/components/layout_2020/wrapper.rs index 504ab9af2cc..bccb37a1c41 100644 --- a/components/layout_2020/wrapper.rs +++ b/components/layout_2020/wrapper.rs @@ -8,17 +8,15 @@ use crate::data::StyleAndLayoutData; use script_layout_interface::wrapper_traits::GetLayoutData; pub trait GetRawData { - fn get_raw_data(&self) -> Option<&StyleAndLayoutData>; + unsafe fn get_raw_data(&self) -> Option<&StyleAndLayoutData>; } impl<'dom, T> GetRawData for T where T: GetLayoutData<'dom>, { - fn get_raw_data(&self) -> Option<&StyleAndLayoutData> { - self.get_style_and_layout_data().map(|opaque| { - let container = opaque.ptr.as_ptr() as *mut StyleAndLayoutData; - unsafe { &*container } - }) + unsafe fn get_raw_data(&self) -> Option<&StyleAndLayoutData> { + self.get_style_and_layout_data() + .map(|opaque| opaque.downcast_ref().unwrap()) } } diff --git a/components/layout_thread/dom_wrapper.rs b/components/layout_thread/dom_wrapper.rs index 9237e9d47e7..4614f30cb93 100644 --- a/components/layout_thread/dom_wrapper.rs +++ b/components/layout_thread/dom_wrapper.rs @@ -70,7 +70,6 @@ use std::borrow::Cow; use std::fmt; use std::fmt::Debug; use std::hash::{Hash, Hasher}; -use std::ptr::NonNull; use std::sync::atomic::Ordering; use std::sync::Arc as StdArc; use style::applicable_declarations::ApplicableDeclarationBlock; @@ -93,9 +92,7 @@ use style::stylist::CascadeData; use style::CaseSensitivityExt; pub unsafe fn drop_style_and_layout_data(data: OpaqueStyleAndLayoutData) { - let ptr = data.ptr.as_ptr() as *mut StyleData; - let non_opaque: *mut StyleAndLayoutData = ptr as *mut _; - let _ = Box::from_raw(non_opaque); + drop(Box::from_raw(data.as_ptr())); } #[derive(Clone, Copy)] @@ -276,10 +273,7 @@ impl<'ln> LayoutNode<'ln> for ServoLayoutNode<'ln> { unsafe fn initialize_data(&self) { if self.get_raw_data().is_none() { - let ptr: *mut StyleAndLayoutData = Box::into_raw(Box::new(StyleAndLayoutData::new())); - let opaque = OpaqueStyleAndLayoutData { - ptr: NonNull::new_unchecked(ptr as *mut StyleData), - }; + let opaque = OpaqueStyleAndLayoutData::new(StyleAndLayoutData::new()); self.init_style_and_layout_data(opaque); }; } @@ -558,10 +552,7 @@ impl<'le> TElement for ServoLayoutElement<'le> { } fn get_data(&self) -> Option<&AtomicRefCell> { - unsafe { - self.get_style_and_layout_data() - .map(|d| &(*(d.ptr.as_ptr() as *mut StyleData)).element_data) - } + self.get_style_data().map(|data| &data.element_data) } fn skip_item_display_fixup(&self) -> bool { @@ -697,10 +688,12 @@ impl<'le> ServoLayoutElement<'le> { } fn get_style_data(&self) -> Option<&StyleData> { - unsafe { - self.get_style_and_layout_data() - .map(|d| &*(d.ptr.as_ptr() as *mut StyleData)) - } + self.get_style_and_layout_data().map(|opaque| { + &opaque + .downcast_ref::() + .unwrap() + .style_data + }) } pub unsafe fn unset_snapshot_flags(&self) { diff --git a/components/layout_thread_2020/dom_wrapper.rs b/components/layout_thread_2020/dom_wrapper.rs index 5a722cd82b8..6fd9451e8b1 100644 --- a/components/layout_thread_2020/dom_wrapper.rs +++ b/components/layout_thread_2020/dom_wrapper.rs @@ -70,7 +70,6 @@ use std::borrow::Cow; use std::fmt; use std::fmt::Debug; use std::hash::{Hash, Hasher}; -use std::ptr::NonNull; use std::sync::atomic::Ordering; use std::sync::Arc as StdArc; use style::applicable_declarations::ApplicableDeclarationBlock; @@ -93,9 +92,7 @@ use style::stylist::CascadeData; use style::CaseSensitivityExt; pub unsafe fn drop_style_and_layout_data(data: OpaqueStyleAndLayoutData) { - let ptr = data.ptr.as_ptr() as *mut StyleData; - let non_opaque: *mut StyleAndLayoutData = ptr as *mut _; - let _ = Box::from_raw(non_opaque); + drop(Box::from_raw(data.as_ptr())); } #[derive(Clone, Copy)] @@ -283,10 +280,7 @@ impl<'ln> LayoutNode<'ln> for ServoLayoutNode<'ln> { unsafe fn initialize_data(&self) { if self.get_raw_data().is_none() { - let ptr: *mut StyleAndLayoutData = Box::into_raw(Box::new(StyleAndLayoutData::new())); - let opaque = OpaqueStyleAndLayoutData { - ptr: NonNull::new_unchecked(ptr as *mut StyleData), - }; + let opaque = OpaqueStyleAndLayoutData::new(StyleAndLayoutData::new()); self.init_style_and_layout_data(opaque); }; } @@ -565,10 +559,7 @@ impl<'le> TElement for ServoLayoutElement<'le> { } fn get_data(&self) -> Option<&AtomicRefCell> { - unsafe { - self.get_style_and_layout_data() - .map(|d| &(*(d.ptr.as_ptr() as *mut StyleData)).element_data) - } + self.get_style_data().map(|data| &data.element_data) } fn skip_item_display_fixup(&self) -> bool { @@ -704,10 +695,12 @@ impl<'le> ServoLayoutElement<'le> { } fn get_style_data(&self) -> Option<&StyleData> { - unsafe { - self.get_style_and_layout_data() - .map(|d| &*(d.ptr.as_ptr() as *mut StyleData)) - } + self.get_style_and_layout_data().map(|opaque| { + &opaque + .downcast_ref::() + .unwrap() + .style_data + }) } pub unsafe fn unset_snapshot_flags(&self) { diff --git a/components/script_layout_interface/lib.rs b/components/script_layout_interface/lib.rs index ef9382378cb..6bfe0af2b30 100644 --- a/components/script_layout_interface/lib.rs +++ b/components/script_layout_interface/lib.rs @@ -7,6 +7,7 @@ //! to depend on script. #![deny(unsafe_code)] +#![feature(box_into_raw_non_null)] #[macro_use] extern crate html5ever; @@ -24,6 +25,7 @@ use libc::c_void; use net_traits::image_cache::PendingImageId; use script_traits::UntrustedNodeAddress; use servo_url::{ImmutableOrigin, ServoUrl}; +use std::any::Any; use std::ptr::NonNull; use std::sync::atomic::AtomicIsize; use style::data::ElementData; @@ -54,7 +56,34 @@ pub struct OpaqueStyleAndLayoutData { // NB: We really store a `StyleAndLayoutData` here, so be careful! #[ignore_malloc_size_of = "TODO(#6910) Box value that should be counted but \ the type lives in layout"] - pub ptr: NonNull, + ptr: NonNull, +} + +impl OpaqueStyleAndLayoutData { + #[inline] + pub fn new(value: T) -> Self + where + T: Any + Send + Sync, + { + Self { + ptr: Box::into_raw_non_null(Box::new(value) as Box), + } + } + + #[inline] + pub fn as_ptr(&self) -> *mut (dyn Any + Send + Sync) { + self.ptr.as_ptr() + } + + /// Extremely cursed. + #[allow(unsafe_code)] + #[inline] + pub unsafe fn downcast_ref<'extended, T>(&self) -> Option<&'extended T> + where + T: Any + Send + Sync, + { + (*self.ptr.as_ptr()).downcast_ref() + } } #[allow(unsafe_code)] diff --git a/tests/unit/script/size_of.rs b/tests/unit/script/size_of.rs index e3107c13290..4b18decc66a 100644 --- a/tests/unit/script/size_of.rs +++ b/tests/unit/script/size_of.rs @@ -30,10 +30,10 @@ macro_rules! sizeof_checker ( // Update the sizes here sizeof_checker!(size_event_target, EventTarget, 56); -sizeof_checker!(size_node, Node, 176); -sizeof_checker!(size_element, Element, 352); -sizeof_checker!(size_htmlelement, HTMLElement, 368); -sizeof_checker!(size_div, HTMLDivElement, 368); -sizeof_checker!(size_span, HTMLSpanElement, 368); -sizeof_checker!(size_text, Text, 208); -sizeof_checker!(size_characterdata, CharacterData, 208); +sizeof_checker!(size_node, Node, 184); +sizeof_checker!(size_element, Element, 360); +sizeof_checker!(size_htmlelement, HTMLElement, 376); +sizeof_checker!(size_div, HTMLDivElement, 376); +sizeof_checker!(size_span, HTMLSpanElement, 376); +sizeof_checker!(size_text, Text, 216); +sizeof_checker!(size_characterdata, CharacterData, 216);