From 36d22d82aa202bb199967e9512281e9a53db42c9 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 21:33:14 +0200 Subject: Adding upstream version 115.7.0esr. Signed-off-by: Daniel Baumann --- servo/components/style_traits/arc_slice.rs | 160 +++++++++++++++++++++++++++++ 1 file changed, 160 insertions(+) create mode 100644 servo/components/style_traits/arc_slice.rs (limited to 'servo/components/style_traits/arc_slice.rs') diff --git a/servo/components/style_traits/arc_slice.rs b/servo/components/style_traits/arc_slice.rs new file mode 100644 index 0000000000..43f31cb283 --- /dev/null +++ b/servo/components/style_traits/arc_slice.rs @@ -0,0 +1,160 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * 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/. */ + +//! A thin atomically-reference-counted slice. + +use serde::de::{Deserialize, Deserializer}; +use serde::ser::{Serialize, Serializer}; +use servo_arc::ThinArc; +use std::ops::Deref; +use std::ptr::NonNull; +use std::{iter, mem}; + +use malloc_size_of::{MallocSizeOf, MallocSizeOfOps, MallocUnconditionalSizeOf}; + +/// A canary that we stash in ArcSlices. +/// +/// Given we cannot use a zero-sized-type for the header, since well, C++ +/// doesn't have zsts, and we want to use cbindgen for this type, we may as well +/// assert some sanity at runtime. +/// +/// We use an u64, to guarantee that we can use a single singleton for every +/// empty slice, even if the types they hold are aligned differently. +const ARC_SLICE_CANARY: u64 = 0xf3f3f3f3f3f3f3f3; + +/// A wrapper type for a refcounted slice using ThinArc. +#[repr(C)] +#[derive(Debug, Eq, PartialEq, ToShmem)] +pub struct ArcSlice(#[shmem(field_bound)] ThinArc); + +impl Deref for ArcSlice { + type Target = [T]; + + #[inline] + fn deref(&self) -> &Self::Target { + debug_assert_eq!(self.0.header, ARC_SLICE_CANARY); + self.0.slice() + } +} + +impl Clone for ArcSlice { + fn clone(&self) -> Self { + ArcSlice(self.0.clone()) + } +} + +lazy_static! { + // ThinArc doesn't support alignments greater than align_of::. + static ref EMPTY_ARC_SLICE: ArcSlice = { + ArcSlice::from_iter_leaked(iter::empty()) + }; +} + +impl Default for ArcSlice { + #[allow(unsafe_code)] + fn default() -> Self { + debug_assert!( + mem::align_of::() <= mem::align_of::(), + "Need to increase the alignment of EMPTY_ARC_SLICE" + ); + unsafe { + let empty: ArcSlice<_> = EMPTY_ARC_SLICE.clone(); + let empty: Self = mem::transmute(empty); + debug_assert_eq!(empty.len(), 0); + empty + } + } +} + +impl Serialize for ArcSlice { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + self.deref().serialize(serializer) + } +} + +impl<'de, T: Deserialize<'de>> Deserialize<'de> for ArcSlice { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let r = Vec::deserialize(deserializer)?; + Ok(ArcSlice::from_iter(r.into_iter())) + } +} + +impl ArcSlice { + /// Creates an Arc for a slice using the given iterator to generate the + /// slice. + #[inline] + pub fn from_iter(items: I) -> Self + where + I: Iterator + ExactSizeIterator, + { + if items.len() == 0 { + return Self::default(); + } + ArcSlice(ThinArc::from_header_and_iter(ARC_SLICE_CANARY, items)) + } + + /// Creates an Arc for a slice using the given iterator to generate the + /// slice, and marks the arc as intentionally leaked from the refcount + /// logging point of view. + #[inline] + pub fn from_iter_leaked(items: I) -> Self + where + I: Iterator + ExactSizeIterator, + { + let arc = ThinArc::from_header_and_iter(ARC_SLICE_CANARY, items); + arc.mark_as_intentionally_leaked(); + ArcSlice(arc) + } + + /// Creates a value that can be passed via FFI, and forgets this value + /// altogether. + #[inline] + #[allow(unsafe_code)] + pub fn forget(self) -> ForgottenArcSlicePtr { + let ret = unsafe { + ForgottenArcSlicePtr(NonNull::new_unchecked(self.0.raw_ptr() as *const _ as *mut _)) + }; + mem::forget(self); + ret + } + + /// Leaks an empty arc slice pointer, and returns it. Only to be used to + /// construct ArcSlices from FFI. + #[inline] + pub fn leaked_empty_ptr() -> *mut std::os::raw::c_void { + let empty: ArcSlice<_> = EMPTY_ARC_SLICE.clone(); + let ptr = empty.0.raw_ptr(); + std::mem::forget(empty); + ptr as *mut _ + } + + /// Returns whether there's only one reference to this ArcSlice. + pub fn is_unique(&self) -> bool { + self.0.is_unique() + } +} + +impl MallocUnconditionalSizeOf for ArcSlice { + #[allow(unsafe_code)] + fn unconditional_size_of(&self, ops: &mut MallocSizeOfOps) -> usize { + let mut size = unsafe { ops.malloc_size_of(self.0.heap_ptr()) }; + for el in self.iter() { + size += el.size_of(ops); + } + size + } +} + +/// The inner pointer of an ArcSlice, to be sent via FFI. +/// The type of the pointer is a bit of a lie, we just want to preserve the type +/// but these pointers cannot be constructed outside of this crate, so we're +/// good. +#[repr(C)] +pub struct ForgottenArcSlicePtr(NonNull); -- cgit v1.2.3