1 /* This Source Code Form is subject to the terms of the Mozilla Public
2  * License, v. 2.0. If a copy of the MPL was not distributed with this
3  * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4 
5 //! A thin atomically-reference-counted slice.
6 
7 use serde::de::{Deserialize, Deserializer};
8 use serde::ser::{Serialize, Serializer};
9 use servo_arc::ThinArc;
10 use std::ops::Deref;
11 use std::ptr::NonNull;
12 use std::{iter, mem};
13 
14 use malloc_size_of::{MallocSizeOf, MallocSizeOfOps, MallocUnconditionalSizeOf};
15 
16 /// A canary that we stash in ArcSlices.
17 ///
18 /// Given we cannot use a zero-sized-type for the header, since well, C++
19 /// doesn't have zsts, and we want to use cbindgen for this type, we may as well
20 /// assert some sanity at runtime.
21 ///
22 /// We use an u64, to guarantee that we can use a single singleton for every
23 /// empty slice, even if the types they hold are aligned differently.
24 const ARC_SLICE_CANARY: u64 = 0xf3f3f3f3f3f3f3f3;
25 
26 /// A wrapper type for a refcounted slice using ThinArc.
27 ///
28 /// cbindgen:derive-eq=false
29 /// cbindgen:derive-neq=false
30 #[repr(C)]
31 #[derive(Debug, Eq, PartialEq, ToShmem)]
32 pub struct ArcSlice<T>(#[shmem(field_bound)] ThinArc<u64, T>);
33 
34 impl<T> Deref for ArcSlice<T> {
35     type Target = [T];
36 
37     #[inline]
deref(&self) -> &Self::Target38     fn deref(&self) -> &Self::Target {
39         debug_assert_eq!(self.0.header.header, ARC_SLICE_CANARY);
40         &self.0.slice
41     }
42 }
43 
44 impl<T> Clone for ArcSlice<T> {
clone(&self) -> Self45     fn clone(&self) -> Self {
46         ArcSlice(self.0.clone())
47     }
48 }
49 
50 lazy_static! {
51     // ThinArc doesn't support alignments greater than align_of::<u64>.
52     static ref EMPTY_ARC_SLICE: ArcSlice<u64> = {
53         ArcSlice::from_iter_leaked(iter::empty())
54     };
55 }
56 
57 impl<T> Default for ArcSlice<T> {
58     #[allow(unsafe_code)]
default() -> Self59     fn default() -> Self {
60         debug_assert!(
61             mem::align_of::<T>() <= mem::align_of::<u64>(),
62             "Need to increase the alignment of EMPTY_ARC_SLICE"
63         );
64         unsafe {
65             let empty: ArcSlice<_> = EMPTY_ARC_SLICE.clone();
66             let empty: Self = mem::transmute(empty);
67             debug_assert_eq!(empty.len(), 0);
68             empty
69         }
70     }
71 }
72 
73 impl<T: Serialize> Serialize for ArcSlice<T> {
serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer,74     fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
75     where
76         S: Serializer,
77     {
78         self.deref().serialize(serializer)
79     }
80 }
81 
82 impl<'de, T: Deserialize<'de>> Deserialize<'de> for ArcSlice<T> {
deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: Deserializer<'de>,83     fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
84     where
85         D: Deserializer<'de>,
86     {
87         let r = Vec::deserialize(deserializer)?;
88         Ok(ArcSlice::from_iter(r.into_iter()))
89     }
90 }
91 
92 impl<T> ArcSlice<T> {
93     /// Creates an Arc for a slice using the given iterator to generate the
94     /// slice.
95     #[inline]
from_iter<I>(items: I) -> Self where I: Iterator<Item = T> + ExactSizeIterator,96     pub fn from_iter<I>(items: I) -> Self
97     where
98         I: Iterator<Item = T> + ExactSizeIterator,
99     {
100         if items.len() == 0 {
101             return Self::default();
102         }
103         ArcSlice(ThinArc::from_header_and_iter(ARC_SLICE_CANARY, items))
104     }
105 
106     /// Creates an Arc for a slice using the given iterator to generate the
107     /// slice, and marks the arc as intentionally leaked from the refcount
108     /// logging point of view.
109     #[inline]
from_iter_leaked<I>(items: I) -> Self where I: Iterator<Item = T> + ExactSizeIterator,110     pub fn from_iter_leaked<I>(items: I) -> Self
111     where
112         I: Iterator<Item = T> + ExactSizeIterator,
113     {
114         let thin_arc = ThinArc::from_header_and_iter(ARC_SLICE_CANARY, items);
115         thin_arc.with_arc(|a| a.mark_as_intentionally_leaked());
116         ArcSlice(thin_arc)
117     }
118 
119     /// Creates a value that can be passed via FFI, and forgets this value
120     /// altogether.
121     #[inline]
122     #[allow(unsafe_code)]
forget(self) -> ForgottenArcSlicePtr<T>123     pub fn forget(self) -> ForgottenArcSlicePtr<T> {
124         let ret = unsafe {
125             ForgottenArcSlicePtr(NonNull::new_unchecked(self.0.ptr() as *const _ as *mut _))
126         };
127         mem::forget(self);
128         ret
129     }
130 
131     /// Leaks an empty arc slice pointer, and returns it. Only to be used to
132     /// construct ArcSlices from FFI.
133     #[inline]
leaked_empty_ptr() -> *mut std::os::raw::c_void134     pub fn leaked_empty_ptr() -> *mut std::os::raw::c_void {
135         let empty: ArcSlice<_> = EMPTY_ARC_SLICE.clone();
136         let ptr = empty.0.ptr();
137         std::mem::forget(empty);
138         ptr as *mut _
139     }
140 
141     /// Returns whether there's only one reference to this ArcSlice.
is_unique(&self) -> bool142     pub fn is_unique(&self) -> bool {
143         self.0.with_arc(|arc| arc.is_unique())
144     }
145 }
146 
147 impl<T: MallocSizeOf> MallocUnconditionalSizeOf for ArcSlice<T> {
148     #[allow(unsafe_code)]
unconditional_size_of(&self, ops: &mut MallocSizeOfOps) -> usize149     fn unconditional_size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
150         let mut size = unsafe { ops.malloc_size_of(self.0.heap_ptr()) };
151         for el in self.iter() {
152             size += el.size_of(ops);
153         }
154         size
155     }
156 }
157 
158 /// The inner pointer of an ArcSlice<T>, to be sent via FFI.
159 /// The type of the pointer is a bit of a lie, we just want to preserve the type
160 /// but these pointers cannot be constructed outside of this crate, so we're
161 /// good.
162 #[repr(C)]
163 pub struct ForgottenArcSlicePtr<T>(NonNull<T>);
164